From e56d98748fa0a51c6d20c5fc8dcdbbd0a24f170c Mon Sep 17 00:00:00 2001 From: Michael Li Date: Fri, 15 Dec 2023 13:08:29 -0500 Subject: [PATCH] chore(e2e): Add docker-based scenario for Admin UI tests --- .github/workflows/enos-run.yml | 12 +- ...2e-ui.hcl => enos-scenario-e2e-ui-aws.hcl} | 59 ++---- enos/enos-scenario-e2e-ui-docker.hcl | 185 ++++++++++++++++++ enos/modules/test_e2e_ui/main.tf | 80 +++++--- enos/scripts/test_e2e_env.sh | 1 - 5 files changed, 260 insertions(+), 77 deletions(-) rename enos/{enos-scenario-e2e-ui.hcl => enos-scenario-e2e-ui-aws.hcl} (77%) create mode 100644 enos/enos-scenario-e2e-ui-docker.hcl diff --git a/.github/workflows/enos-run.yml b/.github/workflows/enos-run.yml index 0c8af20871..1502d41d12 100644 --- a/.github/workflows/enos-run.yml +++ b/.github/workflows/enos-run.yml @@ -187,7 +187,7 @@ jobs: run: | wget https://releases.hashicorp.com/vault/1.12.2/vault_1.12.2_linux_amd64.zip -O /tmp/test-deps/vault.zip - name: Install Vault CLI - if: contains(matrix.filter, 'vault') || contains(matrix.filter, 'e2e_docker') || matrix.filter == 'e2e_database' || matrix.filter == 'e2e_ui builder:crt' + if: contains(matrix.filter, 'vault') || contains(matrix.filter, 'e2e_docker') || matrix.filter == 'e2e_database' || matrix.filter == 'e2e_ui_aws builder:crt' run: | unzip /tmp/test-deps/vault.zip -d /usr/local/bin - name: GH fix for localhost resolution @@ -220,20 +220,20 @@ jobs: mv ${{ steps.download-docker.outputs.download-path }}/*.tar enos/support/boundary_docker_image.tar - name: Set up Node.js uses: actions/setup-node@8f152de45cc393bb48ce5d89d36b731f54556e65 # v4.0.0 - if: matrix.filter == 'e2e_ui builder:crt' + if: contains(matrix.filter, 'e2e_ui') with: node-version: '16.x' - name: Checkout boundary-ui uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - if: matrix.filter == 'e2e_ui builder:crt' + if: contains(matrix.filter, 'e2e_ui') with: repository: hashicorp/boundary-ui path: enos/support/src/boundary-ui - name: Install boundary-ui dependencies - if: matrix.filter == 'e2e_ui builder:crt' + if: contains(matrix.filter, 'e2e_ui') run: yarn --cwd enos/support/src/boundary-ui install - name: Install playwright dependencies (i.e. browsers) - if: matrix.filter == 'e2e_ui builder:crt' + if: contains(matrix.filter, 'e2e_ui') run: npx playwright install --with-deps working-directory: enos/support/src/boundary-ui - name: Output Terraform version info @@ -274,7 +274,7 @@ jobs: run: | docker logs database - name: Upload e2e UI tests debug info - if: matrix.filter == 'e2e_ui builder:crt' && steps.run.outcome == 'failure' + if: contains(matrix.filter, 'e2e_ui') && steps.run.outcome == 'failure' uses: actions/upload-artifact@a8a3f3ad30e3422c9c7b888a15615d19a852ae32 # v3.1.3 with: name: test-e2e-ui-debug diff --git a/enos/enos-scenario-e2e-ui.hcl b/enos/enos-scenario-e2e-ui-aws.hcl similarity index 77% rename from enos/enos-scenario-e2e-ui.hcl rename to enos/enos-scenario-e2e-ui-aws.hcl index 20d04d4830..7fc088e015 100644 --- a/enos/enos-scenario-e2e-ui.hcl +++ b/enos/enos-scenario-e2e-ui-aws.hcl @@ -1,7 +1,7 @@ # Copyright (c) HashiCorp, Inc. # SPDX-License-Identifier: BUSL-1.1 -scenario "e2e_ui" { +scenario "e2e_ui_aws" { terraform_cli = terraform_cli.default terraform = terraform.default providers = [ @@ -123,21 +123,21 @@ scenario "e2e_ui" { } } - step "create_tag1" { + step "create_tag" { module = module.random_stringifier } - step "create_tag1_inputs" { + step "create_tag_inputs" { module = module.generate_aws_host_tag_vars - depends_on = [step.create_tag1] + depends_on = [step.create_tag] variables { - tag_name = step.create_tag1.string + tag_name = step.create_tag.string tag_value = "true" } } - step "create_targets_with_tag1" { + step "create_targets_with_tag" { module = module.aws_target depends_on = [step.create_base_infra] @@ -148,37 +148,7 @@ scenario "e2e_ui" { instance_type = var.target_instance_type vpc_id = step.create_base_infra.vpc_id target_count = 2 - additional_tags = step.create_tag1_inputs.tag_map - subnet_ids = step.create_boundary_cluster.subnet_ids - } - } - - step "create_tag2" { - module = module.random_stringifier - } - - step "create_tag2_inputs" { - module = module.generate_aws_host_tag_vars - depends_on = [step.create_tag2] - - variables { - tag_name = step.create_tag2.string - tag_value = "test" - } - } - - step "create_targets_with_tag2" { - module = module.aws_target - depends_on = [step.create_base_infra] - - variables { - ami_id = step.create_base_infra.ami_ids["ubuntu"]["amd64"] - aws_ssh_keypair_name = var.aws_ssh_keypair_name - enos_user = var.enos_user - instance_type = var.target_instance_type - vpc_id = step.create_base_infra.vpc_id - target_count = 1 - additional_tags = step.create_tag2_inputs.tag_map + additional_tags = step.create_tag_inputs.tag_map subnet_ids = step.create_boundary_cluster.subnet_ids } } @@ -203,12 +173,11 @@ scenario "e2e_ui" { } } - step "run_e2e_ui_test" { + step "run_e2e_test" { module = module.test_e2e_ui depends_on = [ step.create_boundary_cluster, - step.create_targets_with_tag1, - step.create_targets_with_tag2, + step.create_targets_with_tag, step.iam_setup, step.create_vault_cluster ] @@ -222,21 +191,19 @@ scenario "e2e_ui" { local_boundary_dir = local.local_boundary_dir local_boundary_ui_src_dir = local.local_boundary_ui_src_dir aws_ssh_private_key_path = local.aws_ssh_private_key_path - target_address = step.create_targets_with_tag1.target_ips[0] + target_address = step.create_targets_with_tag.target_ips[0] target_user = "ubuntu" target_port = "22" vault_addr = step.create_vault_cluster.instance_public_ips[0] vault_root_token = step.create_vault_cluster.vault_root_token aws_access_key_id = step.iam_setup.access_key_id aws_secret_access_key = step.iam_setup.secret_access_key - aws_host_set_filter1 = step.create_tag1_inputs.tag_string - aws_host_set_ips1 = step.create_targets_with_tag1.target_ips - aws_host_set_filter2 = step.create_tag2_inputs.tag_string - aws_host_set_ips2 = step.create_targets_with_tag2.target_ips + aws_host_set_filter = step.create_tag_inputs.tag_string + aws_host_set_ips = step.create_targets_with_tag.target_ips } } output "test_results" { - value = step.run_e2e_ui_test.test_results + value = step.run_e2e_test.test_results } } diff --git a/enos/enos-scenario-e2e-ui-docker.hcl b/enos/enos-scenario-e2e-ui-docker.hcl new file mode 100644 index 0000000000..0e27c39d08 --- /dev/null +++ b/enos/enos-scenario-e2e-ui-docker.hcl @@ -0,0 +1,185 @@ +# Copyright (c) HashiCorp, Inc. +# SPDX-License-Identifier: BUSL-1.1 + +# For this scenario to work, add the following line to /etc/hosts +# 127.0.0.1 localhost boundary + +scenario "e2e_ui_docker" { + terraform_cli = terraform_cli.default + terraform = terraform.default + providers = [ + provider.enos.default + ] + + matrix { + builder = ["local", "crt"] + } + + locals { + aws_ssh_private_key_path = abspath(var.aws_ssh_private_key_path) + local_boundary_dir = abspath(var.local_boundary_dir) + local_boundary_ui_src_dir = abspath(var.local_boundary_ui_src_dir) + boundary_docker_image_file = abspath(var.boundary_docker_image_file) + license_path = abspath(var.boundary_license_path != null ? var.boundary_license_path : joinpath(path.root, "./support/boundary.hclic")) + + network_cluster = "e2e_cluster" + + build_path = { + "local" = "/tmp", + "crt" = var.crt_bundle_path == null ? null : abspath(var.crt_bundle_path) + } + tags = merge({ + "Project Name" : var.project_name + "Project" : "Enos", + "Environment" : "ci" + }, var.tags) + } + + step "build_boundary_docker_image" { + module = matrix.builder == "crt" ? module.build_boundary_docker_crt : module.build_boundary_docker_local + + variables { + path = matrix.builder == "crt" ? local.boundary_docker_image_file : "" + cli_build_path = local.build_path[matrix.builder] + edition = var.boundary_edition + } + } + + step "create_docker_network" { + module = module.docker_network + variables { + network_name = local.network_cluster + } + } + + step "create_boundary_database" { + depends_on = [ + step.create_docker_network + ] + variables { + image_name = "${var.docker_mirror}/library/postgres:latest" + network_name = [local.network_cluster] + } + module = module.docker_postgres + } + + step "read_license" { + skip_step = var.boundary_edition == "oss" + module = module.read_license + + variables { + file_name = local.license_path + } + } + + step "create_boundary" { + module = module.docker_boundary + depends_on = [ + step.create_docker_network, + step.create_boundary_database, + step.build_boundary_docker_image + ] + variables { + image_name = matrix.builder == "crt" ? var.boundary_docker_image_name : step.build_boundary_docker_image.image_name + network_name = [local.network_cluster] + database_network = local.network_cluster + postgres_address = step.create_boundary_database.address + boundary_license = var.boundary_edition != "oss" ? step.read_license.license : "" + } + } + + step "create_vault" { + module = module.docker_vault + depends_on = [ + step.create_docker_network + ] + variables { + image_name = "${var.docker_mirror}/hashicorp/vault:${var.vault_version}" + network_name = [local.network_cluster] + } + } + + step "create_host" { + module = module.docker_openssh_server + depends_on = [ + step.create_docker_network + ] + variables { + image_name = "${var.docker_mirror}/linuxserver/openssh-server:latest" + network_name = [local.network_cluster] + private_key_file_path = local.aws_ssh_private_key_path + } + } + + locals { + egress_tag = "egress" + } + + step "create_worker" { + module = module.docker_worker + depends_on = [ + step.create_docker_network, + step.build_boundary_docker_image, + step.create_boundary + ] + variables { + image_name = matrix.builder == "crt" ? var.boundary_docker_image_name : step.build_boundary_docker_image.image_name + boundary_license = var.boundary_edition != "oss" ? step.read_license.license : "" + config_file = "worker-config-worker-led.hcl" + container_name = "worker" + initial_upstream = step.create_boundary.upstream_address + network_name = [local.network_cluster] + tags = [local.egress_tag] + port = "9402" + worker_led_registration = true + } + } + + // !! add variables to test_e2e_ui (i.e. ldap, worker variables) + + step "create_ldap_server" { + module = module.docker_ldap + depends_on = [ + step.create_docker_network + ] + variables { + image_name = "${var.docker_mirror}/osixia/openldap:latest" + network_name = [local.network_cluster] + } + } + + step "run_e2e_test" { + module = module.test_e2e_ui + depends_on = [ + step.create_boundary, + step.create_vault, + step.create_host, + step.create_ldap_server, + ] + variables { + debug_no_run = var.e2e_debug_no_run + alb_boundary_api_addr = step.create_boundary.address + auth_method_id = step.create_boundary.auth_method_id + auth_login_name = step.create_boundary.login_name + auth_password = step.create_boundary.password + local_boundary_dir = step.build_boundary_docker_image.cli_zip_path + local_boundary_ui_src_dir = local.local_boundary_ui_src_dir + aws_ssh_private_key_path = local.aws_ssh_private_key_path + target_address = step.create_host.address + target_port = step.create_host.port + target_user = "ubuntu" + vault_addr = step.create_vault.address + vault_addr_internal = step.create_vault.address_internal + vault_root_token = step.create_vault.token + vault_port = step.create_vault.port + ldap_address = step.create_ldap_server.address + ldap_domain_dn = step.create_ldap_server.domain_dn + ldap_admin_dn = step.create_ldap_server.admin_dn + ldap_admin_password = step.create_ldap_server.admin_password + ldap_user_name = step.create_ldap_server.user_name + ldap_user_password = step.create_ldap_server.user_password + ldap_group_name = step.create_ldap_server.group_name + worker_token = step.create_worker.worker_led_token + } + } +} diff --git a/enos/modules/test_e2e_ui/main.tf b/enos/modules/test_e2e_ui/main.tf index 05aeeb377e..7e2d96d78f 100644 --- a/enos/modules/test_e2e_ui/main.tf +++ b/enos/modules/test_e2e_ui/main.tf @@ -42,13 +42,14 @@ variable "local_boundary_ui_src_dir" { description = "Local Path to boundary-ui directory" type = string } -variable "target_user" { - description = "SSH username for target" + +variable "aws_ssh_private_key_path" { + description = "Local Path to key used to SSH onto created hosts" type = string default = "" } -variable "aws_ssh_private_key_path" { - description = "Local Path to key used to SSH onto created hosts" +variable "target_user" { + description = "SSH username for target" type = string default = "" } @@ -92,41 +93,65 @@ variable "aws_secret_access_key" { type = string default = "" } -variable "aws_host_set_filter1" { +variable "aws_host_set_filter" { description = "Filter tag for host set used in dynamic host catalogs" type = string default = "" } -variable "aws_host_set_count1" { - description = "Number of hosts in aws_host_set_filter1" - type = number - default = 0 -} -variable "aws_host_set_ips1" { +variable "aws_host_set_ips" { description = "List of IP addresses in aws_host_set_filter1" type = list(string) default = [""] } -variable "aws_host_set_filter2" { - description = "Filter tag for host set used in dynamic host catalogs" +variable "ldap_address" { + description = "URL to LDAP server" type = string default = "" } -variable "aws_host_set_ips2" { - description = "List of IP addresses in aws_host_set_filter2" - type = list(string) - default = [""] +variable "ldap_domain_dn" { + description = "Distinguished Name to the LDAP domain" + type = string + default = "" +} +variable "ldap_admin_dn" { + description = "Distinguished Name to the LDAP admin user" + type = string + default = "" +} +variable "ldap_admin_password" { + description = "Password for the LDAP admin user" + type = string + default = "" +} +variable "ldap_user_name" { + description = "Username of an LDAP user" + type = string + default = "" +} +variable "ldap_user_password" { + description = "Password for an LDAP user" + type = string + default = "" +} +variable "ldap_group_name" { + description = "Name of LDAP group" + type = string + default = "" +} +variable "worker_token" { + description = "Worker Registration Token" + type = string + default = "" } locals { aws_ssh_private_key_path = abspath(var.aws_ssh_private_key_path) vault_addr = var.vault_addr != "" ? "http://${var.vault_addr}:${var.vault_port}" : "" vault_addr_internal = var.vault_addr_internal != "" ? "http://${var.vault_addr_internal}:8200" : local.vault_addr - aws_host_set_ips1 = jsonencode(var.aws_host_set_ips1) - aws_host_set_ips2 = jsonencode(var.aws_host_set_ips2) + aws_host_set_ips = jsonencode(var.aws_host_set_ips) } -resource "enos_local_exec" "run_e2e_ui_test" { +resource "enos_local_exec" "run_e2e_test" { environment = { BOUNDARY_ADDR = var.alb_boundary_api_addr E2E_PASSWORD_AUTH_METHOD_ID = var.auth_method_id @@ -141,14 +166,21 @@ resource "enos_local_exec" "run_e2e_ui_test" { E2E_VAULT_ADDR = local.vault_addr_internal E2E_AWS_ACCESS_KEY_ID = var.aws_access_key_id E2E_AWS_SECRET_ACCESS_KEY = var.aws_secret_access_key - E2E_AWS_HOST_SET_FILTER = var.aws_host_set_filter1 - E2E_AWS_HOST_SET_IPS = local.aws_host_set_ips1 - E2E_AWS_HOST_SET_FILTER2 = var.aws_host_set_filter2 + E2E_AWS_HOST_SET_FILTER = var.aws_host_set_filter + E2E_AWS_HOST_SET_IPS = local.aws_host_set_ips + E2E_LDAP_ADDR = var.ldap_address + E2E_LDAP_DOMAIN_DN = var.ldap_domain_dn + E2E_LDAP_ADMIN_DN = var.ldap_admin_dn + E2E_LDAP_ADMIN_PASSWORD = var.ldap_admin_password + E2E_LDAP_USER_NAME = var.ldap_user_name + E2E_LDAP_USER_PASSWORD = var.ldap_user_password + E2E_LDAP_GROUP_NAME = var.ldap_group_name + E2E_WORKER_TOKEN = var.worker_token } inline = var.debug_no_run ? [""] : ["set -o pipefail; PATH=\"${var.local_boundary_dir}:$PATH\" yarn --cwd ${var.local_boundary_ui_src_dir}/ui/admin run e2e 2>&1 | tee ${path.module}/../../test-e2e-ui.log"] } output "test_results" { - value = enos_local_exec.run_e2e_ui_test.stdout + value = enos_local_exec.run_e2e_test.stdout } diff --git a/enos/scripts/test_e2e_env.sh b/enos/scripts/test_e2e_env.sh index afd92dd20f..4be9024931 100644 --- a/enos/scripts/test_e2e_env.sh +++ b/enos/scripts/test_e2e_env.sh @@ -9,6 +9,5 @@ STATEDIR=$(ls -td $SCRIPTS_DIR/../.enos/*/ | head -1) # get latest directory cd $STATEDIR terraform show -json terraform.tfstate | jq -r '.values.root_module.child_modules[].resources[] | select(.address=="module.run_e2e_test.enos_local_exec.run_e2e_test") | .values.environment | to_entries[] | "export \(.key)=\(.value|@sh)"' -terraform show -json terraform.tfstate | jq -r '.values.root_module.child_modules[].resources[] | select(.address=="module.run_e2e_ui_test.enos_local_exec.run_e2e_ui_test") | .values.environment | to_entries[] | "export \(.key)=\(.value|@sh)"' cd $DIR