Skip to content
Open
25 changes: 22 additions & 3 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,6 @@ LEADER_ELECTION := false
REGION := eu01
FLOATING_POOL_NAME := floating-net

INFRA_TEST_FLAGS := --region='$(REGION)'

SHELL=/usr/bin/env bash -o pipefail

#########################################
Expand Down Expand Up @@ -148,6 +146,7 @@ cleanup-crds:
gardener-crds:
@cp $(GARDENER_DIR)/example/seed-crds/10-crd-extensions.gardener.cloud_clusters.yaml $(UPSTREAM_CRDS_DIR)
@cp $(GARDENER_DIR)/example/seed-crds/10-crd-extensions.gardener.cloud_infrastructures.yaml $(UPSTREAM_CRDS_DIR)
@cp $(GARDENER_DIR)/example/seed-crds/10-crd-extensions.gardener.cloud_selfhostedshootexposures.yaml $(UPSTREAM_CRDS_DIR)

.PHONY: test
test: $(REPORT_COLLECTOR) $(SETUP_ENVTEST) ## Runs the unit-test suite
Expand All @@ -163,6 +162,16 @@ verify: check check-format test ## Run check, format and test
.PHONY: verify-extended
verify-extended: check-generate check check-format test ## Run check-generate, check, format and test

.PHONY: test-integration
test-integration: $(REPORT_COLLECTOR) $(SETUP_ENVTEST) $(GINKGO) ## Run all integration tests
@GINKGO=$(GINKGO) ./hack/test-integration.sh \
-v --show-node-events \
--procs 2 --timeout 20m \
--grace-period 3m \
./test/integration/... \
-- \
--region='$(REGION)'

.PHONY: test-integration-infra
test-integration-infra: $(REPORT_COLLECTOR) $(SETUP_ENVTEST) $(GINKGO) ## Run infrastructure integration tests
@GINKGO=$(GINKGO) ./hack/test-integration.sh \
Expand All @@ -171,7 +180,17 @@ test-integration-infra: $(REPORT_COLLECTOR) $(SETUP_ENVTEST) $(GINKGO) ## Run in
--grace-period 3m \
./test/integration/infrastructure/stackit \
-- \
$(INFRA_TEST_FLAGS)
--region='$(REGION)'

.PHONY: test-integration-exposure
test-integration-exposure: $(REPORT_COLLECTOR) $(SETUP_ENVTEST) $(GINKGO) ## Run selfhostedshootexposure integration tests
Comment thread
jamand marked this conversation as resolved.
@GINKGO=$(GINKGO) ./hack/test-integration.sh \
-v --show-node-events \
--timeout 20m \
--grace-period 3m \
./test/integration/selfhostedshootexposure/stackit \
-- \
--region='$(REGION)'

help: ## Display this help
@awk 'BEGIN {FS = ":.*##"; printf "\nUsage:\n make \033[36m\033[0m\n"} /^[a-zA-Z_-]+:.*?##/ { printf " \033[36m%-15s\033[0m %s\n", $$1, $$2 } /^##@/ { printf "\n\033[1m%s\033[0m\n", substr($$0, 5) } ' $(MAKEFILE_LIST)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ spec:
- --heartbeat-renew-interval-seconds={{ .Values.controllers.heartbeat.renewIntervalSeconds }}
- --infrastructure-max-concurrent-reconciles={{ .Values.controllers.infrastructure.concurrentSyncs }}
- --ignore-operation-annotation={{ .Values.controllers.ignoreOperationAnnotation }}
Comment thread
jamand marked this conversation as resolved.
- --selfhostedshootexposure-max-concurrent-reconciles={{ .Values.controllers.selfhostedshootexposure.concurrentSyncs }}
- --worker-max-concurrent-reconciles={{ .Values.controllers.worker.concurrentSyncs }}
- --webhook-config-namespace={{ .Release.Namespace }}
- --webhook-config-service-port={{ .Values.webhookConfig.servicePort }}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ rules:
- dnsrecords/status
- infrastructures
- infrastructures/status
- selfhostedshootexposures
- selfhostedshootexposures/status
- workers
- workers/status
verbs:
Expand Down
2 changes: 2 additions & 0 deletions charts/gardener-extension-provider-stackit/values.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@ controllers:
renewIntervalSeconds: 30
infrastructure:
concurrentSyncs: 5
selfhostedshootexposure:
concurrentSyncs: 5
worker:
concurrentSyncs: 5
ignoreOperationAnnotation: false
Expand Down
9 changes: 9 additions & 0 deletions cmd/gardener-extension-provider-stackit/app/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ import (
stackitdnsrecord "github.com/stackitcloud/gardener-extension-provider-stackit/v2/pkg/controller/dnsrecord"
"github.com/stackitcloud/gardener-extension-provider-stackit/v2/pkg/controller/healthcheck"
"github.com/stackitcloud/gardener-extension-provider-stackit/v2/pkg/controller/infrastructure"
stackitselfhostedshootexposure "github.com/stackitcloud/gardener-extension-provider-stackit/v2/pkg/controller/selfhostedshootexposure"
stackitworker "github.com/stackitcloud/gardener-extension-provider-stackit/v2/pkg/controller/worker"
"github.com/stackitcloud/gardener-extension-provider-stackit/v2/pkg/feature"
"github.com/stackitcloud/gardener-extension-provider-stackit/v2/pkg/stackit"
Expand Down Expand Up @@ -92,6 +93,11 @@ func NewControllerManagerCommand(ctx context.Context) *cobra.Command {
MaxConcurrentReconciles: 5,
}

// options for the selfhostedshootexposure controller
selfHostedShootExposureCtrlOpts = &controllercmd.ControllerOptions{
MaxConcurrentReconciles: 5,
}

// options for the worker controller
workerCtrlOpts = &controllercmd.ControllerOptions{
MaxConcurrentReconciles: 5,
Expand Down Expand Up @@ -121,6 +127,7 @@ func NewControllerManagerCommand(ctx context.Context) *cobra.Command {
controllercmd.PrefixOption("controlplane-", controlPlaneCtrlOpts),
controllercmd.PrefixOption("dnsrecord-", dnsRecordCtrlOpts),
controllercmd.PrefixOption("infrastructure-", infraCtrlOpts),
controllercmd.PrefixOption("selfhostedshootexposure-", selfHostedShootExposureCtrlOpts),
controllercmd.PrefixOption("worker-", workerCtrlOpts),
controllercmd.PrefixOption("healthcheck-", healthCheckCtrlOpts),
controllercmd.PrefixOption("heartbeat-", heartbeatCtrlOpts),
Expand Down Expand Up @@ -197,12 +204,14 @@ func NewControllerManagerCommand(ctx context.Context) *cobra.Command {
heartbeatCtrlOpts.Completed().Apply(&heartbeat.DefaultAddOptions)
configFileOpts.Completed().ApplyCustomLabelDomain(&infrastructure.DefaultAddOptions.CustomLabelDomain)
infraCtrlOpts.Completed().Apply(&infrastructure.DefaultAddOptions.Controller)
selfHostedShootExposureCtrlOpts.Completed().Apply(&stackitselfhostedshootexposure.DefaultAddOptions.Controller)
workerCtrlOpts.Completed().Apply(&stackitworker.DefaultAddOptions.Controller)

reconcileOpts.Completed().Apply(&stackitbastion.DefaultAddOptions.IgnoreOperationAnnotation, &stackitbastion.DefaultAddOptions.ExtensionClasses)
reconcileOpts.Completed().Apply(&stackitcontrolplane.DefaultAddOptions.IgnoreOperationAnnotation, &stackitcontrolplane.DefaultAddOptions.ExtensionClasses)
reconcileOpts.Completed().Apply(&stackitdnsrecord.DefaultAddOptions.IgnoreOperationAnnotation, &stackitdnsrecord.DefaultAddOptions.ExtensionClasses)
reconcileOpts.Completed().Apply(&infrastructure.DefaultAddOptions.IgnoreOperationAnnotation, &infrastructure.DefaultAddOptions.ExtensionClasses)
reconcileOpts.Completed().Apply(&stackitselfhostedshootexposure.DefaultAddOptions.IgnoreOperationAnnotation, &stackitselfhostedshootexposure.DefaultAddOptions.ExtensionClasses)
reconcileOpts.Completed().Apply(&stackitworker.DefaultAddOptions.IgnoreOperationAnnotation, &stackitworker.DefaultAddOptions.ExtensionClasses)

stackitworker.DefaultAddOptions.GardenCluster = gardenCluster
Expand Down
14 changes: 7 additions & 7 deletions docs/cloudprovider.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,13 +27,13 @@ stringData:

The service account needs the following permissions:

| Permission | Purpose |
| ------------------------------ | ------------------------------------------------ |
| `nlb.admin` | CCM service-controller and network load balancer |
| `blockstorage.admin` | CSI driver |
| `compute.admin` | CCM node-controller and MCM |
| `iaas.network.admin` | bastion and infrastructure controller |
| `iaas.isoplated-network.admin` | infrastructure controller |
| Permission | Purpose |
| ------------------------------ | --------------------------------------------------------------------------------------- |
| `nlb.admin` | CCM service-controller, network load balancer and self-hosted shoot exposure controller |
| `blockstorage.admin` | CSI driver |
| `compute.admin` | CCM node-controller and MCM |
| `iaas.network.admin` | bastion and infrastructure controller |
| `iaas.isolated-network.admin` | infrastructure controller |

## CloudProfileConfig Fields

Expand Down
17 changes: 17 additions & 0 deletions docs/testing.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
# Integration Tests

## Infrastructure

The infraflow code path of the infrastructure controller contains nearly no unit tests, as it primarily consists
of code interacting with the STACKIT IaaS API. Instead, these code paths are tested via the `infrastructure` integration
tests.
Expand All @@ -15,3 +17,18 @@ make test-integration-infra
The `STACKIT_SERVICE_ACCOUNT_KEY` is simply the JSON struct obtained from the Portal or API, when creating a new Service-Account key.
Additionally the ServiceAccount also needs to have the `iaas.network.admin` as well as the `iaas.isolated-network.admin` roles in-order to
create all necessary resources via the API.

## SelfHostedShootExposure

The `selfhostedshootexposure` controller provisions an NLB through the STACKIT Network Load Balancer API. Run the integration tests via:

```bash
export STACKIT_PROJECT_ID=<PROJECT_ID>
export STACKIT_SERVICE_ACCOUNT_KEY=$(pbpaste)
make test-integration-exposure
```

The ServiceAccount needs the same level of access as the infra tests (it provisions an isolated
network used as the LB's target network) plus permissions to create/update/delete STACKIT load
balancers. In practice, the `owner` role on the project (or a parent folder) covers everything
the suite does.
122 changes: 122 additions & 0 deletions hack/api-reference/api.md
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,44 @@ string
</table>


<h3 id="accesscontrol">AccessControl
</h3>


<p>
(<em>Appears on:</em><a href="#loadbalancer">LoadBalancer</a>)
</p>

<p>
AccessControl restricts access to the load balancer by source IP range.
</p>

<table>
<thead>
<tr>
<th>Field</th>
<th>Description</th>
</tr>
</thead>
<tbody>

<tr>
<td>
<code>allowedSourceRanges</code></br>
<em>
string array
</em>
</td>
<td>
<em>(Optional)</em>
<p>AllowedSourceRanges is the list of CIDRs permitted to reach the load balancer.<br />An empty or missing list means no source-IP restriction is applied.</p>
</td>
</tr>

</tbody>
</table>


<h3 id="applicationloadbalancerconfig">ApplicationLoadBalancerConfig
</h3>

Expand Down Expand Up @@ -971,6 +1009,56 @@ string
</table>


<h3 id="loadbalancer">LoadBalancer
</h3>


<p>
(<em>Appears on:</em><a href="#selfhostedshootexposureconfig">SelfHostedShootExposureConfig</a>)
</p>

<p>
LoadBalancer contains configuration for the load balancer.
</p>

<table>
<thead>
<tr>
<th>Field</th>
<th>Description</th>
</tr>
</thead>
<tbody>

<tr>
<td>
<code>planID</code></br>
<em>
string
</em>
</td>
<td>
<em>(Optional)</em>
<p>PlanID specifies the service plan (size) of the load balancer.<br />Currently supported plans are p10, p50, p250, p750 (compare API docs).<br />See https://docs.stackit.cloud/products/network/load-balancing-and-content-delivery/network-load-balancer/reference/service-plans/<br />Defaults to "p10".</p>
</td>
</tr>
<tr>
<td>
<code>accessControl</code></br>
<em>
<a href="#accesscontrol">AccessControl</a>
</em>
</td>
<td>
<em>(Optional)</em>
<p>AccessControl restricts which source IP ranges may reach the load balancer.</p>
</td>
</tr>

</tbody>
</table>


<h3 id="machineimage">MachineImage
</h3>

Expand Down Expand Up @@ -1686,6 +1774,40 @@ string
</table>


<h3 id="selfhostedshootexposureconfig">SelfHostedShootExposureConfig
</h3>


<p>
SelfHostedShootExposureConfig contains configuration settings for exposing self-hosted shoots.
</p>

<table>
<thead>
<tr>
<th>Field</th>
<th>Description</th>
</tr>
</thead>
<tbody>

<tr>
<td>
<code>loadBalancer</code></br>
<em>
<a href="#loadbalancer">LoadBalancer</a>
</em>
</td>
<td>
<em>(Optional)</em>
<p>LoadBalancer contains configuration for the load balancer.</p>
</td>
</tr>

</tbody>
</table>


<h3 id="servergroupdependency">ServerGroupDependency
</h3>

Expand Down
12 changes: 12 additions & 0 deletions pkg/apis/stackit/v1alpha1/defaults.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,22 @@ import (
"k8s.io/apimachinery/pkg/runtime"
)

// DefaultLoadBalancerPlanID is the default LB service plan for SelfHostedShootExposure.
const DefaultLoadBalancerPlanID = "p10"

func addDefaultingFuncs(scheme *runtime.Scheme) error {
return RegisterDefaults(scheme)
}

func SetDefaults_SelfHostedShootExposureConfig(obj *SelfHostedShootExposureConfig) {
if obj.LoadBalancer == nil {
obj.LoadBalancer = &LoadBalancer{}
}
if obj.LoadBalancer.PlanID == nil {
obj.LoadBalancer.PlanID = new(DefaultLoadBalancerPlanID)
}
}

func SetDefaults_ControlPlaneConfig(obj *ControlPlaneConfig) {
if obj == nil {
obj = &ControlPlaneConfig{}
Expand Down
7 changes: 4 additions & 3 deletions pkg/apis/stackit/v1alpha1/register.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,12 +39,13 @@ func init() {
func addKnownTypes(scheme *runtime.Scheme) error {
scheme.AddKnownTypes(SchemeGroupVersion,
&CloudProfileConfig{},
&ControlPlaneConfig{},
&InfrastructureConfig{},
&InfrastructureStatus{},
&InfrastructureState{},
&ControlPlaneConfig{},
&WorkerStatus{},
&InfrastructureStatus{},
&SelfHostedShootExposureConfig{},
&WorkerConfig{},
&WorkerStatus{},
)
Comment thread
jamand marked this conversation as resolved.
return nil
}
38 changes: 38 additions & 0 deletions pkg/apis/stackit/v1alpha1/types_selfhostedshootexposure.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package v1alpha1

import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)

// +genclient
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object

// SelfHostedShootExposureConfig contains configuration settings for exposing self-hosted shoots.
type SelfHostedShootExposureConfig struct {
metav1.TypeMeta `json:",inline"`

// LoadBalancer contains configuration for the load balancer.
// +optional
LoadBalancer *LoadBalancer `json:"loadBalancer,omitempty"`
}

// LoadBalancer contains configuration for the load balancer.
type LoadBalancer struct {
// PlanID specifies the service plan (size) of the load balancer.
// Currently supported plans are p10, p50, p250, p750 (compare API docs).
Comment thread
jamand marked this conversation as resolved.
// See https://docs.stackit.cloud/products/network/load-balancing-and-content-delivery/network-load-balancer/reference/service-plans/
// Defaults to "p10".
// +optional
PlanID *string `json:"planID,omitempty"`
// AccessControl restricts which source IP ranges may reach the load balancer.
// +optional
AccessControl *AccessControl `json:"accessControl,omitempty"`
}

// AccessControl restricts access to the load balancer by source IP range.
type AccessControl struct {
// AllowedSourceRanges is the list of CIDRs permitted to reach the load balancer.
// An empty or missing list means no source-IP restriction is applied.
// +optional
AllowedSourceRanges []string `json:"allowedSourceRanges,omitempty"`
}
Loading