fix: add primary version 6 flag

Signed-off-by: matttrach <matt.trachier@suse.com>
This commit is contained in:
matttrach 2024-07-25 15:41:39 -05:00
parent 22bed2b03c
commit a32e49e3a0
No known key found for this signature in database
GPG Key ID: E082F2592F87D4AE
10 changed files with 366 additions and 177 deletions

View File

@ -8,11 +8,18 @@ See the examples/select/image for an example of how to do this
## Recent Changes
1. Rename images
1. IPv6 Only Support
To support load balanced IPv6 only instances, the primary interface needs to have the 'primary ipv6 enabled' flag set.
This flag is not currently available in the Terraform provider, but a PR exists: https://github.com/hashicorp/terraform-provider-aws/pull/36425
Until the provider supports this flag we are using a workaround.
The workaround requires the AWS CLI to be installed on the server running Terraform.
The AWS CLI will use the same authentication mechanisms as Terraform, so there is no need to configure additional credentials.
WARNING! If deploying with `ip_family = "ipv6"` the server running Terraform must have the AWS CLI installed.
2. Rename images
- Removed SUSE images that weren't BYOS (bring your own subscription)
- Amazon subscriptions are harder to automate and don't provide direct service, it ends up being a hidden fee of using the image. Instead, users can use the BYOS image without a subscription until they need one, and then they can add a subscription separately bought from SUSE.
- Started using SUSE cloud info API to get the latest image names
2. WARNING! Refactor!
3. WARNING! Refactor!
A new Major version and a few new tricks.
I don't like breaking the interface, but to enable new functionality it made the most sense to refactor.
- set the private ip for your sever
@ -24,11 +31,6 @@ See the examples/select/image for an example of how to do this
- look out for attributes like "server_use_strategy" to enable or disable features
- indirect access!
- now you can assign aws lb target group associations when you generate your server
3. New Images!
- Added SUSE Liberty 7.9
- Added SLE Micro 5.5 (all subscription types)
- WARNING! we can't test llc (US and China) images due to our account geolocation (Germany)
## AWS Access

View File

@ -0,0 +1,7 @@
# Basic
This example shows the simpliest implementation of this module.
In this case "simple" means using the fewest features.
This bare bones example will deploy a server into a VPC with no external access.
We will show how to enable features individually in futher examples.

View File

@ -0,0 +1,85 @@
provider "aws" {
default_tags {
tags = {
Id = local.identifier
Owner = local.email
}
}
}
locals {
identifier = var.identifier # this is a random unique string that can be used to identify resources in the cloud provider
category = "basic"
example = "dualstack"
email = "terraform-ci@suse.com"
project_name = "tf-${substr(md5(join("-", [local.category, local.example, md5(local.identifier)])), 0, 5)}-${local.identifier}"
image = "sles-15"
username = lower(substr("tf-${local.identifier}", 0, 32))
ip = chomp(data.http.myip.response_body)
ssh_key = var.key
}
data "http" "myip" {
url = "https://ipinfo.io/ip"
retry {
attempts = 2
min_delay_ms = 1000
}
}
data "aws_availability_zones" "available" {
state = "available"
}
resource "random_pet" "server" {
keepers = {
# regenerate the pet name when the identifier changes
identifier = local.identifier
}
length = 1
}
module "access" {
source = "rancher/access/aws"
version = "v3.1.2"
vpc_name = "${local.project_name}-vpc"
vpc_type = "dualstack"
security_group_name = "${local.project_name}-sg"
security_group_type = "project"
load_balancer_name = "${local.project_name}-lb"
domain_use_strategy = "skip"
}
module "this" {
depends_on = [
module.access,
]
source = "../../../" # change this to "rancher/server/aws" per https://registry.terraform.io/modules/rancher/server/aws/latest
# version = "v1.1.1" # when using this example you will need to set the version
image_type = local.image
server_name = "${local.project_name}-${random_pet.server.id}"
server_type = "small"
subnet_name = keys(module.access.subnets)[0]
server_ip_family = "dualstack"
security_group_name = module.access.security_group.tags_all.Name
# direct_access_use_strategy = "ssh" # either the subnet needs to be public or you must add an eip
# cloudinit_use_strategy = "default" # use the default cloudinit config
# server_access_addresses = { # you must include ssh access here to enable setup
# "runner" = {
# port = 22
# protocol = "tcp"
# ip_family = "ipv4"
# cidrs = ["${local.ip}/32"]
# }
# }
# server_user = {
# user = local.username
# aws_keypair_use_strategy = "skip" # we will use cloud-init to add a keypair directly
# ssh_key_name = "" # not creating or selecting a key, but this field is still required
# public_ssh_key = local.ssh_key # ssh key to add via cloud-init
# user_workfolder = "/home/${local.username}"
# timeout = 5
# }
}

View File

@ -0,0 +1,9 @@
output "server" {
value = module.this.server
}
output "image" {
value = module.this.image
}
output "access" {
value = module.access
}

View File

@ -0,0 +1,6 @@
variable "identifier" {
type = string
}
variable "key" {
type = string
}

View File

@ -0,0 +1,24 @@
terraform {
required_version = ">= 1.5.0, < 1.6"
required_providers {
local = {
source = "hashicorp/local"
version = ">= 2.4"
}
aws = {
source = "hashicorp/aws"
version = ">= 5.11"
}
random = {
source = "hashicorp/random"
version = ">= 3.1"
}
acme = { # used in the access module
source = "vancluever/acme"
version = ">= 2.0"
}
}
}
provider "acme" {
server_url = "https://acme-staging-v02.api.letsencrypt.org/directory"
}

View File

@ -13,8 +13,8 @@ locals {
example = "sles15"
email = "terraform-ci@suse.com"
project_name = "tf-${substr(md5(join("-", [local.category, local.example, md5(local.identifier)])), 0, 5)}-${local.identifier}"
username = lower(substr("tf-${local.identifier}", 0, 32))
image = "sles-15"
username = lower(substr("tf-${local.identifier}", 0, 32))
ip = chomp(data.http.myip.response_body)
ssh_key = var.key
}

View File

@ -60,6 +60,11 @@ data "aws_subnet" "general_info_create" {
values = [local.subnet]
}
}
data "aws_availability_zone" "general_info_create" {
count = local.create
name = data.aws_subnet.general_info_create[0].availability_zone
}
data "aws_vpc" "general_info_create" {
count = local.create
id = data.aws_security_group.general_info_create[0].vpc_id
@ -123,3 +128,35 @@ resource "aws_instance" "created" {
]
}
}
# WARNING! This forces a dependency on the AWS CLI, but only for "ipv6 only" servers.
# This is a workaround for the fact that the terraform AWS provider doesn't support the primary ipv6 flag yet.
# When the provider supports it, this can be removed and the attribute added to the instance resource.
resource "terraform_data" "set_primary_ipv6" {
count = (local.ip_family == "ipv6" ? local.create : 0)
depends_on = [
data.aws_security_group.general_info_create,
data.aws_subnet.general_info_create,
aws_key_pair.created,
aws_instance.created,
]
triggers_replace = {
"aws_instance" = "${aws_instance.created[0].id}"
}
provisioner "local-exec" {
command = <<-EOT
if ! aws ec2 describe-network-interfaces \
--network-interface-ids ${aws_instance.created[0].primary_network_interface_id} \
--region ${data.aws_availability_zone.general_info_create[0].region} \
--query 'NetworkInterfaces[0].Ipv6Addresses[?IsPrimaryIpv6==`true`]' \
--output text | grep -q .; then
aws ec2 modify-network-interface-attribute \
--network-interface-id ${aws_instance.created[0].primary_network_interface_id} \
--enable-primary-ipv6 \
--region ${data.aws_availability_zone.general_info_create[0].region}
else
echo "Primary IPv6 is already enabled for this network interface"
fi
EOT
}
}

View File

@ -30,6 +30,23 @@ func TestBasicBasic(t *testing.T) {
terraform.InitAndApply(t, terraformOptions)
}
func TestBasicDualstack(t *testing.T) {
t.Parallel()
id := os.Getenv("IDENTIFIER")
if id == "" {
id = random.UniqueId()
}
uniqueID := id + "-" + random.UniqueId()
category := "basic"
directory := "dualstack"
region := "us-west-2"
owner := "terraform-ci@suse.com"
terraformOptions, keyPair := setup(t, category, directory, region, owner, uniqueID)
delete(terraformOptions.Vars, "key_name")
defer teardown(t, category, directory, keyPair)
defer terraform.Destroy(t, terraformOptions)
terraform.InitAndApply(t, terraformOptions)
}
func TestBasicPrivateIp(t *testing.T) {
t.Parallel()
id := os.Getenv("IDENTIFIER")
@ -158,7 +175,7 @@ func TestBasicDirectSshEip(t *testing.T) {
terraform.InitAndPlan(t, terraformOptions)
terraform.InitAndApply(t, terraformOptions)
out := terraform.OutputAll(t,terraformOptions)
out := terraform.OutputAll(t, terraformOptions)
t.Logf("out: %v", out)
outputServer, ok := out["server"].(map[string]interface{})
assert.True(t, ok, fmt.Sprintf("Wrong data type for 'server', expected map[string], got %T", out["server"]))
@ -191,7 +208,7 @@ func TestBasicDirectSshSubnet(t *testing.T) {
terraform.InitAndPlan(t, terraformOptions)
terraform.InitAndApply(t, terraformOptions)
out := terraform.OutputAll(t,terraformOptions)
out := terraform.OutputAll(t, terraformOptions)
t.Logf("out: %v", out)
outputServer, ok := out["server"].(map[string]interface{})
assert.True(t, ok, fmt.Sprintf("Wrong data type for 'server', expected map[string], got %T", out["server"]))

View File

@ -157,6 +157,8 @@ variable "server_ip_family" {
The ip family to use for the server, must be one of "ipv4", "dualstack", or "ipv6".
This is mainly determined by the VPC and subnet that you are deploying to,
attempting to deploy a dualstack or ipv6 server to a non-dualstack/ipv6 VPC/subnet will result in failed connections.
WARNING! When this is set to "ipv6" the server running Terraform must have the AWS CLI installed.
This is due to a missing feature in the AWS provider that allows ipv6 instances to be attached to load balancer target groups.
EOT
default = "ipv4"
validation {