diff --git a/.vscode/launch.json b/.vscode/launch.json index 96161d4..540220c 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -150,7 +150,9 @@ "program": "${workspaceFolder}/dist/usr/bin/vedv", "args": [ "image", - "build" + "build", + "-t", + "image123" ] } ] diff --git a/cac/configure-image.alpine-linux b/cac/configure-image.alpine-linux index 63d9d60..bcb04bb 100644 --- a/cac/configure-image.alpine-linux +++ b/cac/configure-image.alpine-linux @@ -60,7 +60,7 @@ cat <<'EOF' >/usr/local/bin/vedv-adduser set -eu if [[ "$#" -ne 2 ]]; then - echo "usage: ved-adduser " >&2 + echo "usage: vedv-adduser " >&2 exit 1 fi diff --git a/dist/lib/vedv/components/__base/vmobj-entity.bash b/dist/lib/vedv/components/__base/vmobj-entity.bash index a16ac03..172051b 100644 --- a/dist/lib/vedv/components/__base/vmobj-entity.bash +++ b/dist/lib/vedv/components/__base/vmobj-entity.bash @@ -569,9 +569,9 @@ vedv::vmobj_entity::__set_attribute() { # Set ssh_port value # # Arguments: -# type string type (e.g. 'container|image') -# vmobj_id string vmobj id -# ssh_port int ssh port +# type string type (e.g. 'container|image') +# vmobj_id string vmobj id +# ssh_port int ssh port # # Returns: # 0 on success, non-zero on error. @@ -592,8 +592,11 @@ vedv::vmobj_entity::set_ssh_port() { # Get ssh_port value # # Arguments: -# type string type (e.g. 'container|image') -# vmobj_id string vmobj id +# type string type (e.g. 'container|image') +# vmobj_id string vmobj id +# +# Output: +# Writes ssh_port (int) to the stdout. # # Returns: # 0 on success, non-zero on error. @@ -607,3 +610,49 @@ vedv::vmobj_entity::get_ssh_port() { "$vmobj_id" \ 'ssh_port' } + +# +# Set user name +# +# Arguments: +# type string type (e.g. 'container|image') +# vmobj_id string vmobj id +# user_name string user name +# +# Returns: +# 0 on success, non-zero on error. +# +vedv::vmobj_entity::set_user_name() { + local -r type="$1" + local -r vmobj_id="$2" + local -r value="$3" + + vedv::vmobj_entity::__set_attribute \ + "$type" \ + "$vmobj_id" \ + 'user_name' \ + "$value" +} + +# +# Get user name +# +# Arguments: +# type string type (e.g. 'container|image') +# vmobj_id string vmobj id +# +# Output: +# Writes user_name (string) to the stdout. +# +# Returns: +# 0 on success, non-zero on error. +# +vedv::vmobj_entity::get_user_name() { + local -r type="$1" + local -r vmobj_id="$2" + + vedv::vmobj_entity::__get_attribute \ + "$type" \ + "$vmobj_id" \ + 'user_name' +} diff --git a/dist/lib/vedv/components/__base/vmobj-service.bash b/dist/lib/vedv/components/__base/vmobj-service.bash index b3189bd..9f97855 100644 --- a/dist/lib/vedv/components/__base/vmobj-service.bash +++ b/dist/lib/vedv/components/__base/vmobj-service.bash @@ -31,6 +31,16 @@ vedv::vmobj_service::constructor() { readonly __VEDV_VMOBJ_SERVICE_SSH_PASSWORD="$3" } +# +# Get ssh user +# +# Output: +# Writes ssh_user (string) to the stdout +# +vedv::vmobj_service::get_ssh_user() { + echo "$__VEDV_VMOBJ_SERVICE_SSH_USER" +} + # # Tell if a vmobj is started # @@ -667,7 +677,8 @@ vedv::vmobj_service::__exec_ssh_func() { local -r type="$1" local -r vmobj_id="$2" local -r exec_func="$3" - local -r user="${4:-"$__VEDV_VMOBJ_SERVICE_SSH_USER"}" + local user="${4:-}" + # validate arguments vedv::vmobj_entity::validate_type "$type" || return "$?" @@ -679,6 +690,14 @@ vedv::vmobj_service::__exec_ssh_func() { err "Invalid argument 'exec_func': it's empty" return "$ERR_INVAL_ARG" fi + if [[ -z "$user" ]]; then + user="$(vedv::vmobj_entity::get_user_name "$type" "$vmobj_id")" || { + err "Failed to get default user for ${type}" + return "$ERR_VMOBJ_OPERATION" + } + fi + readonly user + if [[ -z "$user" ]]; then err "Invalid argument 'user': it's empty" return "$ERR_INVAL_ARG" @@ -714,6 +733,7 @@ vedv::vmobj_service::__exec_ssh_func() { # type string type (e.g. 'container|image') # vmobj_id string vmobj id # cmd string command to execute +# [user] string user name # # Output: # writes command output to the stdout @@ -725,6 +745,7 @@ vedv::vmobj_service::execute_cmd_by_id() { local -r type="$1" local -r vmobj_id="$2" local -r cmd="$3" + local -r user="${4:-}" # validate arguments vedv::vmobj_entity::validate_type "$type" || return "$?" @@ -740,7 +761,7 @@ vedv::vmobj_service::execute_cmd_by_id() { local -r exec_func="vedv::ssh_client::run_cmd \"\$user\" \"\$ip\" \"\$password\" '${cmd}' \"\$port\"" - vedv::vmobj_service::__exec_ssh_func "$type" "$vmobj_id" "$exec_func" || { + vedv::vmobj_service::__exec_ssh_func "$type" "$vmobj_id" "$exec_func" "$user" || { err "Failed to execute command in ${type}: ${vmobj_id}" return "$ERR_VMOBJ_OPERATION" } @@ -753,6 +774,7 @@ vedv::vmobj_service::execute_cmd_by_id() { # type string type (e.g. 'container|image') # vmobj_id_or_name string vmobj id or name # cmd string command to execute +# [user] string user name # # Output: # writes command output to the stdout @@ -764,13 +786,14 @@ vedv::vmobj_service::execute_cmd() { local -r type="$1" local -r vmobj_id_or_name="$2" local -r cmd="$3" + local -r user="${4:-}" local vmobj_id vmobj_id="$(vedv::vmobj_service::get_ids_from_vmobj_names_or_ids "$type" "$vmobj_id_or_name")" || { err "Failed to get ${type} id by name or id: ${vmobj_id_or_name}" return "$ERR_VMOBJ_OPERATION" } - vedv::vmobj_service::execute_cmd_by_id "$type" "$vmobj_id" "$cmd" + vedv::vmobj_service::execute_cmd_by_id "$type" "$vmobj_id" "$cmd" "$user" } # @@ -875,7 +898,7 @@ vedv::vmobj_service::copy_by_id() { } readonly vedvfileignore - local -r exec_func="vedv::ssh_client::copy \"\$user\" \"\$ip\" \"\$password\" \"\$port\" '${src}' '${dest}' ${vedvfileignore}" + local -r exec_func="vedv::ssh_client::copy \"\$user\" \"\$ip\" \"\$password\" \"\$port\" '${src}' '${dest}' '${vedvfileignore}'" vedv::vmobj_service::__exec_ssh_func "$type" "$vmobj_id" "$exec_func" "$user" || { err "Failed to copy to ${type}: ${vmobj_id}" @@ -918,3 +941,60 @@ vedv::vmobj_service::copy() { "$dest" \ "$user" } + +# +# Create an user if not exits and set its name to +# the vmobj-entity +# +# Arguments: +# type string type (e.g. 'container|image') +# vmobj_id string vmobj id +# user_name string user name +# +# Output: +# writes command output to the stdout +# +# Returns: +# 0 on success, non-zero on error. +# +vedv::vmobj_service::set_user() { + local -r type="$1" + local -r vmobj_id="$2" + local -r user_name="$3" + # validate arguments + vedv::vmobj_entity::validate_type "$type" || + return "$?" + + if [[ -z "$vmobj_id" ]]; then + err "Invalid argument 'vmobj_id': it's empty" + return "$ERR_INVAL_ARG" + fi + if [[ -z "$user_name" ]]; then + err "Invalid argument 'user_name': it's empty" + return "$ERR_INVAL_ARG" + fi + + local cur_user_name + cur_user_name="$(vedv::vmobj_entity::get_user_name "$type" "$vmobj_id")" || { + err "Error getting attribute user name from the ${type} '${vmobj_id}'" + return "$ERR_VMOBJ_OPERATION" + } + readonly cur_user_name + + if [[ "$cur_user_name" == "$user_name" ]]; then + return 0 + fi + + # create user if it doesn't exist + local -r cmd="vedv-adduser '${user_name}' '${__VEDV_VMOBJ_SERVICE_SSH_PASSWORD}'" + + vedv::vmobj_service::execute_cmd_by_id "$type" "$vmobj_id" "$cmd" 'root' &>/dev/null || { + err "Failed to set user '${user_name}' to ${type}: ${vmobj_id}" + return "$ERR_VMOBJ_OPERATION" + } + + vedv::vmobj_entity::set_user_name "$type" "$vmobj_id" "$user_name" || { + err "Error setting attribute user name '${user_name}' to the ${type}: ${vmobj_id}" + return "$ERR_VMOBJ_OPERATION" + } +} diff --git a/dist/lib/vedv/components/container/container-entity.bash b/dist/lib/vedv/components/container/container-entity.bash index b6449ed..8ae2595 100644 --- a/dist/lib/vedv/components/container/container-entity.bash +++ b/dist/lib/vedv/components/container/container-entity.bash @@ -20,7 +20,7 @@ fi readonly VEDV_CONTAINER_ENTITY_TYPE='container' # shellcheck disable=SC2034 -readonly VEDV_CONTAINER_ENTITY_VALID_ATTRIBUTES='parent_image_id|ssh_port' +readonly VEDV_CONTAINER_ENTITY_VALID_ATTRIBUTES='parent_image_id|ssh_port|user_name' # FUNCTIONS @@ -196,3 +196,38 @@ vedv::container_entity::get_parent_image_id() { "$container_id" \ 'parent_image_id' } + +# +# Get user_name value +# +# Arguments: +# container_id string container id +# +# Output: +# Writes user_name (string) to the stdout +# +# Returns: +# 0 on success, non-zero on error. +# +vedv::container_entity::get_user_name() { + local -r container_id="$1" + + vedv::vmobj_entity::get_user_name "$VEDV_CONTAINER_ENTITY_TYPE" "$container_id" +} + +# +# Set user_name value +# +# Arguments: +# container_id string container id +# user_name string user name +# +# Returns: +# 0 on success, non-zero on error. +# +vedv::container_entity::set_user_name() { + local -r container_id="$1" + local -r value="$2" + + vedv::vmobj_entity::set_user_name "$VEDV_CONTAINER_ENTITY_TYPE" "$container_id" "$value" +} diff --git a/dist/lib/vedv/components/container/container-service.bash b/dist/lib/vedv/components/container/container-service.bash index 8d1e2e5..85d32bb 100644 --- a/dist/lib/vedv/components/container/container-service.bash +++ b/dist/lib/vedv/components/container/container-service.bash @@ -152,6 +152,23 @@ vedv::container_service::create() { return "$ERR_CONTAINER_OPERATION" } + local user_name + user_name="$(vedv::image_entity::get_user_name "$image_id")" || { + err "Error getting attribute 'user_name' from the image: ${image_id}" + return "$ERR_IMAGE_OPERATION" + } + readonly user_name + + if [[ -z "$user_name" ]]; then + err "Attribute 'user_name' is empty for the image '${image_id}'" + return "$ERR_INVAL_VALUE" + fi + + vedv::container_entity::set_user_name "$container_id" "$user_name" || { + err "Failed to set 'user_name' for container: ${container_id}" + return "$ERR_CONTAINER_OPERATION" + } + echo "$container_name" } diff --git a/dist/lib/vedv/components/image/image-builder.bash b/dist/lib/vedv/components/image/image-builder.bash index 5c12dd9..a40bf5a 100644 --- a/dist/lib/vedv/components/image/image-builder.bash +++ b/dist/lib/vedv/components/image/image-builder.bash @@ -582,10 +582,11 @@ vedv::image_builder::__layer_copy() { } # -# Calculates the layer id for the run command +# Calculates the layer id for simple commands # # Arguments: -# cmd string run command (e.g. "1 COPY source/ dest/") +# cmd string command (e.g. "1 COPY source/ dest/") +# command_name string command name (e.g. "COPY") # # Output: # Writes layer_id (string) to the stdout @@ -593,13 +594,19 @@ vedv::image_builder::__layer_copy() { # Returns: # 0 on success, non-zero on error. # -vedv::image_builder::__layer_run_calc_id() { +vedv::image_builder::__simple_layer_command_calc_id() { local -r cmd="$1" + local -r command_name="$2" # validate arguments if [[ -z "$cmd" ]]; then err "Argument 'cmd' is required" return "$ERR_INVAL_ARG" fi + if [[ -z "$command_name" ]]; then + err "Argument 'command_name' is required" + return "$ERR_INVAL_ARG" + fi + local cmd_name cmd_name="$(vedv::image_vedvfile_service::get_cmd_name "$cmd")" || { err "Failed to get command name from command '$cmd'" @@ -607,14 +614,31 @@ vedv::image_builder::__layer_run_calc_id() { } readonly cmd_name - if [[ "$cmd_name" != "RUN" ]]; then - err "Invalid command name '${cmd_name}', it must be 'RUN'" + if [[ "$cmd_name" != "$command_name" ]]; then + err "Invalid command name '${cmd_name}', it must be '${command_name}'" return "$ERR_INVAL_ARG" fi utils::crc_sum <<<"$cmd" } +# +# Calculates the layer id for the run command +# +# Arguments: +# cmd string run command (e.g. "1 COPY source/ dest/") +# +# Output: +# Writes layer_id (string) to the stdout +# +# Returns: +# 0 on success, non-zero on error. +# +vedv::image_builder::__layer_run_calc_id() { + local -r cmd="$1" + vedv::image_builder::__simple_layer_command_calc_id "$cmd" "RUN" +} + # # Run commands inside the image # @@ -645,7 +669,11 @@ vedv::image_builder::__layer_run() { fi local cmd_body - cmd_body="$(vedv::image_vedvfile_service::get_cmd_body "$cmd")" + cmd_body="$(vedv::image_vedvfile_service::get_cmd_body "$cmd")" || { + err "Failed to get body from command '${cmd}'" + return "$ERR_INVAL_ARG" + } + cmd_body="$(utils::str_encode "$cmd_body")" readonly cmd_body if [[ -z "$cmd_body" ]]; then @@ -657,6 +685,72 @@ vedv::image_builder::__layer_run() { vedv::image_builder::__layer_execute_cmd "$image_id" "$cmd" "RUN" "$exec_func" } +# +# Calculates the layer id for the user command +# +# Arguments: +# cmd string user command (e.g. "1 USER nalyd") +# +# Output: +# Writes layer_id (string) to the stdout +# +# Returns: +# 0 on success, non-zero on error. +# +vedv::image_builder::__layer_user_calc_id() { + local -r cmd="$1" + vedv::image_builder::__simple_layer_command_calc_id "$cmd" "USER" +} + +# +# Creates and set de default user for the image +# +# Preconditions: +# The image must be started and running +# +# Arguments: +# image_id string image where the user will be set +# cmd string user command (e.g. "1 USER nalyd") +# +# Output: +# Writes command_output (text) to the stdout +# +# Returns: +# 0 on success, non-zero on error. +# +vedv::image_builder::__layer_user() { + local -r image_id="$1" + local -r cmd="$2" + shift 2 + # validate arguments + if [[ -z "$image_id" ]]; then + err "Argument 'image_id' is required" + return "$ERR_INVAL_ARG" + fi + if [[ -z "$cmd" ]]; then + err "Argument 'cmd' is required" + return "$ERR_INVAL_ARG" + fi + + local -a cmd_arr + IFS=' ' read -r -a cmd_arr <<<"$cmd" + # 1 USER nalyd -> nalyd + local user_name + user_name="$(vedv::image_vedvfile_service::get_cmd_body "$cmd")" || { + err "Failed to get user name from command '${cmd}'" + return "$ERR_INVAL_ARG" + } + readonly user_name + + if [[ -z "$user_name" ]]; then + err "Argument 'user_name' must not be empty" + return "$ERR_INVAL_ARG" + fi + + local -r exec_func="vedv::image_service::set_user '${image_id}' '${user_name}'" + vedv::image_builder::__layer_execute_cmd "$image_id" "$cmd" "USER" "$exec_func" +} + # # Delete invalid layers # diff --git a/dist/lib/vedv/components/image/image-entity.bash b/dist/lib/vedv/components/image/image-entity.bash index dd277e8..4074308 100644 --- a/dist/lib/vedv/components/image/image-entity.bash +++ b/dist/lib/vedv/components/image/image-entity.bash @@ -24,7 +24,7 @@ fi readonly VEDV_IMAGE_ENTITY_TYPE='image' # shellcheck disable=SC2034 -readonly VEDV_IMAGE_ENTITY_VALID_ATTRIBUTES='image_cache|ova_file_sum|ssh_port' +readonly VEDV_IMAGE_ENTITY_VALID_ATTRIBUTES='image_cache|ova_file_sum|ssh_port|user_name' # FUNCTIONS @@ -241,10 +241,10 @@ vedv::image_entity::set_image_cache() { # Get ssh_port value # # Arguments: -# image_id string image id +# image_id string image id # # Output: -# Writes ssh_port (int) value +# Writes ssh_port (int) to the stdout # # Returns: # 0 on success, non-zero on error. @@ -258,8 +258,8 @@ vedv::image_entity::get_ssh_port() { # Set ssh_port value # # Arguments: -# image_id string image id -# ssh_port int ssh port +# image_id string image id +# ssh_port int ssh port # # Returns: # 0 on success, non-zero on error. @@ -271,6 +271,40 @@ vedv::image_entity::set_ssh_port() { vedv::vmobj_entity::set_ssh_port "$VEDV_IMAGE_ENTITY_TYPE" "$image_id" "$value" } +# +# Get user_name value +# +# Arguments: +# image_id string image id +# +# Output: +# Writes user_name (string) to the stdout +# +# Returns: +# 0 on success, non-zero on error. +# +vedv::image_entity::get_user_name() { + local -r image_id="$1" + vedv::vmobj_entity::get_user_name "$VEDV_IMAGE_ENTITY_TYPE" "$image_id" +} + +# +# Set user_name value +# +# Arguments: +# image_id string image id +# user_name string ssh port +# +# Returns: +# 0 on success, non-zero on error. +# +vedv::image_entity::set_user_name() { + local -r image_id="$1" + local -r value="$2" + + vedv::vmobj_entity::set_user_name "$VEDV_IMAGE_ENTITY_TYPE" "$image_id" "$value" +} + # # Get snapshots names # diff --git a/dist/lib/vedv/components/image/image-service.bash b/dist/lib/vedv/components/image/image-service.bash index f98972a..58d008c 100644 --- a/dist/lib/vedv/components/image/image-service.bash +++ b/dist/lib/vedv/components/image/image-service.bash @@ -129,6 +129,22 @@ vedv::image_service::__pull_from_file() { return "$ERR_IMAGE_OPERATION" } + local user_name + user_name="$(vedv::image_entity::get_user_name "$image_id")" || { + err "Error getting attribute user name from the image '${image_id}'" + return "$ERR_IMAGE_OPERATION" + } + readonly user_name + + if [[ -z "$user_name" ]]; then + local -r default_user_name="$(vedv::vmobj_service::get_ssh_user)" + + vedv::image_entity::set_user_name "$image_id" "$default_user_name" || { + err "Error setting attribute user name '${default_user_name}' to the image '${image_id}'" + return "$ERR_IMAGE_OPERATION" + } + fi + if [[ "$return_image_id" != true ]]; then echo "$image_name" else @@ -611,6 +627,30 @@ vedv::image_service::copy() { "$user" } +# +# Create an user if not exits and set its name to +# the vmobj-entity +# +# Arguments: +# image_id string image id +# user_name string user name +# +# Output: +# writes command output to the stdout +# +# Returns: +# 0 on success, non-zero on error. +# +vedv::image_service::set_user() { + local -r image_id="$1" + local -r user_name="$2" + + vedv::vmobj_service::set_user \ + 'image' \ + "$image_id" \ + "$user_name" +} + # # Build an image from a Vedvfile, # diff --git a/dist/lib/vedv/components/image/image-vedvfile-service.bash b/dist/lib/vedv/components/image/image-vedvfile-service.bash index 7001cc0..a58c8b8 100644 --- a/dist/lib/vedv/components/image/image-vedvfile-service.bash +++ b/dist/lib/vedv/components/image/image-vedvfile-service.bash @@ -8,7 +8,7 @@ if false; then fi # Variables: -readonly VEDVFILE_SUPPORTED_COMMANDS='FROM|RUN|COPY' +readonly VEDVFILE_SUPPORTED_COMMANDS='FROM|RUN|COPY|USER' # # Constructor @@ -37,7 +37,7 @@ __vedvfile-parser() { # Validate commands # # Arguments: -# commands text with commands (list of commands, splitted by \n) +# commands text commands (list of commands, splitted by \n) # # Output: # writes error message on error @@ -53,14 +53,28 @@ vedv::image_vedvfile_service::__are_supported_commands() { return 0 fi - local -r clean_cmds="$(utils::string::trim "$commands")" + local -a cmds_arr + readarray -t cmds_arr <<<"$commands" + readonly cmds_arr - while IFS= read -r cmd; do - if ! grep -qP "^($VEDVFILE_SUPPORTED_COMMANDS)\s+" <<<"$cmd"; then - err "Command '${cmd}' isn't supported, valid commands are: ${VEDVFILE_SUPPORTED_COMMANDS}" + for cmd_ in "${cmds_arr[@]}"; do + + if [[ -z "$cmd_" ]]; then + continue + fi + + local -a cmd_arr + IFS=' ' read -r -a cmd_arr <<<"$cmd_" + + if [[ "${cmd_arr[0]}" =~ ^[0-9]+$ ]]; then + cmd_arr=("${cmd_arr[@]:1}") + fi + + if [[ "${cmd_arr[0]}" != @($VEDVFILE_SUPPORTED_COMMANDS) ]]; then + err "Command '${cmd_arr[*]}' isn't supported, valid commands are: ${VEDVFILE_SUPPORTED_COMMANDS}" return 1 fi - done <<<"$clean_cmds" + done return 0 } @@ -102,7 +116,7 @@ vedv::image_vedvfile_service::__validate_file() { # Build an image from a Vedvfile # # Arguments: -# vedvfile string Vedvfile full path +# vedvfile string Vedvfile full path # # Output: # writes commands (text) to stdout @@ -136,39 +150,41 @@ vedv::image_vedvfile_service::get_commands() { # Get the command name # # Arguments: -# cmd command +# cmd string command # # Output: -# writes the command name to stdout +# writes the command_name (string) to stdout # # Returns: # 0 on success, non-zero on error. # vedv::image_vedvfile_service::get_cmd_name() { - local -r cmd="$1" + local -r _cmd="$1" - if [[ -z "$cmd" ]]; then + if [[ -z "$_cmd" ]]; then err "Argument 'cmd' must not be empty" return "$ERR_INVAL_ARG" fi - - local cmd_name - cmd_name="$(utils::string::trim "$cmd" | grep -Po "(\d+\s+)?($VEDVFILE_SUPPORTED_COMMANDS)\s+" | - sed -e 's/^[[:digit:]]*\s*//' -e 's/[[:space:]]*$//')" - - if [[ -z "$cmd_name" ]]; then - err "There isn't command name in '${cmd}'" - return "$ERR_INVAL_ARG" + # extract arguments + local -a cmd_arr + IFS=' ' read -r -a cmd_arr <<<"$_cmd" + if [[ "${cmd_arr[0]}" =~ ^[0-9]+$ ]]; then + # remove the command id + cmd_arr=("${cmd_arr[@]:1}") fi + readonly cmd_arr - echo "$cmd_name" + vedv::image_vedvfile_service::__are_supported_commands "${cmd_arr[*]}" || + return "$ERR_INVAL_VALUE" + # COPY --root source/ dest/ -> COPY + echo "${cmd_arr[0]}" } # # Get the command body # # Arguments: -# cmd text command +# cmd text command # # Output: # writes the command_body (text) to stdout @@ -177,14 +193,26 @@ vedv::image_vedvfile_service::get_cmd_name() { # 0 on success, non-zero on error. # vedv::image_vedvfile_service::get_cmd_body() { - local -r cmd="$1" + local -r _cmd="$1" - if [[ -z "$cmd" ]]; then + if [[ -z "$_cmd" ]]; then err "Argument 'cmd' must not be empty" return "$ERR_INVAL_ARG" fi + # extract arguments + local -a cmd_arr + IFS=' ' read -r -a cmd_arr <<<"$_cmd" - echo "$cmd" | sed -e 's/\s*\([[:digit:]]\+\s\+\)\?\(FROM\|RUN\|CMD\|LABEL\|EXPOSE\|ENV\|ADD\|COPY\|ENTRYPOINT\|VOLUME\|USER\|WORKDIR\|ARG\|ONBUILD\|STOPSIGNAL\|HEALTHCHECK\|SHELL\)\s\+//' -e 's/[[:space:]]*$//' + if [[ "${cmd_arr[0]}" =~ ^[0-9]+$ ]]; then + # remove the command id + cmd_arr=("${cmd_arr[@]:1}") + fi + readonly cmd_arr + + vedv::image_vedvfile_service::__are_supported_commands "${cmd_arr[*]}" || + return "$ERR_INVAL_VALUE" + # COPY --root source/ dest/ -> --root source/ dest/ + echo "${cmd_arr[*]:1}" } # @@ -204,7 +232,7 @@ vedv:image_vedvfile_service::get_joined_vedvfileignore() { fi local vedvfileignore_path - + readonly cmd_arr if [[ ! -f "$__VEDV_IMAGE_VEDVFILE_VEDVFILEIGNORE_PATH" ]]; then vedvfileignore_path="$__VEDV_IMAGE_VEDVFILE_BASE_VEDVFILEIGNORE_PATH" else diff --git a/dist/lib/vedv/hypervisors/virtualbox.bash b/dist/lib/vedv/hypervisors/virtualbox.bash index ec0de1f..73378fc 100644 --- a/dist/lib/vedv/hypervisors/virtualbox.bash +++ b/dist/lib/vedv/hypervisors/virtualbox.bash @@ -612,7 +612,7 @@ vedv::hypervisor::set_description() { return "$ERR_INVAL_ARG" fi - if ! VBoxManage modifyvm "$vm_name" --description "$description" >/dev/null; then + if ! VBoxManage setextradata "$vm_name" user-data "$description" >/dev/null; then err "Error setting description, vm: ${vm_name}" return "$ERR_VIRTUALBOX_OPERATION" fi @@ -640,14 +640,17 @@ vedv::hypervisor::get_description() { fi local vminfo - vminfo="$(VBoxManage showvminfo "$vm_name" --machinereadable)" || { + vminfo="$(VBoxManage getextradata "$vm_name" user-data)" || { err "Error getting description of vm: ${vm_name}" return "$ERR_VIRTUALBOX_OPERATION" } + readonly vminfo - echo "$vminfo" | - grep -o '^description=".*"' | - sed -e 's/^description="//' -e 's/"$//' + if [[ "$vminfo" == "No value set!" ]]; then + return 0 + fi + + echo "${vminfo#'Value:' }" } vedv::virtualbox::get_description() { vedv::hypervisor::get_description "$@"; } diff --git a/dist/lib/vedv/ssh-client.bash b/dist/lib/vedv/ssh-client.bash index 383756a..44f0c8c 100644 --- a/dist/lib/vedv/ssh-client.bash +++ b/dist/lib/vedv/ssh-client.bash @@ -18,7 +18,7 @@ vedv::ssh_client::run_cmd() { local -r user="$1" local -r ip="$2" local -r password="$3" - local -r cmd="$4" + local cmd="$4" local -ri port=${5:-22} if [[ -z "$user" ]]; then @@ -44,6 +44,8 @@ vedv::ssh_client::run_cmd() { err "Argument 'cmd' must not be empty" return "$ERR_INVAL_ARG" fi + cmd="$(utils::str_decode "$cmd")" + readonly cmd { sshpass -p "$password" \ @@ -120,7 +122,7 @@ vedv::ssh_client::copy() { { # shellcheck disable=SC2086 - IFS='' rsync -az \ + IFS='' rsync -az --no-owner --no-group \ --exclude-from="$exclude_file_path" \ -e "sshpass -p ${password} ssh -o 'ConnectTimeout=1' -o 'UserKnownHostsFile=/dev/null' -o 'PubkeyAuthentication=no' -o 'StrictHostKeyChecking=no' -o 'LogLevel=ERROR' -p ${port}" \ $source "${user}@${ip}:${dest}" diff --git a/dist/lib/vedv/utils.bash b/dist/lib/vedv/utils.bash index aee9b21..3fb90a3 100644 --- a/dist/lib/vedv/utils.bash +++ b/dist/lib/vedv/utils.bash @@ -341,3 +341,69 @@ utils::array::to_string() { arr2str() { utils::array::to_string "$@"; } utils::sleep() { sleep "$@"; } + +declare -ga VED_UTILS_DECODED_CHARS=() +VED_UTILS_DECODED_CHARS[0]="'" +VED_UTILS_DECODED_CHARS[1]='"' +readonly VED_UTILS_DECODED_CHARS + +declare -ga VED_UTILS_ENCODED_CHARS=() +VED_UTILS_ENCODED_CHARS[0]="@*^&" +VED_UTILS_ENCODED_CHARS[1]='*!@%' +readonly VED_UTILS_ENCODED_CHARS + +# +# Encode a string +# +# Arguments: +# str string string to encode +# +# Output: +# writes the encoded string to stdout +# +utils::str_encode() { + local -r str="$1" + + if [[ -z "$str" ]]; then + return 0 + fi + + local str_encoded="$str" + + for ((i = 0; i < ${#VED_UTILS_DECODED_CHARS[@]}; i += 1)); do + local decode_char="${VED_UTILS_DECODED_CHARS[$i]}" + local encoded_char="${VED_UTILS_ENCODED_CHARS[$i]}" + + str_encoded="${str_encoded//"$decode_char"/"$encoded_char"}" + done + + echo "$str_encoded" +} + +# +# Decode a string +# +# Arguments: +# str string string to decode +# +# Output: +# writes the decoded string to stdout +# +utils::str_decode() { + local -r str="$1" + + if [[ -z "$str" ]]; then + return 0 + fi + + local str_decoded="$str" + + for ((i = 0; i < ${#VED_UTILS_ENCODED_CHARS[@]}; i += 1)); do + local decode_char="${VED_UTILS_DECODED_CHARS[$i]}" + local encoded_char="${VED_UTILS_ENCODED_CHARS[$i]}" + + str_decoded="${str_decoded//"$encoded_char"/"$decode_char"}" + done + + echo "$str_decoded" +} diff --git a/dist/test/lib/vedv/components/__base/vmobj-entity.bats b/dist/test/lib/vedv/components/__base/vmobj-entity.bats index a11acca..d5299cd 100644 --- a/dist/test/lib/vedv/components/__base/vmobj-entity.bats +++ b/dist/test/lib/vedv/components/__base/vmobj-entity.bats @@ -919,3 +919,67 @@ setup_file() { assert_success assert_output '' } + +# Test vedv::vmobj_entity::set_user_name() + +@test 'vedv::vmobj_entity::set_user_name() Should fail If __set_attribute fails' { + local -r type='invalid' + local -r vmobj_id='23456' + local -r value=2022 + + vedv::vmobj_entity::__set_attribute() { + assert_equal "$*" 'invalid 23456 user_name 2022' + return 1 + } + + run vedv::vmobj_entity::set_user_name "$type" "$vmobj_id" "$value" + + assert_failure + assert_output '' +} + +@test 'vedv::vmobj_entity::set_user_name() Should succeed' { + local -r type='invalid' + local -r vmobj_id='23456' + local -r value=2022 + + vedv::vmobj_entity::__set_attribute() { + assert_equal "$*" 'invalid 23456 user_name 2022' + } + + run vedv::vmobj_entity::set_user_name "$type" "$vmobj_id" "$value" + + assert_success + assert_output '' +} + +# Test vedv::vmobj_entity::get_user_name() + +@test 'vedv::vmobj_entity::get_user_name() Should fail If __get_attribute fails' { + local -r type='invalid' + local -r vmobj_id='23456' + + vedv::vmobj_entity::__get_attribute() { + assert_equal "$*" 'invalid 23456 user_name' + return 1 + } + + run vedv::vmobj_entity::get_user_name "$type" "$vmobj_id" + + assert_failure + assert_output '' +} + +@test 'vedv::vmobj_entity::get_user_name() Should succeed' { + local -r type='invalid' + local -r vmobj_id='23456' + + vedv::vmobj_entity::__get_attribute() { + assert_equal "$*" 'invalid 23456 user_name' + } + + run vedv::vmobj_entity::get_user_name "$type" "$vmobj_id" + + assert_success + assert_output '' +} diff --git a/dist/test/lib/vedv/components/__base/vmobj-service.bats b/dist/test/lib/vedv/components/__base/vmobj-service.bats index 7cd8b07..c5008fc 100644 --- a/dist/test/lib/vedv/components/__base/vmobj-service.bats +++ b/dist/test/lib/vedv/components/__base/vmobj-service.bats @@ -5,7 +5,7 @@ load test_helper setup_file() { vedv::vmobj_entity::constructor \ 'container|image' \ - '([image]="image_cache|ova_file_sum|ssh_port" [container]="parent_vmobj_id|ssh_port")' + '([image]="image_cache|ova_file_sum|ssh_port|user_name" [container]="parent_vmobj_id|ssh_port|user_name")' export __VEDV_VMOBJ_ENTITY_TYPE export __VEDV_VMOBJ_ENTITY_VALID_ATTRIBUTES_DICT_STR @@ -1138,6 +1138,11 @@ EOF local -r exec_func="exec_func" __VEDV_VMOBJ_SERVICE_SSH_USER="" + vedv::vmobj_entity::get_user_name() { + assert_equal "$*" "container 12345" + echo "" + } + run vedv::vmobj_service::__exec_ssh_func "$type" "$vmobj_id" "$exec_func" assert_failure @@ -1149,6 +1154,10 @@ EOF local -r vmobj_id=12345 local -r exec_func="ssh_func" + vedv::vmobj_entity::get_user_name() { + assert_equal "$*" "container 12345" + echo "vedv" + } vedv::vmobj_service::start_one() { assert_equal "$*" "container true 12345" return 1 @@ -1165,6 +1174,10 @@ EOF local -r vmobj_id=12345 local -r exec_func="ssh_func" + vedv::vmobj_entity::get_user_name() { + assert_equal "$*" "container 12345" + echo "vedv" + } vedv::vmobj_service::start_one() { assert_equal "$*" "container true 12345" } @@ -1184,6 +1197,10 @@ EOF local -r vmobj_id=12345 local -r exec_func="ssh_func" + vedv::vmobj_entity::get_user_name() { + assert_equal "$*" "container 12345" + echo "vedv" + } vedv::vmobj_service::start_one() { assert_equal "$*" "container true 12345" } @@ -1207,6 +1224,11 @@ EOF local -r vmobj_id=12345 local -r exec_func="ssh_func" + vedv::vmobj_entity::get_user_name() { + assert_equal "$*" "container 12345" + echo "vedv" + } + vedv::vmobj_service::start_one() { assert_equal "$*" "container true 12345" } @@ -1297,16 +1319,17 @@ EOF local -r type="container" local -r vmobj_id=12345 local -r cmd=":" + local -r user="" vedv::vmobj_service::get_ids_from_vmobj_names_or_ids() { assert_equal "$*" "container 12345" echo 12345 } vedv::vmobj_service::execute_cmd_by_id() { - assert_equal "$*" "container 12345 :" + assert_equal "$*" "container 12345 : " } - run vedv::vmobj_service::execute_cmd "$type" "$vmobj_id" "$cmd" + run vedv::vmobj_service::execute_cmd "$type" "$vmobj_id" "$cmd" "$user" assert_success assert_output "" @@ -1385,7 +1408,7 @@ EOF } # Tests for vedv::vmobj_service::copy_by_id() -# bats test_tags=only + @test "vedv::vmobj_service::copy_by_id(), Should fail with invalid type" { local -r type="invalid" local -r vmobj_id="" @@ -1397,7 +1420,7 @@ EOF assert_failure assert_output "Invalid type: invalid, valid types are: container|image" } -# bats test_tags=only + @test "vedv::vmobj_service::copy_by_id(), Should fail With empty vmobj_id" { local -r type="container" local -r vmobj_id="" @@ -1409,7 +1432,7 @@ EOF assert_failure assert_output "Invalid argument 'vmobj_id': it's empty" } -# bats test_tags=only + @test "vedv::vmobj_service::copy_by_id(), Should fail With empty src" { local -r type="container" local -r vmobj_id=12345 @@ -1421,7 +1444,7 @@ EOF assert_failure assert_output "Invalid argument 'src': it's empty" } -# bats test_tags=only + @test "vedv::vmobj_service::copy_by_id(), Should fail With empty dest" { local -r type="container" local -r vmobj_id=12345 @@ -1433,7 +1456,7 @@ EOF assert_failure assert_output "Invalid argument 'dest': it's empty" } -# bats test_tags=only + @test "vedv::vmobj_service::copy_by_id(), Should fail If get_joined_vedvfileignore fails" { local -r type="container" local -r vmobj_id=12345 @@ -1449,7 +1472,7 @@ EOF assert_failure assert_output "Failed to get joined vedvfileignore" } -# bats test_tags=only + @test "vedv::vmobj_service::copy_by_id(), Should fail If __exec_ssh_func fails" { local -r type="container" local -r vmobj_id=12345 @@ -1471,7 +1494,7 @@ EOF } # Tests for vedv::vmobj_service::copy() -# bats test_tags=only + @test "vedv::vmobj_service::copy(), Should fail If get_ids_from_vmobj_names_or_ids fails" { local -r type="container" local -r vmobj_id=12345 @@ -1488,7 +1511,7 @@ EOF assert_failure assert_output "Failed to get container id by name or id: 12345" } -# bats test_tags=only + @test "vedv::vmobj_service::copy(), Should succeed" { local -r type="container" local -r vmobj_id=12345 @@ -1508,3 +1531,135 @@ EOF assert_success assert_output "" } + +# Tests for vedv::vmobj_service::set_user() +# bats test_tags=only +@test "vedv::vmobj_service::set_user() Should fail With invalid type" { + local -r type="invalid" + local -r vmobj_id="" + local -r user_name="" + + run vedv::vmobj_service::set_user "$type" "$vmobj_id" "$user_name" + + assert_failure + assert_output "Invalid type: invalid, valid types are: container|image" +} +# bats test_tags=only +@test "vedv::vmobj_service::set_user() Should fail With empty vmobj_id" { + local -r type="container" + local -r vmobj_id="" + local -r user_name="" + + run vedv::vmobj_service::set_user "$type" "$vmobj_id" "$user_name" + + assert_failure + assert_output "Invalid argument 'vmobj_id': it's empty" +} +# bats test_tags=only +@test "vedv::vmobj_service::set_user() Should fail With empty user_name" { + local -r type="container" + local -r vmobj_id=12345 + local -r user_name="" + + run vedv::vmobj_service::set_user "$type" "$vmobj_id" "$user_name" + + assert_failure + assert_output "Invalid argument 'user_name': it's empty" +} +# bats test_tags=only +@test "vedv::vmobj_service::set_user() Should fail If get_user_name fails" { + local -r type="container" + local -r vmobj_id=12345 + local -r user_name="user" + + vedv::vmobj_entity::get_user_name() { + assert_equal "$*" "container 12345" + return 1 + } + + run vedv::vmobj_service::set_user "$type" "$vmobj_id" "$user_name" + + assert_failure + assert_output "Error getting attribute user name from the container '12345'" +} +# bats test_tags=only +@test "vedv::vmobj_service::set_user() Should succeed If the user is already set" { + local -r type="container" + local -r vmobj_id=12345 + local -r user_name="user" + + vedv::vmobj_entity::get_user_name() { + assert_equal "$*" "container 12345" + echo "user" + } + + run vedv::vmobj_service::set_user "$type" "$vmobj_id" "$user_name" + + assert_success + assert_output "" +} +# bats test_tags=only +@test "vedv::vmobj_service::set_user() Should fail If execute_cmd_by_id fails" { + local -r type="container" + local -r vmobj_id=12345 + local -r user_name="user" + + vedv::vmobj_entity::get_user_name() { + assert_equal "$*" "container 12345" + echo "vedv" + } + vedv::vmobj_service::execute_cmd_by_id() { + assert_equal "$*" "container 12345 vedv-adduser 'user' '${__VEDV_VMOBJ_SERVICE_SSH_PASSWORD}' root" + return 1 + } + + run vedv::vmobj_service::set_user "$type" "$vmobj_id" "$user_name" + + assert_failure + assert_output "Failed to set user 'user' to container: 12345" +} +# bats test_tags=only +@test "vedv::vmobj_service::set_user() Should fail If set_user_name fails" { + local -r type="container" + local -r vmobj_id=12345 + local -r user_name="user" + + vedv::vmobj_entity::get_user_name() { + assert_equal "$*" "container 12345" + echo "vedv" + } + vedv::vmobj_service::execute_cmd_by_id() { + assert_equal "$*" "container 12345 vedv-adduser 'user' '${__VEDV_VMOBJ_SERVICE_SSH_PASSWORD}' root" + } + vedv::vmobj_entity::set_user_name() { + assert_equal "$*" "container 12345 user" + return 1 + } + + run vedv::vmobj_service::set_user "$type" "$vmobj_id" "$user_name" + + assert_failure + assert_output "Error setting attribute user name 'user' to the container: 12345" +} +# bats test_tags=only +@test "vedv::vmobj_service::set_user() Should succeed" { + local -r type="container" + local -r vmobj_id=12345 + local -r user_name="user" + + vedv::vmobj_entity::get_user_name() { + assert_equal "$*" "container 12345" + echo "vedv" + } + vedv::vmobj_service::execute_cmd_by_id() { + assert_equal "$*" "container 12345 vedv-adduser 'user' '${__VEDV_VMOBJ_SERVICE_SSH_PASSWORD}' root" + } + vedv::vmobj_entity::set_user_name() { + assert_equal "$*" "container 12345 user" + } + + run vedv::vmobj_service::set_user "$type" "$vmobj_id" "$user_name" + + assert_success + assert_output "" +} diff --git a/dist/test/lib/vedv/components/container/container-entity.bats b/dist/test/lib/vedv/components/container/container-entity.bats index 3eee39f..534140d 100644 --- a/dist/test/lib/vedv/components/container/container-entity.bats +++ b/dist/test/lib/vedv/components/container/container-entity.bats @@ -47,7 +47,12 @@ load test_helper : } -# Test vedv::container_entity::get_parent_image_id() -@test 'vedv::container_entity::get_parent_image_id() Should succeed' { +# Test vedv::container_entity::get_user_name() +@test 'vedv::container_entity::get_user_name() Should succeed' { + : +} + +# Test vedv::container_entity::set_user_name() +@test 'vedv::container_entity::set_user_name() Should succeed' { : } diff --git a/dist/test/lib/vedv/components/container/container-service.bats b/dist/test/lib/vedv/components/container/container-service.bats index ab18359..35a27bc 100644 --- a/dist/test/lib/vedv/components/container/container-service.bats +++ b/dist/test/lib/vedv/components/container/container-service.bats @@ -486,6 +486,187 @@ setup_file() { assert_output "Failed to set parent image id for container: 'bin-baam'" } +# bats test_tags=only +@test "vedv::container_service::create() Should fail If get_user_name fails" { + local -r image="image1" + local -r container_name='' + + vedv::vmobj_service::exists_with_name() { + assert_equal "$*" "container container1" + echo false + } + petname() { + assert_equal "$*" "INVALID_CALL" + } + vedv::image_service::pull() { + assert_equal "$*" "INVALID_CALL" + } + vedv::image_entity::get_vm_name_by_image_name() { + assert_equal "$*" "image1" + echo "image:foo-bar|crc:12345|" + } + vedv::container_entity::gen_vm_name() { + assert_equal "$*" "" + echo "container:bin-baam|crc:12346|" + } + vedv::image_entity::get_id_by_vm_name() { + assert_equal "$*" "image:foo-bar|crc:12345|" + echo 12345 + } + vedv::image_entity::get_last_layer_id() { + assert_equal "$*" "12345" + echo 53455 + } + vedv::image_entity::get_snapshot_name_by_layer_id() { + assert_equal "$*" "12345 53455" + echo "layer:RUN|id:layer_id|" + } + vedv::hypervisor::clonevm_link() { + assert_equal "$*" "image:foo-bar|crc:12345| container:bin-baam|crc:12346| layer:RUN|id:layer_id|" + } + vedv::container_entity::get_container_name_by_vm_name() { + assert_equal "$*" "container:bin-baam|crc:12346|" + echo "bin-baam" + } + vedv::container_entity::get_id_by_vm_name() { + assert_equal "$*" "container:bin-baam|crc:12346|" + echo 12346 + } + vedv::container_entity::set_parent_image_id() { + assert_equal "$*" "12346 12345" + } + vedv::image_entity::get_user_name() { + assert_equal "$*" "12345" + return 1 + } + + run vedv::container_service::create "$image" "$container_name" + + assert_failure + assert_output "Error getting attribute 'user_name' from the image: 12345" +} +# bats test_tags=only +@test "vedv::container_service::create() Should fail If user_name is empty" { + local -r image="image1" + local -r container_name='' + + vedv::vmobj_service::exists_with_name() { + assert_equal "$*" "container container1" + echo false + } + petname() { + assert_equal "$*" "INVALID_CALL" + } + vedv::image_service::pull() { + assert_equal "$*" "INVALID_CALL" + } + vedv::image_entity::get_vm_name_by_image_name() { + assert_equal "$*" "image1" + echo "image:foo-bar|crc:12345|" + } + vedv::container_entity::gen_vm_name() { + assert_equal "$*" "" + echo "container:bin-baam|crc:12346|" + } + vedv::image_entity::get_id_by_vm_name() { + assert_equal "$*" "image:foo-bar|crc:12345|" + echo 12345 + } + vedv::image_entity::get_last_layer_id() { + assert_equal "$*" "12345" + echo 53455 + } + vedv::image_entity::get_snapshot_name_by_layer_id() { + assert_equal "$*" "12345 53455" + echo "layer:RUN|id:layer_id|" + } + vedv::hypervisor::clonevm_link() { + assert_equal "$*" "image:foo-bar|crc:12345| container:bin-baam|crc:12346| layer:RUN|id:layer_id|" + } + vedv::container_entity::get_container_name_by_vm_name() { + assert_equal "$*" "container:bin-baam|crc:12346|" + echo "bin-baam" + } + vedv::container_entity::get_id_by_vm_name() { + assert_equal "$*" "container:bin-baam|crc:12346|" + echo 12346 + } + vedv::container_entity::set_parent_image_id() { + assert_equal "$*" "12346 12345" + } + vedv::image_entity::get_user_name() { + assert_equal "$*" "12345" + } + + run vedv::container_service::create "$image" "$container_name" + + assert_failure + assert_output "Attribute 'user_name' is empty for the image '12345'" +} +# bats test_tags=only +@test "vedv::container_service::create() Should fail If set_user_name fails" { + local -r image="image1" + local -r container_name='' + + vedv::vmobj_service::exists_with_name() { + assert_equal "$*" "container container1" + echo false + } + petname() { + assert_equal "$*" "INVALID_CALL" + } + vedv::image_service::pull() { + assert_equal "$*" "INVALID_CALL" + } + vedv::image_entity::get_vm_name_by_image_name() { + assert_equal "$*" "image1" + echo "image:foo-bar|crc:12345|" + } + vedv::container_entity::gen_vm_name() { + assert_equal "$*" "" + echo "container:bin-baam|crc:12346|" + } + vedv::image_entity::get_id_by_vm_name() { + assert_equal "$*" "image:foo-bar|crc:12345|" + echo 12345 + } + vedv::image_entity::get_last_layer_id() { + assert_equal "$*" "12345" + echo 53455 + } + vedv::image_entity::get_snapshot_name_by_layer_id() { + assert_equal "$*" "12345 53455" + echo "layer:RUN|id:layer_id|" + } + vedv::hypervisor::clonevm_link() { + assert_equal "$*" "image:foo-bar|crc:12345| container:bin-baam|crc:12346| layer:RUN|id:layer_id|" + } + vedv::container_entity::get_container_name_by_vm_name() { + assert_equal "$*" "container:bin-baam|crc:12346|" + echo "bin-baam" + } + vedv::container_entity::get_id_by_vm_name() { + assert_equal "$*" "container:bin-baam|crc:12346|" + echo 12346 + } + vedv::container_entity::set_parent_image_id() { + assert_equal "$*" "12346 12345" + } + vedv::image_entity::get_user_name() { + assert_equal "$*" "12345" + echo "vedv" + } + vedv::container_entity::set_user_name() { + assert_equal "$*" "12346 vedv" + return 1 + } + + run vedv::container_service::create "$image" "$container_name" + + assert_failure + assert_output "Failed to set 'user_name' for container: 12346" +} + @test "vedv::container_service::create() Should succeed" { local -r image="image1" local -r container_name='' @@ -534,6 +715,13 @@ setup_file() { vedv::container_entity::set_parent_image_id() { assert_equal "$*" "12346 12345" } + vedv::image_entity::get_user_name() { + assert_equal "$*" "12345" + echo "vedv" + } + vedv::container_entity::set_user_name() { + assert_equal "$*" "12346 vedv" + } run vedv::container_service::create "$image" "$container_name" diff --git a/dist/test/lib/vedv/components/image/fixtures/Vedvfile5 b/dist/test/lib/vedv/components/image/fixtures/Vedvfile5 new file mode 100644 index 0000000..77606f8 --- /dev/null +++ b/dist/test/lib/vedv/components/image/fixtures/Vedvfile5 @@ -0,0 +1,15 @@ +FROM /tmp/vedv/test/files/alpine-x86_64.ova + +# That's the default user for the image and its containers +USER nalyd +COPY homefs/* . + +USER root +RUN apk add --no-cache \ + htop \ + bat \ + bmon +COPY rootfs / + +USER vedv +COPY homefs/* . diff --git a/dist/test/lib/vedv/components/image/image-builder.bats b/dist/test/lib/vedv/components/image/image-builder.bats index 08e503a..ae2b4a7 100644 --- a/dist/test/lib/vedv/components/image/image-builder.bats +++ b/dist/test/lib/vedv/components/image/image-builder.bats @@ -912,18 +912,18 @@ Failed to execute command '1 COPY dummy_source dummy_dest'" assert_output "" } -# Test the vedv::image_builder::__layer_run_calc_id() function +# Test the vedv::image_builder::__simple_layer_command_calc_id() function -@test "vedv::image_builder::__layer_run_calc_id() Should return error if cmd is empty" { +@test "vedv::image_builder::__simple_layer_command_calc_id() Should return error if cmd is empty" { # Run the function with an empty argument - run vedv::image_builder::__layer_run_calc_id "" + run vedv::image_builder::__simple_layer_command_calc_id "" '' # Assert that the function failed assert_failure # Assert that the function printed an error message assert_output "Argument 'cmd' is required" } -@test "vedv::image_builder::__layer_run_calc_id() Should return error if cmd name is not RUN" { +@test "vedv::image_builder::__simple_layer_command_calc_id() Should return error if cmd name is not RUN" { # Arrange local -r cmd="1 MOVE source/ dest/" # Stub @@ -932,13 +932,13 @@ Failed to execute command '1 COPY dummy_source dummy_dest'" echo 'MOVE' } # Act - run vedv::image_builder::__layer_run_calc_id "$cmd" + run vedv::image_builder::__simple_layer_command_calc_id "$cmd" 'RUN' # Assert assert_failure assert_output "Invalid command name 'MOVE', it must be 'RUN'" } -@test "vedv::image_builder::__layer_run_calc_id() Should fails if getting cmd_name fails" { +@test "vedv::image_builder::__simple_layer_command_calc_id() Should fails if getting cmd_name fails" { # Arrange local -r cmd="1 RUN source/ dest/" # Stub @@ -947,13 +947,13 @@ Failed to execute command '1 COPY dummy_source dummy_dest'" return 1 } # Act - run vedv::image_builder::__layer_run_calc_id "$cmd" + run vedv::image_builder::__simple_layer_command_calc_id "$cmd" 'RUN' # Assert assert_failure assert_output "Failed to get command name from command '$cmd'" } -@test "vedv::image_builder::__layer_run_calc_id() should succeed if cmd name is RUN" { +@test "vedv::image_builder::__simple_layer_command_calc_id() should succeed if cmd name is RUN" { # Arrange local -r cmd="1 RUN source/ dest/" # Stub @@ -969,7 +969,7 @@ Failed to execute command '1 COPY dummy_source dummy_dest'" fi } # Act - run vedv::image_builder::__layer_run_calc_id "$cmd" + run vedv::image_builder::__simple_layer_command_calc_id "$cmd" 'RUN' # Assert assert_success assert_output "$cmd" @@ -2162,3 +2162,101 @@ The image 'my-image-name' was removed." assert_success assert_output "" } + +# Tests for vedv::image_builder::__layer_run_calc_id() +@test "vedv::image_builder::__layer_run_calc_id(): DUMMY" { + : +} + +# Tests for vedv::image_builder::__layer_user_calc_id() +@test "vedv::image_builder::__layer_user_calc_id(): DUMMY" { + : +} + +# Tests for vedv::image_builder::__layer_user() +# bats test_tags=only +@test "vedv::image_builder::__layer_user() Should fail With empty image_id" { + local -r image_id="" + local -r cmd="" + + run vedv::image_builder::__layer_user "$image_id" "$cmd" + + assert_failure + assert_output "Argument 'image_id' is required" +} +# bats test_tags=only +@test "vedv::image_builder::__layer_user() Should fail With empty cmd" { + local -r image_id="12345" + local -r cmd= + + run vedv::image_builder::__layer_user "$image_id" "$cmd" + + assert_failure + assert_output "Argument 'cmd' is required" +} +# bats test_tags=only +@test "vedv::image_builder::__layer_user() Should fail If get_cmd_body fails" { + local -r image_id="12345" + local -r cmd="1 USER nalyd" + + vedv::image_vedvfile_service::get_cmd_body() { + assert_equal "$*" "1 USER nalyd" + return 1 + } + + run vedv::image_builder::__layer_user "$image_id" "$cmd" + + assert_failure + assert_output "Failed to get user name from command '1 USER nalyd'" +} +# bats test_tags=only +@test "vedv::image_builder::__layer_user() Should fail If user_name is empty" { + local -r image_id="12345" + local -r cmd="1 USER" + + vedv::image_vedvfile_service::get_cmd_body() { + assert_equal "$*" "1 USER" + } + + run vedv::image_builder::__layer_user "$image_id" "$cmd" + + assert_failure + assert_output "Argument 'user_name' must not be empty" +} +# bats test_tags=only +@test "vedv::image_builder::__layer_user() Should fail If __layer_execute_cmd fails" { + local -r image_id="12345" + local -r cmd="1 USER nalyd" + + vedv::image_vedvfile_service::get_cmd_body() { + assert_equal "$*" "1 USER nalyd" + echo "nalyd" + } + vedv::image_builder::__layer_execute_cmd() { + assert_equal "$*" "12345 1 USER nalyd USER vedv::image_service::set_user '12345' 'nalyd'" + return 1 + } + + run vedv::image_builder::__layer_user "$image_id" "$cmd" + + assert_failure + assert_output "" +} +# bats test_tags=only +@test "vedv::image_builder::__layer_user() Should succeed" { + local -r image_id="12345" + local -r cmd="1 USER nalyd" + + vedv::image_vedvfile_service::get_cmd_body() { + assert_equal "$*" "1 USER nalyd" + echo "nalyd" + } + vedv::image_builder::__layer_execute_cmd() { + assert_equal "$*" "12345 1 USER nalyd USER vedv::image_service::set_user '12345' 'nalyd'" + } + + run vedv::image_builder::__layer_user "$image_id" "$cmd" + + assert_success + assert_output "" +} diff --git a/dist/test/lib/vedv/components/image/image-command.f.bats b/dist/test/lib/vedv/components/image/image-command.f.bats index 6047bd8..d7fa49c 100644 --- a/dist/test/lib/vedv/components/image/image-command.f.bats +++ b/dist/test/lib/vedv/components/image/image-command.f.bats @@ -185,7 +185,7 @@ Options: assert_output --partial "Missing argument for option '${arg}'" done } -# bats test_tags=only + @test "vedv image build, Should build the image" { cd "${BATS_TEST_DIRNAME}/fixtures/vedvfiles" @@ -200,3 +200,23 @@ created layer '.*' for command 'RUN' Build finished .* image123" } +# bats test_tags=only +@test "vedv image build, Should build the image with USER" { + cd "${BATS_TEST_DIRNAME}/fixtures" + + run vedv image build -t 'image123' ./Vedvfile5 + + assert_success + assert_output --regexp " +created layer '.*' for command 'FROM' +created layer '.*' for command 'USER' +created layer '.*' for command 'COPY' +created layer '.*' for command 'USER' +created layer '.*' for command 'RUN' +created layer '.*' for command 'COPY' +created layer '.*' for command 'USER' +created layer '.*' for command 'COPY' + +Build finished +.* image123" +} diff --git a/dist/test/lib/vedv/components/image/image-entity.bats b/dist/test/lib/vedv/components/image/image-entity.bats index b56d0be..583d0d5 100644 --- a/dist/test/lib/vedv/components/image/image-entity.bats +++ b/dist/test/lib/vedv/components/image/image-entity.bats @@ -80,6 +80,16 @@ load test_helper : } +# Test vedv::image_entity::get_user_name() +@test 'vedv::image_entity::get_user_name() DUMMY' { + : +} + +# Test vedv::image_entity::set_user_name() +@test 'vedv::image_entity::set_user_name() DUMMY' { + : +} + # Test vedv::image_entity::__get_snapshots_names() function @test "vedv::image_entity::__get_snapshots_names() Should fail When 'image_id' is empty" { # Arrange diff --git a/dist/test/lib/vedv/components/image/image-service.bats b/dist/test/lib/vedv/components/image/image-service.bats index 6a9b174..85555c3 100644 --- a/dist/test/lib/vedv/components/image/image-service.bats +++ b/dist/test/lib/vedv/components/image/image-service.bats @@ -439,6 +439,120 @@ setup_file() { assert_failure assert_output "Error setting attribute ova file sum '1234567890' to the image vm 'image:custom_image1|crc:1334567890|'" } +# bats test_tags=only +@test "vedv::image_service::__pull_from_file() Should fail If get_user_name fails" { + local -r image_file="$TEST_OVA_FILE" + local -r custom_image_name="custom_image1" + + vedv::image_entity::gen_vm_name_from_ova_file() { + assert_equal "$*" "$TEST_OVA_FILE" + echo "image:image1|crc:1234567890|" + } + vedv::image_entity::get_id_by_vm_name() { + if [ "$1" == "image:${custom_image_name}|crc:1334567890|" ]; then + echo '1334567890' + else + assert_equal "$*" "image:image1|crc:1234567890|" + echo '1234567890' + fi + } + vedv::image_entity::get_image_name_by_vm_name() { + assert_equal "$*" "image:image1|crc:1234567890|" + echo 'image1' + } + vedv::image_entity::gen_vm_name() { + assert_equal "$*" "$custom_image_name" + echo "image:${custom_image_name}|crc:1334567890|" + } + + vedv::hypervisor::list_vms_by_partial_name() { + if [[ "$1" == "$image_cache_vm_name" ]]; then + return 0 + fi + assert_equal "$*" "image:${custom_image_name}|crc:1334567890|" + } + vedv::hypervisor::import() { + assert_equal "$*" "${TEST_OVA_FILE} ${image_cache_vm_name}" + } + vedv::hypervisor::clonevm_link() { + assert_equal "$*" "image-cache|crc:12345678900| image:custom_image1|crc:1334567890|" + } + vedv::image_entity::set_image_cache() { + assert_equal "$*" "1334567890 image-cache|crc:12345678900|" + } + vedv::image_entity::set_ova_file_sum() { + assert_equal "$*" "1334567890 1234567890" + } + vedv::image_entity::get_user_name() { + assert_equal "$*" "1334567890" + return 1 + } + + run vedv::image_service::__pull_from_file "$image_file" "$custom_image_name" + + assert_failure + assert_output "Error getting attribute user name from the image '1334567890'" +} +# bats test_tags=only +@test "vedv::image_service::__pull_from_file() Should fail If set_user_name fails" { + local -r image_file="$TEST_OVA_FILE" + local -r custom_image_name="custom_image1" + + vedv::image_entity::gen_vm_name_from_ova_file() { + assert_equal "$*" "$TEST_OVA_FILE" + echo "image:image1|crc:1234567890|" + } + vedv::image_entity::get_id_by_vm_name() { + if [ "$1" == "image:${custom_image_name}|crc:1334567890|" ]; then + echo '1334567890' + else + assert_equal "$*" "image:image1|crc:1234567890|" + echo '1234567890' + fi + } + vedv::image_entity::get_image_name_by_vm_name() { + assert_equal "$*" "image:image1|crc:1234567890|" + echo 'image1' + } + vedv::image_entity::gen_vm_name() { + assert_equal "$*" "$custom_image_name" + echo "image:${custom_image_name}|crc:1334567890|" + } + + vedv::hypervisor::list_vms_by_partial_name() { + if [[ "$1" == "$image_cache_vm_name" ]]; then + return 0 + fi + assert_equal "$*" "image:${custom_image_name}|crc:1334567890|" + } + vedv::hypervisor::import() { + assert_equal "$*" "${TEST_OVA_FILE} ${image_cache_vm_name}" + } + vedv::hypervisor::clonevm_link() { + assert_equal "$*" "image-cache|crc:12345678900| image:custom_image1|crc:1334567890|" + } + vedv::image_entity::set_image_cache() { + assert_equal "$*" "1334567890 image-cache|crc:12345678900|" + } + vedv::image_entity::set_ova_file_sum() { + assert_equal "$*" "1334567890 1234567890" + } + vedv::image_entity::get_user_name() { + assert_equal "$*" "1334567890" + } + vedv::vmobj_service::get_ssh_user() { + echo "vedv" + } + vedv::image_entity::set_user_name() { + assert_equal "$*" "1334567890 vedv" + return 1 + } + + run vedv::image_service::__pull_from_file "$image_file" "$custom_image_name" + + assert_failure + assert_output "Error setting attribute user name 'vedv' to the image '1334567890'" +} @test "vedv::image_service::__pull_from_file() Should succeed" { local -r image_file="$TEST_OVA_FILE" @@ -483,6 +597,15 @@ setup_file() { vedv::image_entity::set_ova_file_sum() { assert_equal "$*" "1334567890 1234567890" } + vedv::image_entity::get_user_name() { + assert_equal "$*" "1334567890" + } + vedv::vmobj_service::get_ssh_user() { + echo "vedv" + } + vedv::image_entity::set_user_name() { + assert_equal "$*" "1334567890 vedv" + } run vedv::image_service::__pull_from_file "$image_file" "$custom_image_name" @@ -533,6 +656,15 @@ setup_file() { vedv::image_entity::set_ova_file_sum() { assert_equal "$*" "1334567890 1234567890" } + vedv::image_entity::get_user_name() { + assert_equal "$*" "1334567890" + } + vedv::vmobj_service::get_ssh_user() { + echo "vedv" + } + vedv::image_entity::set_user_name() { + assert_equal "$*" "1334567890 vedv" + } run vedv::image_service::__pull_from_file "$image_file" "$custom_image_name" true diff --git a/dist/test/lib/vedv/components/image/image-vedvfile-service.bats b/dist/test/lib/vedv/components/image/image-vedvfile-service.bats index 9d461bd..f1280ce 100644 --- a/dist/test/lib/vedv/components/image/image-vedvfile-service.bats +++ b/dist/test/lib/vedv/components/image/image-vedvfile-service.bats @@ -29,7 +29,7 @@ setup_file() { run vedv::image_vedvfile_service::__are_supported_commands "$commands" assert_failure 1 - assert_output "Command 'INVALID command' isn't supported, valid commands are: FROM|RUN|COPY" + assert_output "Command 'INVALID command' isn't supported, valid commands are: FROM|RUN|COPY|USER" } @test "vedv::image_vedvfile_service::__are_supported_commands() Should succeed With valid command" { @@ -113,17 +113,17 @@ EOF @test "vedv::image_vedvfile_service::get_cmd_name() Should fail With empty 'cmd'" { run vedv::image_vedvfile_service::get_cmd_name "" - assert_failure "$ERR_INVAL_ARG" + assert_failure assert_output "Argument 'cmd' must not be empty" } @test "vedv::image_vedvfile_service::get_cmd_name() Should fail If there isn't 'cmd_name' in 'cmd'" { run vedv::image_vedvfile_service::get_cmd_name "echo Hello" - assert_failure "$ERR_INVAL_ARG" - assert_output "There isn't command name in 'echo Hello'" + assert_failure + assert_output "Command 'echo Hello' isn't supported, valid commands are: FROM|RUN|COPY|USER" } - +# bats test_tags=only @test "vedv::image_vedvfile_service::get_cmd_name() Should succeed With valid input" { run vedv::image_vedvfile_service::get_cmd_name " 1 FROM ubuntu:latest " diff --git a/dist/test/lib/vedv/hypervisors/virtualbox.bats b/dist/test/lib/vedv/hypervisors/virtualbox.bats index 6e84e09..f9f1824 100644 --- a/dist/test/lib/vedv/hypervisors/virtualbox.bats +++ b/dist/test/lib/vedv/hypervisors/virtualbox.bats @@ -353,8 +353,7 @@ ${snapshot_name2}" ( fix_var_names() { echo "$*"; } VBoxManage() { - echo 'var1=value1 -description="image_cache=value1 ova_file_sum=value2"' + echo 'image_cache=value1 ova_file_sum=value2' } run vedv::hypervisor::get_description 'vm_name' diff --git a/dist/test/lib/vedv/utils.bats b/dist/test/lib/vedv/utils.bats index 11bf33a..e8e0fb5 100644 --- a/dist/test/lib/vedv/utils.bats +++ b/dist/test/lib/vedv/utils.bats @@ -448,7 +448,6 @@ World!" assert_output "homefs/*" } -# bats test_tags=only @test "utils::get_arg_from_string(), Should returns the argument 2 'RUN' from a string uname..." { skip # This doesn't work with the current implementation run utils::get_arg_from_string "3 RUN uname -r > uname-r.txt" 2 @@ -606,7 +605,7 @@ calc_item_id_from_array_b() { echo "$1"; } } # Tests for utils::array::to_string() -# bats test_tags=only + @test "utils::array::to_string() Should succeed With empty array" { # shellcheck disable=SC2034 local -r arr=() @@ -621,3 +620,79 @@ calc_item_id_from_array_b() { echo "$1"; } assert_success assert_output "()" } + +# Test for utils::str_encode() +# bats test_tags=only +@test "utils::str_encode() Should succeed With empty string" { + local -r str="" + + run utils::str_encode "$str" + + assert_success + assert_output "" +} +# bats test_tags=only +@test "utils::str_encode() Should succeed With string without special characters" { + local -r str="foo" + + run utils::str_encode "$str" + + assert_success + assert_output "foo" +} +# bats test_tags=only +@test "utils::str_encode() Should succeed With string with special characters" { + local -r str="uname -r >uname-r.txt && echo 'Hello World' >hello.txt" + + run utils::str_encode "$str" + + assert_success + assert_output "uname -r >uname-r.txt && echo @*^&Hello World@*^& >hello.txt" +} +# bats test_tags=only +@test "utils::str_encode() Should succeed With string with special characters 2" { + local -r str='uname -r >uname-r.txt && echo "Hello World" >hello.txt' + + run utils::str_encode "$str" + + assert_success + assert_output "uname -r >uname-r.txt && echo *!@%Hello World*!@% >hello.txt" +} + +# Test for utils::str_decode() +# bats test_tags=only +@test "utils::str_decode() Should succeed With empty string" { + local -r str="" + + run utils::str_decode "$str" + + assert_success + assert_output "" +} +# bats test_tags=only +@test "utils::str_decode() Should succeed With string without special characters" { + local -r str="foo" + + run utils::str_decode "$str" + + assert_success + assert_output "foo" +} +# bats test_tags=only +@test "utils::str_decode() Should succeed With string with special characters" { + local -r str="uname -r >uname-r.txt && echo @*^&Hello World@*^& >hello.txt" + + run utils::str_decode "$str" + + assert_success + assert_output "uname -r >uname-r.txt && echo 'Hello World' >hello.txt" +} +# bats test_tags=only +@test "utils::str_decode() Should succeed With string with special characters 2" { + local -r str="uname -r >uname-r.txt && echo *!@%Hello World*!@% >hello.txt" + + run utils::str_decode "$str" + + assert_success + assert_output 'uname -r >uname-r.txt && echo "Hello World" >hello.txt' +} diff --git a/dist/test/test_helper_base.bash b/dist/test/test_helper_base.bash index 8e97d8c..3e35d95 100644 --- a/dist/test/test_helper_base.bash +++ b/dist/test/test_helper_base.bash @@ -30,9 +30,9 @@ if [[ ! -f "$TEST_OVA_FILE" ]]; then cd "${TEST_OVA_FILE%/*}" || exit - wget -O "${TEST_OVA_FILE##*/}" "https://onedrive.live.com/download?cid=DBA0B75F07574EAA&resid=DBA0B75F07574EAA%21143&authkey=ALcaVI4nu5k3K0I" + wget -O "${TEST_OVA_FILE##*/}" "https://onedrive.live.com/download?cid=DBA0B75F07574EAA&resid=DBA0B75F07574EAA%21159&authkey=AJ4qOHVxfQr9yUk" - wget -O "${TEST_OVA_FILE##*/}.sha256" "https://onedrive.live.com/download?cid=DBA0B75F07574EAA&resid=DBA0B75F07574EAA%21142&authkey=ABeSNyUyfAlEwX8" + wget -O "${TEST_OVA_FILE##*/}.sha256" "https://onedrive.live.com/download?cid=DBA0B75F07574EAA&resid=DBA0B75F07574EAA%21158&authkey=ABvQceLTCAmvJs0" sha256sum -c "${TEST_OVA_FILE##*/}.sha256" )