From 9a0e6618928cf2ca29b5ac0c6a3bd962890d86f3 Mon Sep 17 00:00:00 2001 From: Jian Qiu Date: Tue, 16 Apr 2024 15:01:22 +0800 Subject: [PATCH] Get default registration namespace from template manifest Signed-off-by: Jian Qiu --- go.mod | 4 +- go.sum | 8 +- pkg/addon/templateagent/template_agent.go | 46 +- vendor/helm.sh/helm/v3/pkg/release/hook.go | 106 +++++ vendor/helm.sh/helm/v3/pkg/release/info.go | 40 ++ vendor/helm.sh/helm/v3/pkg/release/mock.go | 116 +++++ vendor/helm.sh/helm/v3/pkg/release/release.go | 49 ++ .../helm.sh/helm/v3/pkg/release/responses.go | 24 + vendor/helm.sh/helm/v3/pkg/release/status.go | 49 ++ .../helm.sh/helm/v3/pkg/releaseutil/filter.go | 78 ++++ .../helm/v3/pkg/releaseutil/kind_sorter.go | 160 +++++++ .../helm/v3/pkg/releaseutil/manifest.go | 72 +++ .../v3/pkg/releaseutil/manifest_sorter.go | 233 ++++++++++ .../helm.sh/helm/v3/pkg/releaseutil/sorter.go | 78 ++++ vendor/helm.sh/helm/v3/pkg/time/time.go | 91 ++++ vendor/modules.txt | 14 +- .../pkg/addonfactory/addonfactory.go | 48 +- .../pkg/addonfactory/helm_agentaddon.go | 170 +++++-- .../pkg/addonfactory/template_agentaddon.go | 23 +- .../pkg/addonmanager/constants/constants.go | 8 +- .../controllers/addoninstall/controller.go | 138 ------ .../controllers/agentdeploy/controller.go | 204 +++++---- .../agentdeploy/default_hook_sync.go | 8 +- .../controllers/agentdeploy/default_sync.go | 6 +- .../agentdeploy/hosted_hook_sync.go | 10 +- .../controllers/agentdeploy/hosted_sync.go | 10 +- .../controllers/agentdeploy/utils.go | 20 +- .../controllers/certificate/csrsign.go | 2 +- .../controller.go | 20 +- .../controller.go | 33 +- .../controllers/registration/controller.go | 9 +- .../pkg/addonmanager/manager.go | 45 +- .../addon-framework/pkg/agent/inteface.go | 83 +--- .../addon_configuration_reconciler.go | 114 ----- .../addonconfiguration/controller.go | 196 -------- .../controllers/addonconfiguration/graph.go | 417 ------------------ .../mgmt_addon_progressing_reconciler.go | 143 ------ .../controllers/addonowner/controller.go | 100 ----- .../addon-framework/pkg/utils/addon_config.go | 23 +- .../pkg/apis/work/v1/applier/workapplier.go | 2 +- 40 files changed, 1536 insertions(+), 1464 deletions(-) create mode 100644 vendor/helm.sh/helm/v3/pkg/release/hook.go create mode 100644 vendor/helm.sh/helm/v3/pkg/release/info.go create mode 100644 vendor/helm.sh/helm/v3/pkg/release/mock.go create mode 100644 vendor/helm.sh/helm/v3/pkg/release/release.go create mode 100644 vendor/helm.sh/helm/v3/pkg/release/responses.go create mode 100644 vendor/helm.sh/helm/v3/pkg/release/status.go create mode 100644 vendor/helm.sh/helm/v3/pkg/releaseutil/filter.go create mode 100644 vendor/helm.sh/helm/v3/pkg/releaseutil/kind_sorter.go create mode 100644 vendor/helm.sh/helm/v3/pkg/releaseutil/manifest.go create mode 100644 vendor/helm.sh/helm/v3/pkg/releaseutil/manifest_sorter.go create mode 100644 vendor/helm.sh/helm/v3/pkg/releaseutil/sorter.go create mode 100644 vendor/helm.sh/helm/v3/pkg/time/time.go delete mode 100644 vendor/open-cluster-management.io/addon-framework/pkg/addonmanager/controllers/addoninstall/controller.go rename vendor/open-cluster-management.io/addon-framework/pkg/addonmanager/controllers/{managementaddonconfig => cmaconfig}/controller.go (89%) rename vendor/open-cluster-management.io/addon-framework/pkg/addonmanager/controllers/{managementaddon => cmamanagedby}/controller.go (75%) delete mode 100644 vendor/open-cluster-management.io/addon-framework/pkg/manager/controllers/addonconfiguration/addon_configuration_reconciler.go delete mode 100644 vendor/open-cluster-management.io/addon-framework/pkg/manager/controllers/addonconfiguration/controller.go delete mode 100644 vendor/open-cluster-management.io/addon-framework/pkg/manager/controllers/addonconfiguration/graph.go delete mode 100644 vendor/open-cluster-management.io/addon-framework/pkg/manager/controllers/addonconfiguration/mgmt_addon_progressing_reconciler.go delete mode 100644 vendor/open-cluster-management.io/addon-framework/pkg/manager/controllers/addonowner/controller.go diff --git a/go.mod b/go.mod index a8c16a33f..d06ae74ba 100644 --- a/go.mod +++ b/go.mod @@ -34,9 +34,9 @@ require ( k8s.io/klog/v2 v2.120.1 k8s.io/kube-aggregator v0.29.3 k8s.io/utils v0.0.0-20240310230437-4693a0247e57 - open-cluster-management.io/addon-framework v0.9.1 + open-cluster-management.io/addon-framework v0.9.1-0.20240416063208-ecb7f349df05 open-cluster-management.io/api v0.13.1-0.20240411131856-8f6aa25f111c - open-cluster-management.io/sdk-go v0.13.1-0.20240415030117-612344aae744 + open-cluster-management.io/sdk-go v0.13.1-0.20240416030555-aa744f426379 sigs.k8s.io/controller-runtime v0.17.3 sigs.k8s.io/kube-storage-version-migrator v0.0.6-0.20230721195810-5c8923c5ff96 ) diff --git a/go.sum b/go.sum index c0393f301..0cedb7d05 100644 --- a/go.sum +++ b/go.sum @@ -423,12 +423,12 @@ k8s.io/kube-openapi v0.0.0-20231010175941-2dd684a91f00 h1:aVUu9fTY98ivBPKR9Y5w/A k8s.io/kube-openapi v0.0.0-20231010175941-2dd684a91f00/go.mod h1:AsvuZPBlUDVuCdzJ87iajxtXuR9oktsTctW/R9wwouA= k8s.io/utils v0.0.0-20240310230437-4693a0247e57 h1:gbqbevonBh57eILzModw6mrkbwM0gQBEuevE/AaBsHY= k8s.io/utils v0.0.0-20240310230437-4693a0247e57/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= -open-cluster-management.io/addon-framework v0.9.1 h1:m6n/W29G/4KzMx+8mgC9P/ybuiyNHVy+O6AHEaWbfQg= -open-cluster-management.io/addon-framework v0.9.1/go.mod h1:OEIFCEXhZKO/Grv08CB0T+TGzS0bLshw4G9u7Vw8dw0= +open-cluster-management.io/addon-framework v0.9.1-0.20240416063208-ecb7f349df05 h1:oj4IEyxmQFMxdpnOPE/Y7Xkyfkz4hGVkcYZ4dn8WtKU= +open-cluster-management.io/addon-framework v0.9.1-0.20240416063208-ecb7f349df05/go.mod h1:K+/TwCUz2PZ7L+svaodw6029S/iPJ7eVX21F7NMw+Kw= open-cluster-management.io/api v0.13.1-0.20240411131856-8f6aa25f111c h1:/iUoY6/PqBmcBq3v0+UBFvIcI39k/QPRGqpOv9XtDIc= open-cluster-management.io/api v0.13.1-0.20240411131856-8f6aa25f111c/go.mod h1:CuCPEzXDvOyxBB0H1d1eSeajbHqaeGEKq9c63vQc63w= -open-cluster-management.io/sdk-go v0.13.1-0.20240415030117-612344aae744 h1:dBO6eK3gHSoRpl8OckW1zyOp35BOI48rYgoCznrPn40= -open-cluster-management.io/sdk-go v0.13.1-0.20240415030117-612344aae744/go.mod h1:w2OaxtCyegxeyFLU42UQ3oxUz01QdsBQkcHI17T/l48= +open-cluster-management.io/sdk-go v0.13.1-0.20240416030555-aa744f426379 h1:8jXVHfgy+wgXq1mrWC1mTieoP77WsAAHNpzILMIzWB0= +open-cluster-management.io/sdk-go v0.13.1-0.20240416030555-aa744f426379/go.mod h1:w2OaxtCyegxeyFLU42UQ3oxUz01QdsBQkcHI17T/l48= sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.28.0 h1:TgtAeesdhpm2SGwkQasmbeqDo8th5wOBA5h/AjTKA4I= sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.28.0/go.mod h1:VHVDI/KrK4fjnV61bE2g3sA7tiETLn8sooImelsCx3Y= sigs.k8s.io/controller-runtime v0.17.3 h1:65QmN7r3FWgTxDMz9fvGnO1kbf2nu+acg9p2R9oYYYk= diff --git a/pkg/addon/templateagent/template_agent.go b/pkg/addon/templateagent/template_agent.go index abf43faa9..ba114faaf 100644 --- a/pkg/addon/templateagent/template_agent.go +++ b/pkg/addon/templateagent/template_agent.go @@ -118,12 +118,11 @@ func (a *CRDTemplateAgentAddon) GetAgentAddonOptions() agent.AgentAddonOptions { }, SupportedConfigGVRs: supportedConfigGVRs, Registration: &agent.RegistrationOption{ - CSRConfigurations: a.TemplateCSRConfigurationsFunc(), - PermissionConfig: a.TemplatePermissionConfigFunc(), - CSRApproveCheck: a.TemplateCSRApproveCheckFunc(), - CSRSign: a.TemplateCSRSignFunc(), - AgentInstallNamespace: utils.AgentInstallNamespaceFromDeploymentConfigFunc( - utils.NewAddOnDeploymentConfigGetter(a.addonClient)), + CSRConfigurations: a.TemplateCSRConfigurationsFunc(), + PermissionConfig: a.TemplatePermissionConfigFunc(), + CSRApproveCheck: a.TemplateCSRApproveCheckFunc(), + CSRSign: a.TemplateCSRSignFunc(), + AgentInstallNamespace: a.TemplateAgentRegistrationNamespaceFunc, }, AgentDeployTriggerClusterFilter: func(old, new *clusterv1.ManagedCluster) bool { return utils.ClusterImageRegistriesAnnotationChanged(old, new) || @@ -233,3 +232,38 @@ func (a *CRDTemplateAgentAddon) getDesiredAddOnTemplateInner( return template.DeepCopy(), nil } + +// TemplateAgentRegistrationNamespaceFunc reads deployment resource in the manifests and use that namespace as the default +// registration namespace. If addonDeploymentConfig is set, uses the namespace in it. +func (a *CRDTemplateAgentAddon) TemplateAgentRegistrationNamespaceFunc(addon *addonapiv1alpha1.ManagedClusterAddOn) (string, error) { + template, err := a.getDesiredAddOnTemplateInner(addon.Name, addon.Status.ConfigReferences) + if err != nil { + return "", err + } + + // pick the namespace of the first deployment + var desiredNS = "open-cluster-management-agent-addon" + for _, manifest := range template.Spec.AgentSpec.Workload.Manifests { + object := &unstructured.Unstructured{} + if err := object.UnmarshalJSON(manifest.Raw); err != nil { + a.logger.Error(err, "failed to extract the object") + continue + } + if object.GetKind() != "Deployment" { + continue + } + + desiredNS = object.GetNamespace() + break + } + + overrideNs, err := utils.AgentInstallNamespaceFromDeploymentConfigFunc( + utils.NewAddOnDeploymentConfigGetter(a.addonClient))(addon) + if err != nil { + return "", err + } + if len(overrideNs) > 0 { + desiredNS = overrideNs + } + return desiredNS, nil +} diff --git a/vendor/helm.sh/helm/v3/pkg/release/hook.go b/vendor/helm.sh/helm/v3/pkg/release/hook.go new file mode 100644 index 000000000..cb9955582 --- /dev/null +++ b/vendor/helm.sh/helm/v3/pkg/release/hook.go @@ -0,0 +1,106 @@ +/* +Copyright The Helm Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package release + +import ( + "helm.sh/helm/v3/pkg/time" +) + +// HookEvent specifies the hook event +type HookEvent string + +// Hook event types +const ( + HookPreInstall HookEvent = "pre-install" + HookPostInstall HookEvent = "post-install" + HookPreDelete HookEvent = "pre-delete" + HookPostDelete HookEvent = "post-delete" + HookPreUpgrade HookEvent = "pre-upgrade" + HookPostUpgrade HookEvent = "post-upgrade" + HookPreRollback HookEvent = "pre-rollback" + HookPostRollback HookEvent = "post-rollback" + HookTest HookEvent = "test" +) + +func (x HookEvent) String() string { return string(x) } + +// HookDeletePolicy specifies the hook delete policy +type HookDeletePolicy string + +// Hook delete policy types +const ( + HookSucceeded HookDeletePolicy = "hook-succeeded" + HookFailed HookDeletePolicy = "hook-failed" + HookBeforeHookCreation HookDeletePolicy = "before-hook-creation" +) + +func (x HookDeletePolicy) String() string { return string(x) } + +// HookAnnotation is the label name for a hook +const HookAnnotation = "helm.sh/hook" + +// HookWeightAnnotation is the label name for a hook weight +const HookWeightAnnotation = "helm.sh/hook-weight" + +// HookDeleteAnnotation is the label name for the delete policy for a hook +const HookDeleteAnnotation = "helm.sh/hook-delete-policy" + +// Hook defines a hook object. +type Hook struct { + Name string `json:"name,omitempty"` + // Kind is the Kubernetes kind. + Kind string `json:"kind,omitempty"` + // Path is the chart-relative path to the template. + Path string `json:"path,omitempty"` + // Manifest is the manifest contents. + Manifest string `json:"manifest,omitempty"` + // Events are the events that this hook fires on. + Events []HookEvent `json:"events,omitempty"` + // LastRun indicates the date/time this was last run. + LastRun HookExecution `json:"last_run,omitempty"` + // Weight indicates the sort order for execution among similar Hook type + Weight int `json:"weight,omitempty"` + // DeletePolicies are the policies that indicate when to delete the hook + DeletePolicies []HookDeletePolicy `json:"delete_policies,omitempty"` +} + +// A HookExecution records the result for the last execution of a hook for a given release. +type HookExecution struct { + // StartedAt indicates the date/time this hook was started + StartedAt time.Time `json:"started_at,omitempty"` + // CompletedAt indicates the date/time this hook was completed. + CompletedAt time.Time `json:"completed_at,omitempty"` + // Phase indicates whether the hook completed successfully + Phase HookPhase `json:"phase"` +} + +// A HookPhase indicates the state of a hook execution +type HookPhase string + +const ( + // HookPhaseUnknown indicates that a hook is in an unknown state + HookPhaseUnknown HookPhase = "Unknown" + // HookPhaseRunning indicates that a hook is currently executing + HookPhaseRunning HookPhase = "Running" + // HookPhaseSucceeded indicates that hook execution succeeded + HookPhaseSucceeded HookPhase = "Succeeded" + // HookPhaseFailed indicates that hook execution failed + HookPhaseFailed HookPhase = "Failed" +) + +// String converts a hook phase to a printable string +func (x HookPhase) String() string { return string(x) } diff --git a/vendor/helm.sh/helm/v3/pkg/release/info.go b/vendor/helm.sh/helm/v3/pkg/release/info.go new file mode 100644 index 000000000..b030a8a54 --- /dev/null +++ b/vendor/helm.sh/helm/v3/pkg/release/info.go @@ -0,0 +1,40 @@ +/* +Copyright The Helm Authors. +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + +http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package release + +import ( + "k8s.io/apimachinery/pkg/runtime" + + "helm.sh/helm/v3/pkg/time" +) + +// Info describes release information. +type Info struct { + // FirstDeployed is when the release was first deployed. + FirstDeployed time.Time `json:"first_deployed,omitempty"` + // LastDeployed is when the release was last deployed. + LastDeployed time.Time `json:"last_deployed,omitempty"` + // Deleted tracks when this object was deleted. + Deleted time.Time `json:"deleted"` + // Description is human-friendly "log entry" about this release. + Description string `json:"description,omitempty"` + // Status is the current state of the release + Status Status `json:"status,omitempty"` + // Contains the rendered templates/NOTES.txt if available + Notes string `json:"notes,omitempty"` + // Contains the deployed resources information + Resources map[string][]runtime.Object `json:"resources,omitempty"` +} diff --git a/vendor/helm.sh/helm/v3/pkg/release/mock.go b/vendor/helm.sh/helm/v3/pkg/release/mock.go new file mode 100644 index 000000000..a28e1dc16 --- /dev/null +++ b/vendor/helm.sh/helm/v3/pkg/release/mock.go @@ -0,0 +1,116 @@ +/* +Copyright The Helm Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package release + +import ( + "fmt" + "math/rand" + + "helm.sh/helm/v3/pkg/chart" + "helm.sh/helm/v3/pkg/time" +) + +// MockHookTemplate is the hook template used for all mock release objects. +var MockHookTemplate = `apiVersion: v1 +kind: Job +metadata: + annotations: + "helm.sh/hook": pre-install +` + +// MockManifest is the manifest used for all mock release objects. +var MockManifest = `apiVersion: v1 +kind: Secret +metadata: + name: fixture +` + +// MockReleaseOptions allows for user-configurable options on mock release objects. +type MockReleaseOptions struct { + Name string + Version int + Chart *chart.Chart + Status Status + Namespace string +} + +// Mock creates a mock release object based on options set by MockReleaseOptions. This function should typically not be used outside of testing. +func Mock(opts *MockReleaseOptions) *Release { + date := time.Unix(242085845, 0).UTC() + + name := opts.Name + if name == "" { + name = "testrelease-" + fmt.Sprint(rand.Intn(100)) + } + + version := 1 + if opts.Version != 0 { + version = opts.Version + } + + namespace := opts.Namespace + if namespace == "" { + namespace = "default" + } + + ch := opts.Chart + if opts.Chart == nil { + ch = &chart.Chart{ + Metadata: &chart.Metadata{ + Name: "foo", + Version: "0.1.0-beta.1", + AppVersion: "1.0", + }, + Templates: []*chart.File{ + {Name: "templates/foo.tpl", Data: []byte(MockManifest)}, + }, + } + } + + scode := StatusDeployed + if len(opts.Status) > 0 { + scode = opts.Status + } + + info := &Info{ + FirstDeployed: date, + LastDeployed: date, + Status: scode, + Description: "Release mock", + Notes: "Some mock release notes!", + } + + return &Release{ + Name: name, + Info: info, + Chart: ch, + Config: map[string]interface{}{"name": "value"}, + Version: version, + Namespace: namespace, + Hooks: []*Hook{ + { + Name: "pre-install-hook", + Kind: "Job", + Path: "pre-install-hook.yaml", + Manifest: MockHookTemplate, + LastRun: HookExecution{}, + Events: []HookEvent{HookPreInstall}, + }, + }, + Manifest: MockManifest, + } +} diff --git a/vendor/helm.sh/helm/v3/pkg/release/release.go b/vendor/helm.sh/helm/v3/pkg/release/release.go new file mode 100644 index 000000000..b90612873 --- /dev/null +++ b/vendor/helm.sh/helm/v3/pkg/release/release.go @@ -0,0 +1,49 @@ +/* +Copyright The Helm Authors. +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + +http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package release + +import "helm.sh/helm/v3/pkg/chart" + +// Release describes a deployment of a chart, together with the chart +// and the variables used to deploy that chart. +type Release struct { + // Name is the name of the release + Name string `json:"name,omitempty"` + // Info provides information about a release + Info *Info `json:"info,omitempty"` + // Chart is the chart that was released. + Chart *chart.Chart `json:"chart,omitempty"` + // Config is the set of extra Values added to the chart. + // These values override the default values inside of the chart. + Config map[string]interface{} `json:"config,omitempty"` + // Manifest is the string representation of the rendered template. + Manifest string `json:"manifest,omitempty"` + // Hooks are all of the hooks declared for this release. + Hooks []*Hook `json:"hooks,omitempty"` + // Version is an int which represents the revision of the release. + Version int `json:"version,omitempty"` + // Namespace is the kubernetes namespace of the release. + Namespace string `json:"namespace,omitempty"` + // Labels of the release. + // Disabled encoding into Json cause labels are stored in storage driver metadata field. + Labels map[string]string `json:"-"` +} + +// SetStatus is a helper for setting the status on a release. +func (r *Release) SetStatus(status Status, msg string) { + r.Info.Status = status + r.Info.Description = msg +} diff --git a/vendor/helm.sh/helm/v3/pkg/release/responses.go b/vendor/helm.sh/helm/v3/pkg/release/responses.go new file mode 100644 index 000000000..7ee1fc2ee --- /dev/null +++ b/vendor/helm.sh/helm/v3/pkg/release/responses.go @@ -0,0 +1,24 @@ +/* +Copyright The Helm Authors. +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + +http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package release + +// UninstallReleaseResponse represents a successful response to an uninstall request. +type UninstallReleaseResponse struct { + // Release is the release that was marked deleted. + Release *Release `json:"release,omitempty"` + // Info is an uninstall message + Info string `json:"info,omitempty"` +} diff --git a/vendor/helm.sh/helm/v3/pkg/release/status.go b/vendor/helm.sh/helm/v3/pkg/release/status.go new file mode 100644 index 000000000..e0e3ed62a --- /dev/null +++ b/vendor/helm.sh/helm/v3/pkg/release/status.go @@ -0,0 +1,49 @@ +/* +Copyright The Helm Authors. +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + +http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package release + +// Status is the status of a release +type Status string + +// Describe the status of a release +// NOTE: Make sure to update cmd/helm/status.go when adding or modifying any of these statuses. +const ( + // StatusUnknown indicates that a release is in an uncertain state. + StatusUnknown Status = "unknown" + // StatusDeployed indicates that the release has been pushed to Kubernetes. + StatusDeployed Status = "deployed" + // StatusUninstalled indicates that a release has been uninstalled from Kubernetes. + StatusUninstalled Status = "uninstalled" + // StatusSuperseded indicates that this release object is outdated and a newer one exists. + StatusSuperseded Status = "superseded" + // StatusFailed indicates that the release was not successfully deployed. + StatusFailed Status = "failed" + // StatusUninstalling indicates that a uninstall operation is underway. + StatusUninstalling Status = "uninstalling" + // StatusPendingInstall indicates that an install operation is underway. + StatusPendingInstall Status = "pending-install" + // StatusPendingUpgrade indicates that an upgrade operation is underway. + StatusPendingUpgrade Status = "pending-upgrade" + // StatusPendingRollback indicates that an rollback operation is underway. + StatusPendingRollback Status = "pending-rollback" +) + +func (x Status) String() string { return string(x) } + +// IsPending determines if this status is a state or a transition. +func (x Status) IsPending() bool { + return x == StatusPendingInstall || x == StatusPendingUpgrade || x == StatusPendingRollback +} diff --git a/vendor/helm.sh/helm/v3/pkg/releaseutil/filter.go b/vendor/helm.sh/helm/v3/pkg/releaseutil/filter.go new file mode 100644 index 000000000..dbd0df8e2 --- /dev/null +++ b/vendor/helm.sh/helm/v3/pkg/releaseutil/filter.go @@ -0,0 +1,78 @@ +/* +Copyright The Helm Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package releaseutil // import "helm.sh/helm/v3/pkg/releaseutil" + +import rspb "helm.sh/helm/v3/pkg/release" + +// FilterFunc returns true if the release object satisfies +// the predicate of the underlying filter func. +type FilterFunc func(*rspb.Release) bool + +// Check applies the FilterFunc to the release object. +func (fn FilterFunc) Check(rls *rspb.Release) bool { + if rls == nil { + return false + } + return fn(rls) +} + +// Filter applies the filter(s) to the list of provided releases +// returning the list that satisfies the filtering predicate. +func (fn FilterFunc) Filter(rels []*rspb.Release) (rets []*rspb.Release) { + for _, rel := range rels { + if fn.Check(rel) { + rets = append(rets, rel) + } + } + return +} + +// Any returns a FilterFunc that filters a list of releases +// determined by the predicate 'f0 || f1 || ... || fn'. +func Any(filters ...FilterFunc) FilterFunc { + return func(rls *rspb.Release) bool { + for _, filter := range filters { + if filter(rls) { + return true + } + } + return false + } +} + +// All returns a FilterFunc that filters a list of releases +// determined by the predicate 'f0 && f1 && ... && fn'. +func All(filters ...FilterFunc) FilterFunc { + return func(rls *rspb.Release) bool { + for _, filter := range filters { + if !filter(rls) { + return false + } + } + return true + } +} + +// StatusFilter filters a set of releases by status code. +func StatusFilter(status rspb.Status) FilterFunc { + return FilterFunc(func(rls *rspb.Release) bool { + if rls == nil { + return true + } + return rls.Info.Status == status + }) +} diff --git a/vendor/helm.sh/helm/v3/pkg/releaseutil/kind_sorter.go b/vendor/helm.sh/helm/v3/pkg/releaseutil/kind_sorter.go new file mode 100644 index 000000000..bb8e84dda --- /dev/null +++ b/vendor/helm.sh/helm/v3/pkg/releaseutil/kind_sorter.go @@ -0,0 +1,160 @@ +/* +Copyright The Helm Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package releaseutil + +import ( + "sort" + + "helm.sh/helm/v3/pkg/release" +) + +// KindSortOrder is an ordering of Kinds. +type KindSortOrder []string + +// InstallOrder is the order in which manifests should be installed (by Kind). +// +// Those occurring earlier in the list get installed before those occurring later in the list. +var InstallOrder KindSortOrder = []string{ + "PriorityClass", + "Namespace", + "NetworkPolicy", + "ResourceQuota", + "LimitRange", + "PodSecurityPolicy", + "PodDisruptionBudget", + "ServiceAccount", + "Secret", + "SecretList", + "ConfigMap", + "StorageClass", + "PersistentVolume", + "PersistentVolumeClaim", + "CustomResourceDefinition", + "ClusterRole", + "ClusterRoleList", + "ClusterRoleBinding", + "ClusterRoleBindingList", + "Role", + "RoleList", + "RoleBinding", + "RoleBindingList", + "Service", + "DaemonSet", + "Pod", + "ReplicationController", + "ReplicaSet", + "Deployment", + "HorizontalPodAutoscaler", + "StatefulSet", + "Job", + "CronJob", + "IngressClass", + "Ingress", + "APIService", +} + +// UninstallOrder is the order in which manifests should be uninstalled (by Kind). +// +// Those occurring earlier in the list get uninstalled before those occurring later in the list. +var UninstallOrder KindSortOrder = []string{ + "APIService", + "Ingress", + "IngressClass", + "Service", + "CronJob", + "Job", + "StatefulSet", + "HorizontalPodAutoscaler", + "Deployment", + "ReplicaSet", + "ReplicationController", + "Pod", + "DaemonSet", + "RoleBindingList", + "RoleBinding", + "RoleList", + "Role", + "ClusterRoleBindingList", + "ClusterRoleBinding", + "ClusterRoleList", + "ClusterRole", + "CustomResourceDefinition", + "PersistentVolumeClaim", + "PersistentVolume", + "StorageClass", + "ConfigMap", + "SecretList", + "Secret", + "ServiceAccount", + "PodDisruptionBudget", + "PodSecurityPolicy", + "LimitRange", + "ResourceQuota", + "NetworkPolicy", + "Namespace", + "PriorityClass", +} + +// sort manifests by kind. +// +// Results are sorted by 'ordering', keeping order of items with equal kind/priority +func sortManifestsByKind(manifests []Manifest, ordering KindSortOrder) []Manifest { + sort.SliceStable(manifests, func(i, j int) bool { + return lessByKind(manifests[i], manifests[j], manifests[i].Head.Kind, manifests[j].Head.Kind, ordering) + }) + + return manifests +} + +// sort hooks by kind, using an out-of-place sort to preserve the input parameters. +// +// Results are sorted by 'ordering', keeping order of items with equal kind/priority +func sortHooksByKind(hooks []*release.Hook, ordering KindSortOrder) []*release.Hook { + h := hooks + sort.SliceStable(h, func(i, j int) bool { + return lessByKind(h[i], h[j], h[i].Kind, h[j].Kind, ordering) + }) + + return h +} + +func lessByKind(_ interface{}, _ interface{}, kindA string, kindB string, o KindSortOrder) bool { + ordering := make(map[string]int, len(o)) + for v, k := range o { + ordering[k] = v + } + + first, aok := ordering[kindA] + second, bok := ordering[kindB] + + if !aok && !bok { + // if both are unknown then sort alphabetically by kind, keep original order if same kind + if kindA != kindB { + return kindA < kindB + } + return first < second + } + // unknown kind is last + if !aok { + return false + } + if !bok { + return true + } + // sort different kinds, keep original order if same priority + return first < second +} diff --git a/vendor/helm.sh/helm/v3/pkg/releaseutil/manifest.go b/vendor/helm.sh/helm/v3/pkg/releaseutil/manifest.go new file mode 100644 index 000000000..0b04a4599 --- /dev/null +++ b/vendor/helm.sh/helm/v3/pkg/releaseutil/manifest.go @@ -0,0 +1,72 @@ +/* +Copyright The Helm Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package releaseutil + +import ( + "fmt" + "regexp" + "strconv" + "strings" +) + +// SimpleHead defines what the structure of the head of a manifest file +type SimpleHead struct { + Version string `json:"apiVersion"` + Kind string `json:"kind,omitempty"` + Metadata *struct { + Name string `json:"name"` + Annotations map[string]string `json:"annotations"` + } `json:"metadata,omitempty"` +} + +var sep = regexp.MustCompile("(?:^|\\s*\n)---\\s*") + +// SplitManifests takes a string of manifest and returns a map contains individual manifests +func SplitManifests(bigFile string) map[string]string { + // Basically, we're quickly splitting a stream of YAML documents into an + // array of YAML docs. The file name is just a place holder, but should be + // integer-sortable so that manifests get output in the same order as the + // input (see `BySplitManifestsOrder`). + tpl := "manifest-%d" + res := map[string]string{} + // Making sure that any extra whitespace in YAML stream doesn't interfere in splitting documents correctly. + bigFileTmp := strings.TrimSpace(bigFile) + docs := sep.Split(bigFileTmp, -1) + var count int + for _, d := range docs { + if d == "" { + continue + } + + d = strings.TrimSpace(d) + res[fmt.Sprintf(tpl, count)] = d + count = count + 1 + } + return res +} + +// BySplitManifestsOrder sorts by in-file manifest order, as provided in function `SplitManifests` +type BySplitManifestsOrder []string + +func (a BySplitManifestsOrder) Len() int { return len(a) } +func (a BySplitManifestsOrder) Less(i, j int) bool { + // Split `manifest-%d` + anum, _ := strconv.ParseInt(a[i][len("manifest-"):], 10, 0) + bnum, _ := strconv.ParseInt(a[j][len("manifest-"):], 10, 0) + return anum < bnum +} +func (a BySplitManifestsOrder) Swap(i, j int) { a[i], a[j] = a[j], a[i] } diff --git a/vendor/helm.sh/helm/v3/pkg/releaseutil/manifest_sorter.go b/vendor/helm.sh/helm/v3/pkg/releaseutil/manifest_sorter.go new file mode 100644 index 000000000..413de30e2 --- /dev/null +++ b/vendor/helm.sh/helm/v3/pkg/releaseutil/manifest_sorter.go @@ -0,0 +1,233 @@ +/* +Copyright The Helm Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package releaseutil + +import ( + "log" + "path" + "sort" + "strconv" + "strings" + + "github.com/pkg/errors" + "sigs.k8s.io/yaml" + + "helm.sh/helm/v3/pkg/chartutil" + "helm.sh/helm/v3/pkg/release" +) + +// Manifest represents a manifest file, which has a name and some content. +type Manifest struct { + Name string + Content string + Head *SimpleHead +} + +// manifestFile represents a file that contains a manifest. +type manifestFile struct { + entries map[string]string + path string + apis chartutil.VersionSet +} + +// result is an intermediate structure used during sorting. +type result struct { + hooks []*release.Hook + generic []Manifest +} + +// TODO: Refactor this out. It's here because naming conventions were not followed through. +// So fix the Test hook names and then remove this. +var events = map[string]release.HookEvent{ + release.HookPreInstall.String(): release.HookPreInstall, + release.HookPostInstall.String(): release.HookPostInstall, + release.HookPreDelete.String(): release.HookPreDelete, + release.HookPostDelete.String(): release.HookPostDelete, + release.HookPreUpgrade.String(): release.HookPreUpgrade, + release.HookPostUpgrade.String(): release.HookPostUpgrade, + release.HookPreRollback.String(): release.HookPreRollback, + release.HookPostRollback.String(): release.HookPostRollback, + release.HookTest.String(): release.HookTest, + // Support test-success for backward compatibility with Helm 2 tests + "test-success": release.HookTest, +} + +// SortManifests takes a map of filename/YAML contents, splits the file +// by manifest entries, and sorts the entries into hook types. +// +// The resulting hooks struct will be populated with all of the generated hooks. +// Any file that does not declare one of the hook types will be placed in the +// 'generic' bucket. +// +// Files that do not parse into the expected format are simply placed into a map and +// returned. +func SortManifests(files map[string]string, apis chartutil.VersionSet, ordering KindSortOrder) ([]*release.Hook, []Manifest, error) { + result := &result{} + + var sortedFilePaths []string + for filePath := range files { + sortedFilePaths = append(sortedFilePaths, filePath) + } + sort.Strings(sortedFilePaths) + + for _, filePath := range sortedFilePaths { + content := files[filePath] + + // Skip partials. We could return these as a separate map, but there doesn't + // seem to be any need for that at this time. + if strings.HasPrefix(path.Base(filePath), "_") { + continue + } + // Skip empty files and log this. + if strings.TrimSpace(content) == "" { + continue + } + + manifestFile := &manifestFile{ + entries: SplitManifests(content), + path: filePath, + apis: apis, + } + + if err := manifestFile.sort(result); err != nil { + return result.hooks, result.generic, err + } + } + + return sortHooksByKind(result.hooks, ordering), sortManifestsByKind(result.generic, ordering), nil +} + +// sort takes a manifestFile object which may contain multiple resource definition +// entries and sorts each entry by hook types, and saves the resulting hooks and +// generic manifests (or non-hooks) to the result struct. +// +// To determine hook type, it looks for a YAML structure like this: +// +// kind: SomeKind +// apiVersion: v1 +// metadata: +// annotations: +// helm.sh/hook: pre-install +// +// To determine the policy to delete the hook, it looks for a YAML structure like this: +// +// kind: SomeKind +// apiVersion: v1 +// metadata: +// annotations: +// helm.sh/hook-delete-policy: hook-succeeded +func (file *manifestFile) sort(result *result) error { + // Go through manifests in order found in file (function `SplitManifests` creates integer-sortable keys) + var sortedEntryKeys []string + for entryKey := range file.entries { + sortedEntryKeys = append(sortedEntryKeys, entryKey) + } + sort.Sort(BySplitManifestsOrder(sortedEntryKeys)) + + for _, entryKey := range sortedEntryKeys { + m := file.entries[entryKey] + + var entry SimpleHead + if err := yaml.Unmarshal([]byte(m), &entry); err != nil { + return errors.Wrapf(err, "YAML parse error on %s", file.path) + } + + if !hasAnyAnnotation(entry) { + result.generic = append(result.generic, Manifest{ + Name: file.path, + Content: m, + Head: &entry, + }) + continue + } + + hookTypes, ok := entry.Metadata.Annotations[release.HookAnnotation] + if !ok { + result.generic = append(result.generic, Manifest{ + Name: file.path, + Content: m, + Head: &entry, + }) + continue + } + + hw := calculateHookWeight(entry) + + h := &release.Hook{ + Name: entry.Metadata.Name, + Kind: entry.Kind, + Path: file.path, + Manifest: m, + Events: []release.HookEvent{}, + Weight: hw, + DeletePolicies: []release.HookDeletePolicy{}, + } + + isUnknownHook := false + for _, hookType := range strings.Split(hookTypes, ",") { + hookType = strings.ToLower(strings.TrimSpace(hookType)) + e, ok := events[hookType] + if !ok { + isUnknownHook = true + break + } + h.Events = append(h.Events, e) + } + + if isUnknownHook { + log.Printf("info: skipping unknown hook: %q", hookTypes) + continue + } + + result.hooks = append(result.hooks, h) + + operateAnnotationValues(entry, release.HookDeleteAnnotation, func(value string) { + h.DeletePolicies = append(h.DeletePolicies, release.HookDeletePolicy(value)) + }) + } + + return nil +} + +// hasAnyAnnotation returns true if the given entry has any annotations at all. +func hasAnyAnnotation(entry SimpleHead) bool { + return entry.Metadata != nil && + entry.Metadata.Annotations != nil && + len(entry.Metadata.Annotations) != 0 +} + +// calculateHookWeight finds the weight in the hook weight annotation. +// +// If no weight is found, the assigned weight is 0 +func calculateHookWeight(entry SimpleHead) int { + hws := entry.Metadata.Annotations[release.HookWeightAnnotation] + hw, err := strconv.Atoi(hws) + if err != nil { + hw = 0 + } + return hw +} + +// operateAnnotationValues finds the given annotation and runs the operate function with the value of that annotation +func operateAnnotationValues(entry SimpleHead, annotation string, operate func(p string)) { + if dps, ok := entry.Metadata.Annotations[annotation]; ok { + for _, dp := range strings.Split(dps, ",") { + dp = strings.ToLower(strings.TrimSpace(dp)) + operate(dp) + } + } +} diff --git a/vendor/helm.sh/helm/v3/pkg/releaseutil/sorter.go b/vendor/helm.sh/helm/v3/pkg/releaseutil/sorter.go new file mode 100644 index 000000000..1a8aa78a6 --- /dev/null +++ b/vendor/helm.sh/helm/v3/pkg/releaseutil/sorter.go @@ -0,0 +1,78 @@ +/* +Copyright The Helm Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package releaseutil // import "helm.sh/helm/v3/pkg/releaseutil" + +import ( + "sort" + + rspb "helm.sh/helm/v3/pkg/release" +) + +type list []*rspb.Release + +func (s list) Len() int { return len(s) } +func (s list) Swap(i, j int) { s[i], s[j] = s[j], s[i] } + +// ByName sorts releases by name +type ByName struct{ list } + +// Less compares to releases +func (s ByName) Less(i, j int) bool { return s.list[i].Name < s.list[j].Name } + +// ByDate sorts releases by date +type ByDate struct{ list } + +// Less compares to releases +func (s ByDate) Less(i, j int) bool { + ti := s.list[i].Info.LastDeployed.Unix() + tj := s.list[j].Info.LastDeployed.Unix() + return ti < tj +} + +// ByRevision sorts releases by revision number +type ByRevision struct{ list } + +// Less compares to releases +func (s ByRevision) Less(i, j int) bool { + return s.list[i].Version < s.list[j].Version +} + +// Reverse reverses the list of releases sorted by the sort func. +func Reverse(list []*rspb.Release, sortFn func([]*rspb.Release)) { + sortFn(list) + for i, j := 0, len(list)-1; i < j; i, j = i+1, j-1 { + list[i], list[j] = list[j], list[i] + } +} + +// SortByName returns the list of releases sorted +// in lexicographical order. +func SortByName(list []*rspb.Release) { + sort.Sort(ByName{list}) +} + +// SortByDate returns the list of releases sorted by a +// release's last deployed time (in seconds). +func SortByDate(list []*rspb.Release) { + sort.Sort(ByDate{list}) +} + +// SortByRevision returns the list of releases sorted by a +// release's revision number (release.Version). +func SortByRevision(list []*rspb.Release) { + sort.Sort(ByRevision{list}) +} diff --git a/vendor/helm.sh/helm/v3/pkg/time/time.go b/vendor/helm.sh/helm/v3/pkg/time/time.go new file mode 100644 index 000000000..44f3fedfb --- /dev/null +++ b/vendor/helm.sh/helm/v3/pkg/time/time.go @@ -0,0 +1,91 @@ +/* +Copyright The Helm Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Package time contains a wrapper for time.Time in the standard library and +// associated methods. This package mainly exists to workaround an issue in Go +// where the serializer doesn't omit an empty value for time: +// https://github.com/golang/go/issues/11939. As such, this can be removed if a +// proposal is ever accepted for Go +package time + +import ( + "bytes" + "time" +) + +// emptyString contains an empty JSON string value to be used as output +var emptyString = `""` + +// Time is a convenience wrapper around stdlib time, but with different +// marshalling and unmarshaling for zero values +type Time struct { + time.Time +} + +// Now returns the current time. It is a convenience wrapper around time.Now() +func Now() Time { + return Time{time.Now()} +} + +func (t Time) MarshalJSON() ([]byte, error) { + if t.Time.IsZero() { + return []byte(emptyString), nil + } + + return t.Time.MarshalJSON() +} + +func (t *Time) UnmarshalJSON(b []byte) error { + if bytes.Equal(b, []byte("null")) { + return nil + } + // If it is empty, we don't have to set anything since time.Time is not a + // pointer and will be set to the zero value + if bytes.Equal([]byte(emptyString), b) { + return nil + } + + return t.Time.UnmarshalJSON(b) +} + +func Parse(layout, value string) (Time, error) { + t, err := time.Parse(layout, value) + return Time{Time: t}, err +} +func ParseInLocation(layout, value string, loc *time.Location) (Time, error) { + t, err := time.ParseInLocation(layout, value, loc) + return Time{Time: t}, err +} + +func Date(year int, month time.Month, day, hour, min, sec, nsec int, loc *time.Location) Time { + return Time{Time: time.Date(year, month, day, hour, min, sec, nsec, loc)} +} + +func Unix(sec int64, nsec int64) Time { return Time{Time: time.Unix(sec, nsec)} } + +func (t Time) Add(d time.Duration) Time { return Time{Time: t.Time.Add(d)} } +func (t Time) AddDate(years int, months int, days int) Time { + return Time{Time: t.Time.AddDate(years, months, days)} +} +func (t Time) After(u Time) bool { return t.Time.After(u.Time) } +func (t Time) Before(u Time) bool { return t.Time.Before(u.Time) } +func (t Time) Equal(u Time) bool { return t.Time.Equal(u.Time) } +func (t Time) In(loc *time.Location) Time { return Time{Time: t.Time.In(loc)} } +func (t Time) Local() Time { return Time{Time: t.Time.Local()} } +func (t Time) Round(d time.Duration) Time { return Time{Time: t.Time.Round(d)} } +func (t Time) Sub(u Time) time.Duration { return t.Time.Sub(u.Time) } +func (t Time) Truncate(d time.Duration) Time { return Time{Time: t.Time.Truncate(d)} } +func (t Time) UTC() Time { return Time{Time: t.Time.UTC()} } diff --git a/vendor/modules.txt b/vendor/modules.txt index 9338c6753..d7771c922 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -796,6 +796,9 @@ helm.sh/helm/v3/pkg/chart/loader helm.sh/helm/v3/pkg/chartutil helm.sh/helm/v3/pkg/engine helm.sh/helm/v3/pkg/ignore +helm.sh/helm/v3/pkg/release +helm.sh/helm/v3/pkg/releaseutil +helm.sh/helm/v3/pkg/time # k8s.io/api v0.29.3 ## explicit; go 1.21 k8s.io/api/admission/v1 @@ -1486,26 +1489,23 @@ k8s.io/utils/pointer k8s.io/utils/ptr k8s.io/utils/strings/slices k8s.io/utils/trace -# open-cluster-management.io/addon-framework v0.9.1 +# open-cluster-management.io/addon-framework v0.9.1-0.20240416063208-ecb7f349df05 ## explicit; go 1.21 open-cluster-management.io/addon-framework/pkg/addonfactory open-cluster-management.io/addon-framework/pkg/addonmanager open-cluster-management.io/addon-framework/pkg/addonmanager/addontesting open-cluster-management.io/addon-framework/pkg/addonmanager/constants open-cluster-management.io/addon-framework/pkg/addonmanager/controllers/addonconfig -open-cluster-management.io/addon-framework/pkg/addonmanager/controllers/addoninstall open-cluster-management.io/addon-framework/pkg/addonmanager/controllers/agentdeploy open-cluster-management.io/addon-framework/pkg/addonmanager/controllers/certificate -open-cluster-management.io/addon-framework/pkg/addonmanager/controllers/managementaddon -open-cluster-management.io/addon-framework/pkg/addonmanager/controllers/managementaddonconfig +open-cluster-management.io/addon-framework/pkg/addonmanager/controllers/cmaconfig +open-cluster-management.io/addon-framework/pkg/addonmanager/controllers/cmamanagedby open-cluster-management.io/addon-framework/pkg/addonmanager/controllers/registration open-cluster-management.io/addon-framework/pkg/agent open-cluster-management.io/addon-framework/pkg/assets open-cluster-management.io/addon-framework/pkg/basecontroller/events open-cluster-management.io/addon-framework/pkg/basecontroller/factory open-cluster-management.io/addon-framework/pkg/index -open-cluster-management.io/addon-framework/pkg/manager/controllers/addonconfiguration -open-cluster-management.io/addon-framework/pkg/manager/controllers/addonowner open-cluster-management.io/addon-framework/pkg/utils # open-cluster-management.io/api v0.13.1-0.20240411131856-8f6aa25f111c ## explicit; go 1.21 @@ -1578,7 +1578,7 @@ open-cluster-management.io/api/utils/work/v1/workapplier open-cluster-management.io/api/utils/work/v1/workvalidator open-cluster-management.io/api/work/v1 open-cluster-management.io/api/work/v1alpha1 -# open-cluster-management.io/sdk-go v0.13.1-0.20240415030117-612344aae744 +# open-cluster-management.io/sdk-go v0.13.1-0.20240416030555-aa744f426379 ## explicit; go 1.21 open-cluster-management.io/sdk-go/pkg/apis/cluster/v1alpha1 open-cluster-management.io/sdk-go/pkg/apis/cluster/v1beta1 diff --git a/vendor/open-cluster-management.io/addon-framework/pkg/addonfactory/addonfactory.go b/vendor/open-cluster-management.io/addon-framework/pkg/addonfactory/addonfactory.go index 91e8df4e1..d92690f74 100644 --- a/vendor/open-cluster-management.io/addon-framework/pkg/addonfactory/addonfactory.go +++ b/vendor/open-cluster-management.io/addon-framework/pkg/addonfactory/addonfactory.go @@ -10,7 +10,9 @@ import ( "k8s.io/apimachinery/pkg/runtime/schema" "k8s.io/client-go/kubernetes/scheme" "k8s.io/klog/v2" + "open-cluster-management.io/addon-framework/pkg/addonmanager/constants" addonapiv1alpha1 "open-cluster-management.io/api/addon/v1alpha1" + clusterclientset "open-cluster-management.io/api/client/cluster/clientset/versioned" clusterv1 "open-cluster-management.io/api/cluster/v1" "open-cluster-management.io/addon-framework/pkg/agent" @@ -34,9 +36,12 @@ type AgentAddonFactory struct { getValuesFuncs []GetValuesFunc agentAddonOptions agent.AgentAddonOptions // trimCRDDescription flag is used to trim the description of CRDs in manifestWork. disabled by default. - trimCRDDescription bool + trimCRDDescription bool + // Deprecated: use clusterClient to get the hosting cluster. hostingCluster *clusterv1.ManagedCluster - agentInstallNamespace func(addon *addonapiv1alpha1.ManagedClusterAddOn) string + clusterClient clusterclientset.Interface + agentInstallNamespace func(addon *addonapiv1alpha1.ManagedClusterAddOn) (string, error) + helmEngineStrict bool } // NewAgentAddonFactory builds an addonAgentFactory instance with addon name and fs. @@ -53,12 +58,14 @@ func NewAgentAddonFactory(addonName string, fs embed.FS, dir string) *AgentAddon agentAddonOptions: agent.AgentAddonOptions{ AddonName: addonName, Registration: nil, - InstallStrategy: nil, HealthProber: nil, SupportedConfigGVRs: []schema.GroupVersionResource{}, + // Set a default hosted mode info func. + HostedModeInfoFunc: constants.GetHostedModeInfo, }, trimCRDDescription: false, scheme: s, + helmEngineStrict: false, } } @@ -78,19 +85,6 @@ func (f *AgentAddonFactory) WithGetValuesFuncs(getValuesFuncs ...GetValuesFunc) return f } -// WithInstallStrategy defines the installation strategy of the manifests prescribed by Manifests(..). -// Deprecated: add annotation "addon.open-cluster-management.io/lifecycle: addon-manager" to ClusterManagementAddon -// and define install strategy in ClusterManagementAddon spec.installStrategy instead. -// The migration plan refer to https://github.com/open-cluster-management-io/ocm/issues/355. -func (f *AgentAddonFactory) WithInstallStrategy(strategy *agent.InstallStrategy) *AgentAddonFactory { - if strategy.InstallNamespace == "" { - strategy.InstallNamespace = AddonDefaultInstallNamespace - } - f.agentAddonOptions.InstallStrategy = strategy - - return f -} - // WithAgentRegistrationOption defines how agent is registered to the hub cluster. func (f *AgentAddonFactory) WithAgentRegistrationOption(option *agent.RegistrationOption) *AgentAddonFactory { f.agentAddonOptions.Registration = option @@ -109,12 +103,25 @@ func (f *AgentAddonFactory) WithAgentHostedModeEnabledOption() *AgentAddonFactor return f } +// WithAgentHostedInfoFn sets the function to get the hosting cluster of an addon in the hosted mode. +func (f *AgentAddonFactory) WithAgentHostedInfoFn( + infoFn func(*addonapiv1alpha1.ManagedClusterAddOn, *clusterv1.ManagedCluster) (string, string)) *AgentAddonFactory { + f.agentAddonOptions.HostedModeInfoFunc = infoFn + return f +} + // WithTrimCRDDescription is to enable trim the description of CRDs in manifestWork. func (f *AgentAddonFactory) WithTrimCRDDescription() *AgentAddonFactory { f.trimCRDDescription = true return f } +// WithHelmEngineStrict is to enable script go template rendering for Helm charts to generate manifestWork. +func (f *AgentAddonFactory) WithHelmEngineStrict() *AgentAddonFactory { + f.helmEngineStrict = true + return f +} + // WithConfigGVRs defines the addon supported configuration GroupVersionResource func (f *AgentAddonFactory) WithConfigGVRs(gvrs ...schema.GroupVersionResource) *AgentAddonFactory { f.agentAddonOptions.SupportedConfigGVRs = append(f.agentAddonOptions.SupportedConfigGVRs, gvrs...) @@ -123,11 +130,18 @@ func (f *AgentAddonFactory) WithConfigGVRs(gvrs ...schema.GroupVersionResource) // WithHostingCluster defines the hosting cluster used in hosted mode. An AgentAddon may use this to provide // additional metadata. +// Deprecated: use WithManagedClusterClient to set a cluster client that can get the hosting cluster. func (f *AgentAddonFactory) WithHostingCluster(cluster *clusterv1.ManagedCluster) *AgentAddonFactory { f.hostingCluster = cluster return f } +// WithManagedClusterClient defines the cluster client that can get the hosting cluster used in hosted mode. +func (f *AgentAddonFactory) WithManagedClusterClient(c clusterclientset.Interface) *AgentAddonFactory { + f.clusterClient = c + return f +} + // WithAgentDeployTriggerClusterFilter defines the filter func to trigger the agent deploy/redploy when cluster info is // changed. Addons that need information from the ManagedCluster resource when deploying the agent should use this // function to set what information they need, otherwise the expected/up-to-date agent may be deployed delayed since the @@ -150,7 +164,7 @@ func (f *AgentAddonFactory) WithAgentDeployTriggerClusterFilter( // override the default built-in namespace value; And if the registrationOption is not nil but the // registrationOption.AgentInstallNamespace is nil, this will also set it to this. func (f *AgentAddonFactory) WithAgentInstallNamespace( - nsFunc func(addon *addonapiv1alpha1.ManagedClusterAddOn) string, + nsFunc func(addon *addonapiv1alpha1.ManagedClusterAddOn) (string, error), ) *AgentAddonFactory { f.agentInstallNamespace = nsFunc return f diff --git a/vendor/open-cluster-management.io/addon-framework/pkg/addonfactory/helm_agentaddon.go b/vendor/open-cluster-management.io/addon-framework/pkg/addonfactory/helm_agentaddon.go index c8e8f9917..e010d2073 100644 --- a/vendor/open-cluster-management.io/addon-framework/pkg/addonfactory/helm_agentaddon.go +++ b/vendor/open-cluster-management.io/addon-framework/pkg/addonfactory/helm_agentaddon.go @@ -2,6 +2,7 @@ package addonfactory import ( "bufio" + "context" "fmt" "io" "sort" @@ -10,14 +11,18 @@ import ( "helm.sh/helm/v3/pkg/chart" "helm.sh/helm/v3/pkg/chartutil" "helm.sh/helm/v3/pkg/engine" + "helm.sh/helm/v3/pkg/releaseutil" + "k8s.io/apimachinery/pkg/api/errors" + "k8s.io/apimachinery/pkg/api/meta" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/runtime/serializer" "k8s.io/apimachinery/pkg/util/yaml" "k8s.io/klog/v2" addonapiv1alpha1 "open-cluster-management.io/api/addon/v1alpha1" + clusterclientset "open-cluster-management.io/api/client/cluster/clientset/versioned" clusterv1 "open-cluster-management.io/api/cluster/v1" - "open-cluster-management.io/addon-framework/pkg/addonmanager/constants" "open-cluster-management.io/addon-framework/pkg/agent" ) @@ -42,13 +47,16 @@ type helmDefaultValues struct { } type HelmAgentAddon struct { - decoder runtime.Decoder - chart *chart.Chart - getValuesFuncs []GetValuesFunc - agentAddonOptions agent.AgentAddonOptions - trimCRDDescription bool + decoder runtime.Decoder + chart *chart.Chart + getValuesFuncs []GetValuesFunc + agentAddonOptions agent.AgentAddonOptions + trimCRDDescription bool + // Deprecated: use clusterClient to get the hosting cluster. hostingCluster *clusterv1.ManagedCluster - agentInstallNamespace func(addon *addonapiv1alpha1.ManagedClusterAddOn) string + clusterClient clusterclientset.Interface + agentInstallNamespace func(addon *addonapiv1alpha1.ManagedClusterAddOn) (string, error) + helmEngineStrict bool } func newHelmAgentAddon(factory *AgentAddonFactory, chart *chart.Chart) *HelmAgentAddon { @@ -59,11 +67,40 @@ func newHelmAgentAddon(factory *AgentAddonFactory, chart *chart.Chart) *HelmAgen agentAddonOptions: factory.agentAddonOptions, trimCRDDescription: factory.trimCRDDescription, hostingCluster: factory.hostingCluster, + clusterClient: factory.clusterClient, agentInstallNamespace: factory.agentInstallNamespace, + helmEngineStrict: factory.helmEngineStrict, } } func (a *HelmAgentAddon) Manifests( + cluster *clusterv1.ManagedCluster, + addon *addonapiv1alpha1.ManagedClusterAddOn) ([]runtime.Object, error) { + objects, err := a.renderManifests(cluster, addon) + if err != nil { + return nil, err + } + + manifests := make([]manifest, 0, len(objects)) + for _, obj := range objects { + a, err := meta.TypeAccessor(obj) + if err != nil { + return nil, err + } + manifests = append(manifests, manifest{ + Object: obj, + Kind: a.GetKind(), + }) + } + sortManifestsByKind(manifests, releaseutil.InstallOrder) + + for i, manifest := range manifests { + objects[i] = manifest.Object + } + return objects, nil +} + +func (a *HelmAgentAddon) renderManifests( cluster *clusterv1.ManagedCluster, addon *addonapiv1alpha1.ManagedClusterAddOn) ([]runtime.Object, error) { var objects []runtime.Object @@ -74,7 +111,7 @@ func (a *HelmAgentAddon) Manifests( } helmEngine := engine.Engine{ - Strict: true, + Strict: a.helmEngineStrict, LintMode: false, } @@ -93,16 +130,7 @@ func (a *HelmAgentAddon) Manifests( return objects, err } - // sort the filenames of the templates so the manifests are ordered consistently - keys := make([]string, 0, len(templates)) - for k := range templates { - keys = append(keys, k) - } - sort.Strings(keys) - - for _, k := range keys { - data := templates[k] - + for k, data := range templates { if len(data) == 0 { continue } @@ -131,7 +159,6 @@ func (a *HelmAgentAddon) Manifests( objects = append(objects, object) } } - } if a.trimCRDDescription { @@ -177,8 +204,12 @@ func (a *HelmAgentAddon) getValues( overrideValues = MergeValues(overrideValues, builtinValues) + releaseOptions, err := a.releaseOptions(addon) + if err != nil { + return nil, err + } values, err := chartutil.ToRenderValues(a.chart, overrideValues, - a.releaseOptions(addon), a.capabilities(cluster, addon)) + releaseOptions, a.capabilities(cluster, addon)) if err != nil { klog.Errorf("failed to render helm chart with values %v. err:%v", overrideValues, err) return values, err @@ -187,18 +218,25 @@ func (a *HelmAgentAddon) getValues( return values, nil } -func (a *HelmAgentAddon) getValueAgentInstallNamespace(addon *addonapiv1alpha1.ManagedClusterAddOn) string { +func (a *HelmAgentAddon) getValueAgentInstallNamespace(addon *addonapiv1alpha1.ManagedClusterAddOn) (string, error) { installNamespace := addon.Spec.InstallNamespace if len(installNamespace) == 0 { installNamespace = AddonDefaultInstallNamespace } if a.agentInstallNamespace != nil { - ns := a.agentInstallNamespace(addon) + ns, err := a.agentInstallNamespace(addon) + if err != nil { + klog.Errorf("failed to get agentInstallNamespace from addon %s. err: %v", addon.Name, err) + return "", err + } if len(ns) > 0 { installNamespace = ns + } else { + klog.InfoS("Namespace for addon returned by agent install namespace func is empty", + "addonNamespace", addon.Namespace, "addonName", addon) } } - return installNamespace + return installNamespace, nil } func (a *HelmAgentAddon) getBuiltinValues( @@ -207,9 +245,13 @@ func (a *HelmAgentAddon) getBuiltinValues( builtinValues := helmBuiltinValues{} builtinValues.ClusterName = cluster.GetName() - builtinValues.AddonInstallNamespace = a.getValueAgentInstallNamespace(addon) + addonInstallNamespace, err := a.getValueAgentInstallNamespace(addon) + if err != nil { + return nil, err + } + builtinValues.AddonInstallNamespace = addonInstallNamespace - builtinValues.InstallMode, _ = constants.GetHostedModeInfo(addon.GetAnnotations()) + builtinValues.InstallMode, _ = a.agentAddonOptions.HostedModeInfoFunc(addon, cluster) helmBuiltinValues, err := JsonStructToValues(builtinValues) if err != nil { @@ -219,6 +261,12 @@ func (a *HelmAgentAddon) getBuiltinValues( return helmBuiltinValues, nil } +// Deprecated: use "WithManagedClusterClient" in AgentAddonFactory to set a cluster client that +// can be used to get the hosting cluster. +func (a *HelmAgentAddon) SetHostingCluster(hostingCluster *clusterv1.ManagedCluster) { + a.hostingCluster = hostingCluster +} + func (a *HelmAgentAddon) getDefaultValues( cluster *clusterv1.ManagedCluster, addon *addonapiv1alpha1.ManagedClusterAddOn) (Values, error) { @@ -233,6 +281,21 @@ func (a *HelmAgentAddon) getDefaultValues( if a.hostingCluster != nil { defaultValues.HostingClusterCapabilities = *a.capabilities(a.hostingCluster, addon) + } else if a.clusterClient != nil { + _, hostingClusterName := a.agentAddonOptions.HostedModeInfoFunc(addon, cluster) + if len(hostingClusterName) > 0 { + hostingCluster, err := a.clusterClient.ClusterV1().ManagedClusters(). + Get(context.TODO(), hostingClusterName, metav1.GetOptions{}) + if err == nil { + defaultValues.HostingClusterCapabilities = *a.capabilities(hostingCluster, addon) + } else if errors.IsNotFound(err) { + klog.Infof("hostingCluster %s not found, skip providing default value hostingClusterCapabilities", + hostingClusterName) + } else { + klog.Errorf("failed to get hostingCluster %s. err:%v", hostingClusterName, err) + return nil, err + } + } } helmDefaultValues, err := JsonStructToValues(defaultValues) @@ -254,9 +317,58 @@ func (a *HelmAgentAddon) capabilities( // only support Release.Name, Release.Namespace func (a *HelmAgentAddon) releaseOptions( - addon *addonapiv1alpha1.ManagedClusterAddOn) chartutil.ReleaseOptions { - return chartutil.ReleaseOptions{ - Name: a.agentAddonOptions.AddonName, - Namespace: a.getValueAgentInstallNamespace(addon), + addon *addonapiv1alpha1.ManagedClusterAddOn) (chartutil.ReleaseOptions, error) { + releaseOptions := chartutil.ReleaseOptions{ + Name: a.agentAddonOptions.AddonName, + } + namespace, err := a.getValueAgentInstallNamespace(addon) + if err != nil { + return releaseOptions, err + } + releaseOptions.Namespace = namespace + return releaseOptions, nil +} + +// manifest represents a manifest file, which has a name and some content. +type manifest struct { + Object runtime.Object + Kind string +} + +// sort manifests by kind. +// +// Results are sorted by 'ordering', keeping order of items with equal kind/priority +func sortManifestsByKind(manifests []manifest, ordering releaseutil.KindSortOrder) []manifest { + sort.SliceStable(manifests, func(i, j int) bool { + return lessByKind(manifests[i], manifests[j], manifests[i].Kind, manifests[j].Kind, ordering) + }) + + return manifests +} + +func lessByKind(a interface{}, b interface{}, kindA string, kindB string, o releaseutil.KindSortOrder) bool { + ordering := make(map[string]int, len(o)) + for v, k := range o { + ordering[k] = v + } + + first, aok := ordering[kindA] + second, bok := ordering[kindB] + + if !aok && !bok { + // if both are unknown then sort alphabetically by kind, keep original order if same kind + if kindA != kindB { + return kindA < kindB + } + return first < second + } + // unknown kind is last + if !aok { + return false + } + if !bok { + return true } + // sort different kinds, keep original order if same priority + return first < second } diff --git a/vendor/open-cluster-management.io/addon-framework/pkg/addonfactory/template_agentaddon.go b/vendor/open-cluster-management.io/addon-framework/pkg/addonfactory/template_agentaddon.go index 57584ac19..5772fe95c 100644 --- a/vendor/open-cluster-management.io/addon-framework/pkg/addonfactory/template_agentaddon.go +++ b/vendor/open-cluster-management.io/addon-framework/pkg/addonfactory/template_agentaddon.go @@ -9,7 +9,6 @@ import ( addonapiv1alpha1 "open-cluster-management.io/api/addon/v1alpha1" clusterv1 "open-cluster-management.io/api/cluster/v1" - "open-cluster-management.io/addon-framework/pkg/addonmanager/constants" "open-cluster-management.io/addon-framework/pkg/agent" "open-cluster-management.io/addon-framework/pkg/assets" ) @@ -42,7 +41,7 @@ type TemplateAgentAddon struct { getValuesFuncs []GetValuesFunc agentAddonOptions agent.AgentAddonOptions trimCRDDescription bool - agentInstallNamespace func(addon *addonapiv1alpha1.ManagedClusterAddOn) string + agentInstallNamespace func(addon *addonapiv1alpha1.ManagedClusterAddOn) (string, error) } func newTemplateAgentAddon(factory *AgentAddonFactory) *TemplateAgentAddon { @@ -109,7 +108,10 @@ func (a *TemplateAgentAddon) getValues( overrideValues = MergeValues(overrideValues, userValues) } } - builtinValues := a.getBuiltinValues(cluster, addon) + builtinValues, err := a.getBuiltinValues(cluster, addon) + if err != nil { + return overrideValues, err + } overrideValues = MergeValues(overrideValues, builtinValues) return overrideValues, nil @@ -117,7 +119,7 @@ func (a *TemplateAgentAddon) getValues( func (a *TemplateAgentAddon) getBuiltinValues( cluster *clusterv1.ManagedCluster, - addon *addonapiv1alpha1.ManagedClusterAddOn) Values { + addon *addonapiv1alpha1.ManagedClusterAddOn) (Values, error) { builtinValues := templateBuiltinValues{} builtinValues.ClusterName = cluster.GetName() @@ -126,16 +128,23 @@ func (a *TemplateAgentAddon) getBuiltinValues( installNamespace = AddonDefaultInstallNamespace } if a.agentInstallNamespace != nil { - ns := a.agentInstallNamespace(addon) + ns, err := a.agentInstallNamespace(addon) + if err != nil { + klog.Errorf("failed to get agent install namespace for addon %s: %v", addon.Name, err) + return nil, err + } if len(ns) > 0 { installNamespace = ns + } else { + klog.InfoS("Namespace for addon returned by agent install namespace func is empty", + "addonNamespace", addon.Namespace, "addonName", addon) } } builtinValues.AddonInstallNamespace = installNamespace - builtinValues.InstallMode, _ = constants.GetHostedModeInfo(addon.GetAnnotations()) + builtinValues.InstallMode, _ = a.agentAddonOptions.HostedModeInfoFunc(addon, cluster) - return StructToValues(builtinValues) + return StructToValues(builtinValues), nil } func (a *TemplateAgentAddon) getDefaultValues( diff --git a/vendor/open-cluster-management.io/addon-framework/pkg/addonmanager/constants/constants.go b/vendor/open-cluster-management.io/addon-framework/pkg/addonmanager/constants/constants.go index 56e6f0169..ffc2829a2 100644 --- a/vendor/open-cluster-management.io/addon-framework/pkg/addonmanager/constants/constants.go +++ b/vendor/open-cluster-management.io/addon-framework/pkg/addonmanager/constants/constants.go @@ -4,6 +4,7 @@ import ( "fmt" addonv1alpha1 "open-cluster-management.io/api/addon/v1alpha1" + clusterv1 "open-cluster-management.io/api/cluster/v1" ) const ( @@ -35,8 +36,11 @@ func PreDeleteHookHostingWorkName(addonNamespace, addonName string) string { } // GetHostedModeInfo returns addon installation mode and hosting cluster name. -func GetHostedModeInfo(annotations map[string]string) (string, string) { - hostingClusterName, ok := annotations[addonv1alpha1.HostingClusterNameAnnotationKey] +func GetHostedModeInfo(addon *addonv1alpha1.ManagedClusterAddOn, _ *clusterv1.ManagedCluster) (string, string) { + if len(addon.Annotations) == 0 { + return InstallModeDefault, "" + } + hostingClusterName, ok := addon.Annotations[addonv1alpha1.HostingClusterNameAnnotationKey] if !ok { return InstallModeDefault, "" } diff --git a/vendor/open-cluster-management.io/addon-framework/pkg/addonmanager/controllers/addoninstall/controller.go b/vendor/open-cluster-management.io/addon-framework/pkg/addonmanager/controllers/addoninstall/controller.go deleted file mode 100644 index 4c57759e7..000000000 --- a/vendor/open-cluster-management.io/addon-framework/pkg/addonmanager/controllers/addoninstall/controller.go +++ /dev/null @@ -1,138 +0,0 @@ -package addoninstall - -import ( - "context" - "strings" - - "k8s.io/apimachinery/pkg/api/errors" - "k8s.io/apimachinery/pkg/api/meta" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/runtime" - errorsutil "k8s.io/apimachinery/pkg/util/errors" - "k8s.io/klog/v2" - addonapiv1alpha1 "open-cluster-management.io/api/addon/v1alpha1" - addonv1alpha1client "open-cluster-management.io/api/client/addon/clientset/versioned" - addoninformerv1alpha1 "open-cluster-management.io/api/client/addon/informers/externalversions/addon/v1alpha1" - addonlisterv1alpha1 "open-cluster-management.io/api/client/addon/listers/addon/v1alpha1" - clusterinformers "open-cluster-management.io/api/client/cluster/informers/externalversions/cluster/v1" - clusterlister "open-cluster-management.io/api/client/cluster/listers/cluster/v1" - - "open-cluster-management.io/addon-framework/pkg/agent" - "open-cluster-management.io/addon-framework/pkg/basecontroller/factory" -) - -// managedClusterController reconciles instances of ManagedCluster on the hub. -type addonInstallController struct { - addonClient addonv1alpha1client.Interface - managedClusterLister clusterlister.ManagedClusterLister - managedClusterAddonLister addonlisterv1alpha1.ManagedClusterAddOnLister - agentAddons map[string]agent.AgentAddon -} - -func NewAddonInstallController( - addonClient addonv1alpha1client.Interface, - clusterInformers clusterinformers.ManagedClusterInformer, - addonInformers addoninformerv1alpha1.ManagedClusterAddOnInformer, - agentAddons map[string]agent.AgentAddon, -) factory.Controller { - c := &addonInstallController{ - addonClient: addonClient, - managedClusterLister: clusterInformers.Lister(), - managedClusterAddonLister: addonInformers.Lister(), - agentAddons: agentAddons, - } - - return factory.New().WithFilteredEventsInformersQueueKeysFunc( - func(obj runtime.Object) []string { - accessor, _ := meta.Accessor(obj) - return []string{accessor.GetNamespace()} - }, - func(obj interface{}) bool { - accessor, _ := meta.Accessor(obj) - if _, ok := c.agentAddons[accessor.GetName()]; !ok { - return false - } - - return true - }, - addonInformers.Informer()). - WithInformersQueueKeysFunc( - func(obj runtime.Object) []string { - accessor, _ := meta.Accessor(obj) - return []string{accessor.GetName()} - }, - clusterInformers.Informer(), - ). - WithSync(c.sync).ToController("addon-install-controller") -} - -func (c *addonInstallController) sync(ctx context.Context, syncCtx factory.SyncContext, clusterName string) error { - klog.V(4).Infof("Reconciling addon deploy on cluster %q", clusterName) - - cluster, err := c.managedClusterLister.Get(clusterName) - if errors.IsNotFound(err) { - return nil - } - if err != nil { - return err - } - - // if cluster is deleting, do not install addon - if !cluster.DeletionTimestamp.IsZero() { - klog.V(4).Infof("Cluster %q is deleting, skip addon deploy", clusterName) - return nil - } - - if value, ok := cluster.Annotations[addonapiv1alpha1.DisableAddonAutomaticInstallationAnnotationKey]; ok && - strings.EqualFold(value, "true") { - - klog.V(4).Infof("Cluster %q has annotation %q, skip addon deploy", - clusterName, addonapiv1alpha1.DisableAddonAutomaticInstallationAnnotationKey) - return nil - } - - var errs []error - - for addonName, addon := range c.agentAddons { - if addon.GetAgentAddonOptions().InstallStrategy == nil { - continue - } - - managedClusterFilter := addon.GetAgentAddonOptions().InstallStrategy.GetManagedClusterFilter() - if managedClusterFilter == nil { - continue - } - if !managedClusterFilter(cluster) { - klog.V(4).Infof("managed cluster filter is not match for addon %s on %s", addonName, clusterName) - continue - } - - err = c.applyAddon(ctx, addonName, clusterName, addon.GetAgentAddonOptions().InstallStrategy.InstallNamespace) - if err != nil { - errs = append(errs, err) - } - } - - return errorsutil.NewAggregate(errs) -} - -func (c *addonInstallController) applyAddon(ctx context.Context, addonName, clusterName, installNamespace string) error { - _, err := c.managedClusterAddonLister.ManagedClusterAddOns(clusterName).Get(addonName) - - // only create addon when it is missing, if user update the addon resource ,it should not be reverted - if errors.IsNotFound(err) { - addon := &addonapiv1alpha1.ManagedClusterAddOn{ - ObjectMeta: metav1.ObjectMeta{ - Name: addonName, - Namespace: clusterName, - }, - Spec: addonapiv1alpha1.ManagedClusterAddOnSpec{ - InstallNamespace: installNamespace, - }, - } - _, err = c.addonClient.AddonV1alpha1().ManagedClusterAddOns(clusterName).Create(ctx, addon, metav1.CreateOptions{}) - return err - } - - return err -} diff --git a/vendor/open-cluster-management.io/addon-framework/pkg/addonmanager/controllers/agentdeploy/controller.go b/vendor/open-cluster-management.io/addon-framework/pkg/addonmanager/controllers/agentdeploy/controller.go index 930a0afaf..e5e7bed3a 100644 --- a/vendor/open-cluster-management.io/addon-framework/pkg/addonmanager/controllers/agentdeploy/controller.go +++ b/vendor/open-cluster-management.io/addon-framework/pkg/addonmanager/controllers/agentdeploy/controller.go @@ -252,25 +252,37 @@ func (c *addonDeployController) sync(ctx context.Context, syncCtx factory.SyncCo syncers := []addonDeploySyncer{ &defaultSyncer{ - buildWorks: c.buildDeployManifestWorks, + buildWorks: c.buildDeployManifestWorksFunc( + newAddonWorksBuilder(agentAddon.GetAgentAddonOptions().HostedModeEnabled, c.workBuilder), + addonapiv1alpha1.ManagedClusterAddOnManifestApplied, + ), applyWork: c.applyWork, getWorkByAddon: c.getWorksByAddonFn(index.ManifestWorkByAddon), deleteWork: c.workApplier.Delete, agentAddon: agentAddon, }, &hostedSyncer{ - buildWorks: c.buildDeployManifestWorks, + buildWorks: c.buildDeployManifestWorksFunc( + newHostingAddonWorksBuilder(agentAddon.GetAgentAddonOptions().HostedModeEnabled, c.workBuilder), + addonapiv1alpha1.ManagedClusterAddOnHostingManifestApplied, + ), applyWork: c.applyWork, deleteWork: c.workApplier.Delete, getCluster: c.managedClusterLister.Get, getWorkByAddon: c.getWorksByAddonFn(index.ManifestWorkByHostedAddon), agentAddon: agentAddon}, &defaultHookSyncer{ - buildWorks: c.buildHookManifestWork, + buildWorks: c.buildHookManifestWorkFunc( + newAddonWorksBuilder(agentAddon.GetAgentAddonOptions().HostedModeEnabled, c.workBuilder), + addonapiv1alpha1.ManagedClusterAddOnManifestApplied, + ), applyWork: c.applyWork, agentAddon: agentAddon}, &hostedHookSyncer{ - buildWorks: c.buildHookManifestWork, + buildWorks: c.buildHookManifestWorkFunc( + newHostingAddonWorksBuilder(agentAddon.GetAgentAddonOptions().HostedModeEnabled, c.workBuilder), + addonapiv1alpha1.ManagedClusterAddOnHostingManifestApplied, + ), applyWork: c.applyWork, deleteWork: c.workApplier.Delete, getCluster: c.managedClusterLister.Get, @@ -354,103 +366,109 @@ func (c *addonDeployController) applyWork(ctx context.Context, appliedType strin return work, nil } -func (c *addonDeployController) buildDeployManifestWorks(installMode, workNamespace string, +type buildDeployWorkFunc func( + workNamespace string, cluster *clusterv1.ManagedCluster, existingWorks []*workapiv1.ManifestWork, - addon *addonapiv1alpha1.ManagedClusterAddOn) (appliedWorks, deleteWorks []*workapiv1.ManifestWork, err error) { - var appliedType string - var addonWorkBuilder *addonWorksBuilder - - agentAddon := c.agentAddons[addon.Name] - if agentAddon == nil { - return nil, nil, fmt.Errorf("failed to get agentAddon") - } + addon *addonapiv1alpha1.ManagedClusterAddOn) (appliedWorks, deleteWorks []*workapiv1.ManifestWork, err error) + +func (c *addonDeployController) buildDeployManifestWorksFunc(addonWorkBuilder *addonWorksBuilder, appliedType string) buildDeployWorkFunc { + return func( + workNamespace string, + cluster *clusterv1.ManagedCluster, existingWorks []*workapiv1.ManifestWork, + addon *addonapiv1alpha1.ManagedClusterAddOn) (appliedWorks, deleteWorks []*workapiv1.ManifestWork, err error) { + agentAddon := c.agentAddons[addon.Name] + if agentAddon == nil { + return nil, nil, fmt.Errorf("failed to get agentAddon") + } - switch installMode { - case constants.InstallModeHosted: - appliedType = addonapiv1alpha1.ManagedClusterAddOnHostingManifestApplied - addonWorkBuilder = newHostingAddonWorksBuilder(agentAddon.GetAgentAddonOptions().HostedModeEnabled, c.workBuilder) - case constants.InstallModeDefault: - appliedType = addonapiv1alpha1.ManagedClusterAddOnManifestApplied - addonWorkBuilder = newAddonWorksBuilder(agentAddon.GetAgentAddonOptions().HostedModeEnabled, c.workBuilder) - default: - return nil, nil, fmt.Errorf("invalid install mode %v", installMode) - } + objects, err := agentAddon.Manifests(cluster, addon) + if err != nil { + meta.SetStatusCondition(&addon.Status.Conditions, metav1.Condition{ + Type: appliedType, + Status: metav1.ConditionFalse, + Reason: addonapiv1alpha1.AddonManifestAppliedReasonWorkApplyFailed, + Message: fmt.Sprintf("failed to get manifest from agent interface: %v", err), + }) + return nil, nil, err + } + if len(objects) == 0 { + return nil, nil, nil + } - objects, err := agentAddon.Manifests(cluster, addon) - if err != nil { - meta.SetStatusCondition(&addon.Status.Conditions, metav1.Condition{ - Type: appliedType, - Status: metav1.ConditionFalse, - Reason: addonapiv1alpha1.AddonManifestAppliedReasonWorkApplyFailed, - Message: fmt.Sprintf("failed to get manifest from agent interface: %v", err), - }) - return nil, nil, err - } - if len(objects) == 0 { - return nil, nil, nil - } + // this is to retrieve the intended mode of the addon. + var mode string + if agentAddon.GetAgentAddonOptions().HostedModeInfoFunc == nil { + mode = constants.InstallModeDefault + } else { + mode, _ = agentAddon.GetAgentAddonOptions().HostedModeInfoFunc(addon, cluster) + } - manifestOptions := getManifestConfigOption(agentAddon, cluster, addon) - existingWorksCopy := []workapiv1.ManifestWork{} - for _, work := range existingWorks { - existingWorksCopy = append(existingWorksCopy, *work) - } - appliedWorks, deleteWorks, err = addonWorkBuilder.BuildDeployWorks(workNamespace, addon, existingWorksCopy, objects, manifestOptions) - if err != nil { - meta.SetStatusCondition(&addon.Status.Conditions, metav1.Condition{ - Type: appliedType, - Status: metav1.ConditionFalse, - Reason: addonapiv1alpha1.AddonManifestAppliedReasonWorkApplyFailed, - Message: fmt.Sprintf("failed to build manifestwork: %v", err), - }) - return nil, nil, err + manifestOptions := getManifestConfigOption(agentAddon, cluster, addon) + existingWorksCopy := []workapiv1.ManifestWork{} + for _, work := range existingWorks { + existingWorksCopy = append(existingWorksCopy, *work) + } + appliedWorks, deleteWorks, err = addonWorkBuilder.BuildDeployWorks( + mode, workNamespace, addon, existingWorksCopy, objects, manifestOptions) + if err != nil { + meta.SetStatusCondition(&addon.Status.Conditions, metav1.Condition{ + Type: appliedType, + Status: metav1.ConditionFalse, + Reason: addonapiv1alpha1.AddonManifestAppliedReasonWorkApplyFailed, + Message: fmt.Sprintf("failed to build manifestwork: %v", err), + }) + return nil, nil, err + } + return appliedWorks, deleteWorks, nil } - return appliedWorks, deleteWorks, nil } -func (c *addonDeployController) buildHookManifestWork(installMode, workNamespace string, - cluster *clusterv1.ManagedCluster, addon *addonapiv1alpha1.ManagedClusterAddOn) (*workapiv1.ManifestWork, error) { - var appliedType string - var addonWorkBuilder *addonWorksBuilder - - agentAddon := c.agentAddons[addon.Name] - if agentAddon == nil { - return nil, fmt.Errorf("failed to get agentAddon") - } - switch installMode { - case constants.InstallModeHosted: - appliedType = addonapiv1alpha1.ManagedClusterAddOnHostingManifestApplied - addonWorkBuilder = newHostingAddonWorksBuilder(agentAddon.GetAgentAddonOptions().HostedModeEnabled, c.workBuilder) - case constants.InstallModeDefault: - appliedType = addonapiv1alpha1.ManagedClusterAddOnManifestApplied - addonWorkBuilder = newAddonWorksBuilder(agentAddon.GetAgentAddonOptions().HostedModeEnabled, c.workBuilder) - default: - return nil, fmt.Errorf("invalid install mode %v", installMode) - } +type buildDeployHookFunc func( + workNamespace string, + cluster *clusterv1.ManagedCluster, + addon *addonapiv1alpha1.ManagedClusterAddOn) (*workapiv1.ManifestWork, error) - objects, err := agentAddon.Manifests(cluster, addon) - if err != nil { - meta.SetStatusCondition(&addon.Status.Conditions, metav1.Condition{ - Type: appliedType, - Status: metav1.ConditionFalse, - Reason: addonapiv1alpha1.AddonManifestAppliedReasonWorkApplyFailed, - Message: fmt.Sprintf("failed to get manifest from agent interface: %v", err), - }) - return nil, err - } - if len(objects) == 0 { - return nil, nil - } +func (c *addonDeployController) buildHookManifestWorkFunc(addonWorkBuilder *addonWorksBuilder, appliedType string) buildDeployHookFunc { + return func( + workNamespace string, + cluster *clusterv1.ManagedCluster, + addon *addonapiv1alpha1.ManagedClusterAddOn) (*workapiv1.ManifestWork, error) { + agentAddon := c.agentAddons[addon.Name] + if agentAddon == nil { + return nil, fmt.Errorf("failed to get agentAddon") + } - hookWork, err := addonWorkBuilder.BuildHookWork(workNamespace, addon, objects) - if err != nil { - meta.SetStatusCondition(&addon.Status.Conditions, metav1.Condition{ - Type: appliedType, - Status: metav1.ConditionFalse, - Reason: addonapiv1alpha1.AddonManifestAppliedReasonWorkApplyFailed, - Message: fmt.Sprintf("failed to build manifestwork: %v", err), - }) - return nil, err + objects, err := agentAddon.Manifests(cluster, addon) + if err != nil { + meta.SetStatusCondition(&addon.Status.Conditions, metav1.Condition{ + Type: appliedType, + Status: metav1.ConditionFalse, + Reason: addonapiv1alpha1.AddonManifestAppliedReasonWorkApplyFailed, + Message: fmt.Sprintf("failed to get manifest from agent interface: %v", err), + }) + return nil, err + } + if len(objects) == 0 { + return nil, nil + } + + // this is to retrieve the intended mode of the addon. + var mode string + if agentAddon.GetAgentAddonOptions().HostedModeInfoFunc == nil { + mode = constants.InstallModeDefault + } else { + mode, _ = agentAddon.GetAgentAddonOptions().HostedModeInfoFunc(addon, cluster) + } + hookWork, err := addonWorkBuilder.BuildHookWork(mode, workNamespace, addon, objects) + if err != nil { + meta.SetStatusCondition(&addon.Status.Conditions, metav1.Condition{ + Type: appliedType, + Status: metav1.ConditionFalse, + Reason: addonapiv1alpha1.AddonManifestAppliedReasonWorkApplyFailed, + Message: fmt.Sprintf("failed to build manifestwork: %v", err), + }) + return nil, err + } + return hookWork, nil } - return hookWork, nil } diff --git a/vendor/open-cluster-management.io/addon-framework/pkg/addonmanager/controllers/agentdeploy/default_hook_sync.go b/vendor/open-cluster-management.io/addon-framework/pkg/addonmanager/controllers/agentdeploy/default_hook_sync.go index bcca12205..03e45f9b1 100644 --- a/vendor/open-cluster-management.io/addon-framework/pkg/addonmanager/controllers/agentdeploy/default_hook_sync.go +++ b/vendor/open-cluster-management.io/addon-framework/pkg/addonmanager/controllers/agentdeploy/default_hook_sync.go @@ -10,15 +10,13 @@ import ( clusterv1 "open-cluster-management.io/api/cluster/v1" workapiv1 "open-cluster-management.io/api/work/v1" - "open-cluster-management.io/addon-framework/pkg/addonmanager/constants" "open-cluster-management.io/addon-framework/pkg/agent" "open-cluster-management.io/addon-framework/pkg/basecontroller/factory" ) type defaultHookSyncer struct { - buildWorks func(installMode, workNamespace string, cluster *clusterv1.ManagedCluster, - addon *addonapiv1alpha1.ManagedClusterAddOn) (*workapiv1.ManifestWork, error) - applyWork func(ctx context.Context, appliedType string, + buildWorks buildDeployHookFunc + applyWork func(ctx context.Context, appliedType string, work *workapiv1.ManifestWork, addon *addonapiv1alpha1.ManagedClusterAddOn) (*workapiv1.ManifestWork, error) agentAddon agent.AgentAddon } @@ -29,7 +27,7 @@ func (s *defaultHookSyncer) sync(ctx context.Context, addon *addonapiv1alpha1.ManagedClusterAddOn) (*addonapiv1alpha1.ManagedClusterAddOn, error) { deployWorkNamespace := addon.Namespace - hookWork, err := s.buildWorks(constants.InstallModeDefault, deployWorkNamespace, cluster, addon) + hookWork, err := s.buildWorks(deployWorkNamespace, cluster, addon) if err != nil { return addon, err } diff --git a/vendor/open-cluster-management.io/addon-framework/pkg/addonmanager/controllers/agentdeploy/default_sync.go b/vendor/open-cluster-management.io/addon-framework/pkg/addonmanager/controllers/agentdeploy/default_sync.go index c53c76ab9..621851726 100644 --- a/vendor/open-cluster-management.io/addon-framework/pkg/addonmanager/controllers/agentdeploy/default_sync.go +++ b/vendor/open-cluster-management.io/addon-framework/pkg/addonmanager/controllers/agentdeploy/default_sync.go @@ -8,14 +8,12 @@ import ( clusterv1 "open-cluster-management.io/api/cluster/v1" workapiv1 "open-cluster-management.io/api/work/v1" - "open-cluster-management.io/addon-framework/pkg/addonmanager/constants" "open-cluster-management.io/addon-framework/pkg/agent" "open-cluster-management.io/addon-framework/pkg/basecontroller/factory" ) type defaultSyncer struct { - buildWorks func(installMode, workNamespace string, cluster *clusterv1.ManagedCluster, existingWorks []*workapiv1.ManifestWork, - addon *addonapiv1alpha1.ManagedClusterAddOn) (appliedWorks, deleteWorks []*workapiv1.ManifestWork, err error) + buildWorks buildDeployWorkFunc applyWork func(ctx context.Context, appliedType string, work *workapiv1.ManifestWork, addon *addonapiv1alpha1.ManagedClusterAddOn) (*workapiv1.ManifestWork, error) @@ -54,7 +52,7 @@ func (s *defaultSyncer) sync(ctx context.Context, return addon, err } - deployWorks, deleteWorks, err := s.buildWorks(constants.InstallModeDefault, deployWorkNamespace, cluster, currentWorks, addon) + deployWorks, deleteWorks, err := s.buildWorks(deployWorkNamespace, cluster, currentWorks, addon) if err != nil { return addon, err } diff --git a/vendor/open-cluster-management.io/addon-framework/pkg/addonmanager/controllers/agentdeploy/hosted_hook_sync.go b/vendor/open-cluster-management.io/addon-framework/pkg/addonmanager/controllers/agentdeploy/hosted_hook_sync.go index 98b14f80a..3ee5eb47b 100644 --- a/vendor/open-cluster-management.io/addon-framework/pkg/addonmanager/controllers/agentdeploy/hosted_hook_sync.go +++ b/vendor/open-cluster-management.io/addon-framework/pkg/addonmanager/controllers/agentdeploy/hosted_hook_sync.go @@ -18,8 +18,7 @@ import ( ) type hostedHookSyncer struct { - buildWorks func(installMode, workNamespace string, cluster *clusterv1.ManagedCluster, - addon *addonapiv1alpha1.ManagedClusterAddOn) (*workapiv1.ManifestWork, error) + buildWorks buildDeployHookFunc applyWork func(ctx context.Context, appliedType string, work *workapiv1.ManifestWork, addon *addonapiv1alpha1.ManagedClusterAddOn) (*workapiv1.ManifestWork, error) @@ -43,7 +42,10 @@ func (s *hostedHookSyncer) sync(ctx context.Context, return addon, nil } - installMode, hostingClusterName := constants.GetHostedModeInfo(addon.GetAnnotations()) + if s.agentAddon.GetAgentAddonOptions().HostedModeInfoFunc == nil { + return addon, nil + } + installMode, hostingClusterName := s.agentAddon.GetAgentAddonOptions().HostedModeInfoFunc(addon, cluster) if installMode != constants.InstallModeHosted { return addon, nil } @@ -70,7 +72,7 @@ func (s *hostedHookSyncer) sync(ctx context.Context, addonRemoveFinalizer(addon, addonapiv1alpha1.AddonHostingPreDeleteHookFinalizer) return addon, nil } - hookWork, err := s.buildWorks(constants.InstallModeHosted, hostingClusterName, cluster, addon) + hookWork, err := s.buildWorks(hostingClusterName, cluster, addon) if err != nil { return addon, err } diff --git a/vendor/open-cluster-management.io/addon-framework/pkg/addonmanager/controllers/agentdeploy/hosted_sync.go b/vendor/open-cluster-management.io/addon-framework/pkg/addonmanager/controllers/agentdeploy/hosted_sync.go index 55a0546f7..19a9bca4d 100644 --- a/vendor/open-cluster-management.io/addon-framework/pkg/addonmanager/controllers/agentdeploy/hosted_sync.go +++ b/vendor/open-cluster-management.io/addon-framework/pkg/addonmanager/controllers/agentdeploy/hosted_sync.go @@ -18,8 +18,7 @@ import ( ) type hostedSyncer struct { - buildWorks func(installMode, workNamespace string, cluster *clusterv1.ManagedCluster, existingWorks []*workapiv1.ManifestWork, - addon *addonapiv1alpha1.ManagedClusterAddOn) (appliedWorks, deleteWorks []*workapiv1.ManifestWork, err error) + buildWorks buildDeployWorkFunc applyWork func(ctx context.Context, appliedType string, work *workapiv1.ManifestWork, addon *addonapiv1alpha1.ManagedClusterAddOn) (*workapiv1.ManifestWork, error) @@ -42,7 +41,10 @@ func (s *hostedSyncer) sync(ctx context.Context, return addon, nil } - installMode, hostingClusterName := constants.GetHostedModeInfo(addon.GetAnnotations()) + if s.agentAddon.GetAgentAddonOptions().HostedModeInfoFunc == nil { + return addon, nil + } + installMode, hostingClusterName := s.agentAddon.GetAgentAddonOptions().HostedModeInfoFunc(addon, cluster) if installMode != constants.InstallModeHosted { // the installMode is changed from hosted to default, cleanup the hosting resources if err := s.cleanupDeployWork(ctx, addon); err != nil { @@ -115,7 +117,7 @@ func (s *hostedSyncer) sync(ctx context.Context, return addon, err } - deployWorks, deleteWorks, err := s.buildWorks(constants.InstallModeHosted, hostingClusterName, cluster, currentWorks, addon) + deployWorks, deleteWorks, err := s.buildWorks(hostingClusterName, cluster, currentWorks, addon) if err != nil { return addon, err } diff --git a/vendor/open-cluster-management.io/addon-framework/pkg/addonmanager/controllers/agentdeploy/utils.go b/vendor/open-cluster-management.io/addon-framework/pkg/addonmanager/controllers/agentdeploy/utils.go index a258369ea..7df50357a 100644 --- a/vendor/open-cluster-management.io/addon-framework/pkg/addonmanager/controllers/agentdeploy/utils.go +++ b/vendor/open-cluster-management.io/addon-framework/pkg/addonmanager/controllers/agentdeploy/utils.go @@ -260,19 +260,16 @@ func (m *managedManifest) preDeleteHookManifestWorkName(addonNamespace, addonNam // BuildDeployWorks returns the deploy manifestWorks. if there is no manifest need // to deploy, will return nil. -func (b *addonWorksBuilder) BuildDeployWorks(addonWorkNamespace string, +func (b *addonWorksBuilder) BuildDeployWorks(installMode, addonWorkNamespace string, addon *addonapiv1alpha1.ManagedClusterAddOn, existingWorks []workapiv1.ManifestWork, objects []runtime.Object, manifestOptions []workapiv1.ManifestConfigOption) (deployWorks, deleteWorks []*workapiv1.ManifestWork, err error) { var deployObjects []runtime.Object - var owner *metav1.OwnerReference - installMode, _ := constants.GetHostedModeInfo(addon.GetAnnotations()) - // This owner is only added to the manifestWork deployed in managed cluster ns. // the manifestWork in managed cluster ns is cleaned up via the addon ownerRef, so need to add the owner. // the manifestWork in hosting cluster ns is cleaned up by its controller since it and its addon cross ns. - owner = metav1.NewControllerRef(addon, addonapiv1alpha1.GroupVersion.WithKind("ManagedClusterAddOn")) + owner := metav1.NewControllerRef(addon, addonapiv1alpha1.GroupVersion.WithKind("ManagedClusterAddOn")) var deletionOrphaningRules []workapiv1.OrphaningRule for _, object := range objects { @@ -328,18 +325,13 @@ func (b *addonWorksBuilder) BuildDeployWorks(addonWorkNamespace string, // BuildHookWork returns the preDelete manifestWork, if there is no manifest need // to deploy, will return nil. -func (b *addonWorksBuilder) BuildHookWork(addonWorkNamespace string, +func (b *addonWorksBuilder) BuildHookWork(installMode, addonWorkNamespace string, addon *addonapiv1alpha1.ManagedClusterAddOn, objects []runtime.Object) (hookWork *workapiv1.ManifestWork, err error) { var hookManifests []workapiv1.Manifest var hookManifestConfigs []workapiv1.ManifestConfigOption - var owner *metav1.OwnerReference - installMode, _ := constants.GetHostedModeInfo(addon.GetAnnotations()) - // only set addon as the owner of works in default mode. should not set owner in hosted mode. - if installMode == constants.InstallModeDefault { - owner = metav1.NewControllerRef(addon, addonapiv1alpha1.GroupVersion.WithKind("ManagedClusterAddOn")) - } + owner := metav1.NewControllerRef(addon, addonapiv1alpha1.GroupVersion.WithKind("ManagedClusterAddOn")) for _, object := range objects { deployable, err := b.processor.deployable(b.hostedModeEnabled, installMode, object) @@ -367,7 +359,9 @@ func (b *addonWorksBuilder) BuildHookWork(addonWorkNamespace string, } hookWork = newManifestWork(addon.Namespace, addon.Name, addonWorkNamespace, hookManifests, b.processor.preDeleteHookManifestWorkName) - if owner != nil { + + // This owner is only added to the manifestWork deployed in managed cluster ns. + if addon.Namespace == addonWorkNamespace { hookWork.OwnerReferences = []metav1.OwnerReference{*owner} } hookWork.Spec.ManifestConfigs = hookManifestConfigs diff --git a/vendor/open-cluster-management.io/addon-framework/pkg/addonmanager/controllers/certificate/csrsign.go b/vendor/open-cluster-management.io/addon-framework/pkg/addonmanager/controllers/certificate/csrsign.go index 6c0a3d766..07543ea83 100644 --- a/vendor/open-cluster-management.io/addon-framework/pkg/addonmanager/controllers/certificate/csrsign.go +++ b/vendor/open-cluster-management.io/addon-framework/pkg/addonmanager/controllers/certificate/csrsign.go @@ -71,7 +71,7 @@ func NewCSRSignController( }, csrInformer.Informer()). WithSync(c.sync). - ToController("CSRApprovingController") + ToController("CSRSignController") } func (c *csrSignController) sync(ctx context.Context, syncCtx factory.SyncContext, csrName string) error { diff --git a/vendor/open-cluster-management.io/addon-framework/pkg/addonmanager/controllers/managementaddonconfig/controller.go b/vendor/open-cluster-management.io/addon-framework/pkg/addonmanager/controllers/cmaconfig/controller.go similarity index 89% rename from vendor/open-cluster-management.io/addon-framework/pkg/addonmanager/controllers/managementaddonconfig/controller.go rename to vendor/open-cluster-management.io/addon-framework/pkg/addonmanager/controllers/cmaconfig/controller.go index 300caff89..55b877688 100644 --- a/vendor/open-cluster-management.io/addon-framework/pkg/addonmanager/controllers/managementaddonconfig/controller.go +++ b/vendor/open-cluster-management.io/addon-framework/pkg/addonmanager/controllers/cmaconfig/controller.go @@ -1,4 +1,4 @@ -package managementaddonconfig +package cmaconfig import ( "context" @@ -30,8 +30,8 @@ const ( type enqueueFunc func(obj interface{}) -// clusterManagementAddonConfigController reconciles all interested addon config types (GroupVersionResource) on the hub. -type clusterManagementAddonConfigController struct { +// cmaConfigController reconciles all interested addon config types (GroupVersionResource) on the hub. +type cmaConfigController struct { addonClient addonv1alpha1client.Interface clusterManagementAddonLister addonlisterv1alpha1.ClusterManagementAddOnLister clusterManagementAddonIndexer cache.Indexer @@ -44,7 +44,7 @@ type clusterManagementAddonConfigController struct { addonapiv1alpha1.ClusterManagementAddOnStatus] } -func NewManagementAddonConfigController( +func NewCMAConfigController( addonClient addonv1alpha1client.Interface, clusterManagementAddonInformers addoninformerv1alpha1.ClusterManagementAddOnInformer, configInformerFactory dynamicinformer.DynamicSharedInformerFactory, @@ -53,7 +53,7 @@ func NewManagementAddonConfigController( ) factory.Controller { syncCtx := factory.NewSyncContext(controllerName) - c := &clusterManagementAddonConfigController{ + c := &cmaConfigController{ addonClient: addonClient, clusterManagementAddonLister: clusterManagementAddonInformers.Lister(), clusterManagementAddonIndexer: clusterManagementAddonInformers.Informer().GetIndexer(), @@ -78,7 +78,7 @@ func NewManagementAddonConfigController( WithSync(c.sync).ToController(controllerName) } -func (c *clusterManagementAddonConfigController) buildConfigInformers( +func (c *cmaConfigController) buildConfigInformers( configInformerFactory dynamicinformer.DynamicSharedInformerFactory, configGVRs map[schema.GroupVersionResource]bool, ) []factory.Informer { @@ -104,7 +104,7 @@ func (c *clusterManagementAddonConfigController) buildConfigInformers( return configInformers } -func (c *clusterManagementAddonConfigController) enqueueClusterManagementAddOnsByConfig(gvr schema.GroupVersionResource) enqueueFunc { +func (c *cmaConfigController) enqueueClusterManagementAddOnsByConfig(gvr schema.GroupVersionResource) enqueueFunc { return func(obj interface{}) { namespaceName, err := cache.DeletionHandlingMetaNamespaceKeyFunc(obj) if err != nil { @@ -129,7 +129,7 @@ func (c *clusterManagementAddonConfigController) enqueueClusterManagementAddOnsB } } -func (c *clusterManagementAddonConfigController) sync(ctx context.Context, syncCtx factory.SyncContext, key string) error { +func (c *cmaConfigController) sync(ctx context.Context, syncCtx factory.SyncContext, key string) error { _, addonName, err := cache.SplitMetaNamespaceKey(key) if err != nil { // ignore addon whose key is invalid @@ -158,7 +158,7 @@ func (c *clusterManagementAddonConfigController) sync(ctx context.Context, syncC return err } -func (c *clusterManagementAddonConfigController) updateConfigSpecHash(cma *addonapiv1alpha1.ClusterManagementAddOn) error { +func (c *cmaConfigController) updateConfigSpecHash(cma *addonapiv1alpha1.ClusterManagementAddOn) error { for i, defaultConfigReference := range cma.Status.DefaultConfigReferences { if !utils.ContainGR( @@ -203,7 +203,7 @@ func (c *clusterManagementAddonConfigController) updateConfigSpecHash(cma *addon return nil } -func (c *clusterManagementAddonConfigController) getConfigSpecHash(gr addonapiv1alpha1.ConfigGroupResource, +func (c *cmaConfigController) getConfigSpecHash(gr addonapiv1alpha1.ConfigGroupResource, cr addonapiv1alpha1.ConfigReferent) (string, error) { lister, ok := c.configListers[schema.GroupResource{Group: gr.Group, Resource: gr.Resource}] if !ok { diff --git a/vendor/open-cluster-management.io/addon-framework/pkg/addonmanager/controllers/managementaddon/controller.go b/vendor/open-cluster-management.io/addon-framework/pkg/addonmanager/controllers/cmamanagedby/controller.go similarity index 75% rename from vendor/open-cluster-management.io/addon-framework/pkg/addonmanager/controllers/managementaddon/controller.go rename to vendor/open-cluster-management.io/addon-framework/pkg/addonmanager/controllers/cmamanagedby/controller.go index 47ef7b862..a8c679094 100644 --- a/vendor/open-cluster-management.io/addon-framework/pkg/addonmanager/controllers/managementaddon/controller.go +++ b/vendor/open-cluster-management.io/addon-framework/pkg/addonmanager/controllers/cmamanagedby/controller.go @@ -1,4 +1,4 @@ -package managementaddon +package cmamanagedby import ( "context" @@ -17,11 +17,15 @@ import ( ) const ( - controllerName = "management-addon-controller" + controllerName = "cma-managed-by-controller" ) -// clusterManagementAddonController reconciles cma on the hub. -type clusterManagementAddonController struct { +// cmaManagedByController reconciles clustermanagementaddon on the hub +// to update the annotation "addon.open-cluster-management.io/lifecycle" value. +// It removes the value "self" if exist, which indicate the +// the installation and upgrade of addon will no longer be managed by addon itself. +// Once removed, the value will be set to "addon-manager" by the general addon manager. +type cmaManagedByController struct { addonClient addonv1alpha1client.Interface clusterManagementAddonLister addonlisterv1alpha1.ClusterManagementAddOnLister agentAddons map[string]agent.AgentAddon @@ -31,7 +35,7 @@ type clusterManagementAddonController struct { addonapiv1alpha1.ClusterManagementAddOnStatus] } -func NewManagementAddonController( +func NewCMAManagedByController( addonClient addonv1alpha1client.Interface, clusterManagementAddonInformers addoninformerv1alpha1.ClusterManagementAddOnInformer, agentAddons map[string]agent.AgentAddon, @@ -39,7 +43,7 @@ func NewManagementAddonController( ) factory.Controller { syncCtx := factory.NewSyncContext(controllerName) - c := &clusterManagementAddonController{ + c := &cmaManagedByController{ addonClient: addonClient, clusterManagementAddonLister: clusterManagementAddonInformers.Lister(), agentAddons: agentAddons, @@ -60,7 +64,7 @@ func NewManagementAddonController( WithSync(c.sync).ToController(controllerName) } -func (c *clusterManagementAddonController) sync(ctx context.Context, syncCtx factory.SyncContext, key string) error { +func (c *cmaManagedByController) sync(ctx context.Context, syncCtx factory.SyncContext, key string) error { _, addonName, err := cache.SplitMetaNamespaceKey(key) if err != nil { // ignore addon whose key is invalid @@ -76,19 +80,14 @@ func (c *clusterManagementAddonController) sync(ctx context.Context, syncCtx fac return err } - addon := c.agentAddons[cma.GetName()] - if addon.GetAgentAddonOptions().InstallStrategy == nil { - return nil - } - - // If the addon defines install strategy via WithInstallStrategy(), force add annotation "addon.open-cluster-management.io/lifecycle: self" to cma. - // The annotation with value "self" will be removed when remove WithInstallStrategy() in addon-framework. + // Remove the annotation value "self" since the WithInstallStrategy() is removed in addon-framework. // The migration plan refer to https://github.com/open-cluster-management-io/ocm/issues/355. cmaCopy := cma.DeepCopy() - if cmaCopy.Annotations == nil { - cmaCopy.Annotations = map[string]string{} + if cmaCopy.Annotations == nil || + cmaCopy.Annotations[addonapiv1alpha1.AddonLifecycleAnnotationKey] != addonapiv1alpha1.AddonLifecycleSelfManageAnnotationValue { + return nil } - cmaCopy.Annotations[addonapiv1alpha1.AddonLifecycleAnnotationKey] = addonapiv1alpha1.AddonLifecycleSelfManageAnnotationValue + cmaCopy.Annotations[addonapiv1alpha1.AddonLifecycleAnnotationKey] = "" _, err = c.addonPatcher.PatchLabelAnnotations(ctx, cmaCopy, cmaCopy.ObjectMeta, cma.ObjectMeta) return err diff --git a/vendor/open-cluster-management.io/addon-framework/pkg/addonmanager/controllers/registration/controller.go b/vendor/open-cluster-management.io/addon-framework/pkg/addonmanager/controllers/registration/controller.go index 650be3931..db9bef351 100644 --- a/vendor/open-cluster-management.io/addon-framework/pkg/addonmanager/controllers/registration/controller.go +++ b/vendor/open-cluster-management.io/addon-framework/pkg/addonmanager/controllers/registration/controller.go @@ -163,12 +163,15 @@ func (c *addonRegistrationController) sync(ctx context.Context, syncCtx factory. } if registrationOption.AgentInstallNamespace != nil { - ns := registrationOption.AgentInstallNamespace(managedClusterAddonCopy) + ns, err := registrationOption.AgentInstallNamespace(managedClusterAddonCopy) + if err != nil { + return err + } if len(ns) > 0 { managedClusterAddonCopy.Status.Namespace = ns } else { - klog.Infof("Namespace for addon %s/%s returned by agent install namespace func is empty", - managedClusterAddonCopy.Namespace, managedClusterAddonCopy.Name) + klog.InfoS("Namespace for addon returned by agent install namespace func is empty", + "addonNamespace", managedClusterAddonCopy.Namespace, "addonName", managedClusterAddonCopy.Name) } } diff --git a/vendor/open-cluster-management.io/addon-framework/pkg/addonmanager/manager.go b/vendor/open-cluster-management.io/addon-framework/pkg/addonmanager/manager.go index b2f3575e5..57953b722 100644 --- a/vendor/open-cluster-management.io/addon-framework/pkg/addonmanager/manager.go +++ b/vendor/open-cluster-management.io/addon-framework/pkg/addonmanager/manager.go @@ -22,17 +22,14 @@ import ( workv1informers "open-cluster-management.io/api/client/work/informers/externalversions" "open-cluster-management.io/addon-framework/pkg/addonmanager/controllers/addonconfig" - "open-cluster-management.io/addon-framework/pkg/addonmanager/controllers/addoninstall" "open-cluster-management.io/addon-framework/pkg/addonmanager/controllers/agentdeploy" "open-cluster-management.io/addon-framework/pkg/addonmanager/controllers/certificate" - "open-cluster-management.io/addon-framework/pkg/addonmanager/controllers/managementaddon" - "open-cluster-management.io/addon-framework/pkg/addonmanager/controllers/managementaddonconfig" + "open-cluster-management.io/addon-framework/pkg/addonmanager/controllers/cmaconfig" + "open-cluster-management.io/addon-framework/pkg/addonmanager/controllers/cmamanagedby" "open-cluster-management.io/addon-framework/pkg/addonmanager/controllers/registration" "open-cluster-management.io/addon-framework/pkg/agent" "open-cluster-management.io/addon-framework/pkg/basecontroller/factory" "open-cluster-management.io/addon-framework/pkg/index" - "open-cluster-management.io/addon-framework/pkg/manager/controllers/addonconfiguration" - "open-cluster-management.io/addon-framework/pkg/manager/controllers/addonowner" "open-cluster-management.io/addon-framework/pkg/utils" ) @@ -241,33 +238,17 @@ func (a *addonManager) StartWithInformers(ctx context.Context, a.addonAgents, ) - addonInstallController := addoninstall.NewAddonInstallController( - addonClient, - clusterInformers.Cluster().V1().ManagedClusters(), - addonInformers.Addon().V1alpha1().ManagedClusterAddOns(), - a.addonAgents, - ) - // This controller is used during migrating addons to be managed by addon-manager. // This should be removed when the migration is done. // The migration plan refer to https://github.com/open-cluster-management-io/ocm/issues/355. - managementAddonController := managementaddon.NewManagementAddonController( + managementAddonController := cmamanagedby.NewCMAManagedByController( addonClient, addonInformers.Addon().V1alpha1().ClusterManagementAddOns(), a.addonAgents, utils.FilterByAddonName(a.addonAgents), ) - // This is a duplicate controller in general addon-manager. This should be removed when we - // alway enable the addon-manager - addonOwnerController := addonowner.NewAddonOwnerController( - addonClient, - addonInformers.Addon().V1alpha1().ManagedClusterAddOns(), - addonInformers.Addon().V1alpha1().ClusterManagementAddOns(), - utils.ManagedBySelf(a.addonAgents), - ) - - var addonConfigController, managementAddonConfigController, addonConfigurationController factory.Controller + var addonConfigController, managementAddonConfigController factory.Controller if len(a.addonConfigs) != 0 { addonConfigController = addonconfig.NewAddonConfigController( addonClient, @@ -277,24 +258,13 @@ func (a *addonManager) StartWithInformers(ctx context.Context, a.addonConfigs, utils.FilterByAddonName(a.addonAgents), ) - managementAddonConfigController = managementaddonconfig.NewManagementAddonConfigController( + managementAddonConfigController = cmaconfig.NewCMAConfigController( addonClient, addonInformers.Addon().V1alpha1().ClusterManagementAddOns(), dynamicInformers, a.addonConfigs, utils.FilterByAddonName(a.addonAgents), ) - - // start addonConfiguration controller, note this is to handle the case when the general addon-manager - // is not started, we should consider to remove this when the general addon-manager are always started. - // This controller will also ignore the installStrategy part. - addonConfigurationController = addonconfiguration.NewAddonConfigurationController( - addonClient, - addonInformers.Addon().V1alpha1().ManagedClusterAddOns(), - addonInformers.Addon().V1alpha1().ClusterManagementAddOns(), - nil, nil, - utils.ManagedBySelf(a.addonAgents), - ) } var csrApproveController factory.Controller @@ -334,19 +304,14 @@ func (a *addonManager) StartWithInformers(ctx context.Context, go deployController.Run(ctx, 1) go registrationController.Run(ctx, 1) - go addonInstallController.Run(ctx, 1) go managementAddonController.Run(ctx, 1) - go addonOwnerController.Run(ctx, 1) if addonConfigController != nil { go addonConfigController.Run(ctx, 1) } if managementAddonConfigController != nil { go managementAddonConfigController.Run(ctx, 1) } - if addonConfigurationController != nil { - go addonConfigurationController.Run(ctx, 1) - } if csrApproveController != nil { go csrApproveController.Run(ctx, 1) } diff --git a/vendor/open-cluster-management.io/addon-framework/pkg/agent/inteface.go b/vendor/open-cluster-management.io/addon-framework/pkg/agent/inteface.go index 1dd5d7b00..721426ccf 100644 --- a/vendor/open-cluster-management.io/addon-framework/pkg/agent/inteface.go +++ b/vendor/open-cluster-management.io/addon-framework/pkg/agent/inteface.go @@ -4,11 +4,8 @@ import ( "fmt" certificatesv1 "k8s.io/api/certificates/v1" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/labels" "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/runtime/schema" - "k8s.io/klog/v2" addonapiv1alpha1 "open-cluster-management.io/api/addon/v1alpha1" clusterv1 "open-cluster-management.io/api/cluster/v1" workapiv1 "open-cluster-management.io/api/work/v1" @@ -49,14 +46,6 @@ type AgentAddonOptions struct { // +optional Registration *RegistrationOption - // InstallStrategy defines that addon should be created in which clusters. - // Addon will not be installed automatically until a ManagedClusterAddon is applied to the cluster's - // namespace if InstallStrategy is nil. - // Deprecated: use installStrategy config in ClusterManagementAddOn API instead - // The migration plan refer to https://github.com/open-cluster-management-io/ocm/issues/355. - // +optional - InstallStrategy *InstallStrategy - // Updaters select a set of resources and define the strategies to update them. // UpdateStrategy is Update if no Updater is defined for a resource. // +optional @@ -74,13 +63,16 @@ type AgentAddonOptions struct { // +optional HostedModeEnabled bool + // HostedModeInfoFunc returns whether an addon is in hosted mode, and its hosting cluster. + HostedModeInfoFunc func(addon *addonapiv1alpha1.ManagedClusterAddOn, cluster *clusterv1.ManagedCluster) (string, string) + // SupportedConfigGVRs is a list of addon supported configuration GroupVersionResource // each configuration GroupVersionResource should be unique SupportedConfigGVRs []schema.GroupVersionResource // AgentDeployTriggerClusterFilter defines the filter func to trigger the agent deploy/redploy when cluster info is // changed. Addons that need information from the ManagedCluster resource when deploying the agent should use this - // field to set what information they need, otherwise the expected/up-to-date agent may be deployed delayed since + // field to set what information they need, otherwise the expected/up-to-date agent may be deployed updates since // the default filter func returns false when the ManagedCluster resource is updated. // // For example, the agentAddon needs information from the ManagedCluster annotation, it can set the filter function @@ -128,7 +120,7 @@ type RegistrationOption struct { // Note: Set this very carefully. If this is set, the addon agent must be deployed in the same namespace, which // means when implementing Manifests function in AgentAddon interface, the namespace of the addon agent manifest // must be set to the same value returned by this function. - AgentInstallNamespace func(addon *addonapiv1alpha1.ManagedClusterAddOn) string + AgentInstallNamespace func(addon *addonapiv1alpha1.ManagedClusterAddOn) (string, error) // CSRApproveCheck checks whether the addon agent registration should be approved by the hub. // Addon hub controller can implement this func to auto-approve all the CSRs. A better CSR check is @@ -157,23 +149,6 @@ type RegistrationOption struct { CSRSign CSRSignerFunc } -// InstallStrategy is the installation strategy of the manifests prescribed by Manifests(..). -type InstallStrategy struct { - *installStrategy -} - -type installStrategy struct { - // InstallNamespace is target deploying namespace in the managed cluster upon automatic addon installation. - InstallNamespace string - - // managedClusterFilter will filter the clusters to install the addon to. - managedClusterFilter func(cluster *clusterv1.ManagedCluster) bool -} - -func (s *InstallStrategy) GetManagedClusterFilter() func(cluster *clusterv1.ManagedCluster) bool { - return s.managedClusterFilter -} - type Updater struct { // ResourceIdentifier sets what resources the strategy applies to ResourceIdentifier workapiv1.ResourceIdentifier @@ -258,54 +233,6 @@ func DefaultGroups(clusterName, addonName string) []string { } } -// InstallAllStrategy indicate to install addon to all clusters -func InstallAllStrategy(installNamespace string) *InstallStrategy { - return &InstallStrategy{ - &installStrategy{ - InstallNamespace: installNamespace, - managedClusterFilter: func(cluster *clusterv1.ManagedCluster) bool { - return true - }, - }, - } -} - -// InstallByLabelStrategy indicate to install addon based on clusters' label -func InstallByLabelStrategy(installNamespace string, selector metav1.LabelSelector) *InstallStrategy { - return &InstallStrategy{ - &installStrategy{ - InstallNamespace: installNamespace, - managedClusterFilter: func(cluster *clusterv1.ManagedCluster) bool { - selector, err := metav1.LabelSelectorAsSelector(&selector) - if err != nil { - klog.Warningf("labels selector is not correct: %v", err) - return false - } - - if !selector.Matches(labels.Set(cluster.Labels)) { - return false - } - return true - }, - }, - } -} - -// InstallByFilterFunctionStrategy indicate to install addon based on a filter function, and it will also install addons if the filter function is nil. -func InstallByFilterFunctionStrategy(installNamespace string, f func(cluster *clusterv1.ManagedCluster) bool) *InstallStrategy { - if f == nil { - f = func(cluster *clusterv1.ManagedCluster) bool { - return true - } - } - return &InstallStrategy{ - &installStrategy{ - InstallNamespace: installNamespace, - managedClusterFilter: f, - }, - } -} - // ApprovalAllCSRs returns true for all csrs. func ApprovalAllCSRs(cluster *clusterv1.ManagedCluster, addon *addonapiv1alpha1.ManagedClusterAddOn, csr *certificatesv1.CertificateSigningRequest) bool { return true diff --git a/vendor/open-cluster-management.io/addon-framework/pkg/manager/controllers/addonconfiguration/addon_configuration_reconciler.go b/vendor/open-cluster-management.io/addon-framework/pkg/manager/controllers/addonconfiguration/addon_configuration_reconciler.go deleted file mode 100644 index 5e38bfde4..000000000 --- a/vendor/open-cluster-management.io/addon-framework/pkg/manager/controllers/addonconfiguration/addon_configuration_reconciler.go +++ /dev/null @@ -1,114 +0,0 @@ -package addonconfiguration - -import ( - "context" - "encoding/json" - "fmt" - - jsonpatch "github.com/evanphx/json-patch" - "k8s.io/apimachinery/pkg/api/equality" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/types" - utilerrors "k8s.io/apimachinery/pkg/util/errors" - "k8s.io/klog/v2" - - addonv1alpha1 "open-cluster-management.io/api/addon/v1alpha1" - addonv1alpha1client "open-cluster-management.io/api/client/addon/clientset/versioned" -) - -type managedClusterAddonConfigurationReconciler struct { - addonClient addonv1alpha1client.Interface -} - -func (d *managedClusterAddonConfigurationReconciler) reconcile( - ctx context.Context, cma *addonv1alpha1.ClusterManagementAddOn, graph *configurationGraph) (*addonv1alpha1.ClusterManagementAddOn, reconcileState, error) { - var errs []error - - for _, addon := range graph.getAddonsToUpdate() { - mca := d.mergeAddonConfig(addon.mca, addon.desiredConfigs) - err := d.patchAddonStatus(ctx, mca, addon.mca) - if err != nil { - errs = append(errs, err) - } - } - - return cma, reconcileContinue, utilerrors.NewAggregate(errs) -} - -func (d *managedClusterAddonConfigurationReconciler) mergeAddonConfig( - mca *addonv1alpha1.ManagedClusterAddOn, desiredConfigMap addonConfigMap) *addonv1alpha1.ManagedClusterAddOn { - mcaCopy := mca.DeepCopy() - - var mergedConfigs []addonv1alpha1.ConfigReference - // remove configs that are not desired - for _, config := range mcaCopy.Status.ConfigReferences { - if _, ok := desiredConfigMap[config.ConfigGroupResource]; ok { - mergedConfigs = append(mergedConfigs, config) - } - } - - // append or update configs - for _, config := range desiredConfigMap { - var match bool - for i := range mergedConfigs { - if mergedConfigs[i].ConfigGroupResource != config.ConfigGroupResource { - continue - } - - match = true - // set LastObservedGeneration to 0 when config name/namespace changes - if mergedConfigs[i].DesiredConfig != nil && (mergedConfigs[i].DesiredConfig.ConfigReferent != config.DesiredConfig.ConfigReferent) { - mergedConfigs[i].LastObservedGeneration = 0 - } - mergedConfigs[i].ConfigReferent = config.ConfigReferent - mergedConfigs[i].DesiredConfig = config.DesiredConfig.DeepCopy() - } - - if !match { - mergedConfigs = append(mergedConfigs, config) - } - } - - mcaCopy.Status.ConfigReferences = mergedConfigs - return mcaCopy -} - -func (d *managedClusterAddonConfigurationReconciler) patchAddonStatus(ctx context.Context, new, old *addonv1alpha1.ManagedClusterAddOn) error { - if equality.Semantic.DeepEqual(new.Status, old.Status) { - return nil - } - - oldData, err := json.Marshal(&addonv1alpha1.ManagedClusterAddOn{ - Status: addonv1alpha1.ManagedClusterAddOnStatus{ - Namespace: old.Status.Namespace, - ConfigReferences: old.Status.ConfigReferences, - }, - }) - if err != nil { - return err - } - - newData, err := json.Marshal(&addonv1alpha1.ManagedClusterAddOn{ - ObjectMeta: metav1.ObjectMeta{ - UID: new.UID, - ResourceVersion: new.ResourceVersion, - }, - Status: addonv1alpha1.ManagedClusterAddOnStatus{ - Namespace: new.Status.Namespace, - ConfigReferences: new.Status.ConfigReferences, - }, - }) - if err != nil { - return err - } - - patchBytes, err := jsonpatch.CreateMergePatch(oldData, newData) - if err != nil { - return fmt.Errorf("failed to create patch for addon %s: %w", new.Name, err) - } - - klog.V(2).Infof("Patching addon %s/%s status with %s", new.Namespace, new.Name, string(patchBytes)) - _, err = d.addonClient.AddonV1alpha1().ManagedClusterAddOns(new.Namespace).Patch( - ctx, new.Name, types.MergePatchType, patchBytes, metav1.PatchOptions{}, "status") - return err -} diff --git a/vendor/open-cluster-management.io/addon-framework/pkg/manager/controllers/addonconfiguration/controller.go b/vendor/open-cluster-management.io/addon-framework/pkg/manager/controllers/addonconfiguration/controller.go deleted file mode 100644 index a51c304c9..000000000 --- a/vendor/open-cluster-management.io/addon-framework/pkg/manager/controllers/addonconfiguration/controller.go +++ /dev/null @@ -1,196 +0,0 @@ -package addonconfiguration - -import ( - "context" - - "k8s.io/apimachinery/pkg/api/errors" - "k8s.io/apimachinery/pkg/labels" - "k8s.io/apimachinery/pkg/runtime" - utilerrors "k8s.io/apimachinery/pkg/util/errors" - "k8s.io/client-go/tools/cache" - "k8s.io/klog/v2" - addonv1alpha1 "open-cluster-management.io/api/addon/v1alpha1" - addonv1alpha1client "open-cluster-management.io/api/client/addon/clientset/versioned" - addoninformerv1alpha1 "open-cluster-management.io/api/client/addon/informers/externalversions/addon/v1alpha1" - addonlisterv1alpha1 "open-cluster-management.io/api/client/addon/listers/addon/v1alpha1" - clusterinformersv1beta1 "open-cluster-management.io/api/client/cluster/informers/externalversions/cluster/v1beta1" - clusterlister "open-cluster-management.io/api/client/cluster/listers/cluster/v1beta1" - clusterlisterv1beta1 "open-cluster-management.io/api/client/cluster/listers/cluster/v1beta1" - clusterv1beta1 "open-cluster-management.io/api/cluster/v1beta1" - - "open-cluster-management.io/addon-framework/pkg/basecontroller/factory" - "open-cluster-management.io/addon-framework/pkg/index" -) - -// addonConfigurationController is a controller to update configuration of mca with the following order -// 1. use configuration in mca spec if it is set -// 2. use configuration in install strategy -// 3. use configuration in the default configuration in cma -type addonConfigurationController struct { - addonClient addonv1alpha1client.Interface - clusterManagementAddonLister addonlisterv1alpha1.ClusterManagementAddOnLister - managedClusterAddonIndexer cache.Indexer - addonFilterFunc factory.EventFilterFunc - placementLister clusterlisterv1beta1.PlacementLister - placementDecisionLister clusterlisterv1beta1.PlacementDecisionLister - placementDecisionGetter PlacementDecisionGetter - - reconcilers []addonConfigurationReconcile -} - -type addonConfigurationReconcile interface { - reconcile(ctx context.Context, cma *addonv1alpha1.ClusterManagementAddOn, - graph *configurationGraph) (*addonv1alpha1.ClusterManagementAddOn, reconcileState, error) -} - -type reconcileState int64 - -const ( - reconcileStop reconcileState = iota - reconcileContinue -) - -func NewAddonConfigurationController( - addonClient addonv1alpha1client.Interface, - addonInformers addoninformerv1alpha1.ManagedClusterAddOnInformer, - clusterManagementAddonInformers addoninformerv1alpha1.ClusterManagementAddOnInformer, - placementInformer clusterinformersv1beta1.PlacementInformer, - placementDecisionInformer clusterinformersv1beta1.PlacementDecisionInformer, - addonFilterFunc factory.EventFilterFunc, -) factory.Controller { - c := &addonConfigurationController{ - addonClient: addonClient, - clusterManagementAddonLister: clusterManagementAddonInformers.Lister(), - managedClusterAddonIndexer: addonInformers.Informer().GetIndexer(), - addonFilterFunc: addonFilterFunc, - } - - c.reconcilers = []addonConfigurationReconcile{ - &managedClusterAddonConfigurationReconciler{ - addonClient: addonClient, - }, - &clusterManagementAddonProgressingReconciler{ - addonClient: addonClient, - }, - } - - controllerFactory := factory.New().WithFilteredEventsInformersQueueKeysFunc( - func(obj runtime.Object) []string { - key, _ := cache.DeletionHandlingMetaNamespaceKeyFunc(obj) - return []string{key} - }, - c.addonFilterFunc, - clusterManagementAddonInformers.Informer()).WithInformersQueueKeysFunc( - func(obj runtime.Object) []string { - key, _ := cache.DeletionHandlingMetaNamespaceKeyFunc(obj) - return []string{key} - }, - addonInformers.Informer()) - - // This is to handle the case the self managed addon-manager does not have placementInformer/placementDecisionInformer. - // we will not consider installStrategy related placement for self managed addon-manager. - if placementInformer != nil && placementDecisionInformer != nil { - controllerFactory = controllerFactory.WithInformersQueueKeysFunc( - index.ClusterManagementAddonByPlacementDecisionQueueKey(clusterManagementAddonInformers), placementDecisionInformer.Informer()). - WithInformersQueueKeysFunc(index.ClusterManagementAddonByPlacementQueueKey(clusterManagementAddonInformers), placementInformer.Informer()) - c.placementLister = placementInformer.Lister() - c.placementDecisionLister = placementDecisionInformer.Lister() - c.placementDecisionGetter = PlacementDecisionGetter{Client: placementDecisionInformer.Lister()} - } - - return controllerFactory.WithSync(c.sync).ToController("addon-configuration-controller") -} - -func (c *addonConfigurationController) sync(ctx context.Context, syncCtx factory.SyncContext, key string) error { - _, addonName, err := cache.SplitMetaNamespaceKey(key) - if err != nil { - // ignore addon whose key is invalid - return nil - } - - klog.V(4).Infof("Reconciling addon %q", addonName) - - cma, err := c.clusterManagementAddonLister.Get(addonName) - switch { - case errors.IsNotFound(err): - return nil - case err != nil: - return err - } - - if !c.addonFilterFunc(cma) { - return nil - } - - cma = cma.DeepCopy() - graph, err := c.buildConfigurationGraph(cma) - if err != nil { - return err - } - - // generate the rollout result before calling reconcile() - // so that all the reconcilers are using the same rollout result - err = graph.generateRolloutResult() - if err != nil { - return err - } - - var state reconcileState - var errs []error - for _, reconciler := range c.reconcilers { - cma, state, err = reconciler.reconcile(ctx, cma, graph) - if err != nil { - errs = append(errs, err) - } - if state == reconcileStop { - break - } - } - - return utilerrors.NewAggregate(errs) -} - -func (c *addonConfigurationController) buildConfigurationGraph(cma *addonv1alpha1.ClusterManagementAddOn) (*configurationGraph, error) { - graph := newGraph(cma.Spec.SupportedConfigs, cma.Status.DefaultConfigReferences) - addons, err := c.managedClusterAddonIndexer.ByIndex(index.ManagedClusterAddonByName, cma.Name) - if err != nil { - return graph, err - } - - // add all existing addons to the default at first - for _, addonObject := range addons { - addon := addonObject.(*addonv1alpha1.ManagedClusterAddOn) - graph.addAddonNode(addon) - } - - if cma.Spec.InstallStrategy.Type == "" || cma.Spec.InstallStrategy.Type == addonv1alpha1.AddonInstallStrategyManual { - return graph, nil - } - - // check each install strategy in status - var errs []error - for _, installProgression := range cma.Status.InstallProgressions { - for _, installStrategy := range cma.Spec.InstallStrategy.Placements { - if installStrategy.PlacementRef != installProgression.PlacementRef { - continue - } - - // add placement node - err = graph.addPlacementNode(installStrategy, installProgression, c.placementLister, c.placementDecisionGetter) - if err != nil { - errs = append(errs, err) - continue - } - } - } - - return graph, utilerrors.NewAggregate(errs) -} - -type PlacementDecisionGetter struct { - Client clusterlister.PlacementDecisionLister -} - -func (pdl PlacementDecisionGetter) List(selector labels.Selector, namespace string) ([]*clusterv1beta1.PlacementDecision, error) { - return pdl.Client.PlacementDecisions(namespace).List(selector) -} diff --git a/vendor/open-cluster-management.io/addon-framework/pkg/manager/controllers/addonconfiguration/graph.go b/vendor/open-cluster-management.io/addon-framework/pkg/manager/controllers/addonconfiguration/graph.go deleted file mode 100644 index d0b381e25..000000000 --- a/vendor/open-cluster-management.io/addon-framework/pkg/manager/controllers/addonconfiguration/graph.go +++ /dev/null @@ -1,417 +0,0 @@ -package addonconfiguration - -import ( - "fmt" - "sort" - - "k8s.io/apimachinery/pkg/api/equality" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/util/sets" - - addonv1alpha1 "open-cluster-management.io/api/addon/v1alpha1" - clusterlisterv1beta1 "open-cluster-management.io/api/client/cluster/listers/cluster/v1beta1" - clusterv1alpha1 "open-cluster-management.io/api/cluster/v1alpha1" - clusterv1sdkalpha1 "open-cluster-management.io/sdk-go/pkg/apis/cluster/v1alpha1" - clustersdkv1beta1 "open-cluster-management.io/sdk-go/pkg/apis/cluster/v1beta1" -) - -// configurationTree is a 2 level snapshot tree on the configuration of addons -// the first level is a list of nodes that represents a install strategy and a desired configuration for this install -// strategy. The second level is a list of nodes that represent each mca and its desired configuration -type configurationGraph struct { - // nodes maintains a list between a installStrategy and its related mcas - nodes []*installStrategyNode - // defaults is the nodes with no install strategy - defaults *installStrategyNode -} - -// installStrategyNode is a node in configurationGraph defined by a install strategy -type installStrategyNode struct { - placementRef addonv1alpha1.PlacementRef - pdTracker *clustersdkv1beta1.PlacementDecisionClustersTracker - rolloutStrategy clusterv1alpha1.RolloutStrategy - rolloutResult clusterv1sdkalpha1.RolloutResult - desiredConfigs addonConfigMap - // children keeps a map of addons node as the children of this node - children map[string]*addonNode - clusters sets.Set[string] -} - -// addonNode is node as a child of installStrategy node represting a mca -// addonnode -type addonNode struct { - desiredConfigs addonConfigMap - mca *addonv1alpha1.ManagedClusterAddOn - status *clusterv1sdkalpha1.ClusterRolloutStatus -} - -type addonConfigMap map[addonv1alpha1.ConfigGroupResource]addonv1alpha1.ConfigReference - -// set addon rollout status -func (n *addonNode) setRolloutStatus() { - n.status = &clusterv1sdkalpha1.ClusterRolloutStatus{ClusterName: n.mca.Namespace} - - // desired configs doesn't match actual configs, set to ToApply - if len(n.mca.Status.ConfigReferences) != len(n.desiredConfigs) { - n.status.Status = clusterv1sdkalpha1.ToApply - return - } - - var progressingCond metav1.Condition - for _, cond := range n.mca.Status.Conditions { - if cond.Type == addonv1alpha1.ManagedClusterAddOnConditionProgressing { - progressingCond = cond - break - } - } - - for _, actual := range n.mca.Status.ConfigReferences { - if desired, ok := n.desiredConfigs[actual.ConfigGroupResource]; ok { - // desired config spec hash doesn't match actual, set to ToApply - if !equality.Semantic.DeepEqual(desired.DesiredConfig, actual.DesiredConfig) { - n.status.Status = clusterv1sdkalpha1.ToApply - return - // desired config spec hash matches actual, but last applied config spec hash doesn't match actual - } else if !equality.Semantic.DeepEqual(actual.LastAppliedConfig, actual.DesiredConfig) { - switch progressingCond.Reason { - case addonv1alpha1.ProgressingReasonInstallFailed, addonv1alpha1.ProgressingReasonUpgradeFailed: - n.status.Status = clusterv1sdkalpha1.Failed - n.status.LastTransitionTime = &progressingCond.LastTransitionTime - case addonv1alpha1.ProgressingReasonInstalling, addonv1alpha1.ProgressingReasonUpgrading: - n.status.Status = clusterv1sdkalpha1.Progressing - n.status.LastTransitionTime = &progressingCond.LastTransitionTime - default: - n.status.Status = clusterv1sdkalpha1.Progressing - } - return - } - } else { - n.status.Status = clusterv1sdkalpha1.ToApply - return - } - } - - // succeed - n.status.Status = clusterv1sdkalpha1.Succeeded - if progressingCond.Reason == addonv1alpha1.ProgressingReasonInstallSucceed || progressingCond.Reason == addonv1alpha1.ProgressingReasonUpgradeSucceed { - n.status.LastTransitionTime = &progressingCond.LastTransitionTime - } -} - -func (d addonConfigMap) copy() addonConfigMap { - output := addonConfigMap{} - for k, v := range d { - output[k] = v - } - return output -} - -func newGraph(supportedConfigs []addonv1alpha1.ConfigMeta, defaultConfigReferences []addonv1alpha1.DefaultConfigReference) *configurationGraph { - graph := &configurationGraph{ - nodes: []*installStrategyNode{}, - defaults: &installStrategyNode{ - desiredConfigs: map[addonv1alpha1.ConfigGroupResource]addonv1alpha1.ConfigReference{}, - children: map[string]*addonNode{}, - }, - } - - // init graph.defaults.desiredConfigs with supportedConfigs - for _, config := range supportedConfigs { - if config.DefaultConfig != nil { - graph.defaults.desiredConfigs[config.ConfigGroupResource] = addonv1alpha1.ConfigReference{ - ConfigGroupResource: config.ConfigGroupResource, - ConfigReferent: *config.DefaultConfig, - DesiredConfig: &addonv1alpha1.ConfigSpecHash{ - ConfigReferent: *config.DefaultConfig, - }, - } - } - } - // copy the spechash from cma status defaultConfigReferences - for _, configRef := range defaultConfigReferences { - if configRef.DesiredConfig == nil { - continue - } - defaultsDesiredConfig, ok := graph.defaults.desiredConfigs[configRef.ConfigGroupResource] - if ok && (defaultsDesiredConfig.DesiredConfig.ConfigReferent == configRef.DesiredConfig.ConfigReferent) { - defaultsDesiredConfig.DesiredConfig.SpecHash = configRef.DesiredConfig.SpecHash - } - } - - return graph -} - -// addAddonNode to the graph, starting from placement with the highest order -func (g *configurationGraph) addAddonNode(mca *addonv1alpha1.ManagedClusterAddOn) { - for i := len(g.nodes) - 1; i >= 0; i-- { - if g.nodes[i].clusters.Has(mca.Namespace) { - g.nodes[i].addNode(mca) - return - } - } - - g.defaults.addNode(mca) -} - -// addNode delete clusters on existing graph so the new configuration overrides the previous -func (g *configurationGraph) addPlacementNode( - installStrategy addonv1alpha1.PlacementStrategy, - installProgression addonv1alpha1.InstallProgression, - placementLister clusterlisterv1beta1.PlacementLister, - placementDecisionGetter PlacementDecisionGetter, -) error { - placementRef := installProgression.PlacementRef - installConfigReference := installProgression.ConfigReferences - - // get placement - if placementLister == nil { - return fmt.Errorf("invalid placement lister %v", placementLister) - } - placement, err := placementLister.Placements(placementRef.Namespace).Get(placementRef.Name) - if err != nil { - return err - } - - // new decision tracker - pdTracker := clustersdkv1beta1.NewPlacementDecisionClustersTracker(placement, placementDecisionGetter, nil) - - // refresh and get existing decision clusters - err = pdTracker.Refresh() - if err != nil { - return err - } - clusters := pdTracker.ExistingClusterGroupsBesides().GetClusters() - - node := &installStrategyNode{ - placementRef: placementRef, - pdTracker: pdTracker, - rolloutStrategy: installStrategy.RolloutStrategy, - desiredConfigs: g.defaults.desiredConfigs, - children: map[string]*addonNode{}, - clusters: clusters, - } - - // Set MaxConcurrency - // If progressive strategy is not initialized or MaxConcurrency is not specified, set MaxConcurrency to the default value - if node.rolloutStrategy.Type == clusterv1alpha1.Progressive { - progressiveStrategy := node.rolloutStrategy.Progressive - - if progressiveStrategy == nil { - progressiveStrategy = &clusterv1alpha1.RolloutProgressive{} - } - if progressiveStrategy.MaxConcurrency.StrVal == "" && progressiveStrategy.MaxConcurrency.IntVal == 0 { - progressiveStrategy.MaxConcurrency = placement.Spec.DecisionStrategy.GroupStrategy.ClustersPerDecisionGroup - } - - node.rolloutStrategy.Progressive = progressiveStrategy - } - - // overrides configuration by install strategy - if len(installConfigReference) > 0 { - node.desiredConfigs = node.desiredConfigs.copy() - for _, configRef := range installConfigReference { - if configRef.DesiredConfig == nil { - continue - } - node.desiredConfigs[configRef.ConfigGroupResource] = addonv1alpha1.ConfigReference{ - ConfigGroupResource: configRef.ConfigGroupResource, - ConfigReferent: configRef.DesiredConfig.ConfigReferent, - DesiredConfig: configRef.DesiredConfig.DeepCopy(), - } - } - } - - // remove addon in defaults and other placements. - for _, cluster := range node.clusters.UnsortedList() { - if _, ok := g.defaults.children[cluster]; ok { - node.addNode(g.defaults.children[cluster].mca) - delete(g.defaults.children, cluster) - } - for _, placementNode := range g.nodes { - if _, ok := placementNode.children[cluster]; ok { - node.addNode(placementNode.children[cluster].mca) - delete(placementNode.children, cluster) - } - } - } - g.nodes = append(g.nodes, node) - return nil -} - -func (g *configurationGraph) generateRolloutResult() error { - for _, node := range g.nodes { - if err := node.generateRolloutResult(); err != nil { - return err - } - } - if err := g.defaults.generateRolloutResult(); err != nil { - return err - } - return nil -} - -func (g *configurationGraph) getPlacementNodes() map[addonv1alpha1.PlacementRef]*installStrategyNode { - placementNodeMap := map[addonv1alpha1.PlacementRef]*installStrategyNode{} - for _, node := range g.nodes { - placementNodeMap[node.placementRef] = node - } - - return placementNodeMap -} - -func (g *configurationGraph) getAddonsToUpdate() []*addonNode { - var addons []*addonNode - for _, node := range g.nodes { - addons = append(addons, node.getAddonsToUpdate()...) - } - - addons = append(addons, g.defaults.getAddonsToUpdate()...) - - return addons -} - -func (n *installStrategyNode) addNode(addon *addonv1alpha1.ManagedClusterAddOn) { - n.children[addon.Namespace] = &addonNode{ - mca: addon, - desiredConfigs: n.desiredConfigs, - } - - // override configuration by mca spec - if len(addon.Spec.Configs) > 0 { - n.children[addon.Namespace].desiredConfigs = n.children[addon.Namespace].desiredConfigs.copy() - // TODO we should also filter out the configs which are not supported configs. - for _, config := range addon.Spec.Configs { - n.children[addon.Namespace].desiredConfigs[config.ConfigGroupResource] = addonv1alpha1.ConfigReference{ - ConfigGroupResource: config.ConfigGroupResource, - ConfigReferent: config.ConfigReferent, - DesiredConfig: &addonv1alpha1.ConfigSpecHash{ - ConfigReferent: config.ConfigReferent, - }, - } - // copy the spechash from mca status - for _, configRef := range addon.Status.ConfigReferences { - if configRef.DesiredConfig == nil { - continue - } - nodeDesiredConfig, ok := n.children[addon.Namespace].desiredConfigs[configRef.ConfigGroupResource] - if ok && (nodeDesiredConfig.DesiredConfig.ConfigReferent == configRef.DesiredConfig.ConfigReferent) { - nodeDesiredConfig.DesiredConfig.SpecHash = configRef.DesiredConfig.SpecHash - } - } - } - } - - // set addon node rollout status - n.children[addon.Namespace].setRolloutStatus() -} - -func (n *installStrategyNode) generateRolloutResult() error { - if n.placementRef.Name == "" { - // default addons - rolloutResult := clusterv1sdkalpha1.RolloutResult{} - rolloutResult.ClustersToRollout = []clusterv1sdkalpha1.ClusterRolloutStatus{} - for name, addon := range n.children { - if addon.status == nil { - return fmt.Errorf("failed to get rollout status on cluster %v", name) - } - if addon.status.Status != clusterv1sdkalpha1.Succeeded { - rolloutResult.ClustersToRollout = append(rolloutResult.ClustersToRollout, *addon.status) - } - } - n.rolloutResult = rolloutResult - } else { - // placement addons - rolloutHandler, err := clusterv1sdkalpha1.NewRolloutHandler(n.pdTracker, getClusterRolloutStatus) - if err != nil { - return err - } - - // get existing addons - existingRolloutClusters := []clusterv1sdkalpha1.ClusterRolloutStatus{} - for name, addon := range n.children { - clsRolloutStatus, err := getClusterRolloutStatus(name, addon) - if err != nil { - return err - } - existingRolloutClusters = append(existingRolloutClusters, clsRolloutStatus) - } - - // sort by cluster name - sort.SliceStable(existingRolloutClusters, func(i, j int) bool { - return existingRolloutClusters[i].ClusterName < existingRolloutClusters[j].ClusterName - }) - - _, rolloutResult, err := rolloutHandler.GetRolloutCluster(n.rolloutStrategy, existingRolloutClusters) - if err != nil { - return err - } - n.rolloutResult = rolloutResult - } - - return nil -} - -// addonToUpdate finds the addons to be updated by placement -func (n *installStrategyNode) getAddonsToUpdate() []*addonNode { - var addons []*addonNode - var clusters []string - - // get addon to update from rollout result - for _, c := range n.rolloutResult.ClustersToRollout { - if _, exist := n.children[c.ClusterName]; exist { - clusters = append(clusters, c.ClusterName) - } - } - - // sort addons by name - sort.Strings(clusters) - for _, k := range clusters { - addons = append(addons, n.children[k]) - } - return addons -} - -func (n *installStrategyNode) countAddonUpgradeSucceed() int { - count := 0 - for _, addon := range n.children { - if desiredConfigsEqual(addon.desiredConfigs, n.desiredConfigs) && addon.status.Status == clusterv1sdkalpha1.Succeeded { - count += 1 - } - } - return count -} - -func (n *installStrategyNode) countAddonUpgrading() int { - count := 0 - for _, addon := range n.children { - if desiredConfigsEqual(addon.desiredConfigs, n.desiredConfigs) && addon.status.Status == clusterv1sdkalpha1.Progressing { - count += 1 - } - } - return count -} - -func (n *installStrategyNode) countAddonTimeOut() int { - return len(n.rolloutResult.ClustersTimeOut) -} - -func getClusterRolloutStatus(clusterName string, addonNode *addonNode) (clusterv1sdkalpha1.ClusterRolloutStatus, error) { - if addonNode.status == nil { - return clusterv1sdkalpha1.ClusterRolloutStatus{}, fmt.Errorf("failed to get rollout status on cluster %v", clusterName) - } - return *addonNode.status, nil -} - -func desiredConfigsEqual(a, b addonConfigMap) bool { - if len(a) != len(b) { - return false - } - - for configgrA := range a { - if a[configgrA] != b[configgrA] { - return false - } - } - - return true -} diff --git a/vendor/open-cluster-management.io/addon-framework/pkg/manager/controllers/addonconfiguration/mgmt_addon_progressing_reconciler.go b/vendor/open-cluster-management.io/addon-framework/pkg/manager/controllers/addonconfiguration/mgmt_addon_progressing_reconciler.go deleted file mode 100644 index 36d712383..000000000 --- a/vendor/open-cluster-management.io/addon-framework/pkg/manager/controllers/addonconfiguration/mgmt_addon_progressing_reconciler.go +++ /dev/null @@ -1,143 +0,0 @@ -package addonconfiguration - -import ( - "context" - "encoding/json" - "fmt" - - jsonpatch "github.com/evanphx/json-patch" - "k8s.io/apimachinery/pkg/api/equality" - "k8s.io/apimachinery/pkg/api/meta" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/types" - utilerrors "k8s.io/apimachinery/pkg/util/errors" - "k8s.io/klog/v2" - - addonv1alpha1 "open-cluster-management.io/api/addon/v1alpha1" - addonv1alpha1client "open-cluster-management.io/api/client/addon/clientset/versioned" -) - -type clusterManagementAddonProgressingReconciler struct { - addonClient addonv1alpha1client.Interface -} - -func (d *clusterManagementAddonProgressingReconciler) reconcile( - ctx context.Context, cma *addonv1alpha1.ClusterManagementAddOn, graph *configurationGraph) (*addonv1alpha1.ClusterManagementAddOn, reconcileState, error) { - var errs []error - cmaCopy := cma.DeepCopy() - placementNodes := graph.getPlacementNodes() - - // go through addons and update condition per install progression - for i, installProgression := range cmaCopy.Status.InstallProgressions { - placementNode, exist := placementNodes[installProgression.PlacementRef] - if !exist { - continue - } - - isUpgrade := false - - for _, configReference := range installProgression.ConfigReferences { - if configReference.LastAppliedConfig != nil { - isUpgrade = true - break - } - } - - setAddOnInstallProgressionsAndLastApplied(&cmaCopy.Status.InstallProgressions[i], - isUpgrade, - placementNode.countAddonUpgrading(), - placementNode.countAddonUpgradeSucceed(), - placementNode.countAddonTimeOut(), - len(placementNode.clusters), - ) - } - - err := d.patchMgmtAddonStatus(ctx, cmaCopy, cma) - if err != nil { - errs = append(errs, err) - } - return cmaCopy, reconcileContinue, utilerrors.NewAggregate(errs) -} - -func (d *clusterManagementAddonProgressingReconciler) patchMgmtAddonStatus(ctx context.Context, new, old *addonv1alpha1.ClusterManagementAddOn) error { - if equality.Semantic.DeepEqual(new.Status, old.Status) { - return nil - } - - oldData, err := json.Marshal(&addonv1alpha1.ClusterManagementAddOn{ - Status: addonv1alpha1.ClusterManagementAddOnStatus{ - InstallProgressions: old.Status.InstallProgressions, - }, - }) - if err != nil { - return err - } - - newData, err := json.Marshal(&addonv1alpha1.ClusterManagementAddOn{ - ObjectMeta: metav1.ObjectMeta{ - UID: new.UID, - ResourceVersion: new.ResourceVersion, - }, - Status: addonv1alpha1.ClusterManagementAddOnStatus{ - InstallProgressions: new.Status.InstallProgressions, - }, - }) - if err != nil { - return err - } - - patchBytes, err := jsonpatch.CreateMergePatch(oldData, newData) - if err != nil { - return fmt.Errorf("failed to create patch for addon %s: %w", new.Name, err) - } - - klog.V(2).Infof("Patching clustermanagementaddon %s status with %s", new.Name, string(patchBytes)) - _, err = d.addonClient.AddonV1alpha1().ClusterManagementAddOns().Patch( - ctx, new.Name, types.MergePatchType, patchBytes, metav1.PatchOptions{}, "status") - return err -} - -func setAddOnInstallProgressionsAndLastApplied( - installProgression *addonv1alpha1.InstallProgression, - isUpgrade bool, - progressing, done, timeout, total int) { - // always update progressing condition when there is no config - // skip update progressing condition when last applied config already the same as desired - skip := len(installProgression.ConfigReferences) > 0 - for _, configReference := range installProgression.ConfigReferences { - if !equality.Semantic.DeepEqual(configReference.LastAppliedConfig, configReference.DesiredConfig) && - !equality.Semantic.DeepEqual(configReference.LastKnownGoodConfig, configReference.DesiredConfig) { - skip = false - } - } - if skip { - return - } - condition := metav1.Condition{ - Type: addonv1alpha1.ManagedClusterAddOnConditionProgressing, - } - if (total == 0 && done == 0) || (done != total) { - condition.Status = metav1.ConditionTrue - if isUpgrade { - condition.Reason = addonv1alpha1.ProgressingReasonUpgrading - condition.Message = fmt.Sprintf("%d/%d upgrading..., %d timeout.", progressing+done, total, timeout) - } else { - condition.Reason = addonv1alpha1.ProgressingReasonInstalling - condition.Message = fmt.Sprintf("%d/%d installing..., %d timeout.", progressing+done, total, timeout) - } - } else { - for i, configRef := range installProgression.ConfigReferences { - installProgression.ConfigReferences[i].LastAppliedConfig = configRef.DesiredConfig.DeepCopy() - installProgression.ConfigReferences[i].LastKnownGoodConfig = configRef.DesiredConfig.DeepCopy() - } - condition.Status = metav1.ConditionFalse - if isUpgrade { - condition.Reason = addonv1alpha1.ProgressingReasonUpgradeSucceed - condition.Message = fmt.Sprintf("%d/%d upgrade completed with no errors, %d timeout.", done, total, timeout) - } else { - condition.Reason = addonv1alpha1.ProgressingReasonInstallSucceed - condition.Message = fmt.Sprintf("%d/%d install completed with no errors, %d timeout.", done, total, timeout) - } - } - meta.SetStatusCondition(&installProgression.Conditions, condition) -} diff --git a/vendor/open-cluster-management.io/addon-framework/pkg/manager/controllers/addonowner/controller.go b/vendor/open-cluster-management.io/addon-framework/pkg/manager/controllers/addonowner/controller.go deleted file mode 100644 index beff5b4bd..000000000 --- a/vendor/open-cluster-management.io/addon-framework/pkg/manager/controllers/addonowner/controller.go +++ /dev/null @@ -1,100 +0,0 @@ -package addonowner - -import ( - "context" - - "k8s.io/apimachinery/pkg/api/errors" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/runtime" - "k8s.io/client-go/tools/cache" - "k8s.io/klog/v2" - - addonapiv1alpha1 "open-cluster-management.io/api/addon/v1alpha1" - addonv1alpha1client "open-cluster-management.io/api/client/addon/clientset/versioned" - addoninformerv1alpha1 "open-cluster-management.io/api/client/addon/informers/externalversions/addon/v1alpha1" - addonlisterv1alpha1 "open-cluster-management.io/api/client/addon/listers/addon/v1alpha1" - - "open-cluster-management.io/addon-framework/pkg/basecontroller/factory" - "open-cluster-management.io/addon-framework/pkg/utils" -) - -const UnsupportedConfigurationType = "UnsupportedConfiguration" - -// addonOwnerController reconciles instances of managedclusteradd on the hub -// to add related ClusterManagementAddon as the owner. -type addonOwnerController struct { - addonClient addonv1alpha1client.Interface - managedClusterAddonLister addonlisterv1alpha1.ManagedClusterAddOnLister - clusterManagementAddonLister addonlisterv1alpha1.ClusterManagementAddOnLister - addonFilterFunc factory.EventFilterFunc -} - -func NewAddonOwnerController( - addonClient addonv1alpha1client.Interface, - addonInformers addoninformerv1alpha1.ManagedClusterAddOnInformer, - clusterManagementAddonInformers addoninformerv1alpha1.ClusterManagementAddOnInformer, - addonFilterFunc factory.EventFilterFunc, -) factory.Controller { - c := &addonOwnerController{ - addonClient: addonClient, - managedClusterAddonLister: addonInformers.Lister(), - clusterManagementAddonLister: clusterManagementAddonInformers.Lister(), - addonFilterFunc: addonFilterFunc, - } - - return factory.New().WithFilteredEventsInformersQueueKeysFunc( - func(obj runtime.Object) []string { - key, _ := cache.DeletionHandlingMetaNamespaceKeyFunc(obj) - return []string{key} - }, - c.addonFilterFunc, clusterManagementAddonInformers.Informer()). - WithInformersQueueKeysFunc( - func(obj runtime.Object) []string { - key, _ := cache.DeletionHandlingMetaNamespaceKeyFunc(obj) - return []string{key} - }, - addonInformers.Informer()).WithSync(c.sync).ToController("addon-owner-controller") -} - -func (c *addonOwnerController) sync(ctx context.Context, syncCtx factory.SyncContext, key string) error { - klog.V(4).Infof("Reconciling addon %q", key) - - namespace, addonName, err := cache.SplitMetaNamespaceKey(key) - if err != nil { - // ignore addon whose key is invalid - return nil - } - - addon, err := c.managedClusterAddonLister.ManagedClusterAddOns(namespace).Get(addonName) - switch { - case errors.IsNotFound(err): - return nil - case err != nil: - return err - } - - addonCopy := addon.DeepCopy() - modified := false - - clusterManagementAddon, err := c.clusterManagementAddonLister.Get(addonName) - if errors.IsNotFound(err) { - return nil - } - - if err != nil { - return err - } - - if !c.addonFilterFunc(clusterManagementAddon) { - return nil - } - - owner := metav1.NewControllerRef(clusterManagementAddon, addonapiv1alpha1.GroupVersion.WithKind("ClusterManagementAddOn")) - modified = utils.MergeOwnerRefs(&addonCopy.OwnerReferences, *owner, false) - if modified { - _, err = c.addonClient.AddonV1alpha1().ManagedClusterAddOns(namespace).Update(ctx, addonCopy, metav1.UpdateOptions{}) - return err - } - - return nil -} diff --git a/vendor/open-cluster-management.io/addon-framework/pkg/utils/addon_config.go b/vendor/open-cluster-management.io/addon-framework/pkg/utils/addon_config.go index ecdb98ad0..eaa91a9f0 100644 --- a/vendor/open-cluster-management.io/addon-framework/pkg/utils/addon_config.go +++ b/vendor/open-cluster-management.io/addon-framework/pkg/utils/addon_config.go @@ -7,7 +7,6 @@ import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" "k8s.io/apimachinery/pkg/runtime" - utilruntime "k8s.io/apimachinery/pkg/util/runtime" "k8s.io/klog/v2" addonapiv1alpha1 "open-cluster-management.io/api/addon/v1alpha1" addonv1alpha1client "open-cluster-management.io/api/client/addon/clientset/versioned" @@ -37,23 +36,29 @@ func (g *defaultAddOnDeploymentConfigGetter) Get( // matched addon deployment config, it will return an empty string. func AgentInstallNamespaceFromDeploymentConfigFunc( adcgetter AddOnDeploymentConfigGetter, -) func(*addonapiv1alpha1.ManagedClusterAddOn) string { - return func(addon *addonapiv1alpha1.ManagedClusterAddOn) string { +) func(*addonapiv1alpha1.ManagedClusterAddOn) (string, error) { + return func(addon *addonapiv1alpha1.ManagedClusterAddOn) (string, error) { if addon == nil { - utilruntime.HandleError(fmt.Errorf("failed to get addon install namespace, addon is nil")) - return "" + return "", fmt.Errorf("failed to get addon install namespace, addon is nil") } config, err := GetDesiredAddOnDeploymentConfig(addon, adcgetter) if err != nil { - utilruntime.HandleError(fmt.Errorf("failed to get deployment config for addon %s: %v", addon.Name, err)) - return "" + return "", fmt.Errorf("failed to get deployment config for addon %s: %v", addon.Name, err) } + + // For now, we have no way of knowing if the addon depleoyment config is not configured, or + // is configured but not yet been added to the managedclusteraddon status config references, + // we expect no error will be returned when the addon deployment config is not configured + // so we can use the default namespace. + // TODO: Find a way to distinguish between the above two cases if config == nil { - return "" + klog.InfoS("Addon deployment config is nil, return an empty string for agent install namespace", + "addonNamespace", addon.Namespace, "addonName", addon.Name) + return "", nil } - return config.Spec.AgentInstallNamespace + return config.Spec.AgentInstallNamespace, nil } } diff --git a/vendor/open-cluster-management.io/sdk-go/pkg/apis/work/v1/applier/workapplier.go b/vendor/open-cluster-management.io/sdk-go/pkg/apis/work/v1/applier/workapplier.go index 10332be84..e3c749567 100644 --- a/vendor/open-cluster-management.io/sdk-go/pkg/apis/work/v1/applier/workapplier.go +++ b/vendor/open-cluster-management.io/sdk-go/pkg/apis/work/v1/applier/workapplier.go @@ -128,7 +128,7 @@ func (w *WorkApplier) Delete(ctx context.Context, namespace, name string) error } func shouldUpdateMap(required, existing map[string]string) bool { - if len(required) > len(existing) { + if len(required) != len(existing) { return true } for key, value := range required {