Search icon CANCEL
Subscription
0
Cart icon
Your Cart (0 item)
Close icon
You have no products in your basket yet
Save more on your purchases now! discount-offer-chevron-icon
Savings automatically calculated. No voucher code required
Arrow left icon
All Products
Best Sellers
New Releases
Books
Videos
Audiobooks
Learning Hub
Newsletters
Free Learning
Arrow right icon
Terraform Cookbook - Second Edition
Terraform Cookbook - Second Edition

Terraform Cookbook: Master Infrastructure as Code efficiency with real-world Azure automation using Terraform, Second Edition

eBook
Mex$573.99 Mex$820.99
Print
Mex$1,025.99
Subscription
Free Trial

What do you get with eBook?

Product feature icon Instant access to your Digital eBook purchase
Product feature icon Download this book in EPUB and PDF formats
Product feature icon AI Assistant (beta) to help accelerate your learning
Product feature icon Access this title in our online reader with advanced features
Product feature icon DRM FREE - Read whenever, wherever and however you want
Table of content icon View table of contents Preview book icon Preview Book

Terraform Cookbook - Second Edition

Writing Terraform Configurations

When you start writing Terraform configurations, you will notice very quickly that the language provided by Terraform is very rich and allows for a lot of manipulation.

In the recipes in this chapter, you will learn how to use the Terraform language effectively to apply it to real-life business scenarios. We will discuss how to use providers by specifying their version, and adding aliases to use multiple instances of the same provider. Then we will discuss how to make the code more dynamic with variables and outputs, and we will consider the use of built-in functions and conditions.

Finally, we will learn how to add dependencies between resources, add custom checks with pre- and postconditions, and check the provisioned infrastructure.

All the code examples explained in this book are for illustrative purposes only. Their purpose is to provision cloud infrastructure resources, which may have a cost depending on the cloud used. I strongly suggest that you delete these resources either manually or via the terraform destroy command, which we’ll look at in detail in the recipe Destroying infrastructure resources in Chapter 6, Applying a Basic Terraform Workflow. Additionally, in a lot of the code on the GitHub repository of this chapter, you’ll see the use of random resources, which allow you to have unique resources.

In this chapter, we will cover the following recipes:

  • Configuring Terraform and the provider version to use
  • Adding alias to a provider to use multiple instances of the same provider
  • Manipulating variables
  • Keeping sensitive variables safe
  • Using local variables for custom functions
  • Using outputs to expose Terraform provisioned data
  • Calling Terraform’s built-in functions
  • Using YAML files in Terraform configuration
  • Writing conditional expressions
  • Generating passwords with Terraform
  • Managing Terraform resource dependencies
  • Adding custom pre- and postconditions
  • Using checks for infrastructure validation

Let’s get started!

Technical requirements

For this chapter, you need to have the Terraform binary installed on your computer. The source code for this chapter is available at https://github.com/PacktPublishing/Terraform-Cookbook-Second-Edition/tree/main/CHAP02.

Configuring Terraform and the provider version to use

The default behavior of Terraform is that, when executing the terraform init command, the version of the Terraform binary (also called the Command-Line Interface (CLI)) used is the one installed on the local workstation. In addition, this command downloads the latest version of the providers used in the code.

Also, as we learned in Chapter 1, Setting Up the Terraform Environment, in the Upgrading Terraform providers recipe, this command creates the Terraform dependencies file, .terraform.lock.hcl.

However, for compatibility reasons, it is always advisable to avoid surprises so that you can specify which version of the Terraform binary is going to be used in the Terraform configuration. The following are some examples:

  • A Terraform configuration that uses language constructs introduced in version 0.12 must be executed with that or a greater version
  • A Terraform configuration that contains new features, such as count and for_each, in modules must be executed with Terraform version 0.13 or greater

For more details about the HCL syntax, read the documentation at https://www.terraform.io/docs/configuration/syntax.html.

In the same way and for the same reasons of compatibility, we may want to specify the provider version to be used.

In this recipe, we will learn how to specify the Terraform version, as well as the provider version, that will be used.

Getting ready

To start this recipe, we will write a basic Terraform configuration file that contains the following code:

variable "resource_group_name" {
  default = "rg_test"
}
resource "azurerm_resource_group" "rg" {
  name     = var.resource_group_name
  location = "westeurope"
}
resource "azurerm_public_ip" "pip" {
  name                         = "bookip"
  location                     = "westeurope"
  resource_group_name          = azurerm_resource_group.rg.name
  allocation_method = "Dynamic"
  domain_name_label            = "bookdevops"
}

The source code of this Terraform configuration is available at https://github.com/PacktPublishing/Terraform-Cookbook-Second-Edition/blob/main/CHAP02/version/specific-version.tf.

This example code provides resources in Azure (a resource group and a public IP address).

For more details about the Terraform azurerm provider, read the following documentation: https://registry.terraform.io/providers/hashicorp/azurerm.

This Terraform configuration contains the improvements that were made to the HCL 2.0 language since Terraform 0.12 using the new interpolation syntax.

Finally, when executing the terraform plan command with this configuration, we get the following error messages:

Une image contenant texte  Description générée automatiquement

Figure 2.1: A Terraform plan without a specified version

This means that, currently, this Terraform configuration is not compatible with the latest version of the provider (version 2.56).

Now, we need to be aware of the following compliances:

  • This configuration can only be executed if Terraform 0.13 (or higher) is installed on the local workstation.
  • Our current configuration can be executed even if the azurerm provider evolves with breaking changes.

Regarding the new features provided by Terraform 0.13, read the change log at https://github.com/hashicorp/terraform/blob/master/CHANGELOG.md and the upgrade guide at https://developer.hashicorp.com/terraform/language/v1.1.x/upgrade-guides/0-13.

The source code of this recipe is available at https://github.com/PacktPublishing/Terraform-Cookbook-Second-Edition/tree/main/CHAP02/version.

How to do it…

First, we specify the Terraform version to be installed on the local workstation:

  1. In the Terraform configuration, add the following block:
    terraform {
      required_version = ">= 0.13,<=1"
    }
    
  2. To specify the provider source and version to use, we need to add the required_provider block inside the same terraform block configuration:
    terraform {
      ...
      required_providers {
        azurerm = {
          version = "2.10.0"
       }
      }
    }
    

How it works…

When executing the terraform init command, Terraform will check that the version of the installed Terraform binary that executes the Terraform configuration corresponds to the version specified in the required_version property of the terraform block.

If it matches, it won’t throw an error as it is greater than version 0.13. Otherwise, it will throw an error:

Une image contenant texte  Description générée automatiquement

Figure 2.2: Terraform version incompatibility

Regarding the specification of the provider version, when executing the terraform init command, if no version is specified, Terraform downloads the latest version of the provider. Otherwise, it downloads the specified version, as shown in the following two screenshots.

The following screenshot shows the provider plugin that will be downloaded from the specified source without us specifying the required version (at the time of writing, the latest version of the provider is 3.17.0):

Une image contenant texte  Description générée automatiquement

Figure 2.3: Terraform init downloads the latest version of the provider

As we can see, the specific version of the azurerm provider (3.17.0) has been downloaded.

In addition, the following screenshot shows the azurerm provider plugin that will be downloaded when we specify the required version (2.10.0):

Une image contenant texte  Description générée automatiquement

Figure 2.4: Terraform init downloads the specified provider version

As we can see, the specified version of the azurerm provider (2.10.0) has been downloaded.

For more details about the required_version block and provider versions, go to https://www.terraform.io/docs/configuration/terraform.html#specifying-required-provider-versions.

In the required_version block, we also add the source property, which was introduced in version 0.13 of Terraform and is documented at https://www.terraform.io/language/upgrade-guides/0-13#explicit-provider-source-locations.

There’s more…

In this recipe, we learned how Terraform downloads the azurerm provider in several ways. What we did here applies to all providers you may wish to download.

It is also important to mention that the version of the Terraform binary that will be used is specified in the Terraform state file. This is to ensure that nobody applies this Terraform configuration with a lower version of the Terraform binary, thus ensuring that the format of the Terraform state file conforms with the correct version of the Terraform binary.

In the next recipe, we will implement a provider alias to use multiple instances of the same provider.

See also

Adding alias to a provider to use multiple instances of the same provider

When we write Terraform configuration, some providers contain properties for resource access and authentication such as a URL, authentication token, username, or password.

If we want to use multiple different configurations of the same provider in one Terraform configuration, for example, to provision resources in multiple Azure subscriptions in the same configuration, we can use the alias provider property.

Let’s get started!

Getting ready

First, apply this basic Terraform code to create resources on Azure:

provider "azurerm" {
  subscription_id = "xxxx-xxx-xxx-xxxxxx"
  features {}
}
resource "azurerm_resource_group" "rg" {
  name     = "rg-sub1"
  location = "westeurope"
}
resource "azurerm_resource_group" "rg2" {
  name     = "rg-sub2"
  location = westeurope"
}

This Terraform configuration will create two Azure resource groups on the subscription that is configured by the provider (or in the default subscription on your Azure account).

In order to create an Azure resource group in another subscription, we need to use the alias property.

In this recipe, we will use the alias provider property, and to illustrate it we will provision two Azure resource groups in two different subscriptions in one Terraform configuration.

The requirement for this recipe is to have an Azure account, which you can get for free here: https://azure.microsoft.com/en-us/free/

We will also use the azurerm provider with basic configuration.

You can find your available active subscriptions (subscription IDs) at https://portal.azure.com/#view/Microsoft_Azure_Billing/SubscriptionsBlade.

The source code of this recipe is available here: https://github.com/PacktPublishing/Terraform-Cookbook-Second-Edition/tree/main/CHAP02/alias

How to do it…

Perform the following steps to use multiple instances from one provider:

  1. In main.tf, update the initial Terraform configuration in the provider section:
    provider "azurerm" {
      subscription_id = "xxxx-xxx-xxxxx-xxxxxx"
      alias = "sub1"
      features {}
    }
    provider "azurerm" {
      subscription_id = "yyyy-yyyyy-yyyy-yyyyy"
      alias = "sub2"
      features {}
    }
    
  2. Then update the two existing azurerm_resource_group resources:
    resource "azurerm_resource_group" "example1" {
      provider = azurerm.sub1
      name     = "rg-sub1"
      location = "westeurope"
    }
    resource "azurerm_resource_group" "example2" {
      provider = azurerm.sub2
      name     = "rg-sub2"
      location = "westeurope"
    }
    
  3. Finally, to apply the changes, run the Terraform workflow with the init, plan, and apply commands.

How it works…

In Step 1, we duplicate the provider (azurerm) block and, on each provider, we add the alias property with an identification name. The first is sub1 and the second is sub2.

Then we add the different subscription_id properties to specify the subscription where the resource will be created.

In Step 2, in each azurerm_resource_group resource, we add the provider property with a value that corresponds to that of the alias of the desired provider.

Each azurerm_resource_group resource targets the subscription using the provider’s alias.

Finally, we run the terraform init, plan and apply commands. The screenshot below shows the terraform apply command:

Une image contenant texte  Description générée automatiquement

Figure 2.5: Running the apply command

We can see the two different subscriptions where the Azure resource group will be created.

See also

Manipulating variables

When you write a Terraform configuration where all the properties are hardcoded in the code, you often find yourself faced with the problem of having to duplicate it to reuse it.

In this recipe, we’ll learn how to make the Terraform configuration more dynamic by using variables.

Getting ready

To begin, we are going to work on the main.tf file, which contains a basic Terraform configuration:

resource "azurerm_resource_group" "rg" {
  name     = "My-RG"
  location = "West Europe"
}

As we can see, the name and location properties have values statically written in the code.

Let’s learn how to make them dynamic using variables.

The source code of this recipe is available at https://github.com/PacktPublishing/Terraform-Cookbook-Second-Edition/tree/main/CHAP02/variables.

How to do it…

Perform the following steps:

  1. In the same main.tf file, add the following variable declarations:
    variable "resource_group_name" {
      description ="The name of the resource group"
    }
    variable "location" {
      description ="The name of the Azure region"
      default ="westeurope"
    }
    
  2. Then, modify the Terraform configuration we had at the beginning of this recipe so that it refers to our new variables, as follows:
    resource "azurerm_resource_group" "rg" {
      name     = var.resource_group_name
      location = var.location
    }
    
  3. Finally, in the same folder that contains the main.tf file, create a new file called terraform.tfvars and add the following content:
    resource_group_name = "My-RG"
    location            = "westeurope"
    

How it works…

In Step 1, we wrote the declaration of the two variables, which consists of the following elements:

  • A variable name: This must be unique to this Terraform configuration and must be explicit enough to be understood by all the contributors of the code.
  • A description of what this variable represents: This description is optional but is recommended because it can be displayed by the CLI and can also be integrated into the documentation, which is automatically generated.
  • A default value: This is optional. Not setting a default value makes it mandatory to enter a value.

Then, in Step 2, we modified the Terraform configuration to use these two variables. We did this using the var.<name of the variable> syntax.

Finally, in Step 3, we set values for the variables in the terraform.tfvars file, which is used natively by Terraform.

The result of executing this Terraform configuration is shown in the following screenshot:

Une image contenant texte  Description générée automatiquement

Figure 2.6: Using the terraform.tfvars file

There’s more…

Setting a value for the variable is optional in the terraform.tfvars file since we have set a default value for the variable.

Apart from this terraform.tfvars file, it is possible to give a variable a value using the -var option of the terraform plan and terraform apply commands, as shown in the following command:

terraform plan -var "location=westus"

So, with this command, the location variable declared in our code will have a value of westus instead of westeurope.

In addition, in the 0.13 version of Terraform, we can now create custom validation rules for variables, which makes it possible for us to verify a value during the terraform plan execution.

In our recipe, we can complete the location variable with a validation rule in the validation block as shown in the following code:

variable "location" {
  description ="The name of the Azure location"
  default ="westeurope"
  validation {
    condition = contains(["westeurope","westus"], var.location)          error_message = "The location must be westeurope or westus."
  }
}

In the preceding configuration, the rule checks if the value of the location variable is westeurope or westus.

If you put in an invalid value for the location variable, such as francecentrale, the validation rule will display The location must be westeurope or westus:

Une image contenant texte  Description générée automatiquement

Figure 2.7: Variable validation

For more information about variable custom rules validation, read the documentation at https://www.terraform.io/docs/configuration/variables.html#custom-validation-rules.

Finally, there is another alternative to setting a value to a variable, which consists of setting an environment variable called TF_VAR_<variable name>. In our case, we can create an environment variable called TF_VAR_location with a value of westus and then execute the terraform plan command in the classical way.

Note that using the -var option or the TF_VAR_<name of the variable> environment variable doesn’t hardcode these variables’ values inside the Terraform configuration. Terraform makes it possible for us to give values of variables on the fly. But be careful – these options can have consequences if the same code is executed with other values initially provided in parameters and if the plan’s output isn’t reviewed carefully.

See also

In this recipe, we looked at the basic use of variables. We will learn how to protect sensitive variables in the next recipe, and we will examine more advanced uses of these variables when we learn how to manage environments in Chapter 3, Scaling Your Infrastructure with Terraform, in the Managing infrastructure in multiple environments recipe.

For more information on Terraform variables, refer to the documentation at https://www.terraform.io/docs/configuration/variables.html.

Keeping sensitive variables safe

In the Manipulating variables recipe in this chapter, we learned how to use variables to make our Terraform configuration more dynamic. By default, all variables’ values used in the configuration will be stored in clear text in the Terraform state file, and this value will also be in clear text in the console output execution.

In this recipe, we will learn how to keep Terraform variable information safe from prying eyes by not displaying their values in clear text in the console output.

Getting ready

To start with, we will use the Terraform configuration available at https://github.com/PacktPublishing/Terraform-Cookbook-Second-Edition/tree/main/CHAP02/sample-app, which provisions an Azure Web App with custom app settings.

To illustrate this, we will add a custom application API key, which has a sensitive value, in the key-value app setting.

The source code of this recipe is available at https://github.com/PacktPublishing/Terraform-Cookbook-Second-Edition/tree/main/CHAP02/sample-app.

How to do it…

Perform the following steps:

  1. In the main.tf file, which contains our Terraform configuration, in azurerm_linux_web_app we will add an app_settings property that is set with the api_key variable:
    resource "azurerm_linux_web_app" "app" {
      name                = "${var.app_name}-${var.environment} -${random_string.random.result}”
      location            = azurerm_resource_group.rg-app.location
      resource_group_name = azurerm_resource_group.rg-app.name
      service_plan_id     = azurerm_service_plan.plan-app.id
      site_config {}
      app_settings = {
    API_KEY = var.api_key
      }
              }
    
  2. Then, in variable.tf, declare the custom_app_settings variable:
    variable "api_key " {
      description = "Custom application api key"
      sensitive = true
    }
    
  3. In terraform.tfvars, we instantiate this variable with these values (as an example for this book):
    api_key = "xxxxxxxxxxxxxxxxx"
    
  4. Finally, we run the terraform plan command. The following screenshot shows a part of this execution:
Une image contenant texte  Description générée automatiquement

Figure 2.8: Terraform doesn’t display the sensitive variable value

  1. We can see that the value of the api_key property (which is in uppercase in the Terraform plan output) in app_settings isn’t displayed in the console output.

How it works…

In the recipe, we add the sensitive flag to the api_key variable, which enables the protection of the variable. By enabling this flag, the terraform plan command (and the apply command) doesn’t display the value of the variable in the console output in clear text.

There’s more…

Be careful! The sensitive variable property protects the value of this variable from being displayed in the console output, but the value of this is still written in clear text in the Terraform state file.

Then, if this Terraform configuration is stored in a source control such as Git, the default value of this variable or the tfvars file is also readable as clear text in the source code.

So, to protect the value of this variable in source control, we can set the value of this variable by using Terraform’s environment variable technique with the format TF_VAR_<variable name> as we learned in the previous recipe, Manipulating variables.

In our scenario, we can set the TF_VAR_api_key = "xxxxxxxxxxx" environment variable just before the execution of the terraform plan command.

One scenario in which the sensitive variable is effective is when Terraform is executed in a CI/CD pipeline; then, unauthorized users can’t read the value of the variable.

Finally, one best practice is to use an external secret management solution such as Azure Key Vault or HashiCorp Vault (https://www.vaultproject.io/) to store your secrets and use Terraform providers to get these secrets’ values.

See also

Using local variables for custom functions

In the Manipulating variables recipe in this chapter, we learned how to use variables to dynamize our Terraform configuration. Sometimes, this can be a bit tedious when it comes to using combinations of variables.

In this recipe, we will learn how to implement local variables and use them as custom functions.

Getting ready

To start with, we will use the following Terraform configuration:

variable "application_name" {
  description = "The name of application"
}
variable "environment_name" {
  description = "The name of environment"
}
variable "country_code" {
  description = "The country code (FR-US-...)"
}
resource "azurerm_resource_group" "rg" {
  name = "XXXX" # VARIABLE TO USE
  location = "West Europe"
}
resource "azurerm_public_ip" "pip" {
  name = "XXXX" # VARIABLE TO USE
  location = "West Europe"
  resource_group_name = azurerm_resource_group.rg.name
  allocation_method = "Dynamic"
  domain_name_label = "mydomain"
}

The goal of this recipe is to consistently render the names of the Azure resources. We must provide them with the following nomenclature rule:

CodeAzureResource - Name Application - Environment name - Country Code

The source code of this recipe is available at https://github.com/PacktPublishing/Terraform-Cookbook-Second-Edition/tree/main/CHAP02/localvariables.

How to do it…

Follow these steps:

  1. In the main.tf file, which contains our Terraform configuration, we will add a local variable called resource_name, along with the following code:
    locals {
      resource_name = "${var.application_name}-${var.environment_name}-${var.country_code}"
    }
    
  2. We then use this local variable in the resources with the following code:
    resource "azurerm_resource_group" "rg" {
     name = "RG-${local.resource_name}"
     location = "westeurope"
    }
    resource "azurerm_public_ip" "pip" {
     name = "IP-${local.resource_name}"
     location = "westeurope"
     resource_group_name = azurerm_resource_group.rg.name
     allocation_method = "Dynamic"
     domain_name_label = "mydomain"
    }
    

How it works…

In Step 1, we created a variable called resource_name that is local to our Terraform configuration. This allows us to create a combination of several Terraform variables (which we will see the result of in the Using outputs to expose Terraform provisioned data recipe of this chapter).

Then, in Step 2, we used this local variable with the local.<name of the local variable> expression. Moreover, in the name property, we used it as a concatenation of a variable and static text, which is why we used the "${}" syntax.

The result of executing this Terraform configuration is as follows:

Une image contenant texte  Description générée automatiquement

Figure 2.9: Using the locals variable

In the previous screenshot, we can see the output of executing the terraform plan command with the name of the resource group that we calculated with the locals variable.

There’s more…

The difference between a local variable and Terraform variable is that the local variable can’t be redefined in the Terraform variables file (tfvars), with environment variables, or with the -var CLI argument.

See also

Using outputs to expose Terraform provisioned data

When using Infrastructure as Code tools such as Terraform, it is often necessary to retrieve output values from the provisioned resources after code execution.

One of the uses of these output values is that they can be used after execution by other Terraform configurations or external programs. This is often the case when the execution of the Terraform configuration is integrated into a CI/CD pipeline.

For example, we can use these output values in a CI/CD pipeline that creates an Azure App Service instance with Terraform and deploys the application to this Azure App Service instance. In this example, we can have the name of the Azure App Service instance as the output of the Terraform configuration. These output values are also very useful for transmitting information through modules, which we will see in detail in Chapter 5, Managing Terraform State.

In this recipe, we will learn how to implement output values in Terraform configuration to get the name of the provisioned Azure Web App in the output.

Getting ready

To proceed, we are going to add some Terraform configuration that we already have in the existing main.tf file.

The following is an extract of this existing code, which provides an app service in Azure:

...
resource "azurerm_linux_web_app" "app" {
  name                = "${var.app_name}-${var.environment}"
  location            = azurerm_resource_group.rg-app.location
  resource_group_name = azurerm_resource_group.rg-app.name
  service_plan_id     = azurerm_service_plan.plan-app.id
  site_config {}
}
...

The source code of this recipe is available at https://github.com/PacktPublishing/Terraform-Cookbook-Second-Edition/tree/main/CHAP02/sample-app.

How to do it…

To ensure we have an output value, we will just add the following code to the main.tf file:

output "webapp_name" {
  description = "Name of the webapp"
  value = azurerm_linux_web_app.app.name
}

How it works…

The output block of Terraform is defined by a name, webapp_name, and a value, azurerm_linux_web_app.app.name. These refer to the name of the Azure App Service instance that is provided in the same Terraform configuration. Optionally, we can add a description property that describes what the output returns, which can also be very useful for autogenerated documentation.

It is, of course, possible to define more than one output in the same Terraform configuration.

The outputs are stored in the Terraform state file and are displayed when the terraform apply command is executed, as shown in the following screenshot:

Une image contenant texte  Description générée automatiquement

Figure 2.10: Terraform outputs

Here, we see two output values that are displayed at the end of the execution.

There’s more…

There are two ways to retrieve the values of the output to use them:

  • By using the terraform output command in the Terraform CLI, which we will see in Chapter 6, Applying a Basic Terraform Workflow, in the Exporting the output in JSON recipe
  • By using the terraform_remote_state data source, which we will discuss in Using external resources from other state files recipe

Another consideration is that we can also expose an output that contains sensitive values with the goal of avoiding displaying their values in clear text in the console output. To do this, add the sensitive = true property to the output. The code below creates the output for the Azure App Service password:

output "webapp_password" {
  description = "credential of the webapp"
  value       = azurerm_linux_web_app.app.site_credential
  sensitive = true
}

The image below shows the execution of the Terraform configuration that contains this output:

Une image contenant texte  Description générée automatiquement

Figure 2.11: Sensitive output

We can see that the value of the webapp_password output isn’t displayed in the console.

Be careful; the output value will still be in clear text in the Terraform state file.

See also

Calling Terraform’s built-in functions

When provisioning infrastructure or handling resources with Terraform, it is sometimes necessary to use transformations or combinations of elements provided in the Terraform configuration.

For this purpose, the language supplied with Terraform includes functions that are built in and can be used in any Terraform configuration.

In this recipe, we will discuss how to use built-in functions to apply transformations to code.

Getting ready

To complete this recipe, we will start from scratch regarding the Terraform configuration, which will be used to provision a resource group in Azure. This resource group will be named according to the following naming convention:

RG-<APP NAME>-<ENVIRONMENT>

The result of this transformation will return a name that should be entirely in uppercase.

The source code for this recipe is available at https://github.com/PacktPublishing/Terraform-Cookbook-Second-Edition/tree/main/CHAP02/fct.

How to do it…

Perform the following steps:

  1. In a new local folder, create a file called main.tf.
  2. In this main.tf file, write the following code:
    variable "app_name" {
      description = "Name of application"
    }
    variable "environement" {
      description = "Environement Name"
    }
    
  3. Finally, in this main.tf file, write the following Terraform configuration:
    resource "azurerm_resource_group" "rg-app" {
      name     = upper(format("RG-%s-%s",var.app-name,var.environement))
      location = "westeurope"
    }
    

How it works…

In Step 3, we defined the property name of the resource with a Terraform format function, which allows us to format text. In this function, we used the %s verb to indicate that it is a character string that will be replaced, in order, by the name of the application and the name of the environment.

Furthermore, to capitalize everything inside, we encapsulate the format function in the upper function, which capitalizes all its contents.

The result of executing these Terraform commands on this code can be seen in the following screenshot:

Figure 2.12: Terraform built-in function to capitalize text

Thus, thanks to these functions, it is possible to control the properties that will be used in the Terraform configuration. This also allows us to apply transformations automatically, without having to impose constraints on the user using the Terraform configuration.

See also

There are a multitude of predefined functions in Terraform. The full list can be found at https://www.terraform.io/docs/configuration/functions.html (navigate with the left menu to see all built-in functions):

Using YAML files in Terraform configuration

In the previous recipes, we learned that to set dynamic values inside Terraform configuration, we can use variables.

In some use cases, we must use an external source for configuration, such as JSON or YAML files, and we can imagine that these files are provided manually by external teams or generated automatically by external systems, and we can’t rewrite these files in Terraform variables.

The goal of this recipe is to show how to use a YAML file inside a Terraform configuration.

Let’s get started!

Getting ready

To complete this recipe, we have a YAML file named network.yaml with the following content:

vnet: "myvnet"
address_space: "10.0.0.0/16"
subnets:
- name: subnet1
  iprange: "10.0.1.0/24"
- name: subnet2
  iprange: "10.0.2.0/24"

This file contains the configuration of the Azure network with virtual network and subnets configuration, and it’s placed in the same folder as the Terraform configuration.

In our Terraform configuration, we will use this YAML file to provision the Azure virtual network and subnets.

The source code of this recipe is available at https://github.com/PacktPublishing/Terraform-Cookbook-Second-Edition/tree/main/CHAP02/yaml.

How to do it…

Perform the following steps:

  1. First, in main.tf, create a locals variable called network that calls the built-in yamldecode Terraform function:
    locals {
        network = yamldecode(file("network.yaml"))
    }
    
  2. Then call this local.network variable and its subproperties, which are defined in the YAML file inside the Terraform resource:
    resource "azurerm_virtual_network" "vnet" {
      name                = local.network.vnet
      location            = azurerm_resource_group.rg.location
      resource_group_name = azurerm_resource_group.rg.name
      address_space       = [local.network.address_space]
      dynamic "subnet" {
        for_each = local.network.subnets
        content {
          name           = subnet.value.name
          address_prefix = subnet.value.iprange
        }
      }
    }
    
  3. Finally, run the Terraform workflow with the init, plan, and apply commands. The following picture shows the plan execution:
Une image contenant texte  Description générée automatiquement

Figure 2.13: Terraform uses the YAML file

  1. We can see that the Terraform configuration uses the content configuration of the YAML file.

How it works…

In Step 1, we use the built-in Terraform function yamldecode, which takes on the parameters of the network.yaml file. This function decodes YAML content to Terraform key-value maps.

The result of this map is stored in a local variable named network.

Then in Step 2, we call this local variable by using local.network and use all the sub-keys as object notation, defined in the YAML configuration.

That is all for the Terraform configuration. Finally, we run the terraform init, plan, and apply Terraform commands.

The plan execution shows that Terraform uses YAML for configuration.

There’s more…

In this recipe, we saw how to decode a YAML file, but we can also encode a YAML file, from Terraform to YAML, by using the built-in yamlencode Terraform function (https://www.terraform.io/language/functions/yamlencode).

We learned an example of decoding a YAML file. With Terraform we can do the same operations with a JSON file using the built-in jsondecode and jsonencode functions.

However, it is better to use Terraform variables for Terraform variable validation by using the terraform validate command. Indeed, the YAML file will not be integrated into the validation of Terraform if it is badly formatted or if some information is missing – in these instances it will throw an error.

See also

Writing conditional expressions

When writing the Terraform configuration, we may need to make the code more dynamic by integrating various conditions. In this recipe, we will discuss an example of a conditional expression.

Getting ready

For this recipe, we will use the Terraform configuration we wrote in the previous recipe, the code for which is available at https://github.com/PacktPublishing/Terraform-Cookbook-Second-Edition/tree/main/CHAP02/fct.

We will complete this code by adding a condition to the name of the resource group. This condition is as follows: if the name of the environment is equal to Production, then the name of the resource group will be in the form RG-<APP NAME>; otherwise, the name of the resource group will be in the form RG-<APP NAME>-<ENVIRONMENT NAME>.

How to do it…

In the Terraform configuration of the main.tf file, modify the code of the resource group as follows:

resource "azurerm_resource_group" "rg-app" {
    name = var.environment == "Production" ? upper(format("RG-%s",var.app-name)) : upper(format("RG-%s-%s",var.app-name,var.environment))
    location = "westeurope"
}

How it works…

Here, we added the following condition:

condition ? true assert : false assert

The result of executing Terraform commands on this code if the environment variable is equal to Production can be seen in the following screenshot:

Une image contenant texte  Description générée automatiquement

Figure 2.14: Conditional expression first use case

If the environment variable is not equal to Development, we’ll get the following output:

Une image contenant texte  Description générée automatiquement

Figure 2.15: Conditional expression second use case

There’s more…

One of the usual use cases for conditional expressions is to implement a pattern of features flags.

With features flags, we can make the provisioning of resources optional in a dynamic way, as shown in the following code snippet:

resource "azurerm_application_insights" "appinsight-app" {
  count = var.use_appinsight == true ? 1 : 0
  ....
}

In this code, we have indicated to Terraform that if the use_appinsight variable is true, then the count property is 1, which will allow us to provision one Azure Application Insights resource. Conversely, where the use_appinsight variable is false, the count property is 0 and in this case, Terraform does not create an Application Insights resource instance.

See also

Documentation on conditional expressions in Terraform can be found at https://www.terraform.io/language/expressions/conditionals.

Generating passwords with Terraform

When provisioning infrastructure with Terraform, there are some resources that require passwords in their properties, such as account credentials, VMs, and database connection strings.

To ensure better security by not writing passwords as plaintext in the configuration, you can use a random Terraform provider, which allows you to generate a random string that can be used as a password.

In this recipe, we will discuss how to generate a password with Terraform and assign it to a resource.

Getting ready

In this recipe, we need to provision a VM in Azure that will be provisioned with an administrator password generated dynamically by Terraform.

To do this, we will use an already existing Terraform configuration that provisions a VM in Azure.

The source code for this recipe is available at https://github.com/PacktPublishing/Terraform-Cookbook-Second-Edition/tree/main/CHAP02/password.

How to do it…

Perform the following steps:

  1. In the Terraform configuration file for the VM, add the following code:
    resource "random_password" "password" {
      length = 16
      special = true
      override_special = "_%@"
    }
    
  2. Then, in the code of the resource itself, modify the password property with the following code:
    resource "azurerm_linux_virtual_machine" "myterraformvm" {
      name = "myVM"
      location = "westeurope"
      resource_group_name = azurerm_resource_group.myterraformgroup.name
         computer_name = "vmdemo"
         admin_username = "uservm"
         admin_password = random_password.password.result
    ....
    }
    

How it works…

In Step 1, we added the Terraform random_password resource from the random provider, which allows us to generate strings according to the properties provided. These will be sensitive, meaning that they’re treated as sensitive in the CLI by Terraform, so they will not be displayed to the user.

Then, in Step 2, we used its result (with the result property) in the password property of the VM.

The result of executing the terraform plan command on this code can be seen in the following screenshot:

Une image contenant texte  Description générée automatiquement

Figure 2.16: Generating a password with Terraform

As we can see, the result is (sensitive value).

Please note that the fact a property is sensitive in Terraform means that it cannot be displayed when using the Terraform plan and apply commands in the console output display.

On the other hand, it will be present in clear text in the Terraform state file.

See also

Managing Terraform resource dependencies

One of Terraform’s main features is to allow the parallelization of operations while considering resource dependencies.

In this recipe, we will learn how to create dependencies between resources. We will do this using both implicit and explicit dependencies.

Let’s get started!

Getting ready

To start this recipe, we will use the following Terraform configuration to provision an Azure resource group and, inside it, one Azure virtual network.

Here is the basic configuration:

resource "azurerm_resource_group" "rg" {
  name     = "rgdep"
  location = "westeurope"
}
resource "azurerm_virtual_network" "vnet" {
  name                = "vnet"
  location            = "westeurope"
  resource_group_name = "rgdep"
  address_space       = ["10.0.0.0/16"]
}

The problem with the above configuration is that there are no Terraform dependencies between the resource group and the virtual network. Since Terraform executes its operations according to its dependency graph calculation, during the apply execution the virtual network can be created before the resource group. However, this isn’t acceptable because the virtual network must be created after the resource group.

The goal of this recipe is to learn how to create dependencies between the Azure virtual network and the Azure resource group.

Find out more about the concept of dependencies at https://www.terraform.io/language/resources/behavior#resource-dependencies.

The source code of this recipe is available at https://github.com/PacktPublishing/Terraform-Cookbook-Second-Edition/tree/main/CHAP02/dep.

How to do it…

Perform the following steps:

  1. To create implicit dependencies, update the azurerm_virtual_network resource with the following code:
    resource "azurerm_virtual_network" "vnet" {
      name                = "vnet"
      location            = "westeurope"
      resource_group_name = azurerm_resource_group.rg.name
      address_space       = ["10.0.0.0/16"]
    }
    
  2. To create explicit dependencies, update the azurerm_virtual_network resource with the following code:
    resource "azurerm_virtual_network" "vnet" {
      name                = "vnet"
      location            = "westeurope"
      resource_group_name = "rgdep"
      address_space       = ["10.0.0.0/16"]
      depends_on = [azurerm_resource_group.rg]
    }
    

How it works…

In the first configuration, we use an implicit dependency. By using the resource_group_name = azurerm_resource_group.rg.name property, Terraform creates a dependency that is waiting for the creation of the resource so it can know its name and pass it to the virtual network.

In the second configuration, we use an explicit dependency by using the depends_on meta-argument, which contains the list of resources that must be created before this current resource. Here, we explicitly set that the Azure resource group must be created before creating the Azure virtual network.

Finally, we execute the terraform apply command. The following image shows that this execution has dependencies:

Une image contenant texte  Description générée automatiquement

Figure 2.17: Terraform uses implicit and explicit dependency

We can see the order of resource creation: the Azure resource group [1] is created before the Azure virtual network [2].

And when we run the terraform destroy command, the Azure virtual network is destroyed before the Azure resource group.

There’s more…

If we have the choice between using an implicit or explicit dependency, it’s recommended to use an implicit dependency as explained in this documentation: https://www.terraform.io/language/meta-arguments/depends_on#processing-and-planning-consequences

It is possible to display the Terraform resources graph’s dependencies by using the terraform graph command, which we will learn about in detail in Chapter 6, Applying a Basic Terraform Workflow, in the Generating the graph dependencies recipe.

See also

Adding custom pre and postconditions

In a previous recipe, Manipulating variables, we learned that it is possible to add condition validation inside the variable definition.

In Terraform version 1.2 and newer, it’s possible to add custom validation directly in resources, modules, or data sources with preconditions and postconditions.

These customs validations allow Terraform to set some custom rules during the execution of terraform plan. The precondition will be checked just before the rendering of the plan and the postcondition will be checked just after the rendering.

Let’s get started!

Getting ready

To complete this recipe, we will start with this basic Terraform configuration:

resource "azurerm_virtual_network" "vnet" {
  name                = "vnet"
  location            = azurerm_resource_group.rg.location
  resource_group_name = azurerm_resource_group.rg.name
  address_space       =  [var.address_space] 
}

The above Terraform configuration creates an Azure virtual network.

The first check that we want to perform is to be sure that the address_space variable’s value is IP mask /16.

The second check is to verify that the region (location) of the virtual network is "westeurope".

The source code of this recipe is available at https://github.com/PacktPublishing/Terraform-Cookbook-Second-Edition/tree/main/CHAP02/prepostcond.

How to do it…

The following step shows you how to perform the first check, which is the verification of the IP address range:

  1. Update the Terraform configuration of the Azure virtual network with the code below:
    resource "azurerm_virtual_network" "vnet" {
    …..
      address_space       =  [var.address_space]
      lifecycle {
        precondition {
          condition = cidrnetmask(var.address_space) == "255.255.0.0"
          error_message = "The IP Range must be /16"
        }
      }
    }
    
  2. Then, add the second check to verify the location by adding this configuration in the Azure virtual network:
    resource "azurerm_virtual_network" "vnet" {
      name                = "vnet"
      location            = azurerm_resource_group.rg.location
      resource_group_name = azurerm_resource_group.rg.name
      address_space       =  [var.address_space]
      lifecycle {
        precondition {
          condition = cidrnetmask(var.address_space) == "255.255.0.0"
          error_message = "The IP Range must be /16"
        }
        postcondition {
          condition = self.location  == "westeurope"
          error_message = "Location must be westeurope"
        }
      }
    }
    
  3. Finally, run the Terraform workflow and check that no Terraform error is displayed in the console output.

How it works…

In Step 1, we added the first custom check, which corresponds to the precondition that will be run just before the plan. The precondition block is new inside the lifecycle block metadata. Let’s see this precondition in detail:

precondition {
      condition = cidrnetmask(var.address_space) == "255.255.0.0"
      error_message = "The IP Range must be /16"
}

The precondition block contains two properties:

  1. The condition, that is, the code for the check. Here, we check that the cidrmask of the value of the address_mask variable is equal to “255.255.0.0", that is, that the IP range is /16.
  2. The error_message, that is, the error message that is displayed in the console output if the check returns false.

To test this precondition, if we set the value of the address_space variable to "10.0.0.0/24", the terraform plan execution returns this output:

Une image contenant texte  Description générée automatiquement

Figure 2.18: Precondition custom validation error

The error message is displayed and the terraform plan command doesn’t continue.

Then in Step 2, we add the check for testing the region (the data center’s location) of the Azure virtual network, which must be equal to “westeurope". To do this, we add a postcondition block inside the lifecycle metadata with the following configuration:

postcondition {
      condition = self.location  == "westeurope"
      error_message = "Location must be West Europe"
}

In the configuration above, we set the condition property by using the self keyword to refer to the current resource (in this case this is the Azure virtual network) and we set the error message.

Note that the self keyword can be used only on postconditions, at the moment that all properties are determined, which is only after the terraform plan command has been run.

To test this postcondition, we set the location to "westus" and we get this terraform plan output:

Une image contenant texte  Description générée automatiquement

Figure 2.19: Postcondition custom validation error

We can see that the error message is displayed.

See also

Using checks for infrastructure validation

In the previous recipe, Adding custom pre and postconditions, we learned that it is possible to add pre- or postcondition validation inside the resource configuration.

In Terraform version 1.5 and newer, it’s possible to add infrastructure validation directly in the Terraform configuration, which allows us to check that the provisioned infrastructure is working as intended.

Let’s get started!

Getting ready

In this recipe, we will provision a new Azure App Service instance using a Terraform configuration and inside this same Terraform configuration, we will check that the provisioned App Service instance is running and returns an HTTP Status code equal to 200.

Note that in this recipe we will not go into detail about the Terraform configuration for the Azure App Service. We will only look directly at the availability check of the App Service.

So for this recipe, we will start with the Terraform configuration available at https://github.com/PacktPublishing/Terraform-Cookbook-Second-Edition/tree/main/CHAP02/sample-app, which we will copy into another folder called check.

In the recipe we will learn how to check the App Service instance’s availability. The source code of this recipe is available here: https://github.com/PacktPublishing/Terraform-Cookbook-Second-Edition/tree/main/CHAP02/check.

How to do it…

To check the provisioned infrastructure, perform the following steps:

  1. In the main.tf file that is copied into the check folder, add the following Terraform configuration:
    check "response" {
      data "http" "webapp" {
        url      = "https://${azurerm_linux_web_app.app.default_hostname}"
    insecure=True
      }
      assert {
        condition     = data.http.webapp.status_code == 200
        error_message = "Web app response is ${data.http.webapp.status_code}"
      }
    }
    
  2. In this folder, execute the basic Terraform workflow by running the terraform init, plan, and apply commands.

How it works…

In Step 1, we added the check block, which contains:

  • A data HTTP source that performs an HTTP GET on the given URL. Here, we use the default hostname of the web app in the URL property. For more details about the data HTTP source block, refer to the documentation here: https://registry.terraform.io/providers/hashicorp/http/latest/docs/data-sources/http.
  • An assert block that evaluates the response of the data source by checking that the HTTP code is equal to 200 (status code ok). If this evaluation returns false, then the assert block displays the configured error_message.

In Step 2, we run the Terraform workflow to create the Azure web app and check its availability. The following image shows the output of the terraform apply command:

Une image contenant texte, capture d’écran, Police  Description générée automatiquement

Figure 2.20: Check infrastructure validation is successful

There’s more…

  • Unlike the pre and postconditions, checking with the check block does not block resource provisioning if the assertion returns false. Instead, just a warning message in the output is displayed as shown in the following screenshot:
Une image contenant texte, Police, capture d’écran  Description générée automatiquement

Figure 2.21: Check infrastructure validation on error with warning message

See also

Learn more on Discord

To join the Discord community for this book – where you can share feedback, ask questions to the author, and learn about new releases – follow the QR code below:

https://packt.link/cloudanddevops

Left arrow icon Right arrow icon
Download code icon Download Code

Key benefits

  • Get up and running with Terraform (v1+) CLI and automate infrastructure provisioning
  • Discover how to deploy Kubernetes resources with Terraform
  • Become a Terraform troubleshooting expert for streamlined infrastructure management and minimal downtime

Description

Imagine effortlessly provisioning complex cloud infrastructure across various cloud platforms, all while ensuring robustness, reusability, and security. Introducing the Terraform Cookbook, Second Edition - your go-to guide for mastering Infrastructure as Code (IaC) effortlessly. This new edition is packed with real-world examples for provisioning robust Cloud infrastructure mainly across Azure but also with a dedicated chapter for AWS and GCP. You will delve into manual and automated testing with Terraform configurations, creating and managing a balanced, efficient, reusable infrastructure with Terraform modules. You will learn how to automate the deployment of Terraform configurations through continuous integration and continuous delivery (CI/CD), unleashing Terraform's full potential. New chapters have been added that describe the use of Terraform for Docker and Kubernetes, and explain how to test Terraform configurations using different tools to check code and security compliance. The book devotes an entire chapter to achieving proficiency in Terraform Cloud, covering troubleshooting strategies for common issues and offering resolutions to frequently encountered errors. Get the insider knowledge to boost productivity with Terraform - the indispensable guide for anyone adopting Infrastructure as Code solutions.

What you will learn

  • Use Terraform to build and run cloud and Kubernetes infrastructure using IaC best practices
  • Adapt the Terraform command line adapted to appropriate use cases
  • Automate the deployment of Terraform confi guration with CI/CD
  • Discover manipulation of the Terraform state by adding or removing resources
  • Explore Terraform for Docker and Kubernetes deployment, advanced topics on GitOps practices, and Cloud Development Kit (CDK)
  • Add and apply test code and compliance security in Terraform configuration
  • Debug and troubleshoot common Terraform errors

Product Details

Country selected
Publication date, Length, Edition, Language, ISBN-13
Publication date : Aug 31, 2023
Length 634 pages
Edition : 2nd Edition
Language : English
ISBN-13 : 9781804616420
Concepts :

What do you get with eBook?

Product feature icon Instant access to your Digital eBook purchase
Product feature icon Download this book in EPUB and PDF formats
Product feature icon AI Assistant (beta) to help accelerate your learning
Product feature icon Access this title in our online reader with advanced features
Product feature icon DRM FREE - Read whenever, wherever and however you want

Product Details

Publication date : Aug 31, 2023
Length 634 pages
Edition : 2nd Edition
Language : English
ISBN-13 : 9781804616420
Concepts :

Packt Subscriptions

See our plans and pricing
Modal Close icon
$19.99 billed monthly
Feature tick icon Unlimited access to Packt's library of 7,000+ practical books and videos
Feature tick icon Constantly refreshed with 50+ new titles a month
Feature tick icon Exclusive Early access to books as they're written
Feature tick icon Solve problems while you work with advanced search and reference features
Feature tick icon Offline reading on the mobile app
Feature tick icon Simple pricing, no contract
$199.99 billed annually
Feature tick icon Unlimited access to Packt's library of 7,000+ practical books and videos
Feature tick icon Constantly refreshed with 50+ new titles a month
Feature tick icon Exclusive Early access to books as they're written
Feature tick icon Solve problems while you work with advanced search and reference features
Feature tick icon Offline reading on the mobile app
Feature tick icon Choose a DRM-free eBook or Video every month to keep
Feature tick icon PLUS own as many other DRM-free eBooks or Videos as you like for just Mex$85 each
Feature tick icon Exclusive print discounts
$279.99 billed in 18 months
Feature tick icon Unlimited access to Packt's library of 7,000+ practical books and videos
Feature tick icon Constantly refreshed with 50+ new titles a month
Feature tick icon Exclusive Early access to books as they're written
Feature tick icon Solve problems while you work with advanced search and reference features
Feature tick icon Offline reading on the mobile app
Feature tick icon Choose a DRM-free eBook or Video every month to keep
Feature tick icon PLUS own as many other DRM-free eBooks or Videos as you like for just Mex$85 each
Feature tick icon Exclusive print discounts

Frequently bought together

Stars icon
Total Mex$ 1,606.97 2,298.97 692.00 saved
The Ultimate Docker Container Book
Mex$573.99 Mex$820.99
Infrastructure as Code for Beginners
Mex$458.99 Mex$656.99
Terraform Cookbook
Mex$573.99 Mex$820.99
=
Book stack Total Mex$ 1,606.97 2,298.97 692.00 saved Stars icon

Table of Contents

20 Chapters
Preface Chevron down icon Chevron up icon
1. Setting Up the Terraform Environment Chevron down icon Chevron up icon
2. Writing Terraform Configurations Chevron down icon Chevron up icon
3. Scaling Your Infrastructure with Terraform Chevron down icon Chevron up icon
4. Using Terraform with External Data Chevron down icon Chevron up icon
5. Managing Terraform State Chevron down icon Chevron up icon
6. Applying a Basic Terraform Workflow Chevron down icon Chevron up icon
7. Sharing Terraform Configuration with Modules Chevron down icon Chevron up icon
8. Provisioning Azure Infrastructure with Terraform Chevron down icon Chevron up icon
9. Getting Starting to Provisioning AWS and GCP Infrastructure Using Terraform Chevron down icon Chevron up icon
10. Using Terraform for Docker and Kubernetes Deployment Chevron down icon Chevron up icon
11. Running Test and Compliance Security on Terraform Configuration Chevron down icon Chevron up icon
12. Deep-Diving into Terraform Chevron down icon Chevron up icon
13. Automating Terraform Execution in a CI/CD Pipeline Chevron down icon Chevron up icon
14. Using Terraform Cloud to Improve Team Collaboration Chevron down icon Chevron up icon
15. Troubleshooting Terraform Errors Chevron down icon Chevron up icon
16. Other Books You May Enjoy Chevron down icon Chevron up icon
17. Index Chevron down icon Chevron up icon
Appendix A: Terraform Cheat Sheet Chevron down icon Chevron up icon
1. Appendix B: Terraform Resources Chevron down icon Chevron up icon

Customer reviews

Rating distribution
Full star icon Full star icon Full star icon Full star icon Half star icon 4.5
(2 Ratings)
5 star 50%
4 star 50%
3 star 0%
2 star 0%
1 star 0%
Aneeshkumar Palliparambath Dec 15, 2023
Full star icon Full star icon Full star icon Full star icon Full star icon 5
nice web applicatiin to read ane set notes
Feefo Verified review Feefo image
N/A Feb 21, 2024
Full star icon Full star icon Full star icon Full star icon Empty star icon 4
Feefo Verified review Feefo image
Get free access to Packt library with over 7500+ books and video courses for 7 days!
Start Free Trial

FAQs

How do I buy and download an eBook? Chevron down icon Chevron up icon

Where there is an eBook version of a title available, you can buy it from the book details for that title. Add either the standalone eBook or the eBook and print book bundle to your shopping cart. Your eBook will show in your cart as a product on its own. After completing checkout and payment in the normal way, you will receive your receipt on the screen containing a link to a personalised PDF download file. This link will remain active for 30 days. You can download backup copies of the file by logging in to your account at any time.

If you already have Adobe reader installed, then clicking on the link will download and open the PDF file directly. If you don't, then save the PDF file on your machine and download the Reader to view it.

Please Note: Packt eBooks are non-returnable and non-refundable.

Packt eBook and Licensing When you buy an eBook from Packt Publishing, completing your purchase means you accept the terms of our licence agreement. Please read the full text of the agreement. In it we have tried to balance the need for the ebook to be usable for you the reader with our needs to protect the rights of us as Publishers and of our authors. In summary, the agreement says:

  • You may make copies of your eBook for your own use onto any machine
  • You may not pass copies of the eBook on to anyone else
How can I make a purchase on your website? Chevron down icon Chevron up icon

If you want to purchase a video course, eBook or Bundle (Print+eBook) please follow below steps:

  1. Register on our website using your email address and the password.
  2. Search for the title by name or ISBN using the search option.
  3. Select the title you want to purchase.
  4. Choose the format you wish to purchase the title in; if you order the Print Book, you get a free eBook copy of the same title. 
  5. Proceed with the checkout process (payment to be made using Credit Card, Debit Cart, or PayPal)
Where can I access support around an eBook? Chevron down icon Chevron up icon
  • If you experience a problem with using or installing Adobe Reader, the contact Adobe directly.
  • To view the errata for the book, see www.packtpub.com/support and view the pages for the title you have.
  • To view your account details or to download a new copy of the book go to www.packtpub.com/account
  • To contact us directly if a problem is not resolved, use www.packtpub.com/contact-us
What eBook formats do Packt support? Chevron down icon Chevron up icon

Our eBooks are currently available in a variety of formats such as PDF and ePubs. In the future, this may well change with trends and development in technology, but please note that our PDFs are not Adobe eBook Reader format, which has greater restrictions on security.

You will need to use Adobe Reader v9 or later in order to read Packt's PDF eBooks.

What are the benefits of eBooks? Chevron down icon Chevron up icon
  • You can get the information you need immediately
  • You can easily take them with you on a laptop
  • You can download them an unlimited number of times
  • You can print them out
  • They are copy-paste enabled
  • They are searchable
  • There is no password protection
  • They are lower price than print
  • They save resources and space
What is an eBook? Chevron down icon Chevron up icon

Packt eBooks are a complete electronic version of the print edition, available in PDF and ePub formats. Every piece of content down to the page numbering is the same. Because we save the costs of printing and shipping the book to you, we are able to offer eBooks at a lower cost than print editions.

When you have purchased an eBook, simply login to your account and click on the link in Your Download Area. We recommend you saving the file to your hard drive before opening it.

For optimal viewing of our eBooks, we recommend you download and install the free Adobe Reader version 9.