diff --git a/terraform/cluster-templates-tf/cluster_profiles.tf b/terraform/cluster-templates-tf/cluster_profiles.tf new file mode 100644 index 0000000..4fb7eba --- /dev/null +++ b/terraform/cluster-templates-tf/cluster_profiles.tf @@ -0,0 +1,265 @@ +resource "spectrocloud_cluster_profile" "aws_profile" { + count = var.deploy-aws ? 1 : 0 + + name = "tf-cluster-template-profile-aws" + description = "Cluster profile for the cluster templates tutorial" + cloud = "aws" + type = "cluster" + version = "1.0.0" + + pack { + name = data.spectrocloud_pack.aws_ubuntu.name + tag = data.spectrocloud_pack.aws_ubuntu.version + uid = data.spectrocloud_pack.aws_ubuntu.id + values = data.spectrocloud_pack.aws_ubuntu.values + type = "spectro" + } + + pack { + name = data.spectrocloud_pack.aws_k8s.name + tag = data.spectrocloud_pack.aws_k8s.version + uid = data.spectrocloud_pack.aws_k8s.id + values = data.spectrocloud_pack.aws_k8s.values + type = "spectro" + } + + pack { + name = data.spectrocloud_pack.aws_cni.name + tag = data.spectrocloud_pack.aws_cni.version + uid = data.spectrocloud_pack.aws_cni.id + values = data.spectrocloud_pack.aws_cni.values + type = "spectro" + } + + pack { + name = data.spectrocloud_pack.aws_csi.name + tag = data.spectrocloud_pack.aws_csi.version + uid = data.spectrocloud_pack.aws_csi.id + values = data.spectrocloud_pack.aws_csi.values + type = "spectro" + } + + pack { + name = data.spectrocloud_pack.hellouniverse.name + tag = data.spectrocloud_pack.hellouniverse.version + uid = data.spectrocloud_pack.hellouniverse.id + values = templatefile("manifests/values-hello-universe.yaml", { + port = var.app_port + }) + type = "oci" + } + + profile_variables { + variable { + name = "app_replicas" + display_name = "Hello Universe Replicas" + format = "number" + description = "Number of replicas for the hello-universe workload" + default_value = "1" + required = true + } + } +} + +resource "spectrocloud_cluster_profile" "azure_profile" { + count = var.deploy-azure ? 1 : 0 + + name = "tf-cluster-template-profile-azure" + description = "Cluster profile for the cluster templates tutorial" + cloud = "azure" + type = "cluster" + version = "1.0.0" + + pack { + name = data.spectrocloud_pack.azure_ubuntu.name + tag = data.spectrocloud_pack.azure_ubuntu.version + uid = data.spectrocloud_pack.azure_ubuntu.id + values = data.spectrocloud_pack.azure_ubuntu.values + type = "spectro" + } + + pack { + name = data.spectrocloud_pack.azure_k8s.name + tag = data.spectrocloud_pack.azure_k8s.version + uid = data.spectrocloud_pack.azure_k8s.id + values = data.spectrocloud_pack.azure_k8s.values + type = "spectro" + } + + pack { + name = data.spectrocloud_pack.azure_cni.name + tag = data.spectrocloud_pack.azure_cni.version + uid = data.spectrocloud_pack.azure_cni.id + values = data.spectrocloud_pack.azure_cni.values + type = "spectro" + } + + pack { + name = data.spectrocloud_pack.azure_csi.name + tag = data.spectrocloud_pack.azure_csi.version + uid = data.spectrocloud_pack.azure_csi.id + values = data.spectrocloud_pack.azure_csi.values + type = "spectro" + } + + pack { + name = data.spectrocloud_pack.hellouniverse.name + tag = data.spectrocloud_pack.hellouniverse.version + uid = data.spectrocloud_pack.hellouniverse.id + values = templatefile("manifests/values-hello-universe.yaml", { + port = var.app_port + }) + type = "oci" + } + + profile_variables { + variable { + name = "app_replicas" + display_name = "Hello Universe Replicas" + format = "number" + description = "Number of replicas for the hello-universe workload" + default_value = "1" + required = true + } + } +} + +resource "spectrocloud_cluster_profile" "aws_profile_v110" { + count = (var.deploy-aws && var.create_new_profile_version) ? 1 : 0 + + name = "tf-cluster-template-profile-aws" + description = "Cluster profile for the cluster templates tutorial" + cloud = "aws" + type = "cluster" + version = "1.1.0" + + pack { + name = data.spectrocloud_pack.aws_ubuntu.name + tag = data.spectrocloud_pack.aws_ubuntu.version + uid = data.spectrocloud_pack.aws_ubuntu.id + values = data.spectrocloud_pack.aws_ubuntu.values + type = "spectro" + } + + pack { + name = data.spectrocloud_pack.aws_k8s.name + tag = data.spectrocloud_pack.aws_k8s.version + uid = data.spectrocloud_pack.aws_k8s.id + values = data.spectrocloud_pack.aws_k8s.values + type = "spectro" + } + + pack { + name = data.spectrocloud_pack.aws_cni.name + tag = data.spectrocloud_pack.aws_cni.version + uid = data.spectrocloud_pack.aws_cni.id + values = data.spectrocloud_pack.aws_cni.values + type = "spectro" + } + + pack { + name = data.spectrocloud_pack.aws_csi.name + tag = data.spectrocloud_pack.aws_csi.version + uid = data.spectrocloud_pack.aws_csi.id + values = data.spectrocloud_pack.aws_csi.values + type = "spectro" + } + + pack { + name = data.spectrocloud_pack.hellouniverse.name + tag = data.spectrocloud_pack.hellouniverse.version + uid = data.spectrocloud_pack.hellouniverse.id + values = templatefile("manifests/values-hello-universe.yaml", { + port = var.app_port + }) + type = "oci" + } + + pack { + name = data.spectrocloud_pack.kubecost[0].name + tag = data.spectrocloud_pack.kubecost[0].version + uid = data.spectrocloud_pack.kubecost[0].id + type = "oci" + } + + profile_variables { + variable { + name = "app_replicas" + display_name = "Hello Universe Replicas" + format = "number" + description = "Number of replicas for the hello-universe workload" + default_value = "1" + required = true + } + } +} + +resource "spectrocloud_cluster_profile" "azure_profile_v110" { + count = (var.deploy-azure && var.create_new_profile_version) ? 1 : 0 + + name = "tf-cluster-template-profile-azure" + description = "Cluster profile for the cluster templates tutorial" + cloud = "azure" + type = "cluster" + version = "1.1.0" + + pack { + name = data.spectrocloud_pack.azure_ubuntu.name + tag = data.spectrocloud_pack.azure_ubuntu.version + uid = data.spectrocloud_pack.azure_ubuntu.id + values = data.spectrocloud_pack.azure_ubuntu.values + type = "spectro" + } + + pack { + name = data.spectrocloud_pack.azure_k8s.name + tag = data.spectrocloud_pack.azure_k8s.version + uid = data.spectrocloud_pack.azure_k8s.id + values = data.spectrocloud_pack.azure_k8s.values + type = "spectro" + } + + pack { + name = data.spectrocloud_pack.azure_cni.name + tag = data.spectrocloud_pack.azure_cni.version + uid = data.spectrocloud_pack.azure_cni.id + values = data.spectrocloud_pack.azure_cni.values + type = "spectro" + } + + pack { + name = data.spectrocloud_pack.azure_csi.name + tag = data.spectrocloud_pack.azure_csi.version + uid = data.spectrocloud_pack.azure_csi.id + values = data.spectrocloud_pack.azure_csi.values + type = "spectro" + } + + pack { + name = data.spectrocloud_pack.hellouniverse.name + tag = data.spectrocloud_pack.hellouniverse.version + uid = data.spectrocloud_pack.hellouniverse.id + values = templatefile("manifests/values-hello-universe.yaml", { + port = var.app_port + }) + type = "oci" + } + + pack { + name = data.spectrocloud_pack.kubecost[0].name + tag = data.spectrocloud_pack.kubecost[0].version + uid = data.spectrocloud_pack.kubecost[0].id + type = "oci" + } + + profile_variables { + variable { + name = "app_replicas" + display_name = "Hello Universe Replicas" + format = "number" + description = "Number of replicas for the hello-universe workload" + default_value = "1" + required = true + } + } +} diff --git a/terraform/cluster-templates-tf/cluster_templates.tf b/terraform/cluster-templates-tf/cluster_templates.tf new file mode 100644 index 0000000..9e77159 --- /dev/null +++ b/terraform/cluster-templates-tf/cluster_templates.tf @@ -0,0 +1,37 @@ +resource "spectrocloud_cluster_config_template" "aws_template" { + count = var.deploy-aws ? 1 : 0 + + name = "tf-cluster-template-aws" + cloud_type = "aws" + context = "project" + + cluster_profile { + id = (var.create_new_profile_version && var.update_template_profile_version) ? spectrocloud_cluster_profile.aws_profile_v110[0].id : spectrocloud_cluster_profile.aws_profile[0].id + } + + policy { + id = spectrocloud_cluster_config_policy.maintenance.id + kind = "maintenance" + } + + upgrade_now = var.upgrade_now_timestamp != "" ? var.upgrade_now_timestamp : null +} + +resource "spectrocloud_cluster_config_template" "azure_template" { + count = var.deploy-azure ? 1 : 0 + + name = "tf-cluster-template-azure" + cloud_type = "azure" + context = "project" + + cluster_profile { + id = (var.create_new_profile_version && var.update_template_profile_version) ? spectrocloud_cluster_profile.azure_profile_v110[0].id : spectrocloud_cluster_profile.azure_profile[0].id + } + + policy { + id = spectrocloud_cluster_config_policy.maintenance.id + kind = "maintenance" + } + + upgrade_now = var.upgrade_now_timestamp != "" ? var.upgrade_now_timestamp : null +} diff --git a/terraform/cluster-templates-tf/clusters.tf b/terraform/cluster-templates-tf/clusters.tf new file mode 100644 index 0000000..3de56ef --- /dev/null +++ b/terraform/cluster-templates-tf/clusters.tf @@ -0,0 +1,215 @@ +############# +# AWS Cluster +############# + +resource "spectrocloud_cluster_aws" "dev_cluster" { + count = var.deploy-aws ? 1 : 0 + + name = "tf-dev-cluster" + cluster_timezone = "UTC" + cloud_account_id = data.spectrocloud_cloudaccount_aws.account[0].id + + cloud_config { + region = var.aws-region + ssh_key_name = var.aws-key-pair-name + } + + cluster_template { + id = spectrocloud_cluster_config_template.aws_template[0].id + + cluster_profile { + id = spectrocloud_cluster_profile.aws_profile[0].id + variables = { + "app_replicas" = "1" + } + } + } + + machine_pool { + control_plane = true + control_plane_as_worker = true + name = "control-plane-pool" + count = var.aws_control_plane_nodes.count + instance_type = var.aws_control_plane_nodes.instance_type + disk_size_gb = var.aws_control_plane_nodes.disk_size_gb + azs = var.aws_control_plane_nodes.availability_zones + } + + machine_pool { + name = "worker-pool" + count = var.aws_worker_nodes.count + instance_type = var.aws_worker_nodes.instance_type + disk_size_gb = var.aws_worker_nodes.disk_size_gb + azs = var.aws_worker_nodes.availability_zones + } + + timeouts { + create = "60m" + delete = "60m" + } +} + +################ +# AWS Prod Cluster +################ + +resource "spectrocloud_cluster_aws" "prod_cluster" { + count = var.deploy-aws ? 1 : 0 + + name = "tf-prod-cluster" + cluster_timezone = "UTC" + cloud_account_id = data.spectrocloud_cloudaccount_aws.account[0].id + + cloud_config { + region = var.aws-region + ssh_key_name = var.aws-key-pair-name + } + + cluster_template { + id = spectrocloud_cluster_config_template.aws_template[0].id + + cluster_profile { + id = spectrocloud_cluster_profile.aws_profile[0].id + variables = { + "app_replicas" = "2" + } + } + } + + machine_pool { + control_plane = true + control_plane_as_worker = true + name = "control-plane-pool" + count = var.aws_control_plane_nodes.count + instance_type = var.aws_control_plane_nodes.instance_type + disk_size_gb = var.aws_control_plane_nodes.disk_size_gb + azs = var.aws_control_plane_nodes.availability_zones + } + + machine_pool { + name = "worker-pool" + count = var.aws_worker_nodes.count + instance_type = var.aws_worker_nodes.instance_type + disk_size_gb = var.aws_worker_nodes.disk_size_gb + azs = var.aws_worker_nodes.availability_zones + } + + timeouts { + create = "60m" + delete = "60m" + } +} + +################# +# Azure Cluster +################# + +resource "spectrocloud_cluster_azure" "dev_cluster" { + count = var.deploy-azure ? 1 : 0 + + name = "tf-dev-cluster-azure" + cluster_timezone = "UTC" + cloud_account_id = data.spectrocloud_cloudaccount_azure.account[0].id + + cloud_config { + subscription_id = var.azure_subscription_id + resource_group = var.azure_resource_group + region = var.azure-region + ssh_key = tls_private_key.tutorial_ssh_key_azure[0].public_key_openssh + } + + cluster_template { + id = spectrocloud_cluster_config_template.azure_template[0].id + + cluster_profile { + id = spectrocloud_cluster_profile.azure_profile[0].id + variables = { + "app_replicas" = "1" + } + } + } + + machine_pool { + control_plane = true + control_plane_as_worker = true + name = "control-plane-pool" + count = var.azure_control_plane_nodes.count + instance_type = var.azure_control_plane_nodes.instance_type + azs = var.azure-use-azs ? var.azure_control_plane_nodes.azs : [""] + is_system_node_pool = var.azure_control_plane_nodes.is_system_node_pool + disk { + size_gb = var.azure_control_plane_nodes.disk_size_gb + type = "Standard_LRS" + } + } + + machine_pool { + name = "worker-pool" + count = var.azure_worker_nodes.count + instance_type = var.azure_worker_nodes.instance_type + azs = var.azure-use-azs ? var.azure_worker_nodes.azs : [""] + is_system_node_pool = var.azure_worker_nodes.is_system_node_pool + } + + timeouts { + create = "60m" + delete = "60m" + } +} + +#################### +# Azure Prod Cluster +#################### + +resource "spectrocloud_cluster_azure" "prod_cluster" { + count = var.deploy-azure ? 1 : 0 + + name = "tf-prod-cluster-azure" + cluster_timezone = "UTC" + cloud_account_id = data.spectrocloud_cloudaccount_azure.account[0].id + + cloud_config { + subscription_id = var.azure_subscription_id + resource_group = var.azure_resource_group + region = var.azure-region + ssh_key = tls_private_key.tutorial_ssh_key_azure[0].public_key_openssh + } + + cluster_template { + id = spectrocloud_cluster_config_template.azure_template[0].id + + cluster_profile { + id = spectrocloud_cluster_profile.azure_profile[0].id + variables = { + "app_replicas" = "2" + } + } + } + + machine_pool { + control_plane = true + control_plane_as_worker = true + name = "control-plane-pool" + count = var.azure_control_plane_nodes.count + instance_type = var.azure_control_plane_nodes.instance_type + azs = var.azure-use-azs ? var.azure_control_plane_nodes.azs : [""] + is_system_node_pool = var.azure_control_plane_nodes.is_system_node_pool + disk { + size_gb = var.azure_control_plane_nodes.disk_size_gb + type = "Standard_LRS" + } + } + + machine_pool { + name = "worker-pool" + count = var.azure_worker_nodes.count + instance_type = var.azure_worker_nodes.instance_type + azs = var.azure-use-azs ? var.azure_worker_nodes.azs : [""] + is_system_node_pool = var.azure_worker_nodes.is_system_node_pool + } + + timeouts { + create = "60m" + delete = "60m" + } +} diff --git a/terraform/cluster-templates-tf/data.tf b/terraform/cluster-templates-tf/data.tf new file mode 100644 index 0000000..110b442 --- /dev/null +++ b/terraform/cluster-templates-tf/data.tf @@ -0,0 +1,105 @@ +# Copyright (c) Spectro Cloud +# SPDX-License-Identifier: Apache-2.0 + +######################################## +# Data resources for the cluster profile +######################################## + +data "spectrocloud_project" "current" { + name = var.palette-project +} + +data "spectrocloud_registry" "public_registry" { + name = "Public Repo" +} + +data "spectrocloud_registry" "community_registry" { + name = "Palette Community Registry" +} + +############# +# AWS +############# + +data "spectrocloud_cloudaccount_aws" "account" { + count = var.deploy-aws ? 1 : 0 + name = var.aws-cloud-account-name +} + +data "spectrocloud_pack" "aws_ubuntu" { + name = "ubuntu-aws" + version = "22.04" + registry_uid = data.spectrocloud_registry.public_registry.id +} + +data "spectrocloud_pack" "aws_k8s" { + name = "kubernetes" + version = "1.35.2" + registry_uid = data.spectrocloud_registry.public_registry.id +} + +data "spectrocloud_pack" "aws_cni" { + name = "cni-calico" + version = "3.31.4" + registry_uid = data.spectrocloud_registry.public_registry.id +} + +data "spectrocloud_pack" "aws_csi" { + name = "csi-aws-ebs" + version = "1.59.0" + registry_uid = data.spectrocloud_registry.public_registry.id +} + +############# +# Azure +############# + +data "spectrocloud_cloudaccount_azure" "account" { + count = var.deploy-azure ? 1 : 0 + name = var.azure-cloud-account-name +} + +data "spectrocloud_pack" "azure_ubuntu" { + name = "ubuntu-azure" + version = "22.04" + registry_uid = data.spectrocloud_registry.public_registry.id +} + +data "spectrocloud_pack" "azure_k8s" { + name = "kubernetes" + version = "1.35.2" + registry_uid = data.spectrocloud_registry.public_registry.id +} + +data "spectrocloud_pack" "azure_cni" { + name = "cni-calico-azure" + version = "3.31.4" + registry_uid = data.spectrocloud_registry.public_registry.id +} + +data "spectrocloud_pack" "azure_csi" { + name = "csi-azure" + version = "1.34.2" + registry_uid = data.spectrocloud_registry.public_registry.id +} + +##################### +# Hello Universe Pack +##################### + +data "spectrocloud_pack" "hellouniverse" { + name = "hello-universe" + version = "1.3.0" + registry_uid = data.spectrocloud_registry.community_registry.id +} + +########### +# Kubecost +########### + +data "spectrocloud_pack" "kubecost" { + count = var.create_new_profile_version ? 1 : 0 + name = "cost-analyzer" + version = "1.103.3" + registry_uid = data.spectrocloud_registry.community_registry.id +} diff --git a/terraform/cluster-templates-tf/inputs.tf b/terraform/cluster-templates-tf/inputs.tf new file mode 100644 index 0000000..9434c52 --- /dev/null +++ b/terraform/cluster-templates-tf/inputs.tf @@ -0,0 +1,224 @@ +######### +# Palette +######### + +variable "palette-project" { + description = "Palette project name" + type = string + + validation { + condition = var.palette-project != "" + error_message = "Provide the correct Palette project." + } +} + +##################### +# Hello Universe +##################### + +variable "app_port" { + type = number + description = "The cluster port number on which the service will listen for incoming traffic." +} + +variable "create_new_profile_version" { + type = bool + description = "Create cluster profile version 1.1.0 with Kubecost added. Set to true after the initial clusters are deployed." + default = false +} + +variable "update_template_profile_version" { + type = bool + description = "Update the cluster template to reference cluster profile version 1.1.0. Requires create_new_profile_version to be true and already applied." + default = false +} + +variable "upgrade_now_timestamp" { + type = string + description = "RFC3339 timestamp that triggers an immediate upgrade on all template clusters when changed. Set a new timestamp to re-trigger the upgrade. Leave empty to skip." + default = "" +} + +####### +# AWS +####### + +variable "aws-cloud-account-name" { + type = string + description = "The name of your AWS account as assigned in Palette." + + validation { + condition = var.deploy-aws ? var.aws-cloud-account-name != "REPLACE ME" && var.aws-cloud-account-name != "" : true + error_message = "Provide the correct AWS cloud account name." + } +} + +variable "deploy-aws" { + type = bool + description = "A flag for enabling a deployment on AWS." +} + +variable "aws-region" { + type = string + description = "AWS region." + default = "us-east-1" + + validation { + condition = var.deploy-aws ? var.aws-region != "REPLACE ME" && var.aws-region != "" : true + error_message = "Provide the correct AWS region." + } +} + +variable "aws-key-pair-name" { + type = string + description = "The name of the AWS key pair to use for SSH access to the cluster." + + validation { + condition = var.deploy-aws ? var.aws-key-pair-name != "REPLACE ME" && var.aws-key-pair-name != "" : true + error_message = "Provide the correct AWS SSH key pair name." + } +} + +variable "aws_control_plane_nodes" { + type = object({ + count = string + control_plane = bool + instance_type = string + disk_size_gb = string + availability_zones = list(string) + }) + default = { + count = "1" + control_plane = true + instance_type = "m4.2xlarge" + disk_size_gb = "60" + availability_zones = ["us-east-1a"] + } + description = "AWS control plane nodes configuration." + + validation { + condition = var.deploy-aws ? length(var.aws_control_plane_nodes.availability_zones) > 0 && !contains(var.aws_control_plane_nodes.availability_zones, "REPLACE ME") : true + error_message = "The availability_zones parameter must be set correctly" + } +} + +variable "aws_worker_nodes" { + type = object({ + count = string + control_plane = bool + instance_type = string + disk_size_gb = string + availability_zones = list(string) + }) + default = { + count = "1" + control_plane = false + instance_type = "m4.2xlarge" + disk_size_gb = "60" + availability_zones = ["us-east-1a"] + } + description = "AWS worker nodes configuration." + + validation { + condition = var.deploy-aws ? length(var.aws_worker_nodes.availability_zones) > 0 && !contains(var.aws_worker_nodes.availability_zones, "REPLACE ME") : true + error_message = "The availability_zones parameter must be set correctly" + } +} + +######### +# Azure +######### + +variable "azure-cloud-account-name" { + type = string + description = "The name of your Azure account as assigned in Palette." + default = "" + + validation { + condition = var.deploy-azure ? var.azure-cloud-account-name != "REPLACE ME" && var.azure-cloud-account-name != "" : true + error_message = "Provide the correct Azure cloud account name." + } +} + +variable "deploy-azure" { + type = bool + description = "A flag for enabling a deployment on Azure." +} + +variable "azure_subscription_id" { + type = string + description = "Azure subscription ID." + default = "" + + validation { + condition = var.deploy-azure ? var.azure_subscription_id != "REPLACE ME" && var.azure_subscription_id != "" : true + error_message = "Provide the correct Azure subscription ID." + } +} + +variable "azure_resource_group" { + type = string + description = "Azure resource group." + default = "" + + validation { + condition = var.deploy-azure ? var.azure_resource_group != "REPLACE ME" && var.azure_resource_group != "" : true + error_message = "Provide the correct Azure resource group name." + } +} + +variable "azure-use-azs" { + type = bool + description = "A flag for configuring whether to use Azure Availability Zones. Check if your Azure region supports availability zones by reviewing the [Azure Regions and Availability Zones](https://learn.microsoft.com/en-us/azure/reliability/availability-zones-service-support#azure-regions-with-availability-zone-support) resource." +} + +variable "azure-region" { + type = string + description = "Azure region." + default = "eastus" + + validation { + condition = var.deploy-azure ? var.azure-region != "REPLACE ME" && var.azure-region != "" : true + error_message = "Provide the correct Azure region name." + } +} + +variable "azure_control_plane_nodes" { + type = object({ + count = string + control_plane = bool + instance_type = string + disk_size_gb = string + azs = list(string) + is_system_node_pool = bool + }) + default = { + count = "1" + control_plane = true + instance_type = "Standard_D4s_v5" + disk_size_gb = "60" + azs = ["1"] + is_system_node_pool = false + } + description = "Azure control plane nodes configuration." +} + +variable "azure_worker_nodes" { + type = object({ + count = string + control_plane = bool + instance_type = string + disk_size_gb = string + azs = list(string) + is_system_node_pool = bool + }) + default = { + count = "1" + control_plane = false + instance_type = "Standard_D4s_v5" + disk_size_gb = "60" + azs = ["1"] + is_system_node_pool = false + } + description = "Azure worker nodes configuration." +} diff --git a/terraform/cluster-templates-tf/maintenance_policy.tf b/terraform/cluster-templates-tf/maintenance_policy.tf new file mode 100644 index 0000000..c8b5f5f --- /dev/null +++ b/terraform/cluster-templates-tf/maintenance_policy.tf @@ -0,0 +1,10 @@ +resource "spectrocloud_cluster_config_policy" "maintenance" { + name = "tf-maintenance-policy" + context = "project" + + schedules { + name = "weekly-sunday" + start_cron = "0 0 * * SUN" + duration_hrs = 4 + } +} diff --git a/terraform/cluster-templates-tf/manifests/values-hello-universe.yaml b/terraform/cluster-templates-tf/manifests/values-hello-universe.yaml new file mode 100644 index 0000000..8b29dc2 --- /dev/null +++ b/terraform/cluster-templates-tf/manifests/values-hello-universe.yaml @@ -0,0 +1,13 @@ +pack: + content: + images: + - image: ghcr.io/spectrocloud/hello-universe:1.3.0 + +manifests: + hello-universe: + images: + hellouniverse: ghcr.io/spectrocloud/hello-universe:1.3.0 + apiEnabled: false + namespace: hello-universe + port: ${port} + replicas: "{{.spectro.var.app_replicas}}" diff --git a/terraform/cluster-templates-tf/provider.tf b/terraform/cluster-templates-tf/provider.tf new file mode 100644 index 0000000..58ea8f5 --- /dev/null +++ b/terraform/cluster-templates-tf/provider.tf @@ -0,0 +1,21 @@ +terraform { + required_providers { + spectrocloud = { + version = "0.29.1" + source = "spectrocloud/spectrocloud" + } + + tls = { + source = "hashicorp/tls" + version = "4.0.4" + } + } + + required_version = ">= 1.9" +} + + +provider "spectrocloud" { + # API key set through the environment variable SPECTROCLOUD_APIKEY + project_name = var.palette-project +} diff --git a/terraform/cluster-templates-tf/ssh-key.tf b/terraform/cluster-templates-tf/ssh-key.tf new file mode 100644 index 0000000..bd8840e --- /dev/null +++ b/terraform/cluster-templates-tf/ssh-key.tf @@ -0,0 +1,9 @@ +############### +# Azure SSH Key +############### + +resource "tls_private_key" "tutorial_ssh_key_azure" { + count = var.deploy-azure ? 1 : 0 + algorithm = "RSA" + rsa_bits = "4096" +} diff --git a/terraform/cluster-templates-tf/terraform.tfvars b/terraform/cluster-templates-tf/terraform.tfvars new file mode 100644 index 0000000..efcd3ce --- /dev/null +++ b/terraform/cluster-templates-tf/terraform.tfvars @@ -0,0 +1,69 @@ +##################### +# Palette Settings +##################### +palette-project = "Default" # The name of your project in Palette. + +############################## +# Hello Universe Configuration +############################## +app_port = 8080 # The cluster port number on which the service will listen for incoming traffic. + +create_new_profile_version = false # Set to true to create cluster profile version 1.1.0 with Kubecost. + +update_template_profile_version = false # Set to true after profile v1.1.0 is created to update the cluster template. + +upgrade_now_timestamp = "" # Set to the current RFC3339 timestamp (for example, "2026-05-12T14:30:00Z") to trigger an immediate upgrade of all clusters launched from the template. Change the value each time you want to re-trigger an upgrade. + +########################### +# AWS Deployment Settings +############################ +deploy-aws = false # Set to true to deploy to AWS. + +aws-cloud-account-name = "REPLACE ME" +aws-region = "REPLACE ME" +aws-key-pair-name = "REPLACE ME" + +aws_control_plane_nodes = { + count = "1" + control_plane = true + instance_type = "m4.2xlarge" + disk_size_gb = "60" + availability_zones = ["REPLACE ME"] +} + +aws_worker_nodes = { + count = "1" + control_plane = false + instance_type = "m4.2xlarge" + disk_size_gb = "60" + availability_zones = ["REPLACE ME"] +} + +########################### +# Azure Deployment Settings +############################ +deploy-azure = false # Set to true to deploy to Azure. + +azure-cloud-account-name = "REPLACE ME" +azure_subscription_id = "REPLACE ME" +azure_resource_group = "REPLACE ME" +azure-use-azs = false +azure-region = "REPLACE ME" + +azure_control_plane_nodes = { + count = "1" + control_plane = true + instance_type = "Standard_D4s_v5" + disk_size_gb = "60" + azs = ["REPLACE ME"] + is_system_node_pool = false +} + +azure_worker_nodes = { + count = "1" + control_plane = false + instance_type = "Standard_D4s_v5" + disk_size_gb = "60" + azs = ["REPLACE ME"] + is_system_node_pool = false +} diff --git a/terraform/cluster-templates-tf/tests/aws-replace.tftest.hcl b/terraform/cluster-templates-tf/tests/aws-replace.tftest.hcl new file mode 100644 index 0000000..bd389ba --- /dev/null +++ b/terraform/cluster-templates-tf/tests/aws-replace.tftest.hcl @@ -0,0 +1,40 @@ +variables { + palette-project = "Default" + app_port = 8080 + deploy-aws = true + deploy-azure = false + azure-use-azs = false + aws-cloud-account-name = "REPLACE ME" + aws-region = "REPLACE ME" + aws-key-pair-name = "REPLACE ME" + aws_control_plane_nodes = { + count = "1" + control_plane = true + instance_type = "m4.2xlarge" + disk_size_gb = "60" + availability_zones = ["REPLACE ME"] + } + aws_worker_nodes = { + count = "1" + control_plane = false + instance_type = "m4.2xlarge" + disk_size_gb = "60" + availability_zones = ["REPLACE ME"] + } +} + +mock_provider "spectrocloud" {} + +run "verify_aws" { + + command = plan + + expect_failures = [ + var.aws-cloud-account-name, + var.aws-key-pair-name, + var.aws-region, + var.aws_control_plane_nodes.availability_zones, + var.aws_worker_nodes.availability_zones + ] + +} diff --git a/terraform/cluster-templates-tf/tests/aws.tftest.hcl b/terraform/cluster-templates-tf/tests/aws.tftest.hcl new file mode 100644 index 0000000..b5a3b9a --- /dev/null +++ b/terraform/cluster-templates-tf/tests/aws.tftest.hcl @@ -0,0 +1,105 @@ +variables { + palette-project = "Default" + app_port = 8080 + deploy-aws = true + deploy-azure = false + azure-use-azs = false + aws-cloud-account-name = "test-account" + aws-region = "us-east-1" + aws-key-pair-name = "test-key-pair" + aws_control_plane_nodes = { + count = "1" + control_plane = true + instance_type = "m4.2xlarge" + disk_size_gb = "60" + availability_zones = ["us-east-1"] + } + aws_worker_nodes = { + count = "1" + control_plane = false + instance_type = "m4.2xlarge" + disk_size_gb = "60" + availability_zones = ["us-east-1"] + } +} + +mock_provider "spectrocloud" { +} + +run "verify_aws" { + + command = plan + + assert { + condition = length(spectrocloud_cluster_profile.aws_profile) == 1 + error_message = "No AWS cluster profile was created" + } + + assert { + condition = length(spectrocloud_cluster_config_template.aws_template) == 1 + error_message = "No AWS cluster template was created" + } + + assert { + condition = length(spectrocloud_cluster_aws.dev_cluster) == 1 + error_message = "No AWS cluster was created" + } + + assert { + condition = spectrocloud_cluster_aws.dev_cluster[0].cluster_timezone == "UTC" + error_message = "AWS cluster timezone is not set to UTC" + } + + assert { + condition = length(spectrocloud_cluster_aws.prod_cluster) == 1 + error_message = "No AWS prod cluster was created" + } + + assert { + condition = spectrocloud_cluster_aws.prod_cluster[0].cluster_timezone == "UTC" + error_message = "AWS prod cluster timezone is not set to UTC" + } + +} + +run "verify_profile_v110_planned" { + + command = plan + + variables { + create_new_profile_version = true + update_template_profile_version = false + } + + assert { + condition = length(spectrocloud_cluster_profile.aws_profile_v110) == 1 + error_message = "AWS cluster profile v1.1.0 was not planned for creation" + } + + assert { + condition = length(spectrocloud_cluster_config_template.aws_template) == 1 + error_message = "AWS cluster template was not planned" + } + +} + +run "verify_template_updated_to_v110" { + + command = plan + + variables { + create_new_profile_version = true + update_template_profile_version = true + } + + assert { + condition = length(spectrocloud_cluster_profile.aws_profile_v110) == 1 + error_message = "AWS cluster profile v1.1.0 was not planned for creation" + } + + assert { + condition = length(spectrocloud_cluster_config_template.aws_template) == 1 + error_message = "AWS cluster template was not planned for update" + } + +} diff --git a/terraform/cluster-templates-tf/tests/azure-replace.tftest.hcl b/terraform/cluster-templates-tf/tests/azure-replace.tftest.hcl new file mode 100644 index 0000000..7fa763f --- /dev/null +++ b/terraform/cluster-templates-tf/tests/azure-replace.tftest.hcl @@ -0,0 +1,28 @@ +variables { + palette-project = "Default" + app_port = 8080 + deploy-aws = false + deploy-azure = true + azure-use-azs = false + azure-cloud-account-name = "REPLACE ME" + azure_subscription_id = "REPLACE ME" + azure_resource_group = "REPLACE ME" + azure-region = "REPLACE ME" +} + +mock_provider "spectrocloud" {} + +mock_provider "tls" {} + +run "verify_azure" { + + command = plan + + expect_failures = [ + var.azure-cloud-account-name, + var.azure_subscription_id, + var.azure_resource_group, + var.azure-region, + ] + +} diff --git a/terraform/cluster-templates-tf/tests/azure.tftest.hcl b/terraform/cluster-templates-tf/tests/azure.tftest.hcl new file mode 100644 index 0000000..7bbc6df --- /dev/null +++ b/terraform/cluster-templates-tf/tests/azure.tftest.hcl @@ -0,0 +1,100 @@ +variables { + palette-project = "Default" + app_port = 8080 + deploy-aws = false + deploy-azure = true + azure-use-azs = false + azure-cloud-account-name = "test-account" + azure_subscription_id = "test-subscription-id" + azure_resource_group = "test-resource-group" + azure-region = "eastus" +} + +mock_provider "spectrocloud" { +} + +mock_provider "tls" { +} + +run "verify_azure" { + + command = plan + + assert { + condition = length(spectrocloud_cluster_profile.azure_profile) == 1 + error_message = "No Azure cluster profile was created" + } + + assert { + condition = length(spectrocloud_cluster_config_template.azure_template) == 1 + error_message = "No Azure cluster template was created" + } + + assert { + condition = length(spectrocloud_cluster_azure.dev_cluster) == 1 + error_message = "No Azure cluster was created" + } + + assert { + condition = spectrocloud_cluster_azure.dev_cluster[0].cluster_timezone == "UTC" + error_message = "Azure cluster timezone is not set to UTC" + } + + assert { + condition = length(spectrocloud_cluster_azure.prod_cluster) == 1 + error_message = "No Azure prod cluster was created" + } + + assert { + condition = spectrocloud_cluster_azure.prod_cluster[0].cluster_timezone == "UTC" + error_message = "Azure prod cluster timezone is not set to UTC" + } + + assert { + condition = length(tls_private_key.tutorial_ssh_key_azure) == 1 + error_message = "No Azure SSH key was created" + } + +} + +run "verify_profile_v110_planned" { + + command = plan + + variables { + create_new_profile_version = true + update_template_profile_version = false + } + + assert { + condition = length(spectrocloud_cluster_profile.azure_profile_v110) == 1 + error_message = "Azure cluster profile v1.1.0 was not planned for creation" + } + + assert { + condition = length(spectrocloud_cluster_config_template.azure_template) == 1 + error_message = "Azure cluster template was not planned" + } + +} + +run "verify_template_updated_to_v110" { + + command = plan + + variables { + create_new_profile_version = true + update_template_profile_version = true + } + + assert { + condition = length(spectrocloud_cluster_profile.azure_profile_v110) == 1 + error_message = "Azure cluster profile v1.1.0 was not planned for creation" + } + + assert { + condition = length(spectrocloud_cluster_config_template.azure_template) == 1 + error_message = "Azure cluster template was not planned for update" + } + +}