feat: enable rancher helm chart values

Signed-off-by: matttrach <matt.trachier@suse.com>
This commit is contained in:
matttrach 2025-07-08 10:50:16 -05:00
parent 3df73bf72b
commit ad853e2435
No known key found for this signature in database
GPG Key ID: E082F2592F87D4AE
26 changed files with 301 additions and 355 deletions

11
examples/three/README.md Normal file
View File

@ -0,0 +1,11 @@
# Three
This module was developed working closely with specific customer feedback.
## Goals
- three node HA Rancher cluster where each node has all Kubernetes roles
- the ability to specify a helm repo for the Rancher install (specifically the prime repo)
- the ability to specify custom values for Rancher helm chart
- the ability to use a remote backend, updating the infrastructure using a CI tool

View File

@ -24,8 +24,8 @@ provider "rancher2" {
terraform {
backend "s3" {
# This needs to be set in the backend configs on the command line.
# bucket = local.identifier
# This needs to be set in the backend configs on the command line or somewhere that your identifier can be set.
# terraform init -reconfigure -backend-config="bucket=<identifier>"
# https://developer.hashicorp.com/terraform/language/backend/s3
# https://developer.hashicorp.com/terraform/language/backend#partial-configuration
key = "tfstate"
@ -62,10 +62,25 @@ locals {
acme_server_url = "https://acme-v02.api.letsencrypt.org"
owner = var.owner
rke2_version = var.rke2_version
rancher_helm_repo = "https://releases.rancher.com/server-charts"
rancher_helm_channel = "stable"
helm_chart_strategy = "provide"
# These options use the Let's Encrypt cert that the module generates for you when you deploy the VPC and Domain.
# WARNING! "hostname" must be an fqdn
helm_chart_values = {
"hostname" = "${local.domain}.${local.zone}"
"replicas" = "2"
"bootstrapPassword" = "admin"
"ingress.enabled" = "true"
"ingress.tls.source" = "secret"
"ingress.tls.secretName" = "tls-rancher-ingress"
"privateCA" = "true"
"agentTLSMode" = "system-store"
}
local_file_path = var.file_path
runner_ip = chomp(data.http.myip.response_body) # "runner" is the server running Terraform
rancher_version = var.rancher_version
cert_manager_version = "1.16.3" # "1.13.1"
cert_manager_version = "1.18.1" #"1.16.3"
os = "sle-micro-61"
}
@ -115,8 +130,13 @@ module "rancher" {
}
}
# rancher
cert_manager_version = local.cert_manager_version
rancher_version = local.rancher_version
cert_manager_version = local.cert_manager_version
configure_cert_manager = false # use the cert generated at the project level
rancher_version = local.rancher_version
rancher_helm_repo = local.rancher_helm_repo
rancher_helm_channel = local.rancher_helm_channel
rancher_helm_chart_use_strategy = local.helm_chart_strategy
rancher_helm_chart_values = local.helm_chart_values
}
data "rancher2_cluster" "local" {

View File

@ -20,11 +20,11 @@
},
"nixpkgs": {
"locked": {
"lastModified": 1751180975,
"narHash": "sha256-BKk4yDiXr4LdF80OTVqYJ53Q74rOcA/82EClXug8xsY=",
"lastModified": 1751852175,
"narHash": "sha256-+MLlfTCCOvz4K6AcSPbaPiFM9MYi7fA2Wr1ibmRwIlM=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "a48741b083d4f36dd79abd9f760c84da6b4dc0e5",
"rev": "2defa37146df235ef62f566cde69930a86f14df1",
"type": "github"
},
"original": {

52
main.tf
View File

@ -28,14 +28,19 @@ locals {
cni = var.cni
node_configuration = var.node_configuration
# rancher
cert_manager_version = var.cert_manager_version
rancher_version = var.rancher_version
ip_family = "ipv4"
# ingress_controller = "nginx"
bootstrap_rancher = var.bootstrap_rancher
install_cert_manager = var.install_cert_manager
configure_cert_manager = var.configure_cert_manager
cert_manager_config = var.cert_manager_configuration
cert_name = (var.tls_cert_name != "" ? var.tls_cert_name : module.cluster.cert.name)
cert_key = (var.tls_cert_key != "" ? var.tls_cert_key : module.cluster.cert.key_id)
cert_manager_version = var.cert_manager_version
rancher_version = var.rancher_version
rancher_helm_repo = var.rancher_helm_repo
rancher_helm_channel = var.rancher_helm_channel
ip_family = "ipv4"
rancher_helm_chart_values = var.rancher_helm_chart_values
rancher_helm_chart_use_strategy = var.rancher_helm_chart_use_strategy
bootstrap_rancher = var.bootstrap_rancher
install_cert_manager = var.install_cert_manager
configure_cert_manager = var.configure_cert_manager
cert_manager_config = var.cert_manager_configuration
}
data "aws_route53_zone" "zone" {
@ -59,7 +64,6 @@ module "cluster" {
cni = local.cni
node_configuration = local.node_configuration
ip_family = local.ip_family
# ingress_controller = local.ingress_controller
skip_cert_creation = local.skip_cert
}
@ -72,8 +76,8 @@ module "install_cert_manager" {
project_domain = local.fqdn
zone = local.zone
zone_id = data.aws_route53_zone.zone.zone_id
project_cert_name = module.cluster.cert.name
project_cert_key_id = module.cluster.cert.key_id
project_cert_name = local.cert_name
project_cert_key_id = local.cert_key
path = local.local_file_path
cert_manager_version = local.cert_manager_version
configure_cert_manager = local.configure_cert_manager
@ -85,15 +89,19 @@ module "rancher_bootstrap" {
module.cluster,
module.install_cert_manager,
]
count = (local.bootstrap_rancher ? 1 : 0)
source = "./modules/rancher_bootstrap"
path = local.local_file_path
project_domain = local.fqdn
zone_id = data.aws_route53_zone.zone.zone_id
region = local.cert_manager_config.aws_region
email = local.cert_manager_config.acme_email
acme_server_url = local.cert_manager_config.acme_server_url
rancher_version = local.rancher_version
cert_manager_version = local.cert_manager_version
externalTLS = (local.configure_cert_manager ? false : true)
count = (local.bootstrap_rancher ? 1 : 0)
source = "./modules/rancher_bootstrap"
path = local.local_file_path
project_domain = local.fqdn
zone_id = data.aws_route53_zone.zone.zone_id
region = local.cert_manager_config.aws_region
email = local.cert_manager_config.acme_email
acme_server_url = local.cert_manager_config.acme_server_url
rancher_version = local.rancher_version
rancher_helm_repo = local.rancher_helm_repo
rancher_helm_channel = local.rancher_helm_channel
cert_manager_version = local.cert_manager_version
externalTLS = (local.configure_cert_manager ? false : true)
rancher_helm_chart_values = local.rancher_helm_chart_values
rancher_helm_chart_use_strategy = local.rancher_helm_chart_use_strategy
}

View File

@ -25,11 +25,6 @@ locals {
var.file_path != "" ? (var.file_path == path.root ? "${path.root}/rke2" : var.file_path) :
"${path.root}/rke2"
)
# # tflint-ignore: terraform_unused_declarations
# local_file_path_validate = (can(regex(
# "^\\.",
# local.local_file_path
# )) ? false : one([local.local_file_path, "local_file_path_must_be_relative"])) # used like this we can validate local variables
install_method = var.install_method
download = (local.install_method == "tar" ? "download" : "skip")
@ -182,8 +177,7 @@ module "deploy_initial_node" {
user_workfolder = strcontains(each.value.os, "cis") ? "/var/tmp" : "/home/${local.username}"
timeout = 10
}))}"
server_domain_name = "${substr("${local.project_name}-${md5(each.key)}", 0, 25)}"
server_domain_zone = "${local.zone}"
server_add_domain = false
install_use_strategy = "${local.install_method}"
local_file_use_strategy = "${local.download}"
local_file_path = "${each.value.deploy_path}/configs"
@ -227,7 +221,7 @@ strcontains(each.value.type, "database") ? local.database_config :
}
# There are many ways to orchestrate Terraform configurations with the goal of breaking it down
# In this example I am using Terraform resources to orchestrate Terraform
# In this module I am using Terraform resources to orchestrate Terraform
# I felt this was the best way to accomplish the goal without incurring additional dependencies
module "deploy_additional_nodes" {
source = "../deploy"
@ -271,8 +265,7 @@ module "deploy_additional_nodes" {
user_workfolder = strcontains(each.value.os, "cis") ? "/var/tmp" : "/home/${local.username}"
timeout = 10
}))}"
server_domain_name = "${substr("${local.project_name}-${md5(each.key)}", 0, 25)}"
server_domain_zone = "${local.zone}"
server_add_domain = false
install_use_strategy = "${local.install_method}"
local_file_use_strategy = "${local.download}"
local_file_path = "${each.value.deploy_path}/configs"
@ -318,7 +311,7 @@ strcontains(each.value.type, "database") ? local.database_config :
EOT
}
resource "local_file" "kubeconfig" {
resource "local_sensitive_file" "kubeconfig" {
depends_on = [
module.deploy_initial_node,
module.deploy_additional_nodes,

View File

@ -28,7 +28,7 @@ variable "zone" {
# access
variable "key_name" {
type = string
description = "The name of an ssh key that already exists in AWS of that you want to create."
description = "The name of an ssh key that already exists in AWS."
}
variable "key" {
type = string
@ -112,10 +112,6 @@ variable "ip_family" {
type = string
description = "The IP family to use. Must be 'ipv4', 'ipv6', or 'dualstack'."
}
# variable "ingress_controller" {
# type = string
# description = "The ingress controller to use. Must be 'nginx' or 'traefik'. Currently only supports 'nginx'."
# }
variable "skip_cert_creation" {
type = bool
description = "Skip the generation of a certificate, useful when configuring cert manager."

View File

@ -3,7 +3,6 @@ variable "cert_manager_version" {
description = <<-EOT
The version of cert manager to install.
EOT
default = "v1.13.1"
}
variable "cert_manager_configuration" {
type = object({
@ -18,13 +17,7 @@ variable "cert_manager_configuration" {
https://cert-manager.io/docs/configuration/acme/dns01/route53/#ambient-credentials
https://docs.aws.amazon.com/sdkref/latest/guide/environment-variables.html
EOT
default = {
aws_region = ""
aws_session_token = ""
aws_access_key_id = ""
aws_secret_access_key = ""
}
sensitive = true
sensitive = true
}
variable "zone" {
type = string

View File

@ -30,13 +30,12 @@ module "deploy_cert_manager" {
KUBECONFIG = "${abspath(local.path)}/kubeconfig"
}
inputs = <<-EOT
cert_manager_version = "${local.cert_manager_version}"
project_cert_name = "${local.project_cert_name}"
project_cert_key_id = "${local.project_cert_key_id}"
project_domain = "${local.rancher_domain}"
zone = "${local.zone}"
zone_id = "${local.zone_id}"
project_cert_name = "${local.project_cert_name}"
project_cert_key_id = "${local.project_cert_key_id}"
cert_manager_version = "${local.cert_manager_version}"
configure_cert_manager = "${local.configure_cert_manager}"
cert_manager_configuration = {
aws_region = "${local.cert_manager_config.aws_region}"
aws_session_token = "${local.cert_manager_config.aws_session_token}"

View File

@ -3,19 +3,16 @@ variable "cert_manager_version" {
description = <<-EOT
The version of cert manager to install.
EOT
default = "v1.13.1"
}
variable "project_cert_key_id" {
type = string
description = <<-EOT
The key name to retrieve the project's cert's private key from AWS
EOT
default = ""
}
variable "project_cert_name" {
type = string
description = <<-EOT
The project's cert name
EOT
default = ""
}

View File

@ -45,7 +45,6 @@ variable "cert_manager_version" {
description = <<-EOT
The version of cert manager to install.
EOT
default = "v1.13.1"
}
variable "configure_cert_manager" {
type = bool
@ -75,14 +74,3 @@ variable "cert_manager_configuration" {
}
sensitive = true
}
# variable "backend_file" {
# type = string
# description = <<-EOT
# Path to a .tfbackend file.
# This allows the user to pass a backend file.
# The backend file will be added to the terraform run and will allow state data to be saved remotely.
# Please note that this is a separate state file, and this backend should be independent of the main module's state and any other submodules' states.
# See https://developer.hashicorp.com/terraform/language/backend#file for more information.
# EOT
# default = ""
# }

View File

@ -1,25 +0,0 @@
# !/bin/bash
set -e
# This script can compress text into smaller text or decompress that text back to its original form
# this requires: xz, openssl, jq, bash, and core linux utils (echo, redirection, pipe)
JSON_INPUT="$(jq -r '.')"
COMPRESS="$(jq -r '.compress' <<<"$JSON_INPUT")"
DECOMPRESS="$(jq -r '.decompress' <<<"$JSON_INPUT")"
DATA="$(jq -r '.contents' <<<"$JSON_INPUT")"
if [ -n "$COMPRESS" ] && [ "null" != "$COMPRESS" ]; then
ENCODED_OUTPUT="$(printf "%s" "$DATA" | xz -c -9 -e -T0 | openssl base64 -A -)"
fi
if [ -n "$DECOMPRESS" ] && [ "null" != "$DECOMPRESS" ]; then
ENCODED_OUTPUT="$(echo -n "$DATA" | openssl base64 -d -A | xz -dc | openssl base64 -A -)"
fi
if [ -z "$ENCODED_OUTPUT" ]; then
echo "output is empty" >&2
exit 1
fi
jq -n --arg data "$ENCODED_OUTPUT" '{"data": $data}'

View File

@ -42,7 +42,7 @@ resource "terraform_data" "snapshot" {
]
}
resource "local_file" "file" {
resource "local_sensitive_file" "file" {
depends_on = [
data.external.read_file,
terraform_data.recreate,

View File

@ -1,34 +0,0 @@
#!/bin/bash
set -e
INPUTS="$(jq -r '.')"
FILENAMEFILE="$(jq -r '.filename_file' <<<"$INPUTS")"
NEWFILE="$(jq -r '.filename' <<<"$INPUTS")"
if [ -z "$FILENAMEFILE" ]; then
echo "filename_file required" >&2
exit 1
fi
if [ -z "$NEWFILE" ]; then
echo "filename required" >&2
exit 1
fi
install -d "$(dirname "$FILENAMEFILE")"
touch "$FILENAMEFILE"
# grep returns 1 if the pattern isn't found, so we need to ignore the "failure" here
NEW="$(grep -l "$NEWFILE" "$FILENAMEFILE" || true)"
if [ -z "$NEW" ]; then
echo "$NEWFILE" >> "$FILENAMEFILE"
fi
while read -r FILEPATH; do
if [ -z "$FILEPATH" ]; then continue; fi # ignore empty lines
DIRECTORY="$(dirname "$FILEPATH")"
install -d "$DIRECTORY"
touch "$FILEPATH"
done < "$FILENAMEFILE"
jq -n '{"outcome": "success"}'

View File

@ -1,7 +1,4 @@
# output "encoded_contents" {
# value = base64encode(filesystem_file_writer.file.contents)
# }
output "contents" {
value = local_file.file.content #filesystem_file_writer.file.contents
value = local_sensitive_file.file.content
sensitive = true
}

View File

@ -1,4 +1,4 @@
# !/bin/bash
#!/bin/bash
set -e
JSON_INPUT="$(jq -r '.')"

View File

@ -16,6 +16,7 @@ variable "contents" {
The contents to persist, one of "contents" or "sourcefile" must be given.
EOT
default = ""
sensitive = true
}
variable "sourcefile" {
type = string
@ -23,4 +24,5 @@ variable "sourcefile" {
A file to persist, one of "contents" or "sourcefile" must be given.
EOT
default = ""
sensitive = true
}

View File

@ -3,17 +3,21 @@
# I felt this was the best way to accomplish the goal without incurring additional dependencies
locals {
project_domain = var.project_domain
zone_id = var.zone_id
region = var.region
email = var.email
acme_server_url = var.acme_server_url
rancher_version = replace(var.rancher_version, "v", "") # don't include the v
cert_manager_version = var.cert_manager_version
path = var.path
externalTLS = var.externalTLS
rancher_path = (local.externalTLS ? "${path.module}/rancher_externalTLS" : "${path.module}/rancher")
deploy_path = "${local.path}/rancher_bootstrap"
project_domain = var.project_domain
zone_id = var.zone_id
region = var.region
email = var.email
acme_server_url = var.acme_server_url
rancher_version = replace(var.rancher_version, "v", "") # don't include the v
rancher_helm_repo = var.rancher_helm_repo
rancher_helm_channel = var.rancher_helm_channel
cert_manager_version = var.cert_manager_version
path = var.path
externalTLS = var.externalTLS
rancher_path = (local.externalTLS ? "${path.module}/rancher_externalTLS" : "${path.module}/rancher")
deploy_path = "${local.path}/rancher_bootstrap"
rancher_helm_chart_values = var.rancher_helm_chart_values
rancher_helm_chart_use_strategy = var.rancher_helm_chart_use_strategy
}
module "deploy_rancher" {
@ -29,12 +33,16 @@ module "deploy_rancher" {
KUBE_CONFIG_PATH = "${local.path}/kubeconfig"
}
inputs = <<-EOT
project_domain = "${local.project_domain}"
zone_id = "${local.zone_id}"
region = "${local.region}"
email = "${local.email}"
rancher_version = "${local.rancher_version}"
cert_manager_version = "${local.cert_manager_version}"
acme_server_url = "${local.acme_server_url}"
project_domain = "${local.project_domain}"
rancher_version = "${local.rancher_version}"
rancher_helm_repo = "${local.rancher_helm_repo}"
rancher_helm_channel = "${local.rancher_helm_channel}"
rancher_helm_chart_use_strategy = "${local.rancher_helm_chart_use_strategy}"
rancher_helm_chart_values = "${base64encode(jsonencode(local.rancher_helm_chart_values))}"
zone_id = "${local.zone_id}"
region = "${local.region}"
email = "${local.email}"
cert_manager_version = "${local.cert_manager_version}"
acme_server_url = "${local.acme_server_url}"
EOT
}

View File

@ -1,44 +0,0 @@
#!/bin/bash
set -x
RANCHER_VERSION="$1"
if [ -z "$RANCHER_VERSION" ]; then echo "you must send the Rancher version"; exit 1; fi
if [ "${RANCHER_VERSION:0:1}" != "v" ]; then RANCHER_VERSION="v$RANCHER_VERSION"; fi
git clone https://github.com/rancher/rancher.git
cd rancher || exit 1
git checkout "$RANCHER_VERSION"
cd .. || exit 1
mv rancher/chart ./chart
mv rancher/build.yaml ./config.yaml
rm -rf rancher
mv chart rancher
VERSION="$RANCHER_VERSION"
CHART_VERSION="$(echo "$RANCHER_VERSION" | tr -d 'v')"
CONFIG="config.yaml"
CATTLE_DEFAULT_SHELL_VERSION=$(yq -r -e '.defaultShellVersion' "$CONFIG")
sed -i -e "s/%VERSION%/$CHART_VERSION/g" rancher/Chart.yaml
sed -i -e "s/%APP_VERSION%/$VERSION/g" rancher/Chart.yaml
post_delete_base="$CATTLE_DEFAULT_SHELL_VERSION"
post_delete_image_name=$(echo "$post_delete_base" | tr -d '"' | cut -d ":" -f 1) || true;
post_delete_image_tag=$(echo "$post_delete_base" | tr -d '"' | cut -d ":" -f 2) || true;
if [[ ! $post_delete_image_name =~ ^rancher\/.+ ]]; then
echo "The image name [$post_delete_image_name] is invalid. Its prefix should be rancher/"
exit 1
fi
if [[ ! $post_delete_image_tag =~ ^v.+ ]]; then
echo "The image tag [$post_delete_image_tag] is invalid. It should start with the letter v"
exit 1
fi
# image name has slashes in it and image tag has at symbols in it
sed -i -e "s@%POST_DELETE_IMAGE_NAME%@$post_delete_image_name@g" rancher/values.yaml
sed -i -e "s/%POST_DELETE_IMAGE_TAG%/$post_delete_image_tag/g" rancher/values.yaml
helm lint "$(pwd)/rancher"
helm package "$(pwd)/rancher"

View File

@ -9,7 +9,7 @@ locals {
rancher_helm_channel = var.rancher_helm_channel
rancher_version = replace(var.rancher_version, "v", "") # don't include the v
helm_chart_use_strategy = var.rancher_helm_chart_use_strategy
rancher_helm_chart_values = var.rancher_helm_chart_values
rancher_helm_chart_values = jsondecode(base64decode(var.rancher_helm_chart_values))
default_hc_values = {
"hostname" = local.rancher_domain
"replicas" = "1"
@ -185,6 +185,7 @@ resource "helm_release" "rancher" {
for_each = local.helm_chart_values
content {
name = set.key
type = "string"
value = set.value
}
}

View File

@ -11,6 +11,12 @@ variable "project_domain" {
error_message = "Must be a fully qualified domain name."
}
}
variable "rancher_version" {
type = string
description = <<-EOT
The version of rancher to install.
EOT
}
variable "rancher_helm_repo" {
type = string
description = <<-EOT
@ -38,27 +44,27 @@ variable "rancher_helm_chart_use_strategy" {
default = "default"
}
variable "rancher_helm_chart_values" {
type = map(any)
type = string
description = <<-EOT
A key/value map of Helm arguments to pass to the Rancher helm chart.
A base64 encoded, json encoded key/value map of Helm arguments to pass to the Rancher helm chart.
This will be ignored if the rancher_helm_chart_use_strategy argument is set to "default".
eg.
{
"hostname" = "test.example.com"
"replicas" = "1"
"bootstrapPassword" = "password"
"ingress.enabled" = "true"
"ingress.tls.source" = "letsEncrypt"
"tls" = "ingress"
"letsEncrypt.ingress.class" = "nginx"
"letsEncrypt.environment" = "production"
"letsEncrypt.email" = "test@example.com"
"certmanager.version" = "1.13.1"
"agentTLSMode" = "system-store"
"ingress.extraAnnotations.cert-manager\\.io\\/issuer" = "rancher"
"hostname" : "test.example.com",
"replicas" : "1",
"bootstrapPassword" : "password",
"ingress.enabled" : "true",
"ingress.tls.source" : "letsEncrypt",
"tls" : "ingress",
"letsEncrypt.ingress.class" : "nginx",
"letsEncrypt.environment" : "production",
"letsEncrypt.email" : "test@example.com",
"certmanager.version" : "1.13.1",
"agentTLSMode" : "system-store",
"ingress.extraAnnotations.cert-manager.io/issuer" : "rancher"
}
EOT
default = {}
default = "{}"
}
variable "zone_id" {
type = string
@ -80,13 +86,6 @@ variable "email" {
The email to use when registering an account with Let's Encrypt.
EOT
}
variable "rancher_version" {
type = string
description = <<-EOT
The version of rancher to install.
EOT
default = "2.11.2"
}
variable "cert_manager_version" {
type = string
description = <<-EOT

View File

@ -1,44 +0,0 @@
#!/bin/bash
set -x
RANCHER_VERSION="$1"
if [ -z "$RANCHER_VERSION" ]; then echo "you must send the Rancher version"; exit 1; fi
if [ "${RANCHER_VERSION:0:1}" != "v" ]; then RANCHER_VERSION="v$RANCHER_VERSION"; fi
git clone https://github.com/rancher/rancher.git
cd rancher || exit 1
git checkout "$RANCHER_VERSION"
cd .. || exit 1
mv rancher/chart ./chart
mv rancher/build.yaml ./config.yaml
rm -rf rancher
mv chart rancher
VERSION="$RANCHER_VERSION"
CHART_VERSION="$(echo "$RANCHER_VERSION" | tr -d 'v')"
CONFIG="config.yaml"
CATTLE_DEFAULT_SHELL_VERSION=$(yq -r -e '.defaultShellVersion' "$CONFIG")
sed -i -e "s/%VERSION%/$CHART_VERSION/g" rancher/Chart.yaml
sed -i -e "s/%APP_VERSION%/$VERSION/g" rancher/Chart.yaml
post_delete_base="$CATTLE_DEFAULT_SHELL_VERSION"
post_delete_image_name=$(echo "$post_delete_base" | tr -d '"' | cut -d ":" -f 1) || true;
post_delete_image_tag=$(echo "$post_delete_base" | tr -d '"' | cut -d ":" -f 2) || true;
if [[ ! $post_delete_image_name =~ ^rancher\/.+ ]]; then
echo "The image name [$post_delete_image_name] is invalid. Its prefix should be rancher/"
exit 1
fi
if [[ ! $post_delete_image_tag =~ ^v.+ ]]; then
echo "The image tag [$post_delete_image_tag] is invalid. It should start with the letter v"
exit 1
fi
# image name has slashes in it and image tag has at symbols in it
sed -i -e "s@%POST_DELETE_IMAGE_NAME%@$post_delete_image_name@g" rancher/values.yaml
sed -i -e "s/%POST_DELETE_IMAGE_TAG%/$post_delete_image_tag/g" rancher/values.yaml
helm lint "$(pwd)/rancher"
helm package "$(pwd)/rancher"

View File

@ -9,9 +9,9 @@ locals {
rancher_helm_channel = var.rancher_helm_channel
rancher_version = replace(var.rancher_version, "v", "") # don't include the v
helm_chart_use_strategy = var.rancher_helm_chart_use_strategy
rancher_helm_chart_values = var.rancher_helm_chart_values
rancher_helm_chart_values = jsondecode(base64decode(var.rancher_helm_chart_values))
default_hc_values = {
"hostname" = local.rancher_domain
"hostname" = local.rancher_domain # must be an fqdn
"replicas" = "1"
"bootstrapPassword" = "admin"
"ingress.enabled" = "true"
@ -21,10 +21,10 @@ locals {
"agentTLSMode" = "system-store"
}
helm_chart_values = coalesce( # using coalesce like this essentially gives us a switch function
(local.helm_chart_use_strategy == "merge" ?
merge(local.default_hc_values, local.rancher_helm_chart_values) : null),
(local.helm_chart_use_strategy == "default" ?
local.default_hc_values : null),
(local.helm_chart_use_strategy == "merge" ?
merge(local.default_hc_values, local.rancher_helm_chart_values) : null),
(local.helm_chart_use_strategy == "provide" ?
local.rancher_helm_chart_values : null)
) # WARNING! Some config is necessary, if the result is an empty string the coalesce will fail
@ -98,6 +98,7 @@ resource "helm_release" "rancher" {
for_each = local.helm_chart_values
content {
name = set.key
type = "string"
value = set.value
}
}
@ -149,39 +150,40 @@ resource "terraform_data" "get_public_cert_info" {
}
}
resource "terraform_data" "get_ping" {
depends_on = [
random_password.password,
time_sleep.settle_before_rancher,
terraform_data.wait_for_nginx,
helm_release.rancher,
terraform_data.wait_for_rancher,
terraform_data.get_public_cert_info,
]
provisioner "local-exec" {
command = <<-EOT
check_letsencrypt_ca() {
# Try to verify a known Let's Encrypt certificate (you can use any valid one)
if openssl s_client -showcerts -connect letsencrypt.org:443 < /dev/null | openssl x509 -noout -issuer | grep -q "Let's Encrypt"; then
return 0 # Success
else
return 1 # Failure
fi
}
echo "Checking Let's Encrypt CA"
if check_letsencrypt_ca; then
echo "Let's Encrypt CA is functioning correctly."
else
echo "Error: Let's Encrypt CA is not being used for verification."
exit 1
fi
echo "Checking Cert"
echo | openssl s_client -showcerts -servername ${local.rancher_domain} -connect "${local.rancher_domain}:443" 2>/dev/null | openssl x509 -inform pem -noout -text || true
echo "Checking Curl"
curl "https://${local.rancher_domain}/ping"
EOT
}
}
# this requires a let's encrypt certificate, which we would like to eventually not require
# resource "terraform_data" "get_ping" {
# depends_on = [
# random_password.password,
# time_sleep.settle_before_rancher,
# terraform_data.wait_for_nginx,
# helm_release.rancher,
# terraform_data.wait_for_rancher,
# terraform_data.get_public_cert_info,
# ]
# provisioner "local-exec" {
# command = <<-EOT
# check_letsencrypt_ca() {
# # Try to verify a known Let's Encrypt certificate (you can use any valid one)
# if openssl s_client -showcerts -connect letsencrypt.org:443 < /dev/null | openssl x509 -noout -issuer | grep -q "Let's Encrypt"; then
# return 0 # Success
# else
# return 1 # Failure
# fi
# }
# echo "Checking Let's Encrypt CA"
# if check_letsencrypt_ca; then
# echo "Let's Encrypt CA is functioning correctly."
# else
# echo "Error: Let's Encrypt CA is not being used for verification."
# exit 1
# fi
# echo "Checking Cert"
# echo | openssl s_client -showcerts -servername ${local.rancher_domain} -connect "${local.rancher_domain}:443" 2>/dev/null | openssl x509 -inform pem -noout -text || true
# echo "Checking Curl"
# curl "https://${local.rancher_domain}/ping"
# EOT
# }
# }
resource "rancher2_bootstrap" "admin" {
depends_on = [
@ -191,7 +193,7 @@ resource "rancher2_bootstrap" "admin" {
helm_release.rancher,
terraform_data.wait_for_rancher,
terraform_data.get_public_cert_info,
terraform_data.get_ping,
# terraform_data.get_ping,
]
password = random_password.password.result
}

View File

@ -45,21 +45,21 @@ variable "rancher_helm_chart_use_strategy" {
default = "default"
}
variable "rancher_helm_chart_values" {
type = map(any)
type = string
description = <<-EOT
A key/value map of Helm arguments to pass to the Rancher helm chart.
A base64 encoded, json encoded key/value map of Helm arguments to pass to the Rancher helm chart.
This will be ignored if the rancher_helm_chart_use_strategy argument is set to "default".
eg.
{
"hostname" = local.rancher_domain
"replicas" = "1"
"bootstrapPassword" = "admin"
"ingress.enabled" = "true"
"ingress.tls.source" = "secret"
"ingress.tls.secretName" = "tls-rancher-ingress"
"privateCA" = "true"
"agentTLSMode" = "system-store"
"hostname" : "rancher.example.com",
"replicas" : "1",
"bootstrapPassword" : "admin",
"ingress.enabled" : "true",
"ingress.tls.source" : "secret",
"ingress.tls.secretName" : "tls-rancher-ingress",
"privateCA" : "true",
"agentTLSMode" : "system-store"
}
EOT
default = {}
default = "{}"
}

View File

@ -45,6 +45,21 @@ variable "rancher_version" {
EOT
default = "2.11.2"
}
variable "rancher_helm_repo" {
type = string
description = <<-EOT
The Helm repository to retrieve charts from.
EOT
default = "https://releases.rancher.com/server-charts"
}
variable "rancher_helm_channel" {
type = string
description = <<-EOT
The Helm repository channel retrieve charts from.
Can be "latest" or "stable", defaults to "stable".
EOT
default = "stable"
}
variable "cert_manager_version" {
type = string
description = <<-EOT
@ -66,3 +81,37 @@ variable "path" {
The local file path to stage files for the deployment.
EOT
}
variable "rancher_helm_chart_use_strategy" {
type = string
description = <<-EOT
The strategy to use for Rancher's Helm chart values.
Options include: "default", "merge", or "provide".
Default will tell the module to use our suggested default configuration.
Merge will merge our default suggestions with your supplied configuration, anything you supply will override the default.
Provide will ignore our default suggestions and use the configuration provided in the rancher_helm_chart_values argument.
EOT
default = "default"
validation {
condition = contains(["default", "merge", "provide"], var.rancher_helm_chart_use_strategy)
error_message = "Must be one of 'default', 'merge', or 'provide'."
}
}
variable "rancher_helm_chart_values" {
type = map(any)
description = <<-EOT
A key/value map of Helm arguments to pass to the Rancher helm chart.
This will be ignored if the rancher_helm_chart_use_strategy argument is set to "default".
eg.
{
"hostname" = local.rancher_domain
"replicas" = "1"
"bootstrapPassword" = "admin"
"ingress.enabled" = "true"
"ingress.tls.source" = "secret"
"ingress.tls.secretName" = "tls-rancher-ingress"
"privateCA" = "true"
"agentTLSMode" = "system-store"
}
EOT
default = {}
}

View File

@ -20,16 +20,6 @@ output "admin_password" {
sensitive = true
}
# output "additional_node_states" {
# value = module.cluster.additional_node_states
# sensitive = true
# }
# output "rancher_bootstrap_state" {
# value = module.rancher_bootstrap[0].rancher_bootstrap_state
# sensitive = true
# }
output "vpc" {
value = module.cluster.vpc
}

View File

@ -27,7 +27,6 @@ variable "domain" {
If left empty this will default to the project name.
eg. "test" in "test.example.com"
EOT
default = ""
}
variable "zone" {
type = string
@ -150,14 +149,45 @@ variable "cert_manager_version" {
description = <<-EOT
The version of cert-manager to install.
EOT
default = "v1.18.1" # "v1.13.1"
default = "v1.18.1" # "v1.13.1" # "1.16.3"
}
variable "tls_cert_name" {
type = string
description = <<-EOT
The name of an AWS IAM Server Certificate where the public cert is stored.
This is only used when supplying your own TLS certificate.
EOT
default = ""
}
variable "tls_cert_key" {
type = string
description = <<-EOT
The name of an AWS SecretsManager Secret where the private key is stored.
This is only used when supplying your own TLS certificate.
EOT
default = ""
}
variable "rancher_version" {
type = string
description = <<-EOT
The version of Rancher to install.
The version of rancher to install.
EOT
default = "2.9.1"
default = "2.11.2"
}
variable "rancher_helm_repo" {
type = string
description = <<-EOT
The Helm repository to retrieve charts from.
EOT
default = "https://releases.rancher.com/server-charts"
}
variable "rancher_helm_channel" {
type = string
description = <<-EOT
The Helm repository channel retrieve charts from.
Can be "latest" or "stable", defaults to "stable".
EOT
default = "stable"
}
variable "bootstrap_rancher" {
type = bool
@ -209,27 +239,37 @@ variable "cert_manager_configuration" {
}
sensitive = true
}
# variable "install_cert_manager_backend" {
# type = string
# description = <<-EOT
# Path to a .tfbackend file.
# This allows the user to pass a backend file to the install_cert_manager submodule.
# The backend file will be added to the submodule's terraform run and will allow that module's state data to be saved remotely.
# Please note that this is a separate state file, and this backend should be independent of the main module's state and any other submodules' states.
# See https://developer.hashicorp.com/terraform/language/backend#file for more information.
# The default is to use a local state file.
# EOT
# default = ""
# }
# variable "rancher_bootstrap_backend" {
# type = string
# description = <<-EOT
# Path to a .tfbackend file.
# This allows the user to pass a backend file to the rancher_bootstrap submodule.
# The backend file will be added to the submodule's terraform run and will allow that module's state data to be saved remotely.
# Please note that this is a separate state file, and this backend should be independent of the main module's state and any other submodules' states.
# See https://developer.hashicorp.com/terraform/language/backend#file for more information.
# The default is to use a local state file.
# EOT
# default = ""
# }
variable "rancher_helm_chart_use_strategy" {
type = string
description = <<-EOT
The strategy to use for Rancher's Helm chart values.
Options include: "default", "merge", or "provide".
Default will tell the module to use our suggested default configuration.
Merge will merge our default suggestions with your supplied configuration, anything you supply will override the default.
Provide will ignore our default suggestions and use the configuration provided in the rancher_helm_chart_values argument.
EOT
default = "default"
validation {
condition = contains(["default", "merge", "provide"], var.rancher_helm_chart_use_strategy)
error_message = "Must be one of 'default', 'merge', or 'provide'."
}
}
variable "rancher_helm_chart_values" {
type = map(any)
description = <<-EOT
A key/value map of Helm arguments to pass to the Rancher helm chart.
This will be ignored if the rancher_helm_chart_use_strategy argument is set to "default".
eg.
{
"hostname" = local.rancher_domain
"replicas" = "1"
"bootstrapPassword" = "admin"
"ingress.enabled" = "true"
"ingress.tls.source" = "secret"
"ingress.tls.secretName" = "tls-rancher-ingress"
"privateCA" = "true"
"agentTLSMode" = "system-store"
}
EOT
default = {}
}