Use Terraform for create Azure

This commit is contained in:
katexochen 2022-10-06 11:52:19 +02:00 committed by Paul Meyer
parent 98a16b2b47
commit f4af9c56f5
9 changed files with 97 additions and 400 deletions

View File

@ -25,6 +25,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Changed
<!-- For changes in existing functionality. -->
- Verify measurements using [Rekor](https://github.com/sigstore/rekor) transparency log.
- The `constellation create` on Azure now uses Terraform to create and destroy cloud resources.
### Deprecated
<!-- For soon-to-be removed features. -->

View File

@ -9,7 +9,6 @@ package cloudcmd
import (
"context"
azurecl "github.com/edgelesssys/constellation/v2/cli/internal/azure/client"
"github.com/edgelesssys/constellation/v2/cli/internal/terraform"
"github.com/edgelesssys/constellation/v2/internal/state"
)
@ -22,17 +21,6 @@ type terraformClient interface {
RemoveInstaller()
}
type azureclient interface {
GetState() state.ConstellationState
SetState(state.ConstellationState)
CreateApplicationInsight(ctx context.Context) error
CreateExternalLoadBalancer(ctx context.Context, isDebugCluster bool) error
CreateVirtualNetwork(ctx context.Context) error
CreateSecurityGroup(ctx context.Context, input azurecl.NetworkSecurityGroupInput) error
CreateInstances(ctx context.Context, input azurecl.CreateInstancesInput) error
TerminateResourceGroupResources(ctx context.Context) error
}
type libvirtRunner interface {
Start(ctx context.Context, containerName, imageName string) error
Stop(ctx context.Context) error

View File

@ -8,14 +8,9 @@ package cloudcmd
import (
"context"
"strconv"
"testing"
azurecl "github.com/edgelesssys/constellation/v2/cli/internal/azure/client"
"github.com/edgelesssys/constellation/v2/cli/internal/terraform"
"github.com/edgelesssys/constellation/v2/internal/azureshared"
"github.com/edgelesssys/constellation/v2/internal/cloud/cloudprovider"
"github.com/edgelesssys/constellation/v2/internal/cloud/cloudtypes"
"github.com/edgelesssys/constellation/v2/internal/state"
"go.uber.org/goleak"
)
@ -27,173 +22,6 @@ func TestMain(m *testing.M) {
)
}
type fakeAzureClient struct {
workers cloudtypes.Instances
controlPlanes cloudtypes.Instances
resourceGroup string
name string
uid string
location string
subscriptionID string
tenantID string
subnetID string
loadBalancerName string
controlPlaneScaleSet string
workerScaleSet string
networkSecurityGroup string
adAppObjectID string
}
func (c *fakeAzureClient) GetState() state.ConstellationState {
return state.ConstellationState{
CloudProvider: cloudprovider.Azure.String(),
AzureWorkerInstances: c.workers,
AzureControlPlaneInstances: c.controlPlanes,
Name: c.name,
UID: c.uid,
AzureResourceGroup: c.resourceGroup,
AzureLocation: c.location,
AzureSubscription: c.subscriptionID,
AzureTenant: c.tenantID,
AzureSubnet: c.subnetID,
AzureNetworkSecurityGroup: c.networkSecurityGroup,
AzureWorkerScaleSet: c.workerScaleSet,
AzureControlPlaneScaleSet: c.controlPlaneScaleSet,
AzureADAppObjectID: c.adAppObjectID,
}
}
func (c *fakeAzureClient) SetState(stat state.ConstellationState) {
c.workers = stat.AzureWorkerInstances
c.controlPlanes = stat.AzureControlPlaneInstances
c.name = stat.Name
c.uid = stat.UID
c.resourceGroup = stat.AzureResourceGroup
c.location = stat.AzureLocation
c.subscriptionID = stat.AzureSubscription
c.tenantID = stat.AzureTenant
c.subnetID = stat.AzureSubnet
c.networkSecurityGroup = stat.AzureNetworkSecurityGroup
c.workerScaleSet = stat.AzureWorkerScaleSet
c.controlPlaneScaleSet = stat.AzureControlPlaneScaleSet
c.adAppObjectID = stat.AzureADAppObjectID
}
func (c *fakeAzureClient) CreateApplicationInsight(ctx context.Context) error {
return nil
}
func (c *fakeAzureClient) CreateVirtualNetwork(ctx context.Context) error {
c.subnetID = "subnet"
return nil
}
func (c *fakeAzureClient) CreateExternalLoadBalancer(ctx context.Context, isDebugCluster bool) error {
c.loadBalancerName = "loadBalancer"
return nil
}
func (c *fakeAzureClient) CreateSecurityGroup(ctx context.Context, input azurecl.NetworkSecurityGroupInput) error {
c.networkSecurityGroup = "network-security-group"
return nil
}
func (c *fakeAzureClient) CreateInstances(ctx context.Context, input azurecl.CreateInstancesInput) error {
c.controlPlaneScaleSet = "controlplanes-scale-set"
c.workerScaleSet = "workers-scale-set"
c.workers = make(cloudtypes.Instances)
for i := 0; i < input.CountWorkers; i++ {
id := "id-" + strconv.Itoa(i)
c.workers[id] = cloudtypes.Instance{PublicIP: "192.0.2.1", PrivateIP: "192.0.2.1"}
}
c.controlPlanes = make(cloudtypes.Instances)
for i := 0; i < input.CountControlPlanes; i++ {
id := "id-" + strconv.Itoa(i)
c.controlPlanes[id] = cloudtypes.Instance{PublicIP: "192.0.2.1", PrivateIP: "192.0.2.1"}
}
return nil
}
func (c *fakeAzureClient) CreateServicePrincipal(ctx context.Context) (string, error) {
c.adAppObjectID = "00000000-0000-0000-0000-000000000001"
return azureshared.ApplicationCredentials{
AppClientID: "client-id",
ClientSecretValue: "client-secret",
}.ToCloudServiceAccountURI(), nil
}
func (c *fakeAzureClient) TerminateResourceGroupResources(ctx context.Context) error {
// TODO(katexochen)
return nil
}
func (c *fakeAzureClient) TerminateServicePrincipal(ctx context.Context) error {
if c.adAppObjectID == "" {
return nil
}
c.adAppObjectID = ""
return nil
}
type stubAzureClient struct {
terminateResourceGroupResourcesCalled bool
terminateServicePrincipalCalled bool
createApplicationInsightErr error
createVirtualNetworkErr error
createSecurityGroupErr error
createLoadBalancerErr error
createInstancesErr error
createServicePrincipalErr error
terminateResourceGroupResourcesErr error
terminateServicePrincipalErr error
}
func (c *stubAzureClient) GetState() state.ConstellationState {
return state.ConstellationState{}
}
func (c *stubAzureClient) SetState(state.ConstellationState) {
}
func (c *stubAzureClient) CreateExternalLoadBalancer(ctx context.Context, isDebugCluster bool) error {
return c.createLoadBalancerErr
}
func (c *stubAzureClient) CreateApplicationInsight(ctx context.Context) error {
return c.createApplicationInsightErr
}
func (c *stubAzureClient) CreateVirtualNetwork(ctx context.Context) error {
return c.createVirtualNetworkErr
}
func (c *stubAzureClient) CreateSecurityGroup(ctx context.Context, input azurecl.NetworkSecurityGroupInput) error {
return c.createSecurityGroupErr
}
func (c *stubAzureClient) CreateInstances(ctx context.Context, input azurecl.CreateInstancesInput) error {
return c.createInstancesErr
}
func (c *stubAzureClient) CreateServicePrincipal(ctx context.Context) (string, error) {
return azureshared.ApplicationCredentials{
AppClientID: "00000000-0000-0000-0000-000000000000",
ClientSecretValue: "secret",
}.ToCloudServiceAccountURI(), c.createServicePrincipalErr
}
func (c *stubAzureClient) TerminateResourceGroupResources(ctx context.Context) error {
c.terminateResourceGroupResourcesCalled = true
return c.terminateResourceGroupResourcesErr
}
func (c *stubAzureClient) TerminateServicePrincipal(ctx context.Context) error {
c.terminateServicePrincipalCalled = true
return c.terminateServicePrincipalErr
}
type stubTerraformClient struct {
state state.ConstellationState
cleanUpWorkspaceCalled bool

View File

@ -15,13 +15,10 @@ import (
"runtime"
"strings"
azurecl "github.com/edgelesssys/constellation/v2/cli/internal/azure/client"
"github.com/edgelesssys/constellation/v2/cli/internal/libvirt"
"github.com/edgelesssys/constellation/v2/cli/internal/terraform"
"github.com/edgelesssys/constellation/v2/internal/cloud/cloudprovider"
"github.com/edgelesssys/constellation/v2/internal/cloud/cloudtypes"
"github.com/edgelesssys/constellation/v2/internal/config"
"github.com/edgelesssys/constellation/v2/internal/constants"
"github.com/edgelesssys/constellation/v2/internal/state"
)
@ -29,7 +26,6 @@ import (
type Creator struct {
out io.Writer
newTerraformClient func(ctx context.Context, provider cloudprovider.Provider) (terraformClient, error)
newAzureClient func(subscriptionID, tenantID, name, location, resourceGroup string) (azureclient, error)
newLibvirtRunner func() libvirtRunner
}
@ -40,9 +36,6 @@ func NewCreator(out io.Writer) *Creator {
newTerraformClient: func(ctx context.Context, provider cloudprovider.Provider) (terraformClient, error) {
return terraform.New(ctx, provider)
},
newAzureClient: func(subscriptionID, tenantID, name, location, resourceGroup string) (azureclient, error) {
return azurecl.NewInitialized(subscriptionID, tenantID, name, location, resourceGroup)
},
newLibvirtRunner: func() libvirtRunner {
return libvirt.New()
},
@ -52,14 +45,6 @@ func NewCreator(out io.Writer) *Creator {
// Create creates the handed amount of instances and all the needed resources.
func (c *Creator) Create(ctx context.Context, provider cloudprovider.Provider, config *config.Config, name, insType string, controlPlaneCount, workerCount int,
) (state.ConstellationState, error) {
// Use debug ingress firewall rules when debug mode / image is enabled
var ingressRules cloudtypes.Firewall
if config.IsDebugCluster() {
ingressRules = constants.IngressRulesDebug
} else {
ingressRules = constants.IngressRulesNoDebug
}
switch provider {
case cloudprovider.GCP:
cl, err := c.newTerraformClient(ctx, provider)
@ -69,17 +54,12 @@ func (c *Creator) Create(ctx context.Context, provider cloudprovider.Provider, c
defer cl.RemoveInstaller()
return c.createGCP(ctx, cl, config, name, insType, controlPlaneCount, workerCount)
case cloudprovider.Azure:
cl, err := c.newAzureClient(
config.Provider.Azure.SubscriptionID,
config.Provider.Azure.TenantID,
name,
config.Provider.Azure.Location,
config.Provider.Azure.ResourceGroup,
)
cl, err := c.newTerraformClient(ctx, provider)
if err != nil {
return state.ConstellationState{}, err
}
return c.createAzure(ctx, cl, config, insType, controlPlaneCount, workerCount, ingressRules)
defer cl.RemoveInstaller()
return c.createAzure(ctx, cl, config, name, insType, controlPlaneCount, workerCount)
case cloudprovider.QEMU:
if runtime.GOARCH != "amd64" || runtime.GOOS != "linux" {
return state.ConstellationState{}, fmt.Errorf("creation of a QEMU based Constellation is not supported for %s/%s", runtime.GOOS, runtime.GOARCH)
@ -125,37 +105,29 @@ func (c *Creator) createGCP(ctx context.Context, cl terraformClient, config *con
return cl.GetState(), nil
}
func (c *Creator) createAzure(ctx context.Context, cl azureclient, config *config.Config, insType string, controlPlaneCount, workerCount int, ingressRules cloudtypes.Firewall,
func (c *Creator) createAzure(ctx context.Context, cl terraformClient, config *config.Config,
name, insType string, controlPlaneCount, workerCount int,
) (stat state.ConstellationState, retErr error) {
defer rollbackOnError(context.Background(), c.out, &retErr, &rollbackerAzure{client: cl})
defer rollbackOnError(context.Background(), c.out, &retErr, &rollbackerTerraform{client: cl})
if err := cl.CreateApplicationInsight(ctx); err != nil {
return state.ConstellationState{}, err
}
if err := cl.CreateExternalLoadBalancer(ctx, config.IsDebugCluster()); err != nil {
return state.ConstellationState{}, err
}
if err := cl.CreateVirtualNetwork(ctx); err != nil {
return state.ConstellationState{}, err
}
if err := cl.CreateSecurityGroup(ctx, azurecl.NetworkSecurityGroupInput{
Ingress: ingressRules,
Egress: constants.EgressRules,
}); err != nil {
return state.ConstellationState{}, err
}
createInput := azurecl.CreateInstancesInput{
vars := &terraform.AzureVariables{
CommonVariables: terraform.CommonVariables{
Name: name,
CountControlPlanes: controlPlaneCount,
CountWorkers: workerCount,
InstanceType: insType,
StateDiskSizeGB: config.StateDiskSizeGB,
},
Location: config.Provider.Azure.Location,
ResourceGroup: config.Provider.Azure.ResourceGroup,
UserAssignedIdentity: config.Provider.Azure.UserAssignedIdentity,
InstanceType: insType,
StateDiskType: config.Provider.Azure.StateDiskType,
Image: config.Provider.Azure.Image,
UserAssingedIdentity: config.Provider.Azure.UserAssignedIdentity,
ImageID: config.Provider.Azure.Image,
ConfidentialVM: *config.Provider.Azure.ConfidentialVM,
Debug: config.IsDebugCluster(),
}
if err := cl.CreateInstances(ctx, createInput); err != nil {
if err := cl.CreateCluster(ctx, name, vars); err != nil {
return state.ConstellationState{}, err
}

View File

@ -14,7 +14,6 @@ import (
"testing"
"github.com/edgelesssys/constellation/v2/internal/cloud/cloudprovider"
"github.com/edgelesssys/constellation/v2/internal/cloud/cloudtypes"
"github.com/edgelesssys/constellation/v2/internal/config"
"github.com/edgelesssys/constellation/v2/internal/state"
"github.com/stretchr/testify/assert"
@ -33,30 +32,11 @@ func TestCreator(t *testing.T) {
LoadBalancerIP: "192.0.2.1",
}
wantAzureState := state.ConstellationState{
CloudProvider: cloudprovider.Azure.String(),
AzureControlPlaneInstances: cloudtypes.Instances{
"id-0": {PrivateIP: "192.0.2.1", PublicIP: "192.0.2.1"},
"id-1": {PrivateIP: "192.0.2.1", PublicIP: "192.0.2.1"},
},
AzureWorkerInstances: cloudtypes.Instances{
"id-0": {PrivateIP: "192.0.2.1", PublicIP: "192.0.2.1"},
"id-1": {PrivateIP: "192.0.2.1", PublicIP: "192.0.2.1"},
"id-2": {PrivateIP: "192.0.2.1", PublicIP: "192.0.2.1"},
},
AzureSubnet: "subnet",
AzureNetworkSecurityGroup: "network-security-group",
AzureWorkerScaleSet: "workers-scale-set",
AzureControlPlaneScaleSet: "controlplanes-scale-set",
}
someErr := errors.New("failed")
testCases := map[string]struct {
tfClient terraformClient
newTfClientErr error
azureclient azureclient
newAzureClientErr error
libvirt *stubLibvirtRunner
provider cloudprovider.Provider
config *config.Config
@ -114,39 +94,6 @@ func TestCreator(t *testing.T) {
wantErr: true,
wantRollback: !failOnNonAMD64,
},
"azure": {
azureclient: &fakeAzureClient{},
provider: cloudprovider.Azure,
config: config.Default(),
wantState: wantAzureState,
},
"azure newAzureClient error": {
newAzureClientErr: someErr,
provider: cloudprovider.Azure,
config: config.Default(),
wantErr: true,
},
"azure CreateVirtualNetwork error": {
azureclient: &stubAzureClient{createVirtualNetworkErr: someErr},
provider: cloudprovider.Azure,
config: config.Default(),
wantErr: true,
wantRollback: true,
},
"azure CreateSecurityGroup error": {
azureclient: &stubAzureClient{createSecurityGroupErr: someErr},
provider: cloudprovider.Azure,
config: config.Default(),
wantErr: true,
wantRollback: true,
},
"azure CreateInstances error": {
azureclient: &stubAzureClient{createInstancesErr: someErr},
provider: cloudprovider.Azure,
config: config.Default(),
wantErr: true,
wantRollback: true,
},
"unknown provider": {
provider: cloudprovider.Unknown,
config: config.Default(),
@ -163,9 +110,6 @@ func TestCreator(t *testing.T) {
newTerraformClient: func(ctx context.Context, provider cloudprovider.Provider) (terraformClient, error) {
return tc.tfClient, tc.newTfClientErr
},
newAzureClient: func(subscriptionID, tenantID, name, location, resourceGroup string) (azureclient, error) {
return tc.azureclient, tc.newAzureClientErr
},
newLibvirtRunner: func() libvirtRunner {
return tc.libvirt
},
@ -176,19 +120,11 @@ func TestCreator(t *testing.T) {
if tc.wantErr {
assert.Error(err)
if tc.wantRollback {
switch tc.provider {
case cloudprovider.QEMU:
cl := tc.tfClient.(*stubTerraformClient)
assert.True(cl.destroyClusterCalled)
assert.True(cl.cleanUpWorkspaceCalled)
if tc.provider == cloudprovider.QEMU {
assert.True(tc.libvirt.stopCalled)
case cloudprovider.GCP:
cl := tc.tfClient.(*stubTerraformClient)
assert.True(cl.destroyClusterCalled)
assert.True(cl.cleanUpWorkspaceCalled)
case cloudprovider.Azure:
cl := tc.azureclient.(*stubAzureClient)
assert.True(cl.terminateResourceGroupResourcesCalled)
}
}
} else {

View File

@ -34,14 +34,6 @@ func rollbackOnError(ctx context.Context, w io.Writer, onErr *error, roll rollba
fmt.Fprintln(w, "Rollback succeeded.")
}
type rollbackerAzure struct {
client azureclient
}
func (r *rollbackerAzure) rollback(ctx context.Context) error {
return r.client.TerminateResourceGroupResources(ctx)
}
type rollbackerTerraform struct {
client terraformClient
}

View File

@ -10,7 +10,6 @@ import (
"context"
"fmt"
azurecl "github.com/edgelesssys/constellation/v2/cli/internal/azure/client"
"github.com/edgelesssys/constellation/v2/cli/internal/libvirt"
"github.com/edgelesssys/constellation/v2/cli/internal/terraform"
"github.com/edgelesssys/constellation/v2/internal/cloud/cloudprovider"
@ -19,19 +18,15 @@ import (
// Terminator deletes cloud provider resources.
type Terminator struct {
newTerraformClient func(ctx context.Context) (terraformClient, error)
newAzureClient func(subscriptionID, tenantID string) (azureclient, error)
newTerraformClient func(ctx context.Context, provider cloudprovider.Provider) (terraformClient, error)
newLibvirtRunner func() libvirtRunner
}
// NewTerminator create a new cloud terminator.
func NewTerminator() *Terminator {
return &Terminator{
newTerraformClient: func(ctx context.Context) (terraformClient, error) {
return terraform.New(ctx, cloudprovider.GCP)
},
newAzureClient: func(subscriptionID, tenantID string) (azureclient, error) {
return azurecl.NewFromDefault(subscriptionID, tenantID)
newTerraformClient: func(ctx context.Context, provider cloudprovider.Provider) (terraformClient, error) {
return terraform.New(ctx, provider)
},
newLibvirtRunner: func() libvirtRunner {
return libvirt.New()
@ -42,37 +37,22 @@ func NewTerminator() *Terminator {
// Terminate deletes the could provider resources defined in the constellation state.
func (t *Terminator) Terminate(ctx context.Context, state state.ConstellationState) error {
provider := cloudprovider.FromString(state.CloudProvider)
switch provider {
case cloudprovider.Azure:
cl, err := t.newAzureClient(state.AzureSubscription, state.AzureTenant)
if err != nil {
return err
if provider == cloudprovider.Unknown {
return fmt.Errorf("unknown cloud provider %s", state.CloudProvider)
}
return t.terminateAzure(ctx, cl, state)
case cloudprovider.GCP:
cl, err := t.newTerraformClient(ctx)
if err != nil {
return err
}
defer cl.RemoveInstaller()
return t.terminateTerraform(ctx, cl)
case cloudprovider.QEMU:
cl, err := t.newTerraformClient(ctx)
cl, err := t.newTerraformClient(ctx, provider)
if err != nil {
return err
}
defer cl.RemoveInstaller()
if provider == cloudprovider.QEMU {
libvirt := t.newLibvirtRunner()
return t.terminateQEMU(ctx, cl, libvirt)
default:
return fmt.Errorf("unsupported provider: %s", provider)
}
}
func (t *Terminator) terminateAzure(ctx context.Context, cl azureclient, state state.ConstellationState) error {
cl.SetState(state)
return cl.TerminateResourceGroupResources(ctx)
return t.terminateTerraform(ctx, cl)
}
func (t *Terminator) terminateTerraform(ctx context.Context, cl terraformClient) error {

View File

@ -12,32 +12,16 @@ import (
"testing"
"github.com/edgelesssys/constellation/v2/internal/cloud/cloudprovider"
"github.com/edgelesssys/constellation/v2/internal/cloud/cloudtypes"
"github.com/edgelesssys/constellation/v2/internal/state"
"github.com/stretchr/testify/assert"
)
func TestTerminator(t *testing.T) {
someAzureState := func() state.ConstellationState {
return state.ConstellationState{
CloudProvider: cloudprovider.Azure.String(),
AzureWorkerInstances: cloudtypes.Instances{
"id-0": {PrivateIP: "192.0.2.1", PublicIP: "192.0.2.1"},
"id-1": {PrivateIP: "192.0.2.1", PublicIP: "192.0.2.1"},
},
AzureControlPlaneInstances: cloudtypes.Instances{
"id-c": {PrivateIP: "192.0.2.1", PublicIP: "192.0.2.1"},
},
AzureADAppObjectID: "00000000-0000-0000-0000-000000000001",
}
}
someErr := errors.New("failed")
testCases := map[string]struct {
tfClient terraformClient
newTfClientErr error
azureclient azureclient
newAzureClientErr error
libvirt *stubLibvirtRunner
state state.ConstellationState
wantErr bool
@ -84,20 +68,6 @@ func TestTerminator(t *testing.T) {
state: state.ConstellationState{CloudProvider: cloudprovider.QEMU.String()},
wantErr: true,
},
"azure": {
azureclient: &stubAzureClient{},
state: someAzureState(),
},
"azure newAzureClient error": {
newAzureClientErr: someErr,
state: someAzureState(),
wantErr: true,
},
"azure terminateResourceGroupResources error": {
azureclient: &stubAzureClient{terminateResourceGroupResourcesErr: someErr},
state: someAzureState(),
wantErr: true,
},
"unknown cloud provider": {
state: state.ConstellationState{},
wantErr: true,
@ -109,12 +79,9 @@ func TestTerminator(t *testing.T) {
assert := assert.New(t)
terminator := &Terminator{
newTerraformClient: func(ctx context.Context) (terraformClient, error) {
newTerraformClient: func(ctx context.Context, provider cloudprovider.Provider) (terraformClient, error) {
return tc.tfClient, tc.newTfClientErr
},
newAzureClient: func(subscriptionID, tenantID string) (azureclient, error) {
return tc.azureclient, tc.newAzureClientErr
},
newLibvirtRunner: func() libvirtRunner {
return tc.libvirt
},
@ -126,17 +93,11 @@ func TestTerminator(t *testing.T) {
assert.Error(err)
} else {
assert.NoError(err)
switch cloudprovider.FromString(tc.state.CloudProvider) {
case cloudprovider.QEMU:
assert.True(tc.libvirt.stopCalled)
fallthrough
case cloudprovider.GCP:
cl := tc.tfClient.(*stubTerraformClient)
assert.True(cl.destroyClusterCalled)
assert.True(cl.removeInstallerCalled)
case cloudprovider.Azure:
cl := tc.azureclient.(*stubAzureClient)
assert.True(cl.terminateResourceGroupResourcesCalled)
if cloudprovider.FromString(tc.state.CloudProvider) == cloudprovider.QEMU {
assert.True(tc.libvirt.stopCalled)
}
}
})

View File

@ -78,6 +78,45 @@ func (v *GCPVariables) String() string {
return b.String()
}
// AzureVariables is user configuration for creating a cluster with Terraform on Azure.
type AzureVariables struct {
// CommonVariables contains common variables.
CommonVariables
// ResourceGroup is the name of the Azure resource group to use.
ResourceGroup string
// Location is the Azure location to use.
Location string
// UserAssignedIdentity is the name of the Azure user-assigned identity to use.
UserAssignedIdentity string
// InstanceType is the Azure instance type to use.
InstanceType string
// StateDiskType is the Azure disk type to use for the state disk.
StateDiskType string
// ImageID is the ID of the Azure image to use.
ImageID string
// ConfidentialVM sets the VM to be confidential.
ConfidentialVM bool
// Debug is true if debug mode is enabled.
Debug bool
}
// String returns a string representation of the variables, formatted as Terraform variables.
func (v *AzureVariables) String() string {
b := &strings.Builder{}
b.WriteString(v.CommonVariables.String())
writeLinef(b, "resource_group = %q", v.ResourceGroup)
writeLinef(b, "location = %q", v.Location)
writeLinef(b, "user_assigned_identity = %q", v.UserAssignedIdentity)
writeLinef(b, "instance_type = %q", v.InstanceType)
writeLinef(b, "state_disk_type = %q", v.StateDiskType)
writeLinef(b, "image_id = %q", v.ImageID)
writeLinef(b, "confidential_vm = %t", v.ConfidentialVM)
writeLinef(b, "debug = %t", v.Debug)
return b.String()
}
// QEMUVariables is user configuration for creating a QEMU cluster with Terraform.
type QEMUVariables struct {
// CommonVariables contains common variables.