**DOCUMENTATION**: To see the resources/data-sources and their parameters go to : ** "https://www.terraform.io/docs/providers/oci/" > Core > Resources **\\ * [[https://github.com/ipspace/pubcloud]] * [[https://github.com/rojopolis/TerraformLiveLessons|oreilly_course_code]] ; [[https://github.com/rojopolis/TerraformLiveLessons/blob/master/terraform/hcl/main.tf|Quick-reference]] * [[https://drive.google.com/drive/folders/1hfEqFtbDJ6N39aK6DbNchrSDMRtWfyUx?usp=sharing|oci_course-slides]] * This is the idea but not always strictly true: * Modules is what i write, building blocks, reusable. * But eventually, what is implemented is a Resource. It refers to a **oci_core resource** that can be found in the page above ---- **PROVIDER**: for terraform is a **driver** for tf code to translate into oci api calls. Configure the provider [[https://www.terraform.io/docs/providers/oci/index.html|External Link]] # This is the bare minimum to setup the provider provider "oci" { tenancy_ocid = "${var.tenancy_ocid}" user_ocid = "${var.user_ocid}" fingerprint = "${var.fingerprint}" private_key_path = "${var.private_key_path}" region = "${var.region}" } terraform state list # lists all resources in the state file terraform show # human readable format terraform init # initializes the modules and calls the provider. Once, when we change project/lapto, see [[https://www.terraform.io/docs/ commands/get.html|link] terraform get # downloads all required modules terraform fmt -recursive # fixes syntax. Tabs are important terraform plan -out example1.tfplan # like a dry test terraform apply example1.tfplan # actual push . terraform state list # enumerates all state elements terraform state show # for details ---- **DATA SOURCES (RO)** : Are more like to grab info. from existing, read-only stuff ( you can't always (actually, far from it) have the complete infrastructure in your tf templates, resources already exist and you don't have much control over them but you still need to use them inside your Terraform templates). \\ Do not confuse with data sources. Output comes from the successful creation of a thing (like the output of a module). Data is accessing a thing that already exists but isn't necessarily managed in this state. E.g. getting a vpc id when your networking layer is in a different terraform state, data "oci_identity_availability_domains" "test_availability_domains" { compartment_id = var.tenancy_ocid } # needs the output below to show the datasource pulled from the cloud when doing the 'tf apply' # syntax : data.TYPE.VALUE.ATTRIBUTE output { value = data.oci_identity_availability_domain.test_availability_domains.availability_domains } * Resources are for creating things so for example oci_dns_records. * Data source that will show you things [[https://www.terraform.io/docs/providers/oci/d/dns_records.html]] \\ Syntax: resource "oci_core_instance" "instance" { # << "provider_resource" "name of this specific resource" ---- VARIABLES: There are called with **var.**. They need to be defined before used (only in the same folder, not in subfolders). * terraform.tfvars : tfvars file extension is in the root folder of an environment to define values to variables. So we use a *.tfvar file to load in defaults as they are automatically loaded without any additional command line option. * variables.tf : the .tf uses modules to declare them * variable.tfvar vs. variable.tf : The former contains just the vaulues in a ''map'' format. More info [[https://drive.google.com/file/d/1sjIazwMtXbcSOnTruvrsUner9xCz63uQ/view?usp=sharing|Here]] * **VARIABLE TYPES:** * string variables (default ones) * [[https://www.terraform.io/docs/configuration-0-11/variables.html#maps|map-variables]] ~dictionary: { } * [[https://www.terraform.io/docs/configuration-0-11/variables.html#lists|list-variables]] [ ] * resource-specific parameters * meta-parameters * provisioners **Local variables** - LOCALS 'alias' to be used when many repeated values are used in the module. Hello to keep your code DRY. Names are scoped to the module. # defind like this: locals { http_port = 80 ... # then called like this: resource "aws_lb_listener" "http" { port = local.http_port ... TBD data "aws_region" "current" { name = local.region } ENVIRONMENTAL VARIABLES:\\ - Terraform looks for environment variables with a special prefix of “TF_VAR_variablename . note that TF_VAR_variablenam overrides the default value of variablename defined inside a tf file ---- **MODULE**: Is a __reusable piece of code__. Any set of Terraform configuration files in a folder is a module. The main one, where we work, is called ''root module'' * Check this [[https://github.com/rojopolis/TerraformLiveLessons/blob/fc54a759b099d4dcf20880c57dc717751f8f1709/terraform/modules/trivial/examples/main.tf|Example]] of an extremely simple module (on a [[https://drive.google.com/file/d/1q8PKfoHnTPgoACZjlhoiC97-Tp6T4IeH/view?usp=sharing|Screenshot]]. << **USEFUL** * when we call the module, the name is unrelated to the resources themselves. * Source points to the moudule's location * main.tf in that location is the module's entry point! * The ''output'' of the module is fed back the the root via output (see screenshot link above) * For the module file structure and conventions, see these two links: [[https://developer.hashicorp.com/terraform/language/modules/develop/structure|Link1]] , [[https://drive.google.com/file/d/1qRJne6Ws9-S3ELtpuBC4qM578rjPzKsU/view?usp=sharing|Link2]] ---- File structure (example): (d)modules main.tf outputs.tf variables.tf provider.tf backend.tf bootstrap.sh __FILES:__ * main.tf : is where the execution starts * provider.tf : * variables.tf : where we define the parameters * outputs.tf : from the user's pow is more an input data. ocna_ranges we put here is **consumed by a module** by means of a statement like "cidr_blocks = module.common.ocna_ranges" ; note 'common' is the folder hosting the outputs.tf file where ocna_ranges is defined!) * data.tf : * data source is not really related to data.tf. A data source is accessed via a special kind of resource known as a data resource, declared using a data block. See this [[https://www.terraform.io/docs/configuration/data-sources.html|LINK]] * backend.tf : for the state file key * 'key' is no more than the name of the state file in the block storage – GUI: Phoenix > block storage > compartment Context_Slingshot > ‘ContextTerraformState’ bucket > then we select the file, which can be easily downloaded << is just a json file \\ __main.tf :__\\ * You normally **create an 'object' module from the 'class' module defined in the modules folder** * count : is a reserved variable and defines how many times it goes via that set of instructions * \\ __variables (in general)__\\ * var -from-> variable.tf like in compartment_id = "${var.server_compartment_ocid}" * vars can be passed also module-to-resource (see below 'passing variables') * module -from→ data.tf * modules group resources (normally in the data.tf ): see link \\ __‘id’ attribute__\\ The syntax is TYPE.NAME.ATTRIBUTE. For example, ${aws_instance.web.id} will interpolate the ID attribute from the aws_instance resource named web. If the resource has a count attribute set, you can access individual attributes with a zero-based index, such as ${aws_instance.web.0.id}. You can also use the splat syntax to get a list of all the attributes: ${aws_instance.web.*.id}. ---- __FILES:__ * setup.sh * userdata.sh : for the ldap authenticatio * bootstrap.sh : from gavin (includes userdata.sh ) ---- PASSING VARIABLES TO MODULES: \\ ! In the module folder, we have resources. ! also a variable.tf where we Declare the vars (we can also give them a default value) : variable "cluster_name" {.. ! Inside the module's resources, we refer the variables like this : name = "${var.cluster_name}-alb" ! !In the root main,tf (the one calling the modules (aka root module) we call the modules as below and Set the veriables like this: module "lb-docservers-01" { # we call (instantiate) the module source = "./modules/lb" # this is the location of the module lb_display_name = "docservers-lb01" [...] # To: module "webserver_cluster" { source = "../../../modules/services/webserver-cluster" cluster_name = "webservers-stage" # <<<< [...] In terraform there are no global variables. Either they’re specified in the resource/module itself (or in the local variable.tf) or passed as indicated above. \\ **Ways of feeding lists of values to a module:**\\ **note: toset to convert it to a set, which will remove any duplicate elements and disregard the order of the elements.** module "tcp_8443__ocna_sources_tpdlb-be-internet_nsg_lhr" { source = "./modules" for_each = toset(var.ocna_sources) # then ocna_sources is defined in the variables.tf nsg_near_side_id = oci_core_network_security_group.tpdlb-be-internet_nsg_lhr.id traffic_source = each.value Or module "udp_53_cc-be-internet_nsg_lhr" { for_each = toset(["216.146.35.35/32", "216.146.36.36/32", "8.8.8.8/32"]) source = "./modules" nsg_near_side_id = oci_core_network_security_group.cc-be-internet_nsg_lhr.id protocol = "17" traffic_destination = each.key Or (this is for aws, as the plugin accepts list directly in the '''cidr_blocks''' attribute:\\ '''module.common''' is the folder path, then '''mycompany_ranges''' is a list inside the outputs.tf file resource "aws_security_group_rule" "allow_ssh_from_allowlist" { type = "ingress" from_port = 22 to_port = 22 protocol = "tcp" cidr_blocks = concat(module.common.mycompany_ranges, module.common.vpn1_egress_ranges) ---- **OUTPUTS**: \\ Do not confuse with data sources. Output comes from the successful creation of a thing (like the output of a module). Data is accessing a thing that already exists but isn't necessarily managed in this state. E.g. getting a vpc id when your networking layer is in a different terraform state, \\ Example1: If you wanted to output the arn of the following resource in a module: resource "aws_lb" "test" { # ... } You would use: output "blah-es-asg" { value = "${aws_lb.test.arn}" } Then you access the value with: module.name-of-mudule.blah-es-asg Example2: module "tpd-lb01" { source = "./modules/lb" backends = ( [for ip in module.tpd01.only_private_ips : { ip = "${ip}" }]) # That module tpd01 has a source folder. # The folder has a whole structure with main, vars.. and outputs.tf. # By adding .only_private_ips at the end, we make Can Grab the Output of the module (like an output of a functiomn in py) to use it somewhere else. # it Use Like an Output generator 'module' contained in outputs.tf : output "only_private_ips" { value = [ for instance in oci_core_instance.instance : instance.private_ip ] } You cannot simply reference resources that belong to a module but from outside the module. You need to use **outputs**.\\ In an output, you define which data you want to be **returned by the module** In ./modules/application/application.tf file: output "hostname" { value = "${aws_instance.app-server.private_dns}" } # Now you can use this output inside the template.tf like this: module "crazy_foods" { source = "./modules/application" vpc_id = "${aws_vpc.my_vpc.id}" subnet_id = "${aws_subnet.public.id}" name = "CrazyFoods ${module.mighty_trousers.hostname}" } INTERPOLATION: allows us to reference any other resource it manages using the following syntax: ${RESOURCE_TYPE.RESOURCE_NAME.ATTRIBUTE_NAME}. resource "aws_subnet" "public" { vpc_id = "${aws_vpc.my_vpc.id}" cidr_block = "10.0.1.0/24" } # resource "aws_s3_bucket" "bucket2" { bucket = "${data.aws_caller_identity.current.account_id}-bucket2" } ---- [[https://www.hashicorp.com/blog/hashicorp-terraform-0-12-preview-for-and-for-each|LOOPS]]:\\ * for (see above) * for_each = var.db_instances ---- **CONDITIONALS AND THE 'COUNT' PROPERTY** \\ See [[https://github.com/rojopolis/TerraformLiveLessons/blob/fc54a759b099d4dcf20880c57dc717751f8f1709/terraform/hcl/main.tf#L217|example]] HLC is declarative so cannot have explicit ''if.. then..else''. Instead it has this: condition ? true_val : false_val var.a != "" ? var.a : "default-a" ! locals { minimum_number_of_buckets = 5 number_of_buckets = var.bucket_count > 0 ? var.bucket_count : local.minimum_number_of_buckets } ---- **TEMPLATING WITH HEREDOCS** * https://developer.hashicorp.com/terraform/language/expressions/strings ---- **ITERATIONS** * By means of [[https://blog.gruntwork.io/terraform-tips-tricks-loops-if-statements-and-gotchas-f739bbae55f9|list_comprehensions]] ---- Install tf:\\ * download something like this in Downloads folder: terraform_0.11.11_linux_amd64.zip * unzip it and place it in /bin/terraform ---- TO BE SORTED: * vars defined in variables.tf or hardcoded in the resource's module