Работа с кодом в Terraform

Моя цель - предложение широкого ассортимента товаров и услуг на постоянно высоком качестве обслуживания по самым выгодным ценам.

В предыдущей статье мы рассмотрели основы языка HCL, используемого Terraform для описания требуемых конфигураций. Также мы подготовили небольшое описание для создания экземпляра EC2 в AWS. Однако, в представленном описании у на присутствуют только основные параметры, необходимые для создания узла, но отсутствуют, к примеру параметры для настройки сети.

Для полноценной автоматизации нам было бы неплохо прописать все необходимые для работы сетевые интерфейсы. Для этого объявим две переменные net_primary и net_ad для двух сетевых интерфейсов. Если вам не требуется второй интерфейс, net_ad можно не указывать, однако в большинстве случаев для серверов требуется скорее большее количество сетевых портов.

variable "net_primary" {
  type    = string
  default = "subnet-3155417b"
}
variable "net_ad" {
  type    = string
  default = "subnet-3155417a"
}

В строковых значениях этих переменных мы указали, к каким сетям будут подключаться сетевые интерфейсы, которым будут присвоены net_primary и net_add. В данном примере указаны дефолтные подсети облака Amazon.

Далее добавим в наш конфигурационный файл ресурсы, описывающие сетевые интерфейсы:

resource "aws_network_interface" "primary" {
  subnet_id         = var.net_primary
  source_dest_check = false
}
resource "aws_network_interface" "ad" {
  subnet_id         = var.net_ad
  source_dest_check = false
}  

Указанный в примере параметр source-dest-check отвечает за проверку каждого пакета, проходящего через интерфейс. Когда source-dest-check включен, каждый IP-пакет, проходящий через этот интерфейс, должен быть отправлен, либо предназначаться IP-адресу этого интерфейса.

Но в случае, если вам необходимо настроить маршрутизацию либо NAT на экземпляре, нужно отключить source-dest-check для интерфейса данного экземпляра. Также, в случае, если нам необходимо автоматически назначить IP адрес с помощью DHCP, нужно добавить следующую строку: 

associate_public_ip_address = true 

Давайте добавим эти параметры в наш конфигурационный файл:

terraform {
 required_providers {
   aws = {
     source  = "hashicorp/aws"
     version = "~> 3.0"
   }
 }
}

provider "aws" {
 region = var.region
}
variable "region" {
 default = "us-west-1"
 description = "AWS Region"
}

variable "ami" {
 default = "ami-00831fc7c1e3ddc60"
 description = "Amazon Machine Image ID for Ubuntu Server 20.04"
}

variable "type" {
 default = "t2.micro"
 description = "Size of VM"
}

variable "net_primary" {
  type    = string
  default = "subnet-3155417b"
}

variable "net_ad" {
  type    = string
  default = "subnet-3155417a"
}

resource "aws_instance" "demo" {
 ami = var.ami
 instance_type = var.type
resource "aws_network_interface" "primary" {
  subnet_id         = var.net_primary
  source_dest_check = false
}

resource "aws_network_interface" "ad" {
  subnet_id         = var.net_ad
  source_dest_check = false
}  

 tags = {
   name = "Demo System"
 }
} 

output "instance_id" {
 instance = aws_instance.demo.id
}

Таким образом, мы дополнили настройки нашего экземпляра сетевыми параметрами. Теперь давайте рассмотрим различные функции Terraform, позволяющие обрабатывать числовые и строковые значения. Собственно, наименования этих функций аналогичны используемым в других языках программирования, поэтому тем, кто знаком с любым языком высокого уровня разобраться в этих функциях будет несложно.

Функции Terraform

Основными числовыми функциями, которые могут потребоваться в работе являются min и max, вычисляющие минимальное и максимальное значения из предложенного списка.

max(12, 54, 3)

54

При этом, если список значений вложен в другой список, функция также найдет нужное значение

min([12, 54, 3]...)

3

Строковые функции более востребованы, так как с их помощью можно генерировать различные наименования, тэги и другие строковые значения, необходимые в дальнейшей работе.

Если мы получаем строковые значения из файла , там могут присутствовать символы окончания строки (\n, \r). Для того, чтобы их корректно удалить, можно воспользоваться функцией chomp

chomp("hello\n")

hello

chomp("hello\r\n")

hello

chomp("hello\n\n")

hello 

Еще одна функция, предназначенная для удаления лишних символов по краям строк, это trim. Здесь мы сами передаем функции те символы, которые необходимо удалить. Вот несколько примеров

trim("?!hello?!", "!?")

"hello"

trim("foobar", "far")

"oob"

trim("   hello! world.!  ", "! ")

"hello! world."

 У этой функции есть несколько вариаций, так trimprefix и trimsuffix удаляют символы с начала и с конца строки соответственно, а trimspace удаляет все пробелы в терминах Юникода, то есть помимо самих пробелов также табуляцию, перенос строк и другие значения.

Для поиска строк в конфигурациях мы можем воспользоваться регулярными выражениями с помощью функции regex. На просторах Хабра можно найти массу статей, посвященных работе с регулярными выражениями, поэтому здесь мы не будем на этом останавливаться.

Еще несколько практически полезных функций позволяют работать со списками, состоящими из наборов различных значений. Начнем с функции element, которая извлекает отдельный элемент из списка:

element(["a", "b", "c"], 1)

b 

В этом примере мы получили первый элемент из списка. Напомним, что нумерация в списках Terraform начинается с 0. Но, если мы попросим у этой функции извлечь элемент с индексом, который больше длины списка, функция выполнит “оборот”, то есть присвоит индексу в качестве результата остаток от целочисленного деления (mod).   

element(["a", "b", "c"], 3)

a

Так что будьте готовы к такому “странному” но абсолютно корректному поведению данной функции.

Еще одна интересная функция Terraform это merge. Эта функция получает на вход произвольное количество объектов в формате ключ-значение, у которых ключи могут быть не уникальны. Например:

{a="b", c="d"}, {e="f", c="z"}

Здесь c имеет значения d и z. Функция merge присвоит с значение z, потому-что приоритет имеет тот ключ, который находится позже в последовательности аргументов. Если типы аргументов не совпадают, результирующий тип будет объектом, соответствующим структуре типов атрибутов после применения правил объединения.

Чтобы стало понятнее посмотрим примеры:

merge({a="b", c="d"}, {e="f", c="z"})

{

  "a" = "b"

  "c" = "z"

  "e" = "f"

}

Здесь ключу с соответствует значение z, первое присвоение a=”b” в итоге потеряно. Другой пример:

merge({a="b"}, {a=[1,2], c="z"}, {d=3})
{
  "a" = [
    1,
    2,
  ]
  "c" = "z"
  "d" = 3
}

Здесь мы сначала объединили объекты, в результате чего a был присвоен массив [1,2]. 

Данная функция может быть полезна  в случае, если у нас имеется разнородный набор данных и необходимо привести его к единой структуре.

Рассмотрим пример практического применения данных функций. Ниже приведен блок кода HCL, в котором мы берем номер нашего экземпляра (у нас же развернуто несколько экземпляров EC2, иначе какой смысл во всей автоматизации и IaC

Источник: https://habr.com/ru/company/otus/blog/698252/


Интересные статьи

Интересные статьи

Распространение приложений в линуксе - это боль. Причем в наше время цикл обновлений приложений все уменьшается и эта боль чувствуется все сильнее. В связи с этим появляются технологии вроде snap, fla...
Сразу извиняюсь за свою манеру повествования, ибо она похоже больше на поток сознания, но главное уловить суть, которую я хочу донести.Я хочу подготовить небольшой цикл публикаций про работу с данными...
О работе в стартапах ходит огромное количество слухов. Среди них чаще встречаются: «вам не будут платить вовремя», «вы будете работать круглыми сутками», «вы должны делать то, что не вх...
Всем привет. В преддверии старта курса «Fullstack разработчик JavaScript», хотим поделиться интересным материалом, который прислал наш внештатный автор. Данная статья не имеет отношен...
В прошлом месяце на NVIDIA GTC 2019 компания NVIDIA представила новое приложение, которое превращает нарисованные пользователем простые цветные шарики в великолепные фотореалистичные изображения....