Terraform: Difference between revisions

1,309 bytes added ,  5 years ago
Marked this version for translation
(Marking for translation)
(Marked this version for translation)
Line 1: Line 1:
<languages />
<languages />
<translate>
<translate>
<!--T:1-->
[https://www.terraform.io/ Terraform] is a tool for defining and provisioning data centre infrastructure, including virtual machines.  Terraform is seeing growing use within the Compute Canada Federation.  Its infrastructure-as-code model allows one to maintain OpenStack resources as a collection of definitions which can be easily updated using favourite text editors, shared among members of a group, and stored in version control.
[https://www.terraform.io/ Terraform] is a tool for defining and provisioning data centre infrastructure, including virtual machines.  Terraform is seeing growing use within the Compute Canada Federation.  Its infrastructure-as-code model allows one to maintain OpenStack resources as a collection of definitions which can be easily updated using favourite text editors, shared among members of a group, and stored in version control.


<!--T:2-->
This page is written as a tutorial in which we introduce Terraform and demonstrate its use on our OpenStack clouds.  We set up our local workspace for Terraform and create a VM with a floating IP and attached volume.
This page is written as a tutorial in which we introduce Terraform and demonstrate its use on our OpenStack clouds.  We set up our local workspace for Terraform and create a VM with a floating IP and attached volume.


== Preparation ==
== Preparation == <!--T:3-->


<!--T:4-->
Before starting with Terraform, you need  
Before starting with Terraform, you need  
* access to an OpenStack tenant with available resources,  
* access to an OpenStack tenant with available resources,  
Line 12: Line 15:
* a few things configured on your workstation or laptop.
* a few things configured on your workstation or laptop.


=== Access to OpenStack ===
=== Access to OpenStack === <!--T:5-->


<!--T:6-->
For access to the cloud, see [[Cloud#Getting_a_Cloud_project | Getting a Cloud project]] on the Compute Canada Docs wiki. If you’ve never used OpenStack before, you should familiarize yourself with it first by creating a VM, attaching a volume, associating a floating IP, and ensuring you can login to the VM afterwards.  This tutorial also assumes you already have an SSH keypair created and the public key stored with OpenStack.
For access to the cloud, see [[Cloud#Getting_a_Cloud_project | Getting a Cloud project]] on the Compute Canada Docs wiki. If you’ve never used OpenStack before, you should familiarize yourself with it first by creating a VM, attaching a volume, associating a floating IP, and ensuring you can login to the VM afterwards.  This tutorial also assumes you already have an SSH keypair created and the public key stored with OpenStack.


<!--T:7-->
If you don’t yet know how to do these things, the [[Cloud Quick Start]] guide will get you going.  The experience of creating these resources using the web interface will lay a foundation for understanding both what Terraform is doing, and where it has value.
If you don’t yet know how to do these things, the [[Cloud Quick Start]] guide will get you going.  The experience of creating these resources using the web interface will lay a foundation for understanding both what Terraform is doing, and where it has value.


=== Terraform ===
=== Terraform === <!--T:8-->


<!--T:9-->
See the [https://www.terraform.io/downloads.html Terraform downloads page] for the latest client. This guide is based on Terraform 0.12.
See the [https://www.terraform.io/downloads.html Terraform downloads page] for the latest client. This guide is based on Terraform 0.12.


=== Credentials ===
=== Credentials === <!--T:10-->


<!--T:11-->
There are two ways to provide your OpenStack credentials in a command-line environment: via environment variables or in a configuration file.  We'll need to use one of these methods with Terraform, described in the [[#Defining_OpenStack_provider|next section]].  Regardless of your preferred method, the OpenStack web interface offers a simple way to download credentials: once logged in, click on ''API Access'' in the navigation bar, and on that page is a drop-down menu entitled “Download OpenStack RC File”. From here you may download a <code>clouds.yaml</code> file or an RC file which can be sourced from your shell session.
There are two ways to provide your OpenStack credentials in a command-line environment: via environment variables or in a configuration file.  We'll need to use one of these methods with Terraform, described in the [[#Defining_OpenStack_provider|next section]].  Regardless of your preferred method, the OpenStack web interface offers a simple way to download credentials: once logged in, click on ''API Access'' in the navigation bar, and on that page is a drop-down menu entitled “Download OpenStack RC File”. From here you may download a <code>clouds.yaml</code> file or an RC file which can be sourced from your shell session.


<!--T:12-->
The RC file is a series of shell commands which export environment variables to your current shell session.  It's not a standalone script and must be sourced in the context of the current session, like so:</translate>
The RC file is a series of shell commands which export environment variables to your current shell session.  It's not a standalone script and must be sourced in the context of the current session, like so:</translate>


<source lang="shell">$ source openrc.sh</source>
<source lang="shell">$ source openrc.sh</source>
<translate>It will then prompt you for your OpenStack password, which along with necessary information about you, your tenant and the cloud you’re connecting to will be stored in environment variables prefixed by <code>OS_</code>, such as <code>$OS_AUTH_URL</code> and so on.
<translate><!--T:13-->
It will then prompt you for your OpenStack password, which along with necessary information about you, your tenant and the cloud you’re connecting to will be stored in environment variables prefixed by <code>OS_</code>, such as <code>$OS_AUTH_URL</code> and so on.


<!--T:14-->
The other method is to create a configuration in <code>$HOME/.config/openstack/clouds.yaml</code>. If you don’t have such a file already, you can download `clouds.yaml` as described above and move it into place.  We recommend changing the name given to the cloud in the downloaded file to something meaningful, especially if you use more than one OpenStack cloud. Then, to use the CLI tools described below, simply create an environment variable <code>$OS_CLOUD</code> with the name of the cloud you want to use.
The other method is to create a configuration in <code>$HOME/.config/openstack/clouds.yaml</code>. If you don’t have such a file already, you can download `clouds.yaml` as described above and move it into place.  We recommend changing the name given to the cloud in the downloaded file to something meaningful, especially if you use more than one OpenStack cloud. Then, to use the CLI tools described below, simply create an environment variable <code>$OS_CLOUD</code> with the name of the cloud you want to use.
</translate>
</translate>
Line 36: Line 46:
<source lang="shell">$ export OS_CLOUD=arbutus</source>
<source lang="shell">$ export OS_CLOUD=arbutus</source>


<translate>Whichever you have chosen, you will use this to configure Terraform.
<translate><!--T:15-->
Whichever you have chosen, you will use this to configure Terraform.


=== OpenStack session ===
=== OpenStack session === <!--T:16-->


<!--T:17-->
It is helpful to have a terminal window open running the OpenStack CLI. This provides a handy reference for the specifications you will be building, as you will be looking up flavour and image IDs, and it is useful for verifying the actions performed by Terraform. Horizon can be used for looking up images, and for verifying in general that Terraform is having the intended effects, but it is not possible to directly lookup flavour IDs.
It is helpful to have a terminal window open running the OpenStack CLI. This provides a handy reference for the specifications you will be building, as you will be looking up flavour and image IDs, and it is useful for verifying the actions performed by Terraform. Horizon can be used for looking up images, and for verifying in general that Terraform is having the intended effects, but it is not possible to directly lookup flavour IDs.


<!--T:18-->
The OpenStack CLI (referred to as “OSC”) is a Python client which can be best installed through Python Pip, [https://docs.openstack.org/newton/user-guide/common/cli-install-openstack-command-line-clients.html and available for multiple OSes and distributions].
The OpenStack CLI (referred to as “OSC”) is a Python client which can be best installed through Python Pip, [https://docs.openstack.org/newton/user-guide/common/cli-install-openstack-command-line-clients.html and available for multiple OSes and distributions].


=== Terraform workspace ===
=== Terraform workspace === <!--T:19-->


<!--T:20-->
Finally, create a directory for your Terraform configuration and state files and consider this your home base for this guide. This is where we will start.
Finally, create a directory for your Terraform configuration and state files and consider this your home base for this guide. This is where we will start.


== Defining OpenStack provider ==
== Defining OpenStack provider == <!--T:21-->


<!--T:22-->
First, describe the ''provider'': this is where you tell Terraform to use OpenStack, and how. On initialization the most recent version of the OpenStack provider plugin will be installed in the working directory and on subsequent Terraform operations the included credentials will be used to connect to the specified cloud.
First, describe the ''provider'': this is where you tell Terraform to use OpenStack, and how. On initialization the most recent version of the OpenStack provider plugin will be installed in the working directory and on subsequent Terraform operations the included credentials will be used to connect to the specified cloud.


<!--T:23-->
Your connection and credential information for OpenStack can be provided to Terraform in the specification, in the environment, or partially in the specification with the rest in the environment.
Your connection and credential information for OpenStack can be provided to Terraform in the specification, in the environment, or partially in the specification with the rest in the environment.


<!--T:24-->
The following is an example of a provider specification with connection and credential information:
The following is an example of a provider specification with connection and credential information:
</translate>
</translate>
Line 67: Line 84:


<translate>
<translate>
<!--T:25-->
For some OpenStack instances the above would specify the complete set of information necessary to connect to the instance and manage resources in the given project (“tenant”). However, Terraform supports ''partial credentials'' in which you could leave some values out of the Terraform configuration and supply them a different way. This would allow us, for example, to leave the password out of the configuration file, in which case it would need to be specified in the environment with <code>$OS_PASSWORD</code>.
For some OpenStack instances the above would specify the complete set of information necessary to connect to the instance and manage resources in the given project (“tenant”). However, Terraform supports ''partial credentials'' in which you could leave some values out of the Terraform configuration and supply them a different way. This would allow us, for example, to leave the password out of the configuration file, in which case it would need to be specified in the environment with <code>$OS_PASSWORD</code>.


<!--T:26-->
Alternatively, if you prefer to use <code>clouds.yaml</code>, specify <code>cloud</code> in the provider stanza:
Alternatively, if you prefer to use <code>clouds.yaml</code>, specify <code>cloud</code> in the provider stanza:
</translate>
</translate>
Line 77: Line 96:


<translate>
<translate>
<!--T:27-->
It's acceptable to leave the provider definition completely empty:
It's acceptable to leave the provider definition completely empty:
</translate>
</translate>
Line 84: Line 104:


<translate>
<translate>
<!--T:28-->
In this case, either <code>$OS_CLOUD</code> or the variables set by the appropriate RC file would need to be in the executing environment for Terraform to proceed.
In this case, either <code>$OS_CLOUD</code> or the variables set by the appropriate RC file would need to be in the executing environment for Terraform to proceed.


<!--T:29-->
The [https://www.terraform.io/docs/providers/openstack/index.html configuration reference of the OpenStack Provider] describes the available options in detail.
The [https://www.terraform.io/docs/providers/openstack/index.html configuration reference of the OpenStack Provider] describes the available options in detail.


=== What should you use? ===
=== What should you use? === <!--T:30-->


<!--T:31-->
It may be tempting to leave some of the details in the environment so that the Terraform configuration is more portable or reusable, but as we will see later, the Terraform configuration will and must contain details which are specific to each cloud, such as flavour and image UUIDs, network names, and tenants.
It may be tempting to leave some of the details in the environment so that the Terraform configuration is more portable or reusable, but as we will see later, the Terraform configuration will and must contain details which are specific to each cloud, such as flavour and image UUIDs, network names, and tenants.


<!--T:32-->
The most important consideration in what goes into your configuration in this regard is security. You probably want to avoid storing your credentials in the Terraform configuration, even if you’re not sharing it with anyone, even if it’s on your own workstation and nobody has access but you. Even if you’re not worried about hacking, it is definitely not good practice to store passwords and such in configuration files which may wind up getting copied and moved around your filesystem as you try things out. But also, always remember the “ABC” of Hacking: <strong>A</strong>lways <strong>B</strong>e <strong>C</strong>oncerned about Hacking!
The most important consideration in what goes into your configuration in this regard is security. You probably want to avoid storing your credentials in the Terraform configuration, even if you’re not sharing it with anyone, even if it’s on your own workstation and nobody has access but you. Even if you’re not worried about hacking, it is definitely not good practice to store passwords and such in configuration files which may wind up getting copied and moved around your filesystem as you try things out. But also, always remember the “ABC” of Hacking: <strong>A</strong>lways <strong>B</strong>e <strong>C</strong>oncerned about Hacking!


=== Initializing Terraform ===
=== Initializing Terraform === <!--T:33-->


<!--T:34-->
To ensure we have the provider set up correctly, initialize Terraform and check the configuration so far. With the provider definition in a file called, for example, <code>nodes.tf</code>, run <code>terraform init</code>:
To ensure we have the provider set up correctly, initialize Terraform and check the configuration so far. With the provider definition in a file called, for example, <code>nodes.tf</code>, run <code>terraform init</code>:
</translate>
</translate>
Line 128: Line 153:


<translate>
<translate>
<!--T:35-->
This shows success in initializing Terraform and downloading the OpenStack provider plugin so the OpenStack stanzas will be handled correctly. This does not test out the credentials because this operation doesn’t actually try to connect to the defined provider.
This shows success in initializing Terraform and downloading the OpenStack provider plugin so the OpenStack stanzas will be handled correctly. This does not test out the credentials because this operation doesn’t actually try to connect to the defined provider.


== Defining a VM ==
== Defining a VM == <!--T:36-->


<!--T:37-->
So let’s look at defining a basic VM.
So let’s look at defining a basic VM.


<!--T:38-->
<blockquote>'''Important''': It is good practice to '''always''' specify flavours and images using their IDs even when Terraform supports using the name. Although the name is more readable, the ID is what actually defines the state of the resource and the ID of a given image or flavour '''will never change'''. It is possible, however, for the '''name''' to change. If a flavour or image is retired, for example, and replaced with another of the same name, the next time you run Terraform, the updated ID will be detected and Terraform will determine that you want to '''rebuild or resize the associated resource'''. This is a destructive (and reconstructive) operation.
<blockquote>'''Important''': It is good practice to '''always''' specify flavours and images using their IDs even when Terraform supports using the name. Although the name is more readable, the ID is what actually defines the state of the resource and the ID of a given image or flavour '''will never change'''. It is possible, however, for the '''name''' to change. If a flavour or image is retired, for example, and replaced with another of the same name, the next time you run Terraform, the updated ID will be detected and Terraform will determine that you want to '''rebuild or resize the associated resource'''. This is a destructive (and reconstructive) operation.
</blockquote>
</blockquote>
Line 148: Line 176:


<translate>
<translate>
<!--T:39-->
This will create a VM with the given name, image and flavor, and associate with it a key pair and the default security group.
This will create a VM with the given name, image and flavor, and associate with it a key pair and the default security group.


<!--T:40-->
<blockquote>'''Note''': If you’re following along (please do!), use your own values for <code>image_id</code>, <code>flavor_id</code>, and <code>key_pair</code>, or this will probably fail!
<blockquote>'''Note''': If you’re following along (please do!), use your own values for <code>image_id</code>, <code>flavor_id</code>, and <code>key_pair</code>, or this will probably fail!
</blockquote>
</blockquote>
The values for <code>image_id</code> and <code>flavor_id</code> are one reason I like to have a terminal session open running the OpenStack CLI, connected to the cloud I’m targeting with Terraform: I switch over to it and issue <code>flavor list</code> or <code>image list</code>. These list the names and IDs.
The values for <code>image_id</code> and <code>flavor_id</code> are one reason I like to have a terminal session open running the OpenStack CLI, connected to the cloud I’m targeting with Terraform: I switch over to it and issue <code>flavor list</code> or <code>image list</code>. These list the names and IDs.


<!--T:41-->
If using Horizon (the OpenStack web interface), this is semi-possible–see the [[#Finding_image_and_flavour_UUIDs_in_Horizon|guide in the appendix]].
If using Horizon (the OpenStack web interface), this is semi-possible–see the [[#Finding_image_and_flavour_UUIDs_in_Horizon|guide in the appendix]].


<!--T:42-->
Note that no volumes are supplied. A compute instance in Compute Canada will already have an associated volume but a persistent instance will probably fail unless there is sufficient empty space in the image itself. It is [[OpenStack#Booting_from_a_Volume|recommended that a boot volume be created]] for VMs using persistent flavours.
Note that no volumes are supplied. A compute instance in Compute Canada will already have an associated volume but a persistent instance will probably fail unless there is sufficient empty space in the image itself. It is [[OpenStack#Booting_from_a_Volume|recommended that a boot volume be created]] for VMs using persistent flavours.


=== Trying it out ===
=== Trying it out === <!--T:43-->


<!--T:44-->
The command <code>terraform plan</code> compiles the Terraform definition and attempts to determine how to reconcile the resulting desired state with the actual state on the cloud, and produces a plan of what it would if the changes were applied.
The command <code>terraform plan</code> compiles the Terraform definition and attempts to determine how to reconcile the resulting desired state with the actual state on the cloud, and produces a plan of what it would if the changes were applied.
</translate>
</translate>
Line 219: Line 252:


<translate>
<translate>
<!--T:45-->
Read through this output.  This is a lot of information but it’s ''definitely'' required to check this before applying changes to ensure there are no surprises.
Read through this output.  This is a lot of information but it’s ''definitely'' required to check this before applying changes to ensure there are no surprises.


<!--T:46-->
<blockquote>If you get an error about incomplete credentials, you may have forgotten to define <code>OS_CLOUD</code> or source the RC file, or your <code>clouds.yaml</code> file may be missing.</blockquote>
<blockquote>If you get an error about incomplete credentials, you may have forgotten to define <code>OS_CLOUD</code> or source the RC file, or your <code>clouds.yaml</code> file may be missing.</blockquote>


<!--T:47-->
These values are to resources as they’d be defined in OpenStack. Anything marked <code>known after apply</code> will be determined from the state of newly created resources queried from OpenStack. Other values are set according to what we’ve defined or determined by the Terraform and the OpenStack plugin as either calculated or default values.
These values are to resources as they’d be defined in OpenStack. Anything marked <code>known after apply</code> will be determined from the state of newly created resources queried from OpenStack. Other values are set according to what we’ve defined or determined by the Terraform and the OpenStack plugin as either calculated or default values.


<!--T:48-->
If you are in a hurry and don’t mind risking destroying or rebuilding resources by mistake, at ''least'' make sure you double-check the last line of the plan:
If you are in a hurry and don’t mind risking destroying or rebuilding resources by mistake, at ''least'' make sure you double-check the last line of the plan:
</translate>
</translate>
Line 231: Line 268:


<translate>
<translate>
<!--T:49-->
In this case we know we’re adding a resource so this looks right. If the other values were non-zero then we’d better have another look at our configuration, state and what’s actually defined in OpenStack and make whatever corrections are necessary.
In this case we know we’re adding a resource so this looks right. If the other values were non-zero then we’d better have another look at our configuration, state and what’s actually defined in OpenStack and make whatever corrections are necessary.


=== Side note: What happens to existing OpenStack resources? ===
=== Side note: What happens to existing OpenStack resources? === <!--T:50-->


<!--T:51-->
You may have VMs already defined in your OpenStack project and wonder whether Terraform will affect those resources.
You may have VMs already defined in your OpenStack project and wonder whether Terraform will affect those resources.


<!--T:52-->
It will not. Terraform has no knowledge of resources already defined in the project and does not attempt to determine existing state. Terraform bases its actions on the given configuration and previously determined state relevant to that configuration. Any existing resources are not represented in either and are invisible to Terraform.
It will not. Terraform has no knowledge of resources already defined in the project and does not attempt to determine existing state. Terraform bases its actions on the given configuration and previously determined state relevant to that configuration. Any existing resources are not represented in either and are invisible to Terraform.


<!--T:53-->
It is possible to import previously defined OpenStack resources into Terraform but [https://dleske.gitlab.io/posts/terraform-import-manually/ it is not a trivial amount of work] and outside the scope of this tutorial. The important thing here is that any existing resources in your OpenStack project are safe from inadvertent mangling from Terraform&mdash;but just to be on the safe side, why don’t you make sure you read the output plans carefully? :)
It is possible to import previously defined OpenStack resources into Terraform but [https://dleske.gitlab.io/posts/terraform-import-manually/ it is not a trivial amount of work] and outside the scope of this tutorial. The important thing here is that any existing resources in your OpenStack project are safe from inadvertent mangling from Terraform&mdash;but just to be on the safe side, why don’t you make sure you read the output plans carefully? :)


=== Applying the configuration ===
=== Applying the configuration === <!--T:54-->


<!--T:55-->
Now, use <code>terraform apply</code> to actually effect the changes described in the plan.
Now, use <code>terraform apply</code> to actually effect the changes described in the plan.
</translate>
</translate>
Line 277: Line 319:


<translate>
<translate>
<!--T:56-->
This fails in this example.  OpenStack projects in Compute Canada have at least two networks defined: one private and one public.  Terraform needs to know which one to use.
This fails in this example.  OpenStack projects in Compute Canada have at least two networks defined: one private and one public.  Terraform needs to know which one to use.


== Adding a network ==
== Adding a network == <!--T:57-->


<!--T:58-->
The name of the private network differs from project to project and the naming convention can differ from cloud to cloud within Compute Canada, but typically they are on a 192.168.X.Y network, and can be found in the CLI using `network list` or on Horizon under ''Network''->''Networks''.  If your project's private network is <code>my-tenant-net</code>, you will add a <code>network</code> resource sub-block to your VM definition similar to the following:
The name of the private network differs from project to project and the naming convention can differ from cloud to cloud within Compute Canada, but typically they are on a 192.168.X.Y network, and can be found in the CLI using `network list` or on Horizon under ''Network''->''Networks''.  If your project's private network is <code>my-tenant-net</code>, you will add a <code>network</code> resource sub-block to your VM definition similar to the following:
</translate>
</translate>
Line 297: Line 341:


<translate>
<translate>
<!--T:59-->
Try again:
Try again:
</translate>
</translate>
Line 358: Line 403:


<translate>
<translate>
<!--T:60-->
You now have a VM created by Terraform. You should see your new VM on Horizon or in the output of <code>server list</code> in your OpenStack terminal window:
You now have a VM created by Terraform. You should see your new VM on Horizon or in the output of <code>server list</code> in your OpenStack terminal window:
</translate>
</translate>
Line 372: Line 418:


<translate>
<translate>
<!--T:61-->
In this example output, there are three other VMs created previously which survive untouched by Terraform.
In this example output, there are three other VMs created previously which survive untouched by Terraform.


=== Recap ===
=== Recap === <!--T:62-->


<!--T:63-->
Note there is now a file in your workspace called <code>terraform.tfstate</code>. This was created by Terraform during the application of the new configuration and confirmation of its success. The state file contains details about the managed resources Terraform uses to determine how to arrive at a new state described by configuration updates. In general, you will not need to look at this file, but know that without it, Terraform cannot properly manage resources and if you delete it, you will need to restore it or recreate it, or manage those resources without Terraform.
Note there is now a file in your workspace called <code>terraform.tfstate</code>. This was created by Terraform during the application of the new configuration and confirmation of its success. The state file contains details about the managed resources Terraform uses to determine how to arrive at a new state described by configuration updates. In general, you will not need to look at this file, but know that without it, Terraform cannot properly manage resources and if you delete it, you will need to restore it or recreate it, or manage those resources without Terraform.


<!--T:64-->
You now have a working VM which has successfully been initialized and is on the private network. You can’t log in and check it out however because you haven’t assigned a floating IP to this host, so it’s not directly accessible from outside the tenant.
You now have a working VM which has successfully been initialized and is on the private network. You can’t log in and check it out however because you haven’t assigned a floating IP to this host, so it’s not directly accessible from outside the tenant.


<!--T:65-->
If you had another host in that tenant with a floating IP, you could use that host as a jump host (sometimes called a ''bastion host'') to the new VM, as they will both be on the same private network. This is a good strategy to use for nodes that do not need to be directly accessible from the internet, such as a database server, or just to preserve floating IPs, which are a limited resource.
If you had another host in that tenant with a floating IP, you could use that host as a jump host (sometimes called a ''bastion host'') to the new VM, as they will both be on the same private network. This is a good strategy to use for nodes that do not need to be directly accessible from the internet, such as a database server, or just to preserve floating IPs, which are a limited resource.


<!--T:66-->
For now, add a floating IP to your new VM.
For now, add a floating IP to your new VM.


== Add a floating IP ==
== Add a floating IP == <!--T:67-->


<!--T:68-->
Floating IPs are not created directly on a VM in OpenStack: they are allocated to the project from a pool and associated with the VM’s private network interface.
Floating IPs are not created directly on a VM in OpenStack: they are allocated to the project from a pool and associated with the VM’s private network interface.


<!--T:69-->
Assuming you do not already have a floating IP allocated for this use, declare a desired floating IP resource like the following example. The only thing you need is to know the pool from which to allocate the floating IP; in Compute Canada clouds this is the external network (<code>ext_net</code> in this example).
Assuming you do not already have a floating IP allocated for this use, declare a desired floating IP resource like the following example. The only thing you need is to know the pool from which to allocate the floating IP; in Compute Canada clouds this is the external network (<code>ext_net</code> in this example).
</translate>
</translate>
Line 396: Line 449:


<translate>
<translate>
<!--T:70-->
You may either apply this change immediately or just use <code>terraform plan</code> to show what would happen.
You may either apply this change immediately or just use <code>terraform plan</code> to show what would happen.
</translate>
</translate>
Line 436: Line 490:


<translate>
<translate>
<!--T:71-->
This floating IP is now ''allocated'' but not yet associated with your VM.  Add the following definition:
This floating IP is now ''allocated'' but not yet associated with your VM.  Add the following definition:
</translate>
</translate>
Line 445: Line 500:


<translate>
<translate>
<!--T:72-->
This new resource defines as its attributes references to other resources and their attributes.
This new resource defines as its attributes references to other resources and their attributes.


<!--T:73-->
<blockquote>'''Note''': Current documentation of the OpenStack provider documentation uses syntax which differs from what is presented here as it has not yet been updated for changes to Terraform v.12.
<blockquote>'''Note''': Current documentation of the OpenStack provider documentation uses syntax which differs from what is presented here as it has not yet been updated for changes to Terraform v.12.
</blockquote>
</blockquote>
Line 487: Line 544:


<translate>
<translate>
<!--T:74-->
Note that it has an associated floating IP, you could probably SSH into the new VM right now.
Note that it has an associated floating IP, you could probably SSH into the new VM right now.
</translate>
</translate>
Line 498: Line 556:


<translate>
<translate>
<!--T:75-->
If not, it may be necessary to add your workstation's IP address to the project's default security group.
If not, it may be necessary to add your workstation's IP address to the project's default security group.


== Add a volume ==
== Add a volume == <!--T:76-->


<!--T:77-->
Next, add a root volume to the VM. Since this will replace its boot disk, ''this is a destructive operation''. This is something you need to watch out for in Terraform, and one of the chief reasons for reading your plans carefully before applying.  It’s unlikely you’re going to accidentally cause critical issues in creating new resources, but it can be deceptively easy to accidentally create configuration changes that require ''rebuilding'' existing VMs.
Next, add a root volume to the VM. Since this will replace its boot disk, ''this is a destructive operation''. This is something you need to watch out for in Terraform, and one of the chief reasons for reading your plans carefully before applying.  It’s unlikely you’re going to accidentally cause critical issues in creating new resources, but it can be deceptively easy to accidentally create configuration changes that require ''rebuilding'' existing VMs.


<!--T:78-->
Since this is a root volume, create it as part of the compute instance, as another subblock along with the network subblock:
Since this is a root volume, create it as part of the compute instance, as another subblock along with the network subblock:
</translate>
</translate>
Line 517: Line 578:


<translate>
<translate>
<!--T:79-->
Set the <code>uuid</code> attribute to the UUID of the image you want to use and remove <code>image_id</code> from the outer block definition. The other attributes are self-explanatory, except for <code>destination_type</code>, which is here set to <code>volume</code> to indicate this is to be stored with an OpenStack-provided volume rather than using disk on the hypervisor. <code>delete_on_termination</code> is important&mdash;for testing, you will probably want this to be <code>true</code> so you don’t have to remember to constantly clean up leftover volumes, but for real use you should consider setting it to <code>false</code> as a last defence against accidental deletion of resources.
Set the <code>uuid</code> attribute to the UUID of the image you want to use and remove <code>image_id</code> from the outer block definition. The other attributes are self-explanatory, except for <code>destination_type</code>, which is here set to <code>volume</code> to indicate this is to be stored with an OpenStack-provided volume rather than using disk on the hypervisor. <code>delete_on_termination</code> is important&mdash;for testing, you will probably want this to be <code>true</code> so you don’t have to remember to constantly clean up leftover volumes, but for real use you should consider setting it to <code>false</code> as a last defence against accidental deletion of resources.


<!--T:80-->
<blockquote>Do ''not'' leave the <code>image_id</code> attribute defined in the outer compute instance definition! This will work, but Terraform will see a change from “boot from volume” to “boot directly from image” on every run, and so will always attempt to rebuild your instance. (This is probably a flaw in the OpenStack provider.)
<blockquote>Do ''not'' leave the <code>image_id</code> attribute defined in the outer compute instance definition! This will work, but Terraform will see a change from “boot from volume” to “boot directly from image” on every run, and so will always attempt to rebuild your instance. (This is probably a flaw in the OpenStack provider.)
</blockquote>
</blockquote>
Line 582: Line 645:


<translate>
<translate>
<!--T:81-->
So note there are several warnings of what’s going to be replaced and what’s going to change, not to mention this line:
So note there are several warnings of what’s going to be replaced and what’s going to change, not to mention this line:


<!--T:82-->
<source lang="shell">Plan: 2 to add, 0 to change, 2 to destroy.</source>
<source lang="shell">Plan: 2 to add, 0 to change, 2 to destroy.</source>


<!--T:83-->
Your VM will be created with a new SSH key, so if you connected previously you'll need to remove the SSH key from your <code>known_hosts</code> file (or the equivalent).  After this, the first thing to do is log on and ''apply all available updates''.
Your VM will be created with a new SSH key, so if you connected previously you'll need to remove the SSH key from your <code>known_hosts</code> file (or the equivalent).  After this, the first thing to do is log on and ''apply all available updates''.
</translate>
</translate>
Line 594: Line 660:


<translate>
<translate>
<!--T:84-->
So you now have a working, Terraformed VM and a way to get to it and a place on it to store data once we get there, with the latest OS patches applied.
So you now have a working, Terraformed VM and a way to get to it and a place on it to store data once we get there, with the latest OS patches applied.


== The full example ==
== The full example == <!--T:85-->
</translate>
</translate>


Line 632: Line 699:


<translate>
<translate>
== Appendix ==
== Appendix == <!--T:86-->


=== References ===
=== References === <!--T:87-->


<!--T:88-->
The following might be of interest to those exploring further and building on the work done in this tutorial. Note that as of this writing the OpenStack provider’s documentation conforms to v0.11 syntax, but this should work under v0.12 without trouble.
The following might be of interest to those exploring further and building on the work done in this tutorial. Note that as of this writing the OpenStack provider’s documentation conforms to v0.11 syntax, but this should work under v0.12 without trouble.


<!--T:89-->
* [https://www.terraform.io/intro/index.html Introduction to Terraform]
* [https://www.terraform.io/intro/index.html Introduction to Terraform]
* [https://www.terraform.io/docs/providers/openstack/index.html OpenStack provider]
* [https://www.terraform.io/docs/providers/openstack/index.html OpenStack provider]
Line 643: Line 712:
* [[Cloud|Compute Canada cloud documentation]] and the [[Cloud Quick Start]] Guide
* [[Cloud|Compute Canada cloud documentation]] and the [[Cloud Quick Start]] Guide


=== Examples ===
=== Examples === <!--T:90-->


<!--T:91-->
* The [https://git.computecanada.ca/magic_castle Magic Castle] project
* The [https://git.computecanada.ca/magic_castle Magic Castle] project
* [https://git.computecanada.ca/jeanfran/terraform-ceph-ansible-deployment-testing Terraform Ceph Ansible deployment testing] project
* [https://git.computecanada.ca/jeanfran/terraform-ceph-ansible-deployment-testing Terraform Ceph Ansible deployment testing] project


=== Finding image and flavour UUIDs in Horizon ===
=== Finding image and flavour UUIDs in Horizon === <!--T:92-->


<!--T:93-->
For those more comfortable using the web interface to OpenStack, here is a quick cheat sheet on finding flavour and image UUIDs in Horizon. You’ll need to log into the web interface of the desired cloud for this information.
For those more comfortable using the web interface to OpenStack, here is a quick cheat sheet on finding flavour and image UUIDs in Horizon. You’ll need to log into the web interface of the desired cloud for this information.


<!--T:94-->
To find an image’s UUID, find the ''Images'' menu item under ''Compute'' (1).
To find an image’s UUID, find the ''Images'' menu item under ''Compute'' (1).


<!--T:95-->
[[File:images-1.png|thumb|Find and select desired image]]
[[File:images-1.png|thumb|Find and select desired image]]


<!--T:96-->
You’ll get a list of images available to your project. Click on the one you’d like to use. (2)
You’ll get a list of images available to your project. Click on the one you’d like to use. (2)


<!--T:97-->
[[File:images-2.png|thumb|Now you’ve got the UUID]]
[[File:images-2.png|thumb|Now you’ve got the UUID]]


<!--T:98-->
…and there’s the ID.
…and there’s the ID.


<!--T:99-->
It’s a little tougher for flavours.
It’s a little tougher for flavours.


<!--T:100-->
For this you have to fake out launching an instance, but that doesn’t even give you the ID of the flavour. But at least you’ll know the ''name'' of the flavour you want.
For this you have to fake out launching an instance, but that doesn’t even give you the ID of the flavour. But at least you’ll know the ''name'' of the flavour you want.


<!--T:101-->
[[File:flavour-1.png|thumb|Go to launch an instance]]
[[File:flavour-1.png|thumb|Go to launch an instance]]


<!--T:102-->
Once the launch dialog is open, select the ''Flavor'' pane.
Once the launch dialog is open, select the ''Flavor'' pane.


<!--T:103-->
[[File:flavour-2.png|thumb|On the instance launch dialog select “Flavor”]]
[[File:flavour-2.png|thumb|On the instance launch dialog select “Flavor”]]


<!--T:104-->
Now you should have a list of flavours and it’ll also show you which ones fit within your quotas. All you’ve got here is the name, though.
Now you should have a list of flavours and it’ll also show you which ones fit within your quotas. All you’ve got here is the name, though.


<!--T:105-->
[[File:flavour-3.png|thumb|Select a flavour from the list]]
[[File:flavour-3.png|thumb|Select a flavour from the list]]


<!--T:106-->
To actually get the ID, you have two options:
To actually get the ID, you have two options:


<!--T:107-->
# Use the name for the first Terraform run, and then get the ID from the output or state file, and finally, switch your configuration to use the ID instead. This should not attempt to recreate the VM, but check before you agree to <code>terraform apply</code>.
# Use the name for the first Terraform run, and then get the ID from the output or state file, and finally, switch your configuration to use the ID instead. This should not attempt to recreate the VM, but check before you agree to <code>terraform apply</code>.
# Switch to using the OpenStack CLI. (Recommended.)
# Switch to using the OpenStack CLI. (Recommended.)


== Notes ==
== Notes == <!--T:108-->


<!--T:109-->
This material is adapted from a posting which appeared on [https://acme.c3.ca the ACME group blog] (Compute Canada staff only; login required).  The original is [https://acme.c3.ca/blog/getting-started-with-terraform/ here] and is the first article in a series on Terraform.
This material is adapted from a posting which appeared on [https://acme.c3.ca the ACME group blog] (Compute Canada staff only; login required).  The original is [https://acme.c3.ca/blog/getting-started-with-terraform/ here] and is the first article in a series on Terraform.
</translate>
</translate>
cc_staff
44

edits