forked from open-cluster-management-io/addon-framework
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathaddonfactory.go
More file actions
258 lines (217 loc) · 9.04 KB
/
addonfactory.go
File metadata and controls
258 lines (217 loc) · 9.04 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
package addonfactory
import (
"embed"
"fmt"
apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
apiextensionsv1beta1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1beta1"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/client-go/kubernetes/scheme"
"k8s.io/klog/v2"
addonapiv1alpha1 "open-cluster-management.io/api/addon/v1alpha1"
clusterv1 "open-cluster-management.io/api/cluster/v1"
"open-cluster-management.io/addon-framework/pkg/agent"
)
const AddonDefaultInstallNamespace = "open-cluster-management-agent-addon"
// AnnotationValuesName is the annotation Name of customized values
const AnnotationValuesName string = "addon.open-cluster-management.io/values"
type Values map[string]interface{}
type GetValuesFunc func(cluster *clusterv1.ManagedCluster,
addon *addonapiv1alpha1.ManagedClusterAddOn) (Values, error)
// AgentAddonFactory includes the common fields for building different agentAddon instances.
type AgentAddonFactory struct {
scheme *runtime.Scheme
fs embed.FS
dir string
getValuesFuncs []GetValuesFunc
agentAddonOptions agent.AgentAddonOptions
// trimCRDDescription flag is used to trim the description of CRDs in manifestWork. disabled by default.
trimCRDDescription bool
hostingCluster *clusterv1.ManagedCluster
agentInstallNamespace func(addon *addonapiv1alpha1.ManagedClusterAddOn) string
createAgentInstallNamespace bool
helmEngineStrict bool
}
// NewAgentAddonFactory builds an addonAgentFactory instance with addon name and fs.
// dir is the path prefix based on the fs path.
func NewAgentAddonFactory(addonName string, fs embed.FS, dir string) *AgentAddonFactory {
s := runtime.NewScheme()
_ = scheme.AddToScheme(s)
_ = apiextensionsv1.AddToScheme(s)
_ = apiextensionsv1beta1.AddToScheme(s)
return &AgentAddonFactory{
fs: fs,
dir: dir,
agentAddonOptions: agent.AgentAddonOptions{
AddonName: addonName,
Registration: nil,
InstallStrategy: nil,
HealthProber: nil,
SupportedConfigGVRs: []schema.GroupVersionResource{},
},
trimCRDDescription: false,
scheme: s,
createAgentInstallNamespace: false,
helmEngineStrict: false,
}
}
// WithScheme is an optional configuration, only used when the agentAddon has customized resource types.
func (f *AgentAddonFactory) WithScheme(s *runtime.Scheme) *AgentAddonFactory {
f.scheme = s
_ = scheme.AddToScheme(f.scheme)
_ = apiextensionsv1.AddToScheme(f.scheme)
_ = apiextensionsv1beta1.AddToScheme(f.scheme)
return f
}
// WithGetValuesFuncs adds a list of the getValues func.
// the values got from the big index Func will override the one from small index Func.
func (f *AgentAddonFactory) WithGetValuesFuncs(getValuesFuncs ...GetValuesFunc) *AgentAddonFactory {
f.getValuesFuncs = getValuesFuncs
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
return f
}
// WithAgentHealthProber defines how is the healthiness status of the ManagedClusterAddon probed.
func (f *AgentAddonFactory) WithAgentHealthProber(prober *agent.HealthProber) *AgentAddonFactory {
f.agentAddonOptions.HealthProber = prober
return f
}
// WithAgentHostedModeEnabledOption will enable the agent hosted deploying mode.
func (f *AgentAddonFactory) WithAgentHostedModeEnabledOption() *AgentAddonFactory {
f.agentAddonOptions.HostedModeEnabled = true
return f
}
// WithTrimCRDDescription is to enable trim the description of CRDs in manifestWork.
func (f *AgentAddonFactory) WithTrimCRDDescription() *AgentAddonFactory {
f.trimCRDDescription = true
return f
}
// WithCreateAgentInstallNamespace is to create the agent install namespace object in manifestWork.
func (f *AgentAddonFactory) WithCreateAgentInstallNamespace() *AgentAddonFactory {
f.createAgentInstallNamespace = 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...)
return f
}
// WithHostingCluster defines the hosting cluster used in hosted mode. An AgentAddon may use this to provide
// additional metadata.
func (f *AgentAddonFactory) WithHostingCluster(cluster *clusterv1.ManagedCluster) *AgentAddonFactory {
f.hostingCluster = cluster
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
// 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
// like:
//
// WithAgentDeployClusterTriggerFilter(func(old, new *clusterv1.ManagedCluster) bool {
// return !equality.Semantic.DeepEqual(old.Annotations, new.Annotations)
// })
func (f *AgentAddonFactory) WithAgentDeployTriggerClusterFilter(
filter func(old, new *clusterv1.ManagedCluster) bool,
) *AgentAddonFactory {
f.agentAddonOptions.AgentDeployTriggerClusterFilter = filter
return f
}
// WithAgentInstallNamespace defines the namespace where the agent resources will be deployed, this will
// 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,
) *AgentAddonFactory {
f.agentInstallNamespace = nsFunc
return f
}
// preBuildAddon sets the default values for the agentAddonOptions.
func (f *AgentAddonFactory) preBuildAddon() {
if f.agentInstallNamespace != nil {
if f.agentAddonOptions.Registration != nil && f.agentAddonOptions.Registration.AgentInstallNamespace == nil {
f.agentAddonOptions.Registration.AgentInstallNamespace = f.agentInstallNamespace
}
}
}
// BuildHelmAgentAddon builds a helm agentAddon instance.
func (f *AgentAddonFactory) BuildHelmAgentAddon() (agent.AgentAddon, error) {
f.preBuildAddon()
if err := validateSupportedConfigGVRs(f.agentAddonOptions.SupportedConfigGVRs); err != nil {
return nil, err
}
userChart, err := loadChart(f.fs, f.dir)
if err != nil {
return nil, err
}
agentAddon := newHelmAgentAddon(f, userChart)
return agentAddon, nil
}
// BuildTemplateAgentAddon builds a template agentAddon instance.
func (f *AgentAddonFactory) BuildTemplateAgentAddon() (agent.AgentAddon, error) {
f.preBuildAddon()
if err := validateSupportedConfigGVRs(f.agentAddonOptions.SupportedConfigGVRs); err != nil {
return nil, err
}
templateFiles, err := getTemplateFiles(f.fs, f.dir)
if err != nil {
klog.Errorf("failed to get template files. %v", err)
return nil, err
}
if len(templateFiles) == 0 {
return nil, fmt.Errorf("there is no template files")
}
agentAddon := newTemplateAgentAddon(f)
for _, file := range templateFiles {
template, err := f.fs.ReadFile(file)
if err != nil {
return nil, err
}
agentAddon.addTemplateData(file, template)
}
return agentAddon, nil
}
func validateSupportedConfigGVRs(configGVRs []schema.GroupVersionResource) error {
if len(configGVRs) == 0 {
// no configs required, ignore
return nil
}
configGVRMap := map[schema.GroupVersionResource]bool{}
for index, gvr := range configGVRs {
if gvr.Empty() {
return fmt.Errorf("config type is empty, index=%d", index)
}
if gvr.Version == "" {
return fmt.Errorf("config version is required, index=%d", index)
}
if gvr.Resource == "" {
return fmt.Errorf("config resource is required, index=%d", index)
}
if _, existed := configGVRMap[gvr]; existed {
return fmt.Errorf("config type %q is duplicated", gvr.String())
}
configGVRMap[gvr] = true
}
return nil
}