From 445da85d912f14b7305f4ffd602dce53a060d0cb Mon Sep 17 00:00:00 2001 From: Marco Emilio Poleggi <marco-emilio.poleggi@hesge.ch> Date: Tue, 27 Sep 2022 18:12:55 +0200 Subject: [PATCH] WIP: lab refactoring on OpenStack --- .gitattributes | 3 +- AWS/README.md | 541 ++++++++++++++++++ OpenStack/main.tf | 1 - README-OpenStack.md | 123 ---- README.md | 537 +---------------- SwitchEngines/README.md | 310 ++++++++++ .../conf/clouds.yaml.api_cred | 0 .../conf/clouds.yaml.app_cred | 0 SwitchEngines/main.tf | 1 + {OpenStack => SwitchEngines}/main.tf.advnc | Bin SwitchEngines/main.tf.basic | 52 ++ {OpenStack => SwitchEngines}/outputs.tf | Bin 12 files changed, 912 insertions(+), 656 deletions(-) create mode 100644 AWS/README.md delete mode 120000 OpenStack/main.tf delete mode 100644 README-OpenStack.md create mode 100644 SwitchEngines/README.md rename {OpenStack => SwitchEngines}/conf/clouds.yaml.api_cred (100%) rename {OpenStack => SwitchEngines}/conf/clouds.yaml.app_cred (100%) create mode 120000 SwitchEngines/main.tf rename {OpenStack => SwitchEngines}/main.tf.advnc (100%) create mode 100644 SwitchEngines/main.tf.basic rename {OpenStack => SwitchEngines}/outputs.tf (100%) diff --git a/.gitattributes b/.gitattributes index 6c728f4..6b1576a 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1,3 +1,2 @@ AWS/main.tf.advnc filter=git-crypt diff=git-crypt -OpenStack/main.tf.advnc filter=git-crypt diff=git-crypt -OpenStack/outputs.tf filter=git-crypt diff=git-crypt +SwitchEngines/main.tf.advnc filter=git-crypt diff=git-crypt diff --git a/AWS/README.md b/AWS/README.md new file mode 100644 index 0000000..b97a519 --- /dev/null +++ b/AWS/README.md @@ -0,0 +1,541 @@ +# Lab: Cloud provisioning/orchestration - Terraform and AWS + +Lab template for a Cloud provisioning/orchestration exercise with Terraform +(TF) and AWS. + +## Pedagogical objectives ## + + * Become familiar with a Cloud provisioning/orchestration tool + * Provision Cloud resources in an automated fashion + +## Tasks ## + +In this lab you will perform a number of tasks and document your progress in a +lab report. Each task specifies one or more deliverables to be +produced. Collect all the deliverables in your lab report. + +**N.B.** Some tasks require interacting with your local machine's OS: any +related commands are supposed to be run into a terminal with the following +conventions about the *command line prompt*: + + * `#`: execution with super user's (root) privileges + * `$`: execution with normal user's privileges + * `lcl`: your local machine + * `ins`: your VM instance + +TF CLI commands' output follow a diff-style convention of prefixing lines with +special marks to explain what is (or would be) going on: + * `+`: something is added + * `-`: something is removed/destroyed + * `-/+`: a resource is destroyed and recreated + * `~`: something is modified in place + + +### Task #1: install Terraform CLI and AWS CLI ### + +**Goal:** install the Terraform CLI and AWS CLI on your local machine. +Please, refer to your OS documentation for the proper way to do so + + 1. [Terraform + CLI](https://learn.hashicorp.com/tutorials/terraform/install-cli) + v1.1.4. Skip the TF "Quick start tutorial" (Docker). + 1. [AWS CLI](https://aws.amazon.com/cli/) v1.22.. + 1. Create a new [AWS Access + Key](https://console.aws.amazon.com/iam/home?#/security_credentials). + 1. Configure the AWS CLI: + ``` shell + lcl$ aws configure + ``` + +The following tasks are based on TF's tutorial [build an example +infrastructure on +AWS](https://learn.hashicorp.com/tutorials/terraform/aws-build). + + +### Task #2: configure TF for AWS ### + +**Goal:** instruct TF to handle a single AWS EC2 instance. + +<a name="AMI-query"></a>Find out which AMI to use for a recent Ubuntu server. +You can query the AMI Catalog via + a. [AWS dashboard](https://console.aws.amazon.com/ec2/v2/home?region=us-east-1#AMICatalog:), searching "Ubuntu", selecting "Quickstart AMIs" and filtering by "Free tier", + b. or with CLI, and get the 2 most recent AMIs (it will not list free-tier ones): + ``` shell + lcl$ aws ec2 describe-images --region us-east-1 \ + --filters "Name=root-device-type,Values=ebs" \ + "Name=name,Values=*ubuntu-jammy-22.04-amd64-server*" \ + "Name=architecture,Values=x86_64" \ + --query "reverse(sort_by(Images, &ImageId))[:2].[ImageId]" --output text + ami-0f65ab0fd913bc7be + ami-0eb45246cba02871b + ``` + +:bulb: In the following task(s), we use the first AMI found for the +placeholder `<your-EC2-AMI-ID>`. + +Create a "sandbox" directory on your local machine `~/terraform/AWS/`. Inside +it, create a file called `main.tf` (written in HCL language), the +infrastructure *definition* file, with the following content: + +``` hcl +terraform { + required_providers { + aws = { + source = "hashicorp/aws" + version = "~> 3.27" + } + } + + required_version = ">= 0.14.9" +} + +provider "aws" { + profile = "default" + region = "us-east-1" +} + +resource "aws_instance" "app_server" { + ami = "<your-EC2-AMI-ID>" + instance_type = "t2.micro" + + tags = { + Name = "ExampleAppServerInstance" + } +} +``` + +Initialize your sandbox with: + +``` shell +lcl$ terraform init + +Initializing the backend... + +Initializing provider plugins... +- Finding hashicorp/aws versions matching "~> 3.27"... +- Installing hashicorp/aws v3.27.0... +- Installed hashicorp/aws v3.27.0 (signed by HashiCorp) + +Terraform has created a lock file .terraform.lock.hcl to record the provider +selections it made above. Include this file in your version control repository so +that Terraform can guarantee to make the same selections by default when you run +"terraform init" in the future. + +Terraform has been successfully initialized! +... +``` + +Have a look inside the newly created sub-directory +`~/terraform/AWS/.terraform/`, you'll find the required `aws` provider module +that has been downloaded during the initialization. + +It's good practice to format and validate your configuration: + +``` shell +lcl$ terraform fmt +main.tf +lcl$ terraform validate +Success! The configuration is valid. +``` + +### Task #3: deploy your AWS infrastructure ### + +**Goal:** provision your AWS EC2 instance via TF. + +Run the following command, confirm by typing "yes" and observe its output: + +``` shell +lcl$ terraform apply + +Terraform used the selected providers to generate the following execution plan. +Resource actions are indicated with the following symbols: + + create + +Terraform will perform the following actions: + + # aws_instance.app_server will be created + + resource "aws_instance" "app_server" { + + ami = "ami-0fa37863afb290840" + + arn = (known after apply) + ... + + instance_type = "t2.micro" + ... + + tags = { + + "Name" = "ExampleAppServerInstance" + } + ... + +Plan: 1 to add, 0 to change, 0 to destroy. + +Do you want to perform these actions? + Terraform will perform the actions described above. + Only 'yes' will be accepted to approve. + + Enter a value: yes + +aws_instance.app_server: Creating... +... +aws_instance.app_server: Creation complete after 38s [id=i-0155ba9d77ee0a854] + +Apply complete! Resources: 1 added, 0 changed, 0 destroyed. +``` + +The information shown above before the prompt for action is the `execution +plan`: the `+` prefix mark things to add. Of course, many details are unknown +until the corresponding resource is instantiated. + +:question: How many resources were created? + +You can verify via the AWS dashboard that one EC2 instance has been created. + +The state of the resources acted upon is locally stored. Let's see what's in +our sandbox: +``` shell +lcl$ tree -a +. +├── .terraform +│ └── providers +... +├── .terraform.lock.hcl +├── main.tf +└── terraform.tfstate +``` + +:question: What's in file `terraform.tfstate`? The answer comes from the +following commands: + +``` shell +lcl$ terraform state list +aws_instance.app_server +``` +It confirms that we're tracking one AWS instance. Let's dig a bit more: + +``` shell +lcl$ terraform show +# aws_instance.app_server: +resource "aws_instance" "app_server" { + ami = "ami-0fa37863afb290840" + arn = "arn:aws:ec2:us-east-1:768034348959:instance/i-0155ba9d77ee0a854" + associate_public_ip_address = true + availability_zone = "us-east-1e" + ... + id = "i-0155ba9d77ee0a854" + instance_initiated_shutdown_behavior = "stop" + instance_state = "running" + instance_type = "t2.micro" + ... + private_dns = "ip-172-31-94-207.ec2.internal" + private_ip = "172.31.94.207" + public_dns = "ec2-3-94-184-169.compute-1.amazonaws.com" + public_ip = "3.94.184.169" + ... + tags = { + "Name" = "ExampleAppServerInstance" + } + ... + vpc_security_group_ids = [ + "sg-0c420780b4f729d3e", + ] + ... +} +``` + +The above command output provides useful runtime (state) information, like the +instance IP's address. Indeed, there is a kind of *digital twin* stored inside +the file `terraform.tfstate`. + +:question: Is that instance accessible via SSH? Give it a try. If not, why? + +Now, stop the running instance (its ID is shown above ;-): + +``` shell +lcl$ aws ec2 stop-instances --instance-ids i-0155ba9d77ee0a854 +``` + +wait some seconds and test again: + +``` shell +lcl$ terraform show | grep instance_state + instance_state = "running" +``` + +How come? We just discovered that TF read only the local status of a +resource. So, let's refresh it, and check again: + +``` shell +lcl$ terraform refresh +aws_instance.app_server: Refreshing state... [id=i-0155ba9d77ee0a854] +lcl$ terraform show | grep instance_state + instance_state = "stopped" +``` + +Ah-ha! + +Hold on a second: our TF plan does not specify the desired status of a +resource. What happens if we reapply the plan? Lets' try: + +``` shell +lcl$ terraform apply -auto-approve +aws_instance.app_server: Refreshing state... [id=i-0155ba9d77ee0a854] + +No changes. Your infrastructure matches the configuration. + +Terraform has compared your real infrastructure against your configuration and found no differences, so no changes are needed. + +Apply complete! Resources: 0 added, 0 changed, 0 destroyed. +lcl$ terraform show | grep instance_state + instance_state = "stopped" +``` + +:warning: Apply was run in `-auto-approve` (non interactive) mode which +assumes "yes" to all questions. Use with care! + +From the above commands' output we see that + * the local state is refreshed before doing anything, + * no changes are applied, and + * huh?... the resource is still stopped. + +:bulb: Concerning the last point above, there is acutally no way with TF to +specify an AWS instances's desired *runtime* state ([a bug is +filed](https://github.com/hashicorp/terraform-provider-aws/issues/22)). Of +course, this issue can be solved with a configuration management tool. + +### Task #4: change your infrastructure ### + +**Goal:** modify the resource created before, and learn how to apply changes +to a Terraform project. + +Restart your managed instance: + +``` shell +lcl$ aws ec2 start-instances --instance-ids i-0155ba9d77ee0a854 +``` + +Refresh TF's view of the world: + +``` shell +lcl$ terraform refresh +aws_instance.app_server: Refreshing state... [id=i-0155ba9d77ee0a854] +lcl$ terraform show | grep instance_state + instance_state = "running" +``` + +Replace the resource's `ami` in `main.tf` with the second one found from the +[catalog query done above](#AMI-query) (or another one available with your +account). Before applying our new plan, let's see what TF thinks of it: + +``` shell +lcl$ terraform plan -out=change-AMI.tfplan +aws_instance.app_server: Refreshing state... [id=i-0155ba9d77ee0a854] + +Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following symbols: +-/+ destroy and then create replacement + +Terraform will perform the following actions: + + # aws_instance.app_server must be replaced +-/+ resource "aws_instance" "app_server" { + ~ ami = "ami-0fa37863afb290840" -> "ami-0e2512bd9da751ea8" # forces replacement + +... + +Plan: 1 to add, 0 to change, 1 to destroy. + +Saved the plan to: change-AMI.tfplan + +To perform exactly these actions, run the following command to apply: + terraform apply "change-AMI.tfplan" +``` + +:bulb: Remarks: + * The change we want to apply is destructive! + * We saved our plan. :question: Why? It is not really necessary in a simple + scenario like ours, however a more complex IaC workflow might require plan + artifacts to be programmatically validated and versioned. + +Apply the saved plan: +``` shell +lcl$ terraform apply change-AMI.tfplan +aws_instance.app_server: Destroying... [id=i-0155ba9d77ee0a854] +... +aws_instance.app_server: Destruction complete after 33s +aws_instance.app_server: Creating... +... +aws_instance.app_server: Creation complete after 48s [id=i-0470db35749548101] +``` + +:bulb: What? Not asking for confirmation? Indeed, a saved plan is intended for +automated workflows! Moreover, a saved plan will come handy for rolling back a +broken infrastructure to the last working setup. + +:question: What if we did not save our plan, and called a plain apply command? +Would the result be the same? + + +### Task #5: input variables ### + +**Goal:** make a TF plan more flexible via input variables. + +Our original plan has all its content hard-coded. Let's make it more flexible +with some input variables stored in a separate `variables.tf` file inside your +TF sandbox: + +``` hcl +variable "instance_name" { + description = "Value of the Name tag for the EC2 instance" + type = string + default = "AnotherAppServerInstance" +} +``` + +Then modify the `main.tf` as follows: + +``` hcl +resource "aws_instance" "app_server" { + ami = "ami-0e2512bd9da751ea8" + instance_type = "t2.micro" + + tags = { +- Name = "ExampleAppServerInstance" ++ Name = var.instance_name + } +} +``` + +Apply the changes: +``` shell +lcl$ terraform apply -auto-approve +aws_instance.app_server: Refreshing state... [id=i-0470db35749548101] +... + + ~ update in-place + +Terraform will perform the following actions: + + # aws_instance.app_server will be updated in-place + ~ resource "aws_instance" "app_server" { + id = "i-0470db35749548101" + ~ tags = { + ~ "Name" = "ExampleAppServerInstance" -> "AnotherAppServerInstance" + } + ~ tags_all = { + ~ "Name" = "ExampleAppServerInstance" -> "AnotherAppServerInstance" + } +... + } + +Plan: 0 to add, 1 to change, 0 to destroy. +... +Apply complete! Resources: 0 added, 1 changed, 0 destroyed. +``` + +:bulb: **Exercise:** input variables can also be passed on the `apply` command +line. Find how to do that with another different value for the variable +`instance_name`. :question: Would this last change be persistent if we rerun a +plain `terraform apply`? + + +### Task #6: queries with outputs ### + +**Goal:** use output values to query a provisioned infrastructure. + +We have seen in the previous tasks that the infrastructure's status can be +displayed via `terraform show`: a rather clumsy way, if you just want to +extract some specific information. A better programmatic way of querying your +infrastructure makes use of "outputs". Put the following in a file called +`~/terraform/AWS/outputs.tf`: + +``` hcl +output "instance_id" { + description = "ID of the EC2 instance" + value = aws_instance.app_server.id +} + +output "instance_public_ip" { + description = "Public IP address of the EC2 instance" + value = aws_instance.app_server.public_ip +} +``` + +We have declared two outputs. As usual with TF, before querying their +associated values, we need to apply the changes: + +``` shell +lcl$ terraform apply -auto-approve +... + +Apply complete! Resources: 0 added, 0 changed, 0 destroyed. + +Outputs: + +instance_id = "i-0470db35749548101" +instance_public_ip = "34.201.252.63" +instance_tags = tomap({ + "Name" = "AnotherAppServerInstance" +}) +``` + +So, we already got the needed information, but, within a workflow, it is more +practical to do something like: + +``` shell +lcl$ terraform output -json instance_tags +{"Name":"AnotherAppServerInstance"} +``` + +:question: What if the `Name` tag is changed outside TF? Try it. + +:question: What must be done to have TF respect that external change? + +:question: How to revert an external change via TF? + + +### Task #7: SSH provisioning with Cloud-Init ### + +**Goal:** use Cloud-Init to provision an SSH access to your TF-managed +instance. + +Did you try to SSH into the instance you created via TF? It cannot work, +because we did not instructed TF about networks, users, keys or anything +else. **This is left entirely to you as an exercise.** You need to: + + 1. Destroy your infrastructure. There's a special TF command for that. + 1. Create an SSH key pair `tf-cloud-init`. + 1. Create a new cloud-init file + `~/terraform/AWS/scripts/add-ssh.yaml` with the following content: + ``` yaml + #cloud-config + #^^^^^^^^^^^^ + # DO NOT TOUCH the first line! + --- + groups: + - ubuntu: [root, sys] + - terraform + + users: + - default + - name: terraform + gecos: terraform + primary_group: terraform + groups: users, admin + ssh_authorized_keys: + - <your-SSH-pub-key-on-one-line> + ``` + :warning: **Mind that the first line of this file must spell exactly + `#cloud-config`**! + 1. Modify the `main.tf` as follows: + 1. add a `resource` block of type `"aws_security_group"` allowing ingress + ports 22 and 80 from any address, with any egress port open; + 1. add a `data` block referencing the above authorization file as a + `"template_file"` type; + 1. extend the `"aws_instance"` resource to: + 1. associate a public IP address, + 1. link the `data` block to a user data attribute; + 1. add an output `"public_ip"`. + +When done, *init* your new plan, *validate* and *apply* it. Verify that you +can SSH as user `terraform` (not the customary `ubuntu`) into your instance: + +``` shell +lcl$ ssh terraform@$(terraform output -raw instance_public_ip) -i ../tf-cloud-init +``` diff --git a/OpenStack/main.tf b/OpenStack/main.tf deleted file mode 120000 index 3a0d56a..0000000 --- a/OpenStack/main.tf +++ /dev/null @@ -1 +0,0 @@ -main.tf.advnc \ No newline at end of file diff --git a/README-OpenStack.md b/README-OpenStack.md deleted file mode 100644 index c262cac..0000000 --- a/README-OpenStack.md +++ /dev/null @@ -1,123 +0,0 @@ -## Lab: Cloud provisioning/orchestration - Terraform and OpenStack - -Lab template for a Cloud provisioning/orchestration exercise with Terraform -(TF) and OpenStack/SwitchEngines. - -## Pedagogical objectives ## - - * Become familiar with a Cloud provisioning/orchestration tool - * Provision Cloud resources in an automated fashion - -## Tasks ## - -In this lab you will perform a number of tasks and document your progress in a -lab report. Each task specifies one or more deliverables to be -produced. Collect all the deliverables in your lab report. - -**N.B.** Some tasks require interacting with your local machine's OS: any -related commands are supposed to be run into a terminal with the following -conventions about the *command line prompt*: - - * `#`: execution with super user's (root) privileges - * `$`: execution with normal user's privileges - * `lcl`: your local machine - * `ins`: your VM instance - -TF CLI commands' output follow a diff-style convention of prefixing lines with -special marks to explain what is (or would be) going on: - * `+`: something is added - * `-`: something is removed/destroyed - * `-/+`: a resource is destroyed and recreated - * `~`: something is modified in place - - -### Task #1: install Terraform CLI and OpenStack CLI ### - -**Goal:** install the Terraform CLI and OpenStack CLI on your local machine. -Please, refer to your OS documentation for the proper way to do so - - 1. [Terraform - CLI](https://learn.hashicorp.com/tutorials/terraform/install-cli) - v1.1.4. Skip the TF "Quick start tutorial" (Docker). - 1. [OpenStack CLI](https://docs.openstack.org/newton/user-guide/common/cli-install-openstack-command-line-clients.html) v5.7.0. - 1. Grab or create a new project in your OpenStack account. The placeholder - used in this exercise is `<your-project-name>` with value `Cloud-MA-IaC`. - 1. Create a new [OpenStack Access - Credentials](https://engines.switch.ch/horizon/identity/application_credentials/) - and save as `~/.config/openstack/clouds.yaml`. With SwitchEngine, the - cloud name to use in this is `engines`. :warning: App credentials might - not work for some commands; [API - credentials](https://engines.switch.ch/horizon/project/api_access/clouds.yaml) - with explicit project name/ID setup might be better. - 1. Verify that your credentials are OK: - ``` shell - lcl$ $ openstack --os-cloud=Cloud-MA-IaC [application] credential list - ``` - -### Task #2: configure TF for OpenStack ### - -**Goal:** instruct TF to handle a single OpenStack instance. - -<a name="image-query"></a>Find out the smallest image to use for a Debian server: - -``` shell -lcl$ openstack --os-cloud=Cloud-MA-IaC image list --limit=10 --public --status=active --sort-column=Size -c ID -c Name -c Size --long -+--------------------------------------+-------------------------------------+-------------+ -| ID | Name | Size | -+--------------------------------------+-------------------------------------+-------------+ -| c6596c8a-b074-4a72-9c8c-411d1cb11113 | Debian Buster 10 (SWITCHengines) | 1537409024 | -... -``` - -:bulb: We use the first ID found for the placeholder `<your-image-ID>`. In -SwitchEngines this is 1.5GB. - -Find out the smallest instance *flavor* that acommodates our Debian image. - - ``` shell - lcl$ openstack --os-cloud=engines flavor list --sort-column=RAM --sort-column=Disk --min-disk=5 --min-ram=1024 --limit=1 --public -+----+----------+------+------+-----------+-------+-----------+ -| ID | Name | RAM | Disk | Ephemeral | VCPUs | Is Public | -+----+----------+------+------+-----------+-------+-----------+ -| 2 | m1.small | 2048 | 20 | 0 | 1 | True | -+----+----------+------+------+-----------+-------+-----------+ - ``` - -:bulb: Our flavor will be `m1.small` for the placeholder `<your-flavor>`. - -Create a "sandbox" directory on your local machine `~/terraform/OpenStack/`. Inside -it, create a file called `main.tf` (written in HCL language), the -infrastructure *definition* file, with the appropriate content to handle: - 1. an instance, - 1. a security group to allow SSH access, - 1. a floating IP in the public pool associated to your instance. - -Also, prepare an `~/terraform/OpenStack/outputs.tf` file with the appropriate -contents to get the instance's public IP address (via `instance_public_ip`). - -Initialize your sandbox with: - -``` shell -lcl$ terraform init -``` - -Format and validate your configuration: - -``` shell -lcl$ terraform fmt -main.tf -lcl$ terraform validate -Success! The configuration is valid. -``` - -Then apply! - -``` shell -lcl$ terraform apply -``` - -Verify that you can SSH as user `debian` into your instance: - -``` shell -lcl$ ssh debian@$(terraform output -raw instance_public_ip) -i ../tf-cloud-init -``` diff --git a/README.md b/README.md index fa08b8a..7927f5d 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# Lab: Cloud provisioning/orchestration - Terraform and AWS +# Lab: Cloud provisioning/orchestration - Terraform Lab with Terraform and any Cloud @@ -10,534 +10,11 @@ Lab template for a Cloud provisioning/orchestration exercise with Terraform * Become familiar with a Cloud provisioning/orchestration tool * Provision Cloud resources in an automated fashion -## Tasks ## +## Cloud providers ## -In this lab you will perform a number of tasks and document your progress in a -lab report. Each task specifies one or more deliverables to be -produced. Collect all the deliverables in your lab report. +This lab has been tested with the following cloud providers: -**N.B.** Some tasks require interacting with your local machine's OS: any -related commands are supposed to be run into a terminal with the following -conventions about the *command line prompt*: - - * `#`: execution with super user's (root) privileges - * `$`: execution with normal user's privileges - * `lcl`: your local machine - * `ins`: your VM instance - -TF CLI commands' output follow a diff-style convention of prefixing lines with -special marks to explain what is (or would be) going on: - * `+`: something is added - * `-`: something is removed/destroyed - * `-/+`: a resource is destroyed and recreated - * `~`: something is modified in place - - -### Task #1: install Terraform CLI and AWS CLI ### - -**Goal:** install the Terraform CLI and AWS CLI on your local machine. -Please, refer to your OS documentation for the proper way to do so - - 1. [Terraform - CLI](https://learn.hashicorp.com/tutorials/terraform/install-cli) - v1.1.4. Skip the TF "Quick start tutorial" (Docker). - 1. [AWS CLI](https://aws.amazon.com/cli/) v1.22.. - 1. Create a new [AWS Access - Key](https://console.aws.amazon.com/iam/home?#/security_credentials). - 1. Configure the AWS CLI: - ``` shell - lcl$ aws configure - ``` - -The following tasks are based on TF's tutorial [build an example -infrastructure on -AWS](https://learn.hashicorp.com/tutorials/terraform/aws-build). - - -### Task #2: configure TF for AWS ### - -**Goal:** instruct TF to handle a single AWS EC2 instance. - -<a name="AMI-query"></a>Find out which AMI to use for a recent Ubuntu server. -You can query the AMI Catalog via - a. [AWS dashboard](https://console.aws.amazon.com/ec2/v2/home?region=us-east-1#AMICatalog:), searching "Ubuntu", selecting "Quickstart AMIs" and filtering by "Free tier", - b. or with CLI, and get the 2 most recent AMIs (it will not list free-tier ones): - ``` shell - lcl$ aws ec2 describe-images --region us-east-1 \ - --filters "Name=root-device-type,Values=ebs" \ - "Name=name,Values=*ubuntu-jammy-22.04-amd64-server*" \ - "Name=architecture,Values=x86_64" \ - --query "reverse(sort_by(Images, &ImageId))[:2].[ImageId]" --output text - ami-0f65ab0fd913bc7be - ami-0eb45246cba02871b - ``` - -:bulb: In the following task(s), we use the first AMI found for the -placeholder `<your-EC2-AMI-ID>`. - -Create a "sandbox" directory on your local machine `~/terraform/AWS/`. Inside -it, create a file called `main.tf` (written in HCL language), the -infrastructure *definition* file, with the following content: - -``` hcl -terraform { - required_providers { - aws = { - source = "hashicorp/aws" - version = "~> 3.27" - } - } - - required_version = ">= 0.14.9" -} - -provider "aws" { - profile = "default" - region = "us-east-1" -} - -resource "aws_instance" "app_server" { - ami = "<your-EC2-AMI-ID>" - instance_type = "t2.micro" - - tags = { - Name = "ExampleAppServerInstance" - } -} -``` - -Initialize your sandbox with: - -``` shell -lcl$ terraform init - -Initializing the backend... - -Initializing provider plugins... -- Finding hashicorp/aws versions matching "~> 3.27"... -- Installing hashicorp/aws v3.27.0... -- Installed hashicorp/aws v3.27.0 (signed by HashiCorp) - -Terraform has created a lock file .terraform.lock.hcl to record the provider -selections it made above. Include this file in your version control repository so -that Terraform can guarantee to make the same selections by default when you run -"terraform init" in the future. - -Terraform has been successfully initialized! -... -``` - -Have a look inside the newly created sub-directory -`~/terraform/AWS/.terraform/`, you'll find the required `aws` provider module -that has been downloaded during the initialization. - -It's good practice to format and validate your configuration: - -``` shell -lcl$ terraform fmt -main.tf -lcl$ terraform validate -Success! The configuration is valid. -``` - -### Task #3: deploy your AWS infrastructure ### - -**Goal:** provision your AWS EC2 instance via TF. - -Run the following command, confirm by typing "yes" and observe it's output: - -``` shell -lcl$ terraform apply - -Terraform used the selected providers to generate the following execution plan. -Resource actions are indicated with the following symbols: - + create - -Terraform will perform the following actions: - - # aws_instance.app_server will be created - + resource "aws_instance" "app_server" { - + ami = "ami-0fa37863afb290840" - + arn = (known after apply) - ... - + instance_type = "t2.micro" - ... - + tags = { - + "Name" = "ExampleAppServerInstance" - } - ... - -Plan: 1 to add, 0 to change, 0 to destroy. - -Do you want to perform these actions? - Terraform will perform the actions described above. - Only 'yes' will be accepted to approve. - - Enter a value: yes - -aws_instance.app_server: Creating... -... -aws_instance.app_server: Creation complete after 38s [id=i-0155ba9d77ee0a854] - -Apply complete! Resources: 1 added, 0 changed, 0 destroyed. -``` - -The information shown above before the prompt for action is the `execution -plan`: the `+` prefix mark things to add. Of course, many details are unknown -until the corresponding resource is instantiated. - -:question: How many resources were created? - -You can verify via the AWS dashboard that one EC2 instance has been created. - -The state of the resources acted upon is locally stored. Let's see what's in -our sandbox: -``` shell -lcl$ tree -a -. -├── .terraform -│ └── providers -... -├── .terraform.lock.hcl -├── main.tf -└── terraform.tfstate -``` - -:question: What's in file `terraform.tfstate`? The answer comes from the -following commands: - -``` shell -lcl$ terraform state list -aws_instance.app_server -``` -It confirms that we're tracking one AWS instance. Let's dig a bit more: - -``` shell -lcl$ terraform show -# aws_instance.app_server: -resource "aws_instance" "app_server" { - ami = "ami-0fa37863afb290840" - arn = "arn:aws:ec2:us-east-1:768034348959:instance/i-0155ba9d77ee0a854" - associate_public_ip_address = true - availability_zone = "us-east-1e" - ... - id = "i-0155ba9d77ee0a854" - instance_initiated_shutdown_behavior = "stop" - instance_state = "running" - instance_type = "t2.micro" - ... - private_dns = "ip-172-31-94-207.ec2.internal" - private_ip = "172.31.94.207" - public_dns = "ec2-3-94-184-169.compute-1.amazonaws.com" - public_ip = "3.94.184.169" - ... - tags = { - "Name" = "ExampleAppServerInstance" - } - ... - vpc_security_group_ids = [ - "sg-0c420780b4f729d3e", - ] - ... -} -``` - -The above command output provides useful runtime (state) information, like the -instance IP's address. Indeed, there is a kind of *digital twin* stored inside -the file `terraform.tfstate`. - -:question: Is that instance accessible via SSH? Give it a try. If not, why? - -Now, stop the running instance (its ID is shown above ;-): - -``` shell -lcl$ aws ec2 stop-instances --instance-ids i-0155ba9d77ee0a854 -``` - -wait some seconds and test again: - -``` shell -lcl$ terraform show | grep instance_state - instance_state = "running" -``` - -How come? We just discovered that TF read only the local status of a -resource. So, let's refresh it, and check again: - -``` shell -lcl$ terraform refresh -aws_instance.app_server: Refreshing state... [id=i-0155ba9d77ee0a854] -lcl$ terraform show | grep instance_state - instance_state = "stopped" -``` - -Ah-ha! - -Hold on a second: our TF plan does not specify the desired status of a -resource. What happens if we reapply the plan? Lets' try: - -``` shell -lcl$ terraform apply -auto-approve -aws_instance.app_server: Refreshing state... [id=i-0155ba9d77ee0a854] - -No changes. Your infrastructure matches the configuration. - -Terraform has compared your real infrastructure against your configuration and found no differences, so no changes are needed. - -Apply complete! Resources: 0 added, 0 changed, 0 destroyed. -lcl$ terraform show | grep instance_state - instance_state = "stopped" -``` - -:warning: Apply was run in `-auto-approve` (non interactive) mode which -assumes "yes" to all questions. Use with care! - -From the above commands' output we see that - * the local state is refreshed before doing anything, - * no changes are applied, and - * huh?... the resource is still stopped. - -:bulb: Concerning the last point above, there is acutally no way with TF to -specify an AWS instances's desired *runtime* state ([a bug is -filed](https://github.com/hashicorp/terraform-provider-aws/issues/22)). Of -course, this issue can be solved with a configuration management tool. - -### Task #4: change your infrastructure ### - -**Goal:** modify the resource created before, and learn how to apply changes -to a Terraform project. - -Restart your managed instance: - -``` shell -lcl$ aws ec2 start-instances --instance-ids i-0155ba9d77ee0a854 -``` - -Refresh TF's view of the world: - -``` shell -lcl$ terraform refresh -aws_instance.app_server: Refreshing state... [id=i-0155ba9d77ee0a854] -lcl$ terraform show | grep instance_state - instance_state = "running" -``` - -Replace the resource's `ami` in `main.tf` with the second one found from the -[catalog query done above](#AMI-query) (or another one available with your -account). Before applying our new plan, let's see what TF thinks of it: - -``` shell -lcl$ terraform plan -out=change-AMI.tfplan -aws_instance.app_server: Refreshing state... [id=i-0155ba9d77ee0a854] - -Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following symbols: --/+ destroy and then create replacement - -Terraform will perform the following actions: - - # aws_instance.app_server must be replaced --/+ resource "aws_instance" "app_server" { - ~ ami = "ami-0fa37863afb290840" -> "ami-0e2512bd9da751ea8" # forces replacement - -... - -Plan: 1 to add, 0 to change, 1 to destroy. - -Saved the plan to: change-AMI.tfplan - -To perform exactly these actions, run the following command to apply: - terraform apply "change-AMI.tfplan" -``` - -:bulb: Remarks: - * The change we want to apply is destructive! - * We saved our plan. :question: Why? It is not really necessary in a simple - scenario like ours, however a more complex IaC workflow might require plan - artifacts to be programmatically validated and versioned. - -Apply the saved plan: -``` shell -lcl$ terraform apply change-AMI.tfplan -aws_instance.app_server: Destroying... [id=i-0155ba9d77ee0a854] -... -aws_instance.app_server: Destruction complete after 33s -aws_instance.app_server: Creating... -... -aws_instance.app_server: Creation complete after 48s [id=i-0470db35749548101] -``` - -:bulb: What? Not asking for confirmation? Indeed, a saved plan is intended for -automated workflows! Moreover, a saved plan will come handy for rolling back a -broken infrastructure to the last working setup. - -:question: What if we did not save our plan, and called a plain apply command? -Would the result be the same? - - -### Task #5: input variables ### - -**Goal:** make a TF plan more flexible via input variables. - -Our original plan has all its content hard-coded. Let's make it more flexible -with some input variables stored in a separate `variables.tf` file inside your -TF sandbox: - -``` hcl -variable "instance_name" { - description = "Value of the Name tag for the EC2 instance" - type = string - default = "AnotherAppServerInstance" -} -``` - -Then modify the `main.tf` as follows: - -``` hcl -resource "aws_instance" "app_server" { - ami = "ami-0e2512bd9da751ea8" - instance_type = "t2.micro" - - tags = { -- Name = "ExampleAppServerInstance" -+ Name = var.instance_name - } -} -``` - -Apply the changes: -``` shell -lcl$ terraform apply -auto-approve -aws_instance.app_server: Refreshing state... [id=i-0470db35749548101] -... - - ~ update in-place - -Terraform will perform the following actions: - - # aws_instance.app_server will be updated in-place - ~ resource "aws_instance" "app_server" { - id = "i-0470db35749548101" - ~ tags = { - ~ "Name" = "ExampleAppServerInstance" -> "AnotherAppServerInstance" - } - ~ tags_all = { - ~ "Name" = "ExampleAppServerInstance" -> "AnotherAppServerInstance" - } -... - } - -Plan: 0 to add, 1 to change, 0 to destroy. -... -Apply complete! Resources: 0 added, 1 changed, 0 destroyed. -``` - -:bulb: **Exercise:** input variables can also be passed on the `apply` command -line. Find how to do that with another different value for the variable -`instance_name`. :question: Would this last change be persistent if we rerun a -plain `terraform apply`? - - -### Task #6: queries with outputs ### - -**Goal:** use output values to query a provisioned infrastructure. - -We have seen in the previous tasks that the infrastructure's status can be -displayed via `terraform show`: a rather clumsy way, if you just want to -extract some specific information. A better programmatic way of querying your -infrastructure makes use of "outputs". Put the following in a file called -`~/terraform/AWS/outputs.tf`: - -``` hcl -output "instance_id" { - description = "ID of the EC2 instance" - value = aws_instance.app_server.id -} - -output "instance_public_ip" { - description = "Public IP address of the EC2 instance" - value = aws_instance.app_server.public_ip -} -``` - -We have declared two outputs. As usual with TF, before querying their -associated values, we need to apply the changes: - -``` shell -lcl$ terraform apply -auto-approve -... - -Apply complete! Resources: 0 added, 0 changed, 0 destroyed. - -Outputs: - -instance_id = "i-0470db35749548101" -instance_public_ip = "34.201.252.63" -instance_tags = tomap({ - "Name" = "AnotherAppServerInstance" -}) -``` - -So, we already got the needed information, but, within a workflow, it is more -practical to do something like: - -``` shell -lcl$ terraform output -json instance_tags -{"Name":"AnotherAppServerInstance"} -``` - -:question: What if the `Name` tag is changed outside TF? Try it. - -:question: What must be done to have TF respect that external change? - -:question: How to revert an external change via TF? - - -### Task #7: SSH provisioning with Cloud-Init ### - -**Goal:** use Cloud-Init to provision an SSH access to your TF-managed -instance. - -Did you try to SSH into the instance you created via TF? It cannot work, -because we did not instructed TF about networks, users, keys or anything -else. **This is left entirely to you as an exercise.** You need to: - - 1. Destroy your infrastructure. There's a special TF command for that. - 1. Create an SSH key pair `tf-cloud-init`. - 1. Create a new cloud-init file - `~/terraform/AWS/scripts/add-ssh.yaml` with the following content: - ``` yaml - #cloud-config - #^^^^^^^^^^^^ - # DO NOT TOUCH the first line! - --- - groups: - - ubuntu: [root, sys] - - terraform - - users: - - default - - name: terraform - gecos: terraform - primary_group: terraform - groups: users, admin - ssh_authorized_keys: - - <your-SSH-pub-key-on-one-line> - ``` - :warning: **Mind that the first line of this file must spell exactly - `#cloud-config`**! - 1. Modify the `main.tf` as follows: - 1. add a `resource` block of type `"aws_security_group"` allowing ingress - ports 22 and 80 from any address, with any egress port open; - 1. add a `data` block referencing the above authorization file as a - `"template_file"` type; - 1. extend the `"aws_instance"` resource to: - 1. associate a public IP address, - 1. link the `data` block to a user data attribute; - 1. add an output `"public_ip"`. - -When done, *init* your new plan, *validate* and *apply* it. Verify that you -can SSH as user `terraform` (not the customary `ubuntu`) into your instance: - -``` shell -lcl$ ssh terraform@$(terraform output -raw instance_public_ip) -i ../tf-cloud-init -``` +* [Amazon AWS](AWS/README.md "README-AWS.md") +* [Switch Engines (OpenStack)](SwitchEngines/README.md + "README-SwitchEngines.md") :bulb: **this is the reference provider for + 2022/2023** diff --git a/SwitchEngines/README.md b/SwitchEngines/README.md new file mode 100644 index 0000000..a192ad7 --- /dev/null +++ b/SwitchEngines/README.md @@ -0,0 +1,310 @@ +## Lab: Cloud provisioning/orchestration - Terraform and SwitchEngines (OpenStack) + +Lab template for a Cloud provisioning/orchestration exercise with Terraform +(TF) and SwitchEngines (OpenStack). + +## Pedagogical objectives ## + + * Become familiar with a Cloud provisioning/orchestration tool + * Provision Cloud resources in an automated fashion + +## Tasks ## + +In this lab you will perform a number of tasks and document your progress in a +lab report. Each task specifies one or more deliverables to be +produced. Collect all the deliverables in your lab report. + +**N.B.** Some tasks require interacting with your local machine's OS: any +related commands are supposed to be run into a terminal with the following +conventions about the *command line prompt*: + + * `#`: execution with super user's (root) privileges + * `$`: execution with normal user's privileges + * `lcl`: your local machine + * `ins`: your VM instance + +TF CLI commands' output follow a diff-style convention of prefixing lines with +special marks to explain what is (or would be) going on: + * `+`: something is added + * `-`: something is removed/destroyed + * `-/+`: a resource is destroyed and recreated + * `~`: something is modified in place + + +### Task #1: install Terraform CLI and OpenStack CLI ### + +**Goal:** install the Terraform CLI and OpenStack CLI on your local machine. +Please, refer to your OS documentation for the proper way to do so + + 1. [Terraform + CLI](https://learn.hashicorp.com/tutorials/terraform/install-cli) + v1.1.4. Skip the TF "Quick start tutorial" (Docker). + 1. [OpenStack + CLI](https://docs.openstack.org/newton/user-guide/common/cli-install-openstack-command-line-clients.html) + version >= 5.7.0. It is recommended to install your original distribution + package named like `python-openstackclient`. + 1. Grab or create a new project in your OpenStack account. The placeholder + used in this exercise is `<your-project-name>` with value `Cloud-MA-IaC`. + 1. On the OpenStack Horizon dashboard, + 1. create new [Application + Credentials](https://engines.switch.ch/horizon/identity/application_credentials/) + and save it as `~/.config/openstack/clouds.yaml`. With SwitchEngines, the + cloud name to use for this is `engines`. :warning: App credentials might + not work for some commands. A template is also available in repo file + [`conf/clouds.yaml.api_cred`](conf/clouds.yaml.api_cred). Once created, + 1. alternatively, you can use your [API + credentials](https://engines.switch.ch/horizon/project/api_access/clouds.yaml) + with explicit project name/ID -- you'll have to add your `password` from + your profile page's ["Credentials" + tab](https://engines.admin.switch.ch/users/profile). A template is + available in repo file + [`conf/clouds.yaml.app_cred`](conf/clouds.yaml.app_cred); + 1. Verify that your credentials are OK (:warning: it will reveal secrets!): + ``` shell + lcl$ $ openstack --os-cloud=engines [application] credential list + ``` + +### Task #2: configure TF for OpenStack ### + +**Goal:** instruct TF to handle a single OpenStack instance. + +<a name="image-query"></a>Find out the smallest image to use for a Debian server: + +``` shell +lcl$ openstack --os-cloud=engines image list --public --status=active --sort-column=Size -c ID -c Name -c Size --long ++--------------------------------------+-------------------------------------+-------------+ +| ID | Name | Size | ++--------------------------------------+-------------------------------------+-------------+ +| 8674f1a5-f7d9-4975-af0b-d2e9e33c9152 | Debian Buster 10 (SWITCHengines) | 1537409024 | +... +``` + +:bulb: We use the first ID found for the placeholder `<your-image-ID>`. In +SwitchEngines this is 1.5GB. + +Find out the smallest instance *flavor* that acommodates our Debian image. + + ``` shell + lcl$ openstack --os-cloud=Cloud-MA-IaC flavor list --sort-column=RAM --sort-column=Disk --min-disk=5 --min-ram=1024 --limit=1 --public ++----+----------+------+------+-----------+-------+-----------+ +| ID | Name | RAM | Disk | Ephemeral | VCPUs | Is Public | ++----+----------+------+------+-----------+-------+-----------+ +| 2 | m1.small | 2048 | 20 | 0 | 1 | True | ++----+----------+------+------+-----------+-------+-----------+ + ``` + +:bulb: Our flavor will be `m1.small` for the placeholder `<your-flavor>`. + +Create a "sandbox" directory on your local machine +`~/terraform/OpenStack/`. Inside it, create a file called `main.tf` (written +in HCL language), the infrastructure *definition* file, with the following +content (replace all `<...>` tokens with actual values): + +``` hcl +terraform { + required_version = ">= 0.14.9" + required_providers { + openstack = { + source = "terraform-provider-openstack/openstack" + version = "~> 1.48.0" + } + } +} + +provider "openstack" { + auth_url = "https://keystone.cloud.switch.ch:5000/v3" + project_domain_id = "<your-project-ID>" + application_credential_id = "<your-app-cred-ID>" + application_credential_secret = "<your-app-cred-secret>" + region = "ZH" +} + +resource "openstack_compute_instance_v2" "app_server" { + name = "TF-managed" + image_id = "<your-image-ID>" + flavor_name = "<your-flavor>" +} +``` +Initialize your sandbox with: + +``` shell +lcl$ terraform init + +Initializing the backend... + +Initializing provider plugins... +- Finding terraform-provider-openstack/openstack versions matching "~> 1.48.0"... +- Installing terraform-provider-openstack/openstack v1.48.0... +- Installed terraform-provider-openstack/openstack v1.48.0 (self-signed, key ID 4F80527A391BEFD2) + +Partner and community providers are signed by their developers. +If you'd like to know more about provider signing, you can read about it here: +https://www.terraform.io/docs/cli/plugins/signing.html + +Terraform has created a lock file .terraform.lock.hcl to record the provider +selections it made above. Include this file in your version control repository +so that Terraform can guarantee to make the same selections by default when +you run "terraform init" in the future. + +Terraform has been successfully initialized! +... +``` + +Have a look inside the newly created sub-directory +`~/terraform/OpenStack/.terraform/`, you'll find the required `openstack` +provider module that has been downloaded during the initialization. + +It's good practice to format and validate your configuration: + +``` shell +lcl$ terraform fmt +main.tf +lcl$ terraform validate +Success! The configuration is valid. +``` + +### Task #3: deploy your OpenStack infrastructure ### + +**Goal:** provision your OpenStack instance via TF. + +So far, our plan has been validated but not executed yet. You can either +prepare your plan for later execution or apply it directly. Let's see what would be done: +``` shell +lcl$ terraform plan +Terraform used the selected providers to generate the following execution plan. +Resource actions are indicated with the following symbols: + + create + +Terraform will perform the following actions: + + # openstack_compute_instance_v2.app_server will be created + + resource "openstack_compute_instance_v2" "app_server" { + + access_ip_v4 = (known after apply) + ... + + flavor_name = "m1.small" + + force_delete = false + + id = (known after apply) + + image_id = "8674f1a5-f7d9-4975-af0b-d2e9e33c9152" + + image_name = (known after apply) + + name = "TF-managed" + ... + + + network { + + access_network = (known after apply) + + fixed_ip_v4 = (known after apply) + ... + } + } + +Plan: 1 to add, 0 to change, 0 to destroy. + +────────────────────────────────────────────────────────────────────────────── + +Note: You didn't use the -out option to save this plan, so Terraform can't +guarantee to take exactly these actions if you run "terraform apply" now +``` + +In the command output above, notice the `+` prefix that marks things to +*add*. Of course, many details are unknown until the corresponding resource is +instantiated. + +:question: How many resources would be created? + +If it looks OK, then run the following command, confirm by typing "yes": + +``` shell +lcl$ terraform apply +... +Plan: 1 to add, 0 to change, 0 to destroy. + +Do you want to perform these actions? + Terraform will perform the actions described above. + Only 'yes' will be accepted to approve. + + Enter a value: yes + +openstack_compute_instance_v2.app_server: Creating... +openstack_compute_instance_v2.app_server: Still creating... [10s elapsed] +openstack_compute_instance_v2.app_server: Creation complete after 18s [id=f70aef53-51f9-4d12-a4a9-fe9a6cc5a58f] + +Apply complete! Resources: 1 added, 0 changed, 0 destroyed. +``` + +You can verify via the SwitchEngine dashboard that one instance named +"TF-managed" has indeed been created. + +The state of the resources acted upon is locally stored. Let's see what's in +our sandbox: +``` shell +lcl$ tree -a +. +├── .terraform +│ └── providers +... +├── .terraform.lock.hcl +├── main.tf +└── terraform.tfstate +``` + +:question: What's in file `terraform.tfstate`? The answer comes from the +following commands: + +``` shell +lcl$ terraform state list +openstack_compute_instance_v2.app_server +``` +It confirms that we're tracking one OpenStack instance. Let's dig a bit more: +``` shell +lcl$ terraform show +# openstack_compute_instance_v2.app_server: +resource "openstack_compute_instance_v2" "app_server" { + access_ip_v4 = "10.0.8.116" + ... + flavor_name = "m1.small" + ... + id = "f70aef53-51f9-4d12-a4a9-fe9a6cc5a58f" + image_id = "8674f1a5-f7d9-4975-af0b-d2e9e33c9152" + image_name = "Debian Buster 10 (SWITCHengines)" + name = "TF-managed" + power_state = "active" + region = "ZH" + security_groups = [ + "default", + ] + stop_before_destroy = false + + network { + ... + } +} +``` + +The above command output provides useful runtime (state) information, like the +instance IP's address. Indeed, there is a kind of *digital twin* stored inside +the file `terraform.tfstate`. + +:question: Is that instance accessible from the internet? Give it a try. If +not, why? + +Indeed, the instance doesn't have a (floating) *public* IP address, so we need +to associate one: + + +@@@@@ OLD part below@@@@ + +Also, prepare a `~/terraform/OpenStack/outputs.tf` file with the appropriate +contents to get the instance's public IP address (via `instance_public_ip`). + + + +Then apply! + +``` shell +lcl$ terraform apply +``` + +Verify that you can SSH as user `debian` into your instance: + +``` shell +lcl$ ssh debian@$(terraform output -raw instance_public_ip) -i ../tf-cloud-init +``` diff --git a/OpenStack/conf/clouds.yaml.api_cred b/SwitchEngines/conf/clouds.yaml.api_cred similarity index 100% rename from OpenStack/conf/clouds.yaml.api_cred rename to SwitchEngines/conf/clouds.yaml.api_cred diff --git a/OpenStack/conf/clouds.yaml.app_cred b/SwitchEngines/conf/clouds.yaml.app_cred similarity index 100% rename from OpenStack/conf/clouds.yaml.app_cred rename to SwitchEngines/conf/clouds.yaml.app_cred diff --git a/SwitchEngines/main.tf b/SwitchEngines/main.tf new file mode 120000 index 0000000..3dc4ae1 --- /dev/null +++ b/SwitchEngines/main.tf @@ -0,0 +1 @@ +main.tf.basic \ No newline at end of file diff --git a/OpenStack/main.tf.advnc b/SwitchEngines/main.tf.advnc similarity index 100% rename from OpenStack/main.tf.advnc rename to SwitchEngines/main.tf.advnc diff --git a/SwitchEngines/main.tf.basic b/SwitchEngines/main.tf.basic new file mode 100644 index 0000000..3bcab00 --- /dev/null +++ b/SwitchEngines/main.tf.basic @@ -0,0 +1,52 @@ +terraform { + required_version = ">= 0.14.9" + required_providers { + openstack = { + source = "terraform-provider-openstack/openstack" + # version = "~> 1.35.0" + version = "~> 1.48.0" + } + } +} + +# Configure the OpenStack Provider +provider "openstack" { + auth_url = "https://keystone.cloud.switch.ch:5000/v3" + project_domain_id = "<your-project-ID>" + application_credential_id = "<your-app-cred-ID>" + application_credential_secret = "<your-app-cred-secret>" + region = "LS" +} + +resource "openstack_compute_instance_v2" "app_server" { + name = "TF-managed" + image_id = "<your-image-ID>" + flavor_name = "<your-flavor>" + key_pair = "TF_lab" + security_groups = ["default", "secgroup_tf"] +} + +resource "openstack_networking_secgroup_v2" "secgroup_tf" { + name = "secgroup_tf" +} + +resource "openstack_networking_secgroup_rule_v2" "secgroup_rule_1" { + direction = "ingress" + ethertype = "IPv4" + protocol = "tcp" + port_range_min = 22 + port_range_max = 22 + remote_ip_prefix = "0.0.0.0/0" + security_group_id = "${openstack_networking_secgroup_v2.secgroup_tf.id}" +} + +resource "openstack_networking_floatingip_v2" "fip_1" { + pool = "public" +} + +resource "openstack_compute_floatingip_associate_v2" "fip_1" { + floating_ip = "${openstack_networking_floatingip_v2.fip_1.address}" + instance_id = "${openstack_compute_instance_v2.app_server.id}" + # to avoid getting "Resource not found" + wait_until_associated = true +} diff --git a/OpenStack/outputs.tf b/SwitchEngines/outputs.tf similarity index 100% rename from OpenStack/outputs.tf rename to SwitchEngines/outputs.tf -- GitLab