Skip to content

Commit

Permalink
terraform-provider: Add support for STACKIT / OpenStack
Browse files Browse the repository at this point in the history
  • Loading branch information
malt3 committed Mar 11, 2024
1 parent b2dcc2e commit ca0c4c9
Show file tree
Hide file tree
Showing 24 changed files with 511 additions and 36 deletions.
2 changes: 1 addition & 1 deletion cli/internal/cmd/apply.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion cli/internal/cmd/apply_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
}
16 changes: 14 additions & 2 deletions cli/internal/cmd/applyhelm.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -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.")
Expand All @@ -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 {
Expand Down
2 changes: 1 addition & 1 deletion cli/internal/cmd/init_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
Expand Down
4 changes: 2 additions & 2 deletions cli/internal/cmd/upgradeapply_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
}

Expand Down
7 changes: 3 additions & 4 deletions internal/constellation/helm.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,26 +9,25 @@ 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"
)

// 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)
}
1 change: 0 additions & 1 deletion internal/constellation/helm/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
10 changes: 5 additions & 5 deletions internal/constellation/helm/helm.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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)
}
Expand All @@ -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.
Expand Down
2 changes: 1 addition & 1 deletion internal/constellation/helm/helm_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
17 changes: 12 additions & 5 deletions internal/constellation/helm/loader.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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 {
Expand All @@ -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)
}
Expand All @@ -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)
}
Expand Down
15 changes: 14 additions & 1 deletion internal/constellation/helm/loader_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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(),
Expand All @@ -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)

Expand Down
7 changes: 3 additions & 4 deletions internal/constellation/helm/overrides.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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{
Expand Down Expand Up @@ -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)
Expand All @@ -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.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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))
Expand Down Expand Up @@ -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`
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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.

Expand Down
20 changes: 20 additions & 0 deletions terraform-provider-constellation/docs/resources/cluster.md
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand All @@ -110,6 +111,7 @@ Required:
* `azure-sev-snp`
* `azure-tdx`
* `gcp-sev-es`
* `qemu-vtpm`

Optional:

Expand Down Expand Up @@ -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:
Expand Down
Loading

0 comments on commit ca0c4c9

Please sign in to comment.