Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

validate input for Azure Region and Terraform Environment on deploy.sh and setup_ezdeploy.sh #174

Merged
merged 15 commits into from
Apr 26, 2021
Merged
37 changes: 32 additions & 5 deletions src/deploy.sh
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@
# Copyright (c) Microsoft Corporation.
# Licensed under the MIT License.
#
# shellcheck disable=1090,2154
# shellcheck disable=1091
# SC1091: Not following. Shellcheck can't follow non-constant source. These script are dynamically resolved.
#
# create all the configuration and deploy Terraform resources with minimal input

set -e
Expand Down Expand Up @@ -47,10 +49,16 @@ timestamp=$(date +%s)
##### generate an MLZ config file #####

# set helpful defaults that can be overridden or 'notset' for mandatory input
mlz_config_subid="notset"
mlz_config_location="eastus"
tf_environment="public"
mlz_env_name="mlz${timestamp}"
default_config_subid="notset"
default_config_location="eastus"
default_tf_environment="public"
default_env_name="mlz${timestamp}"

mlz_config_subid="${default_config_subid}"
mlz_config_location="${default_config_location}"
tf_environment="${default_tf_environment}"
mlz_env_name="${default_env_name}"

subs_args=()

# inspect user input
Expand Down Expand Up @@ -79,13 +87,32 @@ do
fi
done

# notify the user about any defaults
notify_of_default() {
argument_name=$1
argument_default=$2
argument_value=$3
if [[ "${argument_value}" = "${argument_default}" ]]; then
echo "INFO: using the default value '${argument_default}' for '${argument_name}', specify the '${argument_name}' argument to provide a different value."
fi
}
notify_of_default "--location" "${default_config_location}" "${mlz_config_location}"
notify_of_default "--tf-environment" "${default_tf_environment}" "${tf_environment}"
notify_of_default "--mlz-env-name" "${default_env_name}" "${mlz_env_name}"

# switch to the MLZ subscription
echo "INFO: setting current subscription to ${mlz_config_subid}..."
az account set \
--subscription "${mlz_config_subid}" \
--only-show-errors \
--output none

# validate that the location is present in the current cloud
"${this_script_path}/scripts/util/validateazlocation.sh" "${mlz_config_location}"

# validate that terraform environment matches for the current cloud
"${this_script_path}/scripts/terraform/validate_cloud_for_tf_env.sh" "${tf_environment}"

# retrieve tenant ID for the MLZ subscription
mlz_tenantid=$(az account show \
--query "tenantId" \
Expand Down
7 changes: 4 additions & 3 deletions src/docs/ui-deployment.md
Original file line number Diff line number Diff line change
Expand Up @@ -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|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
--docker-strategy -d [local|build|load] 'local' for localhost, 'build' to build from this repo, or 'load' to unzip an 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
Expand All @@ -54,11 +54,12 @@ setup_ezdeploy.sh: Setup the front end for MLZ
--tier0-sub-id -0 subscription ID for tier 0 network and resources (defaults to the value provided for -s --subscription-id)
--tier1-sub-id -1 subscription ID for tier 1 network and resources (defaults to the value provided for -s --subscription-id)
--tier2-sub-id -2 subscription ID for tier 2 network and resources (defaults to the value provided for -s --subscription-id)
--zip-file -f Zipped docker file for use with the 'load' docker strategy (defaults to 'mlz.zip')
```

### Step-by-Step Azure Air Gapped Installation

This process closely mirrors the standard Azure documentation with a few subtle amendments.
This process closely mirrors the standard Azure documentation with a few subtle amendments.

On your internet connected staging machine (With Docker Installed):

Expand All @@ -78,7 +79,7 @@ cd src/scripts
./setup_ezdeploy.sh -d load -s <subscription id> -e "<AZURE_ENVIRONMENT>" -l "<AZURE_LOCATION>"
```

If desired both commands allow for the input of file names for exporting and for the load if the defaults are not sufficient.
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

Expand Down
67 changes: 48 additions & 19 deletions src/scripts/setup_ezdeploy.sh
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,9 @@
# 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.
# shellcheck disable=SC1083,SC1091,2154
# SC1083: This is literal. We want to expand the items literally.
# SC1091: Not following. Shellcheck can't follow non-constant source. These script are dynamically resolved.
# SC2154: "var is referenced but not assigned". These values come from an external file.
#
# This script deploys container registries, app registrations, and a container instance to run the MLZ front end
Expand Down Expand Up @@ -34,7 +33,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"
print_formatted "--zip-file" "-f" "Zipped docker file for use with the 'load' docker strategy (defaults to 'mlz.zip')"
}

usage() {
Expand All @@ -45,15 +44,23 @@ usage() {
timestamp=$(date +%s)

# set helpful defaults that can be overridden or 'notset' for mandatory input
docker_strategy="build"
mlz_config_subid="notset"
mlz_config_location="eastus"
tf_environment="public"
mlz_env_name="mlz${timestamp}"
web_port="80"
subs_args=()

default_docker_strategy="build"
default_mlz_location="eastus"
default_tf_environment="public"
default_env_name="mlz${timestamp}"
default_web_port="80"

docker_strategy="${default_docker_strategy}"
mlz_config_location="${default_mlz_location}"
tf_environment="${default_tf_environment}"
mlz_env_name="${default_env_name}"
web_port="${default_web_port}"
zip_file="mlz.zip"

subs_args=()

# inspect user input
while [ $# -gt 0 ] ; do
case $1 in
Expand All @@ -77,10 +84,6 @@ this_script_path=$(realpath "${BASH_SOURCE%/*}")
src_path=$(dirname "${this_script_path}")
container_registry_path="$(realpath "${this_script_path}")/container-registry"

# check for dependencies
"${this_script_path}/util/checkforazcli.sh"
"${this_script_path}/util/checkfordocker.sh"

# check mandatory parameters
for i in { $docker_strategy $mlz_config_subid $mlz_config_location $tf_environment $mlz_env_name $web_port }
do
Expand All @@ -91,6 +94,36 @@ do
fi
done

# notify the user about any defaults
notify_of_default() {
argument_name=$1
argument_default=$2
argument_value=$3
if [[ "${argument_value}" = "${argument_default}" ]]; then
echo "INFO: using the default value '${argument_default}' for '${argument_name}', specify the '${argument_name}' argument to provide a different value."
fi

}
notify_of_default "--docker-strategy" "${default_docker_strategy}" "${docker_strategy}"
notify_of_default "--location" "${default_mlz_location}" "${mlz_config_location}"
notify_of_default "--tf-environment" "${default_tf_environment}" "${tf_environment}"
notify_of_default "--mlz-env-name" "${default_env_name}" "${mlz_env_name}"
notify_of_default "--port" "${default_web_port}" "${web_port}"

# check for dependencies
"${this_script_path}/util/checkforazcli.sh"
"${this_script_path}/util/checkfordocker.sh"

# switch to the MLZ subscription
echo "INFO: setting current az cli subscription to ${mlz_config_subid}..."
az account set --subscription "${mlz_config_subid}"

# validate that the location is present in the current cloud
"${this_script_path}/util/validateazlocation.sh" "${mlz_config_location}"

# validate that terraform environment matches for the current cloud
"${this_script_path}/terraform/validate_cloud_for_tf_env.sh" "${tf_environment}"

# check docker strategy
if [[ $docker_strategy != "local" && \
$docker_strategy != "build" && \
Expand All @@ -114,10 +147,6 @@ if [[ $docker_strategy == "load" ]]; then
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}"

# retrieve tenant ID for the MLZ subscription
mlz_tenantid=$(az account show \
--query "tenantId" \
Expand Down
58 changes: 58 additions & 0 deletions src/scripts/terraform/validate_cloud_for_tf_env.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
#!/bin/bash
#
# Copyright (c) Microsoft Corporation.
# Licensed under the MIT License.
#
# validate cloud matches known tf_environment values

set -e

error_log() {
echo "${1}" 1>&2;
}

usage() {
echo "validate_cloud_for_tf_env.sh: validate a given tf_environment matches the user's cloud"
error_log "usage: validate_cloud_for_tf_env.sh public"
}

this_script_path=$(realpath "${BASH_SOURCE%/*}")

# check for dependencies
"${this_script_path}/../util/checkforazcli.sh"

# inspect user input
if [[ "$#" -lt 1 ]]; then
usage
exit 1
fi

tf_env=$1
tf_env_lower=${tf_env,,} # ${var,,} syntax is to output a string as lowercase

current_cloud=$(az cloud show --query name --output tsv)
current_cloud_lower=${current_cloud,,} # ${var,,} syntax is to output a string as lowercase

# declare a dictionary of Terraform environment names and their clouds
# sourcing the valid combinations from here https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs#environment
declare -A tfenv_cloud_pairs
tfenv_cloud_pairs['public']='azurecloud'
tfenv_cloud_pairs['usgovernment']='azureusgovernment'
tfenv_cloud_pairs['german']='azuregermancloud'
tfenv_cloud_pairs['china']='azurechinacloud'
tfenv_cloud_pairs['ussec']='ussec'
tfenv_cloud_pairs['usnat']='usnat'

tf_env_is_valid=false

# if the dictionary does contain the environment and it maps to the current cloud, then we're good
if [[ ${tfenv_cloud_pairs["${tf_env_lower}"]} == "${current_cloud_lower}" ]]; then
tf_env_is_valid=true
fi

# otherwise, throw an error and exit
if [[ "${tf_env_is_valid}" = false ]]; then
error_log "ERROR: Terraform environment '${tf_env}' is not a valid environment for cloud '${current_cloud}'"
echo "INFO: check the valid settings for Terraform environment here: https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs#environment"
exit 1
fi
42 changes: 42 additions & 0 deletions src/scripts/util/validateazlocation.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
#!/bin/bash
#
# Copyright (c) Microsoft Corporation.
# Licensed under the MIT License.
#
# validate that a given location is present in a user's cloud

set -e

error_log() {
echo "${1}" 1>&2;
}

usage() {
echo "validateazlocation.sh: validate that a given location is present in a user's cloud"
error_log "usage: validateazlocation.sh eastus"
}

this_script_path=$(realpath "${BASH_SOURCE%/*}")

# check for dependencies
"${this_script_path}/checkforazcli.sh"

# inspect user input
if [[ "$#" -lt 1 ]]; then
usage
exit 1
fi

location=$1

current_cloud=$(az cloud show --query name --output tsv)
current_sub=$(az account show --query id --output tsv)
valid_locations=$(az account list-locations --query [].name --output tsv)

# if the active subscription does not support the given location, throw an error and exit
if ! echo "$valid_locations" | grep -iwq "${location}"; then
error_log "ERROR: could not find region '${location}' for subscription of '${current_sub}' in current cloud '${current_cloud}' "
echo "INFO: is this a valid region? Try 'az account list-locations' to see what regions are available to you."
echo "INFO: do you have the correct cloud set? Try 'az cloud set' to set it."
exit 1
fi