terraform: create nodeGroups in tfvars from nodeGroups in config

This commit is contained in:
Malte Poll 2023-08-02 10:41:26 +02:00 committed by Malte Poll
parent d0ec7a3e54
commit 0c20ccb477
3 changed files with 98 additions and 122 deletions

View File

@ -8,12 +8,12 @@ package cloudcmd
import ( import (
"fmt" "fmt"
"strings"
"github.com/edgelesssys/constellation/v2/cli/internal/terraform" "github.com/edgelesssys/constellation/v2/cli/internal/terraform"
"github.com/edgelesssys/constellation/v2/internal/attestation/variant" "github.com/edgelesssys/constellation/v2/internal/attestation/variant"
"github.com/edgelesssys/constellation/v2/internal/cloud/cloudprovider" "github.com/edgelesssys/constellation/v2/internal/cloud/cloudprovider"
"github.com/edgelesssys/constellation/v2/internal/config" "github.com/edgelesssys/constellation/v2/internal/config"
"github.com/edgelesssys/constellation/v2/internal/constants"
"github.com/edgelesssys/constellation/v2/internal/role" "github.com/edgelesssys/constellation/v2/internal/role"
) )
@ -21,13 +21,13 @@ import (
func TerraformUpgradeVars(conf *config.Config, imageRef string) (terraform.Variables, error) { func TerraformUpgradeVars(conf *config.Config, imageRef string) (terraform.Variables, error) {
switch conf.GetProvider() { switch conf.GetProvider() {
case cloudprovider.AWS: case cloudprovider.AWS:
vars := awsTerraformVars(conf, imageRef, nil, nil) vars := awsTerraformVars(conf, imageRef)
return vars, nil return vars, nil
case cloudprovider.Azure: case cloudprovider.Azure:
vars := azureTerraformVars(conf, imageRef, nil, nil) vars := azureTerraformVars(conf, imageRef)
return vars, nil return vars, nil
case cloudprovider.GCP: case cloudprovider.GCP:
vars := gcpTerraformVars(conf, imageRef, nil, nil) vars := gcpTerraformVars(conf, imageRef)
return vars, nil return vars, nil
default: default:
return nil, fmt.Errorf("unsupported provider: %s", conf.GetProvider()) return nil, fmt.Errorf("unsupported provider: %s", conf.GetProvider())
@ -36,27 +36,21 @@ func TerraformUpgradeVars(conf *config.Config, imageRef string) (terraform.Varia
// awsTerraformVars provides variables required to execute the Terraform scripts. // awsTerraformVars provides variables required to execute the Terraform scripts.
// It should be the only place to declare the AWS variables. // It should be the only place to declare the AWS variables.
func awsTerraformVars(conf *config.Config, imageRef string, controlPlaneCount, workerCount *int) *terraform.AWSClusterVariables { func awsTerraformVars(conf *config.Config, imageRef string) *terraform.AWSClusterVariables {
nodeGroups := make(map[string]terraform.AWSNodeGroup)
for groupName, group := range conf.NodeGroups {
nodeGroups[groupName] = terraform.AWSNodeGroup{
Role: role.FromString(group.Role).TFString(),
StateDiskSizeGB: group.StateDiskSizeGB,
InitialCount: group.InitialCount,
Zone: group.Zone,
InstanceType: group.InstanceType,
DiskType: group.StateDiskType,
}
}
return &terraform.AWSClusterVariables{ return &terraform.AWSClusterVariables{
Name: conf.Name, Name: conf.Name,
NodeGroups: map[string]terraform.AWSNodeGroup{ NodeGroups: nodeGroups,
constants.ControlPlaneDefault: {
Role: role.ControlPlane.TFString(),
StateDiskSizeGB: conf.StateDiskSizeGB,
InitialCount: controlPlaneCount,
Zone: conf.Provider.AWS.Zone,
InstanceType: conf.Provider.AWS.InstanceType,
DiskType: conf.Provider.AWS.StateDiskType,
},
constants.WorkerDefault: {
Role: role.Worker.TFString(),
StateDiskSizeGB: conf.StateDiskSizeGB,
InitialCount: workerCount,
Zone: conf.Provider.AWS.Zone,
InstanceType: conf.Provider.AWS.InstanceType,
DiskType: conf.Provider.AWS.StateDiskType,
},
},
Region: conf.Provider.AWS.Region, Region: conf.Provider.AWS.Region,
Zone: conf.Provider.AWS.Zone, Zone: conf.Provider.AWS.Zone,
AMIImageID: imageRef, AMIImageID: imageRef,
@ -70,27 +64,25 @@ func awsTerraformVars(conf *config.Config, imageRef string, controlPlaneCount, w
// azureTerraformVars provides variables required to execute the Terraform scripts. // azureTerraformVars provides variables required to execute the Terraform scripts.
// It should be the only place to declare the Azure variables. // It should be the only place to declare the Azure variables.
func azureTerraformVars(conf *config.Config, imageRef string, controlPlaneCount, workerCount *int) *terraform.AzureClusterVariables { func azureTerraformVars(conf *config.Config, imageRef string) *terraform.AzureClusterVariables {
nodeGroups := make(map[string]terraform.AzureNodeGroup)
for groupName, group := range conf.NodeGroups {
zones := strings.Split(group.Zone, ",")
if len(zones) == 0 || (len(zones) == 1 && zones[0] == "") {
zones = nil
}
nodeGroups[groupName] = terraform.AzureNodeGroup{
Role: role.FromString(group.Role).TFString(),
InitialCount: group.InitialCount,
InstanceType: group.InstanceType,
DiskSizeGB: group.StateDiskSizeGB,
DiskType: group.StateDiskType,
Zones: zones,
}
}
vars := &terraform.AzureClusterVariables{ vars := &terraform.AzureClusterVariables{
Name: conf.Name, Name: conf.Name,
NodeGroups: map[string]terraform.AzureNodeGroup{ NodeGroups: nodeGroups,
constants.ControlPlaneDefault: {
Role: "control-plane",
InitialCount: controlPlaneCount,
InstanceType: conf.Provider.Azure.InstanceType,
DiskSizeGB: conf.StateDiskSizeGB,
DiskType: conf.Provider.Azure.StateDiskType,
Zones: nil, // TODO(elchead): support zones AB#3225. check if lifecycle arg is required.
},
constants.WorkerDefault: {
Role: "worker",
InitialCount: workerCount,
InstanceType: conf.Provider.Azure.InstanceType,
DiskSizeGB: conf.StateDiskSizeGB,
DiskType: conf.Provider.Azure.StateDiskType,
Zones: nil,
},
},
Location: conf.Provider.Azure.Location, Location: conf.Provider.Azure.Location,
ImageID: imageRef, ImageID: imageRef,
CreateMAA: toPtr(conf.GetAttestationConfig().GetVariant().Equal(variant.AzureSEVSNP{})), CreateMAA: toPtr(conf.GetAttestationConfig().GetVariant().Equal(variant.AzureSEVSNP{})),
@ -108,27 +100,21 @@ func azureTerraformVars(conf *config.Config, imageRef string, controlPlaneCount,
// gcpTerraformVars provides variables required to execute the Terraform scripts. // gcpTerraformVars provides variables required to execute the Terraform scripts.
// It should be the only place to declare the GCP variables. // It should be the only place to declare the GCP variables.
func gcpTerraformVars(conf *config.Config, imageRef string, controlPlaneCount, workerCount *int) *terraform.GCPClusterVariables { func gcpTerraformVars(conf *config.Config, imageRef string) *terraform.GCPClusterVariables {
nodeGroups := make(map[string]terraform.GCPNodeGroup)
for groupName, group := range conf.NodeGroups {
nodeGroups[groupName] = terraform.GCPNodeGroup{
Role: role.FromString(group.Role).TFString(),
StateDiskSizeGB: group.StateDiskSizeGB,
InitialCount: group.InitialCount,
Zone: group.Zone,
InstanceType: group.InstanceType,
DiskType: group.StateDiskType,
}
}
return &terraform.GCPClusterVariables{ return &terraform.GCPClusterVariables{
Name: conf.Name, Name: conf.Name,
NodeGroups: map[string]terraform.GCPNodeGroup{ NodeGroups: nodeGroups,
constants.ControlPlaneDefault: {
Role: role.ControlPlane.TFString(),
StateDiskSizeGB: conf.StateDiskSizeGB,
InitialCount: controlPlaneCount,
Zone: conf.Provider.GCP.Zone,
InstanceType: conf.Provider.GCP.InstanceType,
DiskType: conf.Provider.GCP.StateDiskType,
},
constants.WorkerDefault: {
Role: role.Worker.TFString(),
StateDiskSizeGB: conf.StateDiskSizeGB,
InitialCount: workerCount,
Zone: conf.Provider.GCP.Zone,
InstanceType: conf.Provider.GCP.InstanceType,
DiskType: conf.Provider.GCP.StateDiskType,
},
},
Project: conf.Provider.GCP.Project, Project: conf.Provider.GCP.Project,
Region: conf.Provider.GCP.Region, Region: conf.Provider.GCP.Region,
Zone: conf.Provider.GCP.Zone, Zone: conf.Provider.GCP.Zone,
@ -140,11 +126,21 @@ func gcpTerraformVars(conf *config.Config, imageRef string, controlPlaneCount, w
// openStackTerraformVars provides variables required to execute the Terraform scripts. // openStackTerraformVars provides variables required to execute the Terraform scripts.
// It should be the only place to declare the OpenStack variables. // It should be the only place to declare the OpenStack variables.
func openStackTerraformVars(conf *config.Config, imageRef string, controlPlaneCount, workerCount *int) *terraform.OpenStackClusterVariables { func openStackTerraformVars(conf *config.Config, imageRef string) *terraform.OpenStackClusterVariables {
nodeGroups := make(map[string]terraform.OpenStackNodeGroup)
for groupName, group := range conf.NodeGroups {
nodeGroups[groupName] = terraform.OpenStackNodeGroup{
Role: role.FromString(group.Role).TFString(),
StateDiskSizeGB: group.StateDiskSizeGB,
InitialCount: group.InitialCount,
FlavorID: group.InstanceType,
Zone: group.Zone,
StateDiskType: group.StateDiskType,
}
}
return &terraform.OpenStackClusterVariables{ return &terraform.OpenStackClusterVariables{
Name: conf.Name, Name: conf.Name,
Cloud: toPtr(conf.Provider.OpenStack.Cloud), Cloud: toPtr(conf.Provider.OpenStack.Cloud),
FlavorID: conf.Provider.OpenStack.FlavorID,
FloatingIPPoolID: conf.Provider.OpenStack.FloatingIPPoolID, FloatingIPPoolID: conf.Provider.OpenStack.FloatingIPPoolID,
ImageURL: imageRef, ImageURL: imageRef,
DirectDownload: *conf.Provider.OpenStack.DirectDownload, DirectDownload: *conf.Provider.OpenStack.DirectDownload,
@ -152,54 +148,34 @@ func openStackTerraformVars(conf *config.Config, imageRef string, controlPlaneCo
OpenstackUsername: conf.Provider.OpenStack.Username, OpenstackUsername: conf.Provider.OpenStack.Username,
OpenstackPassword: conf.Provider.OpenStack.Password, OpenstackPassword: conf.Provider.OpenStack.Password,
Debug: conf.IsDebugCluster(), Debug: conf.IsDebugCluster(),
NodeGroups: map[string]terraform.OpenStackNodeGroup{ NodeGroups: nodeGroups,
constants.ControlPlaneDefault: { CustomEndpoint: conf.CustomEndpoint,
Role: role.ControlPlane.TFString(),
InitialCount: controlPlaneCount,
Zone: conf.Provider.OpenStack.AvailabilityZone, // TODO(elchead): make configurable AB#3225
StateDiskType: conf.Provider.OpenStack.StateDiskType,
StateDiskSizeGB: conf.StateDiskSizeGB,
},
constants.WorkerDefault: {
Role: role.Worker.TFString(),
InitialCount: workerCount,
Zone: conf.Provider.OpenStack.AvailabilityZone, // TODO(elchead): make configurable AB#3225
StateDiskType: conf.Provider.OpenStack.StateDiskType,
StateDiskSizeGB: conf.StateDiskSizeGB,
},
},
CustomEndpoint: conf.CustomEndpoint,
} }
} }
// qemuTerraformVars provides variables required to execute the Terraform scripts. // qemuTerraformVars provides variables required to execute the Terraform scripts.
// It should be the only place to declare the QEMU variables. // It should be the only place to declare the QEMU variables.
func qemuTerraformVars(conf *config.Config, imageRef string, controlPlaneCount, workerCount *int, libvirtURI, libvirtSocketPath, metadataLibvirtURI string) *terraform.QEMUVariables { func qemuTerraformVars(conf *config.Config, imageRef string, libvirtURI, libvirtSocketPath, metadataLibvirtURI string) *terraform.QEMUVariables {
nodeGroups := make(map[string]terraform.QEMUNodeGroup)
for groupName, group := range conf.NodeGroups {
nodeGroups[groupName] = terraform.QEMUNodeGroup{
Role: role.FromString(group.Role).TFString(),
InitialCount: group.InitialCount,
DiskSize: group.StateDiskSizeGB,
CPUCount: conf.Provider.QEMU.VCPUs,
MemorySize: conf.Provider.QEMU.Memory,
}
}
return &terraform.QEMUVariables{ return &terraform.QEMUVariables{
Name: conf.Name, Name: conf.Name,
LibvirtURI: libvirtURI, LibvirtURI: libvirtURI,
LibvirtSocketPath: libvirtSocketPath, LibvirtSocketPath: libvirtSocketPath,
// TODO(malt3): auto select boot mode based on attestation variant. // TODO(malt3): auto select boot mode based on attestation variant.
// requires image info v2. // requires image info v2.
BootMode: "uefi", BootMode: "uefi",
ImagePath: imageRef, ImagePath: imageRef,
ImageFormat: conf.Provider.QEMU.ImageFormat, ImageFormat: conf.Provider.QEMU.ImageFormat,
NodeGroups: map[string]terraform.QEMUNodeGroup{ NodeGroups: nodeGroups,
constants.ControlPlaneDefault: {
Role: role.ControlPlane.TFString(),
InitialCount: controlPlaneCount,
DiskSize: conf.StateDiskSizeGB,
CPUCount: conf.Provider.QEMU.VCPUs,
MemorySize: conf.Provider.QEMU.Memory,
},
constants.WorkerDefault: {
Role: role.Worker.TFString(),
InitialCount: workerCount,
DiskSize: conf.StateDiskSizeGB,
CPUCount: conf.Provider.QEMU.VCPUs,
MemorySize: conf.Provider.QEMU.Memory,
},
},
Machine: "q35", // TODO(elchead): make configurable AB#3225 Machine: "q35", // TODO(elchead): make configurable AB#3225
MetadataAPIImage: conf.Provider.QEMU.MetadataAPIImage, MetadataAPIImage: conf.Provider.QEMU.MetadataAPIImage,
MetadataLibvirtURI: metadataLibvirtURI, MetadataLibvirtURI: metadataLibvirtURI,

View File

@ -74,8 +74,8 @@ type AWSNodeGroup struct {
// StateDiskSizeGB is the size of the state disk to allocate to each node, in GB. // StateDiskSizeGB is the size of the state disk to allocate to each node, in GB.
StateDiskSizeGB int `hcl:"disk_size" cty:"disk_size"` StateDiskSizeGB int `hcl:"disk_size" cty:"disk_size"`
// InitialCount is the initial number of nodes to create in the node group. // InitialCount is the initial number of nodes to create in the node group.
// During upgrades this value is not set. // During upgrades this value ignored.
InitialCount *int `hcl:"initial_count" cty:"initial_count"` InitialCount int `hcl:"initial_count" cty:"initial_count"`
// Zone is the AWS availability-zone to use in the given region. // Zone is the AWS availability-zone to use in the given region.
Zone string `hcl:"zone" cty:"zone"` Zone string `hcl:"zone" cty:"zone"`
// InstanceType is the type of the EC2 instance to use. // InstanceType is the type of the EC2 instance to use.
@ -141,8 +141,8 @@ type GCPNodeGroup struct {
// StateDiskSizeGB is the size of the state disk to allocate to each node, in GB. // StateDiskSizeGB is the size of the state disk to allocate to each node, in GB.
StateDiskSizeGB int `hcl:"disk_size" cty:"disk_size"` StateDiskSizeGB int `hcl:"disk_size" cty:"disk_size"`
// InitialCount is the initial number of nodes to create in the node group. // InitialCount is the initial number of nodes to create in the node group.
// During upgrades this value is not set. // During upgrades this value ignored.
InitialCount *int `hcl:"initial_count" cty:"initial_count"` InitialCount int `hcl:"initial_count" cty:"initial_count"`
Zone string `hcl:"zone" cty:"zone"` Zone string `hcl:"zone" cty:"zone"`
InstanceType string `hcl:"instance_type" cty:"instance_type"` InstanceType string `hcl:"instance_type" cty:"instance_type"`
DiskType string `hcl:"disk_type" cty:"disk_type"` DiskType string `hcl:"disk_type" cty:"disk_type"`
@ -219,11 +219,11 @@ type AzureNodeGroup struct {
// Role is the role of the node group. // Role is the role of the node group.
Role string `hcl:"role" cty:"role"` Role string `hcl:"role" cty:"role"`
// InitialCount is optional for upgrades. // InitialCount is optional for upgrades.
InitialCount *int `hcl:"initial_count" cty:"initial_count"` InitialCount int `hcl:"initial_count" cty:"initial_count"`
InstanceType string `hcl:"instance_type" cty:"instance_type"` InstanceType string `hcl:"instance_type" cty:"instance_type"`
DiskSizeGB int `hcl:"disk_size" cty:"disk_size"` DiskSizeGB int `hcl:"disk_size" cty:"disk_size"`
DiskType string `hcl:"disk_type" cty:"disk_type"` DiskType string `hcl:"disk_type" cty:"disk_type"`
Zones *[]string `hcl:"zones" cty:"zones"` Zones []string `hcl:"zones" cty:"zones"`
} }
// AzureIAMVariables is user configuration for creating the IAM configuration with Terraform on Microsoft Azure. // AzureIAMVariables is user configuration for creating the IAM configuration with Terraform on Microsoft Azure.
@ -371,7 +371,7 @@ type QEMUNodeGroup struct {
// InitialCount is the number of instances to create. // InitialCount is the number of instances to create.
// InitialCount is optional for upgrades. // InitialCount is optional for upgrades.
// Upgrades are not implemented for QEMU. The type is similar to other NodeGroup types for consistency. // Upgrades are not implemented for QEMU. The type is similar to other NodeGroup types for consistency.
InitialCount *int `hcl:"initial_count" cty:"initial_count"` InitialCount int `hcl:"initial_count" cty:"initial_count"`
// DiskSize is the size of the disk to allocate to each node, in GiB. // DiskSize is the size of the disk to allocate to each node, in GiB.
DiskSize int `hcl:"disk_size" cty:"disk_size"` DiskSize int `hcl:"disk_size" cty:"disk_size"`
// CPUCount is the number of CPUs to allocate to each node. // CPUCount is the number of CPUs to allocate to each node.

View File

@ -22,7 +22,7 @@ func TestAWSClusterVariables(t *testing.T) {
constants.ControlPlaneDefault: { constants.ControlPlaneDefault: {
Role: role.ControlPlane.TFString(), Role: role.ControlPlane.TFString(),
StateDiskSizeGB: 30, StateDiskSizeGB: 30,
InitialCount: toPtr(1), InitialCount: 1,
Zone: "eu-central-1b", Zone: "eu-central-1b",
InstanceType: "x1.foo", InstanceType: "x1.foo",
DiskType: "foodisk", DiskType: "foodisk",
@ -30,7 +30,7 @@ func TestAWSClusterVariables(t *testing.T) {
constants.WorkerDefault: { constants.WorkerDefault: {
Role: role.Worker.TFString(), Role: role.Worker.TFString(),
StateDiskSizeGB: 30, StateDiskSizeGB: 30,
InitialCount: toPtr(2), InitialCount: 2,
Zone: "eu-central-1c", Zone: "eu-central-1c",
InstanceType: "x1.bar", InstanceType: "x1.bar",
DiskType: "bardisk", DiskType: "bardisk",
@ -105,7 +105,7 @@ func TestGCPClusterVariables(t *testing.T) {
constants.ControlPlaneDefault: { constants.ControlPlaneDefault: {
Role: "control-plane", Role: "control-plane",
StateDiskSizeGB: 30, StateDiskSizeGB: 30,
InitialCount: toPtr(1), InitialCount: 1,
Zone: "eu-central-1a", Zone: "eu-central-1a",
InstanceType: "n2d-standard-4", InstanceType: "n2d-standard-4",
DiskType: "pd-ssd", DiskType: "pd-ssd",
@ -113,7 +113,7 @@ func TestGCPClusterVariables(t *testing.T) {
constants.WorkerDefault: { constants.WorkerDefault: {
Role: "worker", Role: "worker",
StateDiskSizeGB: 10, StateDiskSizeGB: 10,
InitialCount: toPtr(1), InitialCount: 1,
Zone: "eu-central-1b", Zone: "eu-central-1b",
InstanceType: "n2d-standard-8", InstanceType: "n2d-standard-8",
DiskType: "pd-ssd", DiskType: "pd-ssd",
@ -177,7 +177,7 @@ func TestAzureClusterVariables(t *testing.T) {
NodeGroups: map[string]AzureNodeGroup{ NodeGroups: map[string]AzureNodeGroup{
constants.ControlPlaneDefault: { constants.ControlPlaneDefault: {
Role: "ControlPlane", Role: "ControlPlane",
InitialCount: to.Ptr(1), InitialCount: 1,
InstanceType: "Standard_D2s_v3", InstanceType: "Standard_D2s_v3",
DiskType: "StandardSSD_LRS", DiskType: "StandardSSD_LRS",
DiskSizeGB: 100, DiskSizeGB: 100,
@ -238,7 +238,6 @@ func TestOpenStackClusterVariables(t *testing.T) {
vars := OpenStackClusterVariables{ vars := OpenStackClusterVariables{
Name: "cluster-name", Name: "cluster-name",
Cloud: toPtr("my-cloud"), Cloud: toPtr("my-cloud"),
FlavorID: "flavor-0123456789abcdef",
FloatingIPPoolID: "fip-pool-0123456789abcdef", FloatingIPPoolID: "fip-pool-0123456789abcdef",
ImageURL: "https://example.com/image.raw", ImageURL: "https://example.com/image.raw",
DirectDownload: true, DirectDownload: true,
@ -249,7 +248,8 @@ func TestOpenStackClusterVariables(t *testing.T) {
NodeGroups: map[string]OpenStackNodeGroup{ NodeGroups: map[string]OpenStackNodeGroup{
constants.ControlPlaneDefault: { constants.ControlPlaneDefault: {
Role: "control-plane", Role: "control-plane",
InitialCount: toPtr(1), InitialCount: 1,
FlavorID: "flavor-0123456789abcdef",
Zone: "az-01", Zone: "az-01",
StateDiskType: "performance-8", StateDiskType: "performance-8",
StateDiskSizeGB: 30, StateDiskSizeGB: 30,
@ -262,6 +262,7 @@ func TestOpenStackClusterVariables(t *testing.T) {
want := `name = "cluster-name" want := `name = "cluster-name"
node_groups = { node_groups = {
control_plane_default = { control_plane_default = {
flavor_id = "flavor-0123456789abcdef"
initial_count = 1 initial_count = 1
role = "control-plane" role = "control-plane"
state_disk_size = 30 state_disk_size = 30
@ -270,7 +271,6 @@ node_groups = {
} }
} }
cloud = "my-cloud" cloud = "my-cloud"
flavor_id = "flavor-0123456789abcdef"
floating_ip_pool_id = "fip-pool-0123456789abcdef" floating_ip_pool_id = "fip-pool-0123456789abcdef"
image_url = "https://example.com/image.raw" image_url = "https://example.com/image.raw"
direct_download = true direct_download = true
@ -290,7 +290,7 @@ func TestQEMUClusterVariables(t *testing.T) {
NodeGroups: map[string]QEMUNodeGroup{ NodeGroups: map[string]QEMUNodeGroup{
"control-plane": { "control-plane": {
Role: role.ControlPlane.TFString(), Role: role.ControlPlane.TFString(),
InitialCount: toPtr(1), InitialCount: 1,
DiskSize: 30, DiskSize: 30,
CPUCount: 4, CPUCount: 4,
MemorySize: 8192, MemorySize: 8192,