Skip to content

Commit

Permalink
feat: functionality added to create Network Load Balancer(NLB). When …
Browse files Browse the repository at this point in the history
…the profile value in the `load_balancers` input is set as `network-fixed`, it signifies to setup an NLB. An existing subnet can be provided to provision NLB otherwise NLB uses the first subnet from the subnets list. Subsequently, a listener, a pool, and pool members are connected to the NLB. (#654)
  • Loading branch information
maheshwarishikha committed Apr 19, 2024
1 parent feac630 commit 0460e99
Show file tree
Hide file tree
Showing 6 changed files with 108 additions and 31 deletions.
5 changes: 3 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,8 @@ No modules.
| [ibm_is_lb.lb](https://registry.terraform.io/providers/IBM-Cloud/ibm/latest/docs/resources/is_lb) | resource |
| [ibm_is_lb_listener.listener](https://registry.terraform.io/providers/IBM-Cloud/ibm/latest/docs/resources/is_lb_listener) | resource |
| [ibm_is_lb_pool.pool](https://registry.terraform.io/providers/IBM-Cloud/ibm/latest/docs/resources/is_lb_pool) | resource |
| [ibm_is_lb_pool_member.pool_members](https://registry.terraform.io/providers/IBM-Cloud/ibm/latest/docs/resources/is_lb_pool_member) | resource |
| [ibm_is_lb_pool_member.alb_pool_members](https://registry.terraform.io/providers/IBM-Cloud/ibm/latest/docs/resources/is_lb_pool_member) | resource |
| [ibm_is_lb_pool_member.nlb_pool_members](https://registry.terraform.io/providers/IBM-Cloud/ibm/latest/docs/resources/is_lb_pool_member) | resource |
| [ibm_is_security_group.security_group](https://registry.terraform.io/providers/IBM-Cloud/ibm/latest/docs/resources/is_security_group) | resource |
| [ibm_is_security_group_rule.security_group_rules](https://registry.terraform.io/providers/IBM-Cloud/ibm/latest/docs/resources/is_security_group_rule) | resource |
| [ibm_is_volume.volume](https://registry.terraform.io/providers/IBM-Cloud/ibm/latest/docs/resources/is_volume) | resource |
Expand All @@ -159,7 +160,7 @@ No modules.
| <a name="input_existing_kms_instance_guid"></a> [existing\_kms\_instance\_guid](#input\_existing\_kms\_instance\_guid) | The GUID of the Hyper Protect Crypto Services instance in which the key specified in var.boot\_volume\_encryption\_key is coming from. | `string` | `null` | no |
| <a name="input_image_id"></a> [image\_id](#input\_image\_id) | Image ID used for VSI. Run 'ibmcloud is images' to find available images in a region | `string` | n/a | yes |
| <a name="input_kms_encryption_enabled"></a> [kms\_encryption\_enabled](#input\_kms\_encryption\_enabled) | Set this to true to control the encryption keys used to encrypt the data that for the block storage volumes for VPC. If set to false, the data is encrypted by using randomly generated keys. For more info on encrypting block storage volumes, see https://cloud.ibm.com/docs/vpc?topic=vpc-creating-instances-byok | `bool` | `false` | no |
| <a name="input_load_balancers"></a> [load\_balancers](#input\_load\_balancers) | Load balancers to add to VSI | <pre>list(<br> object({<br> name = string<br> type = string<br> listener_port = number<br> listener_protocol = string<br> connection_limit = number<br> idle_connection_timeout = optional(number)<br> algorithm = string<br> protocol = string<br> health_delay = number<br> health_retries = number<br> health_timeout = number<br> health_type = string<br> pool_member_port = string<br> profile = optional(string)<br> dns = optional(<br> object({<br> instance_crn = string<br> zone_id = string<br> })<br> )<br> security_group = optional(<br> object({<br> name = string<br> rules = list(<br> object({<br> name = string<br> direction = string<br> source = string<br> tcp = optional(<br> object({<br> port_max = number<br> port_min = number<br> })<br> )<br> udp = optional(<br> object({<br> port_max = number<br> port_min = number<br> })<br> )<br> icmp = optional(<br> object({<br> type = number<br> code = number<br> })<br> )<br> })<br> )<br> })<br> )<br> })<br> )</pre> | `[]` | no |
| <a name="input_load_balancers"></a> [load\_balancers](#input\_load\_balancers) | Load balancers to add to VSI | <pre>list(<br> object({<br> name = string<br> type = string<br> listener_port = optional(number)<br> listener_port_max = optional(number)<br> listener_port_min = optional(number)<br> listener_protocol = string<br> connection_limit = optional(number)<br> idle_connection_timeout = optional(number)<br> algorithm = string<br> protocol = string<br> health_delay = number<br> health_retries = number<br> health_timeout = number<br> health_type = string<br> pool_member_port = string<br> profile = optional(string)<br> accept_proxy_protocol = optional(bool)<br> subnet_id_to_provision_nlb = optional(string) # Required for Network Load Balancer. If no value is provided, the first one from the VPC subnet list will be selected.<br> dns = optional(<br> object({<br> instance_crn = string<br> zone_id = string<br> })<br> )<br> security_group = optional(<br> object({<br> name = string<br> rules = list(<br> object({<br> name = string<br> direction = string<br> source = string<br> tcp = optional(<br> object({<br> port_max = number<br> port_min = number<br> })<br> )<br> udp = optional(<br> object({<br> port_max = number<br> port_min = number<br> })<br> )<br> icmp = optional(<br> object({<br> type = number<br> code = number<br> })<br> )<br> })<br> )<br> })<br> )<br> })<br> )</pre> | `[]` | no |
| <a name="input_machine_type"></a> [machine\_type](#input\_machine\_type) | VSI machine type. Run 'ibmcloud is instance-profiles' to get a list of regional profiles | `string` | n/a | yes |
| <a name="input_placement_group_id"></a> [placement\_group\_id](#input\_placement\_group\_id) | Unique Identifier of the Placement Group for restricting the placement of the instance, default behaviour is placement on any host | `string` | `null` | no |
| <a name="input_prefix"></a> [prefix](#input\_prefix) | The IBM Cloud platform API key needed to deploy IAM enabled resources | `string` | n/a | yes |
Expand Down
2 changes: 1 addition & 1 deletion examples/complete/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,4 @@ It will provision the following:
- A VSI in each subnet placed in the placement group.
- A floating IP for each virtual server created.
- A secondary VSI with secondary subnets and secondary security group.
- A new Application Load Balancer to balance traffic between all virtual servers that are created by this example.
- A new Application Load Balancer and Network Load Balancer to balance traffic between all virtual servers that are created by this example.
14 changes: 14 additions & 0 deletions examples/complete/main.tf
Original file line number Diff line number Diff line change
Expand Up @@ -203,6 +203,20 @@ module "slz_vsi" {
health_timeout = 30
health_type = "http"
pool_member_port = 8080
},
{
name = "${var.prefix}-nlb"
type = "public"
profile = "network-fixed"
listener_port = 3128
listener_protocol = "tcp"
algorithm = "round_robin"
protocol = "tcp"
health_delay = 60
health_retries = 5
health_timeout = 30
health_type = "tcp"
pool_member_port = 3120
}
]
}
53 changes: 39 additions & 14 deletions load_balancer.tf
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,14 @@ locals {
for load_balancer in var.load_balancers :
(load_balancer.name) => load_balancer
}

subnets_id = var.subnets[*].id
}

resource "ibm_is_lb" "lb" {
for_each = local.load_balancer_map
name = "${var.prefix}-${each.value.name}-lb"
subnets = var.subnets[*].id
subnets = (each.value.profile == "network-fixed") ? (each.value.subnet_id_to_provision_nlb != null ? [each.value.subnet_id_to_provision_nlb] : [local.subnets_id[0]]) : local.subnets_id
type = each.value.type #checkov:skip=CKV2_IBM_1:See https://github.com/bridgecrewio/checkov/issues/5824#
profile = each.value.profile
security_groups = each.value.security_group == null ? null : [ibm_is_security_group.security_group[each.value.security_group.name].id]
Expand Down Expand Up @@ -53,7 +55,7 @@ resource "ibm_is_lb_pool" "pool" {
##############################################################################

locals {
pool_members = flatten([
alb_pool_members = flatten([
for load_balancer in var.load_balancers :
[
for ipv4_address in [
Expand All @@ -64,22 +66,42 @@ locals {
port = load_balancer.pool_member_port
target_address = ipv4_address
lb = load_balancer.name
}
profile = load_balancer.profile
} if(load_balancer.profile != "network-fixed")
]
])
}

resource "ibm_is_lb_pool_member" "pool_members" {
count = length(local.pool_members)
port = local.pool_members[count.index].port
lb = ibm_is_lb.lb[local.pool_members[count.index].lb].id
pool = element(split("/", ibm_is_lb_pool.pool[local.pool_members[count.index].lb].id), 1)
target_address = local.pool_members[count.index].target_address
nlb_pool_members = flatten([
for load_balancer in var.load_balancers :
[
for server in ibm_is_instance.vsi :
{
port = load_balancer.pool_member_port
lb = load_balancer.name
target_id = server.id
profile = load_balancer.profile
} if(load_balancer.profile == "network-fixed")
]
])
}

##############################################################################
resource "ibm_is_lb_pool_member" "alb_pool_members" {
count = length(local.alb_pool_members)
port = local.alb_pool_members[count.index].port
lb = ibm_is_lb.lb[local.alb_pool_members[count.index].lb].id
pool = element(split("/", ibm_is_lb_pool.pool[local.alb_pool_members[count.index].lb].id), 1)
target_address = local.alb_pool_members[count.index].target_address
}

resource "ibm_is_lb_pool_member" "nlb_pool_members" {
count = length(local.nlb_pool_members)
port = local.nlb_pool_members[count.index].port
lb = ibm_is_lb.lb[local.nlb_pool_members[count.index].lb].id
pool = element(split("/", ibm_is_lb_pool.pool[local.nlb_pool_members[count.index].lb].id), 1)
target_id = local.nlb_pool_members[count.index].target_id
}

##############################################################################

##############################################################################
# Load Balancer Listener
Expand All @@ -90,10 +112,13 @@ resource "ibm_is_lb_listener" "listener" {
lb = ibm_is_lb.lb[each.value.name].id
default_pool = ibm_is_lb_pool.pool[each.value.name].id
port = each.value.listener_port
port_min = (each.value.listener_port == null && each.value.profile == "network-fixed") ? each.value.listener_port_min : null
port_max = (each.value.listener_port == null && each.value.profile == "network-fixed") ? each.value.listener_port_max : null
protocol = each.value.listener_protocol
connection_limit = each.value.connection_limit > 0 ? each.value.connection_limit : null
idle_connection_timeout = each.value.idle_connection_timeout
depends_on = [ibm_is_lb_pool_member.pool_members]
connection_limit = each.value.profile != "network-fixed" ? (each.value.connection_limit > 0 ? each.value.connection_limit : null) : null
idle_connection_timeout = each.value.profile != "network-fixed" ? each.value.idle_connection_timeout : null
accept_proxy_protocol = each.value.accept_proxy_protocol
depends_on = [ibm_is_lb_pool_member.alb_pool_members, ibm_is_lb_pool_member.nlb_pool_members]
}

##############################################################################
9 changes: 9 additions & 0 deletions moved_config.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
############################################################################################################################################
# The following moved blocks allow consumers to upgrade the module from v3.2.4 or older without destroying the existing ALB pool members
# For more details, please refer - https://github.com/terraform-ibm-modules/terraform-ibm-landing-zone-vsi/issues/649
############################################################################################################################################

moved {
from = ibm_is_lb_pool_member.pool_members
to = ibm_is_lb_pool_member.alb_pool_members
}
56 changes: 42 additions & 14 deletions variables.tf
Original file line number Diff line number Diff line change
Expand Up @@ -233,20 +233,24 @@ variable "load_balancers" {
description = "Load balancers to add to VSI"
type = list(
object({
name = string
type = string
listener_port = number
listener_protocol = string
connection_limit = number
idle_connection_timeout = optional(number)
algorithm = string
protocol = string
health_delay = number
health_retries = number
health_timeout = number
health_type = string
pool_member_port = string
profile = optional(string)
name = string
type = string
listener_port = optional(number)
listener_port_max = optional(number)
listener_port_min = optional(number)
listener_protocol = string
connection_limit = optional(number)
idle_connection_timeout = optional(number)
algorithm = string
protocol = string
health_delay = number
health_retries = number
health_timeout = number
health_type = string
pool_member_port = string
profile = optional(string)
accept_proxy_protocol = optional(bool)
subnet_id_to_provision_nlb = optional(string) # Required for Network Load Balancer. If no value is provided, the first one from the VPC subnet list will be selected.
dns = optional(
object({
instance_crn = string
Expand Down Expand Up @@ -356,6 +360,30 @@ variable "load_balancers" {
error_message = "Each load balancer must have a unique name."
condition = length(distinct(var.load_balancers[*].name)) == length(var.load_balancers[*].name)
}

validation {
error_message = "Application load balancer connection_limit can not be null."
condition = length(
flatten([
for load_balancer in var.load_balancers :
load_balancer.profile != "network-fixed" ?
(load_balancer.connection_limit == null) ? [true] : []
: []
])
) == 0
}

validation {
error_message = "Application load balancer listener_port can not be null."
condition = length(
flatten([
for load_balancer in var.load_balancers :
load_balancer.profile != "network-fixed" ?
(load_balancer.listener_port == null) ? [true] : []
: []
])
) == 0
}
}

##############################################################################
Expand Down

0 comments on commit 0460e99

Please sign in to comment.