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

[GEP-7] Adds a DeployMigrateWaiter component to manage containerruntimes #2762

Merged
merged 1 commit into from
Aug 31, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
3 changes: 2 additions & 1 deletion pkg/api/extensions/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ func GetShootNamespacedCRsLists() []runtime.Object {
//&extensionsv1alpha1.NetworkList{},
&extensionsv1alpha1.OperatingSystemConfigList{},
&extensionsv1alpha1.WorkerList{},
&extensionsv1alpha1.ContainerRuntimeList{},
//The ContainerRuntime CR is now handled as a shoot component
//&extensionsv1alpha1.ContainerRuntimeList{},
}
}
4 changes: 2 additions & 2 deletions pkg/gardenlet/controller/shoot/shoot_control_delete.go
Original file line number Diff line number Diff line change
Expand Up @@ -346,12 +346,12 @@ func (c *Controller) runDeleteShootFlow(o *operation.Operation) *gardencorev1bet
})
deleteContainerRuntimeResources = g.Add(flow.Task{
Name: "Deleting container runtime resources",
Fn: flow.TaskFn(botanist.DeleteAllContainerRuntimeResources).RetryUntilTimeout(defaultInterval, defaultTimeout),
Fn: flow.TaskFn(botanist.Shoot.Components.Extensions.ContainerRuntime.Destroy).RetryUntilTimeout(defaultInterval, defaultTimeout),
Dependencies: flow.NewTaskIDs(initializeShootClients, cleanKubernetesResources, cleanShootNamespaces),
})
waitUntilContainerRuntimeResourcesDeleted = g.Add(flow.Task{
Name: "Waiting until stale container runtime resources are deleted",
Fn: botanist.WaitUntilContainerRuntimeResourcesDeleted,
Fn: botanist.Shoot.Components.Extensions.ContainerRuntime.WaitCleanup,
Dependencies: flow.NewTaskIDs(deleteContainerRuntimeResources),
})

Expand Down
12 changes: 6 additions & 6 deletions pkg/gardenlet/controller/shoot/shoot_control_reconcile.go
Original file line number Diff line number Diff line change
Expand Up @@ -400,23 +400,23 @@ func (c *Controller) runReconcileShootFlow(o *operation.Operation) *gardencorev1
})
deployContainerRuntimeResources = g.Add(flow.Task{
Name: "Deploying container runtime resources",
Fn: flow.TaskFn(botanist.DeployContainerRuntimeResources).RetryUntilTimeout(defaultInterval, defaultTimeout),
Fn: flow.TaskFn(botanist.DeployContainerRuntime).RetryUntilTimeout(defaultInterval, defaultTimeout),
Dependencies: flow.NewTaskIDs(deployReferencedResources, initializeShootClients),
})
_ = g.Add(flow.Task{
Name: "Waiting until container runtime resources are ready",
Fn: flow.TaskFn(botanist.WaitUntilContainerRuntimeResourcesReady),
Fn: botanist.Shoot.Components.Extensions.ContainerRuntime.Wait,
Dependencies: flow.NewTaskIDs(deployContainerRuntimeResources),
})
deleteStaleContainerRuntimeResources = g.Add(flow.Task{
deleteStaleResources = g.Add(flow.Task{
Name: "Delete stale container runtime resources",
Fn: flow.TaskFn(botanist.DeleteStaleContainerRuntimeResources).RetryUntilTimeout(defaultInterval, defaultTimeout),
Fn: flow.TaskFn(botanist.Shoot.Components.Extensions.ContainerRuntime.DeleteStaleResources).RetryUntilTimeout(defaultInterval, defaultTimeout),
Dependencies: flow.NewTaskIDs(initializeShootClients),
})
_ = g.Add(flow.Task{
Name: "Waiting until stale container runtime resources are deleted",
Fn: flow.TaskFn(botanist.WaitUntilContainerRuntimeResourcesDeleted).SkipIf(o.Shoot.HibernationEnabled),
Dependencies: flow.NewTaskIDs(deleteStaleContainerRuntimeResources),
Fn: flow.TaskFn(botanist.Shoot.Components.Extensions.ContainerRuntime.WaitCleanup).SkipIf(o.Shoot.HibernationEnabled),
Dependencies: flow.NewTaskIDs(deleteStaleResources),
})
_ = g.Add(flow.Task{
Name: "Restart control plane pods",
Expand Down
1 change: 1 addition & 0 deletions pkg/operation/botanist/botanist.go
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,7 @@ func New(o *operation.Operation) (*Botanist, error) {
}
o.Shoot.Components.Extensions.Infrastructure = b.DefaultInfrastructure(b.K8sSeedClient.DirectClient())
o.Shoot.Components.Extensions.Network = b.DefaultNetwork(b.K8sSeedClient.DirectClient())
o.Shoot.Components.Extensions.ContainerRuntime = b.DefaultContainerRuntime(b.K8sSeedClient.DirectClient())

// control plane components
o.Shoot.Components.ControlPlane.KubeAPIServerService = b.DefaultKubeAPIServerService()
Expand Down
153 changes: 20 additions & 133 deletions pkg/operation/botanist/containerruntime.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,146 +16,33 @@ package botanist

import (
"context"
"fmt"
"time"

v1beta1constants "github.com/gardener/gardener/pkg/apis/core/v1beta1/constants"
extensionsv1alpha1 "github.com/gardener/gardener/pkg/apis/extensions/v1alpha1"
"github.com/gardener/gardener/pkg/operation/common"
"github.com/gardener/gardener/pkg/operation/botanist/extensions/containerruntime"
"github.com/gardener/gardener/pkg/operation/shoot"
"github.com/gardener/gardener/pkg/utils/flow"

metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/util/sets"
"sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"
"sigs.k8s.io/controller-runtime/pkg/client"
)

// DeployContainerRuntimeResources creates a `Container runtime` resource in the shoot namespace in the seed
// cluster. Deploys one resource per CRI per Worker.
// Gardener waits until an external controller has reconciled the resources successfully.
func (b *Botanist) DeployContainerRuntimeResources(ctx context.Context) error {
var fns []flow.TaskFn

for _, worker := range b.Shoot.Info.Spec.Provider.Workers {
if worker.CRI == nil {
continue
}

for _, containerRuntime := range worker.CRI.ContainerRuntimes {
cr := containerRuntime
workerName := worker.Name

toApply := extensionsv1alpha1.ContainerRuntime{
ObjectMeta: metav1.ObjectMeta{
Name: getContainerRuntimeKey(cr.Type, workerName),
Namespace: b.Shoot.SeedNamespace,
},
}

fns = append(fns, func(ctx context.Context) error {
_, err := controllerutil.CreateOrUpdate(ctx, b.K8sSeedClient.Client(), &toApply, func() error {
metav1.SetMetaDataAnnotation(&toApply.ObjectMeta, v1beta1constants.GardenerOperation, v1beta1constants.GardenerOperationReconcile)
metav1.SetMetaDataAnnotation(&toApply.ObjectMeta, v1beta1constants.GardenerTimestamp, time.Now().UTC().String())
toApply.Spec.BinaryPath = extensionsv1alpha1.ContainerDRuntimeContainersBinFolder
toApply.Spec.Type = cr.Type
toApply.Spec.ProviderConfig = cr.ProviderConfig
toApply.Spec.WorkerPool.Name = workerName
toApply.Spec.WorkerPool.Selector.MatchLabels = map[string]string{v1beta1constants.LabelWorkerPool: workerName, v1beta1constants.LabelWorkerPoolDeprecated: workerName}
return nil
})
return err
})
}
}

return flow.Parallel(fns...)(ctx)
}

func getContainerRuntimeKey(criType, workerName string) string {
return fmt.Sprintf("%s-%s", criType, workerName)
}

// WaitUntilContainerRuntimeResourcesReady waits until all container runtime resources report `Succeeded` in their last operation state.
// The state must be reported before the passed context is cancelled or a container runtime's timeout has been reached.
// As soon as one timeout has been overstepped the function returns an error, further waits on container runtime will be aborted.
func (b *Botanist) WaitUntilContainerRuntimeResourcesReady(ctx context.Context) error {
var fns []flow.TaskFn
for _, worker := range b.Shoot.Info.Spec.Provider.Workers {
if worker.CRI == nil {
continue
}

for _, containerRuntime := range worker.CRI.ContainerRuntimes {
fns = append(fns, func(ctx context.Context) error {
return common.WaitUntilExtensionCRReady(
ctx,
b.K8sSeedClient.DirectClient(),
b.Logger,
func() runtime.Object { return &extensionsv1alpha1.ContainerRuntime{} },
"ContainerRuntime",
b.Shoot.SeedNamespace,
getContainerRuntimeKey(containerRuntime.Type, worker.Name),
DefaultInterval,
DefaultSevereThreshold,
shoot.ExtensionDefaultTimeout,
nil,
)
})
}
}

return flow.ParallelExitOnError(fns...)(ctx)
}

// DeleteStaleContainerRuntimeResources deletes unused container runtime resources from the shoot namespace in the seed.
func (b *Botanist) DeleteStaleContainerRuntimeResources(ctx context.Context) error {
wantedContainerRuntimeTypes := sets.NewString()
for _, worker := range b.Shoot.Info.Spec.Provider.Workers {
if worker.CRI != nil {
for _, containerRuntime := range worker.CRI.ContainerRuntimes {
key := getContainerRuntimeKey(containerRuntime.Type, worker.Name)
wantedContainerRuntimeTypes.Insert(key)
}
}
}
return b.deleteContainerRuntimeResources(ctx, wantedContainerRuntimeTypes)
}

// DeleteAllContainerRuntimeResources deletes all container runtime resources from the Shoot namespace in the Seed.
func (b *Botanist) DeleteAllContainerRuntimeResources(ctx context.Context) error {
return b.deleteContainerRuntimeResources(ctx, sets.NewString())
}

func (b *Botanist) deleteContainerRuntimeResources(ctx context.Context, wantedContainerRuntimeTypes sets.String) error {
return common.DeleteExtensionCRs(
ctx,
b.K8sSeedClient.Client(),
&extensionsv1alpha1.ContainerRuntimeList{},
func() extensionsv1alpha1.Object { return &extensionsv1alpha1.ContainerRuntime{} },
b.Shoot.SeedNamespace,
func(obj extensionsv1alpha1.Object) bool {
cr, ok := obj.(*extensionsv1alpha1.ContainerRuntime)
if !ok {
return false
}
return !wantedContainerRuntimeTypes.Has(getContainerRuntimeKey(cr.Spec.Type, cr.Spec.WorkerPool.Name))
// DefaultContainerRuntime creates the default deployer for the ContainerRuntime custom resource.
func (b *Botanist) DefaultContainerRuntime(seedClient client.Client) shoot.ContainerRuntime {
return containerruntime.New(
b.Logger,
seedClient,
&containerruntime.Values{
Namespace: b.Shoot.SeedNamespace,
Workers: b.Shoot.Info.Spec.Provider.Workers,
},
containerruntime.DefaultInterval,
containerruntime.DefaultSevereThreshold,
containerruntime.DefaultTimeout,
)
}

// WaitUntilContainerRuntimeResourcesDeleted waits until all container runtime resources are gone or the context is cancelled.
func (b *Botanist) WaitUntilContainerRuntimeResourcesDeleted(ctx context.Context) error {
return common.WaitUntilExtensionCRsDeleted(
ctx,
b.K8sSeedClient.DirectClient(),
b.Logger,
&extensionsv1alpha1.ContainerRuntimeList{},
func() extensionsv1alpha1.Object { return &extensionsv1alpha1.ContainerRuntime{} },
"ContainerRuntime",
b.Shoot.SeedNamespace,
DefaultInterval,
shoot.ExtensionDefaultTimeout,
nil,
)
// DeployContainerRuntime deploys the ContainerRuntime custom resources and triggers the restore operation in case
// the Shoot is in the restore phase of the control plane migration
func (b *Botanist) DeployContainerRuntime(ctx context.Context) error {
if b.isRestorePhase() {
return b.Shoot.Components.Extensions.ContainerRuntime.Restore(ctx, b.ShootState)
}
return b.Shoot.Components.Extensions.ContainerRuntime.Deploy(ctx)
}