MIG and ILB modules (#61)

* preliminary net-ilb module, untested

* outputs

* fix basic mistakes, add initial test

* test variable defaults on all resources

* README stub

* net-ilb module fixes and example

* compute-vm module fixes

* fix test

* remove mig from compute vm module

* split out mig from compute-vm (untested)

* split out mig from compute-vm (untested)

* fix mig versions

* small fixes and examples for mig module

* Update README.md

* Update README.md

* switch mig to using a single  variable for both region and zone
This commit is contained in:
Ludovico Magnocavallo 2020-04-30 17:08:18 +02:00 committed by GitHub
parent 5088ed61ff
commit be3c461cf9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
21 changed files with 1459 additions and 333 deletions

View File

@ -0,0 +1,188 @@
# GCE Managed Instance Group module
This module allows creating a managed instance group supporting one or more application versions via instance templates. A health check and an autoscaler can also be optionally created.
This module can be coupled with the [`compute-vm`](../compute-vm) module which can manage instance templates, and the [`net-ilb`](../net-ilb) module to assign the MIG to a backend wired to an Internal Load Balancer. The first use case is shown in the examples below.
## Examples
This example shows how to manage a simple MIG that leverages the `compute-vm` module to manage the underlying instance template. The following sub-examples will only show how to enable specific features of this module, and won't replicate the combined setup.
```hcl
module "cos-nginx" {
source = "./modules/cloud-config-container/nginx"
}
module "nginx-template" {
source = "./modules/compute-vm"
project_id = "my-project"
region = "europe-west1"
zone = "europe-west1-b"
name = "ilb-test"
network_interfaces = [{
network = local.network_self_link,
subnetwork = local.subnetwork_self_link,
nat = false,
addresses = null
}]
boot_disk = {
image = "projects/cos-cloud/global/images/family/cos-stable"
type = "pd-ssd"
size = 10
}
tags = ["http-server", "ssh"]
use_instance_template = true
metadata = {
user-data = module.cos-nginx.cloud_config
}
}
module "nginx-mig" {
source = "./modules/compute-mig"
project_id = "my-project"
location = "europe-west1-b"
name = "mig-test"
target_size = 2
default_version = {
instance_template = module.nginx-template.template.self_link
name = "default"
}
}
```
### Multiple versions
If multiple versions are desired, use more `compute-vm` instances for the additional templates used in each version (not shown here), and reference them like this:
```hcl
module "nginx-mig" {
source = "./modules/compute-mig"
project_id = "my-project"
location = "europe-west1-b"
name = "mig-test"
target_size = 3
default_version = {
instance_template = module.nginx-template-default.template.self_link
name = "default"
}
versions = {
canary = {
instance_template = module.nginx-template-default.template.self_link
target_type = "fixed"
target_size = 1
}
}
}
```
### Health check and autohealing policies
Autohealing policies can use an externally defined health check, or have this module auto-create one:
```hcl
module "nginx-mig" {
source = "./modules/compute-mig"
project_id = "my-project"
location = "europe-west1-b"
name = "mig-test"
target_size = 3
default_version = {
instance_template = module.nginx-template-default.template.self_link
name = "default"
}
auto_healing_policies = {
health_check = module.nginx-mig.health_check.self_link
initial_delay_sec = 30
}
health_check_config = {
type = "http"
check = { port = 80 }
config = {}
logging = true
}
}
```
### Autoscaling
The module can create and manage an autoscaler associated with the MIG. When using autoscaling do not set the `target_size` variable or set it to `null`. Here we show a CPU utilization autoscaler, the other available modes are load balancing utilization and custom metric, like the underlying autoscaler resource.
```hcl
module "nginx-mig" {
source = "./modules/compute-mig"
project_id = "my-project"
location = "europe-west1-b"
name = "mig-test"
target_size = 3
default_version = {
instance_template = module.nginx-template-default.template.self_link
name = "default"
}
autoscaler_config = {
max_replicas = 3
min_replicas = 1
cooldown_period = 30
cpu_utilization_target = 0.65
load_balancing_utilization_target = null
metric = null
}
}
```
### Update policy
```hcl
module "nginx-mig" {
source = "./modules/compute-mig"
project_id = "my-project"
location = "europe-west1-b"
name = "mig-test"
target_size = 3
default_version = {
instance_template = module.nginx-template-default.template.self_link
name = "default"
}
update_policy = {
type = "PROACTIVE"
minimal_action = "REPLACE"
min_ready_sec = 30
max_surge_type = "fixed"
max_surge = 1
max_unavailable_type = null
max_unavailable = null
}
}
```
<!-- BEGIN TFDOC -->
## Variables
| name | description | type | required | default |
|---|---|:---: |:---:|:---:|
| default_version | Default application version template. Additional versions can be specified via the `versions` variable. | <code title="object&#40;&#123;&#10;instance_template &#61; string&#10;name &#61; string&#10;&#125;&#41;">object({...})</code> | ✓ | |
| location | Compute zone, or region if `regional` is set to true. | <code title="">string</code> | ✓ | |
| name | Managed group name. | <code title="">string</code> | ✓ | |
| project_id | Project id. | <code title="">string</code> | ✓ | |
| *auto_healing_policies* | Auto-healing policies for this group. | <code title="object&#40;&#123;&#10;health_check &#61; string&#10;initial_delay_sec &#61; number&#10;&#125;&#41;">object({...})</code> | | <code title="">null</code> |
| *autoscaler_config* | Optional autoscaler configuration. Only one of 'cpu_utilization_target' 'load_balancing_utilization_target' or 'metric' can be not null. | <code title="object&#40;&#123;&#10;max_replicas &#61; number&#10;min_replicas &#61; number&#10;cooldown_period &#61; number&#10;cpu_utilization_target &#61; number&#10;load_balancing_utilization_target &#61; number&#10;metric &#61; object&#40;&#123;&#10;name &#61; string&#10;single_instance_assignment &#61; number&#10;target &#61; number&#10;type &#61; string &#35; GAUGE, DELTA_PER_SECOND, DELTA_PER_MINUTE&#10;filter &#61; string&#10;&#125;&#41;&#10;&#125;&#41;">object({...})</code> | | <code title="">null</code> |
| *health_check_config* | Optional auto-created helth check configuration, use the output self-link to set it in the auto healing policy. Refer to examples for usage. | <code title="object&#40;&#123;&#10;type &#61; string &#35; http https tcp ssl http2&#10;check &#61; map&#40;any&#41; &#35; actual health check block attributes&#10;config &#61; map&#40;number&#41; &#35; interval, thresholds, timeout&#10;logging &#61; bool&#10;&#125;&#41;">object({...})</code> | | <code title="">null</code> |
| *named_ports* | Named ports. | <code title="map&#40;number&#41;">map(number)</code> | | <code title="">null</code> |
| *regional* | Use regional instance group. When set, `location` should be set to the region. | <code title="">bool</code> | | <code title="">false</code> |
| *target_pools* | Optional list of URLs for target pools to which new instances in the group are added. | <code title="list&#40;string&#41;">list(string)</code> | | <code title="">[]</code> |
| *target_size* | Group target size, leave null when using an autoscaler. | <code title="">number</code> | | <code title="">null</code> |
| *update_policy* | Update policy. Type can be 'OPPORTUNISTIC' or 'PROACTIVE', action 'REPLACE' or 'restart', surge type 'fixed' or 'percent'. | <code title="object&#40;&#123;&#10;type &#61; string &#35; OPPORTUNISTIC &#124; PROACTIVE&#10;minimal_action &#61; string &#35; REPLACE &#124; RESTART&#10;min_ready_sec &#61; number&#10;max_surge_type &#61; string &#35; fixed &#124; percent&#10;max_surge &#61; number&#10;max_unavailable_type &#61; string&#10;max_unavailable &#61; number&#10;&#125;&#41;">object({...})</code> | | <code title="">null</code> |
| *versions* | Additional application versions, target_type is either 'fixed' or 'percent'. | <code title="map&#40;object&#40;&#123;&#10;instance_template &#61; string&#10;target_type &#61; string &#35; fixed &#124; percent&#10;target_size &#61; number&#10;&#125;&#41;&#41;">map(object({...}))</code> | | <code title="">null</code> |
| *wait_for_instances* | Wait for all instances to be created/updated before returning. | <code title="">bool</code> | | <code title="">null</code> |
## Outputs
| name | description | sensitive |
|---|---|:---:|
| autoscaler | Auto-created autoscaler resource. | |
| group_manager | Instance group resource. | |
| health_check | Auto-created health-check resource. | |
<!-- END TFDOC -->
## TODO
- [ ] add support for instance groups

367
modules/compute-mig/main.tf Normal file
View File

@ -0,0 +1,367 @@
/**
* Copyright 2019 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
resource "google_compute_autoscaler" "default" {
provider = google-beta
count = var.regional || var.autoscaler_config == null ? 0 : 1
project = var.project_id
name = var.name
description = "Terraform managed."
zone = var.location
target = google_compute_instance_group_manager.default.0.id
autoscaling_policy {
max_replicas = var.autoscaler_config.max_replicas
min_replicas = var.autoscaler_config.min_replicas
cooldown_period = var.autoscaler_config.cooldown_period
dynamic cpu_utilization {
for_each = (
var.autoscaler_config.cpu_utilization_target == null ? [] : [""]
)
content {
target = var.autoscaler_config.cpu_utilization_target
}
}
dynamic load_balancing_utilization {
for_each = (
var.autoscaler_config.load_balancing_utilization_target == null ? [] : [""]
)
content {
target = var.autoscaler_config.load_balancing_utilization_target
}
}
dynamic metric {
for_each = (
var.autoscaler_config.metric == null
? []
: [var.autoscaler_config.metric]
)
iterator = config
content {
name = config.value.name
single_instance_assignment = config.value.single_instance_assignment
target = config.value.target
type = config.value.type
filter = config.value.filter
}
}
}
}
resource "google_compute_instance_group_manager" "default" {
provider = google-beta
count = var.regional ? 0 : 1
project = var.project_id
zone = var.location
name = var.name
base_instance_name = var.name
description = "Terraform-managed."
target_size = var.target_size
target_pools = var.target_pools
wait_for_instances = var.wait_for_instances
dynamic auto_healing_policies {
for_each = var.auto_healing_policies == null ? [] : [var.auto_healing_policies]
iterator = config
content {
health_check = config.value.health_check
initial_delay_sec = config.value.initial_delay_sec
}
}
dynamic update_policy {
for_each = var.update_policy == null ? [] : [var.update_policy]
iterator = config
content {
type = config.value.type
minimal_action = config.value.minimal_action
min_ready_sec = config.value.min_ready_sec
max_surge_fixed = (
config.value.max_surge_type == "fixed" ? config.value.max_surge : null
)
max_surge_percent = (
config.value.max_surge_type == "percent" ? config.value.max_surge : null
)
max_unavailable_fixed = (
config.value.max_unavailable_type == "fixed" ? config.value.max_unavailable : null
)
max_unavailable_percent = (
config.value.max_unavailable_type == "percent" ? config.value.max_unavailable : null
)
}
}
dynamic named_port {
for_each = var.named_ports == null ? {} : var.named_ports
iterator = config
content {
name = config.key
port = config.value
}
}
version {
instance_template = var.default_version.instance_template
name = var.default_version.name
}
dynamic version {
for_each = var.versions == null ? {} : var.versions
iterator = version
content {
name = version.key
instance_template = version.value.instance_template
target_size {
fixed = (
version.value.target_type == "fixed" ? version.value.target_size : null
)
percent = (
version.value.target_type == "percent" ? version.value.target_size : null
)
}
}
}
}
resource "google_compute_region_autoscaler" "default" {
provider = google-beta
count = var.regional && var.autoscaler_config != null ? 1 : 0
project = var.project_id
name = var.name
description = "Terraform managed."
region = var.location
target = google_compute_region_instance_group_manager.default.0.id
autoscaling_policy {
max_replicas = var.autoscaler_config.max_replicas
min_replicas = var.autoscaler_config.min_replicas
cooldown_period = var.autoscaler_config.cooldown_period
dynamic cpu_utilization {
for_each = (
var.autoscaler_config.cpu_utilization_target == null ? [] : [""]
)
content {
target = var.autoscaler_config.cpu_utilization_target
}
}
dynamic load_balancing_utilization {
for_each = (
var.autoscaler_config.load_balancing_utilization_target == null ? [] : [""]
)
content {
target = var.autoscaler_config.load_balancing_utilization_target
}
}
dynamic metric {
for_each = (
var.autoscaler_config.metric == null
? []
: [var.autoscaler_config.metric]
)
iterator = config
content {
name = config.value.name
single_instance_assignment = config.value.single_instance_assignment
target = config.value.target
type = config.value.type
filter = config.value.filter
}
}
}
}
resource "google_compute_region_instance_group_manager" "default" {
provider = google-beta
count = var.regional ? 1 : 0
project = var.project_id
region = var.location
name = var.name
base_instance_name = var.name
description = "Terraform-managed."
target_size = var.target_size
target_pools = var.target_pools
wait_for_instances = var.wait_for_instances
dynamic auto_healing_policies {
for_each = var.auto_healing_policies == null ? [] : [var.auto_healing_policies]
iterator = config
content {
health_check = config.value.health_check
initial_delay_sec = config.value.initial_delay_sec
}
}
dynamic update_policy {
for_each = var.update_policy == null ? [] : [var.update_policy]
iterator = config
content {
type = config.value.type
minimal_action = config.value.minimal_action
min_ready_sec = config.value.min_ready_sec
max_surge_fixed = (
config.value.max_surge_type == "fixed" ? config.value.max_surge : null
)
max_surge_percent = (
config.value.max_surge_type == "percent" ? config.value.max_surge : null
)
max_unavailable_fixed = (
config.value.max_unavailable_type == "fixed" ? config.value.max_unavailable : null
)
max_unavailable_percent = (
config.value.max_unavailable_type == "percent" ? config.value.max_unavailable : null
)
}
}
dynamic named_port {
for_each = var.named_ports == null ? {} : var.named_ports
iterator = config
content {
name = config.key
port = config.value
}
}
version {
instance_template = var.default_version.instance_template
name = var.default_version.name
}
dynamic version {
for_each = var.versions == null ? {} : var.versions
iterator = version
content {
name = version.key
instance_template = version.value.instance_template
target_size {
fixed = (
version.value.target_type == "fixed" ? version.value.target_size : null
)
percent = (
version.value.target_type == "percent" ? version.value.target_size : null
)
}
}
}
}
resource "google_compute_health_check" "default" {
provider = google-beta
count = var.health_check_config == null ? 0 : 1
project = var.project_id
name = var.name
description = "Terraform managed."
check_interval_sec = try(var.health_check_config.config.check_interval_sec, null)
healthy_threshold = try(var.health_check_config.config.healthy_threshold, null)
timeout_sec = try(var.health_check_config.config.timeout_sec, null)
unhealthy_threshold = try(var.health_check_config.config.unhealthy_threshold, null)
dynamic http_health_check {
for_each = (
try(var.health_check_config.type, null) == "http"
? [var.health_check_config.check]
: []
)
iterator = check
content {
host = try(check.value.host, null)
port = try(check.value.port, null)
port_name = try(check.value.port_name, null)
port_specification = try(check.value.port_specification, null)
proxy_header = try(check.value.proxy_header, null)
request_path = try(check.value.request_path, null)
response = try(check.value.response, null)
}
}
dynamic https_health_check {
for_each = (
try(var.health_check_config.type, null) == "https"
? [var.health_check_config.check]
: []
)
iterator = check
content {
host = try(check.value.host, null)
port = try(check.value.port, null)
port_name = try(check.value.port_name, null)
port_specification = try(check.value.port_specification, null)
proxy_header = try(check.value.proxy_header, null)
request_path = try(check.value.request_path, null)
response = try(check.value.response, null)
}
}
dynamic tcp_health_check {
for_each = (
try(var.health_check_config.type, null) == "tcp"
? [var.health_check_config.check]
: []
)
iterator = check
content {
port = try(check.value.port, null)
port_name = try(check.value.port_name, null)
port_specification = try(check.value.port_specification, null)
proxy_header = try(check.value.proxy_header, null)
request = try(check.value.request, null)
response = try(check.value.response, null)
}
}
dynamic ssl_health_check {
for_each = (
try(var.health_check_config.type, null) == "ssl"
? [var.health_check_config.check]
: []
)
iterator = check
content {
port = try(check.value.port, null)
port_name = try(check.value.port_name, null)
port_specification = try(check.value.port_specification, null)
proxy_header = try(check.value.proxy_header, null)
request = try(check.value.request, null)
response = try(check.value.response, null)
}
}
dynamic http2_health_check {
for_each = (
try(var.health_check_config.type, null) == "http2"
? [var.health_check_config.check]
: []
)
iterator = check
content {
host = try(check.value.host, null)
port = try(check.value.port, null)
port_name = try(check.value.port_name, null)
port_specification = try(check.value.port_specification, null)
proxy_header = try(check.value.proxy_header, null)
request_path = try(check.value.request_path, null)
response = try(check.value.response, null)
}
}
dynamic log_config {
for_each = try(var.health_check_config.logging, false) ? [""] : []
content {
enable = true
}
}
}

View File

@ -0,0 +1,40 @@
/**
* Copyright 2019 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
output "autoscaler" {
description = "Auto-created autoscaler resource."
value = var.autoscaler_config == null ? null : try(
google_compute_autoscaler.default.0,
google_compute_region_autoscaler.default.0,
{}
)
}
output "group_manager" {
description = "Instance group resource."
value = try(
google_compute_instance_group_manager.default.0,
google_compute_region_instance_group_manager.default.0,
{}
)
}
output "health_check" {
description = "Auto-created health-check resource."
value = var.health_check_config == null ? null : try(
google_compute_health_check.default.0, {}
)
}

View File

@ -0,0 +1,131 @@
/**
* Copyright 2019 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
variable "autoscaler_config" {
description = "Optional autoscaler configuration. Only one of 'cpu_utilization_target' 'load_balancing_utilization_target' or 'metric' can be not null."
type = object({
max_replicas = number
min_replicas = number
cooldown_period = number
cpu_utilization_target = number
load_balancing_utilization_target = number
metric = object({
name = string
single_instance_assignment = number
target = number
type = string # GAUGE, DELTA_PER_SECOND, DELTA_PER_MINUTE
filter = string
})
})
default = null
}
variable "auto_healing_policies" {
description = "Auto-healing policies for this group."
type = object({
health_check = string
initial_delay_sec = number
})
default = null
}
variable "default_version" {
description = "Default application version template. Additional versions can be specified via the `versions` variable."
type = object({
instance_template = string
name = string
})
}
variable "health_check_config" {
description = "Optional auto-created helth check configuration, use the output self-link to set it in the auto healing policy. Refer to examples for usage."
type = object({
type = string # http https tcp ssl http2
check = map(any) # actual health check block attributes
config = map(number) # interval, thresholds, timeout
logging = bool
})
default = null
}
variable "location" {
description = "Compute zone, or region if `regional` is set to true."
type = string
}
variable "name" {
description = "Managed group name."
type = string
}
variable "named_ports" {
description = "Named ports."
type = map(number)
default = null
}
variable "project_id" {
description = "Project id."
type = string
}
variable "regional" {
description = "Use regional instance group. When set, `location` should be set to the region."
type = bool
default = false
}
variable "target_pools" {
description = "Optional list of URLs for target pools to which new instances in the group are added."
type = list(string)
default = []
}
variable "target_size" {
description = "Group target size, leave null when using an autoscaler."
type = number
default = null
}
variable "update_policy" {
description = "Update policy. Type can be 'OPPORTUNISTIC' or 'PROACTIVE', action 'REPLACE' or 'restart', surge type 'fixed' or 'percent'."
type = object({
type = string # OPPORTUNISTIC | PROACTIVE
minimal_action = string # REPLACE | RESTART
min_ready_sec = number
max_surge_type = string # fixed | percent
max_surge = number
max_unavailable_type = string
max_unavailable = number
})
default = null
}
variable "versions" {
description = "Additional application versions, target_type is either 'fixed' or 'percent'."
type = map(object({
instance_template = string
target_type = string # fixed | percent
target_size = number
}))
default = null
}
variable "wait_for_instances" {
description = "Wait for all instances to be created/updated before returning."
type = bool
default = null
}

View File

@ -1,6 +1,11 @@
# Google Compute Engine VM module
This module allows creating one or multiple instances or an instance template for a specific configuration. A service account is optionally created and assigned if not specified.
This module can operate in two distinct modes:
- instance creation, with optional unmanaged group
- instance template creation
In both modes, an optional service account can be created and assigned to either instances or template. If you need a managed instance group when using the module in template mode, refer to the [`compute-mig`](../compute-mig) module.
## Examples
@ -57,9 +62,9 @@ module "debian-test" {
}
```
### Managed instance group
### Instance group
This example shows a basic instance where the module is used to create an instance template, and the template is associated to a basic managed instance group with no autohealing or autoscaling configuration. Instance group support is meant for prototyping, or in those situations where there's no need to manage multiple application versions.
If an instance group is needed when operating in instance mode, simply set the `group` variable to a non null map. The map can contain named port declarations, or be empty if named ports are not needed.
```hcl
module "instance-group" {
@ -85,16 +90,7 @@ module "instance-group" {
metadata = {
user-data = local.cloud_config
}
group_manager = {
auto_healing_policies = null
options = null
update_policy = null
named_ports = {}
regional = false
target_size = 2
versions = []
default = module.instance-group.template.self_link
}
group = {}
}
```
@ -112,8 +108,7 @@ module "instance-group" {
| *attached_disk_defaults* | Defaults for attached disks options. | <code title="object&#40;&#123;&#10;auto_delete &#61; bool&#10;mode &#61; string&#10;type &#61; string&#10;source &#61; string&#10;&#125;&#41;">object({...})</code> | | <code title="&#123;&#10;auto_delete &#61; true&#10;source &#61; null&#10;mode &#61; &#34;READ_WRITE&#34;&#10;type &#61; &#34;pd-ssd&#34;&#10;&#125;">...</code> |
| *attached_disks* | Additional disks, if options is null defaults will be used in its place. | <code title="list&#40;object&#40;&#123;&#10;name &#61; string&#10;image &#61; string&#10;size &#61; string&#10;options &#61; object&#40;&#123;&#10;auto_delete &#61; bool&#10;mode &#61; string&#10;source &#61; string&#10;type &#61; string&#10;&#125;&#41;&#10;&#125;&#41;&#41;">list(object({...}))</code> | | <code title="">[]</code> |
| *boot_disk* | Boot disk properties. | <code title="object&#40;&#123;&#10;image &#61; string&#10;size &#61; number&#10;type &#61; string&#10;&#125;&#41;">object({...})</code> | | <code title="&#123;&#10;image &#61; &#34;projects&#47;debian-cloud&#47;global&#47;images&#47;family&#47;debian-10&#34;&#10;type &#61; &#34;pd-ssd&#34;&#10;size &#61; 10&#10;&#125;">...</code> |
| *group* | Instance group (for instance use). | <code title="object&#40;&#123;&#10;named_ports &#61; map&#40;number&#41;&#10;&#125;&#41;">object({...})</code> | | <code title="">null</code> |
| *group_manager* | Instance group manager (for template use). | <code title="object&#40;&#123;&#10;auto_healing_policies &#61; object&#40;&#123;&#10;health_check &#61; string&#10;initial_delay_sec &#61; number&#10;&#125;&#41;&#10;named_ports &#61; map&#40;number&#41;&#10;options &#61; object&#40;&#123;&#10;target_pools &#61; list&#40;string&#41;&#10;wait_for_instances &#61; bool&#10;&#125;&#41;&#10;regional &#61; bool&#10;target_size &#61; number&#10;update_policy &#61; object&#40;&#123;&#10;type &#61; string &#35; OPPORTUNISTIC &#124; PROACTIVE&#10;minimal_action &#61; string &#35; REPLACE &#124; RESTART&#10;min_ready_sec &#61; number&#10;max_surge_type &#61; string &#35; fixed &#124; percent&#10;max_surge &#61; number&#10;max_unavailable_type &#61; string&#10;max_unavailable &#61; number&#10;&#125;&#41;&#10;versions &#61; list&#40;object&#40;&#123;&#10;name &#61; string&#10;instance_template &#61; string&#10;target_type &#61; string &#35; fixed &#124; percent&#10;target_size &#61; number&#10;&#125;&#41;&#41;&#10;&#125;&#41;">object({...})</code> | | <code title="">null</code> |
| *group* | Define this variable to create an instance group for instances. Disabled for template use. | <code title="object&#40;&#123;&#10;named_ports &#61; map&#40;number&#41;&#10;&#125;&#41;">object({...})</code> | | <code title="">null</code> |
| *hostname* | Instance FQDN name. | <code title="">string</code> | | <code title="">null</code> |
| *instance_count* | Number of instances to create (only for non-template usage). | <code title="">number</code> | | <code title="">1</code> |
| *instance_type* | Instance type. | <code title="">string</code> | | <code title="">f1-micro</code> |
@ -134,7 +129,6 @@ module "instance-group" {
|---|---|:---:|
| external_ips | Instance main interface external IP addresses. | |
| group | Instance group resource. | |
| group_manager | Instance group resource. | |
| instances | Instance resources. | |
| internal_ips | Instance main interface internal IP addresses. | |
| names | Instance names. | |

View File

@ -1,215 +0,0 @@
/**
* Copyright 2019 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
resource "google_compute_instance_group" "unmanaged" {
count = (
var.group != null && ! var.use_instance_template ? 1 : 0
)
project = var.project_id
network = (
length(var.network_interfaces) > 0
? var.network_interfaces.0.network
: ""
)
zone = var.zone
name = var.name
description = "Terraform-managed."
instances = [
for name, instance in google_compute_instance.default : instance.self_link
]
dynamic named_port {
for_each = var.group.named_ports != null ? var.group.named_ports : {}
iterator = config
content {
name = config.key
port = config.value
}
}
}
resource "google_compute_instance_group_manager" "managed" {
count = (
var.group_manager != null && var.use_instance_template
? var.group_manager.regional ? 0 : 1
: 0
)
project = var.project_id
zone = var.zone
name = var.name
base_instance_name = var.name
description = "Terraform-managed."
target_size = var.group_manager.target_size
target_pools = (
var.group_manager.options == null
? null
: var.group_manager.options.target_pools
)
wait_for_instances = (
var.group_manager.options == null
? null
: var.group_manager.options.wait_for_instances
)
dynamic auto_healing_policies {
for_each = (
var.group_manager.auto_healing_policies == null
? []
: [var.group_manager.auto_healing_policies]
)
iterator = config
content {
health_check = config.value.health_check
initial_delay_sec = config.value.initial_delay_sec
}
}
dynamic update_policy {
for_each = (
var.group_manager.update_policy == null
? []
: [var.group_manager.update_policy]
)
iterator = config
content {
type = config.value.type
minimal_action = config.value.minimal_action
min_ready_sec = config.value.min_ready_sec
max_surge_fixed = (
config.value.max_surge_type == "fixed" ? config.value.max_surge : null
)
max_surge_percent = (
config.value.max_surge_type == "percent" ? config.value.max_surge : null
)
max_unavailable_fixed = (
config.value.max_unavailable_type == "fixed" ? config.value.max_unavailable : null
)
max_unavailable_percent = (
config.value.max_unavailable_type == "percent" ? config.value.max_unavailable : null
)
}
}
dynamic named_port {
for_each = var.group_manager.named_ports != null ? var.group_manager.named_ports : {}
iterator = config
content {
name = config.key
port = config.value
}
}
version {
name = "${var.name}-default"
instance_template = google_compute_instance_template.default.0.self_link
}
dynamic version {
for_each = (
var.group_manager.versions == null ? [] : var.group_manager.versions
)
iterator = config
content {
name = config.value.name
instance_template = config.value.instance_template
target_size {
fixed = config.value.target_type == "fixed" ? config.value.target_size : null
percent = config.value.target_type == "percent" ? config.value.target_size : null
}
}
}
}
resource "google_compute_region_instance_group_manager" "managed" {
count = (
var.group_manager != null && var.use_instance_template
? var.group_manager.regional ? 1 : 0
: 0
)
project = var.project_id
region = var.region
name = var.name
base_instance_name = var.name
description = "Terraform-managed."
target_size = var.group_manager.target_size
target_pools = (
var.group_manager.options == null
? null
: var.group_manager.options.target_pools
)
wait_for_instances = (
var.group_manager.options == null
? null
: var.group_manager.options.wait_for_instances
)
dynamic auto_healing_policies {
for_each = (
var.group_manager.auto_healing_policies == null
? []
: [var.group_manager.auto_healing_policies]
)
iterator = config
content {
health_check = config.value.health_check
initial_delay_sec = config.value.initial_delay_sec
}
}
dynamic update_policy {
for_each = (
var.group_manager.update_policy == null
? []
: [var.group_manager.update_policy]
)
iterator = config
content {
type = config.value.type
minimal_action = config.value.minimal_action
min_ready_sec = config.value.min_ready_sec
max_surge_fixed = (
config.value.max_surge_type == "fixed" ? config.value.max_surge : null
)
max_surge_percent = (
config.value.max_surge_type == "percent" ? config.value.max_surge : null
)
max_unavailable_fixed = (
config.value.max_unavailable_type == "fixed" ? config.value.max_unavailable : null
)
max_unavailable_percent = (
config.value.max_unavailable_type == "percent" ? config.value.max_unavailable : null
)
}
}
dynamic named_port {
for_each = var.group.named_ports
iterator = config
content {
name = config.key
port = config.value
}
}
version {
name = "${var.name}-default"
instance_template = google_compute_instance_template.default.0.self_link
}
dynamic version {
for_each = (
var.group_manager.versions == null ? [] : [var.group_manager.versions]
)
iterator = config
content {
name = config.value.name
instance_template = config.value.instance_template
target_size {
fixed = config.value.target_type == "fixed" ? config.value.target_size : null
percent = config.value.target_type == "percent" ? config.value.target_size : null
}
}
}
}

View File

@ -218,6 +218,32 @@ resource "google_compute_instance_template" "default" {
}
}
resource "google_compute_instance_group" "unmanaged" {
count = (
var.group != null && ! var.use_instance_template ? 1 : 0
)
project = var.project_id
network = (
length(var.network_interfaces) > 0
? var.network_interfaces.0.network
: ""
)
zone = var.zone
name = var.name
description = "Terraform-managed."
instances = [
for name, instance in google_compute_instance.default : instance.self_link
]
dynamic named_port {
for_each = var.group.named_ports != null ? var.group.named_ports : {}
iterator = config
content {
name = config.key
port = config.value
}
}
}
resource "google_service_account" "service_account" {
count = var.service_account_create ? 1 : 0
project = var.project_id

View File

@ -28,24 +28,7 @@ output "external_ips" {
output "group" {
description = "Instance group resource."
value = (
length(google_compute_instance_group.unmanaged) > 0
? google_compute_instance_group.unmanaged.0
: null
)
}
output "group_manager" {
description = "Instance group resource."
value = (
length(google_compute_instance_group_manager.managed) > 0
? google_compute_instance_group_manager.managed.0
: (
length(google_compute_region_instance_group_manager.managed) > 0
? google_compute_region_instance_group_manager.managed.0
: null
)
)
value = try(google_compute_instance_group.unmanaged.0, null)
}
output "instances" {

View File

@ -61,46 +61,13 @@ variable "boot_disk" {
}
variable "group" {
description = "Instance group (for instance use)."
description = "Define this variable to create an instance group for instances. Disabled for template use."
type = object({
named_ports = map(number)
})
default = null
}
variable "group_manager" {
description = "Instance group manager (for template use)."
type = object({
auto_healing_policies = object({
health_check = string
initial_delay_sec = number
})
named_ports = map(number)
options = object({
target_pools = list(string)
wait_for_instances = bool
})
regional = bool
target_size = number
update_policy = object({
type = string # OPPORTUNISTIC | PROACTIVE
minimal_action = string # REPLACE | RESTART
min_ready_sec = number
max_surge_type = string # fixed | percent
max_surge = number
max_unavailable_type = string
max_unavailable = number
})
versions = list(object({
name = string
instance_template = string
target_type = string # fixed | percent
target_size = number
}))
})
default = null
}
variable "hostname" {
description = "Instance FQDN name."
type = string

110
modules/net-ilb/README.md Normal file
View File

@ -0,0 +1,110 @@
# Internal Load Balancer Module
This module allows managing a GCE Internal Load Balancer and integrates the forwarding rule, regional backend, and optional health check resources. It's designed to be a simple match for the [`compute-vm`](../compute-vm) module, which can be used to manage instance templates and instance groups.
## Issues
TODO(ludoo): check if this is still the case after splitting out MIG from compute-vm
There are some corner cases (eg when switching the instance template from internal service account to an externally managed one) where Terraform raises a cycle error on apply. In these situations, run successive applies targeting resources used in the template first then the template itself, and the cycle should be fixed.
One other issue is a `Provider produced inconsistent final plan` error which is sometimes raised when switching template version. This seems to be related to this [open provider issue](https://github.com/terraform-providers/terraform-provider-google/issues/3937), but it's relatively harmless since the resource is updated, and subsequent applies raise no errors.
## Example
This example spins up a simple HTTP server and combines four modules:
- [`nginx`](../cloud-config-container/nginx) from the `cloud-config-container` collection, to manage instance configuration
- [`compute-vm`](../compute-vm) to manage the instance template and unmanaged instance group
- this module to create an Internal Load Balancer in front of the managed instance group
Note that the example uses the GCE default service account. You might want to create an ad-hoc service account by combining the [`iam-service-accounts`](../iam-service-accounts) module, or by having the GCE VM module create one for you. In both cases, remember to set at least logging write permissions for the service account, or the container on the instances won't be able to start.
```hcl
module "cos-nginx" {
source = "./modules/cloud-config-container/nginx"
}
module "instance-group" {
source = "./modules/compute-vm"
project_id = "my-project"
region = "europe-west1"
zone = "europe-west1-b"
name = "ilb-test"
network_interfaces = [{
network = local.network_self_link,
subnetwork = local.subnetwork_self_link,
nat = false,
addresses = null
}]
boot_disk = {
image = "projects/cos-cloud/global/images/family/cos-stable"
type = "pd-ssd"
size = 10
}
tags = ["http-server", "ssh"]
metadata = {
user-data = module.cos-nginx.cloud_config
}
group = {}
}
module "ilb" {
source = "./modules/net-ilb"
project_id = "my-project"
region = "europe-west1"
name = "ilb-test"
service_label = "ilb-test"
network = local.network_self_link
subnetwork = local.subnetwork_self_link
ports = [80]
backends = [{
failover = false
group = module.instance-group.group.self_link
balancing_mode = "CONNECTION"
}]
health_check_config = {
type = "http", check = { port = 80 }, config = {}, logging = true
}
}
```
<!-- BEGIN TFDOC -->
## Variables
| name | description | type | required | default |
|---|---|:---: |:---:|:---:|
| backends | Load balancer backends, balancing mode is one of 'CONNECTION' or 'UTILIZATION'. | <code title="list&#40;object&#40;&#123;&#10;failover &#61; bool&#10;group &#61; string&#10;balancing_mode &#61; string&#10;&#125;&#41;&#41;">list(object({...}))</code> | ✓ | |
| name | Name used for all resources. | <code title="">string</code> | ✓ | |
| network | Network used for resources. | <code title="">string</code> | ✓ | |
| project_id | Project id where resources will be created. | <code title="">string</code> | ✓ | |
| region | GCP region. | <code title="">string</code> | ✓ | |
| subnetwork | Subnetwork used for the forwarding rule. | <code title="">string</code> | ✓ | |
| *address* | Optional IP address used for the forwarding rule. | <code title="">string</code> | | <code title="">null</code> |
| *backend_config* | Optional backend configuration. | <code title="object&#40;&#123;&#10;session_affinity &#61; string&#10;timeout_sec &#61; number&#10;connection_draining_timeout_sec &#61; number&#10;&#125;&#41;">object({...})</code> | | <code title="">null</code> |
| *failover_config* | Optional failover configuration. | <code title="object&#40;&#123;&#10;disable_connection_drain &#61; bool&#10;drop_traffic_if_unhealthy &#61; bool&#10;ratio &#61; number&#10;&#125;&#41;">object({...})</code> | | <code title="">null</code> |
| *global_access* | Global access, defaults to false if not set. | <code title="">bool</code> | | <code title="">null</code> |
| *health_check* | Name of existing health check to use, disables auto-created health check. | <code title="">string</code> | | <code title="">null</code> |
| *health_check_config* | Configuration of the auto-created helth check. | <code title="object&#40;&#123;&#10;type &#61; string &#35; http https tcp ssl http2&#10;check &#61; map&#40;any&#41; &#35; actual health check block attributes&#10;config &#61; map&#40;number&#41; &#35; interval, thresholds, timeout&#10;&#125;&#41;">object({...})</code> | | <code title="&#123;&#10;type &#61; &#34;http&#34;&#10;check &#61; &#123;&#10;port_specification &#61; &#34;USE_SERVING_PORT&#34;&#10;&#125;&#10;config &#61; &#123;&#125;&#10;&#125;">...</code> |
| *labels* | Labels set on resources. | <code title="map&#40;string&#41;">map(string)</code> | | <code title="">{}</code> |
| *log_sample_rate* | Set a value between 0 and 1 to enable logging for resources, and set the sampling rate for backend logging. | <code title="">number</code> | | <code title="">null</code> |
| *ports* | Comma-separated ports, leave null to use all ports. | <code title="list&#40;string&#41;">list(string)</code> | | <code title="">null</code> |
| *protocol* | IP protocol used, defaults to TCP. | <code title="">string</code> | | <code title="">TCP</code> |
| *service_label* | Optional prefix of the fully qualified forwarding rule name. | <code title="">string</code> | | <code title="">null</code> |
## Outputs
| name | description | sensitive |
|---|---|:---:|
| backend | Backend resource. | |
| backend_id | Backend id. | |
| backend_self_link | Backend self link. | |
| forwarding_rule | Forwarding rule resource. | |
| forwarding_rule_address | Forwarding rule address. | |
| forwarding_rule_id | Forwarding rule id. | |
| forwarding_rule_self_link | Forwarding rule self link. | |
| health_check | Auto-created health-check resource. | |
| health_check_self_id | Auto-created health-check self id. | |
| health_check_self_link | Auto-created health-check self link. | |
<!-- END TFDOC -->

191
modules/net-ilb/main.tf Normal file
View File

@ -0,0 +1,191 @@
/**
* Copyright 2020 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
locals {
health_check = (
var.health_check == null
? try(google_compute_health_check.default.0.self_link, null)
: var.health_check
)
}
resource "google_compute_forwarding_rule" "default" {
provider = google-beta
project = var.project_id
name = var.name
description = "Terraform managed."
load_balancing_scheme = "INTERNAL"
region = var.region
network = var.network
subnetwork = var.subnetwork
ip_address = var.address
ip_protocol = var.protocol # TCP | UDP
ports = var.ports # "nnnnn" or "nnnnn,nnnnn,nnnnn" max 5
service_label = var.service_label
all_ports = var.ports == null ? true : null
allow_global_access = var.global_access
backend_service = google_compute_region_backend_service.default.self_link
# is_mirroring_collector = false
labels = var.labels
}
resource "google_compute_region_backend_service" "default" {
provider = google-beta
project = var.project_id
name = var.name
description = "Terraform managed."
load_balancing_scheme = "INTERNAL"
region = var.region
network = var.network
health_checks = [local.health_check]
protocol = var.protocol
session_affinity = try(var.backend_config.session_affinity, null)
timeout_sec = try(var.backend_config.timeout_sec, null)
connection_draining_timeout_sec = try(var.backend_config.connection_draining_timeout_sec, null)
dynamic backend {
for_each = { for b in var.backends : b.group => b }
iterator = backend
content {
balancing_mode = backend.value.balancing_mode
description = "Terraform managed."
failover = backend.value.failover
group = backend.key
}
}
dynamic failover_policy {
for_each = var.failover_config == null ? [] : [var.failover_config]
iterator = config
content {
disable_connection_drain_on_failover = config.value.disable_connection_drain
drop_traffic_if_unhealthy = config.value.drop_traffic_if_unhealthy
failover_ratio = config.value.ratio
}
}
}
resource "google_compute_health_check" "default" {
provider = google-beta
count = var.health_check == null ? 1 : 0
project = var.project_id
name = var.name
description = "Terraform managed."
check_interval_sec = try(var.health_check_config.config.check_interval_sec, null)
healthy_threshold = try(var.health_check_config.config.healthy_threshold, null)
timeout_sec = try(var.health_check_config.config.timeout_sec, null)
unhealthy_threshold = try(var.health_check_config.config.unhealthy_threshold, null)
dynamic http_health_check {
for_each = (
try(var.health_check_config.type, null) == "http"
? [var.health_check_config.check]
: []
)
iterator = check
content {
host = try(check.value.host, null)
port = try(check.value.port, null)
port_name = try(check.value.port_name, null)
port_specification = try(check.value.port_specification, null)
proxy_header = try(check.value.proxy_header, null)
request_path = try(check.value.request_path, null)
response = try(check.value.response, null)
}
}
dynamic https_health_check {
for_each = (
try(var.health_check_config.type, null) == "https"
? [var.health_check_config.check]
: []
)
iterator = check
content {
host = try(check.value.host, null)
port = try(check.value.port, null)
port_name = try(check.value.port_name, null)
port_specification = try(check.value.port_specification, null)
proxy_header = try(check.value.proxy_header, null)
request_path = try(check.value.request_path, null)
response = try(check.value.response, null)
}
}
dynamic tcp_health_check {
for_each = (
try(var.health_check_config.type, null) == "tcp"
? [var.health_check_config.check]
: []
)
iterator = check
content {
port = try(check.value.port, null)
port_name = try(check.value.port_name, null)
port_specification = try(check.value.port_specification, null)
proxy_header = try(check.value.proxy_header, null)
request = try(check.value.request, null)
response = try(check.value.response, null)
}
}
dynamic ssl_health_check {
for_each = (
try(var.health_check_config.type, null) == "ssl"
? [var.health_check_config.check]
: []
)
iterator = check
content {
port = try(check.value.port, null)
port_name = try(check.value.port_name, null)
port_specification = try(check.value.port_specification, null)
proxy_header = try(check.value.proxy_header, null)
request = try(check.value.request, null)
response = try(check.value.response, null)
}
}
dynamic http2_health_check {
for_each = (
try(var.health_check_config.type, null) == "http2"
? [var.health_check_config.check]
: []
)
iterator = check
content {
host = try(check.value.host, null)
port = try(check.value.port, null)
port_name = try(check.value.port_name, null)
port_specification = try(check.value.port_specification, null)
proxy_header = try(check.value.proxy_header, null)
request_path = try(check.value.request_path, null)
response = try(check.value.response, null)
}
}
dynamic log_config {
for_each = try(var.health_check_config.logging, false) ? [""] : []
content {
enable = true
}
}
}

View File

@ -0,0 +1,65 @@
/**
* Copyright 2020 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
output "backend" {
description = "Backend resource."
value = google_compute_region_backend_service.default
}
output "backend_id" {
description = "Backend id."
value = google_compute_region_backend_service.default.id
}
output "backend_self_link" {
description = "Backend self link."
value = google_compute_region_backend_service.default.self_link
}
output "forwarding_rule" {
description = "Forwarding rule resource."
value = google_compute_forwarding_rule.default
}
output "forwarding_rule_address" {
description = "Forwarding rule address."
value = google_compute_forwarding_rule.default.ip_address
}
output "forwarding_rule_id" {
description = "Forwarding rule id."
value = google_compute_forwarding_rule.default.id
}
output "forwarding_rule_self_link" {
description = "Forwarding rule self link."
value = google_compute_forwarding_rule.default.self_link
}
output "health_check" {
description = "Auto-created health-check resource."
value = try(google_compute_health_check.default.0, {})
}
output "health_check_self_id" {
description = "Auto-created health-check self id."
value = try(google_compute_health_check.default.0.id, null)
}
output "health_check_self_link" {
description = "Auto-created health-check self link."
value = try(google_compute_health_check.default.0.self_link, null)
}

View File

@ -0,0 +1,129 @@
/**
* Copyright 2020 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
variable "address" {
description = "Optional IP address used for the forwarding rule."
type = string
default = null
}
variable "backends" {
description = "Load balancer backends, balancing mode is one of 'CONNECTION' or 'UTILIZATION'."
type = list(object({
failover = bool
group = string
balancing_mode = string
}))
}
variable "backend_config" {
description = "Optional backend configuration."
type = object({
session_affinity = string
timeout_sec = number
connection_draining_timeout_sec = number
})
default = null
}
variable "failover_config" {
description = "Optional failover configuration."
type = object({
disable_connection_drain = bool
drop_traffic_if_unhealthy = bool
ratio = number
})
default = null
}
variable "global_access" {
description = "Global access, defaults to false if not set."
type = bool
default = null
}
variable "health_check" {
description = "Name of existing health check to use, disables auto-created health check."
type = string
default = null
}
variable "health_check_config" {
description = "Configuration of the auto-created helth check."
type = object({
type = string # http https tcp ssl http2
check = map(any) # actual health check block attributes
config = map(number) # interval, thresholds, timeout
logging = bool
})
default = {
type = "http"
check = {
port_specification = "USE_SERVING_PORT"
}
config = {}
logging = false
}
}
variable "labels" {
description = "Labels set on resources."
type = map(string)
default = {}
}
variable "name" {
description = "Name used for all resources."
type = string
}
variable "network" {
description = "Network used for resources."
type = string
}
variable "project_id" {
description = "Project id where resources will be created."
type = string
}
variable "ports" {
description = "Comma-separated ports, leave null to use all ports."
type = list(string)
default = null
}
variable "protocol" {
description = "IP protocol used, defaults to TCP."
type = string
default = "TCP"
}
variable "region" {
description = "GCP region."
type = string
}
variable "service_label" {
description = "Optional prefix of the fully qualified forwarding rule name."
type = string
default = null
}
variable "subnetwork" {
description = "Subnetwork used for the forwarding rule."
type = string
}

View File

@ -30,5 +30,4 @@ module "test" {
instance_count = var.instance_count
use_instance_template = var.use_instance_template
group = var.group
group_manager = var.group_manager
}

View File

@ -19,11 +19,6 @@ variable "group" {
default = null
}
variable "group_manager" {
type = any
default = null
}
variable "instance_count" {
type = number
default = 1

View File

@ -44,3 +44,12 @@ def test_template(plan_runner):
assert len(resources) == 1
assert resources[0]['type'] == 'google_compute_instance_template'
assert resources[0]['values']['name_prefix'] == 'test-'
def test_group(plan_runner):
plan, resources = plan_runner(FIXTURES_DIR, instance_count=2,
group='{named_ports={}}')
assert len(resources) == 3
assert set(r['type'] for r in resources) == set([
'google_compute_instance_group', 'google_compute_instance'
])

View File

@ -1,44 +0,0 @@
# Copyright 2020 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import os
import pytest
FIXTURES_DIR = os.path.join(os.path.dirname(__file__), 'fixture')
def test_unmanaged(plan_runner):
plan, resources = plan_runner(FIXTURES_DIR, instance_count=2,
group='{named_ports={}}')
assert len(resources) == 3
assert set(r['type'] for r in resources) == set([
'google_compute_instance_group', 'google_compute_instance'
])
def test_managed(plan_runner):
plan, resources = plan_runner(
FIXTURES_DIR, use_instance_template='true', group_manager=(
'{ '
'auto_healing_policies=null, named_ports={}, options=null, '
'regional=false, target_size=1, update_policy=null, versions=null'
' }'
)
)
assert len(resources) == 2
assert set(r['type'] for r in resources) == set([
'google_compute_instance_group_manager', 'google_compute_instance_template'
])

View File

@ -0,0 +1,13 @@
# Copyright 2020 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

View File

@ -0,0 +1,35 @@
/**
* Copyright 2020 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
module "test" {
source = "../../../../modules/net-ilb"
project_id = "my-project"
region = "europe-west1"
network = "default"
subnetwork = "default"
name = "ilb-test"
labels = {}
address = var.address
backends = var.backends
backend_config = var.backend_config
failover_config = var.failover_config
global_access = var.global_access
health_check = var.health_check
health_check_config = var.health_check_config
ports = var.ports
protocol = var.protocol
service_label = var.service_label
}

View File

@ -0,0 +1,88 @@
/**
* Copyright 2020 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
variable "address" {
type = string
default = null
}
variable "backends" {
type = list(object({
failover = bool
group = string
balancing_mode = string
}))
}
variable "backend_config" {
type = object({
session_affinity = string
timeout_sec = number
connection_draining_timeout_sec = number
})
default = null
}
variable "failover_config" {
type = object({
disable_connection_drain = bool
drop_traffic_if_unhealthy = bool
ratio = number
})
default = null
}
variable "global_access" {
type = bool
default = null
}
variable "health_check" {
type = string
default = null
}
variable "health_check_config" {
type = object({
type = string # http https tcp ssl http2
check = map(any) # actual health check block attributes
config = map(number) # interval, thresholds, timeout
logging = bool
})
default = {
type = "http"
check = {
port_specification = "USE_SERVING_PORT"
}
config = {}
logging = false
}
}
variable "ports" {
type = list(string)
default = null
}
variable "protocol" {
type = string
default = "TCP"
}
variable "service_label" {
type = string
default = null
}

View File

@ -0,0 +1,55 @@
# Copyright 2020 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import os
import pytest
FIXTURES_DIR = os.path.join(os.path.dirname(__file__), 'fixture')
_BACKENDS = '[{balancing_mode="CONNECTION", group="foo", failover=false}]'
def test_defaults(plan_runner):
"Test variable defaults."
_, resources = plan_runner(FIXTURES_DIR, backends=_BACKENDS)
assert len(resources) == 3
resources = dict((r['type'], r['values']) for r in resources)
fwd_rule = resources['google_compute_forwarding_rule']
assert fwd_rule['load_balancing_scheme'] == 'INTERNAL'
assert fwd_rule['all_ports']
assert fwd_rule['allow_global_access'] is None
backend = resources['google_compute_region_backend_service']
assert len(backend['backend']) == 1
assert backend['backend'][0]['group'] == 'foo'
health_check = resources['google_compute_health_check']
for k, v in health_check.items():
if k == 'http_health_check':
assert len(v) == 1
assert v[0]['port_specification'] == 'USE_SERVING_PORT'
elif k.endswith('_health_check'):
assert len(v) == 0
def test_forwarding_rule(plan_runner):
"Test forwarding rule variables."
_, resources = plan_runner(
FIXTURES_DIR, backends=_BACKENDS, global_access='true', ports="[80]")
assert len(resources) == 3
values = [r['values'] for r in resources if r['type']
== 'google_compute_forwarding_rule'][0]
assert not values['all_ports']
assert values['ports'] == ['80']
assert values['allow_global_access']