diff --git a/Dockerfile b/Dockerfile index e3a8f557..6d38357e 100644 --- a/Dockerfile +++ b/Dockerfile @@ -21,6 +21,8 @@ ENV PLUGIN_AZURERM=0.2.2 ENV PLUGIN_NULL=1.0.0 ENV PLUGIN_CLOUDFLARE=0.1.0 ENV PLUGIN_TEMPLATE=1.0.0 +# Pip version +ENV PIP=9.0.3 # Install with apt and pip RUN apt-get update -y && apt-get install -y \ @@ -33,6 +35,7 @@ RUN apt-get update -y && apt-get install -y \ libffi-dev \ openssl \ python-pip \ + qemu-utils \ unzip && \ `# Add google cloud` \ echo "deb http://packages.cloud.google.com/apt cloud-sdk-xenial main" \ @@ -41,9 +44,8 @@ RUN apt-get update -y && apt-get install -y \ | apt-key add - && \ apt-get update -y && apt-get install -y \ google-cloud-sdk="$GOOGLE_CLOUD_SDK_VERSION" && \ - `# Pip` \ - pip install --no-cache-dir --upgrade \ - pip && \ + `# Upgrade pip and install pip deps` \ + pip install --no-cache-dir --upgrade pip=="${PIP}" && \ pip install --no-cache-dir \ ansible=="$ANSIBLE_VERSION" \ j2cli=="$J2CLI_VERSION" \ diff --git a/bin/image-create-openstack.sh b/bin/image-create-openstack.sh index 1af8f93f..99629c1a 100755 --- a/bin/image-create-openstack.sh +++ b/bin/image-create-openstack.sh @@ -1,101 +1,40 @@ #!/usr/bin/env bash # Checks and uploads specified Image to user's OpenStack account. -# Downloads image first from an Amazon S3 storage account to host, -# then uploads image to openstack teenancy. -# Uses curl and python-glanceclient to do the job. +# +# 1. Downloads image first from an Amazon S3 storage (using curl and python-glance client) +# +# 2. Converts the image to the required format (if needed) +# +# 3. Uploads image to openstack tenancy. (using curl and python-glance client) +# +# # # Env vars +# # KN_IMAGE_NAME +# KN_DISC_FORMAT # KN_IMAGE_BUCKET_URL - +# # Exit immediately if a command exits with a non-zero status + set -e +source ./bin/openstack/functions.sh +KN_IMAGE_BUCKET_URL=${KN_IMAGE_BUCKET_URL:-"https://s3.eu-central-1.amazonaws.com/kubenow-eu-central-1"} + echo "Started script image-create-openstack" -if [ -z "$KN_IMAGE_NAME" ]; then +if [ -z "${KN_IMAGE_NAME}" ]; then echo >&2 "env KN_IMAGE_NAME must be set for this script to run" exit 1 fi -KN_IMAGE_BUCKET_URL=${KN_IMAGE_BUCKET_URL:-"https://s3.eu-central-1.amazonaws.com/kubenow-eu-central-1"} -file_name="$KN_IMAGE_NAME.qcow2" - -# Check if image is present already -echo "List images available in OpenStack..." -image_list="$(glance image-list)" -image_id="$(printf '%s' "$image_list" | - grep "\s$KN_IMAGE_NAME\s" | - awk -F "|" '{print $2;}' | - tr -d '[:space:]')" - -# If it doesn't exist then download it -if [ -z "$image_id" ]; then - echo "Image not present in OpenStack" - echo "Downloading image to local /tmp/" - curl "$KN_IMAGE_BUCKET_URL/$file_name" \ - -o "/tmp/$file_name" \ - --connect-timeout 30 \ - --max-time 1800 - - echo "Download md5 sum file" - curl "$KN_IMAGE_BUCKET_URL/$file_name.md5" \ - -o "/tmp/$file_name.md5" \ - --connect-timeout 30 \ - --max-time 1800 - - echo "Check md5 sum" - md5only=$(cut -f1 -d ' ' "/tmp/$file_name.md5") - printf '%s' "$md5only /tmp/$file_name" | md5sum -c -else - echo "File exists - no need to download" -fi - -# If it didn't exist then upload it -if [ -z "$image_id" ]; then - echo "Uploading image" - glance image-create \ - --file "/tmp/$file_name" \ - --disk-format qcow2 \ - --min-disk 20 \ - --container-format bare \ - --name "$KN_IMAGE_NAME" \ - --progress -else - echo "file exists - no need to upload" -fi - -echo "Verify md5 of present/uploaded image..." -echo "List images available in OpenStack..." -image_list="$(glance image-list)" -image_id="$(printf '%s' "$image_list" | - grep "\s$KN_IMAGE_NAME\s" | - awk -F "|" '{print $2;}' | - tr -d '[:space:]')" - -# Get checksum of uploaded file -image_details="$(glance image-show "$image_id")" -checksum="$(printf '%s' "$image_details" | - grep -w "checksum" | - awk -F "|" '{print $3;}' | - tr -d '[:space:]')" - -# Get checksum of bucket image -echo "Download md5 sum file" -curl "$KN_IMAGE_BUCKET_URL/$file_name.md5" \ - -o "/tmp/$file_name.md5" \ - --connect-timeout 30 \ - --max-time 1800 - -md5only=$(cut -f1 -d ' ' "/tmp/$file_name.md5") -if [ "$md5only" != "$checksum" ]; then - echo >&2 "Wrong checksum of present/uploaded image." - echo >&2 "Something might have failed on file transfer." - echo >&2 "Please delete image $KN_IMAGE_NAME from Openstack and try again." +if [ -z "${KN_DISC_FORMAT}" ]; then + echo >&2 "env KN_DISC_FORMAT must be set for this script to run" exit 1 -else - echo "Checksum OK" fi -echo "Image upload done" +maybe_download_image "${KN_IMAGE_NAME}" "${KN_DISC_FORMAT}" "${KN_IMAGE_BUCKET_URL}" +maybe_convert_image "${KN_IMAGE_NAME}" "${KN_DISC_FORMAT}" +maybe_upload_image "${KN_IMAGE_NAME}" "${KN_DISC_FORMAT}" "${KN_IMAGE_BUCKET_URL}" \ No newline at end of file diff --git a/bin/kn-apply b/bin/kn-apply index 8c21bbbc..3aeac451 100755 --- a/bin/kn-apply +++ b/bin/kn-apply @@ -11,6 +11,10 @@ image_name=$(grep -w "boot_image" terraform.tfvars | cut -d "=" -f 2- | awk -F\" '{print $(NF-1)}') +disc_format=$(grep -w "disc_format" terraform.tfvars | + cut -d "=" -f 2- | + awk -F\" '{print $(NF-1)}') + # Check for recognized cloud provider if ! grep -qw "$host_cloud" <<<"openstack gce azure aws"; then echo >&2 "Error: unrecognized host cloud '$host_cloud' in config file terraform.tfvars" @@ -22,6 +26,7 @@ if [ "$host_cloud" = 'openstack' ] || [ "$host_cloud" = 'gce' ] || [ "$host_clou export KN_GCE_ACCOUNT_FILE_PATH="$PWD/service-account.json" export TF_VARS_FILE="$PWD/terraform.tfvars" export KN_IMAGE_NAME="$image_name" + export KN_DISC_FORMAT="$disc_format" /KubeNow_root/bin/image-create-"$host_cloud".sh fi diff --git a/bin/openstack/functions.sh b/bin/openstack/functions.sh new file mode 100644 index 00000000..b0a5ef5b --- /dev/null +++ b/bin/openstack/functions.sh @@ -0,0 +1,247 @@ +#!/usr/bin/env bash + +function is_image_downloaded_already() { + local download_filepath=$1 + + if [[ -e ${download_filepath} ]]; then + echo "true" + else + echo "false" + fi +} + +function is_image_already_uploaded() { + local image_name=$1 + local disc_format=$2 + local image_id + local upload_filename + upload_filename="${image_name}.${disc_format}" + image_id=$(get_image_id "${upload_filename}") + + # If the image exists, return true, otherwise return false + if [[ "${image_id}" == "" ]]; then + echo "false" + else + echo "true" + fi +} + +function wait_for_image_activation() { + local upload_filename=$1; + local wait_time + local max_wait + local sleep_time + local status + wait_time=0 + max_wait=300 + sleep_time=3 + status="nothing" + + # Wait until image status is "active" + while [[ "${status}" != "active" && ${wait_time} -lt ${max_wait} ]]; do + # allow for image to be ready + sleep ${sleep_time} + wait_time=$((wait_time + sleep_time)) + status=$(get_image_status "${upload_filename}") + done + + echo "${status}" +} + +function get_image_status() { + local upload_filename=$1; + local image_id + local image_details + image_id=$(get_image_id "${upload_filename}") + image_details="$(glance image-show "${image_id}")" + + printf '%s' "${image_details}" | + grep -w "status" | + awk -F "|" '{print $3;}' | + tr -d '[:space:]' +} + +function get_image_id() { + local upload_filename=$1; + local image_list + image_list="$(glance image-list)" + + printf '%s' "${image_list}" | + grep "${upload_filename}" | + awk -F "|" '{print $2;}' | + tr -d '[:space:]' +} + +function get_image_checksum() { + local image_id=$1; + local image_details + image_details="$(glance image-show "${image_id}")" + + printf '%s' "${image_details}" | + grep -w "checksum" | + awk -F "|" '{print $3;}' | + tr -d '[:space:]' +} + +function verify_uploaded_image() { + local image_name=$1 + local disc_format=$2 + local image_url=$3 + local upload_filename="${image_name}.${disc_format}" + local upload_filepath="/tmp/${image_name}.${disc_format}" + local image_list + local image_id + local image_details + local checksum + local md5only + image_id=$(get_image_id "${upload_filename}") + checksum=$(get_image_checksum "${image_id}") + + if [[ ${#checksum} != 32 ]]; then + echo "No valid checksum field on server, skipping checksum verification" + else + # Get checksum of bucket image + echo "Download md5 sum file" + curl "${image_url}/${upload_filename}.md5" \ + -o "${upload_filepath}.md5" \ + --connect-timeout 30 \ + --max-time 30 + + md5only=$(cut -f1 -d ' ' "${upload_filepath}.md5") + if [ "${md5only}" != "${checksum}" ]; then + echo >&2 "Wrong checksum of present/uploaded image." + echo >&2 "Something might have failed on file transfer." + echo >&2 "Please delete image ${image_name} from Openstack and try again." + exit 1 + else + echo "Checksum OK" + fi + fi +} + +function upload_image() { + local image_name=$1 + local disc_format=$2 + local image_url=$3 + local upload_filename="${image_name}.${disc_format}" + local upload_filepath="/tmp/${image_name}.${disc_format}" + local min_disc=20 + local image_size + local image_size_number + image_size=$(du -sh --block-size=G --apparent-size LICENSE | awk '{print $1}') + image_size_number=$(echo "${image_size::-1}") + + if [[ "${disc_format}" == "raw" ]]; then + min_disc=${image_size_number}; + fi + + # Upload image + echo "Uploading ${upload_filename} with size ${image_size}B" + glance image-create \ + --file "${upload_filepath}" \ + --disk-format "${disc_format}" \ + --min-disk ${min_disc} \ + --container-format bare \ + --name "${image_name}" \ + --progress + + verify_uploaded_image "${image_name}" "${disc_format}" "${image_url}" +} + +function verify_downloaded_image() { + local download_filename=$1 + local download_url=$2 + local download_filepath="/tmp/${download_filename}" + + echo "Download md5 sum file" + curl "${download_url}/${download_filename}.md5" \ + -o "${download_filepath}.md5" \ + --connect-timeout 30 \ + --max-time 30 + + # Verify md5sum of downloaded file + echo "Check md5 sum" + md5result=$( + cd /tmp || exit; + md5sum -c "${download_filename}.md5" + ) + if [[ "${md5result}" != *": OK"* ]]; then + echo >&2 "Wrong checksum of downloaded image." + echo >&2 "Something might have failed on file transfer." + echo >&2 "Please try again." + exit 1 + else + echo "Checksum of downloaded image OK" + fi +} + +function download_image() { + local download_filename=$1 + local download_url=$2 + local download_filepath="/tmp/${download_filename}" + + echo "Downloading image to local /tmp/" + curl "${download_url}/${download_filename}" \ + -o "${download_filepath}" \ + --connect-timeout 30 \ + --max-time 1800 + + verify_downloaded_image "${download_filename}" "${download_url}" +} + +function maybe_download_image(){ + local image_name=$1 + local disc_format=$2 + local download_url=$3 + local download_filename="${image_name}.qcow2" + local download_filepath="/tmp/${image_name}.qcow2" + local is_image_downloaded_already + is_image_downloaded_already=$(is_image_downloaded_already "${download_filepath}") + + if [[ "${is_image_downloaded_already}" == "false" ]]; then + download_image "${download_filename}" "${download_url}" + else + echo "${download_filename} is already downloaded" + + verify_downloaded_image "${download_filename}" "${download_url}" + fi +} + +function maybe_convert_image(){ + local image_name=$1 + local disc_format=$2 + local download_filename="${image_name}.qcow2" + local download_filepath="/tmp/${image_name}.qcow2" + local upload_filename="${image_name}.${disc_format}" + local upload_filepath="/tmp/${upload_filename}" + local qemu_installed + qemu_installed=$(which qemu-img) + + if [[ ! -e ${upload_filepath} ]]; then + if [[ "${qemu_installed}" == "" ]]; then + echo >&2 "qemu-utils package is missing - image cannot be converted" + echo >&2 "Please ensure that qemu-img is available." + exit 1 + else + qemu-img convert -q -f qcow2 -O "${disc_format}" "${download_filepath}" "${upload_filepath}" + fi + else + echo "${upload_filepath} already exists and so does not require conversion, moving onto upload step" + fi +} + +function maybe_upload_image() { + local image_name=$1 + local disc_format=$2 + local image_url=$3 + local upload_filename="${image_name}.${disc_format}" + local is_image_uploaded + is_image_uploaded=$(is_image_already_uploaded "${image_name}" "${disc_format}") + + if [[ "${is_image_uploaded}" == "false" ]]; then + maybe_convert_image "${image_name}" "${disc_format}" + upload_image "${image_name}" "${disc_format}" "${image_url}" + else + echo "${upload_filename} is already uploaded" + fi +} \ No newline at end of file diff --git a/templates/terraform.tfvars.openstack-template b/templates/terraform.tfvars.openstack-template index 33d8744d..259ad284 100644 --- a/templates/terraform.tfvars.openstack-template +++ b/templates/terraform.tfvars.openstack-template @@ -5,6 +5,7 @@ kubeadm_token = "your-kubeadm-token" # Autogenerated kubeadm token (don't change floating_ip_pool = "your-pool-name" external_network_uuid = "external-net-uuid" # The uuid of the external network in the OpenStack tenancy boot_image = "kubenow-v050" +disc_format = "raw" # Master configuration # obs: too small flavors might cause diffuse errors on your installation