diff --git a/src/Dockerfile b/src/Dockerfile index 7a0131a47..480d44ea5 100644 --- a/src/Dockerfile +++ b/src/Dockerfile @@ -14,6 +14,7 @@ RUN apt-get update \ unzip \ wget \ python3 \ + sed \ python3-pip diff --git a/src/docs/ui-deployment.md b/src/docs/ui-deployment.md index 351e18151..b27aeced6 100644 --- a/src/docs/ui-deployment.md +++ b/src/docs/ui-deployment.md @@ -44,7 +44,7 @@ Here's the full list of parameters for reference: ```plaintext setup_ezdeploy.sh: Setup the front end for MLZ argument description - --docker-strategy -d [local|build|load] 'local' for localhost, 'build' to build from this repo, or 'load' to unzip an image + --docker-strategy -d [local|build|load|export] 'local' for localhost, 'build' to build from this repo, or 'load' to unzip an image, 'export' to build and create mlz.zip with the docker image --subscription-id -s Subscription ID for MissionLZ resources --location -l The location that you're deploying to (defaults to 'eastus') --tf-environment -e Terraform azurerm environment (defaults to 'public') see: https://www.terraform.io/docs/language/settings/backends/azurerm.html#environment @@ -56,6 +56,30 @@ setup_ezdeploy.sh: Setup the front end for MLZ --tier2-sub-id -2 subscription ID for tier 2 network and resources (defaults to the value provided for -s --subscription-id) ``` +### Step-by-Step Azure Air Gapped Installation + +This process closely mirrors the standard Azure documentation with a few subtle amendments. + +On your internet connected staging machine (With Docker Installed): + +Build the docker image needed for deployment: + +```BASH +cd src/scripts +./export_docker.sh +``` + +This will take some time by building the docker image, and then saving it to the scripts working directory and compressing it to "mlz.zip" + +Move this file along with the repo to the destination for airgapped deployment Then execute the following + +```BASH +cd src/scripts +./setup_ezdeploy.sh -d load -s -e "" -l "" +``` + +If desired both commands allow for the input of file names for exporting and for the load if the defaults are not sufficient. + ### Step-by-Step Local Installation Running the user interface on your local workstation is not our recommended approach because it requires more setup, but it works. diff --git a/src/scripts/container-registry/add_auth_scopes.sh b/src/scripts/container-registry/add_auth_scopes.sh index d69fa6a01..1fd159c41 100755 --- a/src/scripts/container-registry/add_auth_scopes.sh +++ b/src/scripts/container-registry/add_auth_scopes.sh @@ -108,7 +108,7 @@ wait_for_app_query_from_list "${mlz_fe_app_name}" "appId" echo "INFO: sourcing app registration information for app ID ${app_id}..." client_password=$(az ad app credential reset \ - --id ${app_id} \ + --id "${app_id}" \ --query password \ --only-show-errors \ --output tsv) diff --git a/src/scripts/export_docker.sh b/src/scripts/export_docker.sh new file mode 100644 index 000000000..87cbff3cb --- /dev/null +++ b/src/scripts/export_docker.sh @@ -0,0 +1,60 @@ +#!/bin/bash +# +# Copyright (c) Microsoft Corporation. +# Licensed under the MIT License. +# +# shellcheck disable=SC1083,SC1090,SC1091,2154 +# SC1083: This is literal. +# SC1090: Can't follow non-constant source. Use a directive to specify location. +# SC1091: Not following. Shellcheck can't follow non-constant source. +# SC2154: "var is referenced but not assigned". These values come from an external file. +# +# This script locally saves a local docker image for movement between airgapped networks. + +set -e + +error_log() { + echo "${1}" 1>&2; +} + +show_help() { + print_formatted() { + long_name=$1 + char_name=$2 + desc=$3 + printf "%20s %2s %s \n" "$long_name" "$char_name" "$desc" + } + print_formatted "argument" "" "description" + print_formatted "--output-file" "-f" "Output file name/location, defaults to same directory 'mlz.zip'" +} + +usage() { + echo "export_docker.sh: Builds MLZ UI and Templates into a dockerfile for movement to another network" + show_help +} + +# default file name +zip_file="mlz.zip" + +# inspect user input +while [ $# -gt 0 ] ; do + case $1 in + -f | --output-file) zip_file="$2" ;; + esac + shift +done + +# build/load, tag, and push image +this_script_path=$(realpath "${BASH_SOURCE%/*}") +src_path=$(dirname "${this_script_path}") +image_name="lzfront" +image_tag="latest" + +echo "INFO: building docker image" +docker build -t "${image_name}" "${src_path}" + +echo "INFO: Saving docker image and compressing it before exiting." +docker save "${image_name}:${image_tag}" -o mlz.tar +zip "${zip_file}" mlz.tar +rm mlz.tar +echo "INFO: Compressed deployable archive is saved locally as ${zip_file}." \ No newline at end of file diff --git a/src/scripts/setup_ezdeploy.sh b/src/scripts/setup_ezdeploy.sh index f667de614..d49700476 100755 --- a/src/scripts/setup_ezdeploy.sh +++ b/src/scripts/setup_ezdeploy.sh @@ -25,7 +25,7 @@ show_help() { printf "%20s %2s %s \n" "$long_name" "$char_name" "$desc" } print_formatted "argument" "" "description" - print_formatted "--docker-strategy" "-d" "[local|build|load] 'local' for localhost, 'build' to build from this repo, or 'load' to unzip an image (defaults to 'build')" + print_formatted "--docker-strategy" "-d" "[local|build|load]| 'local' for localhost, 'build' to build from this repo, or 'load' to unzip an image (defaults to 'build')" print_formatted "--subscription-id" "-s" "Subscription ID for MissionLZ resources" print_formatted "--location" "-l" "The location that you're deploying to (defaults to 'eastus')" print_formatted "--tf-environment" "-e" "Terraform azurerm environment (defaults to 'public') see: https://www.terraform.io/docs/language/settings/backends/azurerm.html#environment" @@ -34,6 +34,7 @@ show_help() { print_formatted "--tier0-sub-id" "-0" "subscription ID for tier 0 network and resources (defaults to the value provided for -s --subscription-id)" print_formatted "--tier1-sub-id" "-1" "subscription ID for tier 1 network and resources (defaults to the value provided for -s --subscription-id)" print_formatted "--tier2-sub-id" "-2" "subscription ID for tier 2 network and resources (defaults to the value provided for -s --subscription-id)" + print_formatted "--zip-file" "-f" "Zipped docker file for use with the load docker strategy, defaults to mlz.zip" } usage() { @@ -51,6 +52,7 @@ tf_environment="public" mlz_env_name="mlz${timestamp}" web_port="80" subs_args=() +zip_file="mlz.zip" # inspect user input while [ $# -gt 0 ] ; do @@ -65,6 +67,7 @@ while [ $# -gt 0 ] ; do -0 | --tier0-sub-id) subs_args+=("-0 ${2}") ;; -1 | --tier1-sub-id) subs_args+=("-1 ${2}") ;; -2 | --tier2-sub-id) subs_args+=("-2 ${2}") ;; + -f | --zip-file) zip_file="$2" ;; esac shift done @@ -96,6 +99,21 @@ if [[ $docker_strategy != "local" && \ exit 1 fi +# build/load, tag, and push image +image_name="lzfront" +image_tag="latest" + +if [[ $docker_strategy == "build" ]]; then + echo "INFO: building docker image" + docker build -t "${image_name}" "${src_path}" +fi + +if [[ $docker_strategy == "load" ]]; then + echo "INFO: Decompressing mlz zip archive and loading it to local docker image library." + unzip "${zip_file}" + docker load -i mlz.tar +fi + # switch to the MLZ subscription echo "INFO: setting current az cli subscription to ${mlz_config_subid}..." az account set --subscription "${mlz_config_subid}" @@ -149,19 +167,6 @@ fi # otherwise, create container registry "${container_registry_path}/create_acr.sh" "$mlz_config_file" -# build/load, tag, and push image -image_name="lzfront" -image_tag="latest" - -if [[ $docker_strategy == "build" ]]; then - docker build -t "${image_name}" "${src_path}" -fi - -if [[ $docker_strategy == "load" ]]; then - unzip mlz.zip . - docker load -i mlz.tar -fi - docker tag "${image_name}:${image_tag}" "${mlz_acr_name}${mlz_acrLoginServerEndpoint}/${image_name}:${image_tag}" docker push "${mlz_acr_name}${mlz_acrLoginServerEndpoint}/${image_name}:${image_tag}"