diff --git a/.gitignore b/.gitignore index 5dae116bb..ce802b85f 100644 --- a/.gitignore +++ b/.gitignore @@ -2,11 +2,12 @@ *.swp *~ -prepare-vms/tags -prepare-vms/infra -prepare-vms/www - -prepare-tf/tag-* +**/terraform.tfstate +**/terraform.tfstate.backup +prepare-labs/terraform/lab-environments +prepare-labs/terraform/many-kubernetes/one-kubernetes-config/config.tf +prepare-labs/terraform/many-kubernetes/one-kubernetes-module/*.tf +prepare-labs/www slides/*.yml.html slides/autopilot/state.yaml @@ -26,3 +27,4 @@ node_modules Thumbs.db ehthumbs.db ehthumbs_vista.db + diff --git a/prepare-vms/Dockerfile b/prepare-labs/Dockerfile similarity index 100% rename from prepare-vms/Dockerfile rename to prepare-labs/Dockerfile diff --git a/prepare-labs/README.md b/prepare-labs/README.md new file mode 100644 index 000000000..9c2102138 --- /dev/null +++ b/prepare-labs/README.md @@ -0,0 +1,196 @@ +# Tools to create lab environments + +This directory contains tools to create lab environments for Docker and Kubernetes courses and workshops. + +It also contains Terraform configurations that can be used stand-alone to create simple Kubernetes clusters. + +Assuming that you have installed all the necessary dependencies, and placed cloud provider access tokens in the right locations, you could do, for instance: + +```bash +# For a Docker course with 50 students, +# create 50 VMs on Digital Ocean. +./labctl create --students 50 --settings settings/docker.env --provider digitalocean + +# For a Kubernetes training with 20 students, +# create 20 clusters of 4 VMs each using kubeadm, +# on a private Openstack cluster. +./labctl create --students 20 --settings settings/kubernetes.env --provider openstack/enix + +# For a Kubernetes workshop with 80 students, +# create 80 clusters with 2 VMs each, +# using Scaleway Kapsule (managed Kubernetes). +./labctl create --students 20 --settings settings/mk8s.env --provider scaleway --mode mk8s +``` + +Interested? Read on! + +## Software requirements + +For Docker labs and Kubernetes labs based on kubeadm: + +- [Parallel SSH](https://github.com/lilydjwg/pssh) + (should be installable with `pip install git+https://github.com/lilydjwg/pssh`; + on a Mac, try `brew install pssh`) + +For all labs: + +- Terraform + +If you want to generate printable cards: + +- [pyyaml](https://pypi.python.org/pypi/PyYAML) +- [jinja2](https://pypi.python.org/pypi/Jinja2) + +These require Python 3. If you are on a Mac, see below for specific instructions on setting up +Python 3 to be the default Python on a Mac. In particular, if you installed `mosh`, Homebrew +may have changed your default Python to Python 2. + +If you don't or can't install these requirements, you +can also run this script in a Docker image. + +You will also need an account with the cloud provider(s) that you want to use to deploy the lab environments. + +## Cloud provider account(s) and credentials + +These scripts create VMs or Kubernetes cluster on cloud providers, so you will need cloud provider account(s) and credentials. + +Generally, we try to use the credentials stored in the configuration file used by the cloud providers CLI tools. + +This means, for instance, that for Linode, if you install `linode-cli` and configure it properly, it will place your credentials in `~/.config/linode-cli`, and our Terraform configurations will try to read that file and use the credentials in it. + +You don't **have to** install the CLI tools of the cloud provider(s) that you want to use; but we recommend that you do. + +If you want to provide your cloud credentials through other means, you will have to adjust the Terraform configuration files in `terraform/provider-config` accordingly. + +## General Workflow + +- fork/clone repo +- make sure your cloud credentials have been configured properly +- run `./labctl create ...` to create lab environments +- run `./labctl destroy ...` when you don't need the environments anymore + +## Customizing things + +You can edit the `settings/*.env` files, for instance to change the size of the clusters, the login or password used for the students... + +Note that these files are sourced before executing any operation on a specific set of lab environments, which means that you can set Terraform variables by adding lines like the following one in the `*.env` files: + +```bash +export TF_VAR_node_size=GP1.L +export TF_VAR_location=eu-north +``` + +## `./labctl` Usage + +If you run `./labctl` without arguments, it will show a list of available commands. + +### Summary of What `./labctl` Does For You + +The script will create a Terraform configuration using a provider-specific template. + +There are two modes: `pssh` and `mk8s`. + +In `pssh` mode, students connect directly to the virtual machines using SSH. + +The Terraform configuration creates a bunch of virtual machines, then the provisioning and configuration are done with `pssh`. There are a number of "steps" that are executed on the VMs, to install Docker, install a number of convenient tools, install and set up Kubernetes (if needed)... The list of "steps" to be executed is configured in the `settings/*.env` file. + +In `mk8s` mode, students don't connect directly to the virtual machines. Instead, they connect to an SSH server running in a Pod (using the `jpetazzo/shpod` image), itself running on a Kubernetes cluster. The Kubernetes cluster is a managed cluster created by the Terraform configuration. + +## `terraform` directory structure and principles + +Legend: +- `πŸ“` directory +- `πŸ“„` file +- `πŸ“„πŸ“„πŸ“„` multiple files +- `🌍` Terraform configuration that can be used "as-is" + +``` +πŸ“terraform +β”œβ”€β”€ πŸ“list-locations +β”‚ └── πŸ“„πŸ“„πŸ“„ helper scripts +β”‚ (to list available locations for each provider) +β”œβ”€β”€ πŸ“many-kubernetes +β”‚ └── πŸ“„πŸ“„πŸ“„ Terraform configuration template +β”‚ (used in mk8s mode) +β”œβ”€β”€ πŸ“one-kubernetes +β”‚ β”‚ (contains Terraform configurations that can spawn +β”‚ β”‚ a single Kubernetes cluster on a given provider) +β”‚ β”œβ”€β”€ πŸ“πŸŒaws +β”‚ β”œβ”€β”€ πŸ“πŸŒcivo +β”‚ β”œβ”€β”€ πŸ“„common.tf +β”‚ β”œβ”€β”€ πŸ“πŸŒdigitalocean +β”‚ └── ... +β”œβ”€β”€ πŸ“provider-config +β”‚ β”œβ”€β”€ πŸ“„aws.tf +β”‚ β”œβ”€β”€ πŸ“„azure.tf +β”‚ β”œβ”€β”€ πŸ“„civo.tf +β”‚ β”œβ”€β”€ πŸ“„digitalocean.tf +β”‚ └── ... +β”œβ”€β”€ πŸ“tags +β”‚ β”‚ (contains Terraform configurations + other files +β”‚ β”‚ for a specific set of VMs or K8S clusters; these +β”‚ β”‚ are created by labctl) +β”‚ β”œβ”€β”€ πŸ“2023-03-27-10-04-79-jp +β”‚ β”œβ”€β”€ πŸ“2023-03-27-10-07-41-jp +β”‚ β”œβ”€β”€ πŸ“2023-03-27-10-16-418-jp +β”‚ └── ... +└── πŸ“virtual-machines + β”‚ (contains Terraform configurations that can spawn + β”‚ a bunch of virtual machines on a given provider) + β”œβ”€β”€ πŸ“πŸŒaws + β”œβ”€β”€ πŸ“πŸŒazure + β”œβ”€β”€ πŸ“„common.tf + β”œβ”€β”€ πŸ“πŸŒdigitalocean + └── ... +``` + +The directory structure can feel a bit overwhelming at first, but it's built with specific goals in mind. + +**Consistent input/output between providers.** The per-provider configurations in `one-kubernetes` all take the same input variables, and provide the same output variables. Same thing for the per-provider configurations in `virtual-machines`. + +**Don't repeat yourself.** As much as possible, common variables, definitions, and logic has been factored in the `common.tf` file that you can see in `one-kubernetes` and `virtual-machines`. That file is then symlinked in each provider-specific directory, to make sure that all providers use the same version of the `common.tf` file. + +**Don't repeat yourself (again).** The things that are specific to each provider (e.g. how to obtain the credentials; the size of the VMs to use...) have been placed in the `provider-config` directory, and are shared between the `one-kubernetes` and the `virtual-machines` configurations. + +**Terraform configurations should work in `labctl` or standalone, without extra work.** The Terraform configurations (identified by 🌍 in the directory tree above) can be used directly. Just go to one of these directories, `terraform init`, `terraform apply`, and you're good to go. But they can also be used from `labctl`. `labctl` shouldn't barf out if you did a `terraform apply` in one of these directories (because it will only copy the `*.tf` files, and leave alone the other files, like the Terraform state). + +The latter means that it should be easy to tweak these configurations, or create a new one, without having to use `labctl` to test it. It also means that if you want to use these configurations but don't care about `labctl`, you absolutely can! + +## Miscellaneous info + +### Making sure Python3 is the default (Mac only) + +Check the `/usr/local/bin/python` symlink. It should be pointing to +`/usr/local/Cellar/python/3`-something. If it isn't, follow these +instructions. + +1) Verify that Python 3 is installed. + +``` +ls -la /usr/local/Cellar/Python +``` + +You should see one or more versions of Python 3. If you don't, +install it with `brew install python`. + +2) Verify that `python` points to Python3. + +``` +ls -la /usr/local/bin/python +``` + +If this points to `/usr/local/Cellar/python@2`, then we'll need to change it. + +``` +rm /usr/local/bin/python +ln -s /usr/local/Cellar/Python/xxxx /usr/local/bin/python +# where xxxx is the most recent Python 3 version you saw above +``` + +### AWS specific notes + +Initial assumptions are you're using a root account. If you'd like to use a IAM user, it will need the right permissions. For `pssh` mode, that includes at least `AmazonEC2FullAccess` and `IAMReadOnlyAccess`. + +In `pssh` mode, the Terraform configuration currently uses the default VPC and Security Group. If you want to use another one, you'll have to make changes to `terraform/virtual-machines/aws`. + +The default VPC Security Group does not open any ports from Internet by default. So you'll need to add Inbound rules for `SSH | TCP | 22 | 0.0.0.0/0` and `Custom TCP Rule | TCP | 8000 - 8002 | 0.0.0.0/0`. diff --git a/prepare-vms/cncsetup.sh b/prepare-labs/cncsetup.sh similarity index 100% rename from prepare-vms/cncsetup.sh rename to prepare-labs/cncsetup.sh diff --git a/prepare-vms/docker-compose.yml b/prepare-labs/docker-compose.yml similarity index 100% rename from prepare-vms/docker-compose.yml rename to prepare-labs/docker-compose.yml diff --git a/prepare-vms/docker.png b/prepare-labs/docker.png similarity index 100% rename from prepare-vms/docker.png rename to prepare-labs/docker.png diff --git a/prepare-vms/workshopctl b/prepare-labs/labctl similarity index 98% rename from prepare-vms/workshopctl rename to prepare-labs/labctl index 99b26fae2..7b478885d 100755 --- a/prepare-vms/workshopctl +++ b/prepare-labs/labctl @@ -21,10 +21,13 @@ DEPENDENCIES=" man pssh ssh - wkhtmltopdf yq " +UNUSED_DEPENDENCIES=" + wkhtmltopdf +" + # Check for missing dependencies, and issue a warning if necessary. missing=0 for dependency in $DEPENDENCIES; do diff --git a/prepare-vms/lib/cli.sh b/prepare-labs/lib/cli.sh similarity index 65% rename from prepare-vms/lib/cli.sh rename to prepare-labs/lib/cli.sh index 22575c0b8..42c9864ed 100644 --- a/prepare-vms/lib/cli.sh +++ b/prepare-labs/lib/cli.sh @@ -50,20 +50,6 @@ sep() { fi } -need_infra() { - if [ -z "$1" ]; then - die "Please specify infrastructure file. (e.g.: infra/aws)" - fi - if [ "$1" = "--infra" ]; then - die "The infrastructure file should be passed directly to this command. Remove '--infra' and try again." - fi - if [ ! -f "$1" ]; then - die "Infrastructure file $1 doesn't exist." - fi - . "$1" - . "lib/infra/$INFRACLASS.sh" -} - need_tag() { if [ -z "$TAG" ]; then die "Please specify a tag. To see available tags, run: $0 tags" @@ -71,25 +57,12 @@ need_tag() { if [ ! -d "tags/$TAG" ]; then die "Tag $TAG not found (directory tags/$TAG does not exist)." fi - for FILE in settings.yaml ips.txt infra.sh; do + for FILE in settings.env ips.txt; do if [ ! -f "tags/$TAG/$FILE" ]; then warning "File tags/$TAG/$FILE not found." fi done - . "tags/$TAG/infra.sh" - . "lib/infra/$INFRACLASS.sh" -} - -need_settings() { - if [ -z "$1" ]; then - die "Please specify a settings file. (e.g.: settings/kube101.yaml)" - fi - if [ ! -f "$1" ]; then - die "Settings file $1 doesn't exist." + if [ -f "tags/$TAG/settings.env" ]; then + . tags/$TAG/settings.env fi } - -need_login_password() { - USER_LOGIN=$(yq -r .user_login < tags/$TAG/settings.yaml) - USER_PASSWORD=$(yq -r .user_password < tags/$TAG/settings.yaml) -} \ No newline at end of file diff --git a/prepare-vms/lib/colors.sh b/prepare-labs/lib/colors.sh similarity index 100% rename from prepare-vms/lib/colors.sh rename to prepare-labs/lib/colors.sh diff --git a/prepare-vms/lib/commands.sh b/prepare-labs/lib/commands.sh similarity index 84% rename from prepare-vms/lib/commands.sh rename to prepare-labs/lib/commands.sh index c16ef3027..67df636a1 100644 --- a/prepare-vms/lib/commands.sh +++ b/prepare-labs/lib/commands.sh @@ -1,5 +1,3 @@ -export AWS_DEFAULT_OUTPUT=text - # Ignore SSH key validation when connecting to these remote hosts. # (Otherwise, deployment scripts break when a VM IP address reuse.) SSHOPTS="-o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -o LogLevel=ERROR" @@ -23,7 +21,7 @@ _cmd_build() { _cmd wrap "Run this program in a container" _cmd_wrap() { - docker-compose run --rm workshopctl "$@" + docker-compose run --rm labctl "$@" } _cmd cards "Generate ready-to-print cards for a group of VMs" @@ -31,10 +29,12 @@ _cmd_cards() { TAG=$1 need_tag + die FIXME + # This will process ips.txt to generate two files: ips.pdf and ips.html ( cd tags/$TAG - ../../lib/ips-txt-to-html.py settings.yaml + ../../../lib/ips-txt-to-html.py settings.yaml ) ln -sf ../tags/$TAG/ips.html www/$TAG.html @@ -47,10 +47,10 @@ _cmd_cards() { info "$0 www" } -_cmd clean "Remove information about stopped clusters" +_cmd clean "Remove information about destroyed clusters" _cmd_clean() { for TAG in tags/*; do - if grep -q ^stopped$ "$TAG/status"; then + if grep -q ^destroyed$ "$TAG/status"; then info "Removing $TAG..." rm -rf "$TAG" fi @@ -61,7 +61,6 @@ _cmd createuser "Create the user that students will use" _cmd_createuser() { TAG=$1 need_tag - need_login_password pssh " set -e @@ -82,7 +81,7 @@ _cmd_createuser() { set -e sudo sed -i 's/PasswordAuthentication no/PasswordAuthentication yes/' /etc/ssh/sshd_config sudo sed -i 's/#MaxAuthTries 6/MaxAuthTries 42/' /etc/ssh/sshd_config - sudo service ssh restart + sudo systemctl restart ssh.service " pssh " @@ -103,9 +102,7 @@ _cmd_createuser() { # in the next deployment step). In the long run, we probably want to # generate these keys locally and push them to the machines instead # (once we move everything to Terraform). - if [ -f "tags/$TAG/id_rsa" ]; then - ssh-add tags/$TAG/id_rsa - fi + ssh-add tags/$TAG/id_rsa pssh " set -e cd /home/$USER_LOGIN @@ -115,9 +112,7 @@ _cmd_createuser() { sudo -u $USER_LOGIN tar -xf- fi " - if [ -f "tags/$TAG/id_rsa" ]; then - ssh-add -d tags/$TAG/id_rsa - fi + ssh-add -d tags/$TAG/id_rsa # FIXME do this only once. pssh -I "sudo -u $USER_LOGIN tee -a /home/$USER_LOGIN/.bashrc" <<"SQRL" @@ -167,49 +162,162 @@ SQRL echo user_ok > tags/$TAG/status } -_cmd standardize "Deal with non-standard Ubuntu cloud images" -_cmd_standardize() { - TAG=$1 - need_tag - # Disable unattended upgrades so that they don't mess up with the subsequent steps - pssh sudo rm -f /etc/apt/apt.conf.d/50unattended-upgrades +_cmd create "Create lab environments" +_cmd_create() { + while [ ! -z "$*" ]; do + case "$1" in + --mode) MODE=$2; shift 2;; + --provider) PROVIDER=$2; shift 2;; + --settings) SETTINGS=$2; shift 2;; + --students) STUDENTS=$2; shift 2;; + --tag) TAG=$2; shift 2;; + *) die "Unrecognized parameter: $1." + esac + done - # Digital Ocean's cloud init disables password authentication; re-enable it. - pssh " - if [ -f /etc/ssh/sshd_config.d/50-cloud-init.conf ]; then - sudo rm /etc/ssh/sshd_config.d/50-cloud-init.conf - sudo systemctl restart ssh.service - fi" + if [ -z "$MODE" ]; then + info "Using default mode (pssh)." + MODE=pssh + fi + if [ -z "$PROVIDER" ]; then + die "Please add --provider flag to specify which provider to use." + fi + if [ -z "$SETTINGS" ]; then + die "Please add --settings flag to specify which settings file to use." + fi + if [ -z "$STUDENTS" ]; then + info "Defaulting to 1 student since --students flag wasn't specified." + STUDENTS=1 + fi - # Special case for scaleway since it doesn't come with sudo - if [ "$INFRACLASS" = "scaleway" ]; then - pssh -l root " - grep DEBIAN_FRONTEND /etc/environment || echo DEBIAN_FRONTEND=noninteractive >> /etc/environment - grep cloud-init /etc/sudoers && rm /etc/sudoers - apt-get update && apt-get install sudo -y" + case "$MODE" in + mk8s) + PROVIDER_BASE=terraform/one-kubernetes + ;; + pssh) + PROVIDER_BASE=terraform/virtual-machines + ;; + *) die "Invalid mode: $MODE (supported modes: mk8s, pssh)." ;; + esac + + if ! [ -f "$SETTINGS" ]; then + die "Settings file ($SETTINGS) not found." fi - # Special case for oracle since their iptables blocks everything but SSH - pssh " - if [ -f /etc/iptables/rules.v4 ]; then - sudo sed -i 's/-A INPUT -j REJECT --reject-with icmp-host-prohibited//' /etc/iptables/rules.v4 - sudo netfilter-persistent flush - sudo netfilter-persistent start - fi" + # Check that the provider is valid. + if [ -d $PROVIDER_BASE/$PROVIDER ]; then + if [ -f $PROVIDER_BASE/$PROVIDER/requires_tfvars ]; then + die "Provider $PROVIDER cannot be used directly, because it requires a tfvars file." + fi + PROVIDER_DIRECTORY=$PROVIDER_BASE/$PROVIDER + TFVARS="" + elif [ -f $PROVIDER_BASE/$PROVIDER.tfvars ]; then + TFVARS=$PROVIDER_BASE/$PROVIDER.tfvars + PROVIDER_DIRECTORY=$(dirname $PROVIDER_BASE/$PROVIDER) + else + error "Provider $PROVIDER not found." + info "Available providers for mode $MODE:" + ( + cd $PROVIDER_BASE + for P in *; do + if [ -d "$P" ]; then + [ -f "$P/requires_tfvars" ] || info "$P" + for V in $P/*.tfvars; do + [ -f "$V" ] && info "${V%.tfvars}" + done + fi + done + ) + die "Please specify a valid provider." + fi - # oracle-cloud-agent upgrades pacakges in the background. - # This breaks our deployment scripts, because when we invoke apt-get, it complains - # that the lock already exists (symptom: random "Exited with error code 100"). - # Workaround: if we detect oracle-cloud-agent, remove it. - # But this agent seems to also take care of installing/upgrading - # the unified-monitoring-agent package, so when we stop the snap, - # it can leave dpkg in a broken state. We "fix" it with the 2nd command. - pssh " - if [ -d /snap/oracle-cloud-agent ]; then - sudo snap remove oracle-cloud-agent - sudo dpkg --remove --force-remove-reinstreq unified-monitoring-agent - fi" + if [ -z "$TAG" ]; then + TAG=$(_cmd_maketag) + fi + mkdir -p tags/$TAG + echo creating > tags/$TAG/status + + ln -s ../../$SETTINGS tags/$TAG/settings.env.orig + cp $SETTINGS tags/$TAG/settings.env + . $SETTINGS + + echo $MODE > tags/$TAG/mode + echo $PROVIDER > tags/$TAG/provider + case "$MODE" in + mk8s) + cp -d terraform/many-kubernetes/*.* tags/$TAG + mkdir tags/$TAG/one-kubernetes-module + cp $PROVIDER_DIRECTORY/*.tf tags/$TAG/one-kubernetes-module + mkdir tags/$TAG/one-kubernetes-config + mv tags/$TAG/one-kubernetes-module/config.tf tags/$TAG/one-kubernetes-config + ;; + pssh) + cp $PROVIDER_DIRECTORY/*.tf tags/$TAG + if [ "$TFVARS" ]; then + cp "$TFVARS" "tags/$TAG/$(basename $TFVARS).auto.tfvars" + fi + ;; + esac + ( + cd tags/$TAG + terraform init + echo tag = \"$TAG\" >> terraform.tfvars + echo how_many_clusters = $STUDENTS >> terraform.tfvars + echo nodes_per_cluster = $CLUSTERSIZE >> terraform.tfvars + for RETRY in 1 2 3; do + if terraform apply -auto-approve; then + touch terraform.ok + break + fi + done + if ! [ -f terraform.ok ]; then + die "Terraform failed." + fi + ) + + sep + info "Successfully created $COUNT instances with tag $TAG" + echo create_ok > tags/$TAG/status + + # If the settings.env file has a "STEPS" field, + # automatically execute all the actions listed in that field. + # If an action fails, retry it up to 10 times. + for STEP in $(echo $STEPS); do + sep "$TAG -> $STEP" + TRY=1 + MAXTRY=10 + while ! $0 $STEP $TAG ; do + TRY=$(($TRY+1)) + if [ $TRY -gt $MAXTRY ]; then + error "This step ($STEP) failed after $MAXTRY attempts." + info "You can troubleshoot the situation manually, or terminate these instances with:" + info "$0 destroy $TAG" + die "Giving up." + else + sep + info "Step '$STEP' failed for '$TAG'. Let's wait 10 seconds and try again." + info "(Attempt $TRY out of $MAXTRY.)" + sleep 10 + fi + done + done + sep + info "Deployment successful." + info "To log into the first machine of that batch, you can run:" + info "$0 ssh $TAG" + info "To terminate these instances, you can run:" + info "$0 destroy $TAG" +} + +_cmd destroy "Destroy lab environments" +_cmd_destroy() { + TAG=$1 + need_tag + cd tags/$TAG + echo destroying > status + terraform destroy -auto-approve + echo destroyed > status } _cmd clusterize "Group VMs in clusters" @@ -217,24 +325,32 @@ _cmd_clusterize() { TAG=$1 need_tag - # Copy settings and install Python YAML parser - pssh -I tee /tmp/settings.yaml >/tmp/pp.out 2>>/tmp/pp.err" /tmp/cluster" + pssh " + echo \$PSSH_HOST > /tmp/ipv4 + head -n 1 /tmp/cluster | sudo tee /etc/ipv4_of_first_node + echo ${CLUSTERPREFIX}1 | sudo tee /etc/name_of_first_node + echo HOSTIP=\$PSSH_HOST | sudo tee -a /etc/environment + NODEINDEX=\$((\$PSSH_NODENUM%$CLUSTERSIZE+1)) + if [ \$NODEINDEX = 1 ]; then + sudo ln -sf /bin/true /usr/local/bin/i_am_first_node + else + sudo ln -sf /bin/false /usr/local/bin/i_am_first_node + fi + echo $CLUSTERPREFIX\$NODEINDEX | sudo tee /etc/hostname + sudo hostname $CLUSTERPREFIX\$NODEINDEX + N=1 + while read ip; do + grep -w \$ip /etc/hosts || echo \$ip $CLUSTERPREFIX\$N | sudo tee -a /etc/hosts + N=\$((\$N+1)) + done < /tmp/cluster + " echo cluster_ok > tags/$TAG/status } @@ -343,11 +459,7 @@ _cmd kube "Setup kubernetes clusters with kubeadm (must be run AFTER deploy)" _cmd_kube() { TAG=$1 need_tag - need_login_password - # Optional version, e.g. 1.13.5 - SETTINGS=tags/$TAG/settings.yaml - KUBEVERSION=$(awk '/^kubernetes_version:/ {print $2}' $SETTINGS) if [ "$KUBEVERSION" ]; then pssh " sudo tee /etc/apt/preferences.d/kubernetes <&1 >/dev/null && { + pssh -l root " + grep DEBIAN_FRONTEND /etc/environment || echo DEBIAN_FRONTEND=noninteractive >> /etc/environment + #grep cloud-init /etc/sudoers && rm /etc/sudoers + apt-get update && apt-get install sudo -y + getent passwd ubuntu || { + useradd ubuntu -m -s /bin/bash + echo 'ubuntu ALL=(ALL:ALL) NOPASSWD:ALL' > /etc/sudoers.d/ubuntu + } + install --owner=ubuntu --mode=700 --directory /home/ubuntu/.ssh + install --owner=ubuntu --mode=600 /root/.ssh/authorized_keys --target-directory /home/ubuntu/.ssh + " + } + + # Now make sure that we have an ubuntu user + pssh true + + # Disable unattended upgrades so that they don't mess up with the subsequent steps + pssh sudo rm -f /etc/apt/apt.conf.d/50unattended-upgrades + + # Digital Ocean's cloud init disables password authentication; re-enable it. + pssh " + if [ -f /etc/ssh/sshd_config.d/50-cloud-init.conf ]; then + sudo rm /etc/ssh/sshd_config.d/50-cloud-init.conf + sudo systemctl restart ssh.service + fi" + + # Special case for oracle since their iptables blocks everything but SSH + pssh " + if [ -f /etc/iptables/rules.v4 ]; then + sudo sed -i 's/-A INPUT -j REJECT --reject-with icmp-host-prohibited//' /etc/iptables/rules.v4 + sudo netfilter-persistent flush + sudo netfilter-persistent start + fi" + + # oracle-cloud-agent upgrades pacakges in the background. + # This breaks our deployment scripts, because when we invoke apt-get, it complains + # that the lock already exists (symptom: random "Exited with error code 100"). + # Workaround: if we detect oracle-cloud-agent, remove it. + # But this agent seems to also take care of installing/upgrading + # the unified-monitoring-agent package, so when we stop the snap, + # it can leave dpkg in a broken state. We "fix" it with the 2nd command. + pssh " + if [ -d /snap/oracle-cloud-agent ]; then + sudo snap remove oracle-cloud-agent + sudo dpkg --remove --force-remove-reinstreq unified-monitoring-agent + fi" +} + _cmd tailhist "Install history viewer on port 1088" _cmd_tailhist () { TAG=$1 need_tag - need_login_password ARCH=${ARCHITECTURE-amd64} [ "$ARCH" = "aarch64" ] && ARCH=arm64 @@ -825,20 +993,6 @@ _cmd_tools() { " } -_cmd opensg "Open the default security group to ALL ingress traffic" -_cmd_opensg() { - need_infra $1 - infra_opensg -} - -_cmd disableaddrchecks "Disable source/destination IP address checks" -_cmd_disableaddrchecks() { - TAG=$1 - need_tag - - infra_disableaddrchecks -} - _cmd pssh "Run an arbitrary command on all nodes" _cmd_pssh() { TAG=$1 @@ -880,122 +1034,22 @@ fi " } -_cmd quotas "Check our infrastructure quotas (max instances)" -_cmd_quotas() { - need_infra $1 - infra_quotas -} - _cmd ssh "Open an SSH session to the first node of a tag" _cmd_ssh() { TAG=$1 need_tag - need_login_password IP=$(head -1 tags/$TAG/ips.txt) info "Logging into $IP (default password: $USER_PASSWORD)" ssh $SSHOPTS $USER_LOGIN@$IP } -_cmd start "Start a group of VMs" -_cmd_start() { - while [ ! -z "$*" ]; do - case "$1" in - --infra) INFRA=$2; shift 2;; - --settings) SETTINGS=$2; shift 2;; - --count) die "Flag --count is deprecated; please use --students instead." ;; - --tag) TAG=$2; shift 2;; - --students) STUDENTS=$2; shift 2;; - *) die "Unrecognized parameter: $1." - esac - done - - if [ -z "$INFRA" ]; then - die "Please add --infra flag to specify which infrastructure file to use." - fi - if [ -z "$SETTINGS" ]; then - die "Please add --settings flag to specify which settings file to use." - fi - if [ -z "$COUNT" ]; then - CLUSTERSIZE=$(awk '/^clustersize:/ {print $2}' $SETTINGS) - if [ -z "$STUDENTS" ]; then - warning "Neither --count nor --students was specified." - warning "According to the settings file, the cluster size is $CLUSTERSIZE." - warning "Deploying one cluster of $CLUSTERSIZE nodes." - STUDENTS=1 - fi - COUNT=$(($STUDENTS*$CLUSTERSIZE)) - fi - - # Check that the specified settings and infrastructure are valid. - need_settings $SETTINGS - need_infra $INFRA - - if [ -z "$TAG" ]; then - TAG=$(_cmd_maketag) - fi - mkdir -p tags/$TAG - ln -s ../../$INFRA tags/$TAG/infra.sh - ln -s ../../$SETTINGS tags/$TAG/settings.yaml - echo creating > tags/$TAG/status - - infra_start $COUNT - sep - info "Successfully created $COUNT instances with tag $TAG" - echo create_ok > tags/$TAG/status - - # If the settings.yaml file has a "steps" field, - # automatically execute all the actions listed in that field. - # If an action fails, retry it up to 10 times. - python -c 'if True: # hack to deal with indentation - import sys, yaml - settings = yaml.safe_load(sys.stdin) - print ("\n".join(settings.get("steps", []))) - ' < tags/$TAG/settings.yaml \ - | while read step; do - if [ -z "$step" ]; then - break - fi - sep "$TAG -> $step" - TRY=1 - MAXTRY=10 - while ! $0 $step $TAG ; do - TRY=$(($TRY+1)) - if [ $TRY -gt $MAXTRY ]; then - error "This step ($step) failed after $MAXTRY attempts." - info "You can troubleshoot the situation manually, or terminate these instances with:" - info "$0 stop $TAG" - die "Giving up." - else - sep - info "Step '$step' failed for '$TAG'. Let's wait 10 seconds and try again." - info "(Attempt $TRY out of $MAXTRY.)" - sleep 10 - fi - done - done - sep - info "Deployment successful." - info "To log into the first machine of that batch, you can run:" - info "$0 ssh $TAG" - info "To terminate these instances, you can run:" - info "$0 stop $TAG" -} - -_cmd stop "Stop (terminate, shutdown, kill, remove, destroy...) instances" -_cmd_stop() { - TAG=$1 - need_tag - infra_stop - echo stopped > tags/$TAG/status -} - _cmd tags "List groups of VMs known locally" _cmd_tags() { ( cd tags - echo "[#] [Status] [Tag] [Infra]" \ - | awk '{ printf "%-7s %-12s %-25s %-25s\n", $1, $2, $3, $4}' + echo "[#] [Status] [Tag] [Mode] [Provider]" \ + | awk '{ printf "%-7s %-12s %-30s %-10s %-25s\n", $1, $2, $3, $4, $5 }' for tag in *; do if [ -f $tag/ips.txt ]; then count="$(wc -l < $tag/ips.txt)" @@ -1007,13 +1061,18 @@ _cmd_tags() { else status="?" fi - if [ -f $tag/infra.sh ]; then - infra="$(basename $(readlink $tag/infra.sh))" + if [ -f $tag/mode ]; then + mode="$(cat $tag/mode)" + else + mode="?" + fi + if [ -f $tag/provider ]; then + provider="$(cat $tag/provider)" else - infra="?" + provider="?" fi - echo "$count $status $tag $infra" \ - | awk '{ printf "%-7s %-12s %-25s %-25s\n", $1, $2, $3, $4}' + echo "$count $status $tag $mode $provider" \ + | awk '{ printf "%-7s %-12s %-30s %-10s %-25s\n", $1, $2, $3, $4, $5 }' done ) } @@ -1055,7 +1114,6 @@ _cmd passwords "Set individual passwords for each cluster" _cmd_passwords() { TAG=$1 need_tag - need_login_password PASSWORDS_FILE="tags/$TAG/passwords" if ! [ -f "$PASSWORDS_FILE" ]; then error "File $PASSWORDS_FILE not found. Please create it first." @@ -1104,22 +1162,6 @@ _cmd_wait() { if [ -d /var/lib/cloud ]; then cloud-init status --wait fi" - - if [ "$SSH_USER" = "root" ]; then - pssh -l root " - getent passwd ubuntu || { - useradd ubuntu -m -s /bin/bash - echo 'ubuntu ALL=(ALL:ALL) NOPASSWD:ALL' > /etc/sudoers.d/ubuntu - } - [ -d /home/ubuntu/.ssh ] || - install --owner=ubuntu --mode=700 --directory /home/ubuntu/.ssh - [ -f /home/ubuntu/.ssh/authorized_keys ] || - install --owner=ubuntu --mode=600 /root/.ssh/authorized_keys --target-directory /home/ubuntu/.ssh - " - fi - - # Now make sure that we have an ubuntu user - pssh true } # Sometimes, weave fails to come up on some nodes. diff --git a/prepare-vms/lib/containerd-config.toml b/prepare-labs/lib/containerd-config.toml similarity index 100% rename from prepare-vms/lib/containerd-config.toml rename to prepare-labs/lib/containerd-config.toml diff --git a/prepare-vms/lib/docker-prompt b/prepare-labs/lib/docker-prompt similarity index 100% rename from prepare-vms/lib/docker-prompt rename to prepare-labs/lib/docker-prompt diff --git a/prepare-vms/lib/find-ubuntu-ami.sh b/prepare-labs/lib/find-ubuntu-ami.sh similarity index 100% rename from prepare-vms/lib/find-ubuntu-ami.sh rename to prepare-labs/lib/find-ubuntu-ami.sh diff --git a/prepare-vms/lib/ips-txt-to-html.py b/prepare-labs/lib/ips-txt-to-html.py similarity index 100% rename from prepare-vms/lib/ips-txt-to-html.py rename to prepare-labs/lib/ips-txt-to-html.py diff --git a/prepare-vms/lib/kubernetes-apt-key.gpg b/prepare-labs/lib/kubernetes-apt-key.gpg similarity index 100% rename from prepare-vms/lib/kubernetes-apt-key.gpg rename to prepare-labs/lib/kubernetes-apt-key.gpg diff --git a/prepare-vms/lib/pssh.sh b/prepare-labs/lib/pssh.sh similarity index 65% rename from prepare-vms/lib/pssh.sh rename to prepare-labs/lib/pssh.sh index 39848f9dc..f7f55e9a4 100644 --- a/prepare-vms/lib/pssh.sh +++ b/prepare-labs/lib/pssh.sh @@ -16,24 +16,12 @@ pssh() { } echo "[parallel-ssh] $@" - export PSSH=$(which pssh || which parallel-ssh) - case "$INFRACLASS" in - hetzner) LOGIN=root ;; - linode) LOGIN=root ;; - *) LOGIN=ubuntu ;; - esac - - if [ -f "tags/$TAG/id_rsa" ]; then - KEYFLAG="-O IdentityFile=tags/$TAG/id_rsa" - else - KEYFLAG="" - fi - - $PSSH $KEYFLAG -h $HOSTFILE -l $LOGIN \ + $(which pssh) -h $HOSTFILE -l ubuntu \ --par ${PSSH_PARALLEL_CONNECTIONS-100} \ --timeout 300 \ -O LogLevel=ERROR \ + -O IdentityFile=tags/$TAG/id_rsa \ -O UserKnownHostsFile=/dev/null \ -O StrictHostKeyChecking=no \ -O ForwardAgent=yes \ diff --git a/prepare-vms/lib/tailhist.html b/prepare-labs/lib/tailhist.html similarity index 100% rename from prepare-vms/lib/tailhist.html rename to prepare-labs/lib/tailhist.html diff --git a/prepare-vms/lib/wkhtmltopdf b/prepare-labs/lib/wkhtmltopdf similarity index 100% rename from prepare-vms/lib/wkhtmltopdf rename to prepare-labs/lib/wkhtmltopdf diff --git a/prepare-vms/map-dns.py b/prepare-labs/map-dns.py similarity index 66% rename from prepare-vms/map-dns.py rename to prepare-labs/map-dns.py index 9601ae741..ae4b12041 100755 --- a/prepare-vms/map-dns.py +++ b/prepare-labs/map-dns.py @@ -2,16 +2,16 @@ """ There are two ways to use this script: -1. Pass a file name and a tag name as a single argument. -It will load a list of domains from the given file (one per line), -and assign them to the clusters corresponding to that tag. -There should be more domains than clusters. -Example: ./map-dns.py domains.txt 2020-08-15-jp - -2. Pass a domain as the 1st argument, and IP addresses then. +1. Pass a domain as the 1st argument, and IP addresses then. It will configure the domain with the listed IP addresses. Example: ./map-dns.py open-duck.site 1.2.3.4 2.3.4.5 3.4.5.6 +2. Pass two files names as argument, in which case the first +file should contain a list of domains, and the second a list of +groups of IP addresses, with one group per line. +There should be more domains than groups of addresses. +Example: ./map-dns.py domains.txt tags/2020-08-15-jp/clusters.txt + In both cases, the domains should be configured to use GANDI LiveDNS. """ import os @@ -30,18 +30,9 @@ if os.path.isfile(domain_or_domain_file): domains = open(domain_or_domain_file).read().split() domains = [ d for d in domains if not d.startswith('#') ] - ips_file_or_tag = sys.argv[2] - if os.path.isfile(ips_file_or_tag): - lines = open(ips_file_or_tag).read().split('\n') - clusters = [line.split() for line in lines] - else: - ips = open(f"tags/{ips_file_or_tag}/ips.txt").read().split() - settings_file = f"tags/{ips_file_or_tag}/settings.yaml" - clustersize = yaml.safe_load(open(settings_file))["clustersize"] - clusters = [] - while ips: - clusters.append(ips[:clustersize]) - ips = ips[clustersize:] + clusters_file = sys.argv[2] + lines = open(clusters_file).read().split('\n') + clusters = [line.split() for line in lines] else: domains = [domain_or_domain_file] clusters = [sys.argv[2:]] diff --git a/prepare-vms/netlify-dns.sh b/prepare-labs/netlify-dns.sh similarity index 100% rename from prepare-vms/netlify-dns.sh rename to prepare-labs/netlify-dns.sh diff --git a/prepare-labs/settings/admin-dmuc.env b/prepare-labs/settings/admin-dmuc.env new file mode 100644 index 000000000..0022f8014 --- /dev/null +++ b/prepare-labs/settings/admin-dmuc.env @@ -0,0 +1,22 @@ +CLUSTERSIZE=1 + +CLUSTERPREFIX=dmuc + +USER_LOGIN=k8s +USER_PASSWORD=training + +STEPS=" + wait + standardize + clusterize + tools + docker + disabledocker + createuser + webssh + tailhist + kubebins + kubetools + cards + ips +" \ No newline at end of file diff --git a/prepare-labs/settings/admin-kubenet.env b/prepare-labs/settings/admin-kubenet.env new file mode 100644 index 000000000..ff3cf2154 --- /dev/null +++ b/prepare-labs/settings/admin-kubenet.env @@ -0,0 +1,23 @@ +CLUSTERSIZE=3 + +CLUSTERPREFIX=kubenet +CLUSTERNUMBER=100 + +USER_LOGIN=k8s +USER_PASSWORD=training + +STEPS=" + disableaddrchecks + wait + standardize + clusterize + tools + docker + createuser + webssh + tailhist + kubebins + kubetools + cards + ips +" \ No newline at end of file diff --git a/prepare-labs/settings/admin-kuberouter.env b/prepare-labs/settings/admin-kuberouter.env new file mode 100644 index 000000000..ec755dc96 --- /dev/null +++ b/prepare-labs/settings/admin-kuberouter.env @@ -0,0 +1,23 @@ +CLUSTERSIZE=3 + +CLUSTERPREFIX=kuberouter +CLUSTERNUMBER=200 + +USER_LOGIN=k8s +USER_PASSWORD=training + +STEPS=" + disableaddrchecks + wait + standardize + clusterize + tools + docker + createuser + webssh + tailhist + kubebins + kubetools + cards + ips +" \ No newline at end of file diff --git a/prepare-labs/settings/admin-oldversion.env b/prepare-labs/settings/admin-oldversion.env new file mode 100644 index 000000000..7b3b1ebeb --- /dev/null +++ b/prepare-labs/settings/admin-oldversion.env @@ -0,0 +1,24 @@ +CLUSTERSIZE=3 + +CLUSTERPREFIX=oldversion + +USER_LOGIN=k8s +USER_PASSWORD=training + +# For a list of old versions, check: +# https://kubernetes.io/releases/patch-releases/#non-active-branch-history +KUBEVERSION=1.20.15 + +STEPS=" + wait + standardize + clusterize + tools + docker + createuser + webssh + tailhist + kube + kubetools + kubetest +" \ No newline at end of file diff --git a/prepare-labs/settings/admin-test.env b/prepare-labs/settings/admin-test.env new file mode 100644 index 000000000..09861fcec --- /dev/null +++ b/prepare-labs/settings/admin-test.env @@ -0,0 +1,20 @@ +CLUSTERSIZE=3 + +CLUSTERPREFIX=test + +USER_LOGIN=k8s +USER_PASSWORD=training + +STEPS=" + wait + standardize + clusterize + tools + docker + createuser + webssh + tailhist + kube + kubetools + kubetest +" \ No newline at end of file diff --git a/prepare-labs/settings/docker.env b/prepare-labs/settings/docker.env new file mode 100644 index 000000000..7d0740e60 --- /dev/null +++ b/prepare-labs/settings/docker.env @@ -0,0 +1,19 @@ +CLUSTERSIZE=1 + +CLUSTERPREFIX=moby + +USER_LOGIN=docker +USER_PASSWORD=training + +STEPS=" + wait + standardize + clusterize + tools + docker + createuser + webssh + tailhist + cards + ips +" \ No newline at end of file diff --git a/prepare-labs/settings/kubernetes.env b/prepare-labs/settings/kubernetes.env new file mode 100644 index 000000000..24c4f553a --- /dev/null +++ b/prepare-labs/settings/kubernetes.env @@ -0,0 +1,20 @@ +CLUSTERSIZE=4 + +CLUSTERPREFIX=node + +USER_LOGIN=k8s +USER_PASSWORD=training + +STEPS=" + wait + standardize + clusterize + tools + docker + createuser + webssh + tailhist + kube + kubetools + kubetest +" \ No newline at end of file diff --git a/prepare-labs/settings/largekube.env b/prepare-labs/settings/largekube.env new file mode 100644 index 000000000..8bd115981 --- /dev/null +++ b/prepare-labs/settings/largekube.env @@ -0,0 +1,21 @@ +CLUSTERSIZE=10 +export TF_VAR_node_size=GP1.M + +CLUSTERPREFIX=node + +USER_LOGIN=k8s +USER_PASSWORD=training + +STEPS=" + wait + standardize + clusterize + tools + docker + createuser + webssh + tailhist + kube + kubetools + kubetest +" diff --git a/prepare-labs/settings/mk8s.env b/prepare-labs/settings/mk8s.env new file mode 100644 index 000000000..2291b4413 --- /dev/null +++ b/prepare-labs/settings/mk8s.env @@ -0,0 +1,6 @@ +CLUSTERSIZE=2 + +USER_LOGIN=k8s +USER_PASSWORD= + +STEPS="stage2" diff --git a/prepare-labs/settings/portal.env b/prepare-labs/settings/portal.env new file mode 100644 index 000000000..04c93f019 --- /dev/null +++ b/prepare-labs/settings/portal.env @@ -0,0 +1,16 @@ +CLUSTERSIZE=1 + +CLUSTERPREFIX=CHANGEME + +USER_LOGIN=portal +USER_PASSWORD=CHANGEME + +STEPS=" + wait + standardize + clusterize + tools + docker + createuser + ips +" diff --git a/prepare-vms/setup-admin-clusters.sh b/prepare-labs/setup-admin-clusters.sh similarity index 100% rename from prepare-vms/setup-admin-clusters.sh rename to prepare-labs/setup-admin-clusters.sh diff --git a/prepare-labs/tags b/prepare-labs/tags new file mode 120000 index 000000000..212737a7d --- /dev/null +++ b/prepare-labs/tags @@ -0,0 +1 @@ +terraform/tags \ No newline at end of file diff --git a/prepare-vms/templates/cards.html b/prepare-labs/templates/cards.html similarity index 100% rename from prepare-vms/templates/cards.html rename to prepare-labs/templates/cards.html diff --git a/prepare-vms/templates/clusters.csv b/prepare-labs/templates/clusters.csv similarity index 100% rename from prepare-vms/templates/clusters.csv rename to prepare-labs/templates/clusters.csv diff --git a/prepare-labs/terraform/list-locations/azure b/prepare-labs/terraform/list-locations/azure new file mode 100755 index 000000000..207b0027e --- /dev/null +++ b/prepare-labs/terraform/list-locations/azure @@ -0,0 +1,4 @@ +#!/bin/sh +az account list-locations -o table \ + --query "sort_by([?metadata.regionType == 'Physical'], ®ionalDisplayName)[] + .{ displayName: displayName, regionalDisplayName: regionalDisplayName }" diff --git a/prepare-tf/source/modules/digitalocean/list_locations.sh b/prepare-labs/terraform/list-locations/digitalocean similarity index 100% rename from prepare-tf/source/modules/digitalocean/list_locations.sh rename to prepare-labs/terraform/list-locations/digitalocean diff --git a/prepare-tf/source/modules/googlecloud/list_locations.sh b/prepare-labs/terraform/list-locations/googlecloud similarity index 100% rename from prepare-tf/source/modules/googlecloud/list_locations.sh rename to prepare-labs/terraform/list-locations/googlecloud diff --git a/prepare-tf/source/modules/linode/list_locations.sh b/prepare-labs/terraform/list-locations/linode similarity index 100% rename from prepare-tf/source/modules/linode/list_locations.sh rename to prepare-labs/terraform/list-locations/linode diff --git a/prepare-tf/source/modules/oraclecloud/list_locations.sh b/prepare-labs/terraform/list-locations/oraclecloud similarity index 100% rename from prepare-tf/source/modules/oraclecloud/list_locations.sh rename to prepare-labs/terraform/list-locations/oraclecloud diff --git a/prepare-tf/source/modules/scaleway/list_locations.sh b/prepare-labs/terraform/list-locations/scaleway similarity index 100% rename from prepare-tf/source/modules/scaleway/list_locations.sh rename to prepare-labs/terraform/list-locations/scaleway diff --git a/prepare-tf/source/locals.tf b/prepare-labs/terraform/many-kubernetes/locals.tf similarity index 60% rename from prepare-tf/source/locals.tf rename to prepare-labs/terraform/many-kubernetes/locals.tf index 760ec4977..2da350f0a 100644 --- a/prepare-tf/source/locals.tf +++ b/prepare-labs/terraform/many-kubernetes/locals.tf @@ -8,8 +8,10 @@ resource "random_string" "_" { resource "time_static" "_" {} locals { - timestamp = formatdate("YYYY-MM-DD-hh-mm", time_static._.rfc3339) - tag = random_string._.result + min_nodes_per_pool = var.nodes_per_cluster + max_nodes_per_pool = var.nodes_per_cluster * 2 + timestamp = formatdate("YYYY-MM-DD-hh-mm", time_static._.rfc3339) + tag = random_string._.result # Common tags to be assigned to all resources common_tags = [ "created-by-terraform", diff --git a/prepare-tf/source/main.tf b/prepare-labs/terraform/many-kubernetes/main.tf similarity index 94% rename from prepare-tf/source/main.tf rename to prepare-labs/terraform/many-kubernetes/main.tf index 905ae56ac..300182444 100644 --- a/prepare-tf/source/main.tf +++ b/prepare-labs/terraform/many-kubernetes/main.tf @@ -1,9 +1,9 @@ module "clusters" { - source = "./modules/PROVIDER" + source = "./one-kubernetes-module" for_each = local.clusters cluster_name = each.value.cluster_name - min_nodes_per_pool = var.min_nodes_per_pool - max_nodes_per_pool = var.max_nodes_per_pool + min_nodes_per_pool = local.min_nodes_per_pool + max_nodes_per_pool = local.max_nodes_per_pool enable_arm_pool = var.enable_arm_pool node_size = var.node_size common_tags = local.common_tags diff --git a/prepare-labs/terraform/many-kubernetes/one-kubernetes-config.tf b/prepare-labs/terraform/many-kubernetes/one-kubernetes-config.tf new file mode 120000 index 000000000..eda2af1de --- /dev/null +++ b/prepare-labs/terraform/many-kubernetes/one-kubernetes-config.tf @@ -0,0 +1 @@ +one-kubernetes-config/config.tf \ No newline at end of file diff --git a/prepare-labs/terraform/many-kubernetes/one-kubernetes-config/README.md b/prepare-labs/terraform/many-kubernetes/one-kubernetes-config/README.md new file mode 100644 index 000000000..b01c3594b --- /dev/null +++ b/prepare-labs/terraform/many-kubernetes/one-kubernetes-config/README.md @@ -0,0 +1,3 @@ +This directory should contain a config.tf file, even if it's empty. +(Because if the file doesn't exist, then the Terraform configuration +in the parent directory will fail.) diff --git a/prepare-labs/terraform/many-kubernetes/one-kubernetes-module/README.md b/prepare-labs/terraform/many-kubernetes/one-kubernetes-module/README.md new file mode 100644 index 000000000..0d876326f --- /dev/null +++ b/prepare-labs/terraform/many-kubernetes/one-kubernetes-module/README.md @@ -0,0 +1,8 @@ +This directory should contain a copy of one of the "one-kubernetes" modules. +For instance, when located in this directory, you can do: + +cp ../../one-kubernetes/linode/* . + +Then, move the config.tf file to ../one-kubernetes-config: + +mv config.tf ../one-kubernetes-config diff --git a/prepare-labs/terraform/many-kubernetes/one-kubernetes-provider.tf b/prepare-labs/terraform/many-kubernetes/one-kubernetes-provider.tf new file mode 120000 index 000000000..316953df4 --- /dev/null +++ b/prepare-labs/terraform/many-kubernetes/one-kubernetes-provider.tf @@ -0,0 +1 @@ +one-kubernetes-module/provider.tf \ No newline at end of file diff --git a/prepare-labs/terraform/many-kubernetes/providers.tf b/prepare-labs/terraform/many-kubernetes/providers.tf new file mode 100644 index 000000000..0489200d6 --- /dev/null +++ b/prepare-labs/terraform/many-kubernetes/providers.tf @@ -0,0 +1,3 @@ +terraform { + required_version = ">= 1.4" +} diff --git a/prepare-tf/source/stage2.tmpl b/prepare-labs/terraform/many-kubernetes/stage2.tmpl similarity index 100% rename from prepare-tf/source/stage2.tmpl rename to prepare-labs/terraform/many-kubernetes/stage2.tmpl diff --git a/prepare-tf/source/variables.tf b/prepare-labs/terraform/many-kubernetes/variables.tf similarity index 54% rename from prepare-tf/source/variables.tf rename to prepare-labs/terraform/many-kubernetes/variables.tf index cfabf7ae2..1dfcda3f2 100644 --- a/prepare-tf/source/variables.tf +++ b/prepare-labs/terraform/many-kubernetes/variables.tf @@ -1,27 +1,20 @@ -variable "how_many_clusters" { - type = number - default = 1 +variable "tag" { + type = string } -variable "node_size" { - type = string - default = "M" - # Can be S, M, L. - # We map these values to different specific instance types for each provider, - # but the idea is that they shoudl correspond to the following sizes: - # S = 2 GB RAM - # M = 4 GB RAM - # L = 8 GB RAM +variable "how_many_clusters" { + type = number + default = 2 } -variable "min_nodes_per_pool" { +variable "nodes_per_cluster" { type = number - default = 1 + default = 2 } -variable "max_nodes_per_pool" { - type = number - default = 0 +variable "node_size" { + type = string + default = "M" } variable "enable_arm_pool" { diff --git a/prepare-labs/terraform/one-kubernetes/aws/common.tf b/prepare-labs/terraform/one-kubernetes/aws/common.tf new file mode 120000 index 000000000..a0251abd3 --- /dev/null +++ b/prepare-labs/terraform/one-kubernetes/aws/common.tf @@ -0,0 +1 @@ +../common.tf \ No newline at end of file diff --git a/prepare-labs/terraform/one-kubernetes/aws/config.tf b/prepare-labs/terraform/one-kubernetes/aws/config.tf new file mode 120000 index 000000000..5675a9204 --- /dev/null +++ b/prepare-labs/terraform/one-kubernetes/aws/config.tf @@ -0,0 +1 @@ +../../provider-config/aws.tf \ No newline at end of file diff --git a/prepare-labs/terraform/one-kubernetes/aws/main.tf b/prepare-labs/terraform/one-kubernetes/aws/main.tf new file mode 100644 index 000000000..24d094e64 --- /dev/null +++ b/prepare-labs/terraform/one-kubernetes/aws/main.tf @@ -0,0 +1,87 @@ +# Taken from: +# https://github.com/hashicorp/learn-terraform-provision-eks-cluster/blob/main/main.tf + +data "aws_availability_zones" "available" {} + +module "vpc" { + source = "terraform-aws-modules/vpc/aws" + version = "3.19.0" + + name = var.cluster_name + + cidr = "10.0.0.0/16" + azs = slice(data.aws_availability_zones.available.names, 0, 3) + + private_subnets = ["10.0.1.0/24", "10.0.2.0/24", "10.0.3.0/24"] + public_subnets = ["10.0.4.0/24", "10.0.5.0/24", "10.0.6.0/24"] + + enable_nat_gateway = true + single_nat_gateway = true + enable_dns_hostnames = true + + public_subnet_tags = { + "kubernetes.io/cluster/${var.cluster_name}" = "shared" + "kubernetes.io/role/elb" = 1 + } + + private_subnet_tags = { + "kubernetes.io/cluster/${var.cluster_name}" = "shared" + "kubernetes.io/role/internal-elb" = 1 + } +} + +module "eks" { + source = "terraform-aws-modules/eks/aws" + version = "19.5.1" + + cluster_name = var.cluster_name + cluster_version = "1.24" + + vpc_id = module.vpc.vpc_id + subnet_ids = module.vpc.private_subnets + cluster_endpoint_public_access = true + + eks_managed_node_group_defaults = { + ami_type = "AL2_x86_64" + + } + + eks_managed_node_groups = { + one = { + name = "node-group-one" + + instance_types = [local.node_size] + + min_size = var.min_nodes_per_pool + max_size = var.max_nodes_per_pool + desired_size = var.min_nodes_per_pool + } + } +} + +# https://aws.amazon.com/blogs/containers/amazon-ebs-csi-driver-is-now-generally-available-in-amazon-eks-add-ons/ +data "aws_iam_policy" "ebs_csi_policy" { + arn = "arn:aws:iam::aws:policy/service-role/AmazonEBSCSIDriverPolicy" +} + +module "irsa-ebs-csi" { + source = "terraform-aws-modules/iam/aws//modules/iam-assumable-role-with-oidc" + version = "4.7.0" + + create_role = true + role_name = "AmazonEKSTFEBSCSIRole-${module.eks.cluster_name}" + provider_url = module.eks.oidc_provider + role_policy_arns = [data.aws_iam_policy.ebs_csi_policy.arn] + oidc_fully_qualified_subjects = ["system:serviceaccount:kube-system:ebs-csi-controller-sa"] +} + +resource "aws_eks_addon" "ebs-csi" { + cluster_name = module.eks.cluster_name + addon_name = "aws-ebs-csi-driver" + addon_version = "v1.5.2-eksbuild.1" + service_account_role_arn = module.irsa-ebs-csi.iam_role_arn + tags = { + "eks_addon" = "ebs-csi" + "terraform" = "true" + } +} \ No newline at end of file diff --git a/prepare-labs/terraform/one-kubernetes/aws/outputs.tf b/prepare-labs/terraform/one-kubernetes/aws/outputs.tf new file mode 100644 index 000000000..972915408 --- /dev/null +++ b/prepare-labs/terraform/one-kubernetes/aws/outputs.tf @@ -0,0 +1,44 @@ +output "cluster_id" { + value = module.eks.cluster_arn +} + +output "has_metrics_server" { + value = false +} + +output "kubeconfig" { + sensitive = true + value = yamlencode({ + apiVersion = "v1" + kind = "Config" + clusters = [{ + name = var.cluster_name + cluster = { + certificate-authority-data = module.eks.cluster_certificate_authority_data + server = module.eks.cluster_endpoint + } + }] + contexts = [{ + name = var.cluster_name + context = { + cluster = var.cluster_name + user = var.cluster_name + } + }] + users = [{ + name = var.cluster_name + user = { + exec = { + apiVersion = "client.authentication.k8s.io/v1beta1" + command = "aws" + args = ["eks", "get-token", "--cluster-name", var.cluster_name] + } + } + }] + current-context = var.cluster_name + }) +} + +data "aws_eks_cluster_auth" "_" { + name = module.eks.cluster_name +} diff --git a/prepare-labs/terraform/one-kubernetes/aws/provider.tf b/prepare-labs/terraform/one-kubernetes/aws/provider.tf new file mode 100644 index 000000000..f2702bf6e --- /dev/null +++ b/prepare-labs/terraform/one-kubernetes/aws/provider.tf @@ -0,0 +1,7 @@ +terraform { + required_providers { + aws = { + source = "hashicorp/aws" + } + } +} diff --git a/prepare-labs/terraform/one-kubernetes/civo/common.tf b/prepare-labs/terraform/one-kubernetes/civo/common.tf new file mode 120000 index 000000000..a0251abd3 --- /dev/null +++ b/prepare-labs/terraform/one-kubernetes/civo/common.tf @@ -0,0 +1 @@ +../common.tf \ No newline at end of file diff --git a/prepare-labs/terraform/one-kubernetes/civo/config.tf b/prepare-labs/terraform/one-kubernetes/civo/config.tf new file mode 120000 index 000000000..7bae5c4ef --- /dev/null +++ b/prepare-labs/terraform/one-kubernetes/civo/config.tf @@ -0,0 +1 @@ +../../provider-config/civo.tf \ No newline at end of file diff --git a/prepare-labs/terraform/one-kubernetes/civo/main.tf b/prepare-labs/terraform/one-kubernetes/civo/main.tf new file mode 100644 index 000000000..1ad5ce347 --- /dev/null +++ b/prepare-labs/terraform/one-kubernetes/civo/main.tf @@ -0,0 +1,17 @@ +# As of March 2023, the default type ("k3s") only supports up +# to Kubernetes 1.23, which belongs to a museum. +# So let's use Talos, which supports up to 1.25. + +resource "civo_kubernetes_cluster" "_" { + name = var.cluster_name + firewall_id = civo_firewall._.id + cluster_type = "talos" + pools { + size = local.node_size + node_count = var.min_nodes_per_pool + } +} + +resource "civo_firewall" "_" { + name = var.cluster_name +} diff --git a/prepare-labs/terraform/one-kubernetes/civo/outputs.tf b/prepare-labs/terraform/one-kubernetes/civo/outputs.tf new file mode 100644 index 000000000..efddd0565 --- /dev/null +++ b/prepare-labs/terraform/one-kubernetes/civo/outputs.tf @@ -0,0 +1,12 @@ +output "cluster_id" { + value = civo_kubernetes_cluster._.id +} + +output "has_metrics_server" { + value = false +} + +output "kubeconfig" { + value = civo_kubernetes_cluster._.kubeconfig + sensitive = true +} diff --git a/prepare-labs/terraform/one-kubernetes/civo/provider.tf b/prepare-labs/terraform/one-kubernetes/civo/provider.tf new file mode 100644 index 000000000..70fb12994 --- /dev/null +++ b/prepare-labs/terraform/one-kubernetes/civo/provider.tf @@ -0,0 +1,7 @@ +terraform { + required_providers { + civo = { + source = "civo/civo" + } + } +} \ No newline at end of file diff --git a/prepare-labs/terraform/one-kubernetes/common.tf b/prepare-labs/terraform/one-kubernetes/common.tf new file mode 100644 index 000000000..95e3da04d --- /dev/null +++ b/prepare-labs/terraform/one-kubernetes/common.tf @@ -0,0 +1,28 @@ +variable "cluster_name" { + type = string + default = "deployed-with-terraform" +} + +variable "common_tags" { + type = list(string) + default = [] +} + +variable "node_size" { + type = string + default = "M" +} + +variable "min_nodes_per_pool" { + type = number + default = 2 +} + +variable "max_nodes_per_pool" { + type = number + default = 4 +} + +locals { + node_size = lookup(var.node_sizes, var.node_size, var.node_size) +} diff --git a/prepare-labs/terraform/one-kubernetes/digitalocean/common.tf b/prepare-labs/terraform/one-kubernetes/digitalocean/common.tf new file mode 120000 index 000000000..a0251abd3 --- /dev/null +++ b/prepare-labs/terraform/one-kubernetes/digitalocean/common.tf @@ -0,0 +1 @@ +../common.tf \ No newline at end of file diff --git a/prepare-labs/terraform/one-kubernetes/digitalocean/config.tf b/prepare-labs/terraform/one-kubernetes/digitalocean/config.tf new file mode 120000 index 000000000..81ac877f5 --- /dev/null +++ b/prepare-labs/terraform/one-kubernetes/digitalocean/config.tf @@ -0,0 +1 @@ +../../provider-config/digitalocean.tf \ No newline at end of file diff --git a/prepare-tf/source/modules/digitalocean/main.tf b/prepare-labs/terraform/one-kubernetes/digitalocean/main.tf similarity index 65% rename from prepare-tf/source/modules/digitalocean/main.tf rename to prepare-labs/terraform/one-kubernetes/digitalocean/main.tf index 29e886cf3..c5252ee3a 100644 --- a/prepare-tf/source/modules/digitalocean/main.tf +++ b/prepare-labs/terraform/one-kubernetes/digitalocean/main.tf @@ -3,15 +3,18 @@ resource "digitalocean_kubernetes_cluster" "_" { tags = var.common_tags # Region is mandatory, so let's provide a default value. region = var.location != null ? var.location : "nyc1" - version = var.k8s_version + version = data.digitalocean_kubernetes_versions._.latest_version node_pool { name = "x86" tags = var.common_tags - size = local.node_type - auto_scale = true + size = local.node_size + auto_scale = var.max_nodes_per_pool > var.min_nodes_per_pool min_nodes = var.min_nodes_per_pool max_nodes = max(var.min_nodes_per_pool, var.max_nodes_per_pool) } } + +data "digitalocean_kubernetes_versions" "_" { +} diff --git a/prepare-tf/source/modules/digitalocean/outputs.tf b/prepare-labs/terraform/one-kubernetes/digitalocean/outputs.tf similarity index 61% rename from prepare-tf/source/modules/digitalocean/outputs.tf rename to prepare-labs/terraform/one-kubernetes/digitalocean/outputs.tf index 6c6567f32..a98dcd184 100644 --- a/prepare-tf/source/modules/digitalocean/outputs.tf +++ b/prepare-labs/terraform/one-kubernetes/digitalocean/outputs.tf @@ -1,7 +1,3 @@ -output "kubeconfig" { - value = digitalocean_kubernetes_cluster._.kube_config.0.raw_config -} - output "cluster_id" { value = digitalocean_kubernetes_cluster._.id } @@ -9,3 +5,8 @@ output "cluster_id" { output "has_metrics_server" { value = false } + +output "kubeconfig" { + value = digitalocean_kubernetes_cluster._.kube_config.0.raw_config + sensitive = true +} diff --git a/prepare-tf/source/modules/digitalocean/providers.tf b/prepare-labs/terraform/one-kubernetes/digitalocean/provider.tf similarity index 57% rename from prepare-tf/source/modules/digitalocean/providers.tf rename to prepare-labs/terraform/one-kubernetes/digitalocean/provider.tf index c2cb425d6..85da66b31 100644 --- a/prepare-tf/source/modules/digitalocean/providers.tf +++ b/prepare-labs/terraform/one-kubernetes/digitalocean/provider.tf @@ -6,7 +6,3 @@ terraform { } } } - -provider "digitalocean" { - token = yamldecode(file("~/.config/doctl/config.yaml"))["access-token"] -} diff --git a/prepare-labs/terraform/one-kubernetes/exoscale/common.tf b/prepare-labs/terraform/one-kubernetes/exoscale/common.tf new file mode 120000 index 000000000..a0251abd3 --- /dev/null +++ b/prepare-labs/terraform/one-kubernetes/exoscale/common.tf @@ -0,0 +1 @@ +../common.tf \ No newline at end of file diff --git a/prepare-labs/terraform/one-kubernetes/exoscale/config.tf b/prepare-labs/terraform/one-kubernetes/exoscale/config.tf new file mode 120000 index 000000000..da0d57909 --- /dev/null +++ b/prepare-labs/terraform/one-kubernetes/exoscale/config.tf @@ -0,0 +1 @@ +../../provider-config/exoscale.tf \ No newline at end of file diff --git a/prepare-labs/terraform/one-kubernetes/exoscale/main.tf b/prepare-labs/terraform/one-kubernetes/exoscale/main.tf new file mode 100644 index 000000000..6e092311b --- /dev/null +++ b/prepare-labs/terraform/one-kubernetes/exoscale/main.tf @@ -0,0 +1,20 @@ +resource "exoscale_sks_cluster" "_" { + zone = var.location + name = var.cluster_name + service_level = "starter" +} + +resource "exoscale_sks_nodepool" "_" { + cluster_id = exoscale_sks_cluster._.id + zone = exoscale_sks_cluster._.zone + name = var.cluster_name + instance_type = local.node_size + size = var.min_nodes_per_pool +} + +resource "exoscale_sks_kubeconfig" "_" { + cluster_id = exoscale_sks_cluster._.id + zone = exoscale_sks_cluster._.zone + user = "kubernetes-admin" + groups = ["system:masters"] +} \ No newline at end of file diff --git a/prepare-labs/terraform/one-kubernetes/exoscale/outputs.tf b/prepare-labs/terraform/one-kubernetes/exoscale/outputs.tf new file mode 100644 index 000000000..b189f307a --- /dev/null +++ b/prepare-labs/terraform/one-kubernetes/exoscale/outputs.tf @@ -0,0 +1,12 @@ +output "cluster_id" { + value = exoscale_sks_cluster._.id +} + +output "has_metrics_server" { + value = true +} + +output "kubeconfig" { + value = exoscale_sks_kubeconfig._.kubeconfig + sensitive = true +} diff --git a/prepare-labs/terraform/one-kubernetes/exoscale/provider.tf b/prepare-labs/terraform/one-kubernetes/exoscale/provider.tf new file mode 100644 index 000000000..f69fb32e3 --- /dev/null +++ b/prepare-labs/terraform/one-kubernetes/exoscale/provider.tf @@ -0,0 +1,7 @@ +terraform { + required_providers { + exoscale = { + source = "exoscale/exoscale" + } + } +} diff --git a/prepare-labs/terraform/one-kubernetes/googlecloud/common.tf b/prepare-labs/terraform/one-kubernetes/googlecloud/common.tf new file mode 120000 index 000000000..a0251abd3 --- /dev/null +++ b/prepare-labs/terraform/one-kubernetes/googlecloud/common.tf @@ -0,0 +1 @@ +../common.tf \ No newline at end of file diff --git a/prepare-labs/terraform/one-kubernetes/googlecloud/config.tf b/prepare-labs/terraform/one-kubernetes/googlecloud/config.tf new file mode 120000 index 000000000..0c56ef723 --- /dev/null +++ b/prepare-labs/terraform/one-kubernetes/googlecloud/config.tf @@ -0,0 +1 @@ +../../provider-config/googlecloud.tf \ No newline at end of file diff --git a/prepare-tf/source/modules/googlecloud/main.tf b/prepare-labs/terraform/one-kubernetes/googlecloud/main.tf similarity index 87% rename from prepare-tf/source/modules/googlecloud/main.tf rename to prepare-labs/terraform/one-kubernetes/googlecloud/main.tf index 5718dfbbf..605944eae 100644 --- a/prepare-tf/source/modules/googlecloud/main.tf +++ b/prepare-labs/terraform/one-kubernetes/googlecloud/main.tf @@ -1,8 +1,8 @@ resource "google_container_cluster" "_" { - name = var.cluster_name - project = local.project - location = local.location - min_master_version = var.k8s_version + name = var.cluster_name + project = local.project + location = local.location + #min_master_version = var.k8s_version # To deploy private clusters, uncomment the section below, # and uncomment the block in network.tf. @@ -43,12 +43,12 @@ resource "google_container_cluster" "_" { name = "x86" node_config { tags = var.common_tags - machine_type = local.node_type + machine_type = local.node_size } initial_node_count = var.min_nodes_per_pool autoscaling { min_node_count = var.min_nodes_per_pool - max_node_count = max(var.min_nodes_per_pool, var.max_nodes_per_pool) + max_node_count = var.max_nodes_per_pool } } @@ -62,4 +62,3 @@ resource "google_container_cluster" "_" { } } } - diff --git a/prepare-tf/source/modules/googlecloud/network.tf b/prepare-labs/terraform/one-kubernetes/googlecloud/network.tf similarity index 100% rename from prepare-tf/source/modules/googlecloud/network.tf rename to prepare-labs/terraform/one-kubernetes/googlecloud/network.tf diff --git a/prepare-tf/source/modules/googlecloud/outputs.tf b/prepare-labs/terraform/one-kubernetes/googlecloud/outputs.tf similarity index 94% rename from prepare-tf/source/modules/googlecloud/outputs.tf rename to prepare-labs/terraform/one-kubernetes/googlecloud/outputs.tf index 3d8343ea6..687943462 100644 --- a/prepare-tf/source/modules/googlecloud/outputs.tf +++ b/prepare-labs/terraform/one-kubernetes/googlecloud/outputs.tf @@ -1,7 +1,14 @@ -data "google_client_config" "_" {} +output "cluster_id" { + value = google_container_cluster._.id +} + +output "has_metrics_server" { + value = true +} output "kubeconfig" { - value = <<-EOT + sensitive = true + value = <<-EOT apiVersion: v1 kind: Config current-context: ${google_container_cluster._.name} @@ -25,11 +32,3 @@ output "kubeconfig" { token: ${data.google_client_config._.access_token} EOT } - -output "cluster_id" { - value = google_container_cluster._.id -} - -output "has_metrics_server" { - value = true -} diff --git a/prepare-tf/source/modules/googlecloud/providers.tf b/prepare-labs/terraform/one-kubernetes/googlecloud/provider.tf similarity index 100% rename from prepare-tf/source/modules/googlecloud/providers.tf rename to prepare-labs/terraform/one-kubernetes/googlecloud/provider.tf diff --git a/prepare-labs/terraform/one-kubernetes/googlecloud/variables.tf b/prepare-labs/terraform/one-kubernetes/googlecloud/variables.tf new file mode 100644 index 000000000..aeb06c4f8 --- /dev/null +++ b/prepare-labs/terraform/one-kubernetes/googlecloud/variables.tf @@ -0,0 +1,12 @@ +locals { + location = var.location != null ? var.location : "europe-north1-a" + region = replace(local.location, "/-[a-z]$/", "") + # Unfortunately, the following line doesn't work + # (that attribute just returns an empty string) + # so we have to hard-code the project name. + #project = data.google_client_config._.project + project = "prepare-tf" +} + +data "google_client_config" "_" {} + diff --git a/prepare-labs/terraform/one-kubernetes/linode/common.tf b/prepare-labs/terraform/one-kubernetes/linode/common.tf new file mode 120000 index 000000000..a0251abd3 --- /dev/null +++ b/prepare-labs/terraform/one-kubernetes/linode/common.tf @@ -0,0 +1 @@ +../common.tf \ No newline at end of file diff --git a/prepare-labs/terraform/one-kubernetes/linode/config.tf b/prepare-labs/terraform/one-kubernetes/linode/config.tf new file mode 120000 index 000000000..3230f2255 --- /dev/null +++ b/prepare-labs/terraform/one-kubernetes/linode/config.tf @@ -0,0 +1 @@ +../../provider-config/linode.tf \ No newline at end of file diff --git a/prepare-tf/source/modules/linode/main.tf b/prepare-labs/terraform/one-kubernetes/linode/main.tf similarity index 60% rename from prepare-tf/source/modules/linode/main.tf rename to prepare-labs/terraform/one-kubernetes/linode/main.tf index 388964fce..4aed177f0 100644 --- a/prepare-tf/source/modules/linode/main.tf +++ b/prepare-labs/terraform/one-kubernetes/linode/main.tf @@ -3,10 +3,10 @@ resource "linode_lke_cluster" "_" { tags = var.common_tags # "region" is mandatory, so let's provide a default value if none was given. region = var.location != null ? var.location : "eu-central" - k8s_version = local.k8s_version + k8s_version = data.linode_lke_versions._.versions[0].id pool { - type = local.node_type + type = local.node_size count = var.min_nodes_per_pool autoscaler { min = var.min_nodes_per_pool @@ -15,3 +15,9 @@ resource "linode_lke_cluster" "_" { } } + +data "linode_lke_versions" "_" { +} + +# FIXME: sort the versions to be sure that we get the most recent one? +# (We don't know in which order they are returned by the provider.) diff --git a/prepare-tf/source/modules/linode/outputs.tf b/prepare-labs/terraform/one-kubernetes/linode/outputs.tf similarity index 62% rename from prepare-tf/source/modules/linode/outputs.tf rename to prepare-labs/terraform/one-kubernetes/linode/outputs.tf index cc6616911..111da44f2 100644 --- a/prepare-tf/source/modules/linode/outputs.tf +++ b/prepare-labs/terraform/one-kubernetes/linode/outputs.tf @@ -1,7 +1,3 @@ -output "kubeconfig" { - value = base64decode(linode_lke_cluster._.kubeconfig) -} - output "cluster_id" { value = linode_lke_cluster._.id } @@ -9,3 +5,8 @@ output "cluster_id" { output "has_metrics_server" { value = false } + +output "kubeconfig" { + value = base64decode(linode_lke_cluster._.kubeconfig) + sensitive = true +} diff --git a/prepare-labs/terraform/one-kubernetes/linode/provider.tf b/prepare-labs/terraform/one-kubernetes/linode/provider.tf new file mode 100644 index 000000000..604a1981c --- /dev/null +++ b/prepare-labs/terraform/one-kubernetes/linode/provider.tf @@ -0,0 +1,8 @@ +terraform { + required_providers { + linode = { + source = "linode/linode" + version = "1.30.0" + } + } +} diff --git a/prepare-labs/terraform/one-kubernetes/oci/common.tf b/prepare-labs/terraform/one-kubernetes/oci/common.tf new file mode 120000 index 000000000..a0251abd3 --- /dev/null +++ b/prepare-labs/terraform/one-kubernetes/oci/common.tf @@ -0,0 +1 @@ +../common.tf \ No newline at end of file diff --git a/prepare-labs/terraform/one-kubernetes/oci/config.tf b/prepare-labs/terraform/one-kubernetes/oci/config.tf new file mode 120000 index 000000000..3f4487705 --- /dev/null +++ b/prepare-labs/terraform/one-kubernetes/oci/config.tf @@ -0,0 +1 @@ +../../provider-config/oci.tf \ No newline at end of file diff --git a/prepare-tf/source/modules/oraclecloud/main.tf b/prepare-labs/terraform/one-kubernetes/oci/main.tf similarity index 67% rename from prepare-tf/source/modules/oraclecloud/main.tf rename to prepare-labs/terraform/one-kubernetes/oci/main.tf index a3c3263c4..e0fde132d 100644 --- a/prepare-tf/source/modules/oraclecloud/main.tf +++ b/prepare-labs/terraform/one-kubernetes/oci/main.tf @@ -4,8 +4,13 @@ resource "oci_identity_compartment" "_" { enable_delete = true } +data "oci_containerengine_cluster_option" "_" { + cluster_option_id = "all" +} + locals { - compartment_id = oci_identity_compartment._.id + compartment_id = oci_identity_compartment._.id + kubernetes_version = data.oci_containerengine_cluster_option._.kubernetes_versions[0] } data "oci_identity_availability_domains" "_" { @@ -13,16 +18,15 @@ data "oci_identity_availability_domains" "_" { } data "oci_core_images" "_" { - for_each = local.pools compartment_id = local.compartment_id operating_system = "Oracle Linux" - operating_system_version = "7.9" - shape = each.value.shape + operating_system_version = "8" + shape = local.shape } resource "oci_containerengine_cluster" "_" { compartment_id = local.compartment_id - kubernetes_version = var.k8s_version + kubernetes_version = local.kubernetes_version name = "tf-oke" vcn_id = oci_core_vcn._.id options { @@ -35,15 +39,14 @@ resource "oci_containerengine_cluster" "_" { } resource "oci_containerengine_node_pool" "_" { - for_each = local.pools cluster_id = oci_containerengine_cluster._.id compartment_id = local.compartment_id - kubernetes_version = var.k8s_version - name = each.key - node_shape = each.value.shape + kubernetes_version = local.kubernetes_version + name = "pool" + node_shape = local.shape node_shape_config { - memory_in_gbs = local.node_type.memory_in_gbs - ocpus = local.node_type.ocpus + memory_in_gbs = local.memory_in_gbs + ocpus = local.ocpus } node_config_details { size = var.min_nodes_per_pool @@ -53,7 +56,7 @@ resource "oci_containerengine_node_pool" "_" { } } node_source_details { - image_id = data.oci_core_images._[each.key].images[0].id + image_id = data.oci_core_images._.images[0].id source_type = "image" } } diff --git a/prepare-tf/source/modules/oraclecloud/network.tf b/prepare-labs/terraform/one-kubernetes/oci/network.tf similarity index 100% rename from prepare-tf/source/modules/oraclecloud/network.tf rename to prepare-labs/terraform/one-kubernetes/oci/network.tf diff --git a/prepare-tf/source/modules/oraclecloud/outputs.tf b/prepare-labs/terraform/one-kubernetes/oci/outputs.tf similarity index 100% rename from prepare-tf/source/modules/oraclecloud/outputs.tf rename to prepare-labs/terraform/one-kubernetes/oci/outputs.tf index 165d656d7..c81fe5fc0 100644 --- a/prepare-tf/source/modules/oraclecloud/outputs.tf +++ b/prepare-labs/terraform/one-kubernetes/oci/outputs.tf @@ -1,11 +1,3 @@ -data "oci_containerengine_cluster_kube_config" "_" { - cluster_id = oci_containerengine_cluster._.id -} - -output "kubeconfig" { - value = data.oci_containerengine_cluster_kube_config._.content -} - output "cluster_id" { value = oci_containerengine_cluster._.id } @@ -13,3 +5,11 @@ output "cluster_id" { output "has_metrics_server" { value = false } + +output "kubeconfig" { + value = data.oci_containerengine_cluster_kube_config._.content +} + +data "oci_containerengine_cluster_kube_config" "_" { + cluster_id = oci_containerengine_cluster._.id +} diff --git a/prepare-tf/source/modules/oraclecloud/providers.tf b/prepare-labs/terraform/one-kubernetes/oci/provider.tf similarity index 50% rename from prepare-tf/source/modules/oraclecloud/providers.tf rename to prepare-labs/terraform/one-kubernetes/oci/provider.tf index 618ba4453..433f0f263 100644 --- a/prepare-tf/source/modules/oraclecloud/providers.tf +++ b/prepare-labs/terraform/one-kubernetes/oci/provider.tf @@ -1,8 +1,7 @@ terraform { required_providers { oci = { - source = "hashicorp/oci" - version = "4.48.0" + source = "oracle/oci" } } } diff --git a/prepare-labs/terraform/one-kubernetes/scaleway/common.tf b/prepare-labs/terraform/one-kubernetes/scaleway/common.tf new file mode 120000 index 000000000..a0251abd3 --- /dev/null +++ b/prepare-labs/terraform/one-kubernetes/scaleway/common.tf @@ -0,0 +1 @@ +../common.tf \ No newline at end of file diff --git a/prepare-labs/terraform/one-kubernetes/scaleway/config.tf b/prepare-labs/terraform/one-kubernetes/scaleway/config.tf new file mode 120000 index 000000000..3ac2b26e6 --- /dev/null +++ b/prepare-labs/terraform/one-kubernetes/scaleway/config.tf @@ -0,0 +1 @@ +../../provider-config/scaleway.tf \ No newline at end of file diff --git a/prepare-labs/terraform/one-kubernetes/scaleway/main.tf b/prepare-labs/terraform/one-kubernetes/scaleway/main.tf new file mode 100644 index 000000000..87167d8af --- /dev/null +++ b/prepare-labs/terraform/one-kubernetes/scaleway/main.tf @@ -0,0 +1,28 @@ +resource "scaleway_k8s_cluster" "_" { + name = var.cluster_name + #region = var.location + tags = var.common_tags + version = local.k8s_version + cni = "cilium" + delete_additional_resources = true +} + +resource "scaleway_k8s_pool" "_" { + cluster_id = scaleway_k8s_cluster._.id + name = "x86" + tags = var.common_tags + node_type = local.node_size + size = var.min_nodes_per_pool + min_size = var.min_nodes_per_pool + max_size = var.max_nodes_per_pool + autoscaling = var.max_nodes_per_pool > var.min_nodes_per_pool + autohealing = true +} + +data "scaleway_k8s_version" "_" { + name = "latest" +} + +locals { + k8s_version = data.scaleway_k8s_version._.name +} diff --git a/prepare-labs/terraform/one-kubernetes/scaleway/outputs.tf b/prepare-labs/terraform/one-kubernetes/scaleway/outputs.tf new file mode 100644 index 000000000..5102e5f24 --- /dev/null +++ b/prepare-labs/terraform/one-kubernetes/scaleway/outputs.tf @@ -0,0 +1,12 @@ +output "cluster_id" { + value = scaleway_k8s_cluster._.id +} + +output "has_metrics_server" { + value = sort([local.k8s_version, "1.22"])[0] == "1.22" +} + +output "kubeconfig" { + sensitive = true + value = scaleway_k8s_cluster._.kubeconfig.0.config_file +} diff --git a/prepare-tf/source/modules/scaleway/providers.tf b/prepare-labs/terraform/one-kubernetes/scaleway/provider.tf similarity index 51% rename from prepare-tf/source/modules/scaleway/providers.tf rename to prepare-labs/terraform/one-kubernetes/scaleway/provider.tf index fc6d5fa2f..3f217ed5b 100644 --- a/prepare-tf/source/modules/scaleway/providers.tf +++ b/prepare-labs/terraform/one-kubernetes/scaleway/provider.tf @@ -1,8 +1,7 @@ terraform { required_providers { scaleway = { - source = "scaleway/scaleway" - version = "2.1.0" + source = "scaleway/scaleway" } } } diff --git a/prepare-labs/terraform/one-kubernetes/vcluster/common.tf b/prepare-labs/terraform/one-kubernetes/vcluster/common.tf new file mode 120000 index 000000000..a0251abd3 --- /dev/null +++ b/prepare-labs/terraform/one-kubernetes/vcluster/common.tf @@ -0,0 +1 @@ +../common.tf \ No newline at end of file diff --git a/prepare-labs/terraform/one-kubernetes/vcluster/config.tf b/prepare-labs/terraform/one-kubernetes/vcluster/config.tf new file mode 120000 index 000000000..4ccf9d5d6 --- /dev/null +++ b/prepare-labs/terraform/one-kubernetes/vcluster/config.tf @@ -0,0 +1 @@ +../../provider-config/vcluster.tf \ No newline at end of file diff --git a/prepare-labs/terraform/one-kubernetes/vcluster/main.tf b/prepare-labs/terraform/one-kubernetes/vcluster/main.tf new file mode 100644 index 000000000..2a05693f3 --- /dev/null +++ b/prepare-labs/terraform/one-kubernetes/vcluster/main.tf @@ -0,0 +1,20 @@ +resource "helm_release" "_" { + name = "vcluster" + namespace = var.cluster_name + create_namespace = true + #tags = var.common_tags + repository = "https://charts.loft.sh" + chart = "vcluster" + set { + name = "storage.persistence" + value = "false" + } + set { + name = "service.type" + value = "NodePort" + } + set { + name = "syncer.extraArgs" + value = "{--tls-san=${local.outer_api_server_host}}" + } +} diff --git a/prepare-labs/terraform/one-kubernetes/vcluster/outputs.tf b/prepare-labs/terraform/one-kubernetes/vcluster/outputs.tf new file mode 100644 index 000000000..f8c88e258 --- /dev/null +++ b/prepare-labs/terraform/one-kubernetes/vcluster/outputs.tf @@ -0,0 +1,39 @@ +output "cluster_id" { + value = var.cluster_name +} + +output "has_metrics_server" { + value = true +} + +output "kubeconfig" { + sensitive = true + value = local.kubeconfig +} + +data "kubernetes_secret_v1" "kubeconfig" { + depends_on = [helm_release._] + metadata { + name = "vc-vcluster" + namespace = var.cluster_name + } +} + +data "kubernetes_service_v1" "vcluster" { + depends_on = [helm_release._] + metadata { + name = "vcluster" + namespace = var.cluster_name + } +} + +locals { + kubeconfig_raw = data.kubernetes_secret_v1.kubeconfig.data.config + node_port = data.kubernetes_service_v1.vcluster.spec[0].port[0].node_port + outer_api_server_url = yamldecode(file("~/kubeconfig")).clusters[0].cluster.server + outer_api_server_host = regex("https://([^:]+):", local.outer_api_server_url)[0] + inner_api_server_host = local.outer_api_server_host + inner_old_server_url = yamldecode(local.kubeconfig_raw).clusters[0].cluster.server + inner_new_server_url = "https://${local.inner_api_server_host}:${local.node_port}" + kubeconfig = replace(local.kubeconfig_raw, local.inner_old_server_url, local.inner_new_server_url) +} \ No newline at end of file diff --git a/prepare-labs/terraform/one-kubernetes/vcluster/provider.tf b/prepare-labs/terraform/one-kubernetes/vcluster/provider.tf new file mode 100644 index 000000000..7b60ad22a --- /dev/null +++ b/prepare-labs/terraform/one-kubernetes/vcluster/provider.tf @@ -0,0 +1,9 @@ +variable "node_sizes" { + type = map(string) + default = {} +} + +variable "location" { + type = string + default = null +} diff --git a/prepare-labs/terraform/provider-config/aws.tf b/prepare-labs/terraform/provider-config/aws.tf new file mode 100644 index 000000000..f67f3b9eb --- /dev/null +++ b/prepare-labs/terraform/provider-config/aws.tf @@ -0,0 +1,17 @@ +provider "aws" { + region = var.location +} + +variable "node_sizes" { + type = map(any) + default = { + S = "t3.small" + M = "t3.medium" + L = "t3.large" + } +} + +variable "location" { + type = string + default = "eu-north-1" +} diff --git a/prepare-labs/terraform/provider-config/azure.tf b/prepare-labs/terraform/provider-config/azure.tf new file mode 100644 index 000000000..bf3e8c909 --- /dev/null +++ b/prepare-labs/terraform/provider-config/azure.tf @@ -0,0 +1,25 @@ +provider "azurerm" { + features {} +} + +/* +Available sizes: +"Standard_D11_v2" # CPU=2 RAM=14 +"Standard_F4s_v2" # CPU=4 RAM=8 +"Standard_D1_v2" # CPU=1 RAM=3.5 +"Standard_B1ms" # CPU=1 RAM=2 +"Standard_B2s" # CPU=2 RAM=4 +*/ +variable "node_sizes" { + type = map(any) + default = { + S = "Standard_B1ms" + M = "Standard_B2s" + L = "Standard_F4s_v2" + } +} + +variable "location" { + type = string + default = "France Central" +} diff --git a/prepare-labs/terraform/provider-config/civo.tf b/prepare-labs/terraform/provider-config/civo.tf new file mode 100644 index 000000000..cd8eca65b --- /dev/null +++ b/prepare-labs/terraform/provider-config/civo.tf @@ -0,0 +1,23 @@ +provider "civo" { + token = local.civo_apikey +} + +locals { + civo_config = jsondecode(file("~/.civo.json")) + civo_current = local.civo_config.meta.current_apikey + civo_apikey = local.civo_config.apikeys[local.civo_current] +} + +variable "node_sizes" { + type = map(any) + default = { + S = "g4s.kube.small" + M = "g4s.kube.medium" + L = "g4s.kube.large" + } +} + +variable "location" { + type = string + default = "lon1" +} diff --git a/prepare-labs/terraform/provider-config/digitalocean.tf b/prepare-labs/terraform/provider-config/digitalocean.tf new file mode 100644 index 000000000..89ba0e742 --- /dev/null +++ b/prepare-labs/terraform/provider-config/digitalocean.tf @@ -0,0 +1,17 @@ +provider "digitalocean" { + token = yamldecode(file("~/.config/doctl/config.yaml"))["access-token"] +} + +variable "node_sizes" { + type = map(any) + default = { + S = "s-1vcpu-2gb" + M = "s-2vcpu-4gb" + L = "s-4vcpu-8gb" + } +} + +variable "location" { + type = string + default = "lon1" +} diff --git a/prepare-labs/terraform/provider-config/exoscale.tf b/prepare-labs/terraform/provider-config/exoscale.tf new file mode 100644 index 000000000..e66d127cc --- /dev/null +++ b/prepare-labs/terraform/provider-config/exoscale.tf @@ -0,0 +1,18 @@ +provider "exoscale" { + key = regex("\n key *= *\"([^\"]+)\"\n", file("~/.config/exoscale/exoscale.toml"))[0] + secret = regex("\n secret *= *\"([^\"]+)\"\n", file("~/.config/exoscale/exoscale.toml"))[0] +} + +variable "node_sizes" { + type = map(any) + default = { + S = "standard.small" + M = "standard.medium" + L = "standard.large" + } +} + +variable "location" { + type = string + default = "ch-gva-2" +} diff --git a/prepare-labs/terraform/provider-config/googlecloud.tf b/prepare-labs/terraform/provider-config/googlecloud.tf new file mode 100644 index 000000000..cb126c890 --- /dev/null +++ b/prepare-labs/terraform/provider-config/googlecloud.tf @@ -0,0 +1,13 @@ +variable "node_sizes" { + type = map(string) + default = { + "S" = "e2-small" + "M" = "e2-medium" + "L" = "e2-standard-2" + } +} + +variable "location" { + type = string + default = null +} diff --git a/prepare-vms/terraform/hetzner/variables.tf b/prepare-labs/terraform/provider-config/hetzner.tf similarity index 67% rename from prepare-vms/terraform/hetzner/variables.tf rename to prepare-labs/terraform/provider-config/hetzner.tf index 852693353..2166ea092 100644 --- a/prepare-vms/terraform/hetzner/variables.tf +++ b/prepare-labs/terraform/provider-config/hetzner.tf @@ -1,11 +1,11 @@ -variable "prefix" { - type = string - default = "provisioned-with-terraform" -} - -variable "how_many_nodes" { - type = number - default = 2 +/* +Okay, the following is pretty gross - it uses the first token found in the hcloud CLI +configuration file. We don't use Hetzner much anyway, and when we do, we only have one +profile ever, and we want this thing to Just Work; so this should do for now, but might +need to be improved if others actively use Hetzner to provision training labs. +*/ +provider "hcloud" { + token = regex("token = \"([A-Za-z0-9]+)\"", file("~/.config/hcloud/cli.toml"))[0] } /* @@ -21,10 +21,13 @@ $ hcloud server-type list | grep shared 25 cpx41 8 shared 16.0 GB 240 GB local 26 cpx51 16 shared 32.0 GB 360 GB local */ - -variable "size" { - type = string - default = "cx21" +variable "node_sizes" { + type = map(any) + default = { + S = "cx11" + M = "cx21" + L = "cx31" + } } /* diff --git a/prepare-labs/terraform/provider-config/linode.tf b/prepare-labs/terraform/provider-config/linode.tf new file mode 100644 index 000000000..c3f350652 --- /dev/null +++ b/prepare-labs/terraform/provider-config/linode.tf @@ -0,0 +1,25 @@ +provider "linode" { + token = regex("\ntoken *= *([0-9a-f]+)\n", file("~/.config/linode-cli"))[0] +} + +/* +Available sizes: +"g6-standard-1" # CPU=1 RAM=2 +"g6-standard-2" # CPU=2 RAM=4 +"g6-standard-4" # CPU=4 RAM=8 +"g6-standard-6" # CPU=6 RAM=16 +"g6-standard-8" # CPU=8 RAM=32 +*/ +variable "node_sizes" { + type = map(any) + default = { + S = "g6-standard-1" + M = "g6-standard-2" + L = "g6-standard-4" + } +} + +variable "location" { + type = string + default = "eu-west" +} diff --git a/prepare-labs/terraform/provider-config/oci.tf b/prepare-labs/terraform/provider-config/oci.tf new file mode 100644 index 000000000..ed996d5b6 --- /dev/null +++ b/prepare-labs/terraform/provider-config/oci.tf @@ -0,0 +1,35 @@ +/* +By convention we'll use "shape OCPUS GB-RAM" +and we'll split it accordingly. + +Available flex shapes: +"VM.Optimized3.Flex" # Intel Ice Lake +"VM.Standard3.Flex" # Intel Ice Lake +"VM.Standard.A1.Flex" # Ampere Altra +"VM.Standard.E3.Flex" # AMD Rome +"VM.Standard.E4.Flex" # AMD Milan +*/ +variable "node_sizes" { + type = map(any) + default = { + S = "VM.Standard.E4.Flex 1 2" + M = "VM.Standard.E4.Flex 2 4" + L = "VM.Standard.E4.Flex 3 8" + } +} + +variable "location" { + type = string + default = null +} + +variable "availability_domain" { + type = number + default = 0 +} + +locals { + shape = split(" ", local.node_size)[0] + ocpus = split(" ", local.node_size)[1] + memory_in_gbs = split(" ", local.node_size)[2] +} diff --git a/prepare-labs/terraform/provider-config/scaleway.tf b/prepare-labs/terraform/provider-config/scaleway.tf new file mode 100644 index 000000000..251f88e8c --- /dev/null +++ b/prepare-labs/terraform/provider-config/scaleway.tf @@ -0,0 +1,13 @@ +variable "node_sizes" { + type = map(any) + default = { + S = "DEV1-S" + M = "DEV1-M" + L = "DEV1-L" + } +} + +variable "location" { + type = string + default = "fr-par-2" +} diff --git a/prepare-labs/terraform/provider-config/vcluster.tf b/prepare-labs/terraform/provider-config/vcluster.tf new file mode 100644 index 000000000..c11f6337e --- /dev/null +++ b/prepare-labs/terraform/provider-config/vcluster.tf @@ -0,0 +1,9 @@ +provider "helm" { + kubernetes { + config_path = "~/kubeconfig" + } +} + +provider "kubernetes" { + config_path = "~/kubeconfig" +} diff --git a/prepare-labs/terraform/virtual-machines/aws/common.tf b/prepare-labs/terraform/virtual-machines/aws/common.tf new file mode 120000 index 000000000..a0251abd3 --- /dev/null +++ b/prepare-labs/terraform/virtual-machines/aws/common.tf @@ -0,0 +1 @@ +../common.tf \ No newline at end of file diff --git a/prepare-labs/terraform/virtual-machines/aws/config.tf b/prepare-labs/terraform/virtual-machines/aws/config.tf new file mode 120000 index 000000000..5675a9204 --- /dev/null +++ b/prepare-labs/terraform/virtual-machines/aws/config.tf @@ -0,0 +1 @@ +../../provider-config/aws.tf \ No newline at end of file diff --git a/prepare-labs/terraform/virtual-machines/aws/main.tf b/prepare-labs/terraform/virtual-machines/aws/main.tf new file mode 100644 index 000000000..1315721c9 --- /dev/null +++ b/prepare-labs/terraform/virtual-machines/aws/main.tf @@ -0,0 +1,30 @@ +resource "aws_instance" "_" { + for_each = local.nodes + tags = { + Name = each.value.node_name + } + instance_type = each.value.node_size + key_name = aws_key_pair._.key_name + ami = data.aws_ami._.id +} + +resource "aws_key_pair" "_" { + key_name = var.tag + public_key = tls_private_key.ssh.public_key_openssh +} + +locals { + ip_addresses = { + for key, value in local.nodes : + key => aws_instance._[key].public_ip + } +} + +data "aws_ami" "_" { + most_recent = true + owners = ["099720109477"] # Canonical + filter { + name = "name" + values = ["ubuntu/images/hvm-ssd/ubuntu-jammy-22.04-amd64-server-*"] + } +} diff --git a/prepare-labs/terraform/virtual-machines/aws/provider.tf b/prepare-labs/terraform/virtual-machines/aws/provider.tf new file mode 100644 index 000000000..f2702bf6e --- /dev/null +++ b/prepare-labs/terraform/virtual-machines/aws/provider.tf @@ -0,0 +1,7 @@ +terraform { + required_providers { + aws = { + source = "hashicorp/aws" + } + } +} diff --git a/prepare-labs/terraform/virtual-machines/azure/common.tf b/prepare-labs/terraform/virtual-machines/azure/common.tf new file mode 120000 index 000000000..a0251abd3 --- /dev/null +++ b/prepare-labs/terraform/virtual-machines/azure/common.tf @@ -0,0 +1 @@ +../common.tf \ No newline at end of file diff --git a/prepare-labs/terraform/virtual-machines/azure/config.tf b/prepare-labs/terraform/virtual-machines/azure/config.tf new file mode 120000 index 000000000..e9e39b2c4 --- /dev/null +++ b/prepare-labs/terraform/virtual-machines/azure/config.tf @@ -0,0 +1 @@ +../../provider-config/azure.tf \ No newline at end of file diff --git a/prepare-vms/terraform/azure/main.tf b/prepare-labs/terraform/virtual-machines/azure/main.tf similarity index 64% rename from prepare-vms/terraform/azure/main.tf rename to prepare-labs/terraform/virtual-machines/azure/main.tf index 651c34c22..ae29de496 100644 --- a/prepare-vms/terraform/azure/main.tf +++ b/prepare-labs/terraform/virtual-machines/azure/main.tf @@ -1,19 +1,19 @@ resource "azurerm_resource_group" "_" { - name = var.prefix + name = var.tag location = var.location } resource "azurerm_public_ip" "_" { - count = var.how_many_nodes - name = format("%s-%04d", var.prefix, count.index + 1) + for_each = local.nodes + name = each.value.node_name location = azurerm_resource_group._.location resource_group_name = azurerm_resource_group._.name allocation_method = "Dynamic" } resource "azurerm_network_interface" "_" { - count = var.how_many_nodes - name = format("%s-%04d", var.prefix, count.index + 1) + for_each = local.nodes + name = each.value.node_name location = azurerm_resource_group._.location resource_group_name = azurerm_resource_group._.name @@ -21,24 +21,24 @@ resource "azurerm_network_interface" "_" { name = "internal" subnet_id = azurerm_subnet._.id private_ip_address_allocation = "Dynamic" - public_ip_address_id = azurerm_public_ip._[count.index].id + public_ip_address_id = azurerm_public_ip._[each.key].id } } resource "azurerm_linux_virtual_machine" "_" { - count = var.how_many_nodes - name = format("%s-%04d", var.prefix, count.index + 1) + for_each = local.nodes + name = each.value.node_name resource_group_name = azurerm_resource_group._.name location = azurerm_resource_group._.location - size = var.size + size = each.value.node_size admin_username = "ubuntu" network_interface_ids = [ - azurerm_network_interface._[count.index].id, + azurerm_network_interface._[each.key].id ] admin_ssh_key { username = "ubuntu" - public_key = local.authorized_keys + public_key = tls_private_key.ssh.public_key_openssh } os_disk { @@ -48,8 +48,8 @@ resource "azurerm_linux_virtual_machine" "_" { source_image_reference { publisher = "Canonical" - offer = "UbuntuServer" - sku = "22.04-LTS" + offer = "0001-com-ubuntu-server-jammy" + sku = "22_04-lts" version = "latest" } } @@ -60,12 +60,15 @@ resource "azurerm_linux_virtual_machine" "_" { # See: https://github.com/hashicorp/terraform-provider-azurerm/issues/310#issuecomment-335479735 data "azurerm_public_ip" "_" { - count = var.how_many_nodes - name = format("%s-%04d", var.prefix, count.index + 1) + for_each = local.nodes + name = each.value.node_name resource_group_name = azurerm_resource_group._.name depends_on = [azurerm_linux_virtual_machine._] } -output "ip_addresses" { - value = join("", formatlist("%s\n", data.azurerm_public_ip._.*.ip_address)) +locals { + ip_addresses = { + for key, value in local.nodes : + key => data.azurerm_public_ip._[key].ip_address + } } diff --git a/prepare-vms/terraform/azure/network.tf b/prepare-labs/terraform/virtual-machines/azure/network.tf similarity index 84% rename from prepare-vms/terraform/azure/network.tf rename to prepare-labs/terraform/virtual-machines/azure/network.tf index 343287e4d..17191adf5 100644 --- a/prepare-vms/terraform/azure/network.tf +++ b/prepare-labs/terraform/virtual-machines/azure/network.tf @@ -1,12 +1,12 @@ resource "azurerm_virtual_network" "_" { - name = "tf-vnet" + name = var.tag address_space = ["10.10.0.0/16"] location = azurerm_resource_group._.location resource_group_name = azurerm_resource_group._.name } resource "azurerm_subnet" "_" { - name = "tf-subnet" + name = var.tag resource_group_name = azurerm_resource_group._.name virtual_network_name = azurerm_virtual_network._.name address_prefixes = ["10.10.0.0/20"] diff --git a/prepare-vms/terraform/azure/provider.tf b/prepare-labs/terraform/virtual-machines/azure/provider.tf similarity index 65% rename from prepare-vms/terraform/azure/provider.tf rename to prepare-labs/terraform/virtual-machines/azure/provider.tf index a2781afeb..1032fcd83 100644 --- a/prepare-vms/terraform/azure/provider.tf +++ b/prepare-labs/terraform/virtual-machines/azure/provider.tf @@ -1,5 +1,4 @@ terraform { - required_version = ">= 1" required_providers { azurerm = { source = "hashicorp/azurerm" @@ -7,7 +6,3 @@ terraform { } } } - -provider "azurerm" { - features {} -} \ No newline at end of file diff --git a/prepare-labs/terraform/virtual-machines/common.tf b/prepare-labs/terraform/virtual-machines/common.tf new file mode 100644 index 000000000..524066143 --- /dev/null +++ b/prepare-labs/terraform/virtual-machines/common.tf @@ -0,0 +1,80 @@ +# Note: on most modern systems (e.g. Fedora 33+, Ubuntu 22.04...) +# SSH authentication with RSA keys requires RSA-2 signatures. +# Terraform started supporting RSA-2 signatures somewhere around +# version 1.2, so we require 1.4 here to be safe. +# (See https://github.com/hashicorp/terraform/issues/30134) +terraform { + required_version = ">= 1.4" +} + +variable "tag" { + type = string + default = "deployed-with-terraform" +} + +variable "how_many_clusters" { + type = number + default = 2 +} + +variable "nodes_per_cluster" { + type = number + default = 3 +} + +variable "node_size" { + type = string + default = "M" + description = "If this is S, M, or L, it will correspond to a VM with 2, 4, 8GB of RAM. If it's anything else, it will be a provider-specific instance type, e.g. g7-highmem-4 or c5n.xlarge." +} + +resource "tls_private_key" "ssh" { + algorithm = "RSA" + rsa_bits = "4096" +} + +resource "local_file" "ssh_private_key" { + content = tls_private_key.ssh.private_key_pem + filename = "id_rsa" + file_permission = "0600" +} + +resource "local_file" "ssh_public_key" { + content = tls_private_key.ssh.public_key_openssh + filename = "id_rsa.pub" + file_permission = "0600" +} + +locals { + nodes = { + for cn in setproduct( + range(1, 1 + var.how_many_clusters), + range(1, 1 + var.nodes_per_cluster) + ) : + format("c%03dn%03d", cn[0], cn[1]) => { + cluster_key = format("c%03d", cn[0]) + cluster_name = format("%s-%03d", var.tag, cn[0]) + node_name = format("%s-%03d-%03d", var.tag, cn[0], cn[1]) + node_size = lookup(var.node_sizes, var.node_size, var.node_size) + } + } +} + +resource "local_file" "ip_addresses" { + content = join("", formatlist("%s\n", [ + for key, value in local.ip_addresses : value + ])) + filename = "ips.txt" + file_permission = "0600" +} + +resource "local_file" "clusters" { + content = join("", formatlist("%s\n", [ + for cid in range(1, 1 + var.how_many_clusters) : + join(" ", + [for nid in range(1, 1 + var.nodes_per_cluster) : + local.ip_addresses[format("c%03dn%03d", cid, nid)] + ])])) + filename = "clusters.txt" + file_permission = "0600" +} diff --git a/prepare-labs/terraform/virtual-machines/digitalocean/common.tf b/prepare-labs/terraform/virtual-machines/digitalocean/common.tf new file mode 120000 index 000000000..a0251abd3 --- /dev/null +++ b/prepare-labs/terraform/virtual-machines/digitalocean/common.tf @@ -0,0 +1 @@ +../common.tf \ No newline at end of file diff --git a/prepare-labs/terraform/virtual-machines/digitalocean/config.tf b/prepare-labs/terraform/virtual-machines/digitalocean/config.tf new file mode 120000 index 000000000..81ac877f5 --- /dev/null +++ b/prepare-labs/terraform/virtual-machines/digitalocean/config.tf @@ -0,0 +1 @@ +../../provider-config/digitalocean.tf \ No newline at end of file diff --git a/prepare-labs/terraform/virtual-machines/digitalocean/main.tf b/prepare-labs/terraform/virtual-machines/digitalocean/main.tf new file mode 100644 index 000000000..204024f14 --- /dev/null +++ b/prepare-labs/terraform/virtual-machines/digitalocean/main.tf @@ -0,0 +1,20 @@ +resource "digitalocean_droplet" "_" { + for_each = local.nodes + name = each.value.node_name + region = var.location + size = each.value.node_size + ssh_keys = [digitalocean_ssh_key._.id] + image = "ubuntu-22-04-x64" +} + +resource "digitalocean_ssh_key" "_" { + name = var.tag + public_key = tls_private_key.ssh.public_key_openssh +} + +locals { + ip_addresses = { + for key, value in local.nodes : + key => digitalocean_droplet._[key].ipv4_address + } +} diff --git a/prepare-labs/terraform/virtual-machines/digitalocean/provider.tf b/prepare-labs/terraform/virtual-machines/digitalocean/provider.tf new file mode 100644 index 000000000..487e9f747 --- /dev/null +++ b/prepare-labs/terraform/virtual-machines/digitalocean/provider.tf @@ -0,0 +1,7 @@ +terraform { + required_providers { + digitalocean = { + source = "digitalocean/digitalocean" + } + } +} diff --git a/prepare-labs/terraform/virtual-machines/hetzner/common.tf b/prepare-labs/terraform/virtual-machines/hetzner/common.tf new file mode 120000 index 000000000..a0251abd3 --- /dev/null +++ b/prepare-labs/terraform/virtual-machines/hetzner/common.tf @@ -0,0 +1 @@ +../common.tf \ No newline at end of file diff --git a/prepare-labs/terraform/virtual-machines/hetzner/config.tf b/prepare-labs/terraform/virtual-machines/hetzner/config.tf new file mode 120000 index 000000000..36276b337 --- /dev/null +++ b/prepare-labs/terraform/virtual-machines/hetzner/config.tf @@ -0,0 +1 @@ +../../provider-config/hetzner.tf \ No newline at end of file diff --git a/prepare-labs/terraform/virtual-machines/hetzner/main.tf b/prepare-labs/terraform/virtual-machines/hetzner/main.tf new file mode 100644 index 000000000..a44a18be9 --- /dev/null +++ b/prepare-labs/terraform/virtual-machines/hetzner/main.tf @@ -0,0 +1,20 @@ +resource "hcloud_server" "_" { + for_each = local.nodes + name = each.value.node_name + location = var.location + server_type = each.value.node_size + ssh_keys = [hcloud_ssh_key._.id] + image = "ubuntu-22.04" +} + +resource "hcloud_ssh_key" "_" { + name = var.tag + public_key = tls_private_key.ssh.public_key_openssh +} + +locals { + ip_addresses = { + for key, value in local.nodes : + key => hcloud_server._[key].ipv4_address + } +} diff --git a/prepare-labs/terraform/virtual-machines/hetzner/provider.tf b/prepare-labs/terraform/virtual-machines/hetzner/provider.tf new file mode 100644 index 000000000..4914c45bd --- /dev/null +++ b/prepare-labs/terraform/virtual-machines/hetzner/provider.tf @@ -0,0 +1,7 @@ +terraform { + required_providers { + hcloud = { + source = "hetznercloud/hcloud" + } + } +} diff --git a/prepare-labs/terraform/virtual-machines/linode/common.tf b/prepare-labs/terraform/virtual-machines/linode/common.tf new file mode 120000 index 000000000..a0251abd3 --- /dev/null +++ b/prepare-labs/terraform/virtual-machines/linode/common.tf @@ -0,0 +1 @@ +../common.tf \ No newline at end of file diff --git a/prepare-labs/terraform/virtual-machines/linode/config.tf b/prepare-labs/terraform/virtual-machines/linode/config.tf new file mode 120000 index 000000000..3230f2255 --- /dev/null +++ b/prepare-labs/terraform/virtual-machines/linode/config.tf @@ -0,0 +1 @@ +../../provider-config/linode.tf \ No newline at end of file diff --git a/prepare-labs/terraform/virtual-machines/linode/main.tf b/prepare-labs/terraform/virtual-machines/linode/main.tf new file mode 100644 index 000000000..7216a3793 --- /dev/null +++ b/prepare-labs/terraform/virtual-machines/linode/main.tf @@ -0,0 +1,15 @@ +resource "linode_instance" "_" { + for_each = local.nodes + label = each.value.node_name + region = var.location + type = each.value.node_size + authorized_keys = [trimspace(tls_private_key.ssh.public_key_openssh)] + image = "linode/ubuntu22.04" +} + +locals { + ip_addresses = { + for key, value in local.nodes : + key => linode_instance._[key].ip_address + } +} diff --git a/prepare-labs/terraform/virtual-machines/linode/provider.tf b/prepare-labs/terraform/virtual-machines/linode/provider.tf new file mode 100644 index 000000000..25adad52b --- /dev/null +++ b/prepare-labs/terraform/virtual-machines/linode/provider.tf @@ -0,0 +1,7 @@ +terraform { + required_providers { + linode = { + source = "linode/linode" + } + } +} diff --git a/prepare-labs/terraform/virtual-machines/oci/common.tf b/prepare-labs/terraform/virtual-machines/oci/common.tf new file mode 120000 index 000000000..a0251abd3 --- /dev/null +++ b/prepare-labs/terraform/virtual-machines/oci/common.tf @@ -0,0 +1 @@ +../common.tf \ No newline at end of file diff --git a/prepare-labs/terraform/virtual-machines/oci/config.tf b/prepare-labs/terraform/virtual-machines/oci/config.tf new file mode 120000 index 000000000..3f4487705 --- /dev/null +++ b/prepare-labs/terraform/virtual-machines/oci/config.tf @@ -0,0 +1 @@ +../../provider-config/oci.tf \ No newline at end of file diff --git a/prepare-vms/terraform/oci/main.tf b/prepare-labs/terraform/virtual-machines/oci/main.tf similarity index 64% rename from prepare-vms/terraform/oci/main.tf rename to prepare-labs/terraform/virtual-machines/oci/main.tf index db39d349f..9dc699151 100644 --- a/prepare-vms/terraform/oci/main.tf +++ b/prepare-labs/terraform/virtual-machines/oci/main.tf @@ -1,6 +1,6 @@ resource "oci_identity_compartment" "_" { - name = var.prefix - description = var.prefix + name = var.tag + description = var.tag enable_delete = true } @@ -14,7 +14,7 @@ data "oci_identity_availability_domains" "_" { data "oci_core_images" "_" { compartment_id = local.compartment_id - shape = var.shape + shape = local.shape operating_system = "Canonical Ubuntu" operating_system_version = "22.04" #operating_system = "Oracle Linux" @@ -22,14 +22,14 @@ data "oci_core_images" "_" { } resource "oci_core_instance" "_" { - count = var.how_many_nodes - display_name = format("%s-%04d", var.prefix, count.index + 1) + for_each = local.nodes + display_name = each.value.node_name availability_domain = data.oci_identity_availability_domains._.availability_domains[var.availability_domain].name compartment_id = local.compartment_id - shape = var.shape + shape = local.shape shape_config { - memory_in_gbs = var.memory_in_gbs_per_node - ocpus = var.ocpus_per_node + memory_in_gbs = local.memory_in_gbs + ocpus = local.ocpus } source_details { source_id = data.oci_core_images._.images[0].id @@ -39,10 +39,13 @@ resource "oci_core_instance" "_" { subnet_id = oci_core_subnet._.id } metadata = { - ssh_authorized_keys = local.authorized_keys + ssh_authorized_keys = tls_private_key.ssh.public_key_openssh } } -output "ip_addresses" { - value = join("", formatlist("%s\n", oci_core_instance._.*.public_ip)) +locals { + ip_addresses = { + for key, value in local.nodes : + key => oci_core_instance._[key].public_ip + } } diff --git a/prepare-vms/terraform/oci/network.tf b/prepare-labs/terraform/virtual-machines/oci/network.tf similarity index 100% rename from prepare-vms/terraform/oci/network.tf rename to prepare-labs/terraform/virtual-machines/oci/network.tf diff --git a/prepare-labs/terraform/virtual-machines/oci/provider.tf b/prepare-labs/terraform/virtual-machines/oci/provider.tf new file mode 100644 index 000000000..433f0f263 --- /dev/null +++ b/prepare-labs/terraform/virtual-machines/oci/provider.tf @@ -0,0 +1,7 @@ +terraform { + required_providers { + oci = { + source = "oracle/oci" + } + } +} diff --git a/prepare-labs/terraform/virtual-machines/openstack/common.tf b/prepare-labs/terraform/virtual-machines/openstack/common.tf new file mode 120000 index 000000000..a0251abd3 --- /dev/null +++ b/prepare-labs/terraform/virtual-machines/openstack/common.tf @@ -0,0 +1 @@ +../common.tf \ No newline at end of file diff --git a/prepare-labs/terraform/virtual-machines/openstack/main.tf b/prepare-labs/terraform/virtual-machines/openstack/main.tf new file mode 100644 index 000000000..a929c293c --- /dev/null +++ b/prepare-labs/terraform/virtual-machines/openstack/main.tf @@ -0,0 +1,36 @@ +resource "openstack_compute_instance_v2" "_" { + for_each = local.nodes + name = each.value.node_name + image_name = var.image + flavor_name = each.value.node_size + security_groups = [openstack_networking_secgroup_v2._.name] + key_pair = openstack_compute_keypair_v2._.name + + network { + name = openstack_networking_network_v2._.name + } +} + +resource "openstack_compute_floatingip_v2" "_" { + for_each = local.nodes + pool = var.pool +} + +resource "openstack_compute_floatingip_associate_v2" "_" { + for_each = local.nodes + floating_ip = openstack_compute_floatingip_v2._[each.key].address + instance_id = openstack_compute_instance_v2._[each.key].id + fixed_ip = openstack_compute_instance_v2._[each.key].network[0].fixed_ip_v4 +} + +locals { + ip_addresses = { + for key, value in local.nodes : + key => openstack_compute_floatingip_v2._[key].address + } +} + +resource "openstack_compute_keypair_v2" "_" { + name = var.tag + public_key = tls_private_key.ssh.public_key_openssh +} diff --git a/prepare-labs/terraform/virtual-machines/openstack/network.tf b/prepare-labs/terraform/virtual-machines/openstack/network.tf new file mode 100644 index 000000000..2a7da178a --- /dev/null +++ b/prepare-labs/terraform/virtual-machines/openstack/network.tf @@ -0,0 +1,21 @@ +resource "openstack_networking_network_v2" "_" { + name = var.tag +} + +resource "openstack_networking_subnet_v2" "_" { + name = var.tag + network_id = openstack_networking_network_v2._.id + cidr = "10.10.0.0/16" + ip_version = 4 + dns_nameservers = ["1.1.1.1"] +} + +resource "openstack_networking_router_v2" "_" { + name = var.tag + external_network_id = var.external_network_id +} + +resource "openstack_networking_router_interface_v2" "_" { + router_id = openstack_networking_router_v2._.id + subnet_id = openstack_networking_subnet_v2._.id +} diff --git a/prepare-vms/terraform/openstack/provider.tf b/prepare-labs/terraform/virtual-machines/openstack/provider.tf similarity index 54% rename from prepare-vms/terraform/openstack/provider.tf rename to prepare-labs/terraform/virtual-machines/openstack/provider.tf index 1202ba4ec..a6b5b0060 100644 --- a/prepare-vms/terraform/openstack/provider.tf +++ b/prepare-labs/terraform/virtual-machines/openstack/provider.tf @@ -1,5 +1,4 @@ terraform { - required_version = ">= 1" required_providers { openstack = { source = "terraform-provider-openstack/openstack" @@ -21,3 +20,27 @@ variable "tenant" {} variable "domain" {} variable "password" {} variable "auth_url" {} + +// For example: "Public training floating" +variable "pool" { + type = string +} + +// For example: "74e32174-cf09-452f-bda0-2bdfe074e251" +variable "external_network_id" { + type = string +} + +variable "image" { + type = string +} + +variable "node_sizes" { + type = map(any) + default = {} +} + +variable "location" { + type = string + default = "" +} diff --git a/prepare-vms/www/index.html b/prepare-labs/terraform/virtual-machines/openstack/requires_tfvars similarity index 100% rename from prepare-vms/www/index.html rename to prepare-labs/terraform/virtual-machines/openstack/requires_tfvars diff --git a/prepare-labs/terraform/virtual-machines/openstack/secgroup.tf b/prepare-labs/terraform/virtual-machines/openstack/secgroup.tf new file mode 100644 index 000000000..870aca65d --- /dev/null +++ b/prepare-labs/terraform/virtual-machines/openstack/secgroup.tf @@ -0,0 +1,11 @@ +resource "openstack_networking_secgroup_v2" "_" { + name = var.tag +} + +resource "openstack_networking_secgroup_rule_v2" "_" { + direction = "ingress" + ethertype = "IPv4" + protocol = "" + remote_ip_prefix = "0.0.0.0/0" + security_group_id = openstack_networking_secgroup_v2._.id +} diff --git a/prepare-labs/terraform/virtual-machines/scaleway/common.tf b/prepare-labs/terraform/virtual-machines/scaleway/common.tf new file mode 120000 index 000000000..a0251abd3 --- /dev/null +++ b/prepare-labs/terraform/virtual-machines/scaleway/common.tf @@ -0,0 +1 @@ +../common.tf \ No newline at end of file diff --git a/prepare-labs/terraform/virtual-machines/scaleway/config.tf b/prepare-labs/terraform/virtual-machines/scaleway/config.tf new file mode 120000 index 000000000..3ac2b26e6 --- /dev/null +++ b/prepare-labs/terraform/virtual-machines/scaleway/config.tf @@ -0,0 +1 @@ +../../provider-config/scaleway.tf \ No newline at end of file diff --git a/prepare-labs/terraform/virtual-machines/scaleway/main.tf b/prepare-labs/terraform/virtual-machines/scaleway/main.tf new file mode 100644 index 000000000..3ec4dcb9b --- /dev/null +++ b/prepare-labs/terraform/virtual-machines/scaleway/main.tf @@ -0,0 +1,17 @@ +resource "scaleway_instance_server" "_" { + for_each = local.nodes + type = each.value.node_size + image = "ubuntu_jammy" + zone = var.location + name = each.value.node_name + enable_ipv6 = true + enable_dynamic_ip = true + tags = [format("AUTHORIZED_KEY=%s", replace(trimspace(tls_private_key.ssh.public_key_openssh), " ", "_"))] +} + +locals { + ip_addresses = { + for key, value in local.nodes : + key => scaleway_instance_server._[key].public_ip + } +} diff --git a/prepare-labs/terraform/virtual-machines/scaleway/provider.tf b/prepare-labs/terraform/virtual-machines/scaleway/provider.tf new file mode 100644 index 000000000..3f217ed5b --- /dev/null +++ b/prepare-labs/terraform/virtual-machines/scaleway/provider.tf @@ -0,0 +1,7 @@ +terraform { + required_providers { + scaleway = { + source = "scaleway/scaleway" + } + } +} diff --git a/prepare-labs/test-all-one-kubernetes.sh b/prepare-labs/test-all-one-kubernetes.sh new file mode 100755 index 000000000..2f98abba7 --- /dev/null +++ b/prepare-labs/test-all-one-kubernetes.sh @@ -0,0 +1,40 @@ +#!/bin/sh +cd terraform/one-kubernetes + +case "$1" in + create) + tmux has-session || tmux new-session -d + for PROVIDER in *; do + [ -f "$PROVIDER/common.tf" ] || continue + tmux new-window -n $PROVIDER + tmux send-keys -t $PROVIDER " + cd $PROVIDER + terraform init -upgrade + /usr/bin/time --output /tmp/time.$PROVIDER --format '%e\n(%E)' terraform apply -auto-approve" + done + ;; + kubeconfig) + for PROVIDER in *; do + [ -f "$PROVIDER/terraform.tfstate" ] || continue + ( + echo "Writing /tmp/kubeconfig.$PROVIDER..." + cd $PROVIDER + terraform output -raw kubeconfig > /tmp/kubeconfig.$PROVIDER + ) + done + ;; + destroy) + for PROVIDER in *; do + [ -f "$PROVIDER/terraform.tfstate" ] || continue + ( + cd $PROVIDER + terraform destroy -auto-approve && + rm -rf terraform.tfstate* .terraform* + ) + done + ;; + *) + echo "Please specify one of the following actions:" + echo "create, kubeconfig, destroy." + ;; +esac diff --git a/prepare-vms/www/README b/prepare-labs/www/README similarity index 100% rename from prepare-vms/www/README rename to prepare-labs/www/README diff --git a/prepare-labs/www/index.html b/prepare-labs/www/index.html new file mode 100644 index 000000000..e69de29bb diff --git a/prepare-tf/README.md b/prepare-tf/README.md deleted file mode 100644 index a89a16804..000000000 --- a/prepare-tf/README.md +++ /dev/null @@ -1,168 +0,0 @@ -⚠️ This is work in progress. The UX needs to be improved, -and the docs could be better. - -This directory contains a Terraform configuration to deploy -a bunch of Kubernetes clusters on various cloud providers, -using their respective managed Kubernetes products. - -## With shell wrapper - -This is the recommended use. It makes it easy to start N clusters -on any provider. It will create a directory with a name like -`tag-YYYY-MM-DD-HH-MM-SS-SEED-PROVIDER`, copy the Terraform configuration -to that directory, then create the clusters using that configuration. - -1. One-time setup: configure provider authentication for the provider(s) that you wish to use. - -- Digital Ocean: - ```bash - doctl auth init - ``` - -- Google Cloud Platform: you will need to create a project named `prepare-tf` - and enable the relevant APIs for this project (sorry, if you're new to GCP, - this sounds vague; but if you're familiar with it you know what to do; if you - want to change the project name you can edit the Terraform configuration) - -- Linode: - ```bash - linode-cli configure - ``` - -- Oracle Cloud: FIXME - (set up `oci` through the `oci-cli` Python package) - -- Scaleway: run `scw init` - -2. Run! - -```bash -./run.sh [number of clusters] [min nodes] [max nodes] -``` - -If you don't specify a provider name, it will list available providers. - -If you don't specify a location, it will list locations available for this provider. - -You can also specify multiple locations, and then they will be -used in round-robin fashion. - -For example, with Google Cloud, since the default quotas are very -low (my account is limited to 8 public IP addresses per zone, and -my requests to increase that quota were denied) you can do the -following: - -```bash -LOCATIONS=$(gcloud compute zones list --format=json | jq -r .[].name | grep ^europe) -./run.sh googlecloud "$LOCATIONS" -``` - -Then when you apply, clusters will be created across all available -zones in Europe. (When I write this, there are 20+ zones in Europe, -so even with my quota, I can create 40 clusters.) - -3. Shutting down - -Go to the directory that was created by the previous step (`tag-YYYY-MM...`) -and run `terraform destroy`. - -You can also run `./clean.sh` which will destroy ALL clusters deployed by the previous run script. - -## Without shell wrapper - -Expert mode. - -Useful to run steps sperarately, and/or when working on the Terraform configurations. - -1. Select the provider you wish to use. - -Go to the `source` directory and edit `main.tf`. - -Change the `source` attribute of the `module "clusters"` section. - -Check the content of the `modules` directory to see available choices. - -2. Initialize the provider. - -```bash -terraform init -``` - -3. Configure provider authentication. - -Our Terraform configurations try to pick up provider authentication information from -local configuration files typically used by the CLI tool of each provider. Our goal -is to make sure that you don't have to set extra environment variables when applying -the Terraform configurations, as long as the CLI tool of that provider has the relevant -authentication information. - -Here are provider-specific instructions: - -- for Digital Ocean, run `doctl auth init`, which will populate `~/.config/doctl/config.yaml` -- for Linode, run `linode-cli configure`, which will populate `~/.config/linode-cli` - -4. Decide how many clusters and how many nodes per clusters you want. - -5. Provision clusters. - -```bash -terraform apply -``` - -6. Perform second stage provisioning. - -This will install an SSH server on the clusters. - -```bash -cd stage2 -terraform init -terraform apply -``` - -7. Obtain cluster connection information. - -The following command shows connection information, one cluster per line, ready to copy-paste in a shared document or spreadsheet. - -```bash -terraform output -json | jq -r 'to_entries[].value.value' -``` - -8. Destroy clusters. - -```bash -cd .. -terraform destroy -``` - -9. Clean up stage2. - -```bash -rm stage2/terraform.tfstate* -``` - -10. Clean up leftovers. - -Some providers don't clean up properly the resources created by the CCM. -For instance, when you create a Kubernetes `Service` of type -`LoadBalancer`, it generally provisions a cloud load balancer. -On Linode (and possibly other providers, too!) these cloud load balancers -aren't deleted when the cluster gets deleted, and they keep incurring -charges. You should check for those, to make sure that you don't -get charged for resources that you don't use anymore. As I write this -paragraph, there is: - -- `linode-delete-ccm-loadbalancers.sh` to delete the Linode - nodebalancers; but be careful: it deletes **all** the nodebalancers - whose name starts with `ccm-`, which means that if you still have - Kubernetes clusters, their load balancers will be deleted as well! - -- `linode-delete-pvc-volumes.sh` to delete Linode persistent disks - that have been created to satisfy Persistent Volume Claims - (these need to be removed manually because the default Storage Class - on Linode has a RETAIN policy). Again, be careful, this will wipe - out any volume whose label starts with `pvc`. (I don't know if it - will remove volumes that are still attached.) - -Eventually, I hope to add more scripts for other providers, and make -them more selective and more robust, but for now, that's better than -nothing. diff --git a/prepare-tf/cleanup.sh b/prepare-tf/cleanup.sh deleted file mode 100755 index 5bef4432c..000000000 --- a/prepare-tf/cleanup.sh +++ /dev/null @@ -1,7 +0,0 @@ -#!/bin/sh -for T in tag-*; do -( - cd $T - terraform apply -destroy -auto-approve && mv ../$T ../deleted$T -) -done diff --git a/prepare-tf/linode-delete-ccm-loadbalancers.sh b/prepare-tf/linode-delete-ccm-loadbalancers.sh deleted file mode 100755 index 141e009aa..000000000 --- a/prepare-tf/linode-delete-ccm-loadbalancers.sh +++ /dev/null @@ -1,4 +0,0 @@ -#!/bin/sh -linode-cli nodebalancers list --json | - jq '.[] | select(.label | startswith("ccm-")) | .id' | - xargs -n1 -P10 linode-cli nodebalancers delete diff --git a/prepare-tf/linode-delete-pvc-volumes.sh b/prepare-tf/linode-delete-pvc-volumes.sh deleted file mode 100755 index 277e44630..000000000 --- a/prepare-tf/linode-delete-pvc-volumes.sh +++ /dev/null @@ -1,4 +0,0 @@ -#!/bin/sh -linode-cli volumes list --json | - jq '.[] | select(.label | startswith("pvc")) | .id' | - xargs -n1 -P10 linode-cli volumes delete diff --git a/prepare-tf/run.sh b/prepare-tf/run.sh deleted file mode 100755 index 61da09abd..000000000 --- a/prepare-tf/run.sh +++ /dev/null @@ -1,66 +0,0 @@ -#!/bin/sh -set -e - -TIME=$(which time) - -[ "$1" ] || { - echo "Syntax:" - echo "" - echo "$0 [how-many-clusters] [min-nodes] [max-nodes]" - echo "" - echo "Available providers:" - ls -1 source/modules - echo "" - echo "Leave the region empty to show available regions for this provider." - echo "You can also specify ALL as a provider to simultaneously provision" - echo "many clusters on *each* provider for benchmarking purposes." - echo "" - exit 1 -} - -PROVIDER="$1" - -[ "$2" ] || { - "./source/modules/$PROVIDER/list_locations.sh" - exit 1 -} - -[ "$TAG" ] || { - TIMESTAMP=$(date +%Y-%m-%d-%H-%M-%S) - RANDOMTAG=$(base64 /dev/urandom | tr A-Z a-z | tr -d /+ | head -c5) - export TAG=tag-$TIMESTAMP-$RANDOMTAG -} - -[ "$PROVIDER" = "ALL" ] && { - for PROVIDER in $(ls -1 source/modules); do - $TERMINAL -T $TAG-$PROVIDER -e sh -c " - export TAG=$TAG-$PROVIDER - $0 $PROVIDER - cd $TAG-$PROVIDER - bash - " & - done - exit 0 -} - -[ -d "source/modules/$PROVIDER" ] || { - echo "Provider '$PROVIDER' not found." - echo "Available providers:" - ls -1 source/modules - exit 1 -} - -cp -a source $TAG -cd $TAG -cp -r modules/$PROVIDER modules/PROVIDER -cat >terraform.tfvars </ips.txt` for a tag of "myworkshop": - -1) If you haven't yet installed `jq` and/or created your event's tags directory in `prepare-vms`: - -``` -brew install jq -mkdir -p tags/myworkshop -``` - -2) And then generate the IP list: - -``` -az vm list-ip-addresses --resource-group workshop --output json | jq -r '.[].virtualMachine.network.publicIpAddresses[].ipAddress' > tags/myworkshop/ips.txt -``` - -After the workshop is over, remove the instances: - -``` -az group delete --resource-group workshop -``` - -### Example Steps to Configure Instances from a non-AWS Source - -- Copy `infra/example.generic` to `infra/generic` -- Run `./workshopctl start --infra infra/generic --settings settings/...yaml` -- Note the `prepare-vms/tags/TAG/` path that has been auto-created. -- Launch instances via your preferred method. You'll need to get the instance IPs and be able to SSH into them. -- Edit the file `prepare-vms/tags/TAG/ips.txt`, it should list the IP addresses of the VMs (one per line, without any comments or other info) -- Continue deployment of cluster configuration with `./workshopctl deploy TAG` -- Optionally, configure Kubernetes clusters of the size in the settings: workshopctl kube `TAG` -- Optionally, test your Kubernetes clusters. They may take a little time to become ready: workshopctl kubetest `TAG` -- Generate cards to print and hand out: workshopctl cards `TAG` -- Print the cards file: prepare-vms/tags/`TAG`/ips.html - - -## Even More Details - -#### Sync of SSH keys - -When the `start` command is run, your local RSA SSH public key will be added to your AWS EC2 keychain. - -To see which local key will be uploaded, run `ssh-add -l | grep RSA`. - -#### Instance + tag creation - -The VMs will be started, with an automatically generated tag (timestamp + your username). - -Your SSH key will be added to the `authorized_keys` of the ubuntu user. - -#### Creation of ./$TAG/ directory and contents - -Following the creation of the VMs, a text file will be created containing a list of their IPs. - -#### Deployment - -Instances can be deployed manually using the `deploy` command: - - $ ./workshopctl deploy TAG - -The `postprep.py` file will be copied via parallel-ssh to all of the VMs and executed. - -#### Pre-pull images - - $ ./workshopctl pull_images TAG - -#### Generate cards - - $ ./workshopctl cards TAG - -If you want to generate both HTML and PDF cards, install [wkhtmltopdf](https://wkhtmltopdf.org/downloads.html); without that installed, only HTML cards will be generated. - -If you don't have `wkhtmltopdf` installed, you will get a warning that it is a missing dependency. If you plan to just print the HTML cards, you can ignore this. - -#### List tags - - $ ./workshopctl tags - - $ ./workshopctl inventory infra/some-infra-file - - $ ./workshopctl inventory - -Note: the `tags` command will show only the VMs that you have provisioned -and deployed on the current machine (i.e. listed in the `tags` subdirectory). -The `inventory` command will try to list all existing VMs (including the -ones not listed in the `tags` directory, and including VMs provisioned -through other mechanisms). It is not supported across all platforms, -however. - -#### Stop and destroy VMs - - $ ./workshopctl stop TAG - -## ToDo - - - Don't write to bash history in system() in postprep - - compose, etc version inconsistent (int vs str) - -## Making sure Python3 is the default (Mac only) - -Check the `/usr/local/bin/python` symlink. It should be pointing to -`/usr/local/Cellar/python/3`-something. If it isn't, follow these -instructions. - -1) Verify that Python 3 is installed. - -``` -ls -la /usr/local/Cellar/Python -``` - -You should see one or more versions of Python 3. If you don't, -install it with `brew install python`. - -2) Verify that `python` points to Python3. - -``` -ls -la /usr/local/bin/python -``` - -If this points to `/usr/local/Cellar/python@2`, then we'll need to change it. - -``` -rm /usr/local/bin/python -ln -s /usr/local/Cellar/Python/xxxx /usr/local/bin/python -# where xxxx is the most recent Python 3 version you saw above -``` diff --git a/prepare-vms/azuredeploy.json b/prepare-vms/azuredeploy.json deleted file mode 100644 index 74dc620ce..000000000 --- a/prepare-vms/azuredeploy.json +++ /dev/null @@ -1,250 +0,0 @@ -{ - "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "parameters": { - "workshopName": { - "type": "string", - "defaultValue": "workshop", - "metadata": { - "description": "Workshop name." - } - }, - "vmPrefix": { - "type": "string", - "defaultValue": "node", - "metadata": { - "description": "Prefix for VM names." - } - }, - "numberOfInstances": { - "type": "int", - "defaultValue": 3, - "metadata": { - "description": "Number of VMs to create." - } - }, - "adminUsername": { - "type": "string", - "defaultValue": "ubuntu", - "metadata": { - "description": "Admin username for VMs." - } - }, - "sshKeyData": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "SSH rsa public key file as a string." - } - }, - "imagePublisher": { - "type": "string", - "defaultValue": "Canonical", - "metadata": { - "description": "OS image publisher; default Canonical." - } - }, - "imageOffer": { - "type": "string", - "defaultValue": "UbuntuServer", - "metadata": { - "description": "The name of the image offer. The default is Ubuntu" - } - }, - "imageSKU": { - "type": "string", - "defaultValue": "16.04-LTS", - "metadata": { - "description": "Version of the image. The default is 16.04-LTS" - } - }, - "vmSize": { - "type": "string", - "defaultValue": "Standard_D1_v2", - "metadata": { - "description": "VM Size." - } - } - }, - "variables": { - "vnetID": "[resourceId('Microsoft.Network/virtualNetworks',variables('virtualNetworkName'))]", - "subnet1Ref": "[concat(variables('vnetID'),'/subnets/',variables('subnet1Name'))]", - "vmName": "[parameters('vmPrefix')]", - "sshKeyPath": "[concat('/home/',parameters('adminUsername'),'/.ssh/authorized_keys')]", - "publicIPAddressName": "PublicIP", - "publicIPAddressType": "Dynamic", - "virtualNetworkName": "MyVNET", - "netSecurityGroup": "MyNSG", - "addressPrefix": "10.0.0.0/16", - "subnet1Name": "subnet-1", - "subnet1Prefix": "10.0.0.0/24", - "nicName": "myVMNic" - }, - "resources": [ - { - "apiVersion": "2017-11-01", - "type": "Microsoft.Network/publicIPAddresses", - "name": "[concat(variables('publicIPAddressName'),copyIndex(1))]", - "location": "[resourceGroup().location]", - "copy": { - "name": "publicIPLoop", - "count": "[parameters('numberOfInstances')]" - }, - "properties": { - "publicIPAllocationMethod": "[variables('publicIPAddressType')]" - }, - "tags": { - "workshop": "[parameters('workshopName')]" - } - }, - { - "apiVersion": "2017-11-01", - "type": "Microsoft.Network/virtualNetworks", - "name": "[variables('virtualNetworkName')]", - "location": "[resourceGroup().location]", - "dependsOn": [ - "[concat('Microsoft.Network/networkSecurityGroups/', variables('netSecurityGroup'))]" - ], - "properties": { - "addressSpace": { - "addressPrefixes": [ - "[variables('addressPrefix')]" - ] - }, - "subnets": [ - { - "name": "[variables('subnet1Name')]", - "properties": { - "addressPrefix": "[variables('subnet1Prefix')]", - "networkSecurityGroup": { - "id": "[resourceId('Microsoft.Network/networkSecurityGroups', variables('netSecurityGroup'))]" - } - } - } - ] - }, - "tags": { - "workshop": "[parameters('workshopName')]" - } - }, - { - "apiVersion": "2017-11-01", - "type": "Microsoft.Network/networkInterfaces", - "name": "[concat(variables('nicName'),copyIndex(1))]", - "location": "[resourceGroup().location]", - "copy": { - "name": "nicLoop", - "count": "[parameters('numberOfInstances')]" - }, - "dependsOn": [ - "[concat('Microsoft.Network/publicIPAddresses/', variables('publicIPAddressName'),copyIndex(1))]", - "[concat('Microsoft.Network/virtualNetworks/', variables('virtualNetworkName'))]" - ], - "properties": { - "ipConfigurations": [ - { - "name": "ipconfig1", - "properties": { - "privateIPAllocationMethod": "Dynamic", - "publicIPAddress": { - "id": "[resourceId('Microsoft.Network/publicIPAddresses', concat(variables('publicIPAddressName'), copyIndex(1)))]" - }, - "subnet": { - "id": "[variables('subnet1Ref')]" - } - } - } - ] - }, - "tags": { - "workshop": "[parameters('workshopName')]" - } - }, - { - "apiVersion": "2017-12-01", - "type": "Microsoft.Compute/virtualMachines", - "name": "[concat(variables('vmName'),copyIndex(1))]", - "location": "[resourceGroup().location]", - "copy": { - "name": "vmLoop", - "count": "[parameters('numberOfInstances')]" - }, - "dependsOn": [ - "[concat('Microsoft.Network/networkInterfaces/', variables('nicName'), copyIndex(1))]" - ], - "properties": { - "hardwareProfile": { - "vmSize": "[parameters('vmSize')]" - }, - "osProfile": { - "computerName": "[concat(variables('vmName'),copyIndex(1))]", - "adminUsername": "[parameters('adminUsername')]", - "linuxConfiguration": { - "disablePasswordAuthentication": true, - "ssh": { - "publicKeys": [ - { - "path": "[variables('sshKeyPath')]", - "keyData": "[parameters('sshKeyData')]" - } - ] - } - } - }, - "storageProfile": { - "osDisk": { - "createOption": "FromImage" - }, - "imageReference": { - "publisher": "[parameters('imagePublisher')]", - "offer": "[parameters('imageOffer')]", - "sku": "[parameters('imageSKU')]", - "version": "latest" - } - }, - "networkProfile": { - "networkInterfaces": [ - { - "id": "[resourceId('Microsoft.Network/networkInterfaces', concat(variables('nicName'),copyIndex(1)))]" - } - ] - } - }, - "tags": { - "workshop": "[parameters('workshopName')]" - } - }, - { - "apiVersion": "2017-11-01", - "type": "Microsoft.Network/networkSecurityGroups", - "name": "[variables('netSecurityGroup')]", - "location": "[resourceGroup().location]", - "tags": { - "workshop": "[parameters('workshopName')]" - }, - "properties": { - "securityRules": [ - { - "name": "default-open-ports", - "properties": { - "protocol": "Tcp", - "sourcePortRange": "*", - "destinationPortRange": "*", - "sourceAddressPrefix": "*", - "destinationAddressPrefix": "*", - "access": "Allow", - "priority": 1000, - "direction": "Inbound" - } - } - ] - } - } - ], - "outputs": { - "resourceID": { - "type": "string", - "value": "[resourceId('Microsoft.Network/publicIPAddresses', concat(variables('publicIPAddressName'),'1'))]" - } - } -} diff --git a/prepare-vms/azuredeploy.parameters.json b/prepare-vms/azuredeploy.parameters.json deleted file mode 100644 index 81058ffb9..000000000 --- a/prepare-vms/azuredeploy.parameters.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "$schema": "http://schema.management.azure.com/schemas/2015-01-01/deploymentParameters.json#", - "contentVersion": "1.0.0.0", - "parameters": { - "sshKeyData": { - "value": "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDXTIl/M9oeSlcsC5Rfe+nZr4Jc4sl200pSw2lpdxlZ3xzeP15NgSSMJnigUrKUXHfqRQ+2wiPxEf0Odz2GdvmXvR0xodayoOQsO24AoERjeSBXCwqITsfp1bGKzMb30/3ojRBo6LBR6r1+lzJYnNCGkT+IQwLzRIpm0LCNz1j08PUI2aZ04+mcDANvHuN/hwi/THbLLp6SNWN43m9r02RcC6xlCNEhJi4wk4VzMzVbSv9RlLGST2ocbUHwmQ2k9OUmpzoOx73aQi9XNnEaFh2w/eIdXM75VtkT3mRryyykg9y0/hH8/MVmIuRIdzxHQqlm++DLXVH5Ctw6a4kS+ki7 workshop" - }, - "workshopName": { - "value": "workshop" - }, - "numberOfInstances": { - "value": 3 - }, - "vmSize": { - "value": "Standard_D1_v2" - } - } -} diff --git a/prepare-vms/e2e.sh b/prepare-vms/e2e.sh deleted file mode 100755 index 7c4e39014..000000000 --- a/prepare-vms/e2e.sh +++ /dev/null @@ -1,10 +0,0 @@ -#!/bin/sh -set -e -TAG=$(./workshopctl maketag) -./workshopctl start --settings settings/jerome.yaml --infra infra/aws-eu-central-1 --tag $TAG -./workshopctl deploy $TAG -./workshopctl kube $TAG -./workshopctl helmprom $TAG -while ! ./workshopctl kubetest $TAG; do sleep 1; done -./workshopctl tmux $TAG -echo ./workshopctl stop $TAG diff --git a/prepare-vms/infra/example.aws b/prepare-vms/infra/example.aws deleted file mode 100644 index 05183d2c8..000000000 --- a/prepare-vms/infra/example.aws +++ /dev/null @@ -1,6 +0,0 @@ -INFRACLASS=aws -# If you are using AWS to deploy, copy this file (e.g. to "aws", or "us-east-1") -# and customize the variables below. -export AWS_DEFAULT_REGION=us-east-1 -export AWS_ACCESS_KEY_ID=AKI... -export AWS_SECRET_ACCESS_KEY=... diff --git a/prepare-vms/infra/example.generic b/prepare-vms/infra/example.generic deleted file mode 100644 index 5846a8995..000000000 --- a/prepare-vms/infra/example.generic +++ /dev/null @@ -1,2 +0,0 @@ -INFRACLASS=generic -# This is for manual provisioning. No other variable or configuration is needed. diff --git a/prepare-vms/infra/example.openstack-cli b/prepare-vms/infra/example.openstack-cli deleted file mode 100644 index d20f79d60..000000000 --- a/prepare-vms/infra/example.openstack-cli +++ /dev/null @@ -1,24 +0,0 @@ -INFRACLASS=openstack-cli - -# Copy that file to e.g. openstack or ovh, then customize it. -# Some Openstack providers (like OVHcloud) will let you download -# a file containing credentials. That's what you need to use. -# The file below contains some example values. -export OS_AUTH_URL=https://auth.cloud.ovh.net/v3/ -export OS_IDENTITY_API_VERSION=3 -export OS_USER_DOMAIN_NAME=${OS_USER_DOMAIN_NAME:-"Default"} -export OS_PROJECT_DOMAIN_NAME=${OS_PROJECT_DOMAIN_NAME:-"Default"} -export OS_TENANT_ID=abcd1234 -export OS_TENANT_NAME="0123456" -export OS_USERNAME="user-xyz123" -export OS_PASSWORD=AbCd1234 -export OS_REGION_NAME="GRA7" - -# And then some values to indicate server type, image, etc. -# You can see available flavors with `openstack flavor list` -export OS_FLAVOR=s1-4 -# You can see available images with `openstack image list` -export OS_IMAGE=896c5f54-51dc-44f0-8c22-ce99ba7164df -# You can create a key with `openstack keypair create --public-key ~/.ssh/id_rsa.pub containertraining` -export OS_KEY=containertraining - diff --git a/prepare-vms/infra/example.terraform.openstack b/prepare-vms/infra/example.terraform.openstack deleted file mode 100644 index 17c94273e..000000000 --- a/prepare-vms/infra/example.terraform.openstack +++ /dev/null @@ -1,12 +0,0 @@ -INFRACLASS=terraform -TERRAFORM=openstack - -# If you are using OpenStack, copy this file (e.g. to "openstack" or "enix") -# and customize the variables below. -export TF_VAR_user="jpetazzo" -export TF_VAR_tenant="training" -export TF_VAR_domain="Default" -export TF_VAR_password="..." -export TF_VAR_auth_url="https://api.r1.nxs.enix.io/v3" -export TF_VAR_flavor="GP1.S" -export TF_VAR_image="Ubuntu 18.04" diff --git a/prepare-vms/infra/hetzner b/prepare-vms/infra/hetzner deleted file mode 100644 index db3220bec..000000000 --- a/prepare-vms/infra/hetzner +++ /dev/null @@ -1,2 +0,0 @@ -INFRACLASS=terraform -TERRAFORM=hetzner diff --git a/prepare-vms/infra/scaleway b/prepare-vms/infra/scaleway deleted file mode 100644 index aa6fa09a1..000000000 --- a/prepare-vms/infra/scaleway +++ /dev/null @@ -1,3 +0,0 @@ -INFRACLASS=scaleway -#SCW_INSTANCE_TYPE=DEV1-L -SCW_ZONE=fr-par-2 diff --git a/prepare-vms/lib/clusterize.py b/prepare-vms/lib/clusterize.py deleted file mode 100644 index 869b59e9f..000000000 --- a/prepare-vms/lib/clusterize.py +++ /dev/null @@ -1,78 +0,0 @@ -#!/usr/bin/env python -import os -import sys -import time -import yaml - -################################# - -config = yaml.load(open("/tmp/settings.yaml")) -CLUSTER_SIZE = config["clustersize"] -CLUSTER_PREFIX = config["clusterprefix"] - -################################# - -# This script will be run as ubuntu user, which has root privileges. - -STEP = 0 - -def bold(msg): - return "{} {} {}".format("$(tput smso)", msg, "$(tput rmso)") - -def system(cmd): - global STEP - with open("/tmp/pp.status", "a") as f: - t1 = time.time() - f.write(bold("--- RUNNING [step {}] ---> {}...".format(STEP, cmd))) - retcode = os.system(cmd) - t2 = time.time() - td = str(t2-t1)[:5] - f.write(bold("[{}] in {}s\n".format(retcode, td))) - STEP += 1 - with open(os.environ["HOME"] + "/.bash_history", "a") as f: - f.write("{}\n".format(cmd)) - if retcode != 0: - msg = "The following command failed with exit code {}:\n".format(retcode) - msg+= cmd - raise(Exception(msg)) - -# Get our public IP address -# ipv4_retrieval_endpoint = "http://169.254.169.254/latest/meta-data/public-ipv4" -ipv4_retrieval_endpoint = "http://myip.enix.org/REMOTE_ADDR" -system("curl --silent {} > /tmp/ipv4".format(ipv4_retrieval_endpoint)) -ipv4 = open("/tmp/ipv4").read() -system("echo HOSTIP={} | sudo tee -a /etc/environment".format(ipv4)) - -### BEGIN CLUSTERING ### - -addresses = list(l.strip() for l in sys.stdin) - -assert ipv4 in addresses - -def makenames(addrs): - return [ "%s%s"%(CLUSTER_PREFIX, i+1) for i in range(len(addrs)) ] - -while addresses: - cluster = addresses[:CLUSTER_SIZE] - addresses = addresses[CLUSTER_SIZE:] - if ipv4 not in cluster: - continue - names = makenames(cluster) - for ipaddr, name in zip(cluster, names): - system("grep ^{} /etc/hosts || echo {} {} | sudo tee -a /etc/hosts" - .format(ipaddr, ipaddr, name)) - print(cluster) - - mynode = cluster.index(ipv4) + 1 - system("echo {}{} | sudo tee /etc/hostname".format(CLUSTER_PREFIX, mynode)) - system("sudo hostname {}{}".format(CLUSTER_PREFIX, mynode)) - - # Record the IPV4 and name of the first node - system("echo {} | sudo tee /etc/ipv4_of_first_node".format(cluster[0])) - system("echo {} | sudo tee /etc/name_of_first_node".format(names[0])) - - # Create a convenience file to easily check if we're the first node - if ipv4 == cluster[0]: - system("sudo ln -sf /bin/true /usr/local/bin/i_am_first_node") - else: - system("sudo ln -sf /bin/false /usr/local/bin/i_am_first_node") diff --git a/prepare-vms/lib/infra.sh b/prepare-vms/lib/infra.sh deleted file mode 100644 index 6735a7c3c..000000000 --- a/prepare-vms/lib/infra.sh +++ /dev/null @@ -1,30 +0,0 @@ -# Default stub functions for infrastructure libraries. -# When loading an infrastructure library, these functions will be overridden. - -infra_list() { - warning "infra_list is unsupported on $INFRACLASS." -} - -infra_quotas() { - warning "infra_quotas is unsupported on $INFRACLASS." -} - -infra_start() { - warning "infra_start is unsupported on $INFRACLASS." -} - -infra_stop() { - warning "infra_stop is unsupported on $INFRACLASS." -} - -infra_quotas() { - warning "infra_quotas is unsupported on $INFRACLASS." -} - -infra_opensg() { - warning "infra_opensg is unsupported on $INFRACLASS." -} - -infra_disableaddrchecks() { - warning "infra_disableaddrchecks is unsupported on $INFRACLASS." -} \ No newline at end of file diff --git a/prepare-vms/lib/infra/aws.sh b/prepare-vms/lib/infra/aws.sh deleted file mode 100644 index a10caace0..000000000 --- a/prepare-vms/lib/infra/aws.sh +++ /dev/null @@ -1,250 +0,0 @@ -if ! command -v aws >/dev/null; then - warning "AWS CLI (aws) not found." -fi - -infra_list() { - aws ec2 describe-instances --output json | - jq -r '.Reservations[].Instances[] | [.InstanceId, .ClientToken, .State.Name, .InstanceType ] | @tsv' -} - -infra_quotas() { - aws_greet - - max_instances=$(aws ec2 describe-account-attributes \ - --attribute-names max-instances \ - --query 'AccountAttributes[*][AttributeValues]') - info "In the current region ($AWS_DEFAULT_REGION) you can deploy up to $max_instances instances." - - # Print list of AWS EC2 regions, highlighting ours ($AWS_DEFAULT_REGION) in the list - # If our $AWS_DEFAULT_REGION is not valid, the error message will be pretty descriptive: - # Could not connect to the endpoint URL: "https://ec2.foo.amazonaws.com/" - info "Available regions:" - aws ec2 describe-regions | awk '{print $3}' | grep --color=auto $AWS_DEFAULT_REGION -C50 -} - -infra_start() { - COUNT=$1 - - # Print our AWS username, to ease the pain of credential-juggling - aws_greet - - # Upload our SSH keys to AWS if needed, to be added to each VM's authorized_keys - key_name=$(aws_sync_keys) - - AMI=$(aws_get_ami) # Retrieve the AWS image ID - if [ -z "$AMI" ]; then - die "I could not find which AMI to use in this region. Try another region?" - fi - AWS_KEY_NAME=$(make_key_name) - AWS_INSTANCE_TYPE=${AWS_INSTANCE_TYPE-t3a.medium} - - sep "Starting instances" - info " Count: $COUNT" - info " Region: $AWS_DEFAULT_REGION" - info " Token/tag: $TAG" - info " AMI: $AMI" - info " Key name: $AWS_KEY_NAME" - info " Instance type: $AWS_INSTANCE_TYPE" - result=$(aws ec2 run-instances \ - --key-name $AWS_KEY_NAME \ - --count $COUNT \ - --instance-type $AWS_INSTANCE_TYPE \ - --client-token $TAG \ - --block-device-mapping 'DeviceName=/dev/sda1,Ebs={VolumeSize=20}' \ - --image-id $AMI) - reservation_id=$(echo "$result" | head -1 | awk '{print $2}') - info "Reservation ID: $reservation_id" - sep - - # if instance creation succeeded, we should have some IDs - IDS=$(aws_get_instance_ids_by_client_token $TAG) - if [ -z "$IDS" ]; then - die "Instance creation failed." - fi - - # Tag these new instances with a tag that is the same as the token - aws_tag_instances $TAG $TAG - - # Wait until EC2 API tells us that the instances are running - aws_wait_until_tag_is_running $TAG $COUNT - - aws_get_instance_ips_by_tag $TAG > tags/$TAG/ips.txt -} - -infra_stop() { - aws_kill_instances_by_tag -} - -infra_opensg() { - aws ec2 authorize-security-group-ingress \ - --group-name default \ - --protocol icmp \ - --port -1 \ - --cidr 0.0.0.0/0 - - aws ec2 authorize-security-group-ingress \ - --group-name default \ - --protocol udp \ - --port 0-65535 \ - --cidr 0.0.0.0/0 - - aws ec2 authorize-security-group-ingress \ - --group-name default \ - --protocol tcp \ - --port 0-65535 \ - --cidr 0.0.0.0/0 -} - -infra_disableaddrchecks() { - IDS=$(aws_get_instance_ids_by_tag $TAG) - for ID in $IDS; do - info "Disabling source/destination IP checks on: $ID" - aws ec2 modify-instance-attribute --source-dest-check "{\"Value\": false}" --instance-id $ID - done -} - -aws_wait_until_tag_is_running() { - max_retry=100 - i=0 - done_count=0 - while [[ $done_count -lt $COUNT ]]; do - let "i += 1" - info "$(printf "%d/%d instances online" $done_count $COUNT)" - done_count=$(aws ec2 describe-instances \ - --filters "Name=tag:Name,Values=$TAG" \ - "Name=instance-state-name,Values=running" \ - --query "length(Reservations[].Instances[])") - if [[ $i -gt $max_retry ]]; then - die "Timed out while waiting for instance creation (after $max_retry retries)" - fi - sleep 1 - done -} - -aws_display_tags() { - # Print all "Name" tags in our region with their instance count - echo "[#] [Status] [Token] [Tag]" \ - | awk '{ printf "%-7s %-12s %-25s %-25s\n", $1, $2, $3, $4}' - aws ec2 describe-instances \ - --query "Reservations[*].Instances[*].[State.Name,ClientToken,Tags[0].Value]" \ - | tr -d "\r" \ - | uniq -c \ - | sort -k 3 \ - | awk '{ printf "%-7s %-12s %-25s %-25s\n", $1, $2, $3, $4}' -} - -aws_get_tokens() { - aws ec2 describe-instances --output text \ - --query 'Reservations[*].Instances[*].[ClientToken]' \ - | sort -u -} - -aws_display_instance_statuses_by_tag() { - IDS=$(aws ec2 describe-instances \ - --filters "Name=tag:Name,Values=$TAG" \ - --query "Reservations[*].Instances[*].InstanceId" | tr '\t' ' ') - - aws ec2 describe-instance-status \ - --instance-ids $IDS \ - --query "InstanceStatuses[*].{ID:InstanceId,InstanceState:InstanceState.Name,InstanceStatus:InstanceStatus.Status,SystemStatus:SystemStatus.Status,Reachability:InstanceStatus.Status}" \ - --output table -} - -aws_display_instances_by_tag() { - result=$(aws ec2 describe-instances --output table \ - --filter "Name=tag:Name,Values=$TAG" \ - --query "Reservations[*].Instances[*].[ \ - InstanceId, \ - State.Name, \ - Tags[0].Value, \ - PublicIpAddress, \ - InstanceType \ - ]" - ) - if [[ -z $result ]]; then - die "No instances found with tag $TAG in region $AWS_DEFAULT_REGION." - else - echo "$result" - fi -} - -aws_get_instance_ids_by_filter() { - FILTER=$1 - aws ec2 describe-instances --filters $FILTER \ - --query Reservations[*].Instances[*].InstanceId \ - --output text | tr "\t" "\n" | tr -d "\r" -} - -aws_get_instance_ids_by_client_token() { - TOKEN=$1 - aws_get_instance_ids_by_filter Name=client-token,Values=$TOKEN -} - -aws_get_instance_ids_by_tag() { - aws_get_instance_ids_by_filter Name=tag:Name,Values=$TAG -} - -aws_get_instance_ips_by_tag() { - aws ec2 describe-instances --filter "Name=tag:Name,Values=$TAG" \ - --output text \ - --query "Reservations[*].Instances[*].PublicIpAddress" \ - | tr "\t" "\n" \ - | sort -n -t . -k 1,1 -k 2,2 -k 3,3 -k 4,4 # sort IPs -} - -aws_kill_instances_by_tag() { - IDS=$(aws_get_instance_ids_by_tag $TAG) - if [ -z "$IDS" ]; then - die "Invalid tag." - fi - - info "Deleting instances with tag $TAG." - - aws ec2 terminate-instances --instance-ids $IDS \ - | grep ^TERMINATINGINSTANCES - - info "Deleted instances with tag $TAG." -} - -aws_tag_instances() { - OLD_TAG_OR_TOKEN=$1 - NEW_TAG=$2 - IDS=$(aws_get_instance_ids_by_client_token $OLD_TAG_OR_TOKEN) - [[ -n "$IDS" ]] && aws ec2 create-tags --tag Key=Name,Value=$NEW_TAG --resources $IDS >/dev/null - IDS=$(aws_get_instance_ids_by_tag $OLD_TAG_OR_TOKEN) - [[ -n "$IDS" ]] && aws ec2 create-tags --tag Key=Name,Value=$NEW_TAG --resources $IDS >/dev/null -} - -aws_get_ami() { - ##VERSION## - find_ubuntu_ami -r $AWS_DEFAULT_REGION -a ${ARCHITECTURE-amd64} -v 18.04 -t hvm:ebs -N -q -} - -aws_greet() { - IAMUSER=$(aws iam get-user --query 'User.UserName') - info "Hello! You seem to be UNIX user $USER, and IAM user $IAMUSER." -} - -aws_sync_keys() { - # make sure ssh-add -l contains "RSA" - ssh-add -l | grep -q RSA \ - || die "The output of \`ssh-add -l\` doesn't contain 'RSA'. Start the agent, add your keys?" - - AWS_KEY_NAME=$(make_key_name) - info "Syncing keys... " - if ! aws ec2 describe-key-pairs --key-name "$AWS_KEY_NAME" &>/dev/null; then - aws ec2 import-key-pair --key-name $AWS_KEY_NAME \ - --public-key-material "$(ssh-add -L \ - | grep -i RSA \ - | head -n1 \ - | cut -d " " -f 1-2)" &>/dev/null - - if ! aws ec2 describe-key-pairs --key-name "$AWS_KEY_NAME" &>/dev/null; then - die "Somehow, importing the key didn't work. Make sure that 'ssh-add -l | grep RSA | head -n1' returns an RSA key?" - else - info "Imported new key $AWS_KEY_NAME." - fi - else - info "Using existing key $AWS_KEY_NAME." - fi -} diff --git a/prepare-vms/lib/infra/generic.sh b/prepare-vms/lib/infra/generic.sh deleted file mode 100644 index ded6069c3..000000000 --- a/prepare-vms/lib/infra/generic.sh +++ /dev/null @@ -1,8 +0,0 @@ -infra_start() { - COUNT=$1 - info "You should now run your provisioning commands for $COUNT machines." - info "Note: no machines have been automatically created!" - info "Once done, put the list of IP addresses in tags/$TAG/ips.txt" - info "(one IP address per line, without any comments or extra lines)." - touch tags/$TAG/ips.txt -} diff --git a/prepare-vms/lib/infra/openstack-cli.sh b/prepare-vms/lib/infra/openstack-cli.sh deleted file mode 100644 index 19d77d4b5..000000000 --- a/prepare-vms/lib/infra/openstack-cli.sh +++ /dev/null @@ -1,53 +0,0 @@ -infra_list() { - openstack server list -f json | - jq -r '.[] | [.ID, .Name , .Status, .Flavor] | @tsv' -} - -infra_start() { - COUNT=$1 - - sep "Starting $COUNT instances" - info " Region: $OS_REGION_NAME" - info " User: $OS_USERNAME" - info " Flavor: $OS_FLAVOR" - info " Image: $OS_IMAGE" - openstack server create \ - --flavor $OS_FLAVOR \ - --image $OS_IMAGE \ - --key-name $OS_KEY \ - --min $COUNT --max $COUNT \ - --property workshopctl=$TAG \ - $TAG - - sep "Waiting for IP addresses to be available" - GOT=0 - while [ "$GOT" != "$COUNT" ]; do - echo "Got $GOT/$COUNT IP addresses." - oscli_get_ips_by_tag $TAG > tags/$TAG/ips.txt - GOT="$(wc -l < tags/$TAG/ips.txt)" - done - -} - -infra_stop() { - info "Counting instances..." - oscli_get_instances_json $TAG | - jq -r .[].Name | - wc -l - info "Deleting instances..." - oscli_get_instances_json $TAG | - jq -r .[].Name | - xargs -P10 -n1 openstack server delete - info "Done." -} - -oscli_get_instances_json() { - TAG=$1 - openstack server list -f json --name "${TAG}-[0-9]*" -} - -oscli_get_ips_by_tag() { - TAG=$1 - oscli_get_instances_json $TAG | - jq -r .[].Networks | grep -oE '[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+' || true -} diff --git a/prepare-vms/lib/infra/scaleway.sh b/prepare-vms/lib/infra/scaleway.sh deleted file mode 100644 index 85415e266..000000000 --- a/prepare-vms/lib/infra/scaleway.sh +++ /dev/null @@ -1,51 +0,0 @@ -if ! command -v scw >/dev/null; then - warning "Scaleway CLI (scw) not found." -fi -if ! [ -f ~/.config/scw/config.yaml ]; then - warning "~/.config/scw/config.yaml not found." -fi - -SCW_INSTANCE_TYPE=${SCW_INSTANCE_TYPE-DEV1-M} -SCW_ZONE=${SCW_ZONE-fr-par-1} - -infra_list() { - scw instance server list -o json | - jq -r '.[] | [.id, .name, .state, .commercial_type] | @tsv' -} - -infra_start() { - COUNT=$1 - - for I in $(seq 1 $COUNT); do - NAME=$(printf "%s-%03d" $TAG $I) - sep "Starting instance $I/$COUNT" - info " Zone: $SCW_ZONE" - info " Name: $NAME" - info " Instance type: $SCW_INSTANCE_TYPE" - scw instance server create \ - type=${SCW_INSTANCE_TYPE} zone=${SCW_ZONE} \ - image=ubuntu_bionic name=${NAME} - done - sep - - scw_get_ips_by_tag $TAG > tags/$TAG/ips.txt -} - -infra_stop() { - info "Counting instances..." - scw_get_ids_by_tag $TAG | wc -l - info "Deleting instances..." - scw_get_ids_by_tag $TAG | - xargs -n1 -P10 \ - scw instance server delete zone=${SCW_ZONE} force-shutdown=true with-ip=true -} - -scw_get_ids_by_tag() { - TAG=$1 - scw instance server list zone=${SCW_ZONE} name=$TAG -o json | jq -r .[].id -} - -scw_get_ips_by_tag() { - TAG=$1 - scw instance server list zone=${SCW_ZONE} name=$TAG -o json | jq -r .[].public_ip.address -} diff --git a/prepare-vms/lib/infra/terraform.sh b/prepare-vms/lib/infra/terraform.sh deleted file mode 100644 index 93cc86672..000000000 --- a/prepare-vms/lib/infra/terraform.sh +++ /dev/null @@ -1,54 +0,0 @@ -error_terraform_configuration() { - error "When using the terraform infraclass, the TERRAFORM" - error "environment variable must be set to one of the available" - error "terraform configurations. These configurations are in" - error "the prepare-vm/terraform subdirectory. You should probably" - error "update your infra file and set the variable." - error "(e.g. with TERRAFORM=openstack)" -} - -if [ "$TERRAFORM" = "" ]; then - error_terraform_configuration - die "Aborting because TERRAFORM variable is not set." -fi - -if [ ! -d terraform/$TERRAFORM ]; then - error_terraform_configuration - die "Aborting because no terraform configuration was found in 'terraform/$TERRAFORM'." -fi - -infra_start() { - COUNT=$1 - - cp terraform/$TERRAFORM/*.tf tags/$TAG - ( - cd tags/$TAG - if ! terraform init; then - error "'terraform init' failed." - error "If it mentions the following error message:" - error "openpgp: signature made by unknown entity." - error "Then you need to upgrade Terraform to 0.11.15" - error "to upgrade its signing keys following the" - error "codecov breach." - die "Aborting." - fi - echo prefix = \"$TAG\" >> terraform.tfvars - echo how_many_nodes = \"$COUNT\" >> terraform.tfvars - for RETRY in 1 2 3; do - if terraform apply -auto-approve; then - terraform output -raw ip_addresses > ips.txt - break - fi - done - if ! [ -f ips.txt ]; then - die "Terraform failed." - fi - ) -} - -infra_stop() { - ( - cd tags/$TAG - terraform destroy -auto-approve - ) -} diff --git a/prepare-vms/lib/infra/unimplemented.sh b/prepare-vms/lib/infra/unimplemented.sh deleted file mode 100644 index c32e2356b..000000000 --- a/prepare-vms/lib/infra/unimplemented.sh +++ /dev/null @@ -1,23 +0,0 @@ -infra_disableaddrchecks() { - die "unimplemented" -} - -infra_list() { - die "unimplemented" -} - -infra_opensg() { - die "unimplemented" -} - -infra_quotas() { - die "unimplemented" -} - -infra_start() { - die "unimplemented" -} - -infra_stop() { - die "unimplemented" -} diff --git a/prepare-vms/settings/admin-dmuc.yaml b/prepare-vms/settings/admin-dmuc.yaml deleted file mode 100644 index 1ed9abe77..000000000 --- a/prepare-vms/settings/admin-dmuc.yaml +++ /dev/null @@ -1,32 +0,0 @@ -# Number of VMs per cluster -clustersize: 1 - -# The hostname of each node will be clusterprefix + a number -clusterprefix: dmuc - -# Jinja2 template to use to generate ready-to-cut cards -cards_template: cards.html - -# Use "Letter" in the US, and "A4" everywhere else -paper_size: A4 - -# Login and password that students will use -user_login: k8s -user_password: training - -image: - -steps: - - wait - - standardize - - clusterize - - tools - - docker - - disabledocker - - createuser - - webssh - - tailhist - - kubebins - - kubetools - - cards - - ips diff --git a/prepare-vms/settings/admin-kubenet.yaml b/prepare-vms/settings/admin-kubenet.yaml deleted file mode 100644 index 434037987..000000000 --- a/prepare-vms/settings/admin-kubenet.yaml +++ /dev/null @@ -1,33 +0,0 @@ -# Number of VMs per cluster -clustersize: 3 - -# The hostname of each node will be clusterprefix + a number -clusterprefix: kubenet - -# Jinja2 template to use to generate ready-to-cut cards -cards_template: cards.html - -# Use "Letter" in the US, and "A4" everywhere else -paper_size: A4 - -# Login and password that students will use -user_login: k8s -user_password: training - -clusternumber: 100 -image: - -steps: - - disableaddrchecks - - wait - - standardize - - clusterize - - tools - - docker - - createuser - - webssh - - tailhist - - kubebins - - kubetools - - cards - - ips diff --git a/prepare-vms/settings/admin-kuberouter.yaml b/prepare-vms/settings/admin-kuberouter.yaml deleted file mode 100644 index ab95e4892..000000000 --- a/prepare-vms/settings/admin-kuberouter.yaml +++ /dev/null @@ -1,33 +0,0 @@ -# Number of VMs per cluster -clustersize: 3 - -# The hostname of each node will be clusterprefix + a number -clusterprefix: kuberouter - -# Jinja2 template to use to generate ready-to-cut cards -cards_template: cards.html - -# Use "Letter" in the US, and "A4" everywhere else -paper_size: A4 - -# Login and password that students will use -user_login: k8s -user_password: training - -clusternumber: 200 -image: - -steps: - - disableaddrchecks - - wait - - standardize - - clusterize - - tools - - docker - - createuser - - webssh - - tailhist - - kubebins - - kubetools - - cards - - ips diff --git a/prepare-vms/settings/admin-oldversion.yaml b/prepare-vms/settings/admin-oldversion.yaml deleted file mode 100644 index 5b2b9a644..000000000 --- a/prepare-vms/settings/admin-oldversion.yaml +++ /dev/null @@ -1,34 +0,0 @@ -# Number of VMs per cluster -clustersize: 3 - -# The hostname of each node will be clusterprefix + a number -clusterprefix: oldversion - -# Jinja2 template to use to generate ready-to-cut cards -cards_template: cards.html - -# Use "Letter" in the US, and "A4" everywhere else -paper_size: A4 - -# Login and password that students will use -user_login: k8s -user_password: training - -# For a list of old versions, check: -# https://kubernetes.io/releases/patch-releases/#non-active-branch-history -kubernetes_version: 1.20.15 - -image: - -steps: - - wait - - standardize - - clusterize - - tools - - docker - - createuser - - webssh - - tailhist - - kube - - kubetools - - kubetest diff --git a/prepare-vms/settings/admin-test.yaml b/prepare-vms/settings/admin-test.yaml deleted file mode 100644 index ef5882a21..000000000 --- a/prepare-vms/settings/admin-test.yaml +++ /dev/null @@ -1,32 +0,0 @@ -# Number of VMs per cluster -clustersize: 3 - -# The hostname of each node will be clusterprefix + a number -clusterprefix: test - -# Jinja2 template to use to generate ready-to-cut cards -cards_template: cards.html - -# Use "Letter" in the US, and "A4" everywhere else -paper_size: A4 - -# Login and password that students will use -user_login: k8s -user_password: training - -image: - -steps: - - wait - - standardize - - clusterize - - tools - - docker - - createuser - - webssh - - tailhist - - kube - - kubetools - - kubetest - - cards - - ips diff --git a/prepare-vms/settings/docker.yaml b/prepare-vms/settings/docker.yaml deleted file mode 100644 index fa124ce76..000000000 --- a/prepare-vms/settings/docker.yaml +++ /dev/null @@ -1,29 +0,0 @@ -# This file is passed by trainer-cli to scripts/ips-txt-to-html.py - -# Number of VMs per cluster -clustersize: 1 - -# The hostname of each node will be clusterprefix + a number -clusterprefix: node - -# Jinja2 template to use to generate ready-to-cut cards -cards_template: cards.html - -# Use "Letter" in the US, and "A4" everywhere else -paper_size: Letter - -# Login and password that students will use -user_login: docker -user_password: training - -steps: - - wait - - standardize - - clusterize - - tools - - docker - - createuser - - webssh - - tailhist - - cards - - ips diff --git a/prepare-vms/settings/kubernetes.yaml b/prepare-vms/settings/kubernetes.yaml deleted file mode 100644 index 6d3a9b8a4..000000000 --- a/prepare-vms/settings/kubernetes.yaml +++ /dev/null @@ -1,30 +0,0 @@ -# Number of VMs per cluster -clustersize: 4 - -# The hostname of each node will be clusterprefix + a number -clusterprefix: node - -# Jinja2 template to use to generate ready-to-cut cards -cards_template: cards.html - -# Use "Letter" in the US, and "A4" everywhere else -paper_size: Letter - -# Login and password that students will use -user_login: k8s -user_password: training - -steps: - - wait - - standardize - - clusterize - - tools - - docker - - createuser - - webssh - - tailhist - - kube - - kubetools - - kubetest - - cards - - ips diff --git a/prepare-vms/settings/portal.yaml b/prepare-vms/settings/portal.yaml deleted file mode 100644 index 00b68fb84..000000000 --- a/prepare-vms/settings/portal.yaml +++ /dev/null @@ -1,26 +0,0 @@ -# This file is passed by trainer-cli to scripts/ips-txt-to-html.py - -# Number of VMs per cluster -clustersize: 1 - -# The hostname of each node will be clusterprefix + a number -clusterprefix: CHANGEME - -# Jinja2 template to use to generate ready-to-cut cards -cards_template: cards.html - -# Use "Letter" in the US, and "A4" everywhere else -paper_size: Letter - -# Login and password that students will use -user_login: portal -user_password: CHANGEME - -steps: - - wait - - standardize - - clusterize - - tools - - docker - - createuser - - ips diff --git a/prepare-vms/terraform/azure/variables.tf b/prepare-vms/terraform/azure/variables.tf deleted file mode 100644 index 128c1baa8..000000000 --- a/prepare-vms/terraform/azure/variables.tf +++ /dev/null @@ -1,32 +0,0 @@ -variable "prefix" { - type = string - default = "provisioned-with-terraform" -} - -variable "how_many_nodes" { - type = number - default = 2 -} - -locals { - authorized_keys = file("~/.ssh/id_rsa.pub") -} - -/* -Available sizes: -"Standard_D11_v2" # CPU=2 RAM=14 -"Standard_F4s_v2" # CPU=4 RAM=8 -"Standard_D1_v2" # CPU=1 RAM=3.5 -"Standard_B1ms" # CPU=1 RAM=2 -"Standard_B2s" # CPU=2 RAM=4 -*/ - -variable "size" { - type = string - default = "Standard_F4s_v2" -} - -variable "location" { - type = string - default = "South Africa North" -} diff --git a/prepare-vms/terraform/digitalocean/main.tf b/prepare-vms/terraform/digitalocean/main.tf deleted file mode 100644 index 83b5979d6..000000000 --- a/prepare-vms/terraform/digitalocean/main.tf +++ /dev/null @@ -1,34 +0,0 @@ -resource "digitalocean_droplet" "_" { - count = var.how_many_nodes - name = format("%s-%04d", var.prefix, count.index + 1) - region = var.location - size = var.size - ssh_keys = [digitalocean_ssh_key._.id] - image = "ubuntu-22-04-x64" -} - -resource "digitalocean_ssh_key" "_" { - name = var.prefix - public_key = tls_private_key.ssh.public_key_openssh -} - -output "ip_addresses" { - value = join("", formatlist("%s\n", digitalocean_droplet._.*.ipv4_address)) -} - -resource "tls_private_key" "ssh" { - algorithm = "RSA" - rsa_bits = "4096" -} - -resource "local_file" "ssh_private_key" { - content = tls_private_key.ssh.private_key_pem - filename = "id_rsa" - file_permission = "0600" -} - -resource "local_file" "ssh_public_key" { - content = tls_private_key.ssh.public_key_openssh - filename = "id_rsa.pub" - file_permission = "0600" -} diff --git a/prepare-vms/terraform/digitalocean/provider.tf b/prepare-vms/terraform/digitalocean/provider.tf deleted file mode 100644 index e83a0baf4..000000000 --- a/prepare-vms/terraform/digitalocean/provider.tf +++ /dev/null @@ -1,12 +0,0 @@ -terraform { - required_version = ">= 1" - required_providers { - digitalocean = { - source = "digitalocean/digitalocean" - } - } -} - -provider "digitalocean" { - token = yamldecode(file("~/.config/doctl/config.yaml"))["access-token"] -} \ No newline at end of file diff --git a/prepare-vms/terraform/digitalocean/variables.tf b/prepare-vms/terraform/digitalocean/variables.tf deleted file mode 100644 index 0946776ce..000000000 --- a/prepare-vms/terraform/digitalocean/variables.tf +++ /dev/null @@ -1,32 +0,0 @@ -variable "prefix" { - type = string - default = "provisioned-with-terraform" -} - -variable "how_many_nodes" { - type = number - default = 2 -} - -locals { - authorized_keys = split("\n", trimspace(file("~/.ssh/id_rsa.pub"))) -} - -/* -Available sizes: -s-1vcpu-2gb -s-2vcpu-2gb -s-2vcpu-4gb -s-4vcpu-8gb -*/ - -variable "size" { - type = string - default = "s-2vcpu-4gb" -} - -/* doctl compute region list */ -variable "location" { - type = string - default = "lon1" -} diff --git a/prepare-vms/terraform/hetzner/main.tf b/prepare-vms/terraform/hetzner/main.tf deleted file mode 100644 index de530aa7f..000000000 --- a/prepare-vms/terraform/hetzner/main.tf +++ /dev/null @@ -1,34 +0,0 @@ -resource "hcloud_server" "_" { - count = var.how_many_nodes - name = format("%s-%04d", var.prefix, count.index + 1) - location = var.location - server_type = var.size - ssh_keys = [hcloud_ssh_key._.id] - image = "ubuntu-22.04" -} - -resource "hcloud_ssh_key" "_" { - name = var.prefix - public_key = tls_private_key.ssh.public_key_openssh -} - -output "ip_addresses" { - value = join("", formatlist("%s\n", hcloud_server._.*.ipv4_address)) -} - -resource "tls_private_key" "ssh" { - algorithm = "RSA" - rsa_bits = "4096" -} - -resource "local_file" "ssh_private_key" { - content = tls_private_key.ssh.private_key_pem - filename = "id_rsa" - file_permission = "0600" -} - -resource "local_file" "ssh_public_key" { - content = tls_private_key.ssh.public_key_openssh - filename = "id_rsa.pub" - file_permission = "0600" -} diff --git a/prepare-vms/terraform/hetzner/provider.tf b/prepare-vms/terraform/hetzner/provider.tf deleted file mode 100644 index 4776603d9..000000000 --- a/prepare-vms/terraform/hetzner/provider.tf +++ /dev/null @@ -1,18 +0,0 @@ -terraform { - required_version = ">= 1" - required_providers { - hcloud = { - source = "hetznercloud/hcloud" - } - } -} - -/* -Okay, the following is pretty gross - it uses the first token found in the hcloud CLI -configuration file. We don't use Hetzner much anyway, and when we do, we only have one -profile ever, and we want this thing to Just Work; so this should do for now, but might -need to be improved if others actively use Hetzner to provision training labs. -*/ -provider hcloud { - token = regex("token = \"([A-Za-z0-9]+)\"", file("~/.config/hcloud/cli.toml"))[0] -} \ No newline at end of file diff --git a/prepare-vms/terraform/linode/main.tf b/prepare-vms/terraform/linode/main.tf deleted file mode 100644 index 604da553f..000000000 --- a/prepare-vms/terraform/linode/main.tf +++ /dev/null @@ -1,12 +0,0 @@ -resource "linode_instance" "_" { - count = var.how_many_nodes - label = format("%s-%04d", var.prefix, count.index + 1) - region = var.location - type = var.size - authorized_keys = local.authorized_keys - image = "linode/ubuntu22.04" -} - -output "ip_addresses" { - value = join("", formatlist("%s\n", linode_instance._.*.ip_address)) -} diff --git a/prepare-vms/terraform/linode/provider.tf b/prepare-vms/terraform/linode/provider.tf deleted file mode 100644 index 708803e71..000000000 --- a/prepare-vms/terraform/linode/provider.tf +++ /dev/null @@ -1,12 +0,0 @@ -terraform { - required_version = ">= 1" - required_providers { - linode = { - source = "linode/linode" - } - } -} - -provider "linode" { - token = regex("\ntoken *= *([0-9a-f]+)\n", file("~/.config/linode-cli"))[0] -} \ No newline at end of file diff --git a/prepare-vms/terraform/linode/variables.tf b/prepare-vms/terraform/linode/variables.tf deleted file mode 100644 index 9e369e243..000000000 --- a/prepare-vms/terraform/linode/variables.tf +++ /dev/null @@ -1,32 +0,0 @@ -variable "prefix" { - type = string - default = "provisioned-with-terraform" -} - -variable "how_many_nodes" { - type = number - default = 2 -} - -locals { - authorized_keys = split("\n", trimspace(file("~/.ssh/id_rsa.pub"))) -} - -/* -Available sizes: -"g6-standard-1" # CPU=1 RAM=2 -"g6-standard-2" # CPU=2 RAM=4 -"g6-standard-4" # CPU=4 RAM=8 -"g6-standard-6" # CPU=6 RAM=16 -"g6-standard-8" # CPU=8 RAM=32 -*/ - -variable "size" { - type = string - default = "g6-standard-2" -} - -variable "location" { - type = string - default = "eu-west" -} diff --git a/prepare-vms/terraform/oci/provider.tf b/prepare-vms/terraform/oci/provider.tf deleted file mode 100644 index 28c622fee..000000000 --- a/prepare-vms/terraform/oci/provider.tf +++ /dev/null @@ -1,8 +0,0 @@ -terraform { - required_version = ">= 1" - required_providers { - openstack = { - source = "hashicorp/oci" - version = "4.48.0" } - } -} diff --git a/prepare-vms/terraform/oci/variables.tf b/prepare-vms/terraform/oci/variables.tf deleted file mode 100644 index a11f79a89..000000000 --- a/prepare-vms/terraform/oci/variables.tf +++ /dev/null @@ -1,42 +0,0 @@ -variable "prefix" { - type = string - default = "provisioned-with-terraform" -} - -variable "how_many_nodes" { - type = number - default = 2 -} - -locals { - authorized_keys = file("~/.ssh/id_rsa.pub") -} - -/* -Available flex shapes: -"VM.Optimized3.Flex" # Intel Ice Lake -"VM.Standard3.Flex" # Intel Ice Lake -"VM.Standard.A1.Flex" # Ampere Altra -"VM.Standard.E3.Flex" # AMD Rome -"VM.Standard.E4.Flex" # AMD Milan -*/ - -variable "shape" { - type = string - default = "VM.Standard.A1.Flex" -} - -variable "availability_domain" { - type = number - default = 0 -} - -variable "ocpus_per_node" { - type = number - default = 1 -} - -variable "memory_in_gbs_per_node" { - type = number - default = 4 -} diff --git a/prepare-vms/terraform/openstack/keypair.tf b/prepare-vms/terraform/openstack/keypair.tf deleted file mode 100644 index 974958388..000000000 --- a/prepare-vms/terraform/openstack/keypair.tf +++ /dev/null @@ -1,5 +0,0 @@ -resource "openstack_compute_keypair_v2" "ssh_deploy_key" { - name = var.prefix - public_key = file("~/.ssh/id_rsa.pub") -} - diff --git a/prepare-vms/terraform/openstack/machines.tf b/prepare-vms/terraform/openstack/machines.tf deleted file mode 100644 index 8f5c47ace..000000000 --- a/prepare-vms/terraform/openstack/machines.tf +++ /dev/null @@ -1,29 +0,0 @@ -resource "openstack_compute_instance_v2" "machine" { - count = var.how_many_nodes - name = format("%s-%04d", var.prefix, count.index + 1) - image_name = var.image - flavor_name = var.flavor - security_groups = [openstack_networking_secgroup_v2.full_access.name] - key_pair = openstack_compute_keypair_v2.ssh_deploy_key.name - - network { - name = openstack_networking_network_v2.internal.name - fixed_ip_v4 = cidrhost(openstack_networking_subnet_v2.internal.cidr, count.index + 10) - } -} - -resource "openstack_compute_floatingip_v2" "machine" { - count = var.how_many_nodes - pool = var.pool -} - -resource "openstack_compute_floatingip_associate_v2" "machine" { - count = var.how_many_nodes - floating_ip = openstack_compute_floatingip_v2.machine.*.address[count.index] - instance_id = openstack_compute_instance_v2.machine.*.id[count.index] - fixed_ip = cidrhost(openstack_networking_subnet_v2.internal.cidr, count.index + 10) -} - -output "ip_addresses" { - value = join("", formatlist("%s\n", openstack_compute_floatingip_v2.machine.*.address)) -} diff --git a/prepare-vms/terraform/openstack/network.tf b/prepare-vms/terraform/openstack/network.tf deleted file mode 100644 index 849de0794..000000000 --- a/prepare-vms/terraform/openstack/network.tf +++ /dev/null @@ -1,23 +0,0 @@ -resource "openstack_networking_network_v2" "internal" { - name = var.prefix -} - -resource "openstack_networking_subnet_v2" "internal" { - name = var.prefix - network_id = openstack_networking_network_v2.internal.id - cidr = "10.10.0.0/16" - ip_version = 4 - dns_nameservers = ["1.1.1.1"] -} - -resource "openstack_networking_router_v2" "router" { - name = var.prefix - external_network_id = var.external_network_id -} - -resource "openstack_networking_router_interface_v2" "router_internal" { - router_id = openstack_networking_router_v2.router.id - subnet_id = openstack_networking_subnet_v2.internal.id -} - - diff --git a/prepare-vms/terraform/openstack/secgroup.tf b/prepare-vms/terraform/openstack/secgroup.tf deleted file mode 100644 index 21704e090..000000000 --- a/prepare-vms/terraform/openstack/secgroup.tf +++ /dev/null @@ -1,12 +0,0 @@ -resource "openstack_networking_secgroup_v2" "full_access" { - name = "${var.prefix} - full access" -} - -resource "openstack_networking_secgroup_rule_v2" "full_access" { - direction = "ingress" - ethertype = "IPv4" - protocol = "" - remote_ip_prefix = "0.0.0.0/0" - security_group_id = openstack_networking_secgroup_v2.full_access.id -} - diff --git a/prepare-vms/terraform/openstack/variables.tf b/prepare-vms/terraform/openstack/variables.tf deleted file mode 100644 index 5d19b3fc2..000000000 --- a/prepare-vms/terraform/openstack/variables.tf +++ /dev/null @@ -1,26 +0,0 @@ -variable "prefix" { - type = string -} - -variable "how_many_nodes" { - type = number -} - -variable "flavor" { - type = string -} - -variable "image" { - type = string - default = "Ubuntu 22.04" -} - -// For example: "Public training floating" -variable "pool" { - type = string -} - -// For example: "74e32174-cf09-452f-bda0-2bdfe074e251" -variable "external_network_id" { - type = string -}