summaryrefslogtreecommitdiff
path: root/systemd/cloud-init-generator.tmpl
blob: 0773356bb693c090ea21aad237b2d48b5831f93f (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
## template:jinja
#!/bin/sh
set -f

LOG=""
DEBUG_LEVEL=1
LOG_D="/run/cloud-init"
ENABLE="enabled"
DISABLE="disabled"
FOUND="found"
NOTFOUND="notfound"
RUN_ENABLED_FILE="$LOG_D/$ENABLE"
{% if variant in ["suse"] %}
CLOUD_SYSTEM_TARGET="/usr/lib/systemd/system/cloud-init.target"
{% else %}
CLOUD_SYSTEM_TARGET="/lib/systemd/system/cloud-init.target"
{% endif %}
CLOUD_TARGET_NAME="cloud-init.target"
# lxc sets 'container', but lets make that explicitly a global
CONTAINER="${container}"

debug() {
    local lvl="$1"
    shift
    [ "$lvl" -gt "$DEBUG_LEVEL" ] && return
    if [ -z "$LOG" ]; then
        local log="$LOG_D/${0##*/}.log"
        { [ -d "$LOG_D" ] || mkdir -p "$LOG_D"; } &&
            { : > "$log"; } >/dev/null 2>&1 && LOG="$log" ||
            LOG="/dev/kmsg"
    fi
    echo "$@" >> "$LOG"
}

etc_file() {
    local pprefix="${1:-/etc/cloud/cloud-init.}"
    _RET="unset"
    [ -f "${pprefix}$ENABLE" ] && _RET="$ENABLE" && return 0
    [ -f "${pprefix}$DISABLE" ] && _RET="$DISABLE" && return 0
    return 0
}

read_proc_cmdline() {
    # return /proc/cmdline for non-container, and /proc/1/cmdline for container
    local ctname="systemd"
    if [ -n "$CONTAINER" ] && ctname=$CONTAINER ||
        systemd-detect-virt --container --quiet; then
        if { _RET=$(tr '\0' ' ' < /proc/1/cmdline); } 2>/dev/null; then
            _RET_MSG="container[$ctname]: pid 1 cmdline"
            return
        fi
        _RET=""
        _RET_MSG="container[$ctname]: pid 1 cmdline not available"
        return 0
    fi

    _RET_MSG="/proc/cmdline"
    read _RET < /proc/cmdline
}

kernel_cmdline() {
    local cmdline="" tok=""
    if [ -n "${KERNEL_CMDLINE+x}" ]; then
        # use KERNEL_CMDLINE if present in environment even if empty
        cmdline=${KERNEL_CMDLINE}
        debug 1 "kernel command line from env KERNEL_CMDLINE: $cmdline"
    elif read_proc_cmdline; then
        read_proc_cmdline && cmdline="$_RET"
        debug 1 "kernel command line ($_RET_MSG): $cmdline"
    fi
    _RET="unset"
    cmdline=" $cmdline "
    tok=${cmdline##* cloud-init=}
    [ "$tok" = "$cmdline" ] && _RET="unset"
    tok=${tok%% *}
    [ "$tok" = "$ENABLE" -o "$tok" = "$DISABLE" ] && _RET="$tok"
    return 0
}

default() {
    _RET="$ENABLE"
}

check_for_datasource() {
    local ds_rc=""
{% if variant in ["rhel", "fedora", "centos"] %}
    local dsidentify="/usr/libexec/cloud-init/ds-identify"
{% else %}
    local dsidentify="/usr/lib/cloud-init/ds-identify"
{% endif %}
    if [ ! -x "$dsidentify" ]; then
        debug 1 "no ds-identify in $dsidentify. _RET=$FOUND"
        return 0
    fi
    $dsidentify
    ds_rc=$?
    debug 1 "ds-identify rc=$ds_rc"
    if [ "$ds_rc" = "0" ]; then
        _RET="$FOUND"
        debug 1 "ds-identify _RET=$_RET"
        return 0
    fi
    _RET="$NOTFOUND"
    debug 1 "ds-identify _RET=$_RET"
    return 1
}

main() {
    local normal_d="$1" early_d="$2" late_d="$3"
    local target_name="multi-user.target" gen_d="$early_d"
    local link_path="$gen_d/${target_name}.wants/${CLOUD_TARGET_NAME}"
    local ds="$NOTFOUND"

    debug 1 "$0 normal=$normal_d early=$early_d late=$late_d"
    debug 2 "$0 $*"

    local search result="error" ret=""
    for search in kernel_cmdline etc_file default; do
        if $search; then
            debug 1 "$search found $_RET"
            [ "$_RET" = "$ENABLE" -o "$_RET" = "$DISABLE" ] &&
                result=$_RET && break
        else
            ret=$?
            debug 0 "search $search returned $ret"
        fi
    done

    # enable AND ds=found == enable
    # enable AND ds=notfound == disable
    # disable || <any> == disabled
    if [ "$result" = "$ENABLE" ]; then
        debug 1 "checking for datasource"
        check_for_datasource
        ds=$_RET
        if [ "$ds" = "$NOTFOUND" ]; then
            debug 1 "cloud-init is enabled but no datasource found, disabling"
            result="$DISABLE"
        fi
    fi

    if [ "$result" = "$ENABLE" ]; then
        if [ -e "$link_path" ]; then
                debug 1 "already enabled: no change needed"
        else
            [ -d "${link_path%/*}" ] || mkdir -p "${link_path%/*}" ||
                debug 0 "failed to make dir $link_path"
            if ln -snf "$CLOUD_SYSTEM_TARGET" "$link_path"; then
                debug 1 "enabled via $link_path -> $CLOUD_SYSTEM_TARGET"
            else
                ret=$?
                debug 0 "[$ret] enable failed:" \
                    "ln $CLOUD_SYSTEM_TARGET $link_path"
            fi
        fi
        : > "$RUN_ENABLED_FILE"
    elif [ "$result" = "$DISABLE" ]; then
        if [ -f "$link_path" ]; then
            if rm -f "$link_path"; then
                debug 1 "disabled. removed existing $link_path"
            else
                ret=$?
                debug 0 "[$ret] disable failed, remove $link_path"
            fi
        else
            debug 1 "already disabled: no change needed [no $link_path]"
        fi
        if [ -e "$RUN_ENABLED_FILE" ]; then
            rm -f "$RUN_ENABLED_FILE"
        fi
    else
        debug 0 "unexpected result '$result' 'ds=$ds'"
        ret=3
    fi
    return $ret
}

main "$@"

# vi: ts=4 expandtab