mirror of
https://github.com/edgelesssys/constellation.git
synced 2024-10-01 01:36:09 -04:00
terraform-provider: Add support for STACKIT / OpenStack
This commit is contained in:
parent
1670d977c6
commit
d69673fab7
@ -844,7 +844,7 @@ type applier interface {
|
||||
// methods required to install/upgrade Helm charts
|
||||
|
||||
PrepareHelmCharts(
|
||||
flags helm.Options, state *state.State, serviceAccURI string, masterSecret uri.MasterSecret, openStackCfg *config.OpenStackConfig,
|
||||
flags helm.Options, state *state.State, serviceAccURI string, masterSecret uri.MasterSecret,
|
||||
) (helm.Applier, bool, error)
|
||||
|
||||
// methods to interact with Kubernetes
|
||||
|
@ -554,7 +554,7 @@ func (s *stubConstellApplier) Init(context.Context, atls.Validator, *state.State
|
||||
|
||||
type helmApplier interface {
|
||||
PrepareHelmCharts(
|
||||
flags helm.Options, stateFile *state.State, serviceAccURI string, masterSecret uri.MasterSecret, openStackCfg *config.OpenStackConfig,
|
||||
flags helm.Options, stateFile *state.State, serviceAccURI string, masterSecret uri.MasterSecret,
|
||||
) (
|
||||
helm.Applier, bool, error)
|
||||
}
|
||||
|
@ -43,6 +43,18 @@ func (a *applyCmd) runHelmApply(cmd *cobra.Command, conf *config.Config, stateFi
|
||||
ApplyTimeout: a.flags.helmTimeout,
|
||||
AllowDestructive: helm.DenyDestructive,
|
||||
}
|
||||
if conf.Provider.OpenStack != nil {
|
||||
var deployYawolLoadBalancer bool
|
||||
if conf.Provider.OpenStack.DeployYawolLoadBalancer != nil {
|
||||
deployYawolLoadBalancer = *conf.Provider.OpenStack.DeployYawolLoadBalancer
|
||||
}
|
||||
options.OpenStackValues = &helm.OpenStackValues{
|
||||
DeployYawolLoadBalancer: deployYawolLoadBalancer,
|
||||
FloatingIPPoolID: conf.Provider.OpenStack.FloatingIPPoolID,
|
||||
YawolFlavorID: conf.Provider.OpenStack.YawolFlavorID,
|
||||
YawolImageID: conf.Provider.OpenStack.YawolImageID,
|
||||
}
|
||||
}
|
||||
|
||||
a.log.Debug("Getting service account URI")
|
||||
serviceAccURI, err := cloudcmd.GetMarshaledServiceAccountURI(conf, a.fileHandler)
|
||||
@ -51,7 +63,7 @@ func (a *applyCmd) runHelmApply(cmd *cobra.Command, conf *config.Config, stateFi
|
||||
}
|
||||
|
||||
a.log.Debug("Preparing Helm charts")
|
||||
executor, includesUpgrades, err := a.applier.PrepareHelmCharts(options, stateFile, serviceAccURI, masterSecret, conf.Provider.OpenStack)
|
||||
executor, includesUpgrades, err := a.applier.PrepareHelmCharts(options, stateFile, serviceAccURI, masterSecret)
|
||||
if errors.Is(err, helm.ErrConfirmationMissing) {
|
||||
if !a.flags.yes {
|
||||
cmd.PrintErrln("WARNING: Upgrading cert-manager will destroy all custom resources you have manually created that are based on the current version of cert-manager.")
|
||||
@ -65,7 +77,7 @@ func (a *applyCmd) runHelmApply(cmd *cobra.Command, conf *config.Config, stateFi
|
||||
}
|
||||
}
|
||||
options.AllowDestructive = helm.AllowDestructive
|
||||
executor, includesUpgrades, err = a.applier.PrepareHelmCharts(options, stateFile, serviceAccURI, masterSecret, conf.Provider.OpenStack)
|
||||
executor, includesUpgrades, err = a.applier.PrepareHelmCharts(options, stateFile, serviceAccURI, masterSecret)
|
||||
}
|
||||
var upgradeErr *compatibility.InvalidUpgradeError
|
||||
if err != nil {
|
||||
|
@ -279,7 +279,7 @@ type stubHelmApplier struct {
|
||||
}
|
||||
|
||||
func (s stubHelmApplier) PrepareHelmCharts(
|
||||
_ helm.Options, _ *state.State, _ string, _ uri.MasterSecret, _ *config.OpenStackConfig,
|
||||
_ helm.Options, _ *state.State, _ string, _ uri.MasterSecret,
|
||||
) (helm.Applier, bool, error) {
|
||||
return stubRunner{}, false, s.err
|
||||
}
|
||||
|
@ -376,9 +376,9 @@ type mockApplier struct {
|
||||
}
|
||||
|
||||
func (m *mockApplier) PrepareHelmCharts(
|
||||
helmOpts helm.Options, stateFile *state.State, str string, masterSecret uri.MasterSecret, openStackCfg *config.OpenStackConfig,
|
||||
helmOpts helm.Options, stateFile *state.State, str string, masterSecret uri.MasterSecret,
|
||||
) (helm.Applier, bool, error) {
|
||||
args := m.Called(helmOpts, stateFile, helmOpts, str, masterSecret, openStackCfg)
|
||||
args := m.Called(helmOpts, stateFile, helmOpts, str, masterSecret)
|
||||
return args.Get(0).(helm.Applier), args.Bool(1), args.Error(2)
|
||||
}
|
||||
|
||||
|
@ -9,7 +9,6 @@ package constellation
|
||||
import (
|
||||
"errors"
|
||||
|
||||
"github.com/edgelesssys/constellation/v2/internal/config"
|
||||
"github.com/edgelesssys/constellation/v2/internal/constellation/helm"
|
||||
"github.com/edgelesssys/constellation/v2/internal/constellation/state"
|
||||
"github.com/edgelesssys/constellation/v2/internal/kms/uri"
|
||||
@ -17,18 +16,18 @@ import (
|
||||
|
||||
// PrepareHelmCharts loads Helm charts for Constellation and returns an executor to apply them.
|
||||
func (a *Applier) PrepareHelmCharts(
|
||||
flags helm.Options, state *state.State, serviceAccURI string, masterSecret uri.MasterSecret, openStackCfg *config.OpenStackConfig,
|
||||
flags helm.Options, state *state.State, serviceAccURI string, masterSecret uri.MasterSecret,
|
||||
) (helm.Applier, bool, error) {
|
||||
if a.helmClient == nil {
|
||||
return nil, false, errors.New("helm client not initialized")
|
||||
}
|
||||
|
||||
return a.helmClient.PrepareApply(flags, state, serviceAccURI, masterSecret, openStackCfg)
|
||||
return a.helmClient.PrepareApply(flags, state, serviceAccURI, masterSecret)
|
||||
}
|
||||
|
||||
type helmApplier interface {
|
||||
PrepareApply(
|
||||
flags helm.Options, stateFile *state.State, serviceAccURI string, masterSecret uri.MasterSecret, openStackCfg *config.OpenStackConfig,
|
||||
flags helm.Options, stateFile *state.State, serviceAccURI string, masterSecret uri.MasterSecret,
|
||||
) (
|
||||
helm.Applier, bool, error)
|
||||
}
|
||||
|
@ -467,7 +467,6 @@ go_library(
|
||||
"//internal/cloud/gcpshared",
|
||||
"//internal/cloud/openstack",
|
||||
"//internal/compatibility",
|
||||
"//internal/config",
|
||||
"//internal/constants",
|
||||
"//internal/constellation/helm/imageversion",
|
||||
"//internal/constellation/state",
|
||||
|
@ -35,7 +35,6 @@ import (
|
||||
|
||||
"github.com/edgelesssys/constellation/v2/internal/attestation/variant"
|
||||
"github.com/edgelesssys/constellation/v2/internal/cloud/cloudprovider"
|
||||
"github.com/edgelesssys/constellation/v2/internal/config"
|
||||
"github.com/edgelesssys/constellation/v2/internal/constants"
|
||||
"github.com/edgelesssys/constellation/v2/internal/constellation/state"
|
||||
"github.com/edgelesssys/constellation/v2/internal/file"
|
||||
@ -91,13 +90,14 @@ type Options struct {
|
||||
MicroserviceVersion semver.Semver
|
||||
HelmWaitMode WaitMode
|
||||
ApplyTimeout time.Duration
|
||||
OpenStackValues *OpenStackValues
|
||||
}
|
||||
|
||||
// PrepareApply loads the charts and returns the executor to apply them.
|
||||
func (h Client) PrepareApply(
|
||||
flags Options, stateFile *state.State, serviceAccURI string, masterSecret uri.MasterSecret, openStackCfg *config.OpenStackConfig,
|
||||
flags Options, stateFile *state.State, serviceAccURI string, masterSecret uri.MasterSecret,
|
||||
) (Applier, bool, error) {
|
||||
releases, err := h.loadReleases(flags.CSP, flags.AttestationVariant, flags.K8sVersion, masterSecret, stateFile, flags, serviceAccURI, openStackCfg)
|
||||
releases, err := h.loadReleases(flags.CSP, flags.AttestationVariant, flags.K8sVersion, masterSecret, stateFile, flags, serviceAccURI)
|
||||
if err != nil {
|
||||
return nil, false, fmt.Errorf("loading Helm releases: %w", err)
|
||||
}
|
||||
@ -111,11 +111,11 @@ func (h Client) PrepareApply(
|
||||
|
||||
func (h Client) loadReleases(
|
||||
csp cloudprovider.Provider, attestationVariant variant.Variant, k8sVersion versions.ValidK8sVersion, secret uri.MasterSecret,
|
||||
stateFile *state.State, flags Options, serviceAccURI string, openStackCfg *config.OpenStackConfig,
|
||||
stateFile *state.State, flags Options, serviceAccURI string,
|
||||
) ([]release, error) {
|
||||
helmLoader := newLoader(csp, attestationVariant, k8sVersion, stateFile, h.cliVersion)
|
||||
h.log.Debug("Created new Helm loader")
|
||||
return helmLoader.loadReleases(flags.Conformance, flags.DeployCSIDriver, flags.HelmWaitMode, secret, serviceAccURI, openStackCfg)
|
||||
return helmLoader.loadReleases(flags.Conformance, flags.DeployCSIDriver, flags.HelmWaitMode, secret, serviceAccURI, flags.OpenStackValues)
|
||||
}
|
||||
|
||||
// Applier runs the Helm actions.
|
||||
|
@ -217,7 +217,7 @@ func TestHelmApply(t *testing.T) {
|
||||
SetInfrastructure(state.Infrastructure{UID: "testuid"}).
|
||||
SetClusterValues(state.ClusterValues{MeasurementSalt: []byte{0x41}}),
|
||||
fakeServiceAccURI(csp),
|
||||
uri.MasterSecret{Key: []byte("secret"), Salt: []byte("masterSalt")}, nil)
|
||||
uri.MasterSecret{Key: []byte("secret"), Salt: []byte("masterSalt")})
|
||||
var upgradeErr *compatibility.InvalidUpgradeError
|
||||
if tc.expectError {
|
||||
assert.Error(t, err)
|
||||
|
@ -21,7 +21,6 @@ import (
|
||||
|
||||
"github.com/edgelesssys/constellation/v2/internal/attestation/variant"
|
||||
"github.com/edgelesssys/constellation/v2/internal/cloud/cloudprovider"
|
||||
"github.com/edgelesssys/constellation/v2/internal/config"
|
||||
"github.com/edgelesssys/constellation/v2/internal/constants"
|
||||
"github.com/edgelesssys/constellation/v2/internal/constellation/helm/imageversion"
|
||||
"github.com/edgelesssys/constellation/v2/internal/constellation/state"
|
||||
@ -115,9 +114,17 @@ func newLoader(csp cloudprovider.Provider, attestationVariant variant.Variant, k
|
||||
// that the new release is installed after the existing one to avoid name conflicts.
|
||||
type releaseApplyOrder []release
|
||||
|
||||
// OpenStackValues are helm values for OpenStack.
|
||||
type OpenStackValues struct {
|
||||
DeployYawolLoadBalancer bool
|
||||
FloatingIPPoolID string
|
||||
YawolFlavorID string
|
||||
YawolImageID string
|
||||
}
|
||||
|
||||
// loadReleases loads the embedded helm charts and returns them as a HelmReleases object.
|
||||
func (i *chartLoader) loadReleases(conformanceMode, deployCSIDriver bool, helmWaitMode WaitMode, masterSecret uri.MasterSecret,
|
||||
serviceAccURI string, openStackCfg *config.OpenStackConfig,
|
||||
serviceAccURI string, openStackValues *OpenStackValues,
|
||||
) (releaseApplyOrder, error) {
|
||||
ciliumRelease, err := i.loadRelease(ciliumInfo, helmWaitMode)
|
||||
if err != nil {
|
||||
@ -143,7 +150,7 @@ func (i *chartLoader) loadReleases(conformanceMode, deployCSIDriver bool, helmWa
|
||||
}
|
||||
|
||||
svcVals, err := extraConstellationServicesValues(i.csp, i.attestationVariant, masterSecret,
|
||||
serviceAccURI, i.stateFile.Infrastructure, openStackCfg)
|
||||
serviceAccURI, i.stateFile.Infrastructure, openStackValues)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("extending constellation-services values: %w", err)
|
||||
}
|
||||
@ -169,13 +176,13 @@ func (i *chartLoader) loadReleases(conformanceMode, deployCSIDriver bool, helmWa
|
||||
}
|
||||
releases = append(releases, awsRelease)
|
||||
}
|
||||
if i.csp == cloudprovider.OpenStack && openStackCfg.DeployYawolLoadBalancer != nil && *openStackCfg.DeployYawolLoadBalancer {
|
||||
if i.csp == cloudprovider.OpenStack && openStackValues != nil && openStackValues.DeployYawolLoadBalancer {
|
||||
yawolRelease, err := i.loadRelease(yawolLBControllerInfo, WaitModeNone)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("loading yawol chart: %w", err)
|
||||
}
|
||||
|
||||
yawolVals, err := extraYawolValues(serviceAccURI, i.stateFile.Infrastructure, openStackCfg)
|
||||
yawolVals, err := extraYawolValues(serviceAccURI, i.stateFile.Infrastructure, openStackValues)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("extending yawol chart values: %w", err)
|
||||
}
|
||||
|
@ -175,6 +175,19 @@ func TestConstellationServices(t *testing.T) {
|
||||
t.Run(name, func(t *testing.T) {
|
||||
assert := assert.New(t)
|
||||
require := require.New(t)
|
||||
var openstackValues *OpenStackValues
|
||||
if tc.config.Provider.OpenStack != nil {
|
||||
var deploy bool
|
||||
if tc.config.Provider.OpenStack.DeployYawolLoadBalancer != nil {
|
||||
deploy = *tc.config.Provider.OpenStack.DeployYawolLoadBalancer
|
||||
}
|
||||
openstackValues = &OpenStackValues{
|
||||
DeployYawolLoadBalancer: deploy,
|
||||
FloatingIPPoolID: tc.config.Provider.OpenStack.FloatingIPPoolID,
|
||||
YawolFlavorID: tc.config.Provider.OpenStack.YawolFlavorID,
|
||||
YawolImageID: tc.config.Provider.OpenStack.YawolImageID,
|
||||
}
|
||||
}
|
||||
|
||||
chartLoader := chartLoader{
|
||||
csp: tc.config.GetProvider(),
|
||||
@ -199,7 +212,7 @@ func TestConstellationServices(t *testing.T) {
|
||||
UID: "uid",
|
||||
Azure: &state.Azure{},
|
||||
GCP: &state.GCP{},
|
||||
}, tc.config.Provider.OpenStack)
|
||||
}, openstackValues)
|
||||
require.NoError(err)
|
||||
values = mergeMaps(values, extraVals)
|
||||
|
||||
|
@ -18,7 +18,6 @@ import (
|
||||
"github.com/edgelesssys/constellation/v2/internal/cloud/cloudprovider"
|
||||
"github.com/edgelesssys/constellation/v2/internal/cloud/gcpshared"
|
||||
"github.com/edgelesssys/constellation/v2/internal/cloud/openstack"
|
||||
"github.com/edgelesssys/constellation/v2/internal/config"
|
||||
"github.com/edgelesssys/constellation/v2/internal/constants"
|
||||
"github.com/edgelesssys/constellation/v2/internal/constellation/state"
|
||||
"github.com/edgelesssys/constellation/v2/internal/kms/uri"
|
||||
@ -83,7 +82,7 @@ func extraCiliumValues(provider cloudprovider.Provider, conformanceMode bool, ou
|
||||
// Values set inside this function are only applied during init, not during upgrade.
|
||||
func extraConstellationServicesValues(
|
||||
csp cloudprovider.Provider, attestationVariant variant.Variant, masterSecret uri.MasterSecret, serviceAccURI string,
|
||||
output state.Infrastructure, openStackCfg *config.OpenStackConfig,
|
||||
output state.Infrastructure, openStackCfg *OpenStackValues,
|
||||
) (map[string]any, error) {
|
||||
extraVals := map[string]any{}
|
||||
extraVals["join-service"] = map[string]any{
|
||||
@ -152,7 +151,7 @@ func extraConstellationServicesValues(
|
||||
|
||||
// extraYawolValues extends the given values map by some values depending on user input.
|
||||
// Values set inside this function are only applied during init, not during upgrade.
|
||||
func extraYawolValues(serviceAccURI string, output state.Infrastructure, openStackCfg *config.OpenStackConfig) (map[string]any, error) {
|
||||
func extraYawolValues(serviceAccURI string, output state.Infrastructure, openStackCfg *OpenStackValues) (map[string]any, error) {
|
||||
extraVals := map[string]any{}
|
||||
|
||||
creds, err := openstack.AccountKeyFromURI(serviceAccURI)
|
||||
@ -163,7 +162,7 @@ func extraYawolValues(serviceAccURI string, output state.Infrastructure, openSta
|
||||
extraVals["yawol-config"] = map[string]any{
|
||||
"secretData": yawolIni,
|
||||
}
|
||||
if openStackCfg.DeployYawolLoadBalancer != nil && *openStackCfg.DeployYawolLoadBalancer {
|
||||
if openStackCfg != nil && openStackCfg.DeployYawolLoadBalancer {
|
||||
extraVals["yawol-controller"] = map[string]any{
|
||||
"yawolOSSecretName": "yawolkey",
|
||||
// has to be larger than ~30s to account for slow OpenStack API calls.
|
||||
|
@ -33,6 +33,7 @@ data "constellation_attestation" "test" {
|
||||
* `azure-sev-snp`
|
||||
* `azure-tdx`
|
||||
* `gcp-sev-es`
|
||||
* `qemu-vtpm`
|
||||
- `csp` (String) CSP (Cloud Service Provider) to use. (e.g. `azure`)
|
||||
See the [full list of CSPs](https://docs.edgeless.systems/constellation/overview/clouds) that Constellation supports.
|
||||
- `image` (Attributes) Constellation OS Image to use on the nodes. (see [below for nested schema](#nestedatt--image))
|
||||
@ -82,6 +83,7 @@ Read-Only:
|
||||
* `azure-sev-snp`
|
||||
* `azure-tdx`
|
||||
* `gcp-sev-es`
|
||||
* `qemu-vtpm`
|
||||
|
||||
<a id="nestedatt--attestation--azure_firmware_signer_config"></a>
|
||||
### Nested Schema for `attestation.azure_firmware_signer_config`
|
||||
|
@ -32,6 +32,7 @@ data "constellation_image" "example" {
|
||||
* `azure-sev-snp`
|
||||
* `azure-tdx`
|
||||
* `gcp-sev-es`
|
||||
* `qemu-vtpm`
|
||||
- `csp` (String) CSP (Cloud Service Provider) to use. (e.g. `azure`)
|
||||
See the [full list of CSPs](https://docs.edgeless.systems/constellation/overview/clouds) that Constellation supports.
|
||||
|
||||
|
@ -86,6 +86,7 @@ See the [full list of CSPs](https://docs.edgeless.systems/constellation/overview
|
||||
- `gcp` (Attributes) GCP-specific configuration. (see [below for nested schema](#nestedatt--gcp))
|
||||
- `in_cluster_endpoint` (String) The endpoint of the cluster. When not set, the out-of-cluster endpoint is used.
|
||||
- `license_id` (String) Constellation license ID. When not set, the community license is used.
|
||||
- `openstack` (Attributes) OpenStack-specific configuration. (see [below for nested schema](#nestedatt--openstack))
|
||||
|
||||
### Read-Only
|
||||
|
||||
@ -110,6 +111,7 @@ Required:
|
||||
* `azure-sev-snp`
|
||||
* `azure-tdx`
|
||||
* `gcp-sev-es`
|
||||
* `qemu-vtpm`
|
||||
|
||||
Optional:
|
||||
|
||||
@ -211,6 +213,24 @@ Required:
|
||||
- `project_id` (String) ID of the GCP project the cluster resides in.
|
||||
- `service_account_key` (String) Base64-encoded private key JSON object of the service account used within the cluster.
|
||||
|
||||
|
||||
<a id="nestedatt--openstack"></a>
|
||||
### Nested Schema for `openstack`
|
||||
|
||||
Required:
|
||||
|
||||
- `cloud` (String) Name of the cloud in the clouds.yaml file.
|
||||
- `floating_ip_pool_id` (String) Floating IP pool to use for the VMs.
|
||||
- `network_id` (String) OpenStack network ID to use for the VMs.
|
||||
- `subnet_id` (String) OpenStack subnet ID to use for the VMs.
|
||||
|
||||
Optional:
|
||||
|
||||
- `clouds_yaml_path` (String) Path to the clouds.yaml file.
|
||||
- `deploy_yawol_load_balancer` (Boolean) Whether to deploy a YAWOL load balancer.
|
||||
- `yawol_flavor_id` (String) OpenStack flavor used by the yawollet.
|
||||
- `yawol_image_id` (String) OpenStack OS image used by the yawollet.
|
||||
|
||||
## Import
|
||||
|
||||
Import is supported using the following syntax:
|
||||
|
128
terraform-provider-constellation/examples/full/stackit/main.tf
Normal file
128
terraform-provider-constellation/examples/full/stackit/main.tf
Normal file
@ -0,0 +1,128 @@
|
||||
terraform {
|
||||
required_providers {
|
||||
constellation = {
|
||||
source = "edgelesssys/constellation"
|
||||
version = "0.0.0" // replace with the version you want to use
|
||||
}
|
||||
random = {
|
||||
source = "hashicorp/random"
|
||||
version = "3.6.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
locals {
|
||||
name = "constell"
|
||||
image_version = "vX.Y.Z"
|
||||
kubernetes_version = "vX.Y.Z"
|
||||
microservice_version = "vX.Y.Z"
|
||||
csp = "stackit"
|
||||
attestation_variant = "qemu-vtpm"
|
||||
zone = "eu01-1"
|
||||
cloud = "stackit"
|
||||
clouds_yaml_path = "~/.config/openstack/clouds.yaml"
|
||||
floating_ip_pool_id = "970ace5c-458f-484a-a660-0903bcfd91ad"
|
||||
stackit_project_id = "" // replace with the STACKIT project id
|
||||
control_plane_count = 3
|
||||
worker_count = 2
|
||||
instance_type = "m1a.8cd"
|
||||
deploy_yawol_load_balancer = true
|
||||
yawol_image_id = "bcd6c13e-75d1-4c3f-bf0f-8f83580cc1be"
|
||||
yawol_flavor_id = "3b11b27e-6c73-470d-b595-1d85b95a8cdf"
|
||||
|
||||
master_secret = random_bytes.master_secret.hex
|
||||
master_secret_salt = random_bytes.master_secret_salt.hex
|
||||
measurement_salt = random_bytes.measurement_salt.hex
|
||||
}
|
||||
|
||||
resource "random_bytes" "master_secret" {
|
||||
length = 32
|
||||
}
|
||||
|
||||
resource "random_bytes" "master_secret_salt" {
|
||||
length = 32
|
||||
}
|
||||
|
||||
resource "random_bytes" "measurement_salt" {
|
||||
length = 32
|
||||
}
|
||||
|
||||
module "stackit_infrastructure" {
|
||||
// replace $VERSION with the Constellation version you want to use, e.g., v2.14.0
|
||||
source = "https://github.com/edgelesssys/constellation/releases/download/$VERSION/terraform-module.zip//terraform-module/openstack"
|
||||
name = local.name
|
||||
node_groups = {
|
||||
control_plane_default = {
|
||||
role = "control-plane"
|
||||
flavor_id = local.instance_type
|
||||
state_disk_size = 30
|
||||
state_disk_type = "storage_premium_perf6"
|
||||
initial_count = local.control_plane_count
|
||||
zone = local.zone
|
||||
},
|
||||
worker_default = {
|
||||
role = "worker"
|
||||
flavor_id = local.instance_type
|
||||
state_disk_size = 30
|
||||
state_disk_type = "storage_premium_perf6"
|
||||
initial_count = local.worker_count
|
||||
zone = local.zone
|
||||
}
|
||||
}
|
||||
image_id = data.constellation_image.bar.image.reference
|
||||
debug = false
|
||||
cloud = local.cloud
|
||||
openstack_clouds_yaml_path = local.clouds_yaml_path
|
||||
floating_ip_pool_id = local.floating_ip_pool_id
|
||||
stackit_project_id = local.stackit_project_id
|
||||
}
|
||||
|
||||
data "constellation_attestation" "foo" {
|
||||
csp = local.csp
|
||||
attestation_variant = local.attestation_variant
|
||||
image = data.constellation_image.bar.image
|
||||
}
|
||||
|
||||
data "constellation_image" "bar" {
|
||||
csp = local.csp
|
||||
attestation_variant = local.attestation_variant
|
||||
version = local.image_version
|
||||
marketplace_image = true
|
||||
}
|
||||
|
||||
resource "constellation_cluster" "stackit_example" {
|
||||
csp = local.csp
|
||||
name = module.stackit_infrastructure.name
|
||||
uid = module.stackit_infrastructure.uid
|
||||
image = data.constellation_image.bar.image
|
||||
attestation = data.constellation_attestation.foo.attestation
|
||||
kubernetes_version = local.kubernetes_version
|
||||
constellation_microservice_version = local.microservice_version
|
||||
init_secret = module.stackit_infrastructure.init_secret
|
||||
master_secret = local.master_secret
|
||||
master_secret_salt = local.master_secret_salt
|
||||
measurement_salt = local.measurement_salt
|
||||
out_of_cluster_endpoint = module.stackit_infrastructure.out_of_cluster_endpoint
|
||||
in_cluster_endpoint = module.stackit_infrastructure.in_cluster_endpoint
|
||||
api_server_cert_sans = module.stackit_infrastructure.api_server_cert_sans
|
||||
openstack = {
|
||||
cloud = local.cloud
|
||||
clouds_yaml_path = local.clouds_yaml_path
|
||||
floating_ip_pool_id = local.floating_ip_pool_id
|
||||
deploy_yawol_load_balancer = local.deploy_yawol_load_balancer
|
||||
yawol_image_id = local.yawol_image_id
|
||||
yawol_flavor_id = local.yawol_flavor_id
|
||||
network_id = module.stackit_infrastructure.network_id
|
||||
subnet_id = module.stackit_infrastructure.lb_subnetwork_id
|
||||
}
|
||||
network_config = {
|
||||
ip_cidr_node = module.stackit_infrastructure.ip_cidr_node
|
||||
ip_cidr_service = "10.96.0.0/12"
|
||||
}
|
||||
}
|
||||
|
||||
output "kubeconfig" {
|
||||
value = constellation_cluster.stackit_example.kubeconfig
|
||||
sensitive = true
|
||||
description = "KubeConfig for the Constellation cluster."
|
||||
}
|
@ -23,6 +23,8 @@ go_library(
|
||||
"//internal/attestation/variant",
|
||||
"//internal/cloud/azureshared",
|
||||
"//internal/cloud/cloudprovider",
|
||||
"//internal/cloud/openstack",
|
||||
"//internal/cloud/openstack/clouds",
|
||||
"//internal/compatibility",
|
||||
"//internal/config",
|
||||
"//internal/constants",
|
||||
@ -30,6 +32,7 @@ go_library(
|
||||
"//internal/constellation/helm",
|
||||
"//internal/constellation/kubecmd",
|
||||
"//internal/constellation/state",
|
||||
"//internal/file",
|
||||
"//internal/grpc/dialer",
|
||||
"//internal/imagefetcher",
|
||||
"//internal/kms/uri",
|
||||
@ -53,6 +56,7 @@ go_library(
|
||||
"@com_github_hashicorp_terraform_plugin_framework//types/basetypes",
|
||||
"@com_github_hashicorp_terraform_plugin_framework_validators//stringvalidator",
|
||||
"@com_github_hashicorp_terraform_plugin_log//tflog",
|
||||
"@com_github_spf13_afero//:afero",
|
||||
],
|
||||
)
|
||||
|
||||
|
@ -110,6 +110,58 @@ func TestAccAttestationSource(t *testing.T) {
|
||||
},
|
||||
},
|
||||
},
|
||||
"STACKIT qemu-vtpm success": {
|
||||
ProtoV6ProviderFactories: testAccProtoV6ProviderFactories,
|
||||
PreCheck: bazelPreCheck,
|
||||
Steps: []resource.TestStep{
|
||||
{
|
||||
Config: testingConfig + `
|
||||
data "constellation_attestation" "test" {
|
||||
csp = "stackit"
|
||||
attestation_variant = "qemu-vtpm"
|
||||
image = {
|
||||
version = "v2.13.0"
|
||||
reference = "v2.13.0"
|
||||
short_path = "v2.13.0"
|
||||
}
|
||||
}
|
||||
`,
|
||||
Check: resource.ComposeAggregateTestCheckFunc(
|
||||
resource.TestCheckResourceAttr("data.constellation_attestation.test", "attestation.variant", "qemu-vtpm"),
|
||||
resource.TestCheckResourceAttr("data.constellation_attestation.test", "attestation.bootloader_version", "0"), // since this is not supported on STACKIT, we expect 0
|
||||
|
||||
resource.TestCheckResourceAttr("data.constellation_attestation.test", "attestation.measurements.15.expected", "0000000000000000000000000000000000000000000000000000000000000000"),
|
||||
resource.TestCheckResourceAttr("data.constellation_attestation.test", "attestation.measurements.15.warn_only", "false"),
|
||||
),
|
||||
},
|
||||
},
|
||||
},
|
||||
"openstack qemu-vtpm success": {
|
||||
ProtoV6ProviderFactories: testAccProtoV6ProviderFactories,
|
||||
PreCheck: bazelPreCheck,
|
||||
Steps: []resource.TestStep{
|
||||
{
|
||||
Config: testingConfig + `
|
||||
data "constellation_attestation" "test" {
|
||||
csp = "openstack"
|
||||
attestation_variant = "qemu-vtpm"
|
||||
image = {
|
||||
version = "v2.13.0"
|
||||
reference = "v2.13.0"
|
||||
short_path = "v2.13.0"
|
||||
}
|
||||
}
|
||||
`,
|
||||
Check: resource.ComposeAggregateTestCheckFunc(
|
||||
resource.TestCheckResourceAttr("data.constellation_attestation.test", "attestation.variant", "qemu-vtpm"),
|
||||
resource.TestCheckResourceAttr("data.constellation_attestation.test", "attestation.bootloader_version", "0"), // since this is not supported on OpenStack, we expect 0
|
||||
|
||||
resource.TestCheckResourceAttr("data.constellation_attestation.test", "attestation.measurements.15.expected", "0000000000000000000000000000000000000000000000000000000000000000"),
|
||||
resource.TestCheckResourceAttr("data.constellation_attestation.test", "attestation.measurements.15.warn_only", "false"),
|
||||
),
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for name, tc := range testCases {
|
||||
|
@ -26,6 +26,8 @@ import (
|
||||
"github.com/edgelesssys/constellation/v2/internal/attestation/variant"
|
||||
"github.com/edgelesssys/constellation/v2/internal/cloud/azureshared"
|
||||
"github.com/edgelesssys/constellation/v2/internal/cloud/cloudprovider"
|
||||
openstackshared "github.com/edgelesssys/constellation/v2/internal/cloud/openstack"
|
||||
"github.com/edgelesssys/constellation/v2/internal/cloud/openstack/clouds"
|
||||
"github.com/edgelesssys/constellation/v2/internal/compatibility"
|
||||
"github.com/edgelesssys/constellation/v2/internal/config"
|
||||
"github.com/edgelesssys/constellation/v2/internal/constants"
|
||||
@ -33,6 +35,7 @@ import (
|
||||
"github.com/edgelesssys/constellation/v2/internal/constellation/helm"
|
||||
"github.com/edgelesssys/constellation/v2/internal/constellation/kubecmd"
|
||||
"github.com/edgelesssys/constellation/v2/internal/constellation/state"
|
||||
"github.com/edgelesssys/constellation/v2/internal/file"
|
||||
"github.com/edgelesssys/constellation/v2/internal/grpc/dialer"
|
||||
"github.com/edgelesssys/constellation/v2/internal/kms/uri"
|
||||
"github.com/edgelesssys/constellation/v2/internal/license"
|
||||
@ -50,6 +53,7 @@ import (
|
||||
"github.com/hashicorp/terraform-plugin-framework/types"
|
||||
"github.com/hashicorp/terraform-plugin-framework/types/basetypes"
|
||||
"github.com/hashicorp/terraform-plugin-log/tflog"
|
||||
"github.com/spf13/afero"
|
||||
)
|
||||
|
||||
var (
|
||||
@ -96,6 +100,7 @@ type ClusterResourceModel struct {
|
||||
Attestation types.Object `tfsdk:"attestation"`
|
||||
GCP types.Object `tfsdk:"gcp"`
|
||||
Azure types.Object `tfsdk:"azure"`
|
||||
OpenStack types.Object `tfsdk:"openstack"`
|
||||
|
||||
OwnerID types.String `tfsdk:"owner_id"`
|
||||
ClusterID types.String `tfsdk:"cluster_id"`
|
||||
@ -129,6 +134,17 @@ type azureAttribute struct {
|
||||
LoadBalancerName string `tfsdk:"load_balancer_name"`
|
||||
}
|
||||
|
||||
type openStackAttribute struct {
|
||||
Cloud string `tfsdk:"cloud"`
|
||||
CloudsYAMLPath string `tfsdk:"clouds_yaml_path"`
|
||||
FloatingIPPoolID string `tfsdk:"floating_ip_pool_id"`
|
||||
DeployYawolLoadBalancer bool `tfsdk:"deploy_yawol_load_balancer"`
|
||||
YawolImageID string `tfsdk:"yawol_image_id"`
|
||||
YawolFlavorID string `tfsdk:"yawol_flavor_id"`
|
||||
NetworkID string `tfsdk:"network_id"`
|
||||
SubnetID string `tfsdk:"subnet_id"`
|
||||
}
|
||||
|
||||
// extraMicroservicesAttribute is the extra microservices attribute's data model.
|
||||
type extraMicroservicesAttribute struct {
|
||||
CSIDriver bool `tfsdk:"csi_driver"`
|
||||
@ -333,6 +349,53 @@ func (r *ClusterResource) Schema(_ context.Context, _ resource.SchemaRequest, re
|
||||
},
|
||||
},
|
||||
},
|
||||
"openstack": schema.SingleNestedAttribute{
|
||||
MarkdownDescription: "OpenStack-specific configuration.",
|
||||
Description: "OpenStack-specific configuration.",
|
||||
Optional: true,
|
||||
Attributes: map[string]schema.Attribute{
|
||||
"cloud": schema.StringAttribute{
|
||||
MarkdownDescription: "Name of the cloud in the clouds.yaml file.",
|
||||
Description: "Name of the cloud in the clouds.yaml file.",
|
||||
Required: true,
|
||||
},
|
||||
"clouds_yaml_path": schema.StringAttribute{
|
||||
MarkdownDescription: "Path to the clouds.yaml file.",
|
||||
Description: "Path to the clouds.yaml file.",
|
||||
Optional: true,
|
||||
},
|
||||
"floating_ip_pool_id": schema.StringAttribute{
|
||||
MarkdownDescription: "Floating IP pool to use for the VMs.",
|
||||
Description: "Floating IP pool to use for the VMs.",
|
||||
Required: true,
|
||||
},
|
||||
"deploy_yawol_load_balancer": schema.BoolAttribute{
|
||||
MarkdownDescription: "Whether to deploy a YAWOL load balancer.",
|
||||
Description: "Whether to deploy a YAWOL load balancer.",
|
||||
Optional: true,
|
||||
},
|
||||
"yawol_image_id": schema.StringAttribute{
|
||||
MarkdownDescription: "OpenStack OS image used by the yawollet.",
|
||||
Description: "OpenStack OS image used by the yawollet.",
|
||||
Optional: true,
|
||||
},
|
||||
"yawol_flavor_id": schema.StringAttribute{
|
||||
MarkdownDescription: "OpenStack flavor used by the yawollet.",
|
||||
Description: "OpenStack flavor used by the yawollet.",
|
||||
Optional: true,
|
||||
},
|
||||
"network_id": schema.StringAttribute{
|
||||
MarkdownDescription: "OpenStack network ID to use for the VMs.",
|
||||
Description: "OpenStack network ID to use for the VMs.",
|
||||
Required: true,
|
||||
},
|
||||
"subnet_id": schema.StringAttribute{
|
||||
MarkdownDescription: "OpenStack subnet ID to use for the VMs.",
|
||||
Description: "OpenStack subnet ID to use for the VMs.",
|
||||
Required: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
// Computed (output) attributes
|
||||
"owner_id": schema.StringAttribute{
|
||||
@ -406,6 +469,26 @@ func (r *ClusterResource) ValidateConfig(ctx context.Context, req resource.Valid
|
||||
"GCP configuration not allowed", "When csp is not set to 'gcp', setting the 'gcp' configuration has no effect.",
|
||||
)
|
||||
}
|
||||
|
||||
// OpenStack Config is required for OpenStack
|
||||
if (strings.EqualFold(data.CSP.ValueString(), cloudprovider.OpenStack.String()) ||
|
||||
strings.EqualFold(data.CSP.ValueString(), "stackit")) &&
|
||||
data.OpenStack.IsNull() {
|
||||
resp.Diagnostics.AddAttributeError(
|
||||
path.Root("openstack"),
|
||||
"OpenStack configuration missing", "When csp is set to 'openstack' or 'stackit', the 'openstack' configuration must be set.",
|
||||
)
|
||||
}
|
||||
|
||||
// OpenStack Config should not be set for other CSPs
|
||||
if !strings.EqualFold(data.CSP.ValueString(), cloudprovider.OpenStack.String()) &&
|
||||
!strings.EqualFold(data.CSP.ValueString(), "stackit") &&
|
||||
!data.OpenStack.IsNull() {
|
||||
resp.Diagnostics.AddAttributeWarning(
|
||||
path.Root("openstack"),
|
||||
"OpenStack configuration not allowed", "When csp is not set to 'openstack' or 'stackit', setting the 'openstack' configuration has no effect.",
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// Configure configures the resource.
|
||||
@ -779,6 +862,7 @@ func (r *ClusterResource) apply(ctx context.Context, data *ClusterResourceModel,
|
||||
serviceAccPayload := constellation.ServiceAccountPayload{}
|
||||
var gcpConfig gcpAttribute
|
||||
var azureConfig azureAttribute
|
||||
var openStackConfig openStackAttribute
|
||||
switch csp {
|
||||
case cloudprovider.GCP:
|
||||
convertDiags = data.GCP.As(ctx, &gcpConfig, basetypes.ObjectAsOptions{})
|
||||
@ -815,6 +899,33 @@ func (r *ClusterResource) apply(ctx context.Context, data *ClusterResourceModel,
|
||||
PreferredAuthMethod: azureshared.AuthMethodUserAssignedIdentity,
|
||||
UamiResourceID: azureConfig.UamiResourceID,
|
||||
}
|
||||
case cloudprovider.OpenStack:
|
||||
convertDiags = data.OpenStack.As(ctx, &openStackConfig, basetypes.ObjectAsOptions{})
|
||||
diags.Append(convertDiags...)
|
||||
if diags.HasError() {
|
||||
return diags
|
||||
}
|
||||
cloudsYAML, err := clouds.ReadCloudsYAML(file.NewHandler(afero.NewOsFs()), openStackConfig.CloudsYAMLPath)
|
||||
if err != nil {
|
||||
diags.AddError("Reading clouds.yaml", err.Error())
|
||||
return diags
|
||||
}
|
||||
cloud, ok := cloudsYAML.Clouds[openStackConfig.Cloud]
|
||||
if !ok {
|
||||
diags.AddError("Reading clouds.yaml", fmt.Sprintf("Cloud %s not found in clouds.yaml", openStackConfig.Cloud))
|
||||
return diags
|
||||
}
|
||||
serviceAccPayload.OpenStack = openstackshared.AccountKey{
|
||||
AuthURL: cloud.AuthInfo.AuthURL,
|
||||
Username: cloud.AuthInfo.Username,
|
||||
Password: cloud.AuthInfo.Password,
|
||||
ProjectID: cloud.AuthInfo.ProjectID,
|
||||
ProjectName: cloud.AuthInfo.ProjectName,
|
||||
UserDomainName: cloud.AuthInfo.UserDomainName,
|
||||
ProjectDomainName: cloud.AuthInfo.ProjectDomainName,
|
||||
RegionName: cloud.RegionName,
|
||||
}
|
||||
|
||||
}
|
||||
serviceAccURI, err := constellation.MarshalServiceAccountURI(csp, serviceAccPayload)
|
||||
if err != nil {
|
||||
@ -861,6 +972,11 @@ func (r *ClusterResource) apply(ctx context.Context, data *ClusterResourceModel,
|
||||
ProjectID: gcpConfig.ProjectID,
|
||||
IPCidrPod: networkCfg.IPCidrPod.ValueString(),
|
||||
}
|
||||
case cloudprovider.OpenStack:
|
||||
stateFile.Infrastructure.OpenStack = &state.OpenStack{
|
||||
NetworkID: openStackConfig.NetworkID,
|
||||
SubnetID: openStackConfig.SubnetID,
|
||||
}
|
||||
}
|
||||
|
||||
// Check license
|
||||
@ -937,6 +1053,14 @@ func (r *ClusterResource) apply(ctx context.Context, data *ClusterResourceModel,
|
||||
masterSecret: secrets.masterSecret,
|
||||
serviceAccURI: serviceAccURI,
|
||||
}
|
||||
if csp == cloudprovider.OpenStack {
|
||||
payload.openStackHelmValues = &helm.OpenStackValues{
|
||||
DeployYawolLoadBalancer: openStackConfig.DeployYawolLoadBalancer,
|
||||
FloatingIPPoolID: openStackConfig.FloatingIPPoolID,
|
||||
YawolImageID: openStackConfig.YawolImageID,
|
||||
YawolFlavorID: openStackConfig.YawolFlavorID,
|
||||
}
|
||||
}
|
||||
helmDiags := r.applyHelmCharts(ctx, applier, payload, stateFile)
|
||||
diags.Append(helmDiags...)
|
||||
if diags.HasError() {
|
||||
@ -1063,6 +1187,7 @@ type applyHelmChartsPayload struct {
|
||||
DeployCSIDriver bool // Whether to deploy the CSI driver.
|
||||
masterSecret uri.MasterSecret // master secret of the cluster.
|
||||
serviceAccURI string // URI of the service account used within the cluster.
|
||||
openStackHelmValues *helm.OpenStackValues // OpenStack-specific Helm values.
|
||||
}
|
||||
|
||||
// applyHelmCharts applies the Helm charts to the cluster.
|
||||
@ -1083,10 +1208,11 @@ func (r *ClusterResource) applyHelmCharts(ctx context.Context, applier *constell
|
||||
// Allow destructive changes to the cluster.
|
||||
// The user has previously been warned about this when planning a microservice version change.
|
||||
AllowDestructive: helm.AllowDestructive,
|
||||
OpenStackValues: payload.openStackHelmValues,
|
||||
}
|
||||
|
||||
executor, _, err := applier.PrepareHelmCharts(options, state,
|
||||
payload.serviceAccURI, payload.masterSecret, nil)
|
||||
payload.serviceAccURI, payload.masterSecret)
|
||||
var upgradeErr *compatibility.InvalidUpgradeError
|
||||
if err != nil {
|
||||
if !errors.As(err, &upgradeErr) {
|
||||
|
@ -489,6 +489,68 @@ func TestAccClusterResource(t *testing.T) {
|
||||
},
|
||||
},
|
||||
},
|
||||
"stackit config missing": {
|
||||
ProtoV6ProviderFactories: testAccProtoV6ProviderFactoriesWithVersion(providerVersion),
|
||||
PreCheck: bazelPreCheck,
|
||||
Steps: []resource.TestStep{
|
||||
{
|
||||
Config: fullClusterTestingConfig(t, "openstack") + fmt.Sprintf(`
|
||||
resource "constellation_cluster" "test" {
|
||||
csp = "stackit"
|
||||
name = "constell"
|
||||
uid = "test"
|
||||
image = data.constellation_image.bar.image
|
||||
attestation = data.constellation_attestation.foo.attestation
|
||||
init_secret = "deadbeef"
|
||||
master_secret = "deadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeef"
|
||||
master_secret_salt = "deadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeef"
|
||||
measurement_salt = "deadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeef"
|
||||
out_of_cluster_endpoint = "192.0.2.1"
|
||||
in_cluster_endpoint = "192.0.2.1"
|
||||
network_config = {
|
||||
ip_cidr_node = "0.0.0.0/24"
|
||||
ip_cidr_service = "0.0.0.0/24"
|
||||
ip_cidr_pod = "0.0.0.0/24"
|
||||
}
|
||||
kubernetes_version = "%s"
|
||||
constellation_microservice_version = "%s"
|
||||
}
|
||||
`, versions.Default, providerVersion),
|
||||
ExpectError: regexp.MustCompile(".*When csp is set to 'openstack' or 'stackit', the 'openstack' configuration\nmust be set.*"),
|
||||
},
|
||||
},
|
||||
},
|
||||
"openstack config missing": {
|
||||
ProtoV6ProviderFactories: testAccProtoV6ProviderFactoriesWithVersion(providerVersion),
|
||||
PreCheck: bazelPreCheck,
|
||||
Steps: []resource.TestStep{
|
||||
{
|
||||
Config: fullClusterTestingConfig(t, "openstack") + fmt.Sprintf(`
|
||||
resource "constellation_cluster" "test" {
|
||||
csp = "openstack"
|
||||
name = "constell"
|
||||
uid = "test"
|
||||
image = data.constellation_image.bar.image
|
||||
attestation = data.constellation_attestation.foo.attestation
|
||||
init_secret = "deadbeef"
|
||||
master_secret = "deadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeef"
|
||||
master_secret_salt = "deadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeef"
|
||||
measurement_salt = "deadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeef"
|
||||
out_of_cluster_endpoint = "192.0.2.1"
|
||||
in_cluster_endpoint = "192.0.2.1"
|
||||
network_config = {
|
||||
ip_cidr_node = "0.0.0.0/24"
|
||||
ip_cidr_service = "0.0.0.0/24"
|
||||
ip_cidr_pod = "0.0.0.0/24"
|
||||
}
|
||||
kubernetes_version = "%s"
|
||||
constellation_microservice_version = "%s"
|
||||
}
|
||||
`, versions.Default, providerVersion),
|
||||
ExpectError: regexp.MustCompile(".*When csp is set to 'openstack' or 'stackit', the 'openstack' configuration\nmust be set.*"),
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for name, tc := range testCases {
|
||||
@ -547,6 +609,19 @@ func fullClusterTestingConfig(t *testing.T, csp string) string {
|
||||
attestation_variant = "gcp-sev-es"
|
||||
image = data.constellation_image.bar.image
|
||||
}`, image)
|
||||
case "openstack":
|
||||
return providerConfig + fmt.Sprintf(`
|
||||
data "constellation_image" "bar" {
|
||||
version = "%s"
|
||||
attestation_variant = "qemu-vtpm"
|
||||
csp = "openstack"
|
||||
}
|
||||
|
||||
data "constellation_attestation" "foo" {
|
||||
csp = "openstack"
|
||||
attestation_variant = "qemu-vtpm"
|
||||
image = data.constellation_image.bar.image
|
||||
}`, image)
|
||||
default:
|
||||
t.Fatal("unknown csp")
|
||||
return ""
|
||||
|
@ -122,6 +122,10 @@ func convertFromTfAttestationCfg(tfAttestation attestationAttribute, attestation
|
||||
attestationConfig = &config.GCPSEVES{
|
||||
Measurements: c11nMeasurements,
|
||||
}
|
||||
case variant.QEMUVTPM{}:
|
||||
attestationConfig = &config.QEMUVTPM{
|
||||
Measurements: c11nMeasurements,
|
||||
}
|
||||
default:
|
||||
return nil, fmt.Errorf("unknown attestation variant: %s", attestationVariant)
|
||||
}
|
||||
@ -177,7 +181,7 @@ func convertToTfAttestation(attVar variant.Variant, snpVersions attestationconfi
|
||||
XFAM: hex.EncodeToString(tdxCfg.XFAM),
|
||||
}
|
||||
tfAttestation.TDX = tfTdxCfg
|
||||
case variant.GCPSEVES{}:
|
||||
case variant.GCPSEVES{}, variant.QEMUVTPM{}:
|
||||
// no additional fields
|
||||
default:
|
||||
return tfAttestation, fmt.Errorf("unknown attestation variant: %s", attVar)
|
||||
|
@ -252,9 +252,10 @@ func (d *ImageDataSource) Read(ctx context.Context, req datasource.ReadRequest,
|
||||
|
||||
// Save data into Terraform state
|
||||
diags := resp.State.SetAttribute(ctx, path.Root("image"), imageAttribute{
|
||||
Reference: imageRef,
|
||||
Version: imageSemver,
|
||||
ShortPath: apiCompatibleVer.ShortPath(),
|
||||
Reference: imageRef,
|
||||
Version: imageSemver,
|
||||
ShortPath: apiCompatibleVer.ShortPath(),
|
||||
MarketplaceImage: data.MarketplaceImage.ValueBoolPointer(),
|
||||
})
|
||||
resp.Diagnostics.Append(diags...)
|
||||
if resp.Diagnostics.HasError() {
|
||||
|
@ -141,6 +141,38 @@ func TestAccImageDataSource(t *testing.T) {
|
||||
},
|
||||
},
|
||||
},
|
||||
"stackit success": {
|
||||
ProtoV6ProviderFactories: testAccProtoV6ProviderFactories,
|
||||
PreCheck: bazelPreCheck,
|
||||
Steps: []resource.TestStep{
|
||||
{
|
||||
Config: testingConfig + `
|
||||
data "constellation_image" "test" {
|
||||
version = "v2.16.0"
|
||||
attestation_variant = "qemu-vtpm"
|
||||
csp = "stackit"
|
||||
}
|
||||
`,
|
||||
Check: resource.TestCheckResourceAttr("data.constellation_image.test", "image.reference", "8ffc1740-1e41-4281-b872-f8088ffd7692"), // should be immutable,
|
||||
},
|
||||
},
|
||||
},
|
||||
"openstack success": {
|
||||
ProtoV6ProviderFactories: testAccProtoV6ProviderFactories,
|
||||
PreCheck: bazelPreCheck,
|
||||
Steps: []resource.TestStep{
|
||||
{
|
||||
Config: testingConfig + `
|
||||
data "constellation_image" "test" {
|
||||
version = "v2.16.0"
|
||||
attestation_variant = "qemu-vtpm"
|
||||
csp = "openstack"
|
||||
}
|
||||
`,
|
||||
Check: resource.TestCheckResourceAttr("data.constellation_image.test", "image.reference", "8ffc1740-1e41-4281-b872-f8088ffd7692"), // should be immutable,
|
||||
},
|
||||
},
|
||||
},
|
||||
"unknown attestation variant": {
|
||||
ProtoV6ProviderFactories: testAccProtoV6ProviderFactories,
|
||||
PreCheck: bazelPreCheck,
|
||||
|
@ -31,11 +31,12 @@ func newAttestationVariantAttributeSchema(t attributeType) schema.Attribute {
|
||||
" * `aws-nitro-tpm`\n" +
|
||||
" * `azure-sev-snp`\n" +
|
||||
" * `azure-tdx`\n" +
|
||||
" * `gcp-sev-es`\n",
|
||||
" * `gcp-sev-es`\n" +
|
||||
" * `qemu-vtpm`\n",
|
||||
Required: isInput,
|
||||
Computed: !isInput,
|
||||
Validators: []validator.String{
|
||||
stringvalidator.OneOf("aws-sev-snp", "aws-nitro-tpm", "azure-sev-snp", "azure-tdx", "gcp-sev-es"),
|
||||
stringvalidator.OneOf("aws-sev-snp", "aws-nitro-tpm", "azure-sev-snp", "azure-tdx", "gcp-sev-es", "qemu-vtpm"),
|
||||
},
|
||||
}
|
||||
}
|
||||
@ -47,7 +48,7 @@ func newCSPAttributeSchema() schema.Attribute {
|
||||
"See the [full list of CSPs](https://docs.edgeless.systems/constellation/overview/clouds) that Constellation supports.",
|
||||
Required: true,
|
||||
Validators: []validator.String{
|
||||
stringvalidator.OneOf("aws", "azure", "gcp"),
|
||||
stringvalidator.OneOf("aws", "azure", "gcp", "openstack", "stackit"),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user