Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ images:
csi-resizer: image-repository:image-tag
csi-liveness-probe: image-repository:image-tag
csi-snapshot-controller: image-repository:image-tag
csi-snapshot-validation-webhook: image-repository:image-tag

socketPath: /var/lib/csi/sockets/pluginproxy
region: ""
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,12 @@ spec:
{{- end }}
- --v=2
- --provide-controller-service=false
{{- if .Values.csi.enableCompatibilityMode }}
- --legacy-storage-mode=true
{{- end }}
{{- if .Values.csi.blockLegacyCreation }}
- --legacy-volume-creation=false
{{- end }}
env:
- name: CSI_ENDPOINT
value: unix://{{ .Values.socketPath }}
Expand All @@ -62,7 +68,7 @@ spec:
allowPrivilegeEscalation: true
ports:
- name: healthz
containerPort: 9908
containerPort: {{ .Values.healthzPort }}
protocol: TCP
livenessProbe:
httpGet:
Expand Down Expand Up @@ -112,7 +118,7 @@ spec:
args:
- --probe-timeout=3m
- --csi-address={{ .Values.socketPath }}
- --health-port=9908
- --health-port={{ .Values.healthzPort }}
{{- if .Values.resources.livenessProbe }}
resources:
{{ toYaml .Values.resources.livenessProbe | indent 10 }}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,12 @@ driverName: block-storage.csi.stackit.cloud

rescanBlockStorageOnResize: "true"

healthzPort: 9908

csi:
enableCompatibilityMode: false
blockLegacyCreation: false

images:
csi-driver-stackit: image-repository:image-tag
csi-node-driver-registrar: image-repository:image-tag
Expand Down
11 changes: 11 additions & 0 deletions hack/api-reference/api.md
Original file line number Diff line number Diff line change
Expand Up @@ -215,6 +215,17 @@ string
<p></p>
</td>
</tr>
<tr>
<td>
<code>compatibilityMode</code></br>
<em>
string
</em>
</td>
<td>
<p></p>
</td>
</tr>

</tbody>
</table>
Expand Down
10 changes: 10 additions & 0 deletions pkg/apis/stackit/v1alpha1/constants.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ package v1alpha1
const (
// DefaultCSIName defines the default CSI (Container Storage Interface) name for STACKIT
DefaultCSIName = "stackit"
// DefaultCSICompatibilityMode defines the default CSI driver's compatibility mode.
DefaultCSICompatibilityMode = "default"
// DefaultCCMName defines the default CCM (Cloud Controller Manager) controller to use
DefaultCCMName = "stackit"
)
Expand All @@ -15,3 +17,11 @@ const (
STACKIT ControllerName = "stackit"
OPENSTACK ControllerName = "openstack"
)

type CSICompatibilityMode string

const (
DEFAULT CSICompatibilityMode = "default"
COMPAT CSICompatibilityMode = "compat"
COMPATBLOCK CSICompatibilityMode = "compatblock"
)
3 changes: 3 additions & 0 deletions pkg/apis/stackit/v1alpha1/defaults.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,4 +43,7 @@ func SetDefaults_ControlPlaneConfig(obj *ControlPlaneConfig) {
if obj.Storage.CSI.Name == "" {
obj.Storage.CSI.Name = DefaultCSIName
}
if obj.Storage.CSI.CompatibilityMode == "" {
obj.Storage.CSI.CompatibilityMode = DefaultCSICompatibilityMode
}
}
3 changes: 2 additions & 1 deletion pkg/apis/stackit/v1alpha1/types_controlplane.go
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,8 @@ type Storage struct {
}

type CSI struct {
Name string `json:"name"`
Name string `json:"name"`
CompatibilityMode string `json:"compatibilityMode,omitempty"`
}

// CSIManila contains configuration for CSI Manila driver (support for NFS volumes)
Expand Down
176 changes: 164 additions & 12 deletions pkg/controller/controlplane/valuesprovider.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,12 @@ import (
"github.com/gardener/gardener/pkg/apis/core/v1beta1"
v1beta1constants "github.com/gardener/gardener/pkg/apis/core/v1beta1/constants"
extensionsv1alpha1 "github.com/gardener/gardener/pkg/apis/extensions/v1alpha1"
"github.com/gardener/gardener/pkg/chartrenderer"
gardenerutils "github.com/gardener/gardener/pkg/utils"
"github.com/gardener/gardener/pkg/utils/chart"
gutil "github.com/gardener/gardener/pkg/utils/gardener"
kutil "github.com/gardener/gardener/pkg/utils/kubernetes"
"github.com/gardener/gardener/pkg/utils/managedresources"
secretutils "github.com/gardener/gardener/pkg/utils/secrets"
secretsmanager "github.com/gardener/gardener/pkg/utils/secrets/manager"
monitoringv1 "github.com/prometheus-operator/prometheus-operator/pkg/apis/monitoring/v1"
Expand All @@ -43,6 +45,7 @@ import (
"k8s.io/apimachinery/pkg/types"
utilruntime "k8s.io/apimachinery/pkg/util/runtime"
vpaautoscalingv1 "k8s.io/autoscaler/vertical-pod-autoscaler/pkg/apis/autoscaling.k8s.io/v1"
"k8s.io/client-go/rest"
"k8s.io/utils/ptr"
k8sclient "sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/controller-runtime/pkg/manager"
Expand Down Expand Up @@ -359,6 +362,7 @@ var (
func NewValuesProvider(mgr manager.Manager, deployALBIngressController bool, customLabelDomain string) genericactuator.ValuesProvider {
return &valuesProvider{
client: mgr.GetClient(),
config: mgr.GetConfig(),
decoder: serializer.NewCodecFactory(mgr.GetScheme(), serializer.EnableStrict).UniversalDecoder(),
deployALBIngressController: deployALBIngressController,
customLabelDomain: customLabelDomain,
Expand All @@ -369,6 +373,7 @@ func NewValuesProvider(mgr manager.Manager, deployALBIngressController bool, cus
type valuesProvider struct {
genericactuator.NoopValuesProvider
client k8sclient.Client
config *rest.Config
decoder runtime.Decoder
deployALBIngressController bool
customLabelDomain string
Expand Down Expand Up @@ -736,6 +741,15 @@ func (vp *valuesProvider) getControlPlaneChartValues(ctx context.Context, cpConf
return nil, err
}

maps.Copy(controlPlaneValues, map[string]any{
"global": map[string]any{
"genericTokenKubeconfigSecretName": extensionscontroller.GenericTokenKubeconfigSecretNameFromCluster(cluster),
},
openstack.CloudControllerManagerName: ccm,
openstack.STACKITCloudControllerManagerName: stackitccm,
stackit.PodIdentityWebhookName: podIdentityWebhook,
})

storageCSIDriver := getCSIDriver(cpConfig)
switch storageCSIDriver {
case stackitv1alpha1.OPENSTACK:
Expand All @@ -750,19 +764,23 @@ func (vp *valuesProvider) getControlPlaneChartValues(ctx context.Context, cpConf
controlPlaneValues[openstack.CSIControllerName] = map[string]any{
"enabled": false,
}
// TODO: make it nice
namespace := cp.Namespace
if getCSICompatibilityMode(cpConfig) != stackitv1alpha1.DEFAULT {
err := vp.deploySeedCSICompatibilityMode(ctx, namespace, controlPlaneValues)
if err != nil {
return nil, fmt.Errorf("failed to deploy CSI CSI compatibility mode: %w", err)
}
} else {
err := vp.deleteSeedCSICompatibilityMode(ctx, namespace)
if err != nil {
return nil, fmt.Errorf("failed to deploy CSI CSI compatibility mode: %w", err)
}
}
default:
return nil, fmt.Errorf("unsupported storage CSI Driver: %s", storageCSIDriver)
}

maps.Copy(controlPlaneValues, map[string]any{
"global": map[string]any{
"genericTokenKubeconfigSecretName": extensionscontroller.GenericTokenKubeconfigSecretNameFromCluster(cluster),
},
openstack.CloudControllerManagerName: ccm,
openstack.STACKITCloudControllerManagerName: stackitccm,
stackit.PodIdentityWebhookName: podIdentityWebhook,
})

if vp.deployALBIngressController {
fmt.Println("deploying ALB Ingress Controller")
albcm, err := getSTACKITALBCMChartValues(cpConfig, cluster, infra, stackitCredentialsConfig, apiEndpoints, scaledDown, stackitRegion)
Expand Down Expand Up @@ -1070,12 +1088,24 @@ func (vp *valuesProvider) getControlPlaneShootChartValues(ctx context.Context, c

csiDriverInUse := getCSIDriver(cpConfig)
switch csiDriverInUse {
case stackitv1alpha1.STACKIT:
values[openstack.CSISTACKITNodeName] = csiDriverSTACKITValues
values[openstack.CSINodeName] = map[string]any{"enabled": false}
case stackitv1alpha1.OPENSTACK:
values[openstack.CSINodeName] = csiNodeDriverValues
values[openstack.CSISTACKITNodeName] = map[string]any{"enabled": false}
case stackitv1alpha1.STACKIT:
values[openstack.CSISTACKITNodeName] = csiDriverSTACKITValues
values[openstack.CSINodeName] = map[string]any{"enabled": false}
compatibilityMode := getCSICompatibilityMode(cpConfig)
namespace := cp.Namespace
if compatibilityMode != stackitv1alpha1.DEFAULT {
blockLegacyCreation := compatibilityMode == stackitv1alpha1.COMPATBLOCK
if err := vp.deployShootCSICompatibilityMode(ctx, namespace, values, blockLegacyCreation); err != nil {
return nil, fmt.Errorf("deploy shoot CSI compatibility mode: %w", err)
}
} else {
if err := vp.deleteShootCSICompatibilityMode(ctx, namespace); err != nil {
return nil, fmt.Errorf("delete shoot CSI compatibility mode: %w", err)
}
}
default:
return nil, fmt.Errorf("unsupported CSI driver type: %s", csiDriverInUse)
}
Expand Down Expand Up @@ -1176,6 +1206,124 @@ func (vp *valuesProvider) checkEmergencyLoadBalancerAccess(ctx context.Context,
return apiURL, apiToken, nil
}

func (vp *valuesProvider) deploySeedCSICompatibilityMode(ctx context.Context, namespace string, values map[string]any) error {
renderer, err := chartrenderer.NewForConfig(vp.config)
if err != nil {
return nil
}

// TODO: constant
chartName := "stackit-blockstorage-csi-driver"

// Get the chart Values
csiStackitValues := values[openstack.CSISTACKITControllerName].(map[string]any)
// Merge csiStackitValues to topLevel. Basically removes the openstack.CSISTACKITControllerName key
chartValues := gardenerutils.MergeMaps(values, csiStackitValues)
// Override chart values
chartValues["prefix"] = "stackit-compat"

//TODO: Use gardener tools for this? If possible
imagesToFind := []string{
"csi-driver-stackit",
"csi-provisioner",
"csi-attacher",
"csi-snapshotter",
"csi-resizer",
"csi-liveness-probe",
"csi-snapshot-controller",
}
images := imagevector.ImageVector()
imageMap := make(map[string]any)

for _, image := range imagesToFind {
foundImage, err := images.FindImage(image)
if err != nil {
return err
}
imageMap[image] = foundImage.String()
}
chartValues["images"] = imageMap

renderedChart, err := renderer.RenderEmbeddedFS(
charts.InternalChart,
filepath.Join(charts.InternalChartsPath, "seed-controlplane/charts/stackit-blockstorage-csi-driver"),
chartName,
"kube-system",
chartValues,
)
if err != nil {
return err
}

data := renderedChart.AsSecretData()
return managedresources.CreateForSeed(ctx, vp.client, namespace, "stackit-csi-compat-chart", false, data)
}

func (vp *valuesProvider) deleteSeedCSICompatibilityMode(ctx context.Context, namespace string) error {
return managedresources.DeleteForSeed(ctx, vp.client, namespace, "stackit-csi-compat-chart")
}

func (vp *valuesProvider) deployShootCSICompatibilityMode(ctx context.Context, namespace string, values map[string]any, blockLegacyCreation bool) error {
renderer, err := chartrenderer.NewForConfig(vp.config)
if err != nil {
return err
}

// TODO: constant
chartName := "stackit-blockstorage-csi-driver"

// Get the chart Values
csiStackitValues := values[openstack.CSISTACKITControllerName].(map[string]any)
// Merge csiStackitValues to topLevel. Basically removes the openstack.CSISTACKITControllerName key
chartValues := gardenerutils.MergeMaps(values, csiStackitValues)
// Override chart values
chartValues["prefix"] = "stackit-compat"

//TODO: Use gardener tools for this? If possible
imagesToFind := []string{
"csi-driver-stackit",
"csi-node-driver-registrar",
"csi-liveness-probe",
}
images := imagevector.ImageVector()
imageMap := make(map[string]any)

for _, image := range imagesToFind {
foundImage, err := images.FindImage(image)
if err != nil {
return err
}
imageMap[image] = foundImage.String()
}
chartValues["images"] = imageMap
chartValues["healthzPort"] = 9909
csiValues := map[string]any{
"enableCompatibilityMode": true,
}
if blockLegacyCreation {
csiValues["blockLegacyCreation"] = true
}
chartValues["csi"] = csiValues

renderedChart, err := renderer.RenderEmbeddedFS(
charts.InternalChart,
filepath.Join(charts.InternalChartsPath, "shoot-system-components/charts/stackit-blockstorage-csi-driver"),
chartName,
"kube-system",
chartValues,
)
if err != nil {
return err
}

data := renderedChart.AsSecretData()
return managedresources.CreateForShoot(ctx, vp.client, namespace, "stackit-csi-compat-shoot-chart", "gardener-extension-provider-stackit", false, data)
}

func (vp *valuesProvider) deleteShootCSICompatibilityMode(ctx context.Context, namespace string) error {
return managedresources.DeleteForShoot(ctx, vp.client, namespace, "stackit-csi-compat-shoot-chart")
}

// decodeLoadBalancerAPIEmergencySecret decodes a [corev1.Secret] for emergency loadbalancer access and
// returns the apiURL and apiToken to use or an error.
// The apiURL and apiToken are only set if both values exist inside the secret and are not empty.
Expand Down Expand Up @@ -1216,6 +1364,10 @@ func getCSIDriver(cpConfig *stackitv1alpha1.ControlPlaneConfig) stackitv1alpha1.
return stackitv1alpha1.ControllerName(cpConfig.Storage.CSI.Name)
}

func getCSICompatibilityMode(cpConfig *stackitv1alpha1.ControlPlaneConfig) stackitv1alpha1.CSICompatibilityMode {
return stackitv1alpha1.CSICompatibilityMode(cpConfig.Storage.CSI.CompatibilityMode)
}

func getCCMController(cpConfig *stackitv1alpha1.ControlPlaneConfig) stackitv1alpha1.ControllerName {
return stackitv1alpha1.ControllerName(cpConfig.CloudControllerManager.Name)
}
Expand Down