doc: добавление документации по созданию вм через tf
This commit is contained in:
@@ -0,0 +1,36 @@
|
|||||||
|
# ---> Terraform
|
||||||
|
# Local .terraform directories
|
||||||
|
**/.terraform/*
|
||||||
|
|
||||||
|
# .tfstate files
|
||||||
|
*.tfstate
|
||||||
|
*.tfstate.*
|
||||||
|
|
||||||
|
# Crash log files
|
||||||
|
crash.log
|
||||||
|
crash.*.log
|
||||||
|
|
||||||
|
# Exclude all .tfvars files, which are likely to contain sensitive data, such as
|
||||||
|
# password, private keys, and other secrets. These should not be part of version
|
||||||
|
# control as they are data points which are potentially sensitive and subject
|
||||||
|
# to change depending on the environment.
|
||||||
|
# *.tfvars
|
||||||
|
*.tfvars.json
|
||||||
|
|
||||||
|
# Ignore override files as they are usually used to override resources locally and so
|
||||||
|
# are not checked in
|
||||||
|
override.tf
|
||||||
|
override.tf.json
|
||||||
|
*_override.tf
|
||||||
|
*_override.tf.json
|
||||||
|
|
||||||
|
# Include override files you do wish to add to version control using negated pattern
|
||||||
|
# !example_override.tf
|
||||||
|
|
||||||
|
# Include tfplan files to ignore the plan output of command: terraform plan -out=tfplan
|
||||||
|
# example: *tfplan*
|
||||||
|
|
||||||
|
# Ignore CLI configuration files
|
||||||
|
.terraformrc
|
||||||
|
terraform.rc
|
||||||
|
.terraform.lock.hcl
|
||||||
@@ -0,0 +1,120 @@
|
|||||||
|
# Развёртывание ВМ в VMware Cloud Director через tf
|
||||||
|
|
||||||
|
Используется **OpenTofu** (`tofu`). Конфигурация создаёт виртуальные машины в vCD: можно задать несколько ВМ, размеры CPU/RAM/дисков и сеть.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Быстрый старт
|
||||||
|
|
||||||
|
1. **Установите OpenTofu** ([opentofu.org](https://opentofu.org)).
|
||||||
|
|
||||||
|
2. **Задайте переменные окружения** (доступ к vCD):
|
||||||
|
```bash
|
||||||
|
export TF_VAR_vmware_username="ваш_пользователь_vCD"
|
||||||
|
export TF_VAR_vmware_password="ваш_пароль_vCD"
|
||||||
|
```
|
||||||
|
Пароль администратора ВМ можно не задавать — тогда он сгенерируется автоматически (см. `tools.tf`). Чтобы задать свой: `export TF_VAR_admin_password="ваш_пароль"`.
|
||||||
|
|
||||||
|
3. **Отредактируйте `terraform.tfvars`** — укажите нужный vDC, имя vApp, параметры ВМ (см. раздел «Конфигурация» ниже).
|
||||||
|
|
||||||
|
4. **Разверните инфраструктуру:**
|
||||||
|
```bash
|
||||||
|
tofu init
|
||||||
|
tofu plan
|
||||||
|
tofu apply
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Конфигурация
|
||||||
|
|
||||||
|
### Переменные окружения
|
||||||
|
|
||||||
|
Обязательные для доступа к vCD:
|
||||||
|
|
||||||
|
- `TF_VAR_vmware_username` — пользователь VMware Cloud Director
|
||||||
|
- `TF_VAR_vmware_password` — пароль VMware Cloud Director
|
||||||
|
|
||||||
|
Опционально: `TF_VAR_admin_password` — пароль администратора на ВМ (если не задан, генерируется автоматически).
|
||||||
|
|
||||||
|
```
|
||||||
|
vcds = {
|
||||||
|
"vdcconfiguration1" = {
|
||||||
|
url = "https://ngcloud.ru/api"
|
||||||
|
org = "dev"
|
||||||
|
vdc = "dev"
|
||||||
|
network_routed = "dev-mgmt-network"
|
||||||
|
servers = {
|
||||||
|
"vappname01" = {
|
||||||
|
"vmname01" = {
|
||||||
|
cpu = "4"
|
||||||
|
memory = "4096"
|
||||||
|
osDisk = "16384"
|
||||||
|
dataDisk = {
|
||||||
|
"1" = "30720"
|
||||||
|
"2" = "15360"
|
||||||
|
}
|
||||||
|
network = {
|
||||||
|
mode = "auto"
|
||||||
|
ip = ""
|
||||||
|
}
|
||||||
|
catalog_name = "dev"
|
||||||
|
template_name = "RockyLinux_9-16G-customize"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
Переменная задаётся в `terraform.tfvars`; схема — в [var.tf](var.tf), использование — [provider.tf](provider.tf), [vapp.tf](vapp.tf), [vm.tf](vm.tf), [local.tf](local.tf).
|
||||||
|
|
||||||
|
*** Ключ vcds — произвольное имя контура (можно несколько vDC в одной конфигурации) ***
|
||||||
|
```
|
||||||
|
vcds = {
|
||||||
|
"test" = {
|
||||||
|
...
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
*** Настройка vDC ***
|
||||||
|
```
|
||||||
|
url = URL API Cloud Director (https://<хост>/api)
|
||||||
|
org = имя организации
|
||||||
|
vdc = имя vDC
|
||||||
|
network_routed = имя routed-сети, куда подключаются ВМ
|
||||||
|
```
|
||||||
|
|
||||||
|
*** Настройка vApp (ключи внутри servers — имена vApp) ***
|
||||||
|
```
|
||||||
|
servers = {
|
||||||
|
"testservers" = { ... } # первый vApp
|
||||||
|
"testvapp2" = { ... } # второй vApp
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
*** Настройка сервера (параметры ВМ) ***
|
||||||
|
```
|
||||||
|
"testservers" = {
|
||||||
|
"test01" = {
|
||||||
|
cpu = кол-во ядер CPU
|
||||||
|
memory = объём RAM (МБ)
|
||||||
|
osDisk = размер системного диска (МБ)
|
||||||
|
dataDisk = { # ключ — unit, значение — размер в МБ
|
||||||
|
"1" = "30720"
|
||||||
|
"2" = "15360"
|
||||||
|
}
|
||||||
|
network = { # mode "auto" (IP из пула) или "manual" (указать ip)
|
||||||
|
mode = "auto"
|
||||||
|
ip = ""
|
||||||
|
}
|
||||||
|
network = mode "auto" (IP из пула) или "manual" (указать ip)
|
||||||
|
mode = "auto"
|
||||||
|
ip = ""
|
||||||
|
catalog_name = каталог с шаблоном
|
||||||
|
template_name = имя шаблона образа
|
||||||
|
# опционально (cloud-init):
|
||||||
|
init_username = "deploy"
|
||||||
|
ssh_authorized_keys = ["ssh-ed25519 AAAA..."]
|
||||||
|
}
|
||||||
|
```
|
||||||
@@ -0,0 +1,39 @@
|
|||||||
|
locals {
|
||||||
|
#######################
|
||||||
|
admin_password = var.admin_password != "" ? var.admin_password : random_password.admin_pass.result
|
||||||
|
#######################
|
||||||
|
# Получаем объект с ключами в виде имен серверов и содержимым всего,
|
||||||
|
# что мы хотим видеть при передаче из vars
|
||||||
|
servers = merge([
|
||||||
|
for vcd_key, vcd_config in var.vcds :
|
||||||
|
merge([
|
||||||
|
for server_group, servers in vcd_config.servers :
|
||||||
|
{
|
||||||
|
for server_name, server_config in servers :
|
||||||
|
"${server_name}.${server_group}" => {
|
||||||
|
vcd_key = vcd_key
|
||||||
|
server_group = server_group
|
||||||
|
server_name = server_name
|
||||||
|
config = server_config
|
||||||
|
network_routed = vcd_config.network_routed
|
||||||
|
role = server_group
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]...)
|
||||||
|
]...)
|
||||||
|
|
||||||
|
# Получаем объект с ключами в виде сервера-uidдиска,
|
||||||
|
# и содержимым в виде его сайзинга
|
||||||
|
disks = merge([
|
||||||
|
for serverName, serverConfig in local.servers:
|
||||||
|
{
|
||||||
|
for diskUid, diskSize in serverConfig.config.dataDisk:
|
||||||
|
"${serverName}-${diskUid}" => {
|
||||||
|
vcd_key = serverConfig.vcd_key
|
||||||
|
vm_name = serverName
|
||||||
|
unit_num = diskUid
|
||||||
|
disk_size = diskSize
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]...)
|
||||||
|
}
|
||||||
@@ -0,0 +1,37 @@
|
|||||||
|
terraform {
|
||||||
|
required_providers {
|
||||||
|
vcd = {
|
||||||
|
source = "vmware/vcd"
|
||||||
|
version = "3.14.1"
|
||||||
|
}
|
||||||
|
random = {
|
||||||
|
source = "hashicorp/random"
|
||||||
|
version = "3.5.1"
|
||||||
|
}
|
||||||
|
local = {
|
||||||
|
source = "hashicorp/local"
|
||||||
|
version = "2.5.1"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# Почему такая конфигурация не будет работать
|
||||||
|
# https://github.com/hashicorp/terraform/issues/24476
|
||||||
|
#
|
||||||
|
# Но решили тут
|
||||||
|
# https://github.com/opentofu/opentofu/issues/2123
|
||||||
|
|
||||||
|
provider "vcd" {
|
||||||
|
alias = "al"
|
||||||
|
for_each = var.vcds
|
||||||
|
|
||||||
|
user = var.vmware_username
|
||||||
|
password = var.vmware_password
|
||||||
|
|
||||||
|
org = each.value.org
|
||||||
|
vdc = each.value.vdc
|
||||||
|
url = each.value.url
|
||||||
|
|
||||||
|
max_retry_timeout = "10"
|
||||||
|
allow_unverified_ssl = "true"
|
||||||
|
}
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
#cloud-config
|
||||||
|
hostname: ${hostname}
|
||||||
|
package_update: true
|
||||||
|
package_upgrade: false
|
||||||
|
packages:
|
||||||
|
- curl
|
||||||
|
- git
|
||||||
|
- jq
|
||||||
|
|
||||||
|
users:
|
||||||
|
- name: ${username}
|
||||||
|
sudo: "ALL=(ALL) NOPASSWD:ALL"
|
||||||
|
groups: "sudo"
|
||||||
|
shell: /bin/bash
|
||||||
|
ssh_authorized_keys:
|
||||||
|
%{ if length(ssh_authorized_keys) > 0 ~}
|
||||||
|
%{ for key in ssh_authorized_keys ~}
|
||||||
|
- ${key}
|
||||||
|
%{ endfor ~}
|
||||||
|
%{ else ~}
|
||||||
|
[]
|
||||||
|
%{ endif ~}
|
||||||
@@ -0,0 +1,39 @@
|
|||||||
|
#######################################################
|
||||||
|
# Импортируемые переменные из TF_VAR
|
||||||
|
# vmware_username = ""
|
||||||
|
# vmware_password = ""
|
||||||
|
|
||||||
|
|
||||||
|
#######################################################
|
||||||
|
|
||||||
|
vcds = {
|
||||||
|
"test" = {
|
||||||
|
url = "https://sandbox.nubes.ru/api"
|
||||||
|
org = "dev"
|
||||||
|
vdc = "dev"
|
||||||
|
network_routed = "dev-mgmt-network"
|
||||||
|
servers = {
|
||||||
|
"testservers" = {
|
||||||
|
"test01" = {
|
||||||
|
cpu = "1"
|
||||||
|
memory = "1024"
|
||||||
|
osDisk = "35000"
|
||||||
|
dataDisk = {
|
||||||
|
"1" = "10000"
|
||||||
|
"2" = "5480"
|
||||||
|
}
|
||||||
|
network = {
|
||||||
|
mode = "auto"
|
||||||
|
ip = ""
|
||||||
|
}
|
||||||
|
catalog_name = "dev"
|
||||||
|
template_name = "Ubuntu_24-20G"
|
||||||
|
init_username = "deploy"
|
||||||
|
ssh_authorized_keys = [
|
||||||
|
"ssh-ed25519 *********"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
# Генерируем пароль для админского пользователя
|
||||||
|
resource "random_password" "admin_pass" {
|
||||||
|
length = 20
|
||||||
|
special = false
|
||||||
|
}
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
resource "vcd_vapp" "vapp" {
|
||||||
|
for_each = var.vcds
|
||||||
|
|
||||||
|
provider = vcd.al[each.key]
|
||||||
|
|
||||||
|
name = each.key
|
||||||
|
power_on = false
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
resource "vcd_vapp_org_network" "routed_network" {
|
||||||
|
for_each = vcd_vapp.vapp
|
||||||
|
|
||||||
|
provider = vcd.al[each.key]
|
||||||
|
|
||||||
|
vapp_name = each.value.name
|
||||||
|
org_network_name = var.vcds[each.key].network_routed
|
||||||
|
reboot_vapp_on_removal = true
|
||||||
|
}
|
||||||
@@ -0,0 +1,42 @@
|
|||||||
|
####################################################
|
||||||
|
variable "vmware_username" {
|
||||||
|
type = string
|
||||||
|
default = ""
|
||||||
|
}
|
||||||
|
variable "vmware_password" {
|
||||||
|
type = string
|
||||||
|
default = ""
|
||||||
|
}
|
||||||
|
|
||||||
|
####################################################
|
||||||
|
# Пароль от ВМ (если пустой — подставляется сгенерированный из tools.tf)
|
||||||
|
variable "admin_password" {
|
||||||
|
type = string
|
||||||
|
default = ""
|
||||||
|
}
|
||||||
|
|
||||||
|
####################################################
|
||||||
|
variable "vcds" {
|
||||||
|
type = map(object({
|
||||||
|
url = string
|
||||||
|
org = string
|
||||||
|
vdc = string
|
||||||
|
network_routed = string
|
||||||
|
servers = map(map(object({
|
||||||
|
cpu = string
|
||||||
|
memory = string
|
||||||
|
osDisk = string
|
||||||
|
catalog_name = string
|
||||||
|
template_name = string
|
||||||
|
dataDisk = map(string)
|
||||||
|
network = object({
|
||||||
|
mode = string
|
||||||
|
ip = string
|
||||||
|
})
|
||||||
|
# cloud-init: пользователь и SSH-ключи (опционально)
|
||||||
|
init_username = optional(string, "deploy")
|
||||||
|
ssh_authorized_keys = optional(list(string), [])
|
||||||
|
})))
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
####################################################
|
||||||
@@ -0,0 +1,84 @@
|
|||||||
|
resource "vcd_vapp_vm" "vm" {
|
||||||
|
for_each = local.servers
|
||||||
|
|
||||||
|
provider = vcd.al[each.value.vcd_key]
|
||||||
|
|
||||||
|
vapp_name = vcd_vapp.vapp[each.value.vcd_key].name
|
||||||
|
name = each.key
|
||||||
|
computer_name = each.key
|
||||||
|
catalog_name = each.value.config["catalog_name"]
|
||||||
|
template_name = each.value.config["template_name"]
|
||||||
|
memory = each.value.config["memory"]
|
||||||
|
cpus = each.value.config["cpu"]
|
||||||
|
|
||||||
|
network {
|
||||||
|
type = "org"
|
||||||
|
name = each.value.network_routed
|
||||||
|
ip_allocation_mode = lookup(each.value.config["network"], "mode", "auto") == "manual" ? "MANUAL" : "POOL"
|
||||||
|
is_primary = true
|
||||||
|
|
||||||
|
# Устанавливаем IP, только если режим "manual"
|
||||||
|
ip = lookup(each.value.config["network"], "mode", "auto") == "manual" ? lookup(each.value.config["network"], "ip", null) : null
|
||||||
|
}
|
||||||
|
|
||||||
|
override_template_disk {
|
||||||
|
bus_type = "paravirtual"
|
||||||
|
size_in_mb = each.value.config["osDisk"]
|
||||||
|
bus_number = 0
|
||||||
|
unit_number = 0
|
||||||
|
}
|
||||||
|
|
||||||
|
customization {
|
||||||
|
enabled = true
|
||||||
|
#force = var.forceRecustomization || !contains(var.servers, var.servers[count.index])
|
||||||
|
#force = var.forceRecustomization
|
||||||
|
force = false
|
||||||
|
allow_local_admin_password = true
|
||||||
|
auto_generate_password = false
|
||||||
|
admin_password = local.admin_password
|
||||||
|
}
|
||||||
|
|
||||||
|
set_extra_config {
|
||||||
|
key = "disk.EnableUUID"
|
||||||
|
value = "TRUE"
|
||||||
|
}
|
||||||
|
|
||||||
|
guest_properties = {
|
||||||
|
"user-data" = base64encode(templatefile("${path.module}/templates/cloudinit.yaml", {
|
||||||
|
hostname = each.key
|
||||||
|
username = each.value.config["init_username"]
|
||||||
|
ssh_authorized_keys = each.value.config["ssh_authorized_keys"]
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
|
||||||
|
# Игноирование изменений дисков (PVC - Named Disks)
|
||||||
|
lifecycle {
|
||||||
|
ignore_changes = [
|
||||||
|
disk, # Игнорирует изменения всех дисков
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
depends_on = [
|
||||||
|
vcd_vapp_org_network.routed_network
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "vcd_vm_internal_disk" "vmdisk" {
|
||||||
|
for_each = local.disks
|
||||||
|
|
||||||
|
provider = vcd.al[each.value.vcd_key]
|
||||||
|
|
||||||
|
vapp_name = vcd_vapp.vapp[each.value.vcd_key].name
|
||||||
|
vm_name = each.value.vm_name
|
||||||
|
|
||||||
|
bus_type = "paravirtual"
|
||||||
|
bus_number = 0
|
||||||
|
unit_number = each.value.unit_num
|
||||||
|
size_in_mb = each.value.disk_size
|
||||||
|
|
||||||
|
allow_vm_reboot = true
|
||||||
|
|
||||||
|
depends_on = [
|
||||||
|
vcd_vapp_vm.vm
|
||||||
|
]
|
||||||
|
}
|
||||||
@@ -0,0 +1,36 @@
|
|||||||
|
# ---> Terraform
|
||||||
|
# Local .terraform directories
|
||||||
|
**/.terraform/*
|
||||||
|
|
||||||
|
# .tfstate files
|
||||||
|
*.tfstate
|
||||||
|
*.tfstate.*
|
||||||
|
|
||||||
|
# Crash log files
|
||||||
|
crash.log
|
||||||
|
crash.*.log
|
||||||
|
|
||||||
|
# Exclude all .tfvars files, which are likely to contain sensitive data, such as
|
||||||
|
# password, private keys, and other secrets. These should not be part of version
|
||||||
|
# control as they are data points which are potentially sensitive and subject
|
||||||
|
# to change depending on the environment.
|
||||||
|
# *.tfvars
|
||||||
|
*.tfvars.json
|
||||||
|
|
||||||
|
# Ignore override files as they are usually used to override resources locally and so
|
||||||
|
# are not checked in
|
||||||
|
override.tf
|
||||||
|
override.tf.json
|
||||||
|
*_override.tf
|
||||||
|
*_override.tf.json
|
||||||
|
|
||||||
|
# Include override files you do wish to add to version control using negated pattern
|
||||||
|
# !example_override.tf
|
||||||
|
|
||||||
|
# Include tfplan files to ignore the plan output of command: terraform plan -out=tfplan
|
||||||
|
# example: *tfplan*
|
||||||
|
|
||||||
|
# Ignore CLI configuration files
|
||||||
|
.terraformrc
|
||||||
|
terraform.rc
|
||||||
|
.terraform.lock.hcl
|
||||||
@@ -0,0 +1,120 @@
|
|||||||
|
# Развёртывание ВМ в VMware Cloud Director через tf
|
||||||
|
|
||||||
|
Используется **OpenTofu** (`tofu`). Конфигурация создаёт виртуальные машины в vCD: можно задать несколько ВМ, размеры CPU/RAM/дисков и сеть.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Быстрый старт
|
||||||
|
|
||||||
|
1. **Установите OpenTofu** ([opentofu.org](https://opentofu.org)).
|
||||||
|
|
||||||
|
2. **Задайте переменные окружения** (доступ к vCD):
|
||||||
|
```bash
|
||||||
|
export TF_VAR_vmware_username="ваш_пользователь_vCD"
|
||||||
|
export TF_VAR_vmware_password="ваш_пароль_vCD"
|
||||||
|
```
|
||||||
|
Пароль администратора ВМ можно не задавать — тогда он сгенерируется автоматически (см. `tools.tf`). Чтобы задать свой: `export TF_VAR_admin_password="ваш_пароль"`.
|
||||||
|
|
||||||
|
3. **Отредактируйте `terraform.tfvars`** — укажите нужный vDC, имя vApp, параметры ВМ (см. раздел «Конфигурация» ниже).
|
||||||
|
|
||||||
|
4. **Разверните инфраструктуру:**
|
||||||
|
```bash
|
||||||
|
tofu init
|
||||||
|
tofu plan
|
||||||
|
tofu apply
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Конфигурация
|
||||||
|
|
||||||
|
### Переменные окружения
|
||||||
|
|
||||||
|
Обязательные для доступа к vCD:
|
||||||
|
|
||||||
|
- `TF_VAR_vmware_username` — пользователь VMware Cloud Director
|
||||||
|
- `TF_VAR_vmware_password` — пароль VMware Cloud Director
|
||||||
|
|
||||||
|
Опционально: `TF_VAR_admin_password` — пароль администратора на ВМ (если не задан, генерируется автоматически).
|
||||||
|
|
||||||
|
```
|
||||||
|
vcds = {
|
||||||
|
"vdcconfiguration1" = {
|
||||||
|
url = "https://ngcloud.ru/api"
|
||||||
|
org = "dev"
|
||||||
|
vdc = "dev"
|
||||||
|
network_routed = "dev-mgmt-network"
|
||||||
|
servers = {
|
||||||
|
"vappname01" = {
|
||||||
|
"vmname01" = {
|
||||||
|
cpu = "4"
|
||||||
|
memory = "4096"
|
||||||
|
osDisk = "16384"
|
||||||
|
dataDisk = {
|
||||||
|
"1" = "30720"
|
||||||
|
"2" = "15360"
|
||||||
|
}
|
||||||
|
network = {
|
||||||
|
mode = "auto"
|
||||||
|
ip = ""
|
||||||
|
}
|
||||||
|
catalog_name = "dev"
|
||||||
|
template_name = "RockyLinux_9-16G-customize"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
Переменная задаётся в `terraform.tfvars`; схема — в [var.tf](var.tf), использование — [provider.tf](provider.tf), [vapp.tf](vapp.tf), [vm.tf](vm.tf), [local.tf](local.tf).
|
||||||
|
|
||||||
|
*** Ключ vcds — произвольное имя контура (можно несколько vDC в одной конфигурации) ***
|
||||||
|
```
|
||||||
|
vcds = {
|
||||||
|
"test" = {
|
||||||
|
...
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
*** Настройка vDC ***
|
||||||
|
```
|
||||||
|
url = URL API Cloud Director (https://<хост>/api)
|
||||||
|
org = имя организации
|
||||||
|
vdc = имя vDC
|
||||||
|
network_routed = имя routed-сети, куда подключаются ВМ
|
||||||
|
```
|
||||||
|
|
||||||
|
*** Настройка vApp (ключи внутри servers — имена vApp) ***
|
||||||
|
```
|
||||||
|
servers = {
|
||||||
|
"testservers" = { ... } # первый vApp
|
||||||
|
"testvapp2" = { ... } # второй vApp
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
*** Настройка сервера (параметры ВМ) ***
|
||||||
|
```
|
||||||
|
"testservers" = {
|
||||||
|
"test01" = {
|
||||||
|
cpu = кол-во ядер CPU
|
||||||
|
memory = объём RAM (МБ)
|
||||||
|
osDisk = размер системного диска (МБ)
|
||||||
|
dataDisk = { # ключ — unit, значение — размер в МБ
|
||||||
|
"1" = "30720"
|
||||||
|
"2" = "15360"
|
||||||
|
}
|
||||||
|
network = { # mode "auto" (IP из пула) или "manual" (указать ip)
|
||||||
|
mode = "auto"
|
||||||
|
ip = ""
|
||||||
|
}
|
||||||
|
network = mode "auto" (IP из пула) или "manual" (указать ip)
|
||||||
|
mode = "auto"
|
||||||
|
ip = ""
|
||||||
|
catalog_name = каталог с шаблоном
|
||||||
|
template_name = имя шаблона образа
|
||||||
|
# опционально (cloud-init):
|
||||||
|
init_username = "deploy"
|
||||||
|
ssh_authorized_keys = ["ssh-ed25519 AAAA..."]
|
||||||
|
}
|
||||||
|
```
|
||||||
@@ -0,0 +1,39 @@
|
|||||||
|
locals {
|
||||||
|
#######################
|
||||||
|
admin_password = var.admin_password != "" ? var.admin_password : random_password.admin_pass.result
|
||||||
|
#######################
|
||||||
|
# Получаем объект с ключами в виде имен серверов и содержимым всего,
|
||||||
|
# что мы хотим видеть при передаче из vars
|
||||||
|
servers = merge([
|
||||||
|
for vcd_key, vcd_config in var.vcds :
|
||||||
|
merge([
|
||||||
|
for server_group, servers in vcd_config.servers :
|
||||||
|
{
|
||||||
|
for server_name, server_config in servers :
|
||||||
|
"${server_name}.${server_group}" => {
|
||||||
|
vcd_key = vcd_key
|
||||||
|
server_group = server_group
|
||||||
|
server_name = server_name
|
||||||
|
config = server_config
|
||||||
|
network_routed = vcd_config.network_routed
|
||||||
|
role = server_group
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]...)
|
||||||
|
]...)
|
||||||
|
|
||||||
|
# Получаем объект с ключами в виде сервера-uidдиска,
|
||||||
|
# и содержимым в виде его сайзинга
|
||||||
|
disks = merge([
|
||||||
|
for serverName, serverConfig in local.servers:
|
||||||
|
{
|
||||||
|
for diskUid, diskSize in serverConfig.config.dataDisk:
|
||||||
|
"${serverName}-${diskUid}" => {
|
||||||
|
vcd_key = serverConfig.vcd_key
|
||||||
|
vm_name = serverName
|
||||||
|
unit_num = diskUid
|
||||||
|
disk_size = diskSize
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]...)
|
||||||
|
}
|
||||||
@@ -0,0 +1,37 @@
|
|||||||
|
terraform {
|
||||||
|
required_providers {
|
||||||
|
vcd = {
|
||||||
|
source = "vmware/vcd"
|
||||||
|
version = "3.14.1"
|
||||||
|
}
|
||||||
|
random = {
|
||||||
|
source = "hashicorp/random"
|
||||||
|
version = "3.5.1"
|
||||||
|
}
|
||||||
|
local = {
|
||||||
|
source = "hashicorp/local"
|
||||||
|
version = "2.5.1"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# Почему такая конфигурация не будет работать
|
||||||
|
# https://github.com/hashicorp/terraform/issues/24476
|
||||||
|
#
|
||||||
|
# Но решили тут
|
||||||
|
# https://github.com/opentofu/opentofu/issues/2123
|
||||||
|
|
||||||
|
provider "vcd" {
|
||||||
|
alias = "al"
|
||||||
|
for_each = var.vcds
|
||||||
|
|
||||||
|
user = var.vmware_username
|
||||||
|
password = var.vmware_password
|
||||||
|
|
||||||
|
org = each.value.org
|
||||||
|
vdc = each.value.vdc
|
||||||
|
url = each.value.url
|
||||||
|
|
||||||
|
max_retry_timeout = "10"
|
||||||
|
allow_unverified_ssl = "true"
|
||||||
|
}
|
||||||
@@ -0,0 +1,39 @@
|
|||||||
|
#######################################################
|
||||||
|
# Импортируемые переменные из TF_VAR
|
||||||
|
# vmware_username = ""
|
||||||
|
# vmware_password = ""
|
||||||
|
|
||||||
|
|
||||||
|
#######################################################
|
||||||
|
|
||||||
|
vcds = {
|
||||||
|
"test" = {
|
||||||
|
url = "https://sandbox.nubes.ru/api"
|
||||||
|
org = "dev"
|
||||||
|
vdc = "dev"
|
||||||
|
network_routed = "dev-mgmt-network"
|
||||||
|
servers = {
|
||||||
|
"testservers" = {
|
||||||
|
"test01" = {
|
||||||
|
cpu = "1"
|
||||||
|
memory = "1024"
|
||||||
|
osDisk = "35000"
|
||||||
|
dataDisk = {
|
||||||
|
"1" = "10000"
|
||||||
|
"2" = "5480"
|
||||||
|
}
|
||||||
|
network = {
|
||||||
|
mode = "auto"
|
||||||
|
ip = ""
|
||||||
|
}
|
||||||
|
catalog_name = "dev"
|
||||||
|
template_name = "Ubuntu_24-20G"
|
||||||
|
init_username = "deploy"
|
||||||
|
ssh_authorized_keys = [
|
||||||
|
"ssh-ed25519 *********"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
# Генерируем пароль для админского пользователя
|
||||||
|
resource "random_password" "admin_pass" {
|
||||||
|
length = 20
|
||||||
|
special = false
|
||||||
|
}
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
resource "vcd_vapp" "vapp" {
|
||||||
|
for_each = var.vcds
|
||||||
|
|
||||||
|
provider = vcd.al[each.key]
|
||||||
|
|
||||||
|
name = each.key
|
||||||
|
power_on = false
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
resource "vcd_vapp_org_network" "routed_network" {
|
||||||
|
for_each = vcd_vapp.vapp
|
||||||
|
|
||||||
|
provider = vcd.al[each.key]
|
||||||
|
|
||||||
|
vapp_name = each.value.name
|
||||||
|
org_network_name = var.vcds[each.key].network_routed
|
||||||
|
reboot_vapp_on_removal = true
|
||||||
|
}
|
||||||
@@ -0,0 +1,42 @@
|
|||||||
|
####################################################
|
||||||
|
variable "vmware_username" {
|
||||||
|
type = string
|
||||||
|
default = ""
|
||||||
|
}
|
||||||
|
variable "vmware_password" {
|
||||||
|
type = string
|
||||||
|
default = ""
|
||||||
|
}
|
||||||
|
|
||||||
|
####################################################
|
||||||
|
# Пароль от ВМ (если пустой — подставляется сгенерированный из tools.tf)
|
||||||
|
variable "admin_password" {
|
||||||
|
type = string
|
||||||
|
default = ""
|
||||||
|
}
|
||||||
|
|
||||||
|
####################################################
|
||||||
|
variable "vcds" {
|
||||||
|
type = map(object({
|
||||||
|
url = string
|
||||||
|
org = string
|
||||||
|
vdc = string
|
||||||
|
network_routed = string
|
||||||
|
servers = map(map(object({
|
||||||
|
cpu = string
|
||||||
|
memory = string
|
||||||
|
osDisk = string
|
||||||
|
catalog_name = string
|
||||||
|
template_name = string
|
||||||
|
dataDisk = map(string)
|
||||||
|
network = object({
|
||||||
|
mode = string
|
||||||
|
ip = string
|
||||||
|
})
|
||||||
|
# cloud-init: пользователь и SSH-ключи (опционально)
|
||||||
|
init_username = optional(string, "deploy")
|
||||||
|
ssh_authorized_keys = optional(list(string), [])
|
||||||
|
})))
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
####################################################
|
||||||
@@ -0,0 +1,84 @@
|
|||||||
|
resource "vcd_vapp_vm" "vm" {
|
||||||
|
for_each = local.servers
|
||||||
|
|
||||||
|
provider = vcd.al[each.value.vcd_key]
|
||||||
|
|
||||||
|
vapp_name = vcd_vapp.vapp[each.value.vcd_key].name
|
||||||
|
name = each.key
|
||||||
|
computer_name = each.key
|
||||||
|
catalog_name = each.value.config["catalog_name"]
|
||||||
|
template_name = each.value.config["template_name"]
|
||||||
|
memory = each.value.config["memory"]
|
||||||
|
cpus = each.value.config["cpu"]
|
||||||
|
|
||||||
|
network {
|
||||||
|
type = "org"
|
||||||
|
name = each.value.network_routed
|
||||||
|
ip_allocation_mode = lookup(each.value.config["network"], "mode", "auto") == "manual" ? "MANUAL" : "POOL"
|
||||||
|
is_primary = true
|
||||||
|
|
||||||
|
# Устанавливаем IP, только если режим "manual"
|
||||||
|
ip = lookup(each.value.config["network"], "mode", "auto") == "manual" ? lookup(each.value.config["network"], "ip", null) : null
|
||||||
|
}
|
||||||
|
|
||||||
|
override_template_disk {
|
||||||
|
bus_type = "paravirtual"
|
||||||
|
size_in_mb = each.value.config["osDisk"]
|
||||||
|
bus_number = 0
|
||||||
|
unit_number = 0
|
||||||
|
}
|
||||||
|
|
||||||
|
customization {
|
||||||
|
enabled = true
|
||||||
|
#force = var.forceRecustomization || !contains(var.servers, var.servers[count.index])
|
||||||
|
#force = var.forceRecustomization
|
||||||
|
force = false
|
||||||
|
allow_local_admin_password = true
|
||||||
|
auto_generate_password = false
|
||||||
|
admin_password = local.admin_password
|
||||||
|
}
|
||||||
|
|
||||||
|
set_extra_config {
|
||||||
|
key = "disk.EnableUUID"
|
||||||
|
value = "TRUE"
|
||||||
|
}
|
||||||
|
|
||||||
|
guest_properties = {
|
||||||
|
"user-data" = base64encode(templatefile("${path.module}/templates/cloudinit.yaml", {
|
||||||
|
hostname = each.key
|
||||||
|
username = each.value.config["init_username"]
|
||||||
|
ssh_authorized_keys = each.value.config["ssh_authorized_keys"]
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
|
||||||
|
# Игноирование изменений дисков (PVC - Named Disks)
|
||||||
|
lifecycle {
|
||||||
|
ignore_changes = [
|
||||||
|
disk, # Игнорирует изменения всех дисков
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
depends_on = [
|
||||||
|
vcd_vapp_org_network.routed_network
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "vcd_vm_internal_disk" "vmdisk" {
|
||||||
|
for_each = local.disks
|
||||||
|
|
||||||
|
provider = vcd.al[each.value.vcd_key]
|
||||||
|
|
||||||
|
vapp_name = vcd_vapp.vapp[each.value.vcd_key].name
|
||||||
|
vm_name = each.value.vm_name
|
||||||
|
|
||||||
|
bus_type = "paravirtual"
|
||||||
|
bus_number = 0
|
||||||
|
unit_number = each.value.unit_num
|
||||||
|
size_in_mb = each.value.disk_size
|
||||||
|
|
||||||
|
allow_vm_reboot = true
|
||||||
|
|
||||||
|
depends_on = [
|
||||||
|
vcd_vapp_vm.vm
|
||||||
|
]
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user