Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

First part implementation of shoot migration for firewalls #308

Merged
merged 54 commits into from
Oct 24, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
54 commits
Select commit Hold shift + click to select a range
62296db
Implement shoot migration for firewall-controller-manager.
Gerrit91 May 2, 2023
bb417ca
Merge remote-tracking branch 'origin/master' into shoot-migration-for…
Gerrit91 May 10, 2023
0798c9b
Set controller config in delegate.
Gerrit91 May 11, 2023
bc7e342
Merge remote-tracking branch 'origin/master' into shoot-migration-for…
Gerrit91 May 31, 2023
bda0c98
Fixes from merging.
Gerrit91 May 31, 2023
b6b77e0
Fix.
Gerrit91 May 31, 2023
adf0857
Fix.
Gerrit91 May 31, 2023
08ed471
Fix.
Gerrit91 May 31, 2023
4197ffc
Resolve injection not working.
Gerrit91 Jun 1, 2023
a2a1a4e
Merge branch 'master' into shoot-migration-for-firewalls
Gerrit91 Jun 2, 2023
62a222d
Bump to g/g v1.51.
Gerrit91 Jun 2, 2023
c1ef996
Try injection into worker actuator.
Gerrit91 Jun 2, 2023
e75b1da
Add debugging output.
Gerrit91 Jun 2, 2023
01daeeb
Loosen up condition.
Gerrit91 Jun 2, 2023
9edce26
Fix linter.
Gerrit91 Jun 2, 2023
af2adcc
Fix.
Gerrit91 Jun 2, 2023
11d50a8
Fix.
Gerrit91 Jun 2, 2023
39aa80b
Fix linter.
Gerrit91 Jun 2, 2023
fe15be3
Progress.
Gerrit91 Jun 2, 2023
0c931a1
Generate controller registration.
Gerrit91 Jun 2, 2023
e21d47d
Use nodes cidr from shoot if possible.
Gerrit91 Jun 2, 2023
211c5b2
Wait for FCM.
Gerrit91 Jun 2, 2023
f39e9b1
Remove mon finalizers.
Gerrit91 Jun 2, 2023
6a1c83c
Fix.
Gerrit91 Jun 2, 2023
a82f5aa
Fix.
Gerrit91 Jun 2, 2023
aff5368
Add finalizer to firewall deployment.
Gerrit91 Jun 2, 2023
bef193a
Orphan the dependents.
Gerrit91 Jun 2, 2023
5b3c5e4
Copy migration secrets.
Gerrit91 Jun 5, 2023
e397e2d
Refinements.
Gerrit91 Jun 7, 2023
97972ff
Fix filter.
Gerrit91 Jun 13, 2023
e946120
More logging.
Gerrit91 Jun 13, 2023
0aefbb3
Try saving state in infrastature status.
Gerrit91 Jun 13, 2023
cb8d00b
Try storing everything in infra state.
Gerrit91 Jun 13, 2023
0a183f7
Trying to save some space by encoding with sigs yaml.
Gerrit91 Jun 13, 2023
e6eb4dd
Tidy.
Gerrit91 Jun 13, 2023
b0609b3
Fix namespace.
Gerrit91 Jun 13, 2023
eb8abd9
Try saving in clean text.
Gerrit91 Jun 13, 2023
2677175
Updates.
Gerrit91 Jun 13, 2023
c66fd2a
Status can be empty.
Gerrit91 Jun 13, 2023
9734255
Set service account uid.
Gerrit91 Jun 13, 2023
46e3aea
Do not store infra status again.
Gerrit91 Jun 13, 2023
1c07238
Trying to back off.
Gerrit91 Jun 13, 2023
5b67cbc
Merge branch 'master' into shoot-migration-for-firewalls
Gerrit91 Jun 20, 2023
d76199e
Private for now.
Gerrit91 Jun 20, 2023
b6e3100
Add back SSH key.
Gerrit91 Jun 20, 2023
4696269
Do everything in worker controller.
Gerrit91 Jun 20, 2023
ba81784
Fix.
Gerrit91 Jun 20, 2023
f7d9b87
Save without managed fields.
Gerrit91 Jun 20, 2023
369c1f5
Use sigs yaml.
Gerrit91 Jun 20, 2023
a8a9ecc
Merge branch 'master' into shoot-migration-for-firewalls
Gerrit91 Jun 27, 2023
82e1001
No need to store service accounts, it does not work.
Gerrit91 Jun 27, 2023
55d0c70
Merge remote-tracking branch 'origin/master' into shoot-migration-for…
Gerrit91 Oct 12, 2023
0a5a09b
Add cleanup of validation and mutation webhooks.
Gerrit91 Oct 23, 2023
76b6446
Merge remote-tracking branch 'origin/master' into shoot-migration-for…
Gerrit91 Oct 23, 2023
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
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ require (
k8s.io/component-base v0.26.3
k8s.io/kubelet v0.26.3
sigs.k8s.io/controller-runtime v0.14.6
sigs.k8s.io/yaml v1.3.0
)

require (
Expand Down Expand Up @@ -161,7 +162,6 @@ require (
sigs.k8s.io/controller-tools v0.11.3 // indirect
sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd // indirect
sigs.k8s.io/structured-merge-diff/v4 v4.2.3 // indirect
sigs.k8s.io/yaml v1.3.0 // indirect
)

replace (
Expand Down
32 changes: 31 additions & 1 deletion pkg/controller/infrastructure/actuator_delete.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,12 @@ import (
"github.com/metal-stack/metal-go/api/models"

extensionscontroller "github.com/gardener/gardener/extensions/pkg/controller"
extensionsv1alpha1 "github.com/gardener/gardener/pkg/apis/extensions/v1alpha1"
"github.com/gardener/gardener/pkg/controllerutils/reconciler"

extensionsv1alpha1 "github.com/gardener/gardener/pkg/apis/extensions/v1alpha1"
admissionregistrationv1 "k8s.io/api/admissionregistration/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"sigs.k8s.io/controller-runtime/pkg/client"
)

type networkDeleter struct {
Expand Down Expand Up @@ -70,6 +73,33 @@ func (a *actuator) Delete(ctx context.Context, logger logr.Logger, infrastructur
}
}

// the valuesprovider is unable to cleanup the mutating and validating webhooks
// because these are not namespaced and the names are determined at runtime
//
// so we clean it up here after control plane has terminated.

name := "firewall-controller-manager-" + cluster.ObjectMeta.Name

mwc := &admissionregistrationv1.MutatingWebhookConfiguration{
ObjectMeta: metav1.ObjectMeta{
Name: name,
},
}
err = a.client.Delete(ctx, mwc)
if client.IgnoreNotFound(err) != nil {
return fmt.Errorf("unable to cleanup firewall-controller-manager mutating webhook")
}

vwc := &admissionregistrationv1.ValidatingWebhookConfiguration{
ObjectMeta: metav1.ObjectMeta{
Name: name,
},
}
err = a.client.Delete(ctx, vwc)
if client.IgnoreNotFound(err) != nil {
return fmt.Errorf("unable to cleanup firewall-controller-manager validating webhook")
}

return nil
}

Expand Down
234 changes: 150 additions & 84 deletions pkg/controller/worker/actuator.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ package worker

import (
"context"
"fmt"
"time"

"github.com/gardener/gardener/extensions/pkg/util"

Expand All @@ -12,7 +14,11 @@ import (
apismetal "github.com/metal-stack/gardener-extension-provider-metal/pkg/apis/metal"
"github.com/metal-stack/gardener-extension-provider-metal/pkg/imagevector"
"github.com/metal-stack/gardener-extension-provider-metal/pkg/metal"
metalclient "github.com/metal-stack/gardener-extension-provider-metal/pkg/metal/client"
metalv1alpha1 "github.com/metal-stack/machine-controller-manager-provider-metal/pkg/provider/migration/legacy-api/machine/v1alpha1"
metalgo "github.com/metal-stack/metal-go"
"github.com/metal-stack/metal-go/api/models"
"github.com/metal-stack/metal-lib/pkg/cache"

extensionsv1alpha1 "github.com/gardener/gardener/pkg/apis/extensions/v1alpha1"
gardener "github.com/gardener/gardener/pkg/client/kubernetes"
Expand All @@ -26,140 +32,200 @@ import (

"sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/controller-runtime/pkg/log"
"sigs.k8s.io/controller-runtime/pkg/runtime/inject"
)

type delegateFactory struct {
logger logr.Logger
type (
// actuator reconciles the cluster's worker nodes and the firewalls.
// we are wrapping gardener's worker actuator here because we need to intercept the migrate call from the actuator.
// unfortunately, there is no callback provided which we could use for this.
//
// why is the firewall reconciliation here and not in the controlplane controller?
//
// the controlplane controller deploys the firewall-controller-manager including validating and mutating webhooks
// this has to be running before we can create a firewall deployment because the mutating webhook is creating the userdata
// the worker controller acts after the controlplane controller, also the terms and responsibilities are pretty similar between machine-controller-manager and firewall-controller-manager,
// so this place seems to be a valid fit.
actuator struct {
controllerConfig config.ControllerConfiguration

workerActuator worker.Actuator

networkCache *cache.Cache[*cacheKey, *models.V1NetworkResponse]

restConfig *rest.Config
client client.Client
scheme *runtime.Scheme
decoder runtime.Decoder
}

restConfig *rest.Config
delegateFactory struct {
controllerConfig config.ControllerConfiguration

client client.Client
scheme *runtime.Scheme
decoder runtime.Decoder
clientGetter func() (*rest.Config, client.Client, *runtime.Scheme, runtime.Decoder)
dataGetter func(ctx context.Context, worker *extensionsv1alpha1.Worker, cluster *extensionscontroller.Cluster) (*additionalData, error)

machineImageMapping []config.MachineImage
controllerConfig config.ControllerConfiguration
}
machineImageMapping []config.MachineImage
}

// NewActuator creates a new Actuator that updates the status of the handled WorkerPoolConfigs.
func NewActuator(machineImages []config.MachineImage, controllerConfig config.ControllerConfiguration) worker.Actuator {
delegateFactory := &delegateFactory{
logger: log.Log.WithName("worker-actuator"),
machineImageMapping: machineImages,
controllerConfig: controllerConfig,
workerDelegate struct {
logger logr.Logger

client client.Client
scheme *runtime.Scheme
decoder runtime.Decoder

machineImageMapping []config.MachineImage
seedChartApplier gardener.ChartApplier
serverVersion string

cluster *extensionscontroller.Cluster
worker *extensionsv1alpha1.Worker

machineClasses []map[string]interface{}
machineDeployments worker.MachineDeployments
machineImages []apismetal.MachineImage

controllerConfig config.ControllerConfiguration
additionalData *additionalData
}
return genericactuator.NewActuator(
delegateFactory,
metal.MachineControllerManagerName,
mcmChart,
mcmShootChart,
imagevector.ImageVector(),
extensionscontroller.ChartRendererFactoryFunc(util.NewChartRendererForShoot),
)
)

func (a *actuator) InjectFunc(f inject.Func) error {
return f(a.workerActuator)
}

func (d *delegateFactory) InjectScheme(scheme *runtime.Scheme) error {
func (a *actuator) InjectScheme(scheme *runtime.Scheme) error {
scheme.AddKnownTypes(metalv1alpha1.SchemeGroupVersion,
&metalv1alpha1.MetalMachineClass{},
&metalv1alpha1.MetalMachineClassList{},
)
d.scheme = scheme
d.decoder = serializer.NewCodecFactory(scheme).UniversalDecoder()
a.scheme = scheme
a.decoder = serializer.NewCodecFactory(scheme).UniversalDecoder()
return nil
}

func (d *delegateFactory) InjectConfig(restConfig *rest.Config) error {
d.restConfig = restConfig
func (a *actuator) InjectClient(client client.Client) error {
a.client = client
return nil
}

func (d *delegateFactory) InjectClient(client client.Client) error {
d.client = client
func (a *actuator) InjectConfig(restConfig *rest.Config) error {
a.restConfig = restConfig
return nil
}

func (d *delegateFactory) WorkerDelegate(ctx context.Context, worker *extensionsv1alpha1.Worker, cluster *extensionscontroller.Cluster) (genericactuator.WorkerDelegate, error) {
clientset, err := kubernetes.NewForConfig(d.restConfig)
if err != nil {
return nil, err
func NewActuator(machineImages []config.MachineImage, controllerConfig config.ControllerConfiguration) worker.Actuator {
a := &actuator{
controllerConfig: controllerConfig,
networkCache: cache.New(15*time.Minute, func(ctx context.Context, accessor *cacheKey) (*models.V1NetworkResponse, error) {
mclient, ok := ctx.Value(ClientKey).(metalgo.Client)
if !ok {
return nil, fmt.Errorf("no client passed in context")
}
privateNetwork, err := metalclient.GetPrivateNetworkFromNodeNetwork(ctx, mclient, accessor.projectID, accessor.nodeCIDR)
if err != nil {
return nil, err
}
return privateNetwork, nil
}),
}

serverVersion, err := clientset.Discovery().ServerVersion()
if err != nil {
return nil, err
delegateFactory := &delegateFactory{
clientGetter: func() (*rest.Config, client.Client, *runtime.Scheme, runtime.Decoder) {
return a.restConfig, a.client, a.scheme, a.decoder
},
dataGetter: a.getAdditionalData,
controllerConfig: controllerConfig,
machineImageMapping: machineImages,
}

seedChartApplier, err := gardener.NewChartApplierForConfig(d.restConfig)
a.workerActuator = genericactuator.NewActuator(
delegateFactory,
metal.MachineControllerManagerName,
mcmChart,
mcmShootChart,
imagevector.ImageVector(),
extensionscontroller.ChartRendererFactoryFunc(util.NewChartRendererForShoot),
)

return a
}

func (a *actuator) Reconcile(ctx context.Context, log logr.Logger, worker *extensionsv1alpha1.Worker, cluster *extensionscontroller.Cluster) error {
err := a.firewallReconcile(ctx, log, worker, cluster)
if err != nil {
return nil, err
return err
}

return NewWorkerDelegate(
d.logger,
d.client,
d.scheme,
d.decoder,
return a.workerActuator.Reconcile(ctx, log, worker, cluster)
}

d.machineImageMapping,
seedChartApplier,
serverVersion.GitVersion,
func (a *actuator) Delete(ctx context.Context, log logr.Logger, worker *extensionsv1alpha1.Worker, cluster *extensionscontroller.Cluster) error {
err := a.workerActuator.Delete(ctx, log, worker, cluster)
if err != nil {
return err
}

worker,
cluster,
d.controllerConfig,
), nil
return a.firewallDelete(ctx, log, cluster)
}

type workerDelegate struct {
logger logr.Logger
func (a *actuator) Migrate(ctx context.Context, log logr.Logger, worker *extensionsv1alpha1.Worker, cluster *extensionscontroller.Cluster) error {
err := a.workerActuator.Migrate(ctx, log, worker, cluster)
if err != nil {
return err
}

client client.Client
scheme *runtime.Scheme
decoder runtime.Decoder
return a.firewallMigrate(ctx, log, cluster)
}

machineImageMapping []config.MachineImage
seedChartApplier gardener.ChartApplier
serverVersion string
func (a *actuator) Restore(ctx context.Context, log logr.Logger, worker *extensionsv1alpha1.Worker, cluster *extensionscontroller.Cluster) error {
err := a.firewallRestore(ctx, log, worker, cluster)
if err != nil {
return err
}

cluster *extensionscontroller.Cluster
worker *extensionsv1alpha1.Worker
return a.workerActuator.Restore(ctx, log, worker, cluster)
}

machineClasses []map[string]interface{}
machineDeployments worker.MachineDeployments
machineImages []apismetal.MachineImage
func (d *delegateFactory) WorkerDelegate(ctx context.Context, worker *extensionsv1alpha1.Worker, cluster *extensionscontroller.Cluster) (genericactuator.WorkerDelegate, error) {
config, client, scheme, decoder := d.clientGetter()

controllerConfig config.ControllerConfiguration
}
clientset, err := kubernetes.NewForConfig(config)
if err != nil {
return nil, err
}

// NewWorkerDelegate creates a new context for a worker reconciliation.
func NewWorkerDelegate(
logger logr.Logger,
client client.Client,
scheme *runtime.Scheme,
decoder runtime.Decoder,
serverVersion, err := clientset.Discovery().ServerVersion()
if err != nil {
return nil, err
}

machineImageMapping []config.MachineImage,
seedChartApplier gardener.ChartApplier,
serverVersion string,
seedChartApplier, err := gardener.NewChartApplierForConfig(config)
if err != nil {
return nil, err
}

worker *extensionsv1alpha1.Worker,
cluster *extensionscontroller.Cluster,
controllerConfig config.ControllerConfiguration,
additionalData, err := d.dataGetter(ctx, worker, cluster)
if err != nil {
return nil, err
}

) genericactuator.WorkerDelegate {
return &workerDelegate{
logger: logger,
logger: log.Log.WithName("metal-worker-delegate").WithValues("cluster", cluster.ObjectMeta.Name),

client: client,
scheme: scheme,
decoder: decoder,

machineImageMapping: machineImageMapping,
machineImageMapping: d.machineImageMapping,
seedChartApplier: seedChartApplier,
serverVersion: serverVersion,
serverVersion: serverVersion.GitVersion,

cluster: cluster,
worker: worker,

controllerConfig: controllerConfig,
}
controllerConfig: d.controllerConfig,
additionalData: additionalData,
}, nil
}
Loading