diff --git a/.gitignore b/.gitignore index 45b4c279..98c44750 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,7 @@ *.tfstate *.tfstate.backup -.terraform -*.iml \ No newline at end of file +*.terraform +*.iml +.idea/ +*.lock +*.lock.hcl diff --git a/Examples/Module-02 Basics/Example-02-01/code/main.tf b/Examples/Module-02 Basics/Example-02-01/code/main.tf new file mode 100755 index 00000000..ae6f7626 --- /dev/null +++ b/Examples/Module-02 Basics/Example-02-01/code/main.tf @@ -0,0 +1,18 @@ + +# Example 02-01 + +resource "aws_instance" "myVM" { + ami = "ami-077e31c4939f6a2f3" + instance_type = "t2.micro" + tags = { + Name = "Example-01" + } +} + +resource "aws_s3_bucket" "myBucket" { + bucket = "terraform-example-02-01" +} + +data "aws_vpc" "default_VPC" { + default = true +} \ No newline at end of file diff --git a/Examples/Module-02 Basics/Example-02-01/code/outputs.tf b/Examples/Module-02 Basics/Example-02-01/code/outputs.tf new file mode 100755 index 00000000..d2ffa316 --- /dev/null +++ b/Examples/Module-02 Basics/Example-02-01/code/outputs.tf @@ -0,0 +1,9 @@ + +output "EC2_public_ip" { + description = "Public IP address of 'myVM" + value = aws_instance.myVM.public_ip +} + +output "VPC_id" { + value = data.aws_vpc.default_VPC.id +} \ No newline at end of file diff --git a/Examples/Module-02 Basics/Example-02-01/code/providers.tf b/Examples/Module-02 Basics/Example-02-01/code/providers.tf new file mode 100755 index 00000000..cfb88ab7 --- /dev/null +++ b/Examples/Module-02 Basics/Example-02-01/code/providers.tf @@ -0,0 +1,19 @@ + +# Example 02-01 - Configuration + +terraform { + required_providers { + aws = { + source = "hashicorp/aws" + version = ">= 3.0" + } + } + # Required version of terraform + required_version = ">0.14" +} + +provider aws { + region = "us-east-2" + profile = "dev" +} + diff --git a/Examples/Module-02 Basics/Example-02-02/code/main.tf b/Examples/Module-02 Basics/Example-02-02/code/main.tf new file mode 100755 index 00000000..8f154406 --- /dev/null +++ b/Examples/Module-02 Basics/Example-02-02/code/main.tf @@ -0,0 +1,11 @@ + +# Example 02-02 + +resource "aws_instance" "myVM" { + ami = var.ami_type + instance_type = var.inst_type + tags = { + Name = "Example-02" + } +} + diff --git a/Examples/Module-02 Basics/Example-02-02/code/outputs.tf b/Examples/Module-02 Basics/Example-02-02/code/outputs.tf new file mode 100755 index 00000000..824768a3 --- /dev/null +++ b/Examples/Module-02 Basics/Example-02-02/code/outputs.tf @@ -0,0 +1,10 @@ + +output "EC2_ami" { + description = "ami type used in myVM" + value = aws_instance.myVM.ami +} + +output "EC2_type" { + description = "instance type used in myVM" + value = aws_instance.myVM.instance_type +} diff --git a/Examples/Module-02 Basics/Example-02-02/code/providers.tf b/Examples/Module-02 Basics/Example-02-02/code/providers.tf new file mode 100755 index 00000000..a55f3b63 --- /dev/null +++ b/Examples/Module-02 Basics/Example-02-02/code/providers.tf @@ -0,0 +1,17 @@ + +terraform { + required_providers { + aws = { + source = "hashicorp/aws" + version = ">= 3.0" + } + } + # Required version of terraform + required_version = ">0.14" +} + +provider aws { + region = "us-east-2" + profile = "dev" +} + diff --git a/Examples/Module-02 Basics/Example-02-02/code/terraform.tfvars b/Examples/Module-02 Basics/Example-02-02/code/terraform.tfvars new file mode 100755 index 00000000..9d69ab61 --- /dev/null +++ b/Examples/Module-02 Basics/Example-02-02/code/terraform.tfvars @@ -0,0 +1 @@ + inst_type = "t2.nano" diff --git a/Examples/Module-02 Basics/Example-02-02/code/variables.tf b/Examples/Module-02 Basics/Example-02-02/code/variables.tf new file mode 100755 index 00000000..d5205b9a --- /dev/null +++ b/Examples/Module-02 Basics/Example-02-02/code/variables.tf @@ -0,0 +1,13 @@ + +variable ami_type { + description = "ami to be used in myVM" + type = string + default = "ami-077e31c4939f6a2f3" + +} + +variable inst_type { + description = "instance type for myVM" + type = string +} + diff --git a/Examples/Module-02 Basics/Example-02-03/code/main.tf b/Examples/Module-02 Basics/Example-02-03/code/main.tf new file mode 100755 index 00000000..a5568633 --- /dev/null +++ b/Examples/Module-02 Basics/Example-02-03/code/main.tf @@ -0,0 +1,10 @@ + +# Example 02-03 + +resource "aws_instance" "myVM" { + ami = var.ami_type + instance_type = var.inst_type + tags = { + Name = "Example-03" + } +} \ No newline at end of file diff --git a/Examples/Module-02 Basics/Example-02-03/code/outputs.tf b/Examples/Module-02 Basics/Example-02-03/code/outputs.tf new file mode 100755 index 00000000..699ce87c --- /dev/null +++ b/Examples/Module-02 Basics/Example-02-03/code/outputs.tf @@ -0,0 +1,10 @@ + +output "EC2_ami" { + description = "ami type used in myVM" + value = aws_instance.myVM.ami +} + +output "EC2_type" { + description = "instance type used in myVM" + value = "Hi, I am a ${aws_instance.myVM.instance_type} instance type" +} \ No newline at end of file diff --git a/Examples/Module-02 Basics/Example-02-03/code/providers.tf b/Examples/Module-02 Basics/Example-02-03/code/providers.tf new file mode 100755 index 00000000..a55f3b63 --- /dev/null +++ b/Examples/Module-02 Basics/Example-02-03/code/providers.tf @@ -0,0 +1,17 @@ + +terraform { + required_providers { + aws = { + source = "hashicorp/aws" + version = ">= 3.0" + } + } + # Required version of terraform + required_version = ">0.14" +} + +provider aws { + region = "us-east-2" + profile = "dev" +} + diff --git a/Examples/Module-02 Basics/Example-02-03/code/terraform.tfvars b/Examples/Module-02 Basics/Example-02-03/code/terraform.tfvars new file mode 100755 index 00000000..9d69ab61 --- /dev/null +++ b/Examples/Module-02 Basics/Example-02-03/code/terraform.tfvars @@ -0,0 +1 @@ + inst_type = "t2.nano" diff --git a/Examples/Module-02 Basics/Example-02-03/code/variables.tf b/Examples/Module-02 Basics/Example-02-03/code/variables.tf new file mode 100755 index 00000000..d5205b9a --- /dev/null +++ b/Examples/Module-02 Basics/Example-02-03/code/variables.tf @@ -0,0 +1,13 @@ + +variable ami_type { + description = "ami to be used in myVM" + type = string + default = "ami-077e31c4939f6a2f3" + +} + +variable inst_type { + description = "instance type for myVM" + type = string +} + diff --git a/Examples/Module-02 Basics/Example-02-04/code/main.tf b/Examples/Module-02 Basics/Example-02-04/code/main.tf new file mode 100755 index 00000000..d0532a81 --- /dev/null +++ b/Examples/Module-02 Basics/Example-02-04/code/main.tf @@ -0,0 +1,14 @@ + +# Example 02-04 + +locals { + name = "example 04" +} + +resource "aws_instance" "myVM" { + ami = var.ami_type + instance_type = var.inst_type + tags = { + Name = local.name + } +} \ No newline at end of file diff --git a/Examples/Module-02 Basics/Example-02-04/code/outputs.tf b/Examples/Module-02 Basics/Example-02-04/code/outputs.tf new file mode 100755 index 00000000..699ce87c --- /dev/null +++ b/Examples/Module-02 Basics/Example-02-04/code/outputs.tf @@ -0,0 +1,10 @@ + +output "EC2_ami" { + description = "ami type used in myVM" + value = aws_instance.myVM.ami +} + +output "EC2_type" { + description = "instance type used in myVM" + value = "Hi, I am a ${aws_instance.myVM.instance_type} instance type" +} \ No newline at end of file diff --git a/Examples/Module-02 Basics/Example-02-04/code/providers.tf b/Examples/Module-02 Basics/Example-02-04/code/providers.tf new file mode 100755 index 00000000..a55f3b63 --- /dev/null +++ b/Examples/Module-02 Basics/Example-02-04/code/providers.tf @@ -0,0 +1,17 @@ + +terraform { + required_providers { + aws = { + source = "hashicorp/aws" + version = ">= 3.0" + } + } + # Required version of terraform + required_version = ">0.14" +} + +provider aws { + region = "us-east-2" + profile = "dev" +} + diff --git a/Examples/Module-02 Basics/Example-02-04/code/terraform.tfvars b/Examples/Module-02 Basics/Example-02-04/code/terraform.tfvars new file mode 100755 index 00000000..9d69ab61 --- /dev/null +++ b/Examples/Module-02 Basics/Example-02-04/code/terraform.tfvars @@ -0,0 +1 @@ + inst_type = "t2.nano" diff --git a/Examples/Module-02 Basics/Example-02-04/code/variables.tf b/Examples/Module-02 Basics/Example-02-04/code/variables.tf new file mode 100755 index 00000000..d5205b9a --- /dev/null +++ b/Examples/Module-02 Basics/Example-02-04/code/variables.tf @@ -0,0 +1,13 @@ + +variable ami_type { + description = "ami to be used in myVM" + type = string + default = "ami-077e31c4939f6a2f3" + +} + +variable inst_type { + description = "instance type for myVM" + type = string +} + diff --git a/Examples/Module-02 Basics/Example-02-05/README.md b/Examples/Module-02 Basics/Example-02-05/README.md new file mode 100644 index 00000000..2309acf0 --- /dev/null +++ b/Examples/Module-02 Basics/Example-02-05/README.md @@ -0,0 +1,5 @@ +# Example-02-05 + +### New elements +* MYSRT +* Variable of `number` type \ No newline at end of file diff --git a/Examples/Module-02 Basics/Example-02-05/code/main.tf b/Examples/Module-02 Basics/Example-02-05/code/main.tf new file mode 100755 index 00000000..4d1651ff --- /dev/null +++ b/Examples/Module-02 Basics/Example-02-05/code/main.tf @@ -0,0 +1,23 @@ + +# Example 02-05 + + +locals { + + message = <<-MYSRT + this is a multi line string + that goes on and one and on + MYSRT + + name = "Example 2-5" +} + + +resource "aws_instance" "myVM" { + ami = var.ami_type + instance_type = var.inst_type + tags = { + Name = local.name + + } +} diff --git a/Examples/Module-02 Basics/Example-02-05/code/outputs.tf b/Examples/Module-02 Basics/Example-02-05/code/outputs.tf new file mode 100755 index 00000000..d33f0225 --- /dev/null +++ b/Examples/Module-02 Basics/Example-02-05/code/outputs.tf @@ -0,0 +1,19 @@ + +output "EC2_ami" { + description = "ami type used in myVM" + value = aws_instance.myVM.ami +} + +output "EC2_type" { + description = "instance type used in myVM" + value = "Hi, I am a ${aws_instance.myVM.instance_type} instance type" +} + +output "Message" { + value = local.message +} + +output "Port" { + description = "Experiment with a number variable" + value = var.port +} \ No newline at end of file diff --git a/Examples/Module-02 Basics/Example-02-05/code/providers.tf b/Examples/Module-02 Basics/Example-02-05/code/providers.tf new file mode 100755 index 00000000..a55f3b63 --- /dev/null +++ b/Examples/Module-02 Basics/Example-02-05/code/providers.tf @@ -0,0 +1,17 @@ + +terraform { + required_providers { + aws = { + source = "hashicorp/aws" + version = ">= 3.0" + } + } + # Required version of terraform + required_version = ">0.14" +} + +provider aws { + region = "us-east-2" + profile = "dev" +} + diff --git a/Examples/Module-02 Basics/Example-02-05/code/terraform.tfvars b/Examples/Module-02 Basics/Example-02-05/code/terraform.tfvars new file mode 100755 index 00000000..8d127d41 --- /dev/null +++ b/Examples/Module-02 Basics/Example-02-05/code/terraform.tfvars @@ -0,0 +1 @@ +inst_type = "t2.nano" diff --git a/Examples/Module-02 Basics/Example-02-05/code/variables.tf b/Examples/Module-02 Basics/Example-02-05/code/variables.tf new file mode 100755 index 00000000..826aa726 --- /dev/null +++ b/Examples/Module-02 Basics/Example-02-05/code/variables.tf @@ -0,0 +1,20 @@ + +variable ami_type { + description = "ami to be used in myVM" + type = string + default = "ami-077e31c4939f6a2f3" + +} + +variable inst_type { + description = "instance type for myVM" + type = string +} + +variable port { + description = "port number" + type = number + default = 8080 +} + + diff --git a/Examples/Module-02 Basics/Example-02-06/README.md b/Examples/Module-02 Basics/Example-02-06/README.md new file mode 100644 index 00000000..7fa210dc --- /dev/null +++ b/Examples/Module-02 Basics/Example-02-06/README.md @@ -0,0 +1,4 @@ +# Example 02-06 + +### Reading variables from a file +* See `main.tf` \ No newline at end of file diff --git a/Examples/Module-02 Basics/Example-02-06/code/main.tf b/Examples/Module-02 Basics/Example-02-06/code/main.tf new file mode 100755 index 00000000..7ffcb340 --- /dev/null +++ b/Examples/Module-02 Basics/Example-02-06/code/main.tf @@ -0,0 +1,15 @@ + +# Example 02-06 + +locals { + name = file("name.txt") + +} + +resource "aws_instance" "myVM" { + ami = var.ami_type + instance_type = var.inst_type + tags = { + Name = local.name + } +} diff --git a/Examples/Module-02 Basics/Example-02-06/code/name.txt b/Examples/Module-02 Basics/Example-02-06/code/name.txt new file mode 100755 index 00000000..49c3a683 --- /dev/null +++ b/Examples/Module-02 Basics/Example-02-06/code/name.txt @@ -0,0 +1 @@ +Example-06 \ No newline at end of file diff --git a/Examples/Module-02 Basics/Example-02-06/code/outputs.tf b/Examples/Module-02 Basics/Example-02-06/code/outputs.tf new file mode 100755 index 00000000..6ca199f8 --- /dev/null +++ b/Examples/Module-02 Basics/Example-02-06/code/outputs.tf @@ -0,0 +1,10 @@ + +output "EC2_ami" { + description = "ami type used in myVM" + value = aws_instance.myVM.ami +} + +output "EC2_type" { + description = "instance type used in myVM" + value = "Hi, my name is ${local.name}" +} \ No newline at end of file diff --git a/Examples/Module-02 Basics/Example-02-06/code/providers.tf b/Examples/Module-02 Basics/Example-02-06/code/providers.tf new file mode 100755 index 00000000..3a2e91ec --- /dev/null +++ b/Examples/Module-02 Basics/Example-02-06/code/providers.tf @@ -0,0 +1,19 @@ + +# Example 02-02 - Configuration + +terraform { + required_providers { + aws = { + source = "hashicorp/aws" + version = ">= 3.0" + } + } + # Required version of terraform + required_version = ">0.14" +} + +provider aws { + region = "us-east-2" + profile = "dev" +} + diff --git a/Examples/Module-02 Basics/Example-02-06/code/terraform.tfvars b/Examples/Module-02 Basics/Example-02-06/code/terraform.tfvars new file mode 100755 index 00000000..9d69ab61 --- /dev/null +++ b/Examples/Module-02 Basics/Example-02-06/code/terraform.tfvars @@ -0,0 +1 @@ + inst_type = "t2.nano" diff --git a/Examples/Module-02 Basics/Example-02-06/code/variables.tf b/Examples/Module-02 Basics/Example-02-06/code/variables.tf new file mode 100755 index 00000000..d5205b9a --- /dev/null +++ b/Examples/Module-02 Basics/Example-02-06/code/variables.tf @@ -0,0 +1,13 @@ + +variable ami_type { + description = "ami to be used in myVM" + type = string + default = "ami-077e31c4939f6a2f3" + +} + +variable inst_type { + description = "instance type for myVM" + type = string +} + diff --git a/Examples/Module-02 Basics/Example-02-07/README.md b/Examples/Module-02 Basics/Example-02-07/README.md new file mode 100644 index 00000000..a909ae46 --- /dev/null +++ b/Examples/Module-02 Basics/Example-02-07/README.md @@ -0,0 +1,4 @@ +# Example-02-07 + +### Template files +* See `main.tf` \ No newline at end of file diff --git a/Examples/Module-02 Basics/Example-02-07/code/document.txt b/Examples/Module-02 Basics/Example-02-07/code/document.txt new file mode 100755 index 00000000..e9e77ff1 --- /dev/null +++ b/Examples/Module-02 Basics/Example-02-07/code/document.txt @@ -0,0 +1,2 @@ + +This code was modified by ${myname} \ No newline at end of file diff --git a/Examples/Module-02 Basics/Example-02-07/code/main.tf b/Examples/Module-02 Basics/Example-02-07/code/main.tf new file mode 100755 index 00000000..1daace2c --- /dev/null +++ b/Examples/Module-02 Basics/Example-02-07/code/main.tf @@ -0,0 +1,15 @@ + +# Example 02-07 + +locals { + developer = "Zippy" + documentation = templatefile("document.txt", {myname = local.developer}) +} + +resource "aws_instance" "myVM" { + ami = var.ami_type + instance_type = var.inst_type + tags = { + Name = "${local.developer}'s machine" + } +} diff --git a/Examples/Module-02 Basics/Example-02-07/code/outputs.tf b/Examples/Module-02 Basics/Example-02-07/code/outputs.tf new file mode 100755 index 00000000..763d4d92 --- /dev/null +++ b/Examples/Module-02 Basics/Example-02-07/code/outputs.tf @@ -0,0 +1,8 @@ + +output "Documentation" { + description = "Developer who worked on this" + value = local.documentation +} + + + diff --git a/Examples/Module-02 Basics/Example-02-07/code/providers.tf b/Examples/Module-02 Basics/Example-02-07/code/providers.tf new file mode 100755 index 00000000..4ea16b73 --- /dev/null +++ b/Examples/Module-02 Basics/Example-02-07/code/providers.tf @@ -0,0 +1,18 @@ + + +terraform { + required_providers { + aws = { + source = "hashicorp/aws" + version = ">= 3.0" + } + } + # Required version of terraform + required_version = ">0.14" +} + +provider aws { + region = "us-east-2" + profile = "dev" +} + diff --git a/Examples/Module-02 Basics/Example-02-07/code/terraform.tfvars b/Examples/Module-02 Basics/Example-02-07/code/terraform.tfvars new file mode 100755 index 00000000..9d69ab61 --- /dev/null +++ b/Examples/Module-02 Basics/Example-02-07/code/terraform.tfvars @@ -0,0 +1 @@ + inst_type = "t2.nano" diff --git a/Examples/Module-02 Basics/Example-02-07/code/variables.tf b/Examples/Module-02 Basics/Example-02-07/code/variables.tf new file mode 100755 index 00000000..d5205b9a --- /dev/null +++ b/Examples/Module-02 Basics/Example-02-07/code/variables.tf @@ -0,0 +1,13 @@ + +variable ami_type { + description = "ami to be used in myVM" + type = string + default = "ami-077e31c4939f6a2f3" + +} + +variable inst_type { + description = "instance type for myVM" + type = string +} + diff --git a/Examples/Module-02 Basics/Example-02-08/README.md b/Examples/Module-02 Basics/Example-02-08/README.md new file mode 100644 index 00000000..1caab698 --- /dev/null +++ b/Examples/Module-02 Basics/Example-02-08/README.md @@ -0,0 +1,4 @@ +# Example-02-08 + +### Data filters +* In `main.tf` \ No newline at end of file diff --git a/Examples/Module-02 Basics/Example-02-08/code/main.tf b/Examples/Module-02 Basics/Example-02-08/code/main.tf new file mode 100755 index 00000000..7c7821e6 --- /dev/null +++ b/Examples/Module-02 Basics/Example-02-08/code/main.tf @@ -0,0 +1,18 @@ + +# Example 02-08 + +data "aws_ami" "ubuntu" { + most_recent = true + + filter { + name = "name" + values = ["ubuntu/images/hvm-ssd/ubuntu-focal-20.04-amd64-server-*"] + } + + filter { + name = "virtualization-type" + values = ["hvm"] + } + + owners = ["099720109477"] # Canonical +} diff --git a/Examples/Module-02 Basics/Example-02-08/code/outputs.tf b/Examples/Module-02 Basics/Example-02-08/code/outputs.tf new file mode 100755 index 00000000..4f2bc140 --- /dev/null +++ b/Examples/Module-02 Basics/Example-02-08/code/outputs.tf @@ -0,0 +1,10 @@ + +output "AMI" { + description = "The Ubuntu AMI" + value = data.aws_ami.ubuntu.id +} + + + + + diff --git a/Examples/Module-02 Basics/Example-02-08/code/providers.tf b/Examples/Module-02 Basics/Example-02-08/code/providers.tf new file mode 100755 index 00000000..4ea16b73 --- /dev/null +++ b/Examples/Module-02 Basics/Example-02-08/code/providers.tf @@ -0,0 +1,18 @@ + + +terraform { + required_providers { + aws = { + source = "hashicorp/aws" + version = ">= 3.0" + } + } + # Required version of terraform + required_version = ">0.14" +} + +provider aws { + region = "us-east-2" + profile = "dev" +} + diff --git a/Examples/Module-02 Basics/Example-02-09/README.md b/Examples/Module-02 Basics/Example-02-09/README.md new file mode 100644 index 00000000..93f7c478 --- /dev/null +++ b/Examples/Module-02 Basics/Example-02-09/README.md @@ -0,0 +1,5 @@ +# Example-02-09 + +### Multiple providers + +* In `providers.tf` \ No newline at end of file diff --git a/Examples/Module-02 Basics/Example-02-09/code/main.tf b/Examples/Module-02 Basics/Example-02-09/code/main.tf new file mode 100755 index 00000000..2340e230 --- /dev/null +++ b/Examples/Module-02 Basics/Example-02-09/code/main.tf @@ -0,0 +1,22 @@ + +# Example 02-09 + +resource "aws_instance" "Ohio" { + ami = "ami-00399ec92321828f5" + instance_type = "t2.micro" + tags = { + Name = "us-east-2" + } +} + +resource "aws_instance" "California" { + provider = aws.California + ami = "ami-0d9858aa3c6322f73" + instance_type = "t2.micro" + tags = { + Name = "us-west-1" + } +} + + + diff --git a/Examples/Module-02 Basics/Example-02-09/code/providers.tf b/Examples/Module-02 Basics/Example-02-09/code/providers.tf new file mode 100755 index 00000000..0551080f --- /dev/null +++ b/Examples/Module-02 Basics/Example-02-09/code/providers.tf @@ -0,0 +1,23 @@ + +terraform { + required_providers { + aws = { + source = "hashicorp/aws" + version = ">= 3.0" + } + } + # Required version of terraform + required_version = ">0.14" +} + +provider aws { + region = "us-east-2" + profile = "dev" +} + +provider aws { + region = "us-west-1" + alias = "California" + profile = "dev" +} + diff --git a/Examples/Module-02 Basics/Examples.md b/Examples/Module-02 Basics/Examples.md new file mode 100644 index 00000000..7abe6d23 --- /dev/null +++ b/Examples/Module-02 Basics/Examples.md @@ -0,0 +1,108 @@ +# Examples Notes + +These notes document how I work with the examples in the Terraform class. + +## Module 2 + +### Example 1 + +This example is basically the code as presented in the slides. My personal preference is to just do the example dynamically so students can see the process. + All the steps are captured in the slides as well. + +#### Example workflow +1. Discuss the code +2. Run the init command + - show the .terraform directory and discuss what happened to create it +3. Run the plan command + - show the state file - explain where it came from + - review the plan output + - check the AWS console to show there are no resources +4. Run apply + - walk through the output including the output variables + - check the AWS console to show the resources now exist +5. Run destroy + - walk through the output of the command + - check the AWS console to show the resources no longer exist + +#### Lab 2-1 + +This lab will essentially be a recap of the example. + +--- +### Example 2 + +Demonstrates the use of variables by modifying the code of example 1 + +#### Example workflow + +1. Explain contents of the variables file. The AMI variable has a default, but the instance type does not. +2. Run the code as is and show the variable for AMI is incorporated, but you are prompted for the value of the instance type +3. Add the terraform.tfvars file and show that the value is read from the file + +#### Lab 2-2 + +In this lab the students modify the previous lab result to use variables + +--- + +### Example 3 + +Creates a local variable "Name" and uses string interpolation to set the tag on the instance + +--- + +### Example 4 + +Local variables are used to set the name of the instance + +--- + +#### Lab 2-3 + +In this lab the students implement the local variables and string interpolation. + +--- + +### Example 5 + +This example just illustrates a heredoc string + +--- + +### Example 6 + +This example demonstrates reading from a local file + +--- + +## Example 7 + +This example demonstrates reading from a template file + +### Lab 2-4 + +Students read from a template file + +--- + +## Example 8 + +This example just demonstrates the use of the filter function with data + +I suggest running it so that students can see that the filter actually does produce the correct result + +--- + +## Example 9 + +Demonstrates the use of multiple providers. Code is simple but should be run to show the actual creations of instances in the two regions + +### Lab 2-5 + +This is a challenge lab that combines the work of the last two examples. Students have to work a bit harder to figure out what needs to be done + +--- + + + + diff --git a/Examples/Module-03 State/Example-3-1/Code/.terraform.lock.hcl b/Examples/Module-03 State/Example-3-1/Code/.terraform.lock.hcl new file mode 100644 index 00000000..dad8737a --- /dev/null +++ b/Examples/Module-03 State/Example-3-1/Code/.terraform.lock.hcl @@ -0,0 +1,22 @@ +# This file is maintained automatically by "terraform init". +# Manual edits may be lost in future updates. + +provider "registry.terraform.io/hashicorp/aws" { + version = "4.10.0" + constraints = ">= 3.0.0" + hashes = [ + "h1:S6xGPRL08YEuBdemiYZyIBf/YwM4OCvzVuaiuU6kLjc=", + "zh:0a2a7eabfeb7dbb17b7f82aff3fa2ba51e836c15e5be4f5468ea44bd1299b48d", + "zh:23409c7205d13d2d68b5528e1c49e0a0455d99bbfec61eb0201142beffaa81f7", + "zh:3adad2245d97816f3919778b52c58fb2de130938a3e9081358bfbb72ec478d9a", + "zh:5bf100aba6332f24b1ffeae7536d5d489bb907bf774a06b95f2183089eaf1a1a", + "zh:63c3a24c0c229a1d3390e6ea2454ba4d8ace9b94e086bee1dbdcf665ae969e15", + "zh:6b76f5ffd920f0a750da3a4ff1d00eab18d9cd3731b009aae3df4135613bad4d", + "zh:8cd6b1e6b51e8e9bbe2944bb169f113d20d1d72d07ccd1b7b83f40b3c958233e", + "zh:9b12af85486a96aedd8d7984b0ff811a4b42e3d88dad1a3fb4c0b580d04fa425", + "zh:c5c31f58fb5bd6aebc6c662a4693640ec763cb3399cce0b592101cf24ece1625", + "zh:cc485410be43d6ad95d81b9e54cc4d2117aadf9bf5941165a9df26565d9cce42", + "zh:cebb89c74b6a3dc6780824b1d1e2a8d16a51e75679e14ad0b830d9f7da1a3a67", + "zh:e7dc427189cb491e1f96e295101964415cbf8630395ee51e396d2a811f365237", + ] +} diff --git a/Examples/Module-03 State/Example-3-1/Code/main.tf b/Examples/Module-03 State/Example-3-1/Code/main.tf new file mode 100755 index 00000000..a6e1c994 --- /dev/null +++ b/Examples/Module-03 State/Example-3-1/Code/main.tf @@ -0,0 +1,24 @@ + +# Example 03-01 + +resource "aws_instance" "X" { + ami = "ami-077e31c4939f6a2f3" + instance_type = "t2.micro" + tags = { + Name = "Instance X" + } +} + +resource "aws_instance" "Y" { + ami = "ami-077e31c4939f6a2f3" + instance_type = "t2.micro" + tags = { + Name = "Instance Y" + } +} + + + + + + diff --git a/Examples/Module-03 State/Example-3-1/Code/providers.tf b/Examples/Module-03 State/Example-3-1/Code/providers.tf new file mode 100755 index 00000000..a55f3b63 --- /dev/null +++ b/Examples/Module-03 State/Example-3-1/Code/providers.tf @@ -0,0 +1,17 @@ + +terraform { + required_providers { + aws = { + source = "hashicorp/aws" + version = ">= 3.0" + } + } + # Required version of terraform + required_version = ">0.14" +} + +provider aws { + region = "us-east-2" + profile = "dev" +} + diff --git a/Examples/Module-03 State/Example-3-2/Code/main.tf b/Examples/Module-03 State/Example-3-2/Code/main.tf new file mode 100755 index 00000000..e759151a --- /dev/null +++ b/Examples/Module-03 State/Example-3-2/Code/main.tf @@ -0,0 +1,16 @@ + +# Example 03-02 + +resource "aws_instance" "VM" { + ami = "ami-077e31c4939f6a2f3" + instance_type = "t2.micro" + tags = { + Name = "Default" + } +} + + + + + + diff --git a/Examples/Module-03 State/Example-3-2/Code/providers.tf b/Examples/Module-03 State/Example-3-2/Code/providers.tf new file mode 100755 index 00000000..a55f3b63 --- /dev/null +++ b/Examples/Module-03 State/Example-3-2/Code/providers.tf @@ -0,0 +1,17 @@ + +terraform { + required_providers { + aws = { + source = "hashicorp/aws" + version = ">= 3.0" + } + } + # Required version of terraform + required_version = ">0.14" +} + +provider aws { + region = "us-east-2" + profile = "dev" +} + diff --git a/Examples/Module-03 State/Example-3-3/Code/main.tf b/Examples/Module-03 State/Example-3-3/Code/main.tf new file mode 100755 index 00000000..d9ccd3ef --- /dev/null +++ b/Examples/Module-03 State/Example-3-3/Code/main.tf @@ -0,0 +1,45 @@ +resource "aws_s3_bucket" "zippy" { + bucket = "terraform-zippy" + + # Prevent accidental deletion of this S3 bucket + # lifecycle { + # prevent_destroy = true + # } + + # Enable versioning so we can see the full revision history of our + # state files + versioning { + enabled = false + } + + # Enable server-side encryption by default + server_side_encryption_configuration { + rule { + apply_server_side_encryption_by_default { + sse_algorithm = "AES256" + } + } + } +} + +resource "aws_dynamodb_table" "state-locks" { + name = "zippy-locks" + billing_mode = "PAY_PER_REQUEST" + hash_key = "LockID" + + attribute { + name = "LockID" + type = "S" + } +} + + +output "s3_bucket_arn" { + value = aws_s3_bucket.zippy.arn + description = "The ARN of the S3 bucket" +} + +output "dynamodb_table_name" { + value = aws_dynamodb_table.state-locks.name + description = "The name of the DynamoDB table" +} diff --git a/Examples/Module-03 State/Example-3-3/Code/providers.tf b/Examples/Module-03 State/Example-3-3/Code/providers.tf new file mode 100755 index 00000000..77f1e153 --- /dev/null +++ b/Examples/Module-03 State/Example-3-3/Code/providers.tf @@ -0,0 +1,19 @@ + +terraform { + required_providers { + aws = { + source = "hashicorp/aws" + version = ">= 3.0" + } + } + # Required version of terraform + required_version = ">0.14" + + +} + +provider aws { + region = "us-east-2" + profile = "dev" +} + diff --git a/Examples/Module-03 State/Example-3-4/code/main.tf b/Examples/Module-03 State/Example-3-4/code/main.tf new file mode 100755 index 00000000..453929af --- /dev/null +++ b/Examples/Module-03 State/Example-3-4/code/main.tf @@ -0,0 +1,10 @@ + + + +resource "aws_instance" "myVM" { + ami = "ami-077e31c4939f6a2f3" + instance_type = "t2.micro" + tags = { + Name = "Remote Backend" + } +} diff --git a/Examples/Module-03 State/Example-3-4/code/providers.tf b/Examples/Module-03 State/Example-3-4/code/providers.tf new file mode 100755 index 00000000..fa5d4d93 --- /dev/null +++ b/Examples/Module-03 State/Example-3-4/code/providers.tf @@ -0,0 +1,32 @@ + +terraform { + required_providers { + aws = { + source = "hashicorp/aws" + version = ">= 3.0" + } + } + # Required version of terraform + required_version = ">0.14" + +} + +terraform { + backend "s3" { + profile = "dev" + # Replace this with your bucket name! + bucket = "terraform-zippy" + key = "myproj/terraform.tfstate" + region = "us-east-2" + + # Replace this with your DynamoDB table name! + dynamodb_table = "zippy-locks" + encrypt = true + } +} + +provider aws { + region = "us-east-2" + profile = "dev" +} + diff --git a/Examples/Module-03 State/Examples.md b/Examples/Module-03 State/Examples.md new file mode 100644 index 00000000..589875e5 --- /dev/null +++ b/Examples/Module-03 State/Examples.md @@ -0,0 +1,78 @@ +# Examples Notes + +These notes document how I work with the examples in the Terraform class. + +## Module 3 + +There is not a lot of code writing in module 3; instead, there is a lot of manipulating a set of EC2 instances to illustrate how they are maintained in the state file + +The basic code used is in the example 3-1 folder + +### Example 3-1 + +This example is used to provide practical demos of the comments made about state. The configuration is simple - just two VMS. What I demo in this example is the same as what the students will do in the lab, so they get to see it before they try it. + +I would suggest having a running VM created at the console to show that all of the terraform operations do not affect non-terraform resources + +The specific things I demonstrate are: + +1. Commenting out a VM resource and show that terraform deletes the running vm +2. The state list and show commands +3. Making a change in the running VM, usually the Name, then showing how terraform reverts the running VM to conform to the specification +3. Making a non-destructive change in the code to a VM, usually changing the instance type and showing how terraform does a change in place +4. Making a destructive chance, like the ami from amazon linux to ubuntu, to show how the resource is recreated +5. Using the state rm command to remove a VM from terraform, showing that it is still running in AWS and terraform can no longer see it and will try and create a new version +6. Using the import command to add the removed vm back into terraform +7. Create a copy of one of the instance definitions but with a different name then use the state mv command to rename one of the instances to the new name. Since the old name is no longer associated with the running instance, terraform will plan to create one +8. Finally, the use of the taint and untaint commands are shown + +### Example 3-2 + +This example is a preview of lab 3-2 demonstrating the use of workspaces. I use very simple code with just a single VM + +1. The VM is tagged with the Name "default" +2. Run apply to create the VM +3. Show the state file in the root directory and the running VM in the console +4. Create workspace "dev" and switch to it +5. Retag the VM with the name "dev" +6. Run terraform apply and show there are two VMs, one named "default" and one named "dev" +7. Show the workspace state files that have been created +8. Switch back to the default workspace and run terraform plan to show that the default VM will be altered in place and that this is not what we want +9. Try to delete the "dev" workspace and notice the terraform warning +10. Switch to dev and run destroy +11. switch back to default and run destroy + + +I end this demo by underscoring that there are two different things that have to be managed +* The state files, which terraform manages +* The source code *tf file that we manage + +The takeaway that leads onto the next example is that with sloppy source code management, we can corrupt our state + +### Example 3-3 + +This example requires that you have git installed. + +1. Using the same code from the previous example, make sure the VM is named "default" +2. Create a git repo, add main.tf to the repo and commit. The default workspace is now using the main git branch +3. Run terraform apply +4. Switch to the "dev" workspace +5. Create and checkout a branch called "dev" +6. Rename the instance to "dev" and run terraform apply +7. Examine both machines in AWS to ensure they are running +8. Switch to the default workspace +9. Checkout the main git branch +10. Run terraform plan to see that code changes on the dev branch will not affect default + +This will be the only place where git will be demonstrated. Point out that the danger of this approach is that forgetting to check out the right branch when you switch workspaces could step on other people's code. + +Clean up and destroy all the resources used in this demo + +### Example 3-4 + +Example walks through the setting up of the remote backend + + + + + diff --git a/Examples/Module-04 HCL/Example-04-01/code/main.tf b/Examples/Module-04 HCL/Example-04-01/code/main.tf new file mode 100755 index 00000000..3e06b28b --- /dev/null +++ b/Examples/Module-04 HCL/Example-04-01/code/main.tf @@ -0,0 +1,17 @@ + +# Example 04-01 + +resource "aws_instance" "Clone" { + count = 3 + ami = "ami-077e31c4939f6a2f3" + instance_type = "t2.micro" + tags = { + Name = "VM-${count.index}" + } +} + + + + + + diff --git a/Examples/Module-04 HCL/Example-04-01/code/providers.tf b/Examples/Module-04 HCL/Example-04-01/code/providers.tf new file mode 100755 index 00000000..a55f3b63 --- /dev/null +++ b/Examples/Module-04 HCL/Example-04-01/code/providers.tf @@ -0,0 +1,17 @@ + +terraform { + required_providers { + aws = { + source = "hashicorp/aws" + version = ">= 3.0" + } + } + # Required version of terraform + required_version = ">0.14" +} + +provider aws { + region = "us-east-2" + profile = "dev" +} + diff --git a/Examples/Module-04 HCL/Example-04-02/code/main.tf b/Examples/Module-04 HCL/Example-04-02/code/main.tf new file mode 100755 index 00000000..08861c90 --- /dev/null +++ b/Examples/Module-04 HCL/Example-04-02/code/main.tf @@ -0,0 +1,31 @@ + +# Example 04-02 + +resource "aws_instance" "Matrix" { + count = length(var.VM_names) + ami = "ami-077e31c4939f6a2f3" + instance_type = "t2.micro" + tags = { + Name = "VM-${var.VM_names[count.index]}" + } +} + +variable "VM_names" { + type = list(string) + default = ["Neo", "Morpheus"] +} + +output "Neo" { + value = aws_instance.Matrix[0].tags.Name + description = "Outputs a single string" +} +output "Everyone" { + value = aws_instance.Matrix[*].tags.Name + description = "Outputs a list of strings" +} + + + + + + diff --git a/Examples/Module-04 HCL/Example-04-02/code/providers.tf b/Examples/Module-04 HCL/Example-04-02/code/providers.tf new file mode 100755 index 00000000..a55f3b63 --- /dev/null +++ b/Examples/Module-04 HCL/Example-04-02/code/providers.tf @@ -0,0 +1,17 @@ + +terraform { + required_providers { + aws = { + source = "hashicorp/aws" + version = ">= 3.0" + } + } + # Required version of terraform + required_version = ">0.14" +} + +provider aws { + region = "us-east-2" + profile = "dev" +} + diff --git a/Examples/Module-04 HCL/Example-04-03/code/main.tf b/Examples/Module-04 HCL/Example-04-03/code/main.tf new file mode 100755 index 00000000..8915b359 --- /dev/null +++ b/Examples/Module-04 HCL/Example-04-03/code/main.tf @@ -0,0 +1,21 @@ + +# Example 04-03 + +resource "aws_instance" "Matrix" { + for_each = toset(var.VM_names) + ami = "ami-077e31c4939f6a2f3" + instance_type = "t2.micro" + tags = { + Name = "VM-${each.value}" + } +} + +variable "VM_names" { + type = list(string) + default = ["Neo", "Morpheus"] +} + + + + + diff --git a/Examples/Module-04 HCL/Example-04-03/code/providers.tf b/Examples/Module-04 HCL/Example-04-03/code/providers.tf new file mode 100755 index 00000000..a55f3b63 --- /dev/null +++ b/Examples/Module-04 HCL/Example-04-03/code/providers.tf @@ -0,0 +1,17 @@ + +terraform { + required_providers { + aws = { + source = "hashicorp/aws" + version = ">= 3.0" + } + } + # Required version of terraform + required_version = ">0.14" +} + +provider aws { + region = "us-east-2" + profile = "dev" +} + diff --git a/Examples/Module-04 HCL/Example-04-04/code/main.tf b/Examples/Module-04 HCL/Example-04-04/code/main.tf new file mode 100755 index 00000000..1f6b00de --- /dev/null +++ b/Examples/Module-04 HCL/Example-04-04/code/main.tf @@ -0,0 +1,30 @@ + +# Example 04-04 + +resource "aws_security_group" "example" { + name = "demo-simple" + description = "demo-simple" + + ingress { + description = "description 0" + from_port = 80 + to_port = 80 + protocol = "tcp" + cidr_blocks = ["0.0.0.0/0"] + } + ingress { + description = "description 1" + from_port = 81 + to_port = 81 + protocol = "tcp" + cidr_blocks = ["0.0.0.0/0"] + } + tags = { + Name = "for_each" + } +} + + + + + diff --git a/Examples/Module-04 HCL/Example-04-04/code/providers.tf b/Examples/Module-04 HCL/Example-04-04/code/providers.tf new file mode 100755 index 00000000..a55f3b63 --- /dev/null +++ b/Examples/Module-04 HCL/Example-04-04/code/providers.tf @@ -0,0 +1,17 @@ + +terraform { + required_providers { + aws = { + source = "hashicorp/aws" + version = ">= 3.0" + } + } + # Required version of terraform + required_version = ">0.14" +} + +provider aws { + region = "us-east-2" + profile = "dev" +} + diff --git a/Examples/Module-04 HCL/Example-04-05/code/main.tf b/Examples/Module-04 HCL/Example-04-05/code/main.tf new file mode 100755 index 00000000..c3a5cd36 --- /dev/null +++ b/Examples/Module-04 HCL/Example-04-05/code/main.tf @@ -0,0 +1,40 @@ + +# Example 04-05 + +locals { + rules = [{ + description = "HTTP Port", + port = 80, + cidr_blocks = ["0.0.0.0/0"], + },{ + description = "Custom Port", + port = 81, + cidr_blocks = ["10.0.0.0/16"], + }] +} + +resource "aws_security_group" "for_each" { + name = "Dynamic" + description = "Dynamic Inline Block" + + dynamic "ingress" { + for_each = local.rules + content { + description = ingress.value.description + from_port = ingress.value.port + to_port = ingress.value.port + protocol = "tcp" + cidr_blocks = ingress.value.cidr_blocks + } + } + tags = { + Name = "Dynamic" + } + + } + + + + + + diff --git a/Examples/Module-04 HCL/Example-04-05/code/providers.tf b/Examples/Module-04 HCL/Example-04-05/code/providers.tf new file mode 100755 index 00000000..a55f3b63 --- /dev/null +++ b/Examples/Module-04 HCL/Example-04-05/code/providers.tf @@ -0,0 +1,17 @@ + +terraform { + required_providers { + aws = { + source = "hashicorp/aws" + version = ">= 3.0" + } + } + # Required version of terraform + required_version = ">0.14" +} + +provider aws { + region = "us-east-2" + profile = "dev" +} + diff --git a/Examples/Module-04 HCL/Example-04-06/code/main.tf b/Examples/Module-04 HCL/Example-04-06/code/main.tf new file mode 100755 index 00000000..8f66f91c --- /dev/null +++ b/Examples/Module-04 HCL/Example-04-06/code/main.tf @@ -0,0 +1,19 @@ + +# Example 04-06 + + variable "names" { + description = "A list of names" + type = list(string) + default = ["neo", "trinity", "morpheus"] + } + + output "upper_names" { + value = [for name in var.names : upper(name)] + } + + output "short_upper_names" { + value = [for name in var.names : upper(name) if length(name) < 5] + } + + + diff --git a/Examples/Module-04 HCL/Example-04-06/code/providers.tf b/Examples/Module-04 HCL/Example-04-06/code/providers.tf new file mode 100755 index 00000000..a55f3b63 --- /dev/null +++ b/Examples/Module-04 HCL/Example-04-06/code/providers.tf @@ -0,0 +1,17 @@ + +terraform { + required_providers { + aws = { + source = "hashicorp/aws" + version = ">= 3.0" + } + } + # Required version of terraform + required_version = ">0.14" +} + +provider aws { + region = "us-east-2" + profile = "dev" +} + diff --git a/Examples/Module-04 HCL/Example-04-07/code/main.tf b/Examples/Module-04 HCL/Example-04-07/code/main.tf new file mode 100755 index 00000000..2dd4bd64 --- /dev/null +++ b/Examples/Module-04 HCL/Example-04-07/code/main.tf @@ -0,0 +1,20 @@ + +# Example 04-07 + +variable "hero_thousand_faces" { + description = "map" + type = map(string) + default = { + neo = "hero" + trinity = "love interest" + morpheus = "mentor" + } +} + +output "bios" { + value = [for name, role in var.hero_thousand_faces : "${name} is the ${role}"] +} + + output "upper_roles" { + value = {for name, role in var.hero_thousand_faces : upper(name) => upper(role)} + } \ No newline at end of file diff --git a/Examples/Module-04 HCL/Example-04-07/code/providers.tf b/Examples/Module-04 HCL/Example-04-07/code/providers.tf new file mode 100755 index 00000000..a55f3b63 --- /dev/null +++ b/Examples/Module-04 HCL/Example-04-07/code/providers.tf @@ -0,0 +1,17 @@ + +terraform { + required_providers { + aws = { + source = "hashicorp/aws" + version = ">= 3.0" + } + } + # Required version of terraform + required_version = ">0.14" +} + +provider aws { + region = "us-east-2" + profile = "dev" +} + diff --git a/Examples/Module-04 HCL/Example-04-08/code/main.tf b/Examples/Module-04 HCL/Example-04-08/code/main.tf new file mode 100755 index 00000000..023e1722 --- /dev/null +++ b/Examples/Module-04 HCL/Example-04-08/code/main.tf @@ -0,0 +1,30 @@ + +# Example 04-08 + +variable "names" { + description = "Names to render" + type = list(string) + default = ["neo", "trinity", "morpheus"] +} + +output "for_directive" { + + value = < index.html + nohup busybox httpd -f -p 8080 & + EOF + + tags = { + Name = "${var.app_name} App" + } + vpc_security_group_ids = [data.aws_security_group.default.id] + + +} \ No newline at end of file diff --git a/Examples/Module-07 Testing/Example-7-2/code/step-1/EC2/variables.tf b/Examples/Module-07 Testing/Example-7-2/code/step-1/EC2/variables.tf new file mode 100644 index 00000000..aac6205c --- /dev/null +++ b/Examples/Module-07 Testing/Example-7-2/code/step-1/EC2/variables.tf @@ -0,0 +1,28 @@ +variable "ami_type" { + description = "The ami to use depending on region" + type = string + default = "ami-03d315ad33b9d49c4" +} + +variable "instance_type" { + description = "The instance class to use" + type = string + default = "t2.small" +} + +variable "access_port" { + description = "Access port to use for the application" + type = number + default = 80 +} + +variable "app_name" { + description = "The name of the application deployment" + type = string + default = "No Name" +} + +variable "sg_groups" { + description = "Associated security groups" + type = list(string) +} diff --git a/Examples/Module-07 Testing/Example-7-2/code/step-1/SG/main.tf b/Examples/Module-07 Testing/Example-7-2/code/step-1/SG/main.tf new file mode 100644 index 00000000..08ef0011 --- /dev/null +++ b/Examples/Module-07 Testing/Example-7-2/code/step-1/SG/main.tf @@ -0,0 +1,21 @@ +resource "aws_security_group" "app_port" { + description = " Security group to allow access app instance" + ingress { + description = "OpenPort" + from_port = var.access_port + to_port = var.access_port + protocol = "tcp" + cidr_blocks = ["0.0.0.0/0"] + } + + egress { + from_port = 0 + to_port = 0 + protocol = "-1" + cidr_blocks = ["0.0.0.0/0"] + } + + tags = { + Name = var.sg_name + } +} diff --git a/Examples/Module-07 Testing/Example-7-2/code/step-1/SG/output.tf b/Examples/Module-07 Testing/Example-7-2/code/step-1/SG/output.tf new file mode 100644 index 00000000..ce2cef5f --- /dev/null +++ b/Examples/Module-07 Testing/Example-7-2/code/step-1/SG/output.tf @@ -0,0 +1,4 @@ + +output "secgps" { + value =aws_security_group.app_port.id +} \ No newline at end of file diff --git a/Examples/Module-07 Testing/Example-7-2/code/step-1/SG/variables.tf b/Examples/Module-07 Testing/Example-7-2/code/step-1/SG/variables.tf new file mode 100644 index 00000000..e453d4ce --- /dev/null +++ b/Examples/Module-07 Testing/Example-7-2/code/step-1/SG/variables.tf @@ -0,0 +1,13 @@ + +variable "access_port" { + description = "Access port to use for the application" + type = number + default = 80 +} + +variable "sg_name" { + description = "The name of the security group" + type = string + default = "My SG" +} + diff --git a/Examples/Module-07 Testing/Example-7-2/code/step-1/root/main.tf b/Examples/Module-07 Testing/Example-7-2/code/step-1/root/main.tf new file mode 100644 index 00000000..821f79f7 --- /dev/null +++ b/Examples/Module-07 Testing/Example-7-2/code/step-1/root/main.tf @@ -0,0 +1,19 @@ +// Starting point + +module "SecGrp" { + source = "../SG" + access_port = var.access_port + sg_name = "Test SG" +} + +module "hello_app" { + source = "../EC2" + instance_type = var.instance_type + app_name = var.app_name + sg_groups = [module.SecGrp.secgps] + +} + +data "aws_security_group" "default_sg" { + name = "default" +} diff --git a/Examples/Module-07 Testing/Example-7-2/code/step-1/root/outputs.tf b/Examples/Module-07 Testing/Example-7-2/code/step-1/root/outputs.tf new file mode 100644 index 00000000..9a3275b6 --- /dev/null +++ b/Examples/Module-07 Testing/Example-7-2/code/step-1/root/outputs.tf @@ -0,0 +1,10 @@ +/*output "app_id" { + description = "Id of the hello apps" + value = [aws_instance.hello_app1.id,aws_instance.hello_app2.id] +} + +output "app_ip" { + description = "Public ip of the hello app" + value = [aws_instance.hello_app1.public_ip,aws_instance.hello_app1.public_ip] +} +*/ \ No newline at end of file diff --git a/Examples/Module-07 Testing/Example-7-2/code/step-1/root/providers.tf b/Examples/Module-07 Testing/Example-7-2/code/step-1/root/providers.tf new file mode 100755 index 00000000..d989f70c --- /dev/null +++ b/Examples/Module-07 Testing/Example-7-2/code/step-1/root/providers.tf @@ -0,0 +1,15 @@ +terraform { + required_providers { + aws = { + source = "hashicorp/aws" + version = ">= 3.0" + } + } + # Required version of terraform + required_version = ">0.14" +} + +provider "aws" { + region = "us-east-2" + profile = "dev" +} \ No newline at end of file diff --git a/Examples/Module-07 Testing/Example-7-2/code/step-1/root/terraform.tfvars b/Examples/Module-07 Testing/Example-7-2/code/step-1/root/terraform.tfvars new file mode 100644 index 00000000..f7d59f17 --- /dev/null +++ b/Examples/Module-07 Testing/Example-7-2/code/step-1/root/terraform.tfvars @@ -0,0 +1,4 @@ + +access_port = 8080 +app_name = "zippy" +instance_type = "t2.nano" \ No newline at end of file diff --git a/Examples/Module-07 Testing/Example-7-2/code/step-1/root/variables.tf b/Examples/Module-07 Testing/Example-7-2/code/step-1/root/variables.tf new file mode 100644 index 00000000..23b614ee --- /dev/null +++ b/Examples/Module-07 Testing/Example-7-2/code/step-1/root/variables.tf @@ -0,0 +1,18 @@ + +variable "instance_type" { + description = "The instance type to use" + type = string +} + + +variable "access_port" { + description = "Access port to use for the application" + type = number + default = 80 +} + +variable "app_name" { + description = "The name of the application deployment" + type = string +} + diff --git a/Examples/Module-07 Testing/Example-7-2/code/step-2/EC2/data.tf b/Examples/Module-07 Testing/Example-7-2/code/step-2/EC2/data.tf new file mode 100644 index 00000000..467051cc --- /dev/null +++ b/Examples/Module-07 Testing/Example-7-2/code/step-2/EC2/data.tf @@ -0,0 +1,21 @@ + +data "aws_ami" "ubuntu" { + most_recent = true + + filter { + name = "name" + values = ["ubuntu/images/hvm-ssd/ubuntu-focal-20.04-amd64-server-*"] + } + + filter { + name = "virtualization-type" + values = ["hvm"] + } + + owners = ["099720109477"] # Canonical +} + +data "aws_security_group" "default" { + name = "default" +} + diff --git a/Examples/Module-07 Testing/Example-7-2/code/step-2/EC2/main.tf b/Examples/Module-07 Testing/Example-7-2/code/step-2/EC2/main.tf new file mode 100644 index 00000000..a602404a --- /dev/null +++ b/Examples/Module-07 Testing/Example-7-2/code/step-2/EC2/main.tf @@ -0,0 +1,22 @@ +resource "aws_instance" "hello_app" { + + ami = data.aws_ami.ubuntu.id + instance_type = var.instance_type + + + user_data = <<-EOF + #!/bin/bash + echo "Hello, World" > index.html + nohup busybox httpd -f -p 8080 & + EOF + + tags = { + Name = "${var.app_name} App" + } + vpc_security_group_ids = [data.aws_security_group.default.id] + +} + +output "my_instance" { + value = aws_instance.hello_app +} \ No newline at end of file diff --git a/Examples/Module-07 Testing/Example-7-2/code/step-2/EC2/variables.tf b/Examples/Module-07 Testing/Example-7-2/code/step-2/EC2/variables.tf new file mode 100644 index 00000000..aac6205c --- /dev/null +++ b/Examples/Module-07 Testing/Example-7-2/code/step-2/EC2/variables.tf @@ -0,0 +1,28 @@ +variable "ami_type" { + description = "The ami to use depending on region" + type = string + default = "ami-03d315ad33b9d49c4" +} + +variable "instance_type" { + description = "The instance class to use" + type = string + default = "t2.small" +} + +variable "access_port" { + description = "Access port to use for the application" + type = number + default = 80 +} + +variable "app_name" { + description = "The name of the application deployment" + type = string + default = "No Name" +} + +variable "sg_groups" { + description = "Associated security groups" + type = list(string) +} diff --git a/Examples/Module-07 Testing/Example-7-2/code/step-2/SG/main.tf b/Examples/Module-07 Testing/Example-7-2/code/step-2/SG/main.tf new file mode 100644 index 00000000..08ef0011 --- /dev/null +++ b/Examples/Module-07 Testing/Example-7-2/code/step-2/SG/main.tf @@ -0,0 +1,21 @@ +resource "aws_security_group" "app_port" { + description = " Security group to allow access app instance" + ingress { + description = "OpenPort" + from_port = var.access_port + to_port = var.access_port + protocol = "tcp" + cidr_blocks = ["0.0.0.0/0"] + } + + egress { + from_port = 0 + to_port = 0 + protocol = "-1" + cidr_blocks = ["0.0.0.0/0"] + } + + tags = { + Name = var.sg_name + } +} diff --git a/Examples/Module-07 Testing/Example-7-2/code/step-2/SG/output.tf b/Examples/Module-07 Testing/Example-7-2/code/step-2/SG/output.tf new file mode 100644 index 00000000..ce2cef5f --- /dev/null +++ b/Examples/Module-07 Testing/Example-7-2/code/step-2/SG/output.tf @@ -0,0 +1,4 @@ + +output "secgps" { + value =aws_security_group.app_port.id +} \ No newline at end of file diff --git a/Examples/Module-07 Testing/Example-7-2/code/step-2/SG/variables.tf b/Examples/Module-07 Testing/Example-7-2/code/step-2/SG/variables.tf new file mode 100644 index 00000000..e453d4ce --- /dev/null +++ b/Examples/Module-07 Testing/Example-7-2/code/step-2/SG/variables.tf @@ -0,0 +1,13 @@ + +variable "access_port" { + description = "Access port to use for the application" + type = number + default = 80 +} + +variable "sg_name" { + description = "The name of the security group" + type = string + default = "My SG" +} + diff --git a/Examples/Module-07 Testing/Example-7-2/code/step-2/root/main.tf b/Examples/Module-07 Testing/Example-7-2/code/step-2/root/main.tf new file mode 100644 index 00000000..34e59559 --- /dev/null +++ b/Examples/Module-07 Testing/Example-7-2/code/step-2/root/main.tf @@ -0,0 +1,16 @@ +// Starting point + +module "SecGrp" { + source = "../SG" + access_port = var.access_port + sg_name = "Test SG" +} + +module "hello_app" { + source = "../EC2" + instance_type = var.instance_type + app_name = var.app_name + sg_groups = [module.SecGrp.secgps] + +} + diff --git a/Examples/Module-07 Testing/Example-7-2/code/step-2/root/outputs.tf b/Examples/Module-07 Testing/Example-7-2/code/step-2/root/outputs.tf new file mode 100644 index 00000000..9a3275b6 --- /dev/null +++ b/Examples/Module-07 Testing/Example-7-2/code/step-2/root/outputs.tf @@ -0,0 +1,10 @@ +/*output "app_id" { + description = "Id of the hello apps" + value = [aws_instance.hello_app1.id,aws_instance.hello_app2.id] +} + +output "app_ip" { + description = "Public ip of the hello app" + value = [aws_instance.hello_app1.public_ip,aws_instance.hello_app1.public_ip] +} +*/ \ No newline at end of file diff --git a/Examples/Module-07 Testing/Example-7-2/code/step-2/root/providers.tf b/Examples/Module-07 Testing/Example-7-2/code/step-2/root/providers.tf new file mode 100755 index 00000000..d989f70c --- /dev/null +++ b/Examples/Module-07 Testing/Example-7-2/code/step-2/root/providers.tf @@ -0,0 +1,15 @@ +terraform { + required_providers { + aws = { + source = "hashicorp/aws" + version = ">= 3.0" + } + } + # Required version of terraform + required_version = ">0.14" +} + +provider "aws" { + region = "us-east-2" + profile = "dev" +} \ No newline at end of file diff --git a/Examples/Module-07 Testing/Example-7-2/code/step-2/root/terraform.tfvars b/Examples/Module-07 Testing/Example-7-2/code/step-2/root/terraform.tfvars new file mode 100644 index 00000000..f7d59f17 --- /dev/null +++ b/Examples/Module-07 Testing/Example-7-2/code/step-2/root/terraform.tfvars @@ -0,0 +1,4 @@ + +access_port = 8080 +app_name = "zippy" +instance_type = "t2.nano" \ No newline at end of file diff --git a/Examples/Module-07 Testing/Example-7-2/code/step-2/root/tests.tf b/Examples/Module-07 Testing/Example-7-2/code/step-2/root/tests.tf new file mode 100644 index 00000000..2a4eebea --- /dev/null +++ b/Examples/Module-07 Testing/Example-7-2/code/step-2/root/tests.tf @@ -0,0 +1,3 @@ +output "Integration_Test_1" { + value = (module.hello_app.my_instance.vpc_security_group_ids == module.SecGrp.secgps) +} \ No newline at end of file diff --git a/Examples/Module-07 Testing/Example-7-2/code/step-2/root/variables.tf b/Examples/Module-07 Testing/Example-7-2/code/step-2/root/variables.tf new file mode 100644 index 00000000..23b614ee --- /dev/null +++ b/Examples/Module-07 Testing/Example-7-2/code/step-2/root/variables.tf @@ -0,0 +1,18 @@ + +variable "instance_type" { + description = "The instance type to use" + type = string +} + + +variable "access_port" { + description = "Access port to use for the application" + type = number + default = 80 +} + +variable "app_name" { + description = "The name of the application deployment" + type = string +} + diff --git a/Examples/Module-07 Testing/Example-7-2/code/step-2/root/vars.tf b/Examples/Module-07 Testing/Example-7-2/code/step-2/root/vars.tf new file mode 100644 index 00000000..58951f36 --- /dev/null +++ b/Examples/Module-07 Testing/Example-7-2/code/step-2/root/vars.tf @@ -0,0 +1,27 @@ + + +module "asg" { + source = "../../modules/cluster/asg-rolling-deploy" + + cluster_name = var.cluster_name + ami = "ami-0c55b159cbfafe1f0" + instance_type = "t2.micro" + + min_size = 1 + max_size = 1 + enable_autoscaling = false + + subnet_ids = data.aws_subnet_ids.default.ids +} + +data "aws_vpc" "default" { + default = true +} + +data "aws_subnet_ids" "default" { + vpc_id = data.aws_vpc.default.id +} + + + + diff --git a/Examples/Module-07 Testing/Examples-07.md b/Examples/Module-07 Testing/Examples-07.md new file mode 100644 index 00000000..b532c0f5 --- /dev/null +++ b/Examples/Module-07 Testing/Examples-07.md @@ -0,0 +1,56 @@ + +# Examples for Module 7 - Testing + +The two examples provided illustrate a basic unit test and a basic integration test using only terraform HCL code. These examples are intended to only show test thinking when it comes to terraform and not establish a methodology for doing testing. + +The code is very simplistic since it is intended to demonstrate some testing ideas, and using overly complex code would distract from the underlying teaching points. + +One point to make is that we don't actually need sophisticated testing tools to write basic automated tests -- we can even use terraform HCL to write tests + +## Example One - Unit Testing a Module + +The unit being tested in example one is a module that takes a string as input and creates a bucket with that name. However, the module does not create a bucket with the correct name since there is some development code that uses a local name for the bucket instead. This code was inadvertently not removed after development. + +In this case, the error is obvious and would be found with even a cursory inspection, but again, this is a very simplistic example. + +### Step one + +1. Run the code in the step one directory +2. Look in terraform.tfvars file to show the expected bucket name +3. The code runs without any errors or warnings, but fails to produce the right bucket + +The takeaway is that in a more complicated deployment, this sort of error may not be noticed until things start failing, and then we have to start what might be a massive bug hunt. + +### Step two + +1. The first thing to be done is to make the Bucket module testable. There is no way to reference the created bucket to check any of its attributes +2. An output variable is created that returns the id of the created bucket +3. A test is added using an output that compares the id of the bucket with the value provided to the module + +### Step three + +1. The incorrect code is removed, and the test passes + +--- + +## Example Two - Integration Testing + +In this example, we have two modules, one creating an EC2 instance web server, and the other creating a security group. We can begin with the assumption that both modules work perfectly. + +Integration testing is essentially ensuring we are connecting the parts of our infrastructure together correctly. + +In this example, the problem will be omitted code. There will be nothing to connect the security group to the EC2 server + +### Step One + +1. Create the infrastructure and note that while there are no errors or warning, the resulting webserver does not work. +2. The problem is an integration error. The security group module works correctly, the EC2 module works correctly, but the error is that we connect the wrong security group to the EC2 instance. +3. There is a reference to the default security group in our code derived from a data block. This may be left over from some development work, but we connect to this instead of the actual security group we created for the application + +### Step Two + +1. Add the integration test to ensure that the security group we created is in fact the security group that the web server is using (this is the integration part) + +2. Run the test and see the test fail + +3. Add in the missing code and the test passes and the \ No newline at end of file diff --git a/TODO.md b/TODO.md new file mode 100644 index 00000000..d360eb44 --- /dev/null +++ b/TODO.md @@ -0,0 +1,8 @@ +# TODO issues +* Add README.me into `Examples` directories +* Example 9 - Oregon AMI? +* Ansible and Terraform + * https://www.hashicorp.com/resources/ansible-terraform-better-together +* State drift +* https://www.trendmicro.com/en_sg/devops/22/c/terraform-tutorial-drift-detection-strategies.html?PID=100357191&SID=tuid%3A305E2BC49F9969CE18623A849ECB683B&cjevent=5816b301c59b11ec833d00820a1c0e12 +* State file stored in the backend (like S3) \ No newline at end of file diff --git a/artwork/fig00-01.png b/artwork/fig00-01.png new file mode 100644 index 00000000..9525e80a Binary files /dev/null and b/artwork/fig00-01.png differ diff --git a/artwork/fig00-02.png b/artwork/fig00-02.png new file mode 100644 index 00000000..89a97a26 Binary files /dev/null and b/artwork/fig00-02.png differ diff --git a/artwork/install_1.jpg b/artwork/install_1.jpg new file mode 100644 index 00000000..2081bd0f Binary files /dev/null and b/artwork/install_1.jpg differ diff --git a/artwork/install_2.jpg b/artwork/install_2.jpg new file mode 100644 index 00000000..807c4a06 Binary files /dev/null and b/artwork/install_2.jpg differ diff --git a/artwork/install_3.jpg b/artwork/install_3.jpg new file mode 100644 index 00000000..3d341c77 Binary files /dev/null and b/artwork/install_3.jpg differ diff --git a/artwork/load-balancer.png b/artwork/load-balancer.png new file mode 100644 index 00000000..96c6ef43 Binary files /dev/null and b/artwork/load-balancer.png differ diff --git a/code/terraform/00-preface/hello-world-google-vm/README.md b/code/terraform/00-preface/hello-world-google-vm/README.md new file mode 100644 index 00000000..efa1ef38 --- /dev/null +++ b/code/terraform/00-preface/hello-world-google-vm/README.md @@ -0,0 +1,31 @@ +# Terraform "Hello, World" example for Google Cloud + +This folder contains a "Hello, World" example of a [Terraform](https://www.terraform.io/) configuration. The configuration +deploys a single server in a [Google Cloud](http://cloud.google.com/). + +For more info, please see the preface of *[Terraform: Up and Running](http://www.terraformupandrunning.com)*. + +## Pre-requisites + +* You must have [Terraform](https://www.terraform.io/) installed on your computer. +* You must have a [Google Cloud](http://cloud.google.com/) account. + +## Quick start + +**Please note that this example will deploy real resources into your Google Cloud account. We have made every effort to ensure +all the resources qualify for the free tier, but we are not responsible for any charges you may incur.** + +Configure your account as explained [here](https://learn.hashicorp.com/tutorials/terraform/google-cloud-platform-build?in=terraform/gcp-get-started). + +Deploy the code: + +``` +terraform init +terraform apply +``` + +Clean up when you're done: + +``` +terraform destroy +``` \ No newline at end of file diff --git a/code/terraform/00-preface/hello-world-google-vm/main.tf b/code/terraform/00-preface/hello-world-google-vm/main.tf new file mode 100644 index 00000000..44a33845 --- /dev/null +++ b/code/terraform/00-preface/hello-world-google-vm/main.tf @@ -0,0 +1,40 @@ +terraform { + required_providers { + google = { + source = "hashicorp/google" + version = "3.5.0" + } + } +} + +# If you run in Google Cloud, in the shell, then you do not need the credentials. +# Otherwise, set them up as the README tells you. + +provider "google" { + // credentials = file("/home/mark/mark.json") + + project = "hadoop-setup-245603" + region = "us-central1" + zone = "us-central1-c" +} + +resource "google_compute_network" "vpc_network" { + name = "terraform-network" +} + +resource "google_compute_instance" "vm_instance" { + name = "terraform-instance" + machine_type = "f1-micro" + + boot_disk { + initialize_params { + image = "debian-cloud/debian-9" + } + } + + network_interface { + network = google_compute_network.vpc_network.name + access_config { + } + } +} diff --git a/code/terraform/00-preface/hello-world-google/README.md b/code/terraform/00-preface/hello-world-google/README.md new file mode 100644 index 00000000..efa1ef38 --- /dev/null +++ b/code/terraform/00-preface/hello-world-google/README.md @@ -0,0 +1,31 @@ +# Terraform "Hello, World" example for Google Cloud + +This folder contains a "Hello, World" example of a [Terraform](https://www.terraform.io/) configuration. The configuration +deploys a single server in a [Google Cloud](http://cloud.google.com/). + +For more info, please see the preface of *[Terraform: Up and Running](http://www.terraformupandrunning.com)*. + +## Pre-requisites + +* You must have [Terraform](https://www.terraform.io/) installed on your computer. +* You must have a [Google Cloud](http://cloud.google.com/) account. + +## Quick start + +**Please note that this example will deploy real resources into your Google Cloud account. We have made every effort to ensure +all the resources qualify for the free tier, but we are not responsible for any charges you may incur.** + +Configure your account as explained [here](https://learn.hashicorp.com/tutorials/terraform/google-cloud-platform-build?in=terraform/gcp-get-started). + +Deploy the code: + +``` +terraform init +terraform apply +``` + +Clean up when you're done: + +``` +terraform destroy +``` \ No newline at end of file diff --git a/code/terraform/00-preface/hello-world-google/main.tf b/code/terraform/00-preface/hello-world-google/main.tf new file mode 100644 index 00000000..45ef2e8e --- /dev/null +++ b/code/terraform/00-preface/hello-world-google/main.tf @@ -0,0 +1,23 @@ +terraform { + required_providers { + google = { + source = "hashicorp/google" + version = "3.5.0" + } + } +} + +# If you run in Google Cloud, in the shell, then you do not need the credentials. +# Otherwise, set them up as the README tells you. + +provider "google" { + // credentials = file("/home/mark/mark.json") + + project = "hadoop-setup-245603" + region = "us-central1" + zone = "us-central1-c" +} + +resource "google_compute_network" "vpc_network" { + name = "terraform-network" +} diff --git a/code/terraform/00-preface/hello-world-oracle/README.md b/code/terraform/00-preface/hello-world-oracle/README.md new file mode 100644 index 00000000..0daee2dc --- /dev/null +++ b/code/terraform/00-preface/hello-world-oracle/README.md @@ -0,0 +1,31 @@ +# Terraform "Hello, World" example for Oracle Cloud OCI + +This folder contains a "Hello, World" example of a [Terraform](https://www.terraform.io/) configuration. The configuration +deploys a single server in a [Google Cloud](http://cloud.google.com/). + +For more info, please see the preface of *[Terraform: Up and Running](http://www.terraformupandrunning.com)*. + +## Pre-requisites + +* You must have [Terraform](https://www.terraform.io/) installed on your computer. +* You must have a [Oracle Cloud](TODO) account. + +## Quick start + +**Please note that this example will deploy real resources into your Google Cloud account. We have made every effort to ensure +all the resources qualify for the free tier, but we are not responsible for any charges you may incur.** + +Configure your account as explained [here](https://learn.hashicorp.com/tutorials/terraform/google-cloud-platform-build?in=terraform/gcp-get-started). + +Deploy the code: + +``` +terraform init +terraform apply +``` + +Clean up when you're done: + +``` +terraform destroy +``` \ No newline at end of file diff --git a/code/terraform/00-preface/hello-world/.terraform.lock.hcl b/code/terraform/00-preface/hello-world/.terraform.lock.hcl index ebee2d96..b9490653 100644 --- a/code/terraform/00-preface/hello-world/.terraform.lock.hcl +++ b/code/terraform/00-preface/hello-world/.terraform.lock.hcl @@ -2,6 +2,7 @@ # Manual edits may be lost in future updates. provider "registry.terraform.io/hashicorp/aws" { + version = "4.19.0" constraints = "~> 4.0" hashes = [ diff --git a/code/terraform/01-why-terraform/web-server/.terraform.lock.hcl b/code/terraform/01-why-terraform/web-server/.terraform.lock.hcl index ebee2d96..fefdb5c6 100644 --- a/code/terraform/01-why-terraform/web-server/.terraform.lock.hcl +++ b/code/terraform/01-why-terraform/web-server/.terraform.lock.hcl @@ -2,6 +2,7 @@ # Manual edits may be lost in future updates. provider "registry.terraform.io/hashicorp/aws" { + version = "4.19.0" constraints = "~> 4.0" hashes = [ @@ -21,5 +22,6 @@ provider "registry.terraform.io/hashicorp/aws" { "zh:ce2623a13f74677cdb948607e456ce00407c57333b8310d5c9d053fc3defbc78", "zh:e0d57e8784e6ccfa96fdd07ae1ddcc947be242bc11e7a5dd16b520b4204e0d09", "zh:f988b7c37e95a5b3a493a6b9dcc5ed270136f97d5c0effa84a51940f71626c12", + ] } diff --git a/code/terraform/02-intro-to-terraform-syntax/one-webserver/.terraform.lock.hcl b/code/terraform/02-intro-to-terraform-syntax/one-webserver/.terraform.lock.hcl index ebee2d96..fefdb5c6 100644 --- a/code/terraform/02-intro-to-terraform-syntax/one-webserver/.terraform.lock.hcl +++ b/code/terraform/02-intro-to-terraform-syntax/one-webserver/.terraform.lock.hcl @@ -2,6 +2,7 @@ # Manual edits may be lost in future updates. provider "registry.terraform.io/hashicorp/aws" { + version = "4.19.0" constraints = "~> 4.0" hashes = [ @@ -21,5 +22,6 @@ provider "registry.terraform.io/hashicorp/aws" { "zh:ce2623a13f74677cdb948607e456ce00407c57333b8310d5c9d053fc3defbc78", "zh:e0d57e8784e6ccfa96fdd07ae1ddcc947be242bc11e7a5dd16b520b4204e0d09", "zh:f988b7c37e95a5b3a493a6b9dcc5ed270136f97d5c0effa84a51940f71626c12", + ] } diff --git a/labs/lab00-1.md b/labs/lab00-1.md new file mode 100644 index 00000000..08a37b5f --- /dev/null +++ b/labs/lab00-1.md @@ -0,0 +1,38 @@ +# Lab 00: Install Terraform + +### Overview +Install terraform + +### Depends On +None + +### Run time +30 minutes + +## Option 1 + +* Open CloudShell1/ + +![](../artwork/install_1.jpg) + +![](../artwork/install_2.jpg) + +* run below command to check the terraform version + + ```shell + terraform --version + ``` +![](../artwork/install_3.jpg) + +## Option 2: Use platform install + +* Open [page](https://learn.hashicorp.com/tutorials/terraform/install-cli) + +![](../artwork/fig00-02.png) + +* Proceed accordingly + +## Option 3 + +* If you are on AWS, you can use the AWS IDE, Cloud9 +* Terraform is already installed there! \ No newline at end of file diff --git a/labs/lab01-1.md b/labs/lab01-1.md new file mode 100644 index 00000000..a70c2d3d --- /dev/null +++ b/labs/lab01-1.md @@ -0,0 +1,57 @@ +# Lab 01: Terraform Hello World + +### Overview +Install terraform and run the first script + +### Depends On +None + +### Run time +30 minutes + +## Step 1: Create an AWS account +## Step 2: Install `terraform` +## Step 3: Terraform script + +* Create a folder `labs/lab01` on your computer +* Place the `main.tf` file in this folder and start putting the code there + +* Specify the provider + +```hcl-terraform + +terraform { + required_providers { + aws = { + source = "hashicorp/aws" + version = ">= 3.3.0" + } + } + required_version = ">= 0.14" +} + +provider "aws" { + region = "us-east-2" + # If you are using a profile, you can add it here + profile = "profile_name" +} +``` + +* Create an instance + +```hcl-terraform + +resource "aws_instance" "example" { + ami = "ami-0c55b159cbfafe1f0" + instance_type = "t2.micro" +} +``` + +* Run `terraform init` +* Run `terraform plan` +* Run `terraform apply` +* Verify the results in the AWS console +* Run `terraform destroy` + +## Step 4: +* Congratulations on completing your first Terraform lab diff --git a/labs/lab01-2.md b/labs/lab01-2.md new file mode 100644 index 00000000..23f72adf --- /dev/null +++ b/labs/lab01-2.md @@ -0,0 +1,34 @@ +# Tag it + +### Overview +Tag the resource + +### Depends On +[lab01-1](lab01-1.md) + +### Run time +30 minutes + +* From the previous lab, copy `main.tf` +* Add the following + +```hcl-terraform +resource "aws_instance" "example" { + ami = "ami-0c55b159cbfafe1f0" + instance_type = "t2.micro" + + tags = { + Name = "terraform-example" + } +} +``` + +* Run `terraform init` +* Run `terraform plan` +* Run `terraform apply` +* Verify the results in the AWS console +* Run `terraform destroy` + +### Done + +* Congratulations on completing the lab \ No newline at end of file diff --git a/labs/lab02-1.md b/labs/lab02-1.md new file mode 100644 index 00000000..415b8691 --- /dev/null +++ b/labs/lab02-1.md @@ -0,0 +1,88 @@ +# Lab 02-1: Create a web server + +### Overview +* Create a web server + +### Depends On +* None + +### Run time +* 30 minutes + +## Step 1: Prepare the project + +* Create a folder `labs/lab02-1` on your computer +* Place the `main.tf` file in this folder +* Following work is in the `main.tf` + +## Step 2: Code + +* Specify terraform and provider + +```hcl-terraform + +terraform { + required_providers { + aws = { + source = "hashicorp/aws" + version = ">= 3.3.0" + } + } + required_version = ">= 0.14" +} + +provider "aws" { + region = "us-east-2" +} +``` + +* Describe the instance to run + +```hcl-terraform + +resource "aws_instance" "app" { + instance_type = "t2.micro" + availability_zone = "us-east-2a" + ami = "ami-0c55b159cbfafe1f0" + + user_data = <<-EOF + #!/bin/bash + echo "Hello, World" > index.html + nohup busybox httpd -f -p 8080 & + EOF + + tags = { + Name = "terraform-web-server" + } +} +``` + +## Step 3: Verify + +* Run the following commands + + terraform plan + terraform apply + +* Verify the result on Amazon dashboard +* Login to AWS dashboard +* Analyze every element you created + +# What's missing? + +* Security group! (Coming up) + +* Run the following commands + + terraform destroy + +## Step 4: Debug (optional) + +* Observe that you do not have the key and cannot login into the instance +* Research and find out how to give the instance a key +* Debug: + * Re-run the configuration with the key + * login into the instance + * verify the curl operation from the inside + +### Congratulations! You have successfully completed the lab. \ No newline at end of file diff --git a/labs/lab02-2.md b/labs/lab02-2.md new file mode 100644 index 00000000..bf1d32af --- /dev/null +++ b/labs/lab02-2.md @@ -0,0 +1,100 @@ +# Lab 02-2: Create a working web server + +### Overview + +* Use parameters +* Encode the port as parameter +* Create security group +* Place the web server instance into the security group + +### Depends On +lab01.md + +### Run time +30 minutes + +## Step 1: Prepare the project + +* Create a folder `labs/lab01-2` on your computer +* Place the `main.tf` file in this folder +* Following work is in the `main.tf` + +## Step 2: Require `terraform` version at least 0.14 + + terraform { + required_version = ">= 0.14" + } + +## Step 3: Declare AWS provider + + provider "aws" { + region = "us-east-2" + + # Allow any 3.3 or greater version of the AWS provider + version = ">= 3.3.0 + } + +## Step 4: Store the server port in a parameter + + variable "server_port" { + description = "Server port for HTTP requests" + type = number + default = 8080 + } + +## Step 5: Declare the instance to be started + +* Start the instance in the Security Group +* Place the script that will act as a web server + + resource "aws_instance" "instance1" { + ami = "ami-0c55b159cbfafe1f0" + instance_type = "t2.micro" + vpc_security_group_ids = [aws_security_group.instance.id] + + tags = { + Name = "terraform-example" + } + user_data = <<-EOF + #!/bin/bash + echo "Hello, World" > index.html + nohup busybox httpd -f -p ${var.server_port} & + EOF + } + +## Step 6: Declare the security group +* Give it a name `terraform-example-sg` +* Allow access from anywhere +* On the port `server_port` + + resource "aws_security_group" "instance" { + name = "tterraform-example-sg" + + ingress { + from_port = var.server_port + to_port = var.server_port + protocol = "tcp" + cidr_blocks = ["0.0.0.0/0"] + } + } + +## Step 7: Add the `output` parameter +* Return the public ip of the server being created + + output "public_ip" { + value = aws_instance.instance1.public_ip + description = "The public IP address of the web server" + } + +## Step 8: Execute plan +* Run the following commands + + terraform plan + terraform apply + +* Verify the result on Amazon dashboard + +## Step 9: Cleanup +* Run the following commands + + terraform destroy \ No newline at end of file diff --git a/labs/lab02-3-prep.md b/labs/lab02-3-prep.md new file mode 100644 index 00000000..b88e6b29 --- /dev/null +++ b/labs/lab02-3-prep.md @@ -0,0 +1,57 @@ +# Lab 02-3-prep: Learn to work with the load balancer + +### Overview +* Create two instances +* Connect to them through the load balancer +* This lab is optional or can be done as a demo + +![](../artwork/load-balancer.png) + +### Depends On +* You need an Amazon account + +### Qwiklabs alternative +* Trainer shows a load balancer lab on Google (qwiklabs) or on Amazon (amazon.qwiklabs) + +### Run time +* 45 minutes + +## Step 1: Login into your Amazon account + +## Step 2: Add a security group +* Allow traffic on port 8080 from anywhere + +## Step 3: Launch instances +* Launch two instances (micro instances are enough) in the security group created in the previous step +* Use the same login key for both +* Login into each instance and start the web server response +* Your login command will look like this: `ssh -i .ssh/hi1.pem ubuntu@3.16.76.156`, with your ip and key +* (Most AWS images accept `ubuntu` or `ec2-user` as user names) +* Put the following into `run.sh` + + #!/bin/bash + echo "Hello, World" > index.html + nohup busybox httpd -f -p 8080 & +* Make it executable: `chmod +x run.sh` +* `./run.sh` + +## Step 4: Verify each instance +* First verify within the instance with `curl` +* Then verify in the browser + +## Step 5: Create a load balancer +* Put the two instances created earlier as targets + +## Step 6: Verify traffic through the load balancer +* Open the browser at http://:8080 + +## Step 7: Bonus +* Keep hitting the load balancer, observe which instance you are getting + +## Step 8: Bigger bonus + +* Try some load tool like JMeter +* Observe performance + +## Congratulations, you are now ready to automate this + diff --git a/labs/lab02-3.md b/labs/lab02-3.md new file mode 100644 index 00000000..59ba15ab --- /dev/null +++ b/labs/lab02-3.md @@ -0,0 +1,207 @@ +# Lab 02-3: Create a scalable web server + +### Overview +* Use ASG - auto-scaling group +* Prepare two web servers, security group, and place the instances behind the elastic load balancer + +### Depends On +lab01.md + +### Run time +45 minutes + +## Step 1: Prepare the project + +* Create a folder `labs/lab01-3` on your computer +* Place the `main.tf` file in this folder +* Following work is in the `main.tf` + + +## Step 2: Require `terraform` version between 0.12 and 0.14 + + + terraform { + required_version = ">= 0.12, <= 0.14.8" + } + +## Step 3: Declare AWS provider + + provider "aws" { + region = "us-east-2" + } + +## Step 4: Declare the `server_port` parameter + + variable "server_port" { + description = "Server port for HTTP requests" + type = number + default = 8080 + } + + +## Step 5: Create the AMI to be launched in the ASG + + resource "aws_launch_configuration" "example" { + image_id = "ami-0c55b159cbfafe1f0" + instance_type = "t2.micro" + security_groups = [aws_security_group.instance.id] + + user_data = <<-EOF + #!/bin/bash + echo "Hello, World" > index.html + nohup busybox httpd -f -p ${var.server_port} & + EOF + + # Required when using a launch configuration with an auto scaling group. + # https://www.terraform.io/docs/providers/aws/r/launch_configuration.html + lifecycle { + create_before_destroy = true + } + } + + +## Step 6: Prepare the VPC + + data "aws_vpc" "default" { + default = true + } + + data "aws_subnet_ids" "default" { + vpc_id = data.aws_vpc.default.id + } + +## Step 7: Set up ASG parameters + + resource "aws_autoscaling_group" "example" { + launch_configuration = aws_launch_configuration.example.name + vpc_zone_identifier = data.aws_subnet_ids.default.ids + + min_size = 2 + max_size = 10 + + tag { + key = "Name" + value = "terraform-asg-example" + propagate_at_launch = true + } + } + +## Step 8: Create load balancer + + resource "aws_lb_listener" "http" { + load_balancer_arn = aws_lb.example.arn + port = 80 + protocol = "HTTP" + + # By default, return a simple 404 page + default_action { + type = "fixed-response" + + fixed_response { + content_type = "text/plain" + message_body = "404: page not found" + status_code = 404 + } + } + } + +## Step 9: Create a security group for the load balancer + + resource "aws_security_group" "alb" { + name = "terraform-example-alb" + + # Allow inbound HTTP requests + ingress { + from_port = 80 + to_port = 80 + protocol = "tcp" + cidr_blocks = ["0.0.0.0/0"] + } + + # Allow all outbound requests + egress { + from_port = 0 + to_port = 0 + protocol = "-1" + cidr_blocks = ["0.0.0.0/0"] + } + } + + +## Step 10: Create the load balancer + + resource "aws_lb" "example" { + name = "terraform-asg-example" + load_balancer_type = "application" + subnets = data.aws_subnet_ids.default.ids + } + + +## Step 11: Set up load balancer parameters + + resource "aws_lb_target_group" "asg" { + name = "terraform-asg-example" + port = var.server_port + protocol = "HTTP" + vpc_id = data.aws_vpc.default.id + + health_check { + path = "/" + protocol = "HTTP" + matcher = "200" + interval = 15 + timeout = 3 + healthy_threshold = 2 + unhealthy_threshold = 2 + } + } + +## Step 12: In our security group, allow the server port we configured earlier + + resource "aws_security_group" "instance" { + name = "terraform-example-instance" + + ingress { + from_port = var.server_port + to_port = var.server_port + protocol = "tcp" + cidr_blocks = ["0.0.0.0/0"] + } + } + + +## Step 13: Output the load balancer endpoint for our server farm + + output "alb_dns_name" { + value = aws_lb.example.dns_name + description = "The domain name of the load balancer" + } + +## Step 14: Execute plan +* Run the following commands + + terraform plan + terraform apply + +* Verify the result on Amazon dashboard + +## Bonus + +* There may be a bug in this lab: each instances will work but the access through the load balancer will not work. +* If you observe this, debug and fix the labs + +## Bigger bonus + +* Try some load tool like JMeter +* Observe performance and verify that auto-scaling kicks in + +## Step 15: Cleanup +* Run the following commands + + terraform destroy + +## Step 16: Congratulations! + +* You have completed the ASG lab +* What improvements can you suggest? +* Implement the improvements diff --git a/labs/oracle/1-install.md b/labs/oracle/1-install.md new file mode 100644 index 00000000..4de133f4 --- /dev/null +++ b/labs/oracle/1-install.md @@ -0,0 +1,28 @@ +# Install Terraform + +In this lab we will practice the installation of Terrafrom + + +### STEP 1: + +* Login to your oracle cloud console page + +* open Cloud shell from your console + + + +* You will see the cloud shell terminal + + + +* Terrafrom is pre installed on oracle cloud shell. To check the version run below command: + + ``` + terrafrom --version + ``` + + + +* If you want to install terraform on your local machine follow the steps provided in this OCI document + + https://docs.oracle.com/en-us/iaas/developer-tutorials/tutorials/tf-provider/01-summary.htm \ No newline at end of file diff --git a/labs/oracle/Module-03 State/Example-3-1/Code/main.tf b/labs/oracle/Module-03 State/Example-3-1/Code/main.tf new file mode 100644 index 00000000..7d57e182 --- /dev/null +++ b/labs/oracle/Module-03 State/Example-3-1/Code/main.tf @@ -0,0 +1,52 @@ +resource "oci_core_instance" "X" { + # Required + availability_domain = data.oci_identity_availability_domains.ads.availability_domains[0].name + compartment_id = "ocid1.tenancy.oc1..aaaaaaaa6ag77lnluy7avrzhjkg7g3kriz5t5u2jnsw43yecx4oylzxsv5uq" + shape = "VM.Standard2.1" + source_details { + source_id = "ocid1.image.oc1.uk-london-1.aaaaaaaa3lb354447utq7gq6v3hqvo7u3nrkbf5fxmdxfem5jq4ngy4rtxba" + source_type = "image" + } + + # Optional + display_name = "Instance_X" + create_vnic_details { + assign_public_ip = true + subnet_id = "ocid1.subnet.oc1.uk-london-1.aaaaaaaa6n3zzrw6xnv2capcbpxwht4zr72uoxnnxvbrp5vcqmg56p7zaszq" + } + + preserve_boot_volume = false +} + +resource "oci_core_flex_instance" "Y" { + + source = "oracle-terraform-modules/compute-instance/oci" + instance_flex_memory_in_gbs = 1 + instance_flex_ocpus = 1 + + # Required + availability_domain = data.oci_identity_availability_domains.ads.availability_domains[0].name + compartment_id = "ocid1.tenancy.oc1..aaaaaaaa6ag77lnluy7avrzhjkg7g3kriz5t5u2jnsw43yecx4oylzxsv5uq" + shape = "VM.Standard3.Flex" + source_details { + source_id = "ocid1.image.oc1.uk-london-1.aaaaaaaa3lb354447utq7gq6v3hqvo7u3nrkbf5fxmdxfem5jq4ngy4rtxba" + source_type = "image" + } + + # Optional + display_name = "Instance_Y" + create_vnic_details { + assign_public_ip = true + subnet_id = "ocid1.subnet.oc1.uk-london-1.aaaaaaaa6n3zzrw6xnv2capcbpxwht4zr72uoxnnxvbrp5vcqmg56p7zaszq" + } + + preserve_boot_volume = false +} + +data "oci_identity_availability_domains" "ads" { + compartment_id = "ocid1.tenancy.oc1..aaaaaaaa6ag77lnluy7avrzhjkg7g3kriz5t5u2jnsw43yecx4oylzxsv5uq" +} + + + + diff --git a/labs/oracle/Module-03 State/Example-3-1/Code/providers.tf b/labs/oracle/Module-03 State/Example-3-1/Code/providers.tf new file mode 100644 index 00000000..7f706e3d --- /dev/null +++ b/labs/oracle/Module-03 State/Example-3-1/Code/providers.tf @@ -0,0 +1,6 @@ +provider "oci" { + tenancy_ocid = "" + user_ocid = "" + private_key_path = "" + fingerprint = "" +} \ No newline at end of file diff --git a/labs/oracle/Module-03 State/Example-3-2/Code/main.tf b/labs/oracle/Module-03 State/Example-3-2/Code/main.tf new file mode 100644 index 00000000..39d44887 --- /dev/null +++ b/labs/oracle/Module-03 State/Example-3-2/Code/main.tf @@ -0,0 +1,28 @@ +resource "oci_core_instance" "VM" { + # Required + availability_domain = data.oci_identity_availability_domains.ads.availability_domains[0].name + compartment_id = "ocid1.tenancy.oc1..aaaaaaaa6ag77lnluy7avrzhjkg7g3kriz5t5u2jnsw43yecx4oylzxsv5uq" + shape = "VM.Standard2.1" + source_details { + source_id = "ocid1.image.oc1.uk-london-1.aaaaaaaa3lb354447utq7gq6v3hqvo7u3nrkbf5fxmdxfem5jq4ngy4rtxba" + source_type = "image" + } + + # Optional + display_name = "Instance_VM" + create_vnic_details { + assign_public_ip = true + subnet_id = "ocid1.subnet.oc1.uk-london-1.aaaaaaaa6n3zzrw6xnv2capcbpxwht4zr72uoxnnxvbrp5vcqmg56p7zaszq" + } + + preserve_boot_volume = false +} + +data "oci_identity_availability_domains" "ads" { + compartment_id = var.compartment_id +} + + + + + diff --git a/labs/oracle/Module-03 State/Example-3-2/Code/providers.tf b/labs/oracle/Module-03 State/Example-3-2/Code/providers.tf new file mode 100644 index 00000000..7f706e3d --- /dev/null +++ b/labs/oracle/Module-03 State/Example-3-2/Code/providers.tf @@ -0,0 +1,6 @@ +provider "oci" { + tenancy_ocid = "" + user_ocid = "" + private_key_path = "" + fingerprint = "" +} \ No newline at end of file diff --git a/labs/oracle/Module-03 State/Example-3-3/Code/main.tf b/labs/oracle/Module-03 State/Example-3-3/Code/main.tf new file mode 100644 index 00000000..dbbcb0bb --- /dev/null +++ b/labs/oracle/Module-03 State/Example-3-3/Code/main.tf @@ -0,0 +1,23 @@ +resource "oci_core_instance" "Y" { + # Required + availability_domain = data.oci_identity_availability_domains.ads.availability_domains[0].name + compartment_id = "ocid1.tenancy.oc1..aaaaaaaa6ag77lnluy7avrzhjkg7g3kriz5t5u2jnsw43yecx4oylzxsv5uq" + shape = "VM.Standard2.1" + source_details { + source_id = "ocid1.image.oc1.uk-london-1.aaaaaaaa3lb354447utq7gq6v3hqvo7u3nrkbf5fxmdxfem5jq4ngy4rtxba" + source_type = "image" + } + + # Optional + display_name = "Instance_Y" + create_vnic_details { + assign_public_ip = true + subnet_id = "ocid1.subnet.oc1.uk-london-1.aaaaaaaa6n3zzrw6xnv2capcbpxwht4zr72uoxnnxvbrp5vcqmg56p7zaszq" + } + + preserve_boot_volume = false +} + +data "oci_identity_availability_domains" "ads" { + compartment_id = "ocid1.tenancy.oc1..aaaaaaaa6ag77lnluy7avrzhjkg7g3kriz5t5u2jnsw43yecx4oylzxsv5uq" +} \ No newline at end of file diff --git a/labs/oracle/Module-03 State/Example-3-3/Code/providers.tf b/labs/oracle/Module-03 State/Example-3-3/Code/providers.tf new file mode 100644 index 00000000..48150bcc --- /dev/null +++ b/labs/oracle/Module-03 State/Example-3-3/Code/providers.tf @@ -0,0 +1,14 @@ +terraform { + backend "http" { + address = "https://objectstorage.uk-london-1.oraclecloud.com/p/J1Z9AB_-KZ8nQOEOtYZfcT6NgoI7-NVO-Jejauuuvf5dshUv8kXfOflN1l8uf6dt/n/lrsivuswtz6j/b/himkum_bucket_500/o/terraform.tfstate" + update_method = "PUT" + } +} + +provider "oci" { + tenancy_ocid = "" + user_ocid = "" + private_key_path = "" + fingerprint = "" +} + diff --git a/labs/oracle/Module-03 State/Examples.md b/labs/oracle/Module-03 State/Examples.md new file mode 100644 index 00000000..589875e5 --- /dev/null +++ b/labs/oracle/Module-03 State/Examples.md @@ -0,0 +1,78 @@ +# Examples Notes + +These notes document how I work with the examples in the Terraform class. + +## Module 3 + +There is not a lot of code writing in module 3; instead, there is a lot of manipulating a set of EC2 instances to illustrate how they are maintained in the state file + +The basic code used is in the example 3-1 folder + +### Example 3-1 + +This example is used to provide practical demos of the comments made about state. The configuration is simple - just two VMS. What I demo in this example is the same as what the students will do in the lab, so they get to see it before they try it. + +I would suggest having a running VM created at the console to show that all of the terraform operations do not affect non-terraform resources + +The specific things I demonstrate are: + +1. Commenting out a VM resource and show that terraform deletes the running vm +2. The state list and show commands +3. Making a change in the running VM, usually the Name, then showing how terraform reverts the running VM to conform to the specification +3. Making a non-destructive change in the code to a VM, usually changing the instance type and showing how terraform does a change in place +4. Making a destructive chance, like the ami from amazon linux to ubuntu, to show how the resource is recreated +5. Using the state rm command to remove a VM from terraform, showing that it is still running in AWS and terraform can no longer see it and will try and create a new version +6. Using the import command to add the removed vm back into terraform +7. Create a copy of one of the instance definitions but with a different name then use the state mv command to rename one of the instances to the new name. Since the old name is no longer associated with the running instance, terraform will plan to create one +8. Finally, the use of the taint and untaint commands are shown + +### Example 3-2 + +This example is a preview of lab 3-2 demonstrating the use of workspaces. I use very simple code with just a single VM + +1. The VM is tagged with the Name "default" +2. Run apply to create the VM +3. Show the state file in the root directory and the running VM in the console +4. Create workspace "dev" and switch to it +5. Retag the VM with the name "dev" +6. Run terraform apply and show there are two VMs, one named "default" and one named "dev" +7. Show the workspace state files that have been created +8. Switch back to the default workspace and run terraform plan to show that the default VM will be altered in place and that this is not what we want +9. Try to delete the "dev" workspace and notice the terraform warning +10. Switch to dev and run destroy +11. switch back to default and run destroy + + +I end this demo by underscoring that there are two different things that have to be managed +* The state files, which terraform manages +* The source code *tf file that we manage + +The takeaway that leads onto the next example is that with sloppy source code management, we can corrupt our state + +### Example 3-3 + +This example requires that you have git installed. + +1. Using the same code from the previous example, make sure the VM is named "default" +2. Create a git repo, add main.tf to the repo and commit. The default workspace is now using the main git branch +3. Run terraform apply +4. Switch to the "dev" workspace +5. Create and checkout a branch called "dev" +6. Rename the instance to "dev" and run terraform apply +7. Examine both machines in AWS to ensure they are running +8. Switch to the default workspace +9. Checkout the main git branch +10. Run terraform plan to see that code changes on the dev branch will not affect default + +This will be the only place where git will be demonstrated. Point out that the danger of this approach is that forgetting to check out the right branch when you switch workspaces could step on other people's code. + +Clean up and destroy all the resources used in this demo + +### Example 3-4 + +Example walks through the setting up of the remote backend + + + + + diff --git a/labs/oracle/Module-04 HCL/Example-04-01/code/main.tf b/labs/oracle/Module-04 HCL/Example-04-01/code/main.tf new file mode 100644 index 00000000..4b83378c --- /dev/null +++ b/labs/oracle/Module-04 HCL/Example-04-01/code/main.tf @@ -0,0 +1,14 @@ +resource "oci_objectstorage_bucket" "test_bucket" { + + count = 3 + + #Required + compartment_id = "ocid1.tenancy.oc1..aaaaaaaa6ag77lnluy7avrzhjkg7g3kriz5t5u2jnsw43yecx4oylzxsv5uq" + name = "himkum_bucket_${count.index}" + namespace = "lrsivuswtz6j" +} + + + + + diff --git a/labs/oracle/Module-04 HCL/Example-04-01/code/providers.tf b/labs/oracle/Module-04 HCL/Example-04-01/code/providers.tf new file mode 100644 index 00000000..7f706e3d --- /dev/null +++ b/labs/oracle/Module-04 HCL/Example-04-01/code/providers.tf @@ -0,0 +1,6 @@ +provider "oci" { + tenancy_ocid = "" + user_ocid = "" + private_key_path = "" + fingerprint = "" +} \ No newline at end of file diff --git a/labs/oracle/Module-04 HCL/Example-04-02/code/main.tf b/labs/oracle/Module-04 HCL/Example-04-02/code/main.tf new file mode 100644 index 00000000..7b4ec29c --- /dev/null +++ b/labs/oracle/Module-04 HCL/Example-04-02/code/main.tf @@ -0,0 +1,30 @@ +resource "oci_objectstorage_bucket" "Matrix" { + + count = length(var.bucket_names) + + #Required + compartment_id = "ocid1.tenancy.oc1..aaaaaaaa6ag77lnluy7avrzhjkg7g3kriz5t5u2jnsw43yecx4oylzxsv5uq" + name = "himkum_bucket_${var.bucket_names[count.index]}" + namespace = "lrsivuswtz6j" +} + + +variable "bucket_names" { + type = list(string) + default = ["Neo", "Morpheus"] +} + +output "Neo" { + value = oci_objectstorage_bucket.Matrix[0].name + description = "Outputs a single string" +} +output "Everyone" { + value = oci_objectstorage_bucket.Matrix[*].name + description = "Outputs a list of strings" +} + + + + + + diff --git a/labs/oracle/Module-04 HCL/Example-04-02/code/providers.tf b/labs/oracle/Module-04 HCL/Example-04-02/code/providers.tf new file mode 100644 index 00000000..7f706e3d --- /dev/null +++ b/labs/oracle/Module-04 HCL/Example-04-02/code/providers.tf @@ -0,0 +1,6 @@ +provider "oci" { + tenancy_ocid = "" + user_ocid = "" + private_key_path = "" + fingerprint = "" +} \ No newline at end of file diff --git a/labs/oracle/Module-04 HCL/Example-04-03/code/main.tf b/labs/oracle/Module-04 HCL/Example-04-03/code/main.tf new file mode 100644 index 00000000..f69e1d39 --- /dev/null +++ b/labs/oracle/Module-04 HCL/Example-04-03/code/main.tf @@ -0,0 +1,19 @@ +resource "oci_objectstorage_bucket" "Matrix" { + + for_each = toset(var.bucket_names) + + #Required + compartment_id = "ocid1.tenancy.oc1..aaaaaaaa6ag77lnluy7avrzhjkg7g3kriz5t5u2jnsw43yecx4oylzxsv5uq" + name = "himkum_bucket_${each.value}" + namespace = "lrsivuswtz6j" +} + + +variable "bucket_names" { + type = list(string) + default = ["Neo", "Morpheus"] +} + + + + diff --git a/labs/oracle/Module-04 HCL/Example-04-03/code/providers.tf b/labs/oracle/Module-04 HCL/Example-04-03/code/providers.tf new file mode 100644 index 00000000..7f706e3d --- /dev/null +++ b/labs/oracle/Module-04 HCL/Example-04-03/code/providers.tf @@ -0,0 +1,6 @@ +provider "oci" { + tenancy_ocid = "" + user_ocid = "" + private_key_path = "" + fingerprint = "" +} \ No newline at end of file diff --git a/labs/oracle/Module-04 HCL/Example-04-04/code/main.tf b/labs/oracle/Module-04 HCL/Example-04-04/code/main.tf new file mode 100644 index 00000000..e69de29b diff --git a/labs/oracle/Module-04 HCL/Example-04-04/code/providers.tf b/labs/oracle/Module-04 HCL/Example-04-04/code/providers.tf new file mode 100644 index 00000000..7f706e3d --- /dev/null +++ b/labs/oracle/Module-04 HCL/Example-04-04/code/providers.tf @@ -0,0 +1,6 @@ +provider "oci" { + tenancy_ocid = "" + user_ocid = "" + private_key_path = "" + fingerprint = "" +} \ No newline at end of file diff --git a/labs/oracle/Module-04 HCL/Example-04-05/code/main.tf b/labs/oracle/Module-04 HCL/Example-04-05/code/main.tf new file mode 100644 index 00000000..e69de29b diff --git a/labs/oracle/Module-04 HCL/Example-04-05/code/providers.tf b/labs/oracle/Module-04 HCL/Example-04-05/code/providers.tf new file mode 100644 index 00000000..7f706e3d --- /dev/null +++ b/labs/oracle/Module-04 HCL/Example-04-05/code/providers.tf @@ -0,0 +1,6 @@ +provider "oci" { + tenancy_ocid = "" + user_ocid = "" + private_key_path = "" + fingerprint = "" +} \ No newline at end of file diff --git a/labs/oracle/Module-04 HCL/Example-04-06/code/main.tf b/labs/oracle/Module-04 HCL/Example-04-06/code/main.tf new file mode 100644 index 00000000..af1febac --- /dev/null +++ b/labs/oracle/Module-04 HCL/Example-04-06/code/main.tf @@ -0,0 +1,13 @@ + variable "names" { + description = "A list of names" + type = list(string) + default = ["neo", "trinity", "morpheus"] + } + + output "upper_names" { + value = [for name in var.names : upper(name)] + } + + output "short_upper_names" { + value = [for name in var.names : upper(name) if length(name) < 5] + } \ No newline at end of file diff --git a/labs/oracle/Module-04 HCL/Example-04-06/code/providers.tf b/labs/oracle/Module-04 HCL/Example-04-06/code/providers.tf new file mode 100644 index 00000000..7f706e3d --- /dev/null +++ b/labs/oracle/Module-04 HCL/Example-04-06/code/providers.tf @@ -0,0 +1,6 @@ +provider "oci" { + tenancy_ocid = "" + user_ocid = "" + private_key_path = "" + fingerprint = "" +} \ No newline at end of file diff --git a/labs/oracle/Module-04 HCL/Example-04-07/code/main.tf b/labs/oracle/Module-04 HCL/Example-04-07/code/main.tf new file mode 100644 index 00000000..8216960b --- /dev/null +++ b/labs/oracle/Module-04 HCL/Example-04-07/code/main.tf @@ -0,0 +1,17 @@ +variable "hero_thousand_faces" { + description = "map" + type = map(string) + default = { + neo = "hero" + trinity = "love interest" + morpheus = "mentor" + } +} + +output "bios" { + value = [for name, role in var.hero_thousand_faces : "${name} is the ${role}"] +} + + output "upper_roles" { + value = {for name, role in var.hero_thousand_faces : upper(name) => upper(role)} + } \ No newline at end of file diff --git a/labs/oracle/Module-04 HCL/Example-04-07/code/providers.tf b/labs/oracle/Module-04 HCL/Example-04-07/code/providers.tf new file mode 100644 index 00000000..7f706e3d --- /dev/null +++ b/labs/oracle/Module-04 HCL/Example-04-07/code/providers.tf @@ -0,0 +1,6 @@ +provider "oci" { + tenancy_ocid = "" + user_ocid = "" + private_key_path = "" + fingerprint = "" +} \ No newline at end of file diff --git a/labs/oracle/Module-04 HCL/Example-04-08/code/main.tf b/labs/oracle/Module-04 HCL/Example-04-08/code/main.tf new file mode 100644 index 00000000..d2ebd8bc --- /dev/null +++ b/labs/oracle/Module-04 HCL/Example-04-08/code/main.tf @@ -0,0 +1,27 @@ +variable "names" { + description = "Names to render" + type = list(string) + default = ["neo", "trinity", "morpheus"] +} + +output "for_directive" { + + value = < index.html + nohup busybox httpd -f -p 8080 & + EOF + + tags = { + Name = "${var.app_name} App" + } + vpc_security_group_ids = [data.aws_security_group.default.id] + + +} \ No newline at end of file diff --git a/labs/oracle/Module-07 Testing/Example-7-2/code/step-1/EC2/variables.tf b/labs/oracle/Module-07 Testing/Example-7-2/code/step-1/EC2/variables.tf new file mode 100644 index 00000000..aac6205c --- /dev/null +++ b/labs/oracle/Module-07 Testing/Example-7-2/code/step-1/EC2/variables.tf @@ -0,0 +1,28 @@ +variable "ami_type" { + description = "The ami to use depending on region" + type = string + default = "ami-03d315ad33b9d49c4" +} + +variable "instance_type" { + description = "The instance class to use" + type = string + default = "t2.small" +} + +variable "access_port" { + description = "Access port to use for the application" + type = number + default = 80 +} + +variable "app_name" { + description = "The name of the application deployment" + type = string + default = "No Name" +} + +variable "sg_groups" { + description = "Associated security groups" + type = list(string) +} diff --git a/labs/oracle/Module-07 Testing/Example-7-2/code/step-1/SG/main.tf b/labs/oracle/Module-07 Testing/Example-7-2/code/step-1/SG/main.tf new file mode 100644 index 00000000..08ef0011 --- /dev/null +++ b/labs/oracle/Module-07 Testing/Example-7-2/code/step-1/SG/main.tf @@ -0,0 +1,21 @@ +resource "aws_security_group" "app_port" { + description = " Security group to allow access app instance" + ingress { + description = "OpenPort" + from_port = var.access_port + to_port = var.access_port + protocol = "tcp" + cidr_blocks = ["0.0.0.0/0"] + } + + egress { + from_port = 0 + to_port = 0 + protocol = "-1" + cidr_blocks = ["0.0.0.0/0"] + } + + tags = { + Name = var.sg_name + } +} diff --git a/labs/oracle/Module-07 Testing/Example-7-2/code/step-1/SG/output.tf b/labs/oracle/Module-07 Testing/Example-7-2/code/step-1/SG/output.tf new file mode 100644 index 00000000..ce2cef5f --- /dev/null +++ b/labs/oracle/Module-07 Testing/Example-7-2/code/step-1/SG/output.tf @@ -0,0 +1,4 @@ + +output "secgps" { + value =aws_security_group.app_port.id +} \ No newline at end of file diff --git a/labs/oracle/Module-07 Testing/Example-7-2/code/step-1/SG/variables.tf b/labs/oracle/Module-07 Testing/Example-7-2/code/step-1/SG/variables.tf new file mode 100644 index 00000000..e453d4ce --- /dev/null +++ b/labs/oracle/Module-07 Testing/Example-7-2/code/step-1/SG/variables.tf @@ -0,0 +1,13 @@ + +variable "access_port" { + description = "Access port to use for the application" + type = number + default = 80 +} + +variable "sg_name" { + description = "The name of the security group" + type = string + default = "My SG" +} + diff --git a/labs/oracle/Module-07 Testing/Example-7-2/code/step-1/root/main.tf b/labs/oracle/Module-07 Testing/Example-7-2/code/step-1/root/main.tf new file mode 100644 index 00000000..821f79f7 --- /dev/null +++ b/labs/oracle/Module-07 Testing/Example-7-2/code/step-1/root/main.tf @@ -0,0 +1,19 @@ +// Starting point + +module "SecGrp" { + source = "../SG" + access_port = var.access_port + sg_name = "Test SG" +} + +module "hello_app" { + source = "../EC2" + instance_type = var.instance_type + app_name = var.app_name + sg_groups = [module.SecGrp.secgps] + +} + +data "aws_security_group" "default_sg" { + name = "default" +} diff --git a/labs/oracle/Module-07 Testing/Example-7-2/code/step-1/root/outputs.tf b/labs/oracle/Module-07 Testing/Example-7-2/code/step-1/root/outputs.tf new file mode 100644 index 00000000..9a3275b6 --- /dev/null +++ b/labs/oracle/Module-07 Testing/Example-7-2/code/step-1/root/outputs.tf @@ -0,0 +1,10 @@ +/*output "app_id" { + description = "Id of the hello apps" + value = [aws_instance.hello_app1.id,aws_instance.hello_app2.id] +} + +output "app_ip" { + description = "Public ip of the hello app" + value = [aws_instance.hello_app1.public_ip,aws_instance.hello_app1.public_ip] +} +*/ \ No newline at end of file diff --git a/labs/oracle/Module-07 Testing/Example-7-2/code/step-1/root/providers.tf b/labs/oracle/Module-07 Testing/Example-7-2/code/step-1/root/providers.tf new file mode 100644 index 00000000..95e0e996 --- /dev/null +++ b/labs/oracle/Module-07 Testing/Example-7-2/code/step-1/root/providers.tf @@ -0,0 +1,15 @@ +terraform { + required_providers { + aws = { + source = "hashicorp/aws" + version = ">= 3.0" + } + } + # Required version of terraform + required_version = ">0.14" +} + +provider "aws" { + region = "us-east-2" + profile = "dev" +} \ No newline at end of file diff --git a/labs/oracle/Module-07 Testing/Example-7-2/code/step-1/root/terraform.tfvars b/labs/oracle/Module-07 Testing/Example-7-2/code/step-1/root/terraform.tfvars new file mode 100644 index 00000000..f7d59f17 --- /dev/null +++ b/labs/oracle/Module-07 Testing/Example-7-2/code/step-1/root/terraform.tfvars @@ -0,0 +1,4 @@ + +access_port = 8080 +app_name = "zippy" +instance_type = "t2.nano" \ No newline at end of file diff --git a/labs/oracle/Module-07 Testing/Example-7-2/code/step-1/root/variables.tf b/labs/oracle/Module-07 Testing/Example-7-2/code/step-1/root/variables.tf new file mode 100644 index 00000000..23b614ee --- /dev/null +++ b/labs/oracle/Module-07 Testing/Example-7-2/code/step-1/root/variables.tf @@ -0,0 +1,18 @@ + +variable "instance_type" { + description = "The instance type to use" + type = string +} + + +variable "access_port" { + description = "Access port to use for the application" + type = number + default = 80 +} + +variable "app_name" { + description = "The name of the application deployment" + type = string +} + diff --git a/labs/oracle/Module-07 Testing/Example-7-2/code/step-2/EC2/data.tf b/labs/oracle/Module-07 Testing/Example-7-2/code/step-2/EC2/data.tf new file mode 100644 index 00000000..467051cc --- /dev/null +++ b/labs/oracle/Module-07 Testing/Example-7-2/code/step-2/EC2/data.tf @@ -0,0 +1,21 @@ + +data "aws_ami" "ubuntu" { + most_recent = true + + filter { + name = "name" + values = ["ubuntu/images/hvm-ssd/ubuntu-focal-20.04-amd64-server-*"] + } + + filter { + name = "virtualization-type" + values = ["hvm"] + } + + owners = ["099720109477"] # Canonical +} + +data "aws_security_group" "default" { + name = "default" +} + diff --git a/labs/oracle/Module-07 Testing/Example-7-2/code/step-2/EC2/main.tf b/labs/oracle/Module-07 Testing/Example-7-2/code/step-2/EC2/main.tf new file mode 100644 index 00000000..a602404a --- /dev/null +++ b/labs/oracle/Module-07 Testing/Example-7-2/code/step-2/EC2/main.tf @@ -0,0 +1,22 @@ +resource "aws_instance" "hello_app" { + + ami = data.aws_ami.ubuntu.id + instance_type = var.instance_type + + + user_data = <<-EOF + #!/bin/bash + echo "Hello, World" > index.html + nohup busybox httpd -f -p 8080 & + EOF + + tags = { + Name = "${var.app_name} App" + } + vpc_security_group_ids = [data.aws_security_group.default.id] + +} + +output "my_instance" { + value = aws_instance.hello_app +} \ No newline at end of file diff --git a/labs/oracle/Module-07 Testing/Example-7-2/code/step-2/EC2/variables.tf b/labs/oracle/Module-07 Testing/Example-7-2/code/step-2/EC2/variables.tf new file mode 100644 index 00000000..aac6205c --- /dev/null +++ b/labs/oracle/Module-07 Testing/Example-7-2/code/step-2/EC2/variables.tf @@ -0,0 +1,28 @@ +variable "ami_type" { + description = "The ami to use depending on region" + type = string + default = "ami-03d315ad33b9d49c4" +} + +variable "instance_type" { + description = "The instance class to use" + type = string + default = "t2.small" +} + +variable "access_port" { + description = "Access port to use for the application" + type = number + default = 80 +} + +variable "app_name" { + description = "The name of the application deployment" + type = string + default = "No Name" +} + +variable "sg_groups" { + description = "Associated security groups" + type = list(string) +} diff --git a/labs/oracle/Module-07 Testing/Example-7-2/code/step-2/SG/main.tf b/labs/oracle/Module-07 Testing/Example-7-2/code/step-2/SG/main.tf new file mode 100644 index 00000000..08ef0011 --- /dev/null +++ b/labs/oracle/Module-07 Testing/Example-7-2/code/step-2/SG/main.tf @@ -0,0 +1,21 @@ +resource "aws_security_group" "app_port" { + description = " Security group to allow access app instance" + ingress { + description = "OpenPort" + from_port = var.access_port + to_port = var.access_port + protocol = "tcp" + cidr_blocks = ["0.0.0.0/0"] + } + + egress { + from_port = 0 + to_port = 0 + protocol = "-1" + cidr_blocks = ["0.0.0.0/0"] + } + + tags = { + Name = var.sg_name + } +} diff --git a/labs/oracle/Module-07 Testing/Example-7-2/code/step-2/SG/output.tf b/labs/oracle/Module-07 Testing/Example-7-2/code/step-2/SG/output.tf new file mode 100644 index 00000000..ce2cef5f --- /dev/null +++ b/labs/oracle/Module-07 Testing/Example-7-2/code/step-2/SG/output.tf @@ -0,0 +1,4 @@ + +output "secgps" { + value =aws_security_group.app_port.id +} \ No newline at end of file diff --git a/labs/oracle/Module-07 Testing/Example-7-2/code/step-2/SG/variables.tf b/labs/oracle/Module-07 Testing/Example-7-2/code/step-2/SG/variables.tf new file mode 100644 index 00000000..e453d4ce --- /dev/null +++ b/labs/oracle/Module-07 Testing/Example-7-2/code/step-2/SG/variables.tf @@ -0,0 +1,13 @@ + +variable "access_port" { + description = "Access port to use for the application" + type = number + default = 80 +} + +variable "sg_name" { + description = "The name of the security group" + type = string + default = "My SG" +} + diff --git a/labs/oracle/Module-07 Testing/Example-7-2/code/step-2/root/main.tf b/labs/oracle/Module-07 Testing/Example-7-2/code/step-2/root/main.tf new file mode 100644 index 00000000..34e59559 --- /dev/null +++ b/labs/oracle/Module-07 Testing/Example-7-2/code/step-2/root/main.tf @@ -0,0 +1,16 @@ +// Starting point + +module "SecGrp" { + source = "../SG" + access_port = var.access_port + sg_name = "Test SG" +} + +module "hello_app" { + source = "../EC2" + instance_type = var.instance_type + app_name = var.app_name + sg_groups = [module.SecGrp.secgps] + +} + diff --git a/labs/oracle/Module-07 Testing/Example-7-2/code/step-2/root/outputs.tf b/labs/oracle/Module-07 Testing/Example-7-2/code/step-2/root/outputs.tf new file mode 100644 index 00000000..9a3275b6 --- /dev/null +++ b/labs/oracle/Module-07 Testing/Example-7-2/code/step-2/root/outputs.tf @@ -0,0 +1,10 @@ +/*output "app_id" { + description = "Id of the hello apps" + value = [aws_instance.hello_app1.id,aws_instance.hello_app2.id] +} + +output "app_ip" { + description = "Public ip of the hello app" + value = [aws_instance.hello_app1.public_ip,aws_instance.hello_app1.public_ip] +} +*/ \ No newline at end of file diff --git a/labs/oracle/Module-07 Testing/Example-7-2/code/step-2/root/providers.tf b/labs/oracle/Module-07 Testing/Example-7-2/code/step-2/root/providers.tf new file mode 100644 index 00000000..95e0e996 --- /dev/null +++ b/labs/oracle/Module-07 Testing/Example-7-2/code/step-2/root/providers.tf @@ -0,0 +1,15 @@ +terraform { + required_providers { + aws = { + source = "hashicorp/aws" + version = ">= 3.0" + } + } + # Required version of terraform + required_version = ">0.14" +} + +provider "aws" { + region = "us-east-2" + profile = "dev" +} \ No newline at end of file diff --git a/labs/oracle/Module-07 Testing/Example-7-2/code/step-2/root/terraform.tfvars b/labs/oracle/Module-07 Testing/Example-7-2/code/step-2/root/terraform.tfvars new file mode 100644 index 00000000..f7d59f17 --- /dev/null +++ b/labs/oracle/Module-07 Testing/Example-7-2/code/step-2/root/terraform.tfvars @@ -0,0 +1,4 @@ + +access_port = 8080 +app_name = "zippy" +instance_type = "t2.nano" \ No newline at end of file diff --git a/labs/oracle/Module-07 Testing/Example-7-2/code/step-2/root/tests.tf b/labs/oracle/Module-07 Testing/Example-7-2/code/step-2/root/tests.tf new file mode 100644 index 00000000..2a4eebea --- /dev/null +++ b/labs/oracle/Module-07 Testing/Example-7-2/code/step-2/root/tests.tf @@ -0,0 +1,3 @@ +output "Integration_Test_1" { + value = (module.hello_app.my_instance.vpc_security_group_ids == module.SecGrp.secgps) +} \ No newline at end of file diff --git a/labs/oracle/Module-07 Testing/Example-7-2/code/step-2/root/variables.tf b/labs/oracle/Module-07 Testing/Example-7-2/code/step-2/root/variables.tf new file mode 100644 index 00000000..23b614ee --- /dev/null +++ b/labs/oracle/Module-07 Testing/Example-7-2/code/step-2/root/variables.tf @@ -0,0 +1,18 @@ + +variable "instance_type" { + description = "The instance type to use" + type = string +} + + +variable "access_port" { + description = "Access port to use for the application" + type = number + default = 80 +} + +variable "app_name" { + description = "The name of the application deployment" + type = string +} + diff --git a/labs/oracle/Module-07 Testing/Example-7-2/code/step-2/root/vars.tf b/labs/oracle/Module-07 Testing/Example-7-2/code/step-2/root/vars.tf new file mode 100644 index 00000000..58951f36 --- /dev/null +++ b/labs/oracle/Module-07 Testing/Example-7-2/code/step-2/root/vars.tf @@ -0,0 +1,27 @@ + + +module "asg" { + source = "../../modules/cluster/asg-rolling-deploy" + + cluster_name = var.cluster_name + ami = "ami-0c55b159cbfafe1f0" + instance_type = "t2.micro" + + min_size = 1 + max_size = 1 + enable_autoscaling = false + + subnet_ids = data.aws_subnet_ids.default.ids +} + +data "aws_vpc" "default" { + default = true +} + +data "aws_subnet_ids" "default" { + vpc_id = data.aws_vpc.default.id +} + + + + diff --git a/labs/oracle/Module-07 Testing/Examples-07.md b/labs/oracle/Module-07 Testing/Examples-07.md new file mode 100644 index 00000000..b532c0f5 --- /dev/null +++ b/labs/oracle/Module-07 Testing/Examples-07.md @@ -0,0 +1,56 @@ + +# Examples for Module 7 - Testing + +The two examples provided illustrate a basic unit test and a basic integration test using only terraform HCL code. These examples are intended to only show test thinking when it comes to terraform and not establish a methodology for doing testing. + +The code is very simplistic since it is intended to demonstrate some testing ideas, and using overly complex code would distract from the underlying teaching points. + +One point to make is that we don't actually need sophisticated testing tools to write basic automated tests -- we can even use terraform HCL to write tests + +## Example One - Unit Testing a Module + +The unit being tested in example one is a module that takes a string as input and creates a bucket with that name. However, the module does not create a bucket with the correct name since there is some development code that uses a local name for the bucket instead. This code was inadvertently not removed after development. + +In this case, the error is obvious and would be found with even a cursory inspection, but again, this is a very simplistic example. + +### Step one + +1. Run the code in the step one directory +2. Look in terraform.tfvars file to show the expected bucket name +3. The code runs without any errors or warnings, but fails to produce the right bucket + +The takeaway is that in a more complicated deployment, this sort of error may not be noticed until things start failing, and then we have to start what might be a massive bug hunt. + +### Step two + +1. The first thing to be done is to make the Bucket module testable. There is no way to reference the created bucket to check any of its attributes +2. An output variable is created that returns the id of the created bucket +3. A test is added using an output that compares the id of the bucket with the value provided to the module + +### Step three + +1. The incorrect code is removed, and the test passes + +--- + +## Example Two - Integration Testing + +In this example, we have two modules, one creating an EC2 instance web server, and the other creating a security group. We can begin with the assumption that both modules work perfectly. + +Integration testing is essentially ensuring we are connecting the parts of our infrastructure together correctly. + +In this example, the problem will be omitted code. There will be nothing to connect the security group to the EC2 server + +### Step One + +1. Create the infrastructure and note that while there are no errors or warning, the resulting webserver does not work. +2. The problem is an integration error. The security group module works correctly, the EC2 module works correctly, but the error is that we connect the wrong security group to the EC2 instance. +3. There is a reference to the default security group in our code derived from a data block. This may be left over from some development work, but we connect to this instead of the actual security group we created for the application + +### Step Two + +1. Add the integration test to ensure that the security group we created is in fact the security group that the web server is using (this is the integration part) + +2. Run the test and see the test fail + +3. Add in the missing code and the test passes and the \ No newline at end of file diff --git a/labs/oracle/lab-01/availability-domains.tf b/labs/oracle/lab-01/availability-domains.tf new file mode 100644 index 00000000..44cc091e --- /dev/null +++ b/labs/oracle/lab-01/availability-domains.tf @@ -0,0 +1,8 @@ +# Source from https://registry.terraform.io/providers/oracle/oci/latest/docs/data-sources/identity_availability_domains + +# is the compartment OCID for the root compartment. +# Use for the compartment OCID. + +data "oci_identity_availability_domains" "ads" { + compartment_id = "ocid1.tenancy.oc1..aaaaaaaa6ag77lnluy7avrzhjkg7g3kriz5t5u2jnsw43yecx4oylzxsv5uq" +} \ No newline at end of file diff --git a/labs/oracle/lab-01/outputs.tf b/labs/oracle/lab-01/outputs.tf new file mode 100644 index 00000000..2f747106 --- /dev/null +++ b/labs/oracle/lab-01/outputs.tf @@ -0,0 +1,4 @@ +# Output the "list" of all availability domains. +output "all-availability-domains-in-your-tenancy" { + value = data.oci_identity_availability_domains.ads.availability_domains +} \ No newline at end of file diff --git a/labs/oracle/lab-01/provider.tf b/labs/oracle/lab-01/provider.tf new file mode 100644 index 00000000..7b0327d8 --- /dev/null +++ b/labs/oracle/lab-01/provider.tf @@ -0,0 +1,6 @@ +provider "oci" { + tenancy_ocid = "" + user_ocid = "" + private_key_path = "" + fingerprint = "" +} \ No newline at end of file diff --git a/labs/oracle/lab-01/readme.md b/labs/oracle/lab-01/readme.md new file mode 100644 index 00000000..ea3a78fc --- /dev/null +++ b/labs/oracle/lab-01/readme.md @@ -0,0 +1,131 @@ +# Terraform: Set Up OCI Terraform + +## Prepare + +* Get Tenancy Information + + - Collect the following information from the Oracle Cloud Infrastructure Console and copy it into your notepad. + + - Tenancy OCID: (tenancy-ocid) + From your user avatar, go to Tenancy: (your-tenancy) and copy OCID. + +* Add Compartment Policy + + - If your username is in the Administrators group, then skip this section. Otherwise, have your administrator add the following policy to your tenancy + + - Steps to Add the Policy + + - In the top navigation bar, open the Profile menu. + - Click your username. + - In the left pane, click Groups. + - In a notepad, copy the Group Name that your username belongs. + - Open the navigation menu and click Identity & Security. Under Identity, click Policies. + - Select your compartment from the Compartment drop-down. + - Click Create Policy. + - Fill in the following information: + - Name: manage-compartments + - Description: Allow the group to list, create, update, delete and recover compartments in the tenancy. + - Compartment: (root) + - For Policy Builder, click Show manual editor. + - Paste in the following policy: + ``` + allow group to manage compartments in tenancy + ``` + - Click Create. + +## Create Scripts + +* Create three scripts: one for authentication, one to fetch data from your account, and one to print outputs. + + - availability-domains.tf + - output.tf+ + - provider.tf + +## Run Script + +* Initialize + - Initialize a working directory in the current directory. + ``` + terraform init + ``` + + - Check the contents of the working directory. + ``` + ls -a + ``` + You now have a folder called .terraform that includes the plugins for the oci provider. + +* Plan + + - Create an execution plan to check whether the changes shown in the execution plan match your expectations, without changing the real resources. + ``` + terraform plan + ``` + - Confirm that you have Plan: 0 to add, 0 to change, 0 to destroy. + + Example output: + + ``` + Changes to Outputs: + + all-availability-domains-in-your-tenancy = [ + + { + + compartment_id = "ocid1.tenancy.oc1..xxx" + + id = "ocid1.availabilitydomain.xxx" + + name = "QnsC:US-ASHBURN-AD-1" + }, + + { + + compartment_id = "ocid1.tenancy.oc1..xxx" + + id = "ocid1.availabilitydomain.xxx" + + name = "QnsC:US-ASHBURN-AD-2" + }, + + { + + compartment_id = "ocid1.tenancy.oc1..xxx" + + id = "ocid1.availabilitydomain.xxx" + + name = "QnsC:US-ASHBURN-AD-3" + }, + ] + + You can apply this plan to save these new output values to the Terraform state, without changing any real + infrastructure. + ``` + - Note + + You are fetching data, so the plan shows that you are only adding outputs. You are not adding, changing, or destroying any resources. + +* Apply + + - Run your Terraform scripts and get your outputs: + + ``` + terraform apply + ``` + - When prompted for confirmation, enter yes, for your resource to be created. + + After you run the apply command, the output is displayed in the terminal. + + Example output: + ``` + Apply complete! Resources: 0 added, 0 changed, 0 destroyed. + + Outputs: + + all-availability-domains-in-your-tenancy = tolist([ + { + "compartment_id" = "ocid1.tenancy.xxx" + "id" = "ocid1.availabilitydomain.xxx" + "name" = "QnsC:US-ASHBURN-AD-1" + }, + { + "compartment_id" = "ocid1.tenancy.xxx" + "id" = "ocid1.availabilitydomain.xxx" + "name" = "QnsC:US-ASHBURN-AD-2" + }, + { + "compartment_id" = "ocid1.tenancy.xxx" + "id" = "ocid1.availabilitydomain.xxx" + "name" = "QnsC:US-ASHBURN-AD-3" + }, + ]) + ``` + +Congratulations! Your Oracle Cloud Infrastructure account can now authenticate your Oracle Cloud Infrastructure Terraform provider scripts. diff --git a/labs/oracle/lab-02/compartment.tf b/labs/oracle/lab-02/compartment.tf new file mode 100644 index 00000000..ae2a6531 --- /dev/null +++ b/labs/oracle/lab-02/compartment.tf @@ -0,0 +1,6 @@ +resource "oci_identity_compartment" "tf-compartment" { + # Required + compartment_id = "ocid1.tenancy.oc1..aaaaaaaa6ag77lnluy7avrzhjkg7g3kriz5t5u2jnsw43yecx4oylzxsv5uq" + description = "Compartment for Terraform resources." + name = "compartment_him_1" +} \ No newline at end of file diff --git a/labs/oracle/lab-02/outputs.tf b/labs/oracle/lab-02/outputs.tf new file mode 100644 index 00000000..c8b590c0 --- /dev/null +++ b/labs/oracle/lab-02/outputs.tf @@ -0,0 +1,9 @@ +# Outputs for compartment + +output "compartment-name" { + value = oci_identity_compartment.tf-compartment.name +} + +output "compartment-OCID" { + value = oci_identity_compartment.tf-compartment.id +} \ No newline at end of file diff --git a/labs/oracle/lab-02/provider.tf b/labs/oracle/lab-02/provider.tf new file mode 100644 index 00000000..7f706e3d --- /dev/null +++ b/labs/oracle/lab-02/provider.tf @@ -0,0 +1,6 @@ +provider "oci" { + tenancy_ocid = "" + user_ocid = "" + private_key_path = "" + fingerprint = "" +} \ No newline at end of file diff --git a/labs/oracle/lab-02/readme.md b/labs/oracle/lab-02/readme.md new file mode 100644 index 00000000..89917b90 --- /dev/null +++ b/labs/oracle/lab-02/readme.md @@ -0,0 +1,135 @@ +# Terraform: Create a Compartment + +## Prepare + +* Get Tenancy Information + + - Collect the following information from the Oracle Cloud Infrastructure Console and copy it into your notepad. + + - Tenancy OCID: (tenancy-ocid) + From your user avatar, go to Tenancy: (your-tenancy) and copy OCID. + +* Add Compartment Policy + + - If your username is in the Administrators group, then skip this section. Otherwise, have your administrator add the following policy to your tenancy + + - Steps to Add the Policy + + - In the top navigation bar, open the Profile menu. + - Click your username. + - In the left pane, click Groups. + - In a notepad, copy the Group Name that your username belongs. + - Open the navigation menu and click Identity & Security. Under Identity, click Policies. + - Select your compartment from the Compartment drop-down. + - Click Create Policy. + - Fill in the following information: + - Name: manage-compartments + - Description: Allow the group to list, create, update, delete and recover compartments in the tenancy. + - Compartment: (root) + - For Policy Builder, click Show manual editor. + - Paste in the following policy: + ``` + allow group to manage compartments in tenancy + ``` + - Click Create. + +## Create Scripts + +* Create three scripts: one for authentication, one to create a compartment, and one to print outputs. + + - compartment.tf + - output.tf + - provider.tf + +## Create a Compartment + +* Initialize + - Initialize a working directory in the current directory. + ``` + terraform init + ``` + + - Confirm that Terraform has been successfully initialized!. + + Example output: + ``` + Initializing the backend... + + Initializing provider plugins... + - Finding latest version of hashicorp/oci... + - Installing hashicorp/oci vx.x.x... + - Installed hashicorp/oci vx.x.x (signed by HashiCorp) + + Terraform has been successfully initialized! + ``` +* Plan + + - Create an execution plan to check whether the changes shown in the execution plan match your expectations, without changing the real resources. + ``` + terraform plan + ``` + - Confirm that you have Plan: 0 to add, 0 to change, 0 to destroy. + + Example output: + + ``` + 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: + + # oci_identity_compartment.tf-compartment will be created + + resource "oci_identity_compartment" "tf-compartment" { + + compartment_id = "ocid1.tenancy.xxx" + + defined_tags = (known after apply) + + description = "Compartment for Terraform resources." + + freeform_tags = (known after apply) + + id = (known after apply) + + inactive_state = (known after apply) + + is_accessible = (known after apply) + + name = "" + + state = (known after apply) + + time_created = (known after apply) + } + + Plan: 1 to add, 0 to change, 0 to destroy. + + Changes to Outputs: + + compartment-OCID = (known after apply) + + compartment-name = "" + ``` + +* Apply + + - Create your compartment with Terraform: + + ``` + terraform apply + ``` + - When prompted for confirmation, enter yes, for your resource to be created. + + - (Optional) Watch the creation from the Console: + + - Open the navigation menu and click Identity & Security. Under Identity, click Compartments. + + - Refresh the page, until you see the compartment name. + + - Click the compartment name to see its details such as its OCID. + + - In the output terminal, review your defined outputs. + + Example output: + ``` + oci_identity_compartment.tf-compartment: Creating... + oci_identity_compartment.tf-compartment: Creation complete after 9s [id=xxx] + + Apply complete! Resources: 1 added, 0 changed, 0 destroyed. + + Outputs: + + compartment-OCID = ocid1.compartment.xxx + compartment-name = + ``` + +Congratulations! You have successfully logged in and created a compartment in your tenancy, using the Oracle Cloud Infrastructure Terraform provider. \ No newline at end of file diff --git a/labs/oracle/lab-03/availability-domains.tf b/labs/oracle/lab-03/availability-domains.tf new file mode 100644 index 00000000..44cc091e --- /dev/null +++ b/labs/oracle/lab-03/availability-domains.tf @@ -0,0 +1,8 @@ +# Source from https://registry.terraform.io/providers/oracle/oci/latest/docs/data-sources/identity_availability_domains + +# is the compartment OCID for the root compartment. +# Use for the compartment OCID. + +data "oci_identity_availability_domains" "ads" { + compartment_id = "ocid1.tenancy.oc1..aaaaaaaa6ag77lnluy7avrzhjkg7g3kriz5t5u2jnsw43yecx4oylzxsv5uq" +} \ No newline at end of file diff --git a/labs/oracle/lab-03/compute.tf b/labs/oracle/lab-03/compute.tf new file mode 100644 index 00000000..287807bb --- /dev/null +++ b/labs/oracle/lab-03/compute.tf @@ -0,0 +1,19 @@ +resource "oci_core_instance" "ubuntu_instance" { + # Required + availability_domain = data.oci_identity_availability_domains.ads.availability_domains[0].name + compartment_id = "ocid1.compartment.oc1..aaaaaaaayf3gksj2b37farc2tep72goofuc25tzsd72blhdjmel54kwv2xla" + shape = "VM.Standard2.1" + source_details { + source_id = "ocid1.image.oc1.uk-london-1.aaaaaaaa3lb354447utq7gq6v3hqvo7u3nrkbf5fxmdxfem5jq4ngy4rtxba" + source_type = "image" + } + + # Optional + display_name = "himkum-ubuntu" + create_vnic_details { + assign_public_ip = true + subnet_id = "ocid1.subnet.oc1.uk-london-1.aaaaaaaa6n3zzrw6xnv2capcbpxwht4zr72uoxnnxvbrp5vcqmg56p7zaszq" + } + + preserve_boot_volume = false +} \ No newline at end of file diff --git a/labs/oracle/lab-03/outputs.tf b/labs/oracle/lab-03/outputs.tf new file mode 100644 index 00000000..359a50cd --- /dev/null +++ b/labs/oracle/lab-03/outputs.tf @@ -0,0 +1,45 @@ + +# The "name" of the availability domain to be used for the compute instance. +output "name-of-first-availability-domain" { + value = data.oci_identity_availability_domains.ads.availability_domains[0].name +} + + +# Outputs for compute instance + +output "public-ip-for-compute-instance" { + value = oci_core_instance.ubuntu_instance.public_ip +} + + +output "instance-name" { + value = oci_core_instance.ubuntu_instance.display_name +} + +output "instance-OCID" { + value = oci_core_instance.ubuntu_instance.id +} + +output "instance-region" { + value = oci_core_instance.ubuntu_instance.region +} + +output "instance-shape" { + value = oci_core_instance.ubuntu_instance.shape +} + +output "instance-state" { + value = oci_core_instance.ubuntu_instance.state +} + +output "instance-OCPUs" { + value = oci_core_instance.ubuntu_instance.shape_config[0].ocpus +} + +output "instance-memory-in-GBs" { + value = oci_core_instance.ubuntu_instance.shape_config[0].memory_in_gbs +} + +output "time-created" { + value = oci_core_instance.ubuntu_instance.time_created +} \ No newline at end of file diff --git a/labs/oracle/lab-03/provider.tf b/labs/oracle/lab-03/provider.tf new file mode 100644 index 00000000..7f706e3d --- /dev/null +++ b/labs/oracle/lab-03/provider.tf @@ -0,0 +1,6 @@ +provider "oci" { + tenancy_ocid = "" + user_ocid = "" + private_key_path = "" + fingerprint = "" +} \ No newline at end of file diff --git a/labs/oracle/lab-03/readme.md b/labs/oracle/lab-03/readme.md new file mode 100644 index 00000000..99c969cf --- /dev/null +++ b/labs/oracle/lab-03/readme.md @@ -0,0 +1,165 @@ +# Terraform: Create a Compute Instance + +## Prepare + +* Create SSH Encryption Keys + + - Create a Virtual Cloud Network (VCN) + + - Set up a VCN to connect your Linux instance to the internet. You configure all the components needed to create your virtual network. + + - Click the Oracle Cloud icon to go to the main landing page. + + - Scroll down to Launch Resources. + + - Select Set up a network with a wizard. + + - In the Start VCN Wizard workflow, select VCN with Internet Connectivity and then click Start VCN Wizard . + + - Fill in basic information: + + - VCN Name: + + - Compartment: + + - In the Configure VCN and Subnets section, keep the default values for the CIDR blocks: + + - VCN CIDR BLOCK: 10.0.0.0/16 + + - PUBLIC SUBNET CIDR BLOCK: 10.0.0.0/24 + + - PRIVATE SUBNET CIDR BLOCK: 10.0.1.0/24 + + - Note + - Notice the public and private subnets have different network addresses. + + - For DNS Resolution, uncheck Use DNS hostnames in this VCN. + + - Click Next. + + - The Create a VCN with Internet Connectivity configuration dialog is displayed (not shown here) confirming all the values you just entered. + + - Click Create to create your VCN. + + - The Creating Resources dialog is displayed (not shown here) showing all VCN components being created. + + - Click View Virtual Cloud Network to view your new VCN. + + - You have successfully created a VCN to host your compute instance. + + - Gather Required Information + + - Prepare the information you need and copy them into your notepad. + + - Compartment Name: (your-compartment-name) + + - Find your compartment name from the Create a Compartment tutorial you performed in the Before you Begin section. + + - Collect the following information from the Oracle Cloud Infrastructure Console. + + - Compartment ID: (compartment-ocid) + + - In the Console search bar, enter (your-compartment-name). + + - Click (your-compartment-name) in the search results. + + - Copy the OCID. + + - Subnet ID: (subnet-ocid) + + - Open the navigation menu and click Networking, and then click Virtual Cloud Networks. + + - Click (your-vcn-name) from section 2. + + - Click the public subnet and copy OCID. + + - Find the source id for the image of the compute instance. + + - Source ID: (source-ocid) + + - In the Console's top navigation bar, find your region. + + - Go to https://docs.oracle.com/en-us/iaas/images/ + + - Click Ubuntu 20.04 and click the latest image: Canonical-Ubuntu-20.04-(date). + + - Find the image for your region and copy OCID. + + - Note + + - Ensure that you select a commercial OCID without gov in its OCID. + + - Choose the shape for the compute instance. + + - Shape: VM.Standard2.1 + + - To choose a different shape, go to VM Standard Shapes. + + - Add Resource Policy + + - If your username is in the Administrators group, then skip this section. Otherwise, have your administrator add the following policy to your tenancy: + + ``` + allow group to manage all-resources in compartment + ``` + + - With this privilege, you can manage all resources in your compartment, essentially giving you administrative rights in that compartment. + + - Steps to Add the Policy + + - Open the navigation menu and click Identity & Security. Under Identity, click Policies. + + - Select your compartment from the Compartment drop-down. + + - Click Create Policy. + + - Fill in the following information: + + - Name: manage-(your-compartment-name)-resources + + - Description: Allow users to list, create, update, and delete resources in (your-compartment-name). + + - Compartment: (your-tenancy)(root) + + - For Policy Builder, select the following choices: + + - Policy use cases: Compartment Management + + - Common policy templates: Let compartment admins manage the compartment + + - Groups: (the-group-your-username-belongs) + + - Location: (your-tenancy)(root) + + - Click Create. + +## Create Scripts + +* Create four scripts: one for authentication, one to fetch data, one to create a compute instance, and one to print outputs. + + - availablity-domains.tf + - compute.tf + - output.tf + - provider.tf + +## Run Scripts + +``` +terraform init +``` + +``` +terraform plan +``` + +``` +terraform apply +``` + +## Watch the instance creation from the Console. + +* Open the navigation menu and click Compute. Under Compute, click Instances. + +* Select your compartment. + +* Watch your instance appear in the list of instances. \ No newline at end of file diff --git a/labs/oracle/lab-04/outputs.tf b/labs/oracle/lab-04/outputs.tf new file mode 100644 index 00000000..50b28df3 --- /dev/null +++ b/labs/oracle/lab-04/outputs.tf @@ -0,0 +1,3 @@ +output "bucket-name" { + value = oci_objectstorage_bucket.test_bucket.name +} \ No newline at end of file diff --git a/labs/oracle/lab-04/readme.md b/labs/oracle/lab-04/readme.md new file mode 100644 index 00000000..ba3b8e2c --- /dev/null +++ b/labs/oracle/lab-04/readme.md @@ -0,0 +1,30 @@ +# Terraform: Create a Object storage bucket + +## Create Scripts + +* Create below scripts + + - storage.tf + - output.tf + +## Run Scripts + +``` +terraform init +``` + +``` +terraform plan +``` + +``` +terraform apply +``` + +## Watch the storage creation from the Console. + +* Open the navigation menu and click Storage. Under "Object Storage & Archive Storage", click "Buckets". + +* Select your compartment. + +* Watch your instance appear in the list of buckets. \ No newline at end of file diff --git a/labs/oracle/lab-04/storage.tf b/labs/oracle/lab-04/storage.tf new file mode 100644 index 00000000..3ead8fc0 --- /dev/null +++ b/labs/oracle/lab-04/storage.tf @@ -0,0 +1,8 @@ +# Source from https://registry.terraform.io/providers/oracle/oci/latest/docs/resources/objectstorage_bucket + +resource "oci_objectstorage_bucket" "test_bucket" { + #Required + compartment_id = "ocid1.compartment.oc1..aaaaaaaayf3gksj2b37farc2tep72goofuc25tzsd72blhdjmel54kwv2xla" + name = "himkum_bucket_2" + namespace = "lrsivuswtz6j" +} \ No newline at end of file diff --git a/labs/oracle/lab-05/main.tf b/labs/oracle/lab-05/main.tf new file mode 100644 index 00000000..df0363a6 --- /dev/null +++ b/labs/oracle/lab-05/main.tf @@ -0,0 +1,25 @@ +resource "oci_core_instance" "myVM" { + # Required + availability_domain = data.oci_identity_availability_domains.ads.availability_domains[0].name + compartment_id = var.compartment_id + shape = var.shape + source_details { + source_id = "ocid1.image.oc1.uk-london-1.aaaaaaaa3lb354447utq7gq6v3hqvo7u3nrkbf5fxmdxfem5jq4ngy4rtxba" + source_type = "image" + } + + # Optional + display_name = "him_myVM" + + create_vnic_details { + assign_public_ip = true + subnet_id = "ocid1.subnet.oc1.uk-london-1.aaaaaaaa6n3zzrw6xnv2capcbpxwht4zr72uoxnnxvbrp5vcqmg56p7zaszq" + } + + preserve_boot_volume = false + +} + +data "oci_identity_availability_domains" "ads" { + compartment_id = var.compartment_id +} diff --git a/labs/oracle/lab-05/outputs.tf b/labs/oracle/lab-05/outputs.tf new file mode 100644 index 00000000..a00bf780 --- /dev/null +++ b/labs/oracle/lab-05/outputs.tf @@ -0,0 +1,5 @@ + +output "Instance_type" { + description = "instance type used in myVM" + value = "Hi, I am a ${oci_core_instance.myVM.display_name} instance name" +} \ No newline at end of file diff --git a/labs/oracle/lab-05/providers.tf b/labs/oracle/lab-05/providers.tf new file mode 100644 index 00000000..7f706e3d --- /dev/null +++ b/labs/oracle/lab-05/providers.tf @@ -0,0 +1,6 @@ +provider "oci" { + tenancy_ocid = "" + user_ocid = "" + private_key_path = "" + fingerprint = "" +} \ No newline at end of file diff --git a/labs/oracle/lab-05/terraform.tfvars b/labs/oracle/lab-05/terraform.tfvars new file mode 100644 index 00000000..28ddcc3f --- /dev/null +++ b/labs/oracle/lab-05/terraform.tfvars @@ -0,0 +1 @@ + shape = "VM.Standard2.1" diff --git a/labs/oracle/lab-05/variables.tf b/labs/oracle/lab-05/variables.tf new file mode 100644 index 00000000..0c6c23f3 --- /dev/null +++ b/labs/oracle/lab-05/variables.tf @@ -0,0 +1,12 @@ +variable compartment_id { + description = "compartment id" + type = string + default = "ocid1.tenancy.oc1..aaaaaaaa6ag77lnluy7avrzhjkg7g3kriz5t5u2jnsw43yecx4oylzxsv5uq" + +} + +variable shape { + description = "instance type" + type = string +} + diff --git a/labs/oracle/lab-06/main.tf b/labs/oracle/lab-06/main.tf new file mode 100644 index 00000000..03cc01f7 --- /dev/null +++ b/labs/oracle/lab-06/main.tf @@ -0,0 +1,29 @@ +locals { + name = "him_myVM_1" +} + +resource "oci_core_instance" "myVM" { + # Required + availability_domain = data.oci_identity_availability_domains.ads.availability_domains[0].name + compartment_id = var.compartment_id + shape = var.shape + + # Optional + display_name = local.name + + source_details { + source_id = "ocid1.image.oc1.uk-london-1.aaaaaaaa3lb354447utq7gq6v3hqvo7u3nrkbf5fxmdxfem5jq4ngy4rtxba" + source_type = "image" + } + + create_vnic_details { + assign_public_ip = true + subnet_id = "ocid1.subnet.oc1.uk-london-1.aaaaaaaa6n3zzrw6xnv2capcbpxwht4zr72uoxnnxvbrp5vcqmg56p7zaszq" + } + + preserve_boot_volume = false +} + +data "oci_identity_availability_domains" "ads" { + compartment_id = var.compartment_id +} \ No newline at end of file diff --git a/labs/oracle/lab-06/outputs.tf b/labs/oracle/lab-06/outputs.tf new file mode 100644 index 00000000..a00bf780 --- /dev/null +++ b/labs/oracle/lab-06/outputs.tf @@ -0,0 +1,5 @@ + +output "Instance_type" { + description = "instance type used in myVM" + value = "Hi, I am a ${oci_core_instance.myVM.display_name} instance name" +} \ No newline at end of file diff --git a/labs/oracle/lab-06/providers.tf b/labs/oracle/lab-06/providers.tf new file mode 100644 index 00000000..7f706e3d --- /dev/null +++ b/labs/oracle/lab-06/providers.tf @@ -0,0 +1,6 @@ +provider "oci" { + tenancy_ocid = "" + user_ocid = "" + private_key_path = "" + fingerprint = "" +} \ No newline at end of file diff --git a/labs/oracle/lab-06/terraform.tfvars b/labs/oracle/lab-06/terraform.tfvars new file mode 100644 index 00000000..457a35a3 --- /dev/null +++ b/labs/oracle/lab-06/terraform.tfvars @@ -0,0 +1 @@ +shape = "VM.Standard2.1" diff --git a/labs/oracle/lab-06/variables.tf b/labs/oracle/lab-06/variables.tf new file mode 100644 index 00000000..bebbcd33 --- /dev/null +++ b/labs/oracle/lab-06/variables.tf @@ -0,0 +1,11 @@ +variable compartment_id { + description = "compartment id" + type = string + default = "ocid1.tenancy.oc1..aaaaaaaa6ag77lnluy7avrzhjkg7g3kriz5t5u2jnsw43yecx4oylzxsv5uq" + +} + +variable shape { + description = "instance type" + type = string +} \ No newline at end of file diff --git a/labs/oracle/lab-07/README.md b/labs/oracle/lab-07/README.md new file mode 100644 index 00000000..5f453217 --- /dev/null +++ b/labs/oracle/lab-07/README.md @@ -0,0 +1,3 @@ +### New elements +* MYSRT +* Variable of `number` type \ No newline at end of file diff --git a/labs/oracle/lab-07/code/main.tf b/labs/oracle/lab-07/code/main.tf new file mode 100644 index 00000000..1ed5b087 --- /dev/null +++ b/labs/oracle/lab-07/code/main.tf @@ -0,0 +1,35 @@ +locals { + + message = <<-MYSRT + this is a multi line string + that goes on and one and on + MYSRT + + name = "him_myVM_0_1" +} + +resource "oci_core_instance" "myVM" { + # Required + availability_domain = data.oci_identity_availability_domains.ads.availability_domains[0].name + compartment_id = var.compartment_id + shape = var.shape + + # Optional + display_name = local.name + + source_details { + source_id = "ocid1.image.oc1.uk-london-1.aaaaaaaa3lb354447utq7gq6v3hqvo7u3nrkbf5fxmdxfem5jq4ngy4rtxba" + source_type = "image" + } + + create_vnic_details { + assign_public_ip = true + subnet_id = "ocid1.subnet.oc1.uk-london-1.aaaaaaaa6n3zzrw6xnv2capcbpxwht4zr72uoxnnxvbrp5vcqmg56p7zaszq" + } + + preserve_boot_volume = false +} + +data "oci_identity_availability_domains" "ads" { + compartment_id = var.compartment_id +} diff --git a/labs/oracle/lab-07/code/outputs.tf b/labs/oracle/lab-07/code/outputs.tf new file mode 100644 index 00000000..1fa2147b --- /dev/null +++ b/labs/oracle/lab-07/code/outputs.tf @@ -0,0 +1,13 @@ +output "Instance_type" { + description = "instance type used in myVM" + value = "Hi, I am a ${oci_core_instance.myVM.display_name} instance name" +} + +output "Message" { + value = local.message +} + +output "Port" { + description = "Experiment with a number variable" + value = var.port +} \ No newline at end of file diff --git a/labs/oracle/lab-07/code/providers.tf b/labs/oracle/lab-07/code/providers.tf new file mode 100644 index 00000000..7f706e3d --- /dev/null +++ b/labs/oracle/lab-07/code/providers.tf @@ -0,0 +1,6 @@ +provider "oci" { + tenancy_ocid = "" + user_ocid = "" + private_key_path = "" + fingerprint = "" +} \ No newline at end of file diff --git a/labs/oracle/lab-07/code/terraform.tfvars b/labs/oracle/lab-07/code/terraform.tfvars new file mode 100644 index 00000000..457a35a3 --- /dev/null +++ b/labs/oracle/lab-07/code/terraform.tfvars @@ -0,0 +1 @@ +shape = "VM.Standard2.1" diff --git a/labs/oracle/lab-07/code/variables.tf b/labs/oracle/lab-07/code/variables.tf new file mode 100644 index 00000000..c42efd63 --- /dev/null +++ b/labs/oracle/lab-07/code/variables.tf @@ -0,0 +1,19 @@ +variable compartment_id { + description = "compartment id" + type = string + default = "ocid1.tenancy.oc1..aaaaaaaa6ag77lnluy7avrzhjkg7g3kriz5t5u2jnsw43yecx4oylzxsv5uq" + +} + +variable shape { + description = "instance type" + type = string +} + +variable port { + description = "port number" + type = number + default = 8080 +} + + diff --git a/labs/oracle/lab-08/README.md b/labs/oracle/lab-08/README.md new file mode 100644 index 00000000..58d7a8ff --- /dev/null +++ b/labs/oracle/lab-08/README.md @@ -0,0 +1,2 @@ +### Reading variables from a file +* See `main.tf` \ No newline at end of file diff --git a/labs/oracle/lab-08/code/main.tf b/labs/oracle/lab-08/code/main.tf new file mode 100644 index 00000000..94489ec0 --- /dev/null +++ b/labs/oracle/lab-08/code/main.tf @@ -0,0 +1,30 @@ +locals { + name = file("name.txt") + +} + +resource "oci_core_instance" "myVM" { + # Required + availability_domain = data.oci_identity_availability_domains.ads.availability_domains[0].name + compartment_id = var.compartment_id + shape = var.shape + + # Optional + display_name = local.name + + source_details { + source_id = "ocid1.image.oc1.uk-london-1.aaaaaaaa3lb354447utq7gq6v3hqvo7u3nrkbf5fxmdxfem5jq4ngy4rtxba" + source_type = "image" + } + + create_vnic_details { + assign_public_ip = true + subnet_id = "ocid1.subnet.oc1.uk-london-1.aaaaaaaa6n3zzrw6xnv2capcbpxwht4zr72uoxnnxvbrp5vcqmg56p7zaszq" + } + + preserve_boot_volume = false +} + +data "oci_identity_availability_domains" "ads" { + compartment_id = var.compartment_id +} diff --git a/labs/oracle/lab-08/code/name.txt b/labs/oracle/lab-08/code/name.txt new file mode 100644 index 00000000..bd761f95 --- /dev/null +++ b/labs/oracle/lab-08/code/name.txt @@ -0,0 +1 @@ +him_myVM_0_2 \ No newline at end of file diff --git a/labs/oracle/lab-08/code/outputs.tf b/labs/oracle/lab-08/code/outputs.tf new file mode 100644 index 00000000..19bf395a --- /dev/null +++ b/labs/oracle/lab-08/code/outputs.tf @@ -0,0 +1,4 @@ +output "Instance_type" { + description = "instance type used in myVM" + value = "Hi, my name is ${local.name}" +} \ No newline at end of file diff --git a/labs/oracle/lab-08/code/providers.tf b/labs/oracle/lab-08/code/providers.tf new file mode 100644 index 00000000..7f706e3d --- /dev/null +++ b/labs/oracle/lab-08/code/providers.tf @@ -0,0 +1,6 @@ +provider "oci" { + tenancy_ocid = "" + user_ocid = "" + private_key_path = "" + fingerprint = "" +} \ No newline at end of file diff --git a/labs/oracle/lab-08/code/terraform.tfvars b/labs/oracle/lab-08/code/terraform.tfvars new file mode 100644 index 00000000..457a35a3 --- /dev/null +++ b/labs/oracle/lab-08/code/terraform.tfvars @@ -0,0 +1 @@ +shape = "VM.Standard2.1" diff --git a/labs/oracle/lab-08/code/variables.tf b/labs/oracle/lab-08/code/variables.tf new file mode 100644 index 00000000..bebbcd33 --- /dev/null +++ b/labs/oracle/lab-08/code/variables.tf @@ -0,0 +1,11 @@ +variable compartment_id { + description = "compartment id" + type = string + default = "ocid1.tenancy.oc1..aaaaaaaa6ag77lnluy7avrzhjkg7g3kriz5t5u2jnsw43yecx4oylzxsv5uq" + +} + +variable shape { + description = "instance type" + type = string +} \ No newline at end of file diff --git a/labs/oracle/lab-09/README.md b/labs/oracle/lab-09/README.md new file mode 100644 index 00000000..773a69aa --- /dev/null +++ b/labs/oracle/lab-09/README.md @@ -0,0 +1,2 @@ +### Template files +* See `main.tf` \ No newline at end of file diff --git a/labs/oracle/lab-09/code/document.txt b/labs/oracle/lab-09/code/document.txt new file mode 100644 index 00000000..e9e77ff1 --- /dev/null +++ b/labs/oracle/lab-09/code/document.txt @@ -0,0 +1,2 @@ + +This code was modified by ${myname} \ No newline at end of file diff --git a/labs/oracle/lab-09/code/main.tf b/labs/oracle/lab-09/code/main.tf new file mode 100644 index 00000000..98b5abbf --- /dev/null +++ b/labs/oracle/lab-09/code/main.tf @@ -0,0 +1,31 @@ +locals { + developer = "Zippy" + documentation = templatefile("document.txt", {myname = local.developer}) +} + +resource "oci_core_instance" "myVM" { + # Required + availability_domain = data.oci_identity_availability_domains.ads.availability_domains[0].name + compartment_id = var.compartment_id + shape = var.shape + + # Optional + display_name = "${local.developer}'s machine" + + source_details { + source_id = "ocid1.image.oc1.uk-london-1.aaaaaaaa3lb354447utq7gq6v3hqvo7u3nrkbf5fxmdxfem5jq4ngy4rtxba" + source_type = "image" + } + + create_vnic_details { + assign_public_ip = true + subnet_id = "ocid1.subnet.oc1.uk-london-1.aaaaaaaa6n3zzrw6xnv2capcbpxwht4zr72uoxnnxvbrp5vcqmg56p7zaszq" + } + + preserve_boot_volume = false +} + + +data "oci_identity_availability_domains" "ads" { + compartment_id = var.compartment_id +} \ No newline at end of file diff --git a/labs/oracle/lab-09/code/outputs.tf b/labs/oracle/lab-09/code/outputs.tf new file mode 100644 index 00000000..3563dbc0 --- /dev/null +++ b/labs/oracle/lab-09/code/outputs.tf @@ -0,0 +1,8 @@ + +output "Documentation" { + description = "Developer who worked on this" + value = local.documentation +} + + + diff --git a/labs/oracle/lab-09/code/providers.tf b/labs/oracle/lab-09/code/providers.tf new file mode 100644 index 00000000..7f706e3d --- /dev/null +++ b/labs/oracle/lab-09/code/providers.tf @@ -0,0 +1,6 @@ +provider "oci" { + tenancy_ocid = "" + user_ocid = "" + private_key_path = "" + fingerprint = "" +} \ No newline at end of file diff --git a/labs/oracle/lab-09/code/terraform.tfvars b/labs/oracle/lab-09/code/terraform.tfvars new file mode 100644 index 00000000..457a35a3 --- /dev/null +++ b/labs/oracle/lab-09/code/terraform.tfvars @@ -0,0 +1 @@ +shape = "VM.Standard2.1" diff --git a/labs/oracle/lab-09/code/variables.tf b/labs/oracle/lab-09/code/variables.tf new file mode 100644 index 00000000..bebbcd33 --- /dev/null +++ b/labs/oracle/lab-09/code/variables.tf @@ -0,0 +1,11 @@ +variable compartment_id { + description = "compartment id" + type = string + default = "ocid1.tenancy.oc1..aaaaaaaa6ag77lnluy7avrzhjkg7g3kriz5t5u2jnsw43yecx4oylzxsv5uq" + +} + +variable shape { + description = "instance type" + type = string +} \ No newline at end of file diff --git a/labs/oracle/lab-10/README.md b/labs/oracle/lab-10/README.md new file mode 100644 index 00000000..5603f140 --- /dev/null +++ b/labs/oracle/lab-10/README.md @@ -0,0 +1,2 @@ +### Data filters +* In `main.tf` \ No newline at end of file diff --git a/labs/oracle/lab-10/code/main.tf b/labs/oracle/lab-10/code/main.tf new file mode 100644 index 00000000..09fadf60 --- /dev/null +++ b/labs/oracle/lab-10/code/main.tf @@ -0,0 +1,26 @@ +data "oci_core_instances" "r1" { + #Required + compartment_id = "ocid1.tenancy.oc1..aaaaaaaa6ag77lnluy7avrzhjkg7g3kriz5t5u2jnsw43yecx4oylzxsv5uq" + + filter { + name = "source_details.source_type" + values = ["image"] + } + + filter { + name = "defined_tags.Operations.CostCenter" + values = ["42"] + } + + filter { + name = "availability_domain" + values = ["\\w*-AD-1"] + regex = true + } + + filter { + name = "state" + values = ["RUNNING"] + } + +} \ No newline at end of file diff --git a/labs/oracle/lab-10/code/outputs.tf b/labs/oracle/lab-10/code/outputs.tf new file mode 100644 index 00000000..4bf8b796 --- /dev/null +++ b/labs/oracle/lab-10/code/outputs.tf @@ -0,0 +1,4 @@ +output "OCI_instances" { + description = "The OCI instances" + value = data.oci_core_instances.r1.id +} \ No newline at end of file diff --git a/labs/oracle/lab-10/code/providers.tf b/labs/oracle/lab-10/code/providers.tf new file mode 100644 index 00000000..7f706e3d --- /dev/null +++ b/labs/oracle/lab-10/code/providers.tf @@ -0,0 +1,6 @@ +provider "oci" { + tenancy_ocid = "" + user_ocid = "" + private_key_path = "" + fingerprint = "" +} \ No newline at end of file diff --git a/labs/oracle/lab-11/README.md b/labs/oracle/lab-11/README.md new file mode 100644 index 00000000..5f0cf5d2 --- /dev/null +++ b/labs/oracle/lab-11/README.md @@ -0,0 +1,3 @@ +### Multiple providers + +* In `providers.tf` \ No newline at end of file diff --git a/labs/oracle/lab-11/code/main.tf b/labs/oracle/lab-11/code/main.tf new file mode 100644 index 00000000..b99fff78 --- /dev/null +++ b/labs/oracle/lab-11/code/main.tf @@ -0,0 +1,49 @@ +resource "oci_core_instance" "X" { + + # Required + availability_domain = data.oci_identity_availability_domains.ads.availability_domains[0].name + compartment_id = "ocid1.tenancy.oc1..aaaaaaaa6ag77lnluy7avrzhjkg7g3kriz5t5u2jnsw43yecx4oylzxsv5uq" + shape = "VM.Standard2.1" + source_details { + source_id = "ocid1.image.oc1.uk-london-1.aaaaaaaa3lb354447utq7gq6v3hqvo7u3nrkbf5fxmdxfem5jq4ngy4rtxba" + source_type = "image" + } + + # Optional + display_name = "Instance_X" + create_vnic_details { + assign_public_ip = true + subnet_id = "ocid1.subnet.oc1.uk-london-1.aaaaaaaa6n3zzrw6xnv2capcbpxwht4zr72uoxnnxvbrp5vcqmg56p7zaszq" + } + + preserve_boot_volume = false +} + +resource "oci_core_instance" "Y" { + + provider = oci.region2 + # Required + availability_domain = data.oci_identity_availability_domains.ads.availability_domains[0].name + compartment_id = "ocid1.compartment.oc1..aaaaaaaayf3gksj2b37farc2tep72goofuc25tzsd72blhdjmel54kwv2xla" + shape = "VM.Standard2.1" + source_details { + source_id = "ocid1.image.oc1.uk-london-1.aaaaaaaa3lb354447utq7gq6v3hqvo7u3nrkbf5fxmdxfem5jq4ngy4rtxba" + source_type = "image" + } + + # Optional + display_name = "Instance_Y" + create_vnic_details { + assign_public_ip = true + subnet_id = "ocid1.subnet.oc1.uk-london-1.aaaaaaaa6n3zzrw6xnv2capcbpxwht4zr72uoxnnxvbrp5vcqmg56p7zaszq" + } + + preserve_boot_volume = false +} + +data "oci_identity_availability_domains" "ads" { + compartment_id = "ocid1.tenancy.oc1..aaaaaaaa6ag77lnluy7avrzhjkg7g3kriz5t5u2jnsw43yecx4oylzxsv5uq" +} + + + diff --git a/labs/oracle/lab-11/code/providers.tf b/labs/oracle/lab-11/code/providers.tf new file mode 100644 index 00000000..871d2f69 --- /dev/null +++ b/labs/oracle/lab-11/code/providers.tf @@ -0,0 +1,8 @@ +provider "oci" { + tenancy_ocid = "ocid1.tenancy.oc1..aaaaaaaa6ag77lnluy7avrzhjkg7g3kriz5t5u2jnsw43yecx4oylzxsv5uq" +} + +provider "oci" { + alias = "region2" + tenancy_ocid = "ocid1.compartment.oc1..aaaaaaaayf3gksj2b37farc2tep72goofuc25tzsd72blhdjmel54kwv2xla" +} diff --git a/labs/oracle/lab-12/main.tf b/labs/oracle/lab-12/main.tf new file mode 100644 index 00000000..de4500e9 --- /dev/null +++ b/labs/oracle/lab-12/main.tf @@ -0,0 +1,28 @@ +resource "oci_core_instance" "myVM" { + + for_each = var.virtual_machines + + # Required + availability_domain = data.oci_identity_availability_domains.ads.availability_domains[0].name + compartment_id = var.compartment_id + shape = var.shape + source_details { + source_id = "ocid1.image.oc1.uk-london-1.aaaaaaaa3lb354447utq7gq6v3hqvo7u3nrkbf5fxmdxfem5jq4ngy4rtxba" + source_type = "image" + } + + # Optional + display_name = each.key + + create_vnic_details { + assign_public_ip = true + subnet_id = "ocid1.subnet.oc1.uk-london-1.aaaaaaaa6n3zzrw6xnv2capcbpxwht4zr72uoxnnxvbrp5vcqmg56p7zaszq" + } + + preserve_boot_volume = false + +} + +data "oci_identity_availability_domains" "ads" { + compartment_id = var.compartment_id +} diff --git a/labs/oracle/lab-12/outputs.tf b/labs/oracle/lab-12/outputs.tf new file mode 100644 index 00000000..61645072 --- /dev/null +++ b/labs/oracle/lab-12/outputs.tf @@ -0,0 +1,5 @@ + +output "Instance_type" { + description = "instance type used in myVM" + value = oci_core_instance.myVM.display_name +} \ No newline at end of file diff --git a/labs/oracle/lab-12/providers.tf b/labs/oracle/lab-12/providers.tf new file mode 100644 index 00000000..7f706e3d --- /dev/null +++ b/labs/oracle/lab-12/providers.tf @@ -0,0 +1,6 @@ +provider "oci" { + tenancy_ocid = "" + user_ocid = "" + private_key_path = "" + fingerprint = "" +} \ No newline at end of file diff --git a/labs/oracle/lab-12/terraform.tfvars b/labs/oracle/lab-12/terraform.tfvars new file mode 100644 index 00000000..28ddcc3f --- /dev/null +++ b/labs/oracle/lab-12/terraform.tfvars @@ -0,0 +1 @@ + shape = "VM.Standard2.1" diff --git a/labs/oracle/lab-12/variables.tf b/labs/oracle/lab-12/variables.tf new file mode 100644 index 00000000..41acfaa0 --- /dev/null +++ b/labs/oracle/lab-12/variables.tf @@ -0,0 +1,20 @@ +variable compartment_id { + description = "compartment id" + type = string + default = "ocid1.tenancy.oc1..aaaaaaaa6ag77lnluy7avrzhjkg7g3kriz5t5u2jnsw43yecx4oylzxsv5uq" + +} + +variable shape { + description = "instance type" + type = string +} + +variable "virtual_machines" { + type = map(object({})) + + default = { + test_vm_1 = {} + test_vm_2 = {} + } +} diff --git a/student-environments/clean.sh b/student-environments/clean.sh new file mode 100755 index 00000000..c688cb71 --- /dev/null +++ b/student-environments/clean.sh @@ -0,0 +1,67 @@ +#!/bin/bash + +set -e + +dry_run=false +if [[ "$1" == "dry-run" ]]; then + dry_run=true +fi + +function run_clean_command() { + if [[ $dry_run == false ]]; then + $* + else + echo "DRY RUN: $*" + fi +} + +regions="us-east-1 us-east-2 us-west-1 us-west-2" +# regions="$(aws ec2 describe-regions | jq -r '.Regions[].RegionName')" + +for region in $regions; do + echo "Cleaning up resources in $region..." + for cloud9_environment in $(aws --region $region cloud9 list-environments | jq -r '.environmentIds[]'); do + echo "Removing Cloud9 environment: $cloud9_environment" + run_clean_command aws --region $region cloud9 delete-environment --environment-id $cloud9_environment + done + for autoscaler in $(aws --region $region autoscaling describe-auto-scaling-groups | jq -r '.AutoScalingGroups[].AutoScalingGroupName'); do + echo "Removing autoscaler: $autoscaler" + run_clean_command aws --region $region autoscaling delete-auto-scaling-group --auto-scaling-group-name $autoscaler --force-delete + done + for load_balancer in $(aws --region $region elbv2 describe-load-balancers | jq -r '.LoadBalancers[].LoadBalancerArn'); do + for listener in $(aws --region $region elbv2 describe-listeners --load-balancer-arn $load_balancer | jq -r '.Listeners[].ListenerArn'); do + echo "Removing load balancer listener: $listener" + run_clean_command aws --region $region elbv2 delete-listener --listener-arn $listener + done + echo "Removing load balancer: $load_balancer" + run_clean_command aws --region $region elbv2 delete-load-balancer --load-balancer-arn $load_balancer + done + for target_group in $(aws --region $region elbv2 describe-target-groups | jq -r '.TargetGroups[].TargetGroupArn'); do + echo "Removing target group: $target_group" + run_clean_command aws --region $region elbv2 delete-target-group --target-group-arn $target_group + done + for launch_configuration in $(aws --region $region autoscaling describe-launch-configurations | jq -r '.LaunchConfigurations[].LaunchConfigurationName'); do + echo "Removing launch configuration: $launch_configuration" + run_clean_command aws --region $region autoscaling delete-launch-configuration --launch-configuration-name $launch_configuration + done + for instance in $(aws --region $region ec2 describe-instances | jq -r '.Reservations[].Instances[].InstanceId'); do + echo "Removing EC2 instance: $instance" + run_clean_command aws --region $region ec2 terminate-instances --instance-ids $instance + done + for key_pair in $(aws --region $region ec2 describe-key-pairs | jq -r '.KeyPairs[].KeyName'); do + echo "Removing key pair: $key_pair" + run_clean_command aws --region $region ec2 delete-key-pair --key-name $key_pair + done + for security_group in $(aws --region $region ec2 describe-security-groups | jq -r '.SecurityGroups[].GroupName'); do + if [[ "$security_group" != "default" ]]; then + echo "Removing security group: $security_group" + set +e + run_clean_command aws --region $region ec2 delete-security-group --group-name $security_group + set -e + fi + done + for dynamodb_table in $(aws --region $region dynamodb list-tables | jq -r '.TableNames[]'); do + echo "Deleting DynamoDB table: $dynamodb_table" + run_clean_command aws --region $region dynamodb delete-table --table-name $dynamodb_table + done +done diff --git a/student-environments/get-all-ec2.sh b/student-environments/get-all-ec2.sh new file mode 100755 index 00000000..618e6375 --- /dev/null +++ b/student-environments/get-all-ec2.sh @@ -0,0 +1,6 @@ +#!/bin/bash + +for region in `aws ec2 describe-regions --output text | cut -f4`; do + echo -e "\nListing Instances in region:'$region'..." + aws ec2 describe-instances --region $region +done diff --git a/student-environments/main.tf b/student-environments/main.tf new file mode 100644 index 00000000..74f2c6f3 --- /dev/null +++ b/student-environments/main.tf @@ -0,0 +1,221 @@ +provider "aws" { + version = "~> 2.0" + region = "us-west-2" +} + +provider "aws" { + alias = "california" + region = "us-west-1" +} + +resource "aws_s3_bucket" "student_buckets" { + count = length(var.students) + bucket = "rockholla-di-${var.students[count.index].name}" + acl = "private" + provider = aws.california + force_destroy = true +} + +resource "aws_iam_account_password_policy" "students" { + minimum_password_length = 8 + require_lowercase_characters = true + require_numbers = true + require_uppercase_characters = true + require_symbols = false + allow_users_to_change_password = true +} + +resource "aws_iam_user" "students" { + count = length(var.students) + name = var.students[count.index].name + force_destroy = true +} + +resource "aws_iam_user_login_profile" "students" { + count = length(var.students) + user = var.students[count.index].name + password_length = 10 + pgp_key = var.pgp_key + password_reset_required = false + lifecycle { + ignore_changes = [password_length, password_reset_required, pgp_key] + } + depends_on = [aws_iam_user.students] +} + +resource "aws_iam_policy" "student_bucket_access" { + count = length(var.students) + name = "${var.students[count.index].name}StudentBucketAccess" + description = "Allowing student access to their own bucket" + policy = < { + console.log(`Ensuring that the account rockholla-di-${account} is created...`) + let result = shell.exec(`./new-aws-org-account.sh --account_name rockholla-di-${account} --account_email di+${account}@rockholla.org --cl_profile_name rockholla-di-${account}`) + if (result.code != 0) { + console.error(`Error creating org account ${account}`) + } + console.log(`Done with rockholla-di-${account}`) + console.log('-----------------------------------------------------------------------') +}) \ No newline at end of file diff --git a/student-environments/org-idea/accounts.json b/student-environments/org-idea/accounts.json new file mode 100644 index 00000000..c9cfa2d3 --- /dev/null +++ b/student-environments/org-idea/accounts.json @@ -0,0 +1,35 @@ +{ + "names": [ + "bates", + "bill", + "blonde", + "chucky", + "commodus", + "corleone", + "doe", + "dooku", + "doom", + "dracula", + "drago", + "fett", + "ghostface", + "goblin", + "gruber", + "hal", + "hutt", + "jafar", + "joker", + "krueger", + "lecter", + "lestrange", + "loki", + "luther", + "magento", + "maleficent", + "malfoy", + "maul", + "myers", + "mystique", + "norton", + ] +} \ No newline at end of file diff --git a/student-environments/org-idea/new-aws-org-account.sh b/student-environments/org-idea/new-aws-org-account.sh new file mode 100755 index 00000000..6dd7eaf4 --- /dev/null +++ b/student-environments/org-idea/new-aws-org-account.sh @@ -0,0 +1,167 @@ +#!/bin/bash +function usage +{ + echo "usage: organization_new_acc.sh [-h] --account_name ACCOUNT_NAME + --account_email ACCOUNT_EMAIL + --cl_profile_name CLI_PROFILE_NAME + [--ou_name ORGANIZATION_UNIT_NAME] + [--region AWS_REGION]" +} + +newAccName="" +newAccEmail="" +newProfile="" +roleName="OrganizationAccountAccessRole" +destinationOUname="" +region="us-east-1" + +while [ "$1" != "" ]; do + case $1 in + -n | --account_name ) shift + newAccName=$1 + ;; + -e | --account_email ) shift + newAccEmail=$1 + ;; + -p | --cl_profile_name ) shift + newProfile=$1 + ;; + -o | --ou_name ) shift + destinationOUname=$1 + ;; + -r | --region ) shift + region=$1 + ;; + -h | --help ) usage + exit + ;; + esac + shift +done + +if [ "$newAccName" = "" ] || [ "$newAccEmail" = "" ] || [ "$newProfile" = "" ] +then + usage + exit +fi + +if aws organizations list-accounts --query 'Accounts[?Name==`'"$newAccName"'`]' | grep "$newAccName" &>/dev/null; then + printf "Account $newAccName already exists, exiting\n" + exit +fi + +printf "Create New Account\n" +ReqID=$(aws organizations create-account --email $newAccEmail --account-name "$newAccName" --role-name $roleName \ +--query 'CreateAccountStatus.[Id]' \ +--output text) + +printf "Waiting for New Account ..." +orgStat=$(aws organizations describe-create-account-status --create-account-request-id $ReqID \ +--query 'CreateAccountStatus.[State]' \ +--output text) + +while [ $orgStat != "SUCCEEDED" ] +do + if [ $orgStat = "FAILED" ] + then + printf "\nAccount Failed to Create\n" + exit 1 + fi + printf "." + sleep 10 + orgStat=$(aws organizations describe-create-account-status --create-account-request-id $ReqID \ + --query 'CreateAccountStatus.[State]' \ + --output text) +done + +accID=$(aws organizations describe-create-account-status --create-account-request-id $ReqID \ +--query 'CreateAccountStatus.[AccountId]' \ +--output text) + +accARN="arn:aws:iam::$accID:role/$roleName" + +printf "\nCreate New CLI Profile\n" +aws configure set region $region --profile $newProfile +aws configure set role_arn $accARN --profile $newProfile +aws configure set source_profile default --profile $newProfile + +cfcntr=0 +printf "Waiting for CF Service ..." +aws cloudformation list-stacks --profile $newProfile > /dev/null 2>&1 +actOut=$? +while [[ $actOut -ne 0 && $cfcntr -le 10 ]] +do + sleep 5 + aws cloudformation list-stacks --profile $newProfile > /dev/null 2>&1 + actOut=$? + if [ $actOut -eq 0 ] + then + break + fi + printf "." + cfcntr=$[$cfcntr +1] +done + +if [ $cfcntr -gt 10 ] +then + printf "\nCF Service not available\n" + exit 1 +fi + +printf "\nCreate VPC Under New Account\n" +aws cloudformation create-stack --stack-name VPC --template-body file://CF-VPC.json --profile $newProfile > /dev/null 2>&1 +if [ $? -ne 0 ] +then + printf "CF VPC Stack Failed to Create\n" + exit 1 +fi + +printf "Waiting for CF Stack to Finish ..." +cfStat=$(aws cloudformation describe-stacks --stack-name VPC --profile $newProfile --query 'Stacks[0].[StackStatus]' --output text) +while [ $cfStat != "CREATE_COMPLETE" ] +do + sleep 5 + printf "." + cfStat=$(aws cloudformation describe-stacks --stack-name VPC --profile $newProfile --query 'Stacks[0].[StackStatus]' --output text) + if [ $cfStat = "CREATE_FAILED" ] + then + printf "\nVPC Failed to Create\n" + exit 1 + fi +done +printf "\nVPC Created\n" + +printf "Create Role and Policy\n" +aws cloudformation create-stack --stack-name Roles --template-body file://CF-IAM.json --capabilities CAPABILITY_NAMED_IAM --profile $newProfile > /dev/null 2>&1 +cfStat=$(aws cloudformation describe-stacks --stack-name Roles --profile $newProfile --query 'Stacks[0].[StackStatus]' --output text) +while [ $cfStat != "CREATE_COMPLETE" ] +do + sleep 5 + printf "." + cfStat=$(aws cloudformation describe-stacks --stack-name Roles --profile $newProfile --query 'Stacks[0].[StackStatus]' --output text) + if [ $cfStat = "CREATE_FAILED" ] + then + printf "\Role Failed to Create\n" + exit 1 + fi +done +printf "\Role Created\n" + +printf "Create Configure Rule\n" +configRole=arn:aws:iam::$accID:role/service-role/config-rule-role + +aws configservice put-configuration-recorder --configuration-recorder name=default,roleARN=$configRole --recording-group allSupported=true,includeGlobalResourceTypes=true --profile $newProfile > /dev/null 2>&1 +aws configservice put-config-rule --config-rule file://CF-ConfigRules.json --profile $newProfile > /dev/null 2>&1 + +if [ "$destinationOUname" != "" ] +then + printf "Moving New Account to OU\n" + rootOU=$(aws organizations list-roots --query 'Roots[0].[Id]' --output text) + destOU=$(aws organizations list-organizational-units-for-parent --parent-id $rootOU --query 'OrganizationalUnits[?Name==`'$destinationOUname'`].[Id]' --output text) + + aws organizations move-account --account-id $accID --source-parent-id $rootOU --destination-parent-id $destOU > /dev/null 2>&1 + if [ $? -ne 0 ] + then + printf "Moving Account Failed\n" + fi +fi diff --git a/student-environments/org-idea/package-lock.json b/student-environments/org-idea/package-lock.json new file mode 100644 index 00000000..769b0af4 --- /dev/null +++ b/student-environments/org-idea/package-lock.json @@ -0,0 +1,121 @@ +{ + "name": "student-environments", + "version": "1.0.0", + "lockfileVersion": 1, + "requires": true, + "dependencies": { + "balanced-match": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", + "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=" + }, + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" + }, + "fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=" + }, + "glob": { + "version": "7.1.4", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.4.tgz", + "integrity": "sha512-hkLPepehmnKk41pUGm3sYxoFs/umurYfYJCerbXEyFIWcAzvpipAgVkBqqT9RBKMGjnq6kMuyYwha6csxbiM1A==", + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "requires": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" + }, + "interpret": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/interpret/-/interpret-1.2.0.tgz", + "integrity": "sha512-mT34yGKMNceBQUoVn7iCDKDntA7SC6gycMAWzGx1z/CMCTV7b2AAtXlo3nRyHZ1FelRkQbQjprHSYGwzLtkVbw==" + }, + "minimatch": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", + "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "requires": { + "brace-expansion": "^1.1.7" + } + }, + "once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "requires": { + "wrappy": "1" + } + }, + "path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=" + }, + "path-parse": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz", + "integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==" + }, + "rechoir": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.6.2.tgz", + "integrity": "sha1-hSBLVNuoLVdC4oyWdW70OvUOM4Q=", + "requires": { + "resolve": "^1.1.6" + } + }, + "resolve": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.11.1.tgz", + "integrity": "sha512-vIpgF6wfuJOZI7KKKSP+HmiKggadPQAdsp5HiC1mvqnfp0gF1vdwgBWZIdrVft9pgqoMFQN+R7BSWZiBxx+BBw==", + "requires": { + "path-parse": "^1.0.6" + } + }, + "shelljs": { + "version": "0.8.3", + "resolved": "https://registry.npmjs.org/shelljs/-/shelljs-0.8.3.tgz", + "integrity": "sha512-fc0BKlAWiLpwZljmOvAOTE/gXawtCoNrP5oaY7KIaQbbyHeQVg01pSEuEGvGh3HEdBU4baCD7wQBwADmM/7f7A==", + "requires": { + "glob": "^7.0.0", + "interpret": "^1.0.0", + "rechoir": "^0.6.2" + } + }, + "wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" + } + } +} diff --git a/student-environments/org-idea/package.json b/student-environments/org-idea/package.json new file mode 100644 index 00000000..a600ae40 --- /dev/null +++ b/student-environments/org-idea/package.json @@ -0,0 +1,14 @@ +{ + "name": "student-environments", + "version": "1.0.0", + "description": "", + "main": "index.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "author": "", + "license": "ISC", + "dependencies": { + "shelljs": "^0.8.3" + } +} diff --git a/student-environments/outputs.tf b/student-environments/outputs.tf new file mode 100644 index 00000000..3519fe48 --- /dev/null +++ b/student-environments/outputs.tf @@ -0,0 +1,7 @@ +output "students" { + value = var.students +} + +output "passwords" { + value = ["${aws_iam_user_login_profile.students.*.encrypted_password}"] +} diff --git a/student-environments/print-users.sh b/student-environments/print-users.sh new file mode 100755 index 00000000..67abfef9 --- /dev/null +++ b/student-environments/print-users.sh @@ -0,0 +1,28 @@ +#!/bin/bash + +values=$(terraform output -json) + +if [ -z "$1" ]; then + echo "First argument to this script should be one of: introduction, intermediate" + echo "in order to determine how to output the user values" +fi + +let i=0 +for username in $(echo $values | jq -r '.students.value[].name'); do + echo "Instructions repo: https://github.com/rockholla/terraform-packer-workshop" + echo "Console URL: https://rockholla-di.signin.aws.amazon.com/console" + echo "Username/Alias: $username" + password=$(echo $values | jq -r '.passwords.value[]['"$i"']' | base64 --decode | gpg -dq) + echo "AWS Console Password: $password" + region=$(echo $values | jq -r '.students.value['"$i"'].region') + if [[ "$1" == "introduction" ]]; then + echo "Exercise 11 Region: $region" + elif [[ "$1" == "intermediate" ]]; then + echo "TODO for region" + fi + echo "Instructor email: patrick+di@rockholla.org" + echo "" + echo "" + echo "" + let i=i+1 +done diff --git a/student-environments/rb.sh b/student-environments/rb.sh new file mode 100755 index 00000000..a91069ab --- /dev/null +++ b/student-environments/rb.sh @@ -0,0 +1,5 @@ +#!/bin/bash + +for bucket in $(aws s3 ls | awk '{print $3}'); do + aws s3 rb --force s3://$bucket +done diff --git a/student-environments/terraform.sh b/student-environments/terraform.sh new file mode 100755 index 00000000..8a134635 --- /dev/null +++ b/student-environments/terraform.sh @@ -0,0 +1,5 @@ +#!/bin/bash + +export TF_VAR_pgp_key=$(gpg --export "rockholla-di" | base64) +terraform init +terraform $@ diff --git a/student-environments/terraform.tfvars b/student-environments/terraform.tfvars new file mode 100644 index 00000000..a636184d --- /dev/null +++ b/student-environments/terraform.tfvars @@ -0,0 +1,33 @@ +students=[ + { name: "bane", region: "us-west-1" }, + { name: "bateman", region: "us-west-1" }, + { name: "bates", region: "us-west-1" }, + { name: "bill", region: "us-west-1" }, + { name: "blonde", region: "us-west-1" }, + { name: "chucky", region: "us-west-1" }, + { name: "commodus", region: "us-west-1" }, + { name: "corleone", region: "us-west-1" }, + { name: "doe", region: "us-west-2" }, + { name: "dooku", region: "us-west-2" }, + { name: "doom", region: "us-west-2" }, + { name: "dracula", region: "us-west-2" }, + { name: "drago", region: "us-west-2" }, + { name: "fett", region: "us-west-2" }, + { name: "ghostface", region: "us-west-2" }, + { name: "goblin", region: "us-west-2" }, + { name: "gruber", region: "us-east-1" }, + { name: "hal", region: "us-east-1" }, + { name: "hutt", region: "us-east-1" }, + { name: "jafar", region: "us-east-1" }, + { name: "joker", region: "us-east-1" }, + { name: "krueger", region: "us-east-1" }, + { name: "lecter", region: "us-east-1" }, + { name: "lestrange", region: "us-east-1" }, + { name: "loki", region: "us-east-2" }, + { name: "luther", region: "us-east-2" }, + { name: "magento", region: "us-east-2" }, + { name: "maleficent", region: "us-east-2" }, + { name: "malfoy", region: "us-east-2" }, + { name: "maul", region: "us-east-2" }, + { name: "force", region: "us-east-2" }, +] \ No newline at end of file diff --git a/student-environments/tests/.dockerignore b/student-environments/tests/.dockerignore new file mode 100644 index 00000000..f59ec20a --- /dev/null +++ b/student-environments/tests/.dockerignore @@ -0,0 +1 @@ +* \ No newline at end of file diff --git a/student-environments/tests/.gitignore b/student-environments/tests/.gitignore new file mode 100644 index 00000000..382f9542 --- /dev/null +++ b/student-environments/tests/.gitignore @@ -0,0 +1 @@ +workspace/ \ No newline at end of file diff --git a/student-environments/tests/Dockerfile b/student-environments/tests/Dockerfile new file mode 100644 index 00000000..e82e88fa --- /dev/null +++ b/student-environments/tests/Dockerfile @@ -0,0 +1,26 @@ +FROM alpine:latest + +ENV AWSCLI_VERSION "1.16.243" +ENV TERRAFORM_VERSION="0.12.9" + +RUN apk add --no-cache git jq curl \ + python \ + python-dev \ + py-pip \ + build-base \ + && pip install awscli==$AWSCLI_VERSION --upgrade --user \ + && apk --purge -v del py-pip \ + && rm -rf /var/cache/apk/* + + +RUN curl -O https://releases.hashicorp.com/terraform/$TERRAFORM_VERSION/terraform_$TERRAFORM_VERSION_linux_amd64.zip && \ + unzip terraform_$TERRAFORM_VERSION_linux_amd64.zip -d /usr/bin/ + +ENV AWS_DEFAULT_REGION= +ENV AWS_ACCESS_KEY_ID= +ENV AWS_SECRET_ACCESS_KEY= +ENV TF_VAR_student_alias= + +RUN mkdir -p /workdir +WORKDIR /workdir + diff --git a/student-environments/tests/exercises.sh b/student-environments/tests/exercises.sh new file mode 100755 index 00000000..97e33954 --- /dev/null +++ b/student-environments/tests/exercises.sh @@ -0,0 +1,33 @@ +#!/bin/bash + +username="$1" +access_key="$2" +secret_key="$3" +region="$4" +exercise_number="$5" +exercise_region="$6" + +export AWS_DEFAULT_REGION=$region +export AWS_ACCESS_KEY_ID=$access_key +export AWS_SECRET_ACCESS_KEY=$secret_key +export TF_VAR_student_alias=$username + +if [ ! -d ./workspace/$username/$exercise_number ]; then + cp -r ../../exercises/$exercise_number ./workspace/$username/$exercise_number +fi +cd ./workspace/$username/$exercise_number + +function common_exec() { + if ! docker run --name "${username}-tests" --rm -e AWS_DEFAULT_REGION=$region -e AWS_ACCESS_KEY_ID=$access_key -e AWS_SECRET_ACCESS_KEY=$secret_key -e TF_VAR_student_alias=$username -v $(pwd):/workdir terraform-workshop/terraform:latest sh -c "$@"; then + touch ../errored + exit 1 + fi +} + +random_seconds=$(jot -r 1 2 15) +sleep $random_seconds +if [[ "$exercise_number" == "03" ]]; then + common_exec "terraform init && terraform apply -auto-approve && sleep 120 && terraform destroy -auto-approve" +elif [[ "$exercise_number" == "11" ]]; then + common_exec "terraform init && terraform apply -var aws_region=$exercise_region -auto-approve && sleep 120 && terraform destroy -var aws_region=$exercise_region -auto-approve" +fi diff --git a/student-environments/tests/test.sh b/student-environments/tests/test.sh new file mode 100755 index 00000000..f384fba9 --- /dev/null +++ b/student-environments/tests/test.sh @@ -0,0 +1,31 @@ +#!/bin/bash + +cd .. +values=$(terraform output -json) +cd ./tests + +docker build -t terraform-workshop/terraform:latest . + +region="us-east-2" +exercise_number="$1" +if [ -z "$exercise_number" ]; then + echo "first arg should be the exercise number" + exit 1 +fi +find . -name errored | xargs rm + +let i=0 +for username in $(echo $values | jq -r '.students.value[].name'); do + access_key=$(echo $values | jq -r '.test_access_keys.value[]['"$i"']') + secret_key=$(echo $values | jq -r '.test_secret_keys.value[]['"$i"']') + exercise_region=$(echo $values | jq -r '.students.value['"$i"'].region') + echo "Executing exercise $exercise_number for $username" + mkdir -p ./workspace/$username + ( + ./exercises.sh $username $access_key $secret_key $region $exercise_number $exercise_region + ) &> ./workspace/$username/$exercise_number.log & + let i=i+1 +done +wait +echo "Any detected errors:" +find . -name errored \ No newline at end of file diff --git a/student-environments/variables.tf b/student-environments/variables.tf new file mode 100644 index 00000000..30e890a5 --- /dev/null +++ b/student-environments/variables.tf @@ -0,0 +1,8 @@ +variable "students" { + type = list(map(string)) + description = "list of students and associated region" +} + +variable "pgp_key" { + description = "base64 encoded gpg key for use in generating user passwords" +} \ No newline at end of file