Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

F#129: Parses cloudconfig data from USER_DATA #130

Open
wants to merge 20 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
73 changes: 73 additions & 0 deletions context-linux/src/etc/one-context.d/net-95-cloudinit-start
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
#!/usr/bin/env bash

# -------------------------------------------------------------------------- #
# Copyright 2002-2024, OpenNebula Project, OpenNebula Systems #
# #
# Licensed under the Apache License, Version 2.0 (the "License"); you may #
# not use this file except in compliance with the License. You may obtain #
# a copy of the License at #
# #
# http://www.apache.org/licenses/LICENSE-2.0 #
# #
# Unless required by applicable law or agreed to in writing, software #
# distributed under the License is distributed on an "AS IS" BASIS, #
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. #
# See the License for the specific language governing permissions and #
# limitations under the License. #
#--------------------------------------------------------------------------- #

sk4zuzu marked this conversation as resolved.
Show resolved Hide resolved
set -eo pipefail

export USER_DATA="${USER_DATA:-${USERDATA}}"
if [ -z "$USER_DATA" ]; then
echo "No USER_DATA env variable found. Skipping execution..."
exit 0
fi

CLOUDINIT_BASE_DIR="/var/lib/one-context/cloudinit"
CLOUDINIT_ENV_FILE="${CLOUDINIT_BASE_DIR}/cloudinit_env.sh"
CLOUDINIT_LOCK_FILE="${CLOUDINIT_BASE_DIR}/cloudinit-boot-finished"
CLOUDINIT_RUNCMD_TMP_DIR="${CLOUDINIT_BASE_DIR}/tmp"
CLOUDINIT_RUNCMD_TMP_SCRIPT="${CLOUDINIT_RUNCMD_TMP_DIR}/runcmd_script.sh"

bootstrap_cloudinit_env()
{
install -m "u=rwx,go=" -d "${CLOUDINIT_BASE_DIR}"
{
echo "export CLOUDINIT_LOCK_FILE=${CLOUDINIT_LOCK_FILE}"
echo "export CLOUDINIT_BASE_DIR=${CLOUDINIT_BASE_DIR}"
echo "export CLOUDINIT_RUNCMD_TMP_DIR=${CLOUDINIT_RUNCMD_TMP_DIR}"
echo "export CLOUDINIT_RUNCMD_TMP_SCRIPT=${CLOUDINIT_RUNCMD_TMP_SCRIPT}"
} >> "${CLOUDINIT_ENV_FILE}"

}

if [ -e "${CLOUDINIT_LOCK_FILE}" ]; then
echo "Lock file exists in ${CLOUDINIT_LOCK_FILE}. Skipping execution..."
exit 0
fi
bootstrap_cloudinit_env

# creates tmp dir for cloudinit runcmd script
install -m "u=rwx,go=" -d "${CLOUDINIT_RUNCMD_TMP_DIR}"

USER_DATA_ENCODING="${USER_DATA_ENCODING:-${USERDATA_ENCODING}}"

if [ "${USER_DATA_ENCODING}" = "base64" ]; then
if ! USER_DATA="$(echo "${USER_DATA}" | base64 -d 2>/dev/null)"; then
echo "Error: Failed base64 decoding of userdata" >&2
exit 1
fi
fi

# shellcheck source=/dev/null
. "${CLOUDINIT_ENV_FILE}"

one_cloudinit.rb
EXIT_CODE=$?

if [ "${EXIT_CODE}" -ne 0 ]; then
echo "one_cloudinit execution failed. Exit code: ${EXIT_CODE}"
exit 1
fi
echo "one_cloudinit execution finished"
68 changes: 68 additions & 0 deletions context-linux/src/etc/one-context.d/net-96-cloudinit-finish
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
#!/usr/bin/env bash

# -------------------------------------------------------------------------- #
# Copyright 2002-2024, OpenNebula Project, OpenNebula Systems #
# #
# Licensed under the Apache License, Version 2.0 (the "License"); you may #
# not use this file except in compliance with the License. You may obtain #
# a copy of the License at #
# #
# http://www.apache.org/licenses/LICENSE-2.0 #
# #
# Unless required by applicable law or agreed to in writing, software #
# distributed under the License is distributed on an "AS IS" BASIS, #
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. #
# See the License for the specific language governing permissions and #
# limitations under the License. #
#--------------------------------------------------------------------------- #

sk4zuzu marked this conversation as resolved.
Show resolved Hide resolved
set -eo pipefail

# avoid executing this script when no $USER_DATA or $USERDATA is granted (avoids locking multi-stage builds)
export USER_DATA="${USER_DATA:-${USERDATA}}"
if [ -z "$USER_DATA" ]; then
echo "No USER_DATA env variable found. Skipping execution..."
exit 0
fi

CLOUDINIT_BASE_DIR="/var/lib/one-context/cloudinit"
CLOUDINIT_ENV_FILE="${CLOUDINIT_BASE_DIR}/cloudinit_env.sh"

lock_and_cleanup()
{
# write cloud-init boot finished file
date +"%Y-%m-%d %H:%M:%S" > "${CLOUDINIT_LOCK_FILE}"
rm -rf "${CLOUDINIT_RUNCMD_TMP_DIR}"
}

# Source cloudinit env vars
# shellcheck source=/dev/null
. "${CLOUDINIT_ENV_FILE}"

if [ -e "${CLOUDINIT_LOCK_FILE}" ]; then
echo "Lock file exists in ${CLOUDINIT_LOCK_FILE}. Skipping execution..."
exit 0
fi

trap lock_and_cleanup EXIT

# Execute cloudinit scripts
if [ -e "${CLOUDINIT_RUNCMD_TMP_SCRIPT}" ]; then

chmod u+x "${CLOUDINIT_RUNCMD_TMP_SCRIPT}"

echo "Executing ${CLOUDINIT_LOCK_FILE}..."
set +e
$SHELL -ex "${CLOUDINIT_RUNCMD_TMP_SCRIPT}"
EXIT_CODE=$?
set -e
if [ "${EXIT_CODE}" -ne 0 ]; then
echo "runcmd script execution failed. Exit code: ${EXIT_CODE}"
exit 1
fi
echo "runcmd script execution finished"

else
echo "No runcmd script found in: ${CLOUDINIT_RUNCMD_TMP_SCRIPT}. Skipping execution..."
fi

87 changes: 87 additions & 0 deletions context-linux/src/usr/bin/cloudinit_cc_run_cmd.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
#!/usr/bin/env ruby

# -------------------------------------------------------------------------- #
# Copyright 2002-2024, OpenNebula Project, OpenNebula Systems #
# #
# Licensed under the Apache License, Version 2.0 (the "License"); you may #
# not use this file except in compliance with the License. You may obtain #
# a copy of the License at #
# #
# http://www.apache.org/licenses/LICENSE-2.0 #
# #
# Unless required by applicable law or agreed to in writing, software #
# distributed under the License is distributed on an "AS IS" BASIS, #
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. #
# See the License for the specific language governing permissions and #
# limitations under the License. #
#--------------------------------------------------------------------------- #

require 'fileutils'

module CloudInit

##
# RunCmd class implements the runcmd cloud-config directive.
##
class RunCmd

attr_accessor :cmd_list

def initialize(cmd_list)
raise 'RunCmd must be instantiated with a command list as an argument' \
unless cmd_list.is_a?(Array)

@cmd_list = cmd_list
end

def exec
if @cmd_list.empty?
CloudInit::Logger.debug('[runCmd] empty cmdlist, ignoring...')
return
end
CloudInit::Logger.debug("[runCmd] processing commands'")

runcmd_script_path = ENV['CLOUDINIT_RUNCMD_TMP_SCRIPT']
if !runcmd_script_path
raise 'mandatory CLOUDINIT_RUNCMD_TMP_SCRIPT env var not found!'
end

begin
file_content = create_shell_file_content
rescue StandardError => e
raise "could not generate runcmd script file content: #{e.message}"
end

File.open(runcmd_script_path, 'w', 0o700) do |file|
file.write(file_content)
end

CloudInit::Logger.debug(
"[runCmd] runcmd script successfully created in '#{runcmd_script_path}'"
)
end

def create_shell_file_content
content = "#!/bin/sh\n"
@cmd_list.each do |cmd|
if cmd.is_a?(Array)
escaped = []
cmd.each do |token|
# Ensure that each element of the command in the
# array is properly shell-protected with single quotes
modified_string = token.gsub("'") {|x| "'\\#{x}'" }
escaped << "\'#{modified_string}\'"
end
content << "#{escaped.join(' ')}\n"
elsif cmd.is_a?(String)
content << "#{cmd}\n"
else
raise 'incompatible command specification, must be array or string'
end
end
return content
end

end

end
Loading