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

Use SSA for updating addon channel objects #14074

Merged
merged 1 commit into from
Jul 30, 2022
Merged
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
83 changes: 37 additions & 46 deletions channels/pkg/channels/apply.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,17 +18,19 @@ package channels

import (
"context"
"encoding/json"
"fmt"

"go.uber.org/multierr"
"k8s.io/apimachinery/pkg/api/meta"
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/apimachinery/pkg/types"
"k8s.io/client-go/dynamic"
"k8s.io/client-go/restmapper"
"k8s.io/klog/v2"
"k8s.io/kops/pkg/kubemanifest"
"k8s.io/kops/upup/pkg/fi"
)

type Applier struct {
Expand Down Expand Up @@ -84,59 +86,48 @@ func (p *Applier) applyObjectsOfKind(ctx context.Context, gvk schema.GroupVersio
}

func (p *Applier) applyObjects(ctx context.Context, restMapping *meta.RESTMapping, expectedObjects []*kubemanifest.Object) error {
gvr := restMapping.Resource

baseResource := p.Client.Resource(gvr)
var merr error

actualObjects, err := baseResource.List(ctx, v1.ListOptions{})
if err != nil {
return fmt.Errorf("error listing objects: %w", err)
for _, expectedObject := range expectedObjects {
err := p.patchObject(ctx, restMapping, expectedObject)
merr = multierr.Append(merr, err)
}

actualMap := make(map[string]unstructured.Unstructured)
for _, actualObject := range actualObjects.Items {
key := actualObject.GetNamespace() + "/" + actualObject.GetName()
actualMap[key] = actualObject
}
return merr
}

var merr error
func (p *Applier) patchObject(ctx context.Context, restMapping *meta.RESTMapping, expectedObject *kubemanifest.Object) error {
gvr := restMapping.Resource
name := expectedObject.GetName()
namespace := expectedObject.GetNamespace()
key := namespace + "/" + name

for _, expectedObject := range expectedObjects {
name := expectedObject.GetName()
namespace := expectedObject.GetNamespace()
key := namespace + "/" + name

var resource dynamic.ResourceInterface
if restMapping.Scope.Name() == meta.RESTScopeNameNamespace {
if namespace == "" {
return fmt.Errorf("namespace not set for namespace-scoped object %q", key)
}
resource = p.Client.Resource(gvr).Namespace(namespace)
} else {
if namespace != "" {
return fmt.Errorf("namespace was set for cluster-scoped object %q", key)
}
resource = p.Client.Resource(gvr)
}
var resource dynamic.ResourceInterface

obj := expectedObject.ToUnstructured()

if actual, found := actualMap[key]; found {
klog.V(2).Infof("updating %s %s", gvr, key)
var opts v1.UpdateOptions
obj.SetResourceVersion(actual.GetResourceVersion())
if _, err := resource.Update(ctx, obj, opts); err != nil {
merr = multierr.Append(merr, fmt.Errorf("failed to create %s: %w", key, err))
}
} else {
klog.V(2).Infof("creating %s %s", gvr, key)
var opts v1.CreateOptions
if _, err := resource.Create(ctx, obj, opts); err != nil {
merr = multierr.Append(merr, fmt.Errorf("failed to create %s: %w", key, err))
}
if restMapping.Scope.Name() == meta.RESTScopeNameNamespace {
if namespace == "" {
return fmt.Errorf("namespace not set for namespace-scoped object %q", key)
}
resource = p.Client.Resource(gvr).Namespace(namespace)
} else {
if namespace != "" {
return fmt.Errorf("namespace was set for cluster-scoped object %q", key)
}
resource = p.Client.Resource(gvr)
}

obj := expectedObject.ToUnstructured()

jsonData, err := json.Marshal(obj)
if err != nil {
return fmt.Errorf("failed to marsal %q into json: %w", obj.GetName(), err)
}

return merr
{
_, err := resource.Patch(ctx, obj.GetName(), types.ApplyPatchType, jsonData, v1.PatchOptions{FieldManager: "kops", Force: fi.Bool(true)})
if err != nil {
return fmt.Errorf("failed to path object %q: %w", obj.GetName(), err)
}
}
return nil
}