diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml new file mode 100644 index 0000000..95ee11e --- /dev/null +++ b/.pre-commit-config.yaml @@ -0,0 +1,31 @@ +repos: +- repo: https://github.com/pre-commit/pre-commit-hooks + rev: v4.6.0 + hooks: + # Git style + - id: check-added-large-files + - id: check-merge-conflict + - id: check-vcs-permalinks + - id: forbid-new-submodules + - id: no-commit-to-branch + + # Common errors + - id: end-of-file-fixer + - id: trailing-whitespace + args: [--markdown-linebreak-ext=md] + exclude: CHANGELOG.md + - id: check-yaml + - id: check-merge-conflict + - id: check-executables-have-shebangs + +- repo: https://github.com/jumanjihouse/pre-commit-hooks + rev: 3.0.0 + hooks: + - id: shfmt + args: ['-l', '-i', '2', '-ci', '-sr', '-w'] + - id: shellcheck +- repo: https://github.com/antonbabenko/pre-commit-terraform + rev: v1.96.3 + hooks: + - id: terraform_fmt + - id: terraform_docs diff --git a/Makefile b/Makefile index ac8575b..10a5749 100644 --- a/Makefile +++ b/Makefile @@ -1,4 +1,4 @@ -local_team_servers := $(shell vagrant status | grep -E -o 'team[0-9]+') +local_team_servers = $(shell vagrant status | grep -E -o 'team[0-9]+') ci: @bash ./scripts/ci.sh @@ -8,9 +8,11 @@ up-local: @vagrant up --parallel up-aws: + @terraform -chdir=./terraform init @terraform -chdir=./terraform apply yeet-aws: + @terraform -chdir=./terraform init @terraform -chdir=./terraform apply -auto-approve @printf 'Waiting 30s for EC2 instances to hopefully process userdata...\n' && sleep 30 @make -s provision-aws diff --git a/instructions/challenge_2.md b/instructions/challenge_2.md index 7379a4d..5cd5253 100644 --- a/instructions/challenge_2.md +++ b/instructions/challenge_2.md @@ -18,6 +18,6 @@ following: - Once there, the app there needs to be named `run-app`, not `app` - To ensure both locations always have the same version (e.g. during hotfixes), - make a reference from the binary location to the target location without - copying the actual file. This way, any update or change will reflect in both + make a reference from the binary location to the target location *without + copying the actual file*. This way, any update or change will reflect in both places at once without needing to manually sync them. diff --git a/instructions/challenge_3.md b/instructions/challenge_3.md index 31a1739..df7d085 100644 --- a/instructions/challenge_3.md +++ b/instructions/challenge_3.md @@ -15,5 +15,5 @@ Create that service, and get it running. You need to make sure it runs *even if the system reboots* -- meaning that if the server is restarted for any reason, the app service needs to start again *without you starting it manually*. -If for any reason you need to check out more detailed logs of the service, you -can also use the separate `journalctl` command to inspect them. +If for any reason you need to check out more detailed logs of the service you're +creating, you can also use the separate `journalctl` command to inspect them. diff --git a/instructions/challenge_4.md b/instructions/challenge_4.md index d732017..6f9634d 100644 --- a/instructions/challenge_4.md +++ b/instructions/challenge_4.md @@ -24,5 +24,5 @@ look at the `/opt/app` directory again, you may have noticed that there is a correctly-installed app binary. Once you do that, be sure to check the `systemd` and/or `journald` logs of the -new `app-deb.service` to make sure it's running successfully! (and, just like -the last one, that it would keep running after a reboot) +new `app-deb.service` to make sure it's running successfully (and, just like +the last one, that it would keep running after a reboot). diff --git a/instructions/challenge_6.md b/instructions/challenge_6.md index 9e09159..25ecd5b 100644 --- a/instructions/challenge_6.md +++ b/instructions/challenge_6.md @@ -8,7 +8,7 @@ dissappeared while on a golfing trip a few weeks past. We were told that the code was about ready to deploy, just hadn't gotten the chance to merge it into the main branch. See if you can figure out how to get it up and running. -The name of the app is 'carrot-cruncher'. The last dev got the repo set up +The name of the app is "carrot-cruncher". The last dev got the repo set up somewhere on disk, but they never said where... hopefully you'll able to find it. When you do, supposedly there was a new working branch pushed to the remote repo, so you'll need to figure out how to authenticate to that repo. diff --git a/scripts/ci.sh b/scripts/ci.sh index 93b120f..4a7eb9e 100644 --- a/scripts/ci.sh +++ b/scripts/ci.sh @@ -24,6 +24,7 @@ if [[ "$( Installing CI checks for Go...\n' for pkg in \ honnef.co/go/tools/cmd/staticcheck@latest \ + github.com/mgechev/revive@latest \ github.com/kisielk/errcheck@latest \ ; do go install "${pkg}" @@ -39,9 +40,11 @@ while read -r module ; do cd "${mod_dir}" printf '>> Running go vet...\n' go vet ./... - printf '>> Running linter...\n' + printf '>> Running staticcheck linter...\n' staticcheck ./... - printf '>> Running error checker...\n' + printf '>> Running revive linter...\n' + revive --set_exit_status ./... + printf '>> Running error-checker...\n' errcheck ./... ) done < /tmp/go-modules diff --git a/scripts/linux-workshop-admin.sh b/scripts/linux-workshop-admin.sh index f3aff85..85c857c 100755 --- a/scripts/linux-workshop-admin.sh +++ b/scripts/linux-workshop-admin.sh @@ -35,13 +35,13 @@ _score-for-challenge() { log-info "Providing instruction to user for Challenge ${next_challenge}" cp "${wsroot}/instructions/challenge_${next_challenge}.md" /home/appuser/ # Also broadcast message to user when challenge is complete - wall "Congrats on finishing Challenge ${which_challenge}! Be sure to check your home directory for any new instruction files! (hit any key to dismiss this message)" + wall "Congrats on finishing Challenge ${which_challenge}! Be sure to check your home directory for any new instruction files! (hit Enter to dismiss this message)" else log-info 'Team is done with the workshop!' cp "${wsroot}/instructions/congrats.md" /home/appuser/ # This check suppresses an infinite loop of congratulations, lol if [[ ! -f "${wsroot}"/team_has_been_congratulated ]] ; then - wall "Congratulations -- you have completed ALL CHALLENGES! Be sure to read congrats.md in your home directory! (hit any key to dismiss this message)" + wall "Congratulations -- you have completed ALL CHALLENGES! Be sure to read congrats.md in your home directory! (hit Enter to dismiss this message)" touch "${wsroot}"/team_has_been_congratulated fi fi diff --git a/scripts/provision-ec2-team-parallelizer.sh b/scripts/provision-ec2-team-parallelizer.sh index bcc33a2..6ec387b 100644 --- a/scripts/provision-ec2-team-parallelizer.sh +++ b/scripts/provision-ec2-team-parallelizer.sh @@ -32,7 +32,7 @@ log-info "Adding files to Team server ${server_num} at ${server_ip}..." scp -P 2332 -r -o StrictHostKeyChecking=accept-new ../scripts ../services ../instructions ../dummy-app-src admin@"${server_ip}":/tmp log-info "Running init on Team server ${server_num} at ${server_ip}..." -ssh -p 2332 admin@"${server_ip}" "export team_name=Team-${server_num} && export db_addr=${db_priv_ip} && sudo -E bash /tmp/scripts/init.sh" +ssh -p 2332 admin@"${server_ip}" "source /tmp/.tfenv && sudo -E bash /tmp/scripts/init.sh" log-info "Running tests on Team server ${server_num} at ${server_ip}..." ssh -p 2332 admin@"${server_ip}" "sudo -E bats /.ws/scripts/test.bats" diff --git a/terraform/.gitignore b/terraform/.gitignore index 9d82155..0793958 100644 --- a/terraform/.gitignore +++ b/terraform/.gitignore @@ -1,3 +1,4 @@ .terraform/ *.tfvars *tfstate* +!main.auto.tfvars diff --git a/terraform/.terraform.lock.hcl b/terraform/.terraform.lock.hcl index f41fd23..86e311f 100644 --- a/terraform/.terraform.lock.hcl +++ b/terraform/.terraform.lock.hcl @@ -2,45 +2,45 @@ # Manual edits may be lost in future updates. provider "registry.terraform.io/hashicorp/aws" { - version = "4.64.0" - constraints = ">= 3.29.0, >= 3.72.0, >= 4.35.0" + version = "5.83.1" + constraints = ">= 3.29.0, >= 4.20.0, >= 5.46.0" hashes = [ - "h1:11rlibZkK0ZoQzRMzzjqmExHbNJ3MJ2xYpjxyiFd5cE=", - "h1:4xXf+eZtKPiRyjle7HUPaVzF3h/6S8seNEIIbWlDbuk=", - "zh:092614f767995140cf444cad1a97fb569885db16cb1c1dc9ee56e801232bac29", - "zh:142e262fbb162c8a86493cfab4aadaf96a8572f1a3a6be444d465a4aee377dba", - "zh:1c58c8cb9934dc98a2dd9dc48a8a3d94a14c2c3f2bc0136410a9344938d4ecfb", - "zh:36efdf30cd52b92668cf6f912538c6e176b1a140a00e63ee0f753b85878c8b53", - "zh:4c631e367fd69692b57f85564de561733380e9674e146d3a7725b781ec5db944", - "zh:57ace91cb022ec944ad3af9272b78f48e7f71e9d1bf113ca56c6ce8deb4341fe", - "zh:7fc9581b530ebf28fda80c62c20c6fbbb936a878c24872349eb107b7f198e64c", - "zh:8280cd8f04c31af83f3e74f07704b258fbaa8bf1d70679d5ea2f0cbda2571de2", - "zh:8e6217a9443b651d4349d75bdc37af9298970d854bf515d8c305919b193e4a38", + "h1:8KI8wFWW2iPYVMyNGI75bxgmwy8MjZk4G6Quut5H7x8=", + "h1:vInFMDq9oMs53/i+7IU8hZgmTLhFfng8L8kbuALZxSI=", + "zh:0313253c78f195973752c4d1f62bfdd345a9c99c1bc7a612a8c1f1e27d51e49e", + "zh:108523f3e9ebc93f7d900c51681f6edbd3f3a56b8a62b0afc31d8214892f91e0", + "zh:175b9bf2a00bea6ac1c73796ad77b0e00dcbbde166235017c49377d7763861d8", + "zh:1c8bf55b8548bbad683cd6d7bdb03e8840a00b2422dc1529ffb9892820657130", + "zh:22338f09bae62d5ff646de00182417f992548da534fee7d98c5d0136d4bd5d7a", + "zh:92de1107ec43de60612be5f6255616f16a9cf82d88df1af1c0471b81f3a82c16", "zh:9b12af85486a96aedd8d7984b0ff811a4b42e3d88dad1a3fb4c0b580d04fa425", - "zh:9c62bc4a9034a6caf15b8863da6f5a621b947d5fca161b4bd2f2e8e78eec8e3b", - "zh:9d0a45cd4a031d19ee14c0a15f25df6359dcd342ccf4e2ee4751b3ee496edb57", - "zh:ab47f4e300c46dc1757e2b8d8d749f34f044f219479106a00bf40572091a8999", - "zh:b55119290497dda96ab9ba3dca00d648808dc99d18960ad8aa875775bfaf95db", - "zh:df513941e6979f557edcac28d84bd91af9786104b0deba45b3b259a5ad215897", + "zh:9c7bfb7afea330e6d90e1466125a8cba3db1ed4043c5da52f737459c89290a6e", + "zh:ba59b374d477e5610674b70f5abfe0408e8f809390347372751384151440d3d0", + "zh:bd1c433966002f586d63cb1e3e16326991f238bc6beeb2352be36ec651917b0b", + "zh:ca2b4d1d02651c15261fffa4b142e45def9a22c6069353f0f663fd2046e268f8", + "zh:d8ed98c748f7a3f1a72277cfee9afe346aca39ab319d17402277852551d8f14a", + "zh:ed3d8bc89de5f35f3c5f4802ff7c749fda2e2be267f9af4a850694f099960a72", + "zh:f698732a4391c3f4d7079b4aaa52389da2a460cac5eed438ed688f147d603689", + "zh:f9f51b17f2978394954e9f6ab9ef293b8e11f1443117294ccf87f7f8212b3439", ] } provider "registry.terraform.io/hashicorp/http" { - version = "3.3.0" + version = "3.4.5" hashes = [ - "h1:QL/rtSlbi+F+ukbr/k4MahiO5lX4AiEu37p4kOV9ELk=", - "h1:pK/CC2NlpUbL4x3R386uxfS80HodJXtGREg0k2ABukw=", - "zh:27d101f4c089d1e367bbbbb3f260fc7d52f63559a4424c08633e566863c951b2", - "zh:37860671324229f52a7d82eea88a31fe24321297fd699d879de5b6cf6aae086c", - "zh:4680716579e361298e4331ce0c92e38011fc41ed56bd55302c23b696b3b8c469", - "zh:547cd2a407ca0d22307634d83ffc64cd4225f221baa09682b7a8c5a2429c34d8", - "zh:61965698af75aad7482f2f593b75f15e4a4f6f0117b643c69f3da61f40b1a9c7", + "h1:ZDXm3QR3UhjciYS49A+KrjVg1qDQ23HyQ24JFdWQEKk=", + "h1:ceAVZEuaQd7jQX13qf5w7hy3ioiXpuwUaaDRsnAiMLM=", + "zh:2072006c177efc101471f3d5eb8e1d8e6c68778cbfd6db3d3f22f59cfe6ce6ae", + "zh:3ac4cc0efe11ee054300769cfcc37491433937a8824621d1f8f7a18e7401da87", + "zh:63997e5457c9ddf9cfff17bd7bf9f083cbeff3105452045662109dd6be499ef9", "zh:78d5eefdd9e494defcb3c68d282b8f96630502cac21d1ea161f53cfe9bb483b3", - "zh:93f9e0f2244816cbb72197c733ada4214df691e4e6a84b8e340e43e43ab8a383", - "zh:969aad70624d033c257c365cf75001d29fa7341b48d673cd7317205395b4791b", - "zh:e9504018b1af992c041bda1e4a6f01db1f1cdb1a7df8055d1082049befbc4217", - "zh:fa7f6af94e75c6fe21782c622ed387ae08ee3ffeaa0176f08d0b06bb61bb50f4", - "zh:feda1d7cdae86bce829f82223f625b55c858a36d3aca1a762d7258798a25b476", - "zh:ff1f3d8c53930aad2fde32d6328df7e7e5b5de36dd7c0682d15518993ab199ef", + "zh:826819bb8ab7d6e3095f597083d5b1ab93d1854312b9e1b6c18288fff9664f34", + "zh:8ad74e7d8ec2e226a73d49c7c317108f61a4cb803972fb3f945d1709d5115fcd", + "zh:a609ca9e0c91d250ac80295e39d5f524e8c0872d33ba8fde3c3e41893b4b015d", + "zh:ae07d19babc452f63f6a6511b944990e819dc20687b6c8f01d1676812f5ada53", + "zh:b7c827dc32a1a5d77185a78cd391b01217894b384f58169f98a96d683730d8ce", + "zh:d045e3db9f5e39ce78860d3fd94e04604fcbe246f6fe346ee50a971f936e9ccd", + "zh:ec28f9b52c74edd47eebbb5c254a6df5706360cde5ccd65097976efca23a2977", + "zh:f24982eaa7d34fd66554c3cf94873713a0dff14da9ea4c4be0cc76f1a6146d59", ] } diff --git a/terraform/dns.tf b/terraform/dns.tf new file mode 100644 index 0000000..973434e --- /dev/null +++ b/terraform/dns.tf @@ -0,0 +1,39 @@ + +data "aws_route53_zone" "root_zone" { + count = var.create_dns ? 1 : 0 + name = var.zone_name + +} + +resource "aws_route53_zone" "workshop_zone" { + count = var.create_dns ? 1 : 0 + name = "${var.event_name}.${var.zone_name}" +} + +resource "aws_route53_record" "workshop" { + count = var.create_dns ? 1 : 0 + zone_id = data.aws_route53_zone.root_zone[0].zone_id + name = aws_route53_zone.workshop_zone[0].name + type = "NS" + ttl = "300" + records = aws_route53_zone.workshop_zone[0].name_servers +} + +resource "aws_route53_record" "teams" { + count = var.create_dns ? var.num_teams : 0 + zone_id = aws_route53_zone.workshop_zone[0].zone_id + name = "team-${count.index + 1}" + type = "A" + ttl = 300 #5 mins + records = [module.team_servers[count.index].public_ip] + depends_on = [aws_route53_record.hub] +} + +resource "aws_route53_record" "db" { + count = var.create_dns ? 1 : 0 + zone_id = aws_route53_zone.workshop_zone[0].zone_id + name = "db" + type = "A" + ttl = 300 #5 mins + records = [module.db.public_ip] +} diff --git a/terraform/main.auto.tfvars b/terraform/main.auto.tfvars new file mode 100644 index 0000000..40dc399 --- /dev/null +++ b/terraform/main.auto.tfvars @@ -0,0 +1,26 @@ +num_teams = 2 +event_name = "codemash" +custom_security_group_ingress = [{ + from_port = 2332, + to_port = 2332, + protocol = "tcp", + description = "ssh", + cidr_blocks = "0.0.0.0/0" + }, + { + from_port = 8080, + to_port = 8080, + protocol = "tcp", + description = "http", + cidr_blocks = "0.0.0.0/0" + }, + { + from_port = 443, + to_port = 443, + protocol = "tcp", + description = "https for wetty", + cidr_blocks = "0.0.0.0/0" + } +] +zone_name = "sbx.justindebo.com" +create_dns = true diff --git a/terraform/main.tf b/terraform/main.tf index 97d969b..28da300 100644 --- a/terraform/main.tf +++ b/terraform/main.tf @@ -20,8 +20,8 @@ module "vpc" { name = local.name cidr = "10.0.0.0/16" - azs = [data.aws_availability_zones.available.names[0]] - public_subnets = ["10.0.1.0/24"] + azs = [data.aws_availability_zones.available.names[0], data.aws_availability_zones.available.names[1]] + public_subnets = cidrsubnets("10.0.0.0/16", 8, 8) enable_nat_gateway = false @@ -124,7 +124,7 @@ module "team_servers" { instance_type = "t3a.micro" key_name = aws_key_pair.main.key_name vpc_security_group_ids = [module.security_group.security_group_id] - subnet_id = module.vpc.public_subnets[0] + subnet_id = module.vpc.public_subnets[count.index % 2] associate_public_ip_address = true user_data = <<-EOF @@ -133,6 +133,8 @@ module "team_servers" { # NOTE: setting sshd to listen on both 2332 AND regular 22 grep -q 2332 /etc/ssh/sshd_config || printf 'Port 2332\nPort 22\n' >> /etc/ssh/sshd_config systemctl restart ssh + # Variables to be sourced before init.sh runs + printf 'export team_name="Team-${count.index + 1}"\nexport db_addr="${module.db.private_ip}"\n' > /tmp/.tfenv EOF tags = local.tags diff --git a/terraform/outputs.tf b/terraform/outputs.tf index 3928af0..a6b77aa 100644 --- a/terraform/outputs.tf +++ b/terraform/outputs.tf @@ -2,6 +2,10 @@ output "instance_ips" { value = { for instance in module.team_servers : instance.tags_all["Name"] => instance.public_ip } } +output "instance_dns" { + value = { for dns in aws_route53_record.teams : "${dns.name}.${aws_route53_zone.workshop_zone[0].name}" => dns.records } +} + output "db_pub_ip" { value = module.db.public_ip } diff --git a/terraform/variables.tf b/terraform/variables.tf index 2a27336..1955d10 100644 --- a/terraform/variables.tf +++ b/terraform/variables.tf @@ -32,3 +32,15 @@ variable "ssh_local_key_path" { type = string default = "~/.ssh/id_rsa.pub" } + +variable "create_dns" { + description = "Whether to create a Route53 DNS zone for the workshop instances" + type = bool + default = false +} + +variable "zone_name" { + description = "Route53 zone name to use for workshop instances" + type = string + default = null +}