Skip to content

Commit ff7bcb6

Browse files
authored
F#129: Parses cloudconfig data from USER_DATA (#130)
The following modules are supported: - write_files - runcmd Signed-off-by: Aleix Ramírez <[email protected]> Signed-off-by: Jaime <[email protected]>
1 parent 4b54c62 commit ff7bcb6

File tree

5 files changed

+558
-0
lines changed

5 files changed

+558
-0
lines changed
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
#!/usr/bin/env bash
2+
3+
# -------------------------------------------------------------------------- #
4+
# Copyright 2002-2024, OpenNebula Project, OpenNebula Systems #
5+
# #
6+
# Licensed under the Apache License, Version 2.0 (the "License"); you may #
7+
# not use this file except in compliance with the License. You may obtain #
8+
# a copy of the License at #
9+
# #
10+
# http://www.apache.org/licenses/LICENSE-2.0 #
11+
# #
12+
# Unless required by applicable law or agreed to in writing, software #
13+
# distributed under the License is distributed on an "AS IS" BASIS, #
14+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. #
15+
# See the License for the specific language governing permissions and #
16+
# limitations under the License. #
17+
#--------------------------------------------------------------------------- #
18+
19+
set -eo pipefail
20+
21+
export USER_DATA="${USER_DATA:-${USERDATA}}"
22+
if [ -z "$USER_DATA" ]; then
23+
echo "No USER_DATA env variable found. Skipping execution..."
24+
exit 0
25+
fi
26+
27+
CLOUDINIT_BASE_DIR="/var/lib/one-context/cloudinit"
28+
CLOUDINIT_ENV_FILE="${CLOUDINIT_BASE_DIR}/cloudinit_env.sh"
29+
CLOUDINIT_LOCK_FILE="${CLOUDINIT_BASE_DIR}/cloudinit-boot-finished"
30+
CLOUDINIT_RUNCMD_TMP_DIR="${CLOUDINIT_BASE_DIR}/tmp"
31+
CLOUDINIT_RUNCMD_TMP_SCRIPT="${CLOUDINIT_RUNCMD_TMP_DIR}/runcmd_script.sh"
32+
33+
bootstrap_cloudinit_env()
34+
{
35+
install -m "u=rwx,go=" -d "${CLOUDINIT_BASE_DIR}"
36+
{
37+
echo "export CLOUDINIT_LOCK_FILE=${CLOUDINIT_LOCK_FILE}"
38+
echo "export CLOUDINIT_BASE_DIR=${CLOUDINIT_BASE_DIR}"
39+
echo "export CLOUDINIT_RUNCMD_TMP_DIR=${CLOUDINIT_RUNCMD_TMP_DIR}"
40+
echo "export CLOUDINIT_RUNCMD_TMP_SCRIPT=${CLOUDINIT_RUNCMD_TMP_SCRIPT}"
41+
} >> "${CLOUDINIT_ENV_FILE}"
42+
43+
}
44+
45+
if [ -e "${CLOUDINIT_LOCK_FILE}" ]; then
46+
echo "Lock file exists in ${CLOUDINIT_LOCK_FILE}. Skipping execution..."
47+
exit 0
48+
fi
49+
bootstrap_cloudinit_env
50+
51+
# creates tmp dir for cloudinit runcmd script
52+
install -m "u=rwx,go=" -d "${CLOUDINIT_RUNCMD_TMP_DIR}"
53+
54+
USER_DATA_ENCODING="${USER_DATA_ENCODING:-${USERDATA_ENCODING}}"
55+
56+
if [ "${USER_DATA_ENCODING}" = "base64" ]; then
57+
if ! USER_DATA="$(echo "${USER_DATA}" | base64 -d 2>/dev/null)"; then
58+
echo "Error: Failed base64 decoding of userdata" >&2
59+
exit 1
60+
fi
61+
fi
62+
63+
# shellcheck source=/dev/null
64+
. "${CLOUDINIT_ENV_FILE}"
65+
66+
one_cloudinit.rb
67+
EXIT_CODE=$?
68+
69+
if [ "${EXIT_CODE}" -ne 0 ]; then
70+
echo "one_cloudinit execution failed. Exit code: ${EXIT_CODE}"
71+
exit 1
72+
fi
73+
echo "one_cloudinit execution finished"
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
#!/usr/bin/env bash
2+
3+
# -------------------------------------------------------------------------- #
4+
# Copyright 2002-2024, OpenNebula Project, OpenNebula Systems #
5+
# #
6+
# Licensed under the Apache License, Version 2.0 (the "License"); you may #
7+
# not use this file except in compliance with the License. You may obtain #
8+
# a copy of the License at #
9+
# #
10+
# http://www.apache.org/licenses/LICENSE-2.0 #
11+
# #
12+
# Unless required by applicable law or agreed to in writing, software #
13+
# distributed under the License is distributed on an "AS IS" BASIS, #
14+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. #
15+
# See the License for the specific language governing permissions and #
16+
# limitations under the License. #
17+
#--------------------------------------------------------------------------- #
18+
19+
set -eo pipefail
20+
21+
# avoid executing this script when no $USER_DATA or $USERDATA is granted (avoids locking multi-stage builds)
22+
export USER_DATA="${USER_DATA:-${USERDATA}}"
23+
if [ -z "$USER_DATA" ]; then
24+
echo "No USER_DATA env variable found. Skipping execution..."
25+
exit 0
26+
fi
27+
28+
CLOUDINIT_BASE_DIR="/var/lib/one-context/cloudinit"
29+
CLOUDINIT_ENV_FILE="${CLOUDINIT_BASE_DIR}/cloudinit_env.sh"
30+
31+
lock_and_cleanup()
32+
{
33+
# write cloud-init boot finished file
34+
date +"%Y-%m-%d %H:%M:%S" > "${CLOUDINIT_LOCK_FILE}"
35+
rm -rf "${CLOUDINIT_RUNCMD_TMP_DIR}"
36+
}
37+
38+
# Source cloudinit env vars
39+
# shellcheck source=/dev/null
40+
. "${CLOUDINIT_ENV_FILE}"
41+
42+
if [ -e "${CLOUDINIT_LOCK_FILE}" ]; then
43+
echo "Lock file exists in ${CLOUDINIT_LOCK_FILE}. Skipping execution..."
44+
exit 0
45+
fi
46+
47+
trap lock_and_cleanup EXIT
48+
49+
# Execute cloudinit scripts
50+
if [ -e "${CLOUDINIT_RUNCMD_TMP_SCRIPT}" ]; then
51+
52+
chmod u+x "${CLOUDINIT_RUNCMD_TMP_SCRIPT}"
53+
54+
echo "Executing ${CLOUDINIT_LOCK_FILE}..."
55+
set +e
56+
$SHELL -ex "${CLOUDINIT_RUNCMD_TMP_SCRIPT}"
57+
EXIT_CODE=$?
58+
set -e
59+
if [ "${EXIT_CODE}" -ne 0 ]; then
60+
echo "runcmd script execution failed. Exit code: ${EXIT_CODE}"
61+
exit 1
62+
fi
63+
echo "runcmd script execution finished"
64+
65+
else
66+
echo "No runcmd script found in: ${CLOUDINIT_RUNCMD_TMP_SCRIPT}. Skipping execution..."
67+
fi
68+
Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
#!/usr/bin/env ruby
2+
3+
# -------------------------------------------------------------------------- #
4+
# Copyright 2002-2024, OpenNebula Project, OpenNebula Systems #
5+
# #
6+
# Licensed under the Apache License, Version 2.0 (the "License"); you may #
7+
# not use this file except in compliance with the License. You may obtain #
8+
# a copy of the License at #
9+
# #
10+
# http://www.apache.org/licenses/LICENSE-2.0 #
11+
# #
12+
# Unless required by applicable law or agreed to in writing, software #
13+
# distributed under the License is distributed on an "AS IS" BASIS, #
14+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. #
15+
# See the License for the specific language governing permissions and #
16+
# limitations under the License. #
17+
#--------------------------------------------------------------------------- #
18+
19+
require 'fileutils'
20+
21+
module CloudInit
22+
23+
##
24+
# RunCmd class implements the runcmd cloud-config directive.
25+
##
26+
class RunCmd
27+
28+
attr_accessor :cmd_list
29+
30+
def initialize(cmd_list)
31+
raise 'RunCmd must be instantiated with a command list as an argument' \
32+
unless cmd_list.is_a?(Array)
33+
34+
@cmd_list = cmd_list
35+
end
36+
37+
def exec
38+
if @cmd_list.empty?
39+
CloudInit::Logger.debug('[runCmd] empty cmdlist, ignoring...')
40+
return
41+
end
42+
CloudInit::Logger.debug("[runCmd] processing commands'")
43+
44+
runcmd_script_path = ENV['CLOUDINIT_RUNCMD_TMP_SCRIPT']
45+
if !runcmd_script_path
46+
raise 'mandatory CLOUDINIT_RUNCMD_TMP_SCRIPT env var not found!'
47+
end
48+
49+
begin
50+
file_content = create_shell_file_content
51+
rescue StandardError => e
52+
raise "could not generate runcmd script file content: #{e.message}"
53+
end
54+
55+
File.open(runcmd_script_path, 'w', 0o700) do |file|
56+
file.write(file_content)
57+
end
58+
59+
CloudInit::Logger.debug(
60+
"[runCmd] runcmd script successfully created in '#{runcmd_script_path}'"
61+
)
62+
end
63+
64+
def create_shell_file_content
65+
content = "#!/bin/sh\n"
66+
@cmd_list.each do |cmd|
67+
if cmd.is_a?(Array)
68+
escaped = []
69+
cmd.each do |token|
70+
# Ensure that each element of the command in the
71+
# array is properly shell-protected with single quotes
72+
modified_string = token.gsub("'") {|x| "'\\#{x}'" }
73+
escaped << "\'#{modified_string}\'"
74+
end
75+
content << "#{escaped.join(' ')}\n"
76+
elsif cmd.is_a?(String)
77+
content << "#{cmd}\n"
78+
else
79+
raise 'incompatible command specification, must be array or string'
80+
end
81+
end
82+
return content
83+
end
84+
85+
end
86+
87+
end

0 commit comments

Comments
 (0)