From 8feb754ddd8e18184e459533a455984fad9ead69 Mon Sep 17 00:00:00 2001 From: yunielrc87 Date: Sat, 21 Jan 2023 17:07:56 -0500 Subject: [PATCH] feat(container): add create container --- .../container/container-command.bash | 102 ++++++++++++++++-- .../container/container-service.bash | 96 ++++++++++++++++- .../container/container-command.bats | 56 ++++++++++ .../container/container-service.bats | 73 +++++++++++++ .../components/container/test_helper.bash | 5 + 5 files changed, 318 insertions(+), 14 deletions(-) create mode 100644 dist/test/lib/vedv/components/container/container-command.bats create mode 100644 dist/test/lib/vedv/components/container/container-service.bats create mode 100644 dist/test/lib/vedv/components/container/test_helper.bash diff --git a/dist/lib/vedv/components/container/container-command.bash b/dist/lib/vedv/components/container/container-command.bash index b144ea0..dafa117 100644 --- a/dist/lib/vedv/components/container/container-command.bash +++ b/dist/lib/vedv/components/container/container-command.bash @@ -4,6 +4,10 @@ # Process command line and call service # +# REQUIRE +# . '../../utils.bash' +# . './container-service.bash' + # VARIABLES # FUNCTIONS @@ -22,10 +26,72 @@ vedv::container_command::constructor() { } # -# IMPL: Create a new container +# Create a new container +# +# Flags: +# [-h | --help | help] Show help +# +# Options: +# [--name] Container name +# +# Arguments: +# IMAGE Image name or an OVF file +# +# Output: +# Writes container ID to the stdout +# +# Returns: +# 0 on success, non-zero on error. +# vedv::container_command::__create() { - echo 'vedv::container-command::__create' - vedv::container_service::create + local image + local name='' + + [[ $# == 0 ]] && set -- '-h' + + while [[ $# -gt 0 ]]; do + case "$1" in + -h | --help | help) + vedv::container_command::__create_help + return 0 + ;; + --name) + shift + name="$1" + shift + ;; + *) + if [[ -z "${image:-}" ]]; then + image="$1" + shift + else + echo -e "Invalid parameter: ${1}\n" >&2 + vedv::container_command::__create_help + return "$ERR_INVAL_ARG" + fi + ;; + esac + done + + vedv::container_service::create "$image" "${name:-}" +} + +# +# Show help for __create command +# +# Output: +# Writes the help to the stdout +# +vedv::container_command::__create_help() { + cat <<-HELPMSG +Usage: +${__VED_CONTAINER_COMMAND_SCRIPT_NAME} container create [OPTIONS] IMAGE + +Create a new container + +Options: + --name Assign a name to the container +HELPMSG } # IMPL: Start one or more stopped containers @@ -52,19 +118,37 @@ vedv::container_command::__run() { vedv::container_service::run } +# +# Show help +# +# Flags: +# [-s| --short] Print short description +# +# Output: +# Writes the help to the stdout +# vedv::container_command::__help() { - echo 'vedv::container_command::__help' + # if [[ "${1:-}" == @(-s|--short) ]]; then + # echo "${__VED_CONTAINER_COMMAND_SCRIPT_NAME} container Manage containers" + # return 0 + # fi + cat <<-HELPMSG +Usage: +${__VED_CONTAINER_COMMAND_SCRIPT_NAME} container COMMAND + +Manage containers + +Commands: + create Create a new container + +Run '${__VED_CONTAINER_COMMAND_SCRIPT_NAME} container COMMAND --help' for more information on a command. +HELPMSG } vedv::container_command::run_cmd() { [[ $# == 0 ]] && set -- '-h' - if [[ "${1:-}" == @(-h|--help) ]]; then - vedv::container_command::__help - return 0 - fi - while [[ $# -gt 0 ]]; do case "$1" in -h | --help | help) diff --git a/dist/lib/vedv/components/container/container-service.bash b/dist/lib/vedv/components/container/container-service.bash index d8b42bd..c03a1de 100644 --- a/dist/lib/vedv/components/container/container-service.bash +++ b/dist/lib/vedv/components/container/container-service.bash @@ -3,9 +3,11 @@ # # -# VARIABLES +# REQUIRE +# . '../../utils.bash' +# . '../image/image-service.bash' -__VEDV_CONTAINER_SERVICE_HYPERVISOR='' +# VARIABLES # FUNCTIONS @@ -22,10 +24,94 @@ vedv::container_service::constructor() { readonly __VEDV_CONTAINER_SERVICE_HYPERVISOR="$1" } -# IMPL: Create a new container +# +# Generate container vm name from a image vm name +# +# Arguments: +# image_vm_name image name +# +# Output: +# Writes generated name to the stdout +# +# Returns: +# 0 on success, non-zero on error. +# +vedv::container_service::__gen_container_vm_name_from_image_vm_name() { + local -r image_vm_name="$1" + + local container_name="${image_vm_name#'image:'}" + container_name="${container_name%'|crc'*}" + + local -r crc_sum="$(echo "$container_name" | cksum | cut -d' ' -f1)" + + local -r container_vm_name="container:${container_name}|crc:${crc_sum}" + + echo "$container_vm_name" +} + +# +# Generate container vm name +# +# Arguments: +# [container_name] container name +# +# Output: +# Writes generated name to the stdout +# +# Returns: +# 0 on success, non-zero on error. +# +vedv::container_service::__gen_container_vm_name() { + local container_name="${1:-}" + + if [[ -z "$container_name" ]]; then + container_name="$(petname)" + fi + + local -r crc_sum="$(echo "$container_name" | cksum | cut -d' ' -f1)" + local -r container_vm_name="container:${container_name}|crc:${crc_sum}" + + echo "$container_vm_name" +} + +# +# Create a new container +# +# Arguments: +# image image name or an OVF file +# container_name container name +# +# Output: +# Writes container ID to the stdout +# +# Returns: +# 0 on success, non-zero on error. +# vedv::container_service::create() { - echo 'vedv::container_service::create' - vedv::"$__VEDV_CONTAINER_SERVICE_HYPERVISOR"::container::create + local -r image="$1" + local -r container_name="${2:-}" + + # Import an OVF from a file or url + local -r image_vm_name=$(vedv::image_service::pull "$image") + local -r container_vm_name="$(vedv::container_service::__gen_container_vm_name "$container_name")" + + if [[ -n "$(vedv::"$__VEDV_IMAGE_SERVICE_HYPERVISOR"::list_wms_by_partial_name "$container_vm_name")" ]]; then + err "container with name: '${container_name}' already exist" + return "$ERR_VM_EXIST" + fi + + # create a vm snapshoot, the snapshoot is the container + local output + local -i ecode=0 + output="$(vedv::"$__VEDV_CONTAINER_SERVICE_HYPERVISOR"::clonevm_link "$image_vm_name" "$container_vm_name" 2>&1)" || ecode=$? + + if [[ $ecode -eq 0 ]]; then + echo "$container_vm_name" + else + err "$output" + fi + + return $ecode } # IMPL: Start one or more stopped containers diff --git a/dist/test/lib/vedv/components/container/container-command.bats b/dist/test/lib/vedv/components/container/container-command.bats new file mode 100644 index 0000000..04553b9 --- /dev/null +++ b/dist/test/lib/vedv/components/container/container-command.bats @@ -0,0 +1,56 @@ +# shellcheck disable=SC2016 +load test_helper + +setup_file() { + vedv::container_command::constructor 'vedv' + export __VED_CONTAINER_COMMAND_SCRIPT_NAME +} + +vedv::container_service::create() { echo "container created, arguments: $*"; } + +@test "vedv::container_command::__create(), with arg '-h|--help|help' should show help" { + local -r help_output='vedv container create [OPTIONS] IMAGE' + + run vedv::container_command::__create -h + + assert_success + assert_output --partial "$help_output" + + run vedv::container_command::__create --help + + assert_success + assert_output --partial "$help_output" + + run vedv::container_command::__create help + + assert_success + assert_output --partial "$help_output" + +} + +@test 'vedv::container_command::__create(), should create a container' { + local image_file="$TEST_OVA_FILE" + + run vedv::container_command::__create "$image_file" + + assert_success + assert_output 'container created, arguments: /tmp/vedv/test/files/alpine-x86_64.ova ' +} + +@test 'vedv::container_command::__create(), with --name should create a container' { + local container_name='super-llama-testunit-container-command' + local image_file="$TEST_OVA_FILE" + + run vedv::container_command::__create --name "$container_name" "$image_file" + + assert_success + assert_output 'container created, arguments: /tmp/vedv/test/files/alpine-x86_64.ova super-llama-testunit-container-command' +} + +@test "vedv::container_command::__create(), with invalid arg throw an error" { + + run vedv::container_command::__create 'image_file' 'invalid_arg' + + assert_failure 69 + assert_output --partial 'Invalid parameter: invalid_arg' +} diff --git a/dist/test/lib/vedv/components/container/container-service.bats b/dist/test/lib/vedv/components/container/container-service.bats new file mode 100644 index 0000000..42375a7 --- /dev/null +++ b/dist/test/lib/vedv/components/container/container-service.bats @@ -0,0 +1,73 @@ +# shellcheck disable=SC2016 +load test_helper + +setup_file() { + vedv::container_service::constructor 'virtualbox' + vedv::image_service::constructor 'virtualbox' + + export __VEDV_CONTAINER_SERVICE_HYPERVISOR + export __VEDV_IMAGE_SERVICE_HYPERVISOR +} + +teardown() { + delete_vms_by_partial_vm_name 'testunit-container-service' + delete_vms_by_partial_vm_name 'image:alpine-x86_64|crc:87493131' +} + +@test "vedv::container_service::__gen_container_vm_name_from_image_vm_name(), with 'image_vm_name' unset should throw an error" { + run vedv::container_service::__gen_container_vm_name_from_image_vm_name + + assert_failure 1 + assert_output --partial '$1: unbound variable' +} + +@test "vedv::container_service::__gen_container_vm_name_from_image_vm_name(), should generate the name" { + local image_vm_name='image:base-image|crc:261268494' + run vedv::container_service::__gen_container_vm_name_from_image_vm_name "$image_vm_name" + + assert_success + assert_output 'container:base-image|crc:261268494' +} + +@test "vedv::container_service::__gen_container_vm_name, should generate the name" { + petname() { echo 'tintin-pet'; } + run vedv::container_service::__gen_container_vm_name + + assert_success + assert_output 'container:tintin-pet|crc:1823374605' +} + +@test "vedv::container_service::__gen_container_vm_name, with name, should generate the name" { + local -r container_name='rinti-love' + run vedv::container_service::__gen_container_vm_name "$container_name" + + assert_success + assert_output 'container:rinti-love|crc:1085124909' +} + +@test "vedv::container_service::create, with name unset, should throw an error" { + run vedv::container_service::create + + assert_failure 1 + assert_output --partial '$1: unbound variable' +} + +@test "vedv::container_service::create, should create a container vm" { + local -r image="$TEST_OVA_FILE" + local -r container_name='happy-dyli-testunit-container-service' + run vedv::container_service::create "$image" "$container_name" + + assert_success + assert_output 'container:happy-dyli-testunit-container-service|crc:2520159523' +} + +@test "vedv::container_service::create, should throw error if there is another container with the same name" { + local -r image="$TEST_OVA_FILE" + local -r container_name='happy-dyli-testunit-container-service' + + vedv::container_service::create "$image" "$container_name" + run vedv::container_service::create "$image" "$container_name" + + assert_failure 80 + assert_output "container with name: 'happy-dyli-testunit-container-service' already exist" +} diff --git a/dist/test/lib/vedv/components/container/test_helper.bash b/dist/test/lib/vedv/components/container/test_helper.bash new file mode 100644 index 0000000..fab3acc --- /dev/null +++ b/dist/test/lib/vedv/components/container/test_helper.bash @@ -0,0 +1,5 @@ +. "${DIST_PATH}/test/test_helper_base.bash" +. "${DIST_PATH}/lib/vedv/hypervisors/virtualbox.bash" +. "${DIST_PATH}/lib/vedv/components/image/image-service.bash" +. "${DIST_PATH}/lib/vedv/components/container/container-service.bash" +. "${DIST_PATH}/lib/vedv/components/container/container-command.bash"