Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

add a helper func for setting agent install namespace from addon deployment config #205

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion cmd/example/helloworld/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -93,12 +93,17 @@ func runController(ctx context.Context, kubeConfig *rest.Config) error {
utilrand.String(5),
)

// Set agent install namespace from addon deployment config if it exists
registrationOption.AgentInstallNamespace = utils.AgentInstallNamespaceFromDeploymentConfigFunc(
utils.NewAddOnDeploymentConfigGetter(addonClient),
)

agentAddon, err := addonfactory.NewAgentAddonFactory(helloworld.AddonName, helloworld.FS, "manifests/templates").
WithConfigGVRs(utils.AddOnDeploymentConfigGVR).
WithGetValuesFuncs(
helloworld.GetDefaultValues,
addonfactory.GetAddOnDeploymentConfigValues(
addonfactory.NewAddOnDeploymentConfigGetter(addonClient),
utils.NewAddOnDeploymentConfigGetter(addonClient),
addonfactory.ToAddOnDeploymentConfigValues,
addonfactory.ToImageOverrideValuesFunc("Image", helloworld.DefaultHelloWorldExampleImage),
),
Expand Down
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ require (
k8s.io/component-base v0.26.7
k8s.io/klog/v2 v2.80.1
k8s.io/utils v0.0.0-20221128185143-99ec85e7a448
open-cluster-management.io/api v0.11.1-0.20230731134013-26e75df27f50
open-cluster-management.io/api v0.11.1-0.20230905055724-cf1ead467a83
sigs.k8s.io/controller-runtime v0.14.4
)

Expand Down
4 changes: 2 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -819,8 +819,8 @@ k8s.io/kube-openapi v0.0.0-20221012153701-172d655c2280 h1:+70TFaan3hfJzs+7VK2o+O
k8s.io/kube-openapi v0.0.0-20221012153701-172d655c2280/go.mod h1:+Axhij7bCpeqhklhUTe3xmOn6bWxolyZEeyaFpjGtl4=
k8s.io/utils v0.0.0-20221128185143-99ec85e7a448 h1:KTgPnR10d5zhztWptI952TNtt/4u5h3IzDXkdIMuo2Y=
k8s.io/utils v0.0.0-20221128185143-99ec85e7a448/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0=
open-cluster-management.io/api v0.11.1-0.20230731134013-26e75df27f50 h1:njvnCHeYMQvBWjKW97xa2r3A0/tN8H0FI9kL4AeCqVs=
open-cluster-management.io/api v0.11.1-0.20230731134013-26e75df27f50/go.mod h1:WgKUCJ7+Bf40DsOmH1Gdkpyj3joco+QLzrlM6Ak39zE=
open-cluster-management.io/api v0.11.1-0.20230905055724-cf1ead467a83 h1:3zbT3sT/tEAQbpjIk6uRiTQGknQ3kQlfd11ElVuXyyQ=
open-cluster-management.io/api v0.11.1-0.20230905055724-cf1ead467a83/go.mod h1:nsQ/G5JpfjQUg7dHpblyywWC6BRqklNaF6fIswVCHyY=
rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0=
rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA=
Expand Down
38 changes: 9 additions & 29 deletions pkg/addonfactory/addondeploymentconfig.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ import (
"strings"

corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/klog/v2"
addonapiv1alpha1 "open-cluster-management.io/api/addon/v1alpha1"
Expand All @@ -29,25 +28,10 @@ var AddOnDeploymentConfigGVR = schema.GroupVersionResource{
// Deprecated: use AddOnDeploymentConfigToValuesFunc instead.
type AddOnDeloymentConfigToValuesFunc func(config addonapiv1alpha1.AddOnDeploymentConfig) (Values, error)

// AddOnDeloymentConfigGetter has a method to return a AddOnDeploymentConfig object
// Deprecated: use AddOnDeploymentConfigGetter instead.
type AddOnDeloymentConfigGetter interface {
Get(ctx context.Context, namespace, name string) (*addonapiv1alpha1.AddOnDeploymentConfig, error)
}

type defaultAddOnDeploymentConfigGetter struct {
addonClient addonv1alpha1client.Interface
}

func (g *defaultAddOnDeploymentConfigGetter) Get(
ctx context.Context, namespace, name string) (*addonapiv1alpha1.AddOnDeploymentConfig, error) {
return g.addonClient.AddonV1alpha1().AddOnDeploymentConfigs(namespace).Get(ctx, name, metav1.GetOptions{})
}

// NewAddOnDeloymentConfigGetter returns a AddOnDeloymentConfigGetter with addon client
// Deprecated: use NewAddOnDeploymentConfigGetter instead.
func NewAddOnDeloymentConfigGetter(addonClient addonv1alpha1client.Interface) AddOnDeloymentConfigGetter {
return &defaultAddOnDeploymentConfigGetter{addonClient: addonClient}
// Deprecated: use NewAddOnDeploymentConfigGetter in pkg/utils package instead.
func NewAddOnDeloymentConfigGetter(addonClient addonv1alpha1client.Interface) utils.AddOnDeploymentConfigGetter {
return utils.NewAddOnDeploymentConfigGetter(addonClient)
}

// GetAddOnDeloymentConfigValues uses AddOnDeloymentConfigGetter to get the AddOnDeploymentConfig object, then
Expand All @@ -56,7 +40,7 @@ func NewAddOnDeloymentConfigGetter(addonClient addonv1alpha1client.Interface) Ad
// override the one from small index
// Deprecated: use GetAddOnDeploymentConfigValues instead.
func GetAddOnDeloymentConfigValues(
getter AddOnDeloymentConfigGetter, toValuesFuncs ...AddOnDeloymentConfigToValuesFunc) GetValuesFunc {
getter utils.AddOnDeploymentConfigGetter, toValuesFuncs ...AddOnDeloymentConfigToValuesFunc) GetValuesFunc {
return func(cluster *clusterv1.ManagedCluster, addon *addonapiv1alpha1.ManagedClusterAddOn) (Values, error) {
var lastValues = Values{}
for _, config := range addon.Status.ConfigReferences {
Expand Down Expand Up @@ -212,22 +196,18 @@ func ToAddOnCustomizedVariableValues(config addonapiv1alpha1.AddOnDeploymentConf
// The transformation logic depends on the definition of the addon template
type AddOnDeploymentConfigToValuesFunc func(config addonapiv1alpha1.AddOnDeploymentConfig) (Values, error)

// AddOnDeploymentConfigGetter has a method to return a AddOnDeploymentConfig object
type AddOnDeploymentConfigGetter interface {
Get(ctx context.Context, namespace, name string) (*addonapiv1alpha1.AddOnDeploymentConfig, error)
}

// NewAddOnDeploymentConfigGetter returns a AddOnDeploymentConfigGetter with addon client
func NewAddOnDeploymentConfigGetter(addonClient addonv1alpha1client.Interface) AddOnDeploymentConfigGetter {
return &defaultAddOnDeploymentConfigGetter{addonClient: addonClient}
// Deprecated: use NewAddOnDeploymentConfigGetter in pkg/utils package instead.
func NewAddOnDeploymentConfigGetter(addonClient addonv1alpha1client.Interface) utils.AddOnDeploymentConfigGetter {
return utils.NewAddOnDeploymentConfigGetter(addonClient)
}

// GetAddOnDeploymentConfigValues uses AddOnDeploymentConfigGetter to get the AddOnDeploymentConfig object, then
// uses AddOnDeploymentConfigToValuesFunc to transform the AddOnDeploymentConfig object to Values object
// If there are multiple AddOnDeploymentConfig objects in the AddOn ConfigReferences, the big index object will
// override the one from small index
func GetAddOnDeploymentConfigValues(
getter AddOnDeploymentConfigGetter, toValuesFuncs ...AddOnDeploymentConfigToValuesFunc) GetValuesFunc {
getter utils.AddOnDeploymentConfigGetter, toValuesFuncs ...AddOnDeploymentConfigToValuesFunc) GetValuesFunc {
return func(cluster *clusterv1.ManagedCluster, addon *addonapiv1alpha1.ManagedClusterAddOn) (Values, error) {
var lastValues = Values{}
for _, config := range addon.Status.ConfigReferences {
Expand Down Expand Up @@ -360,7 +340,7 @@ func getRegistriesFromClusterAnnotation(
// - the imageKey can support the nested key, for example: "global.imageOverrides.helloWorldImage", the output
// will be: {"global": {"imageOverrides": {"helloWorldImage": "quay.io/ocm/addon-agent:v1"}}}
// - Image registries configured in the addonDeploymentConfig will take precedence over the managed cluster annotation
func GetAgentImageValues(getter AddOnDeploymentConfigGetter, imageKey, image string) GetValuesFunc {
func GetAgentImageValues(getter utils.AddOnDeploymentConfigGetter, imageKey, image string) GetValuesFunc {
return func(cluster *clusterv1.ManagedCluster, addon *addonapiv1alpha1.ManagedClusterAddOn) (Values, error) {

// Get image from AddOnDeploymentConfig
Expand Down
120 changes: 120 additions & 0 deletions pkg/utils/addon_config.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
package utils

import (
"context"
"fmt"

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"
)

// AddOnDeploymentConfigGetter has a method to return a AddOnDeploymentConfig object
type AddOnDeploymentConfigGetter interface {
Get(ctx context.Context, namespace, name string) (*addonapiv1alpha1.AddOnDeploymentConfig, error)
}

type defaultAddOnDeploymentConfigGetter struct {
addonClient addonv1alpha1client.Interface
}

// NewAddOnDeploymentConfigGetter returns a AddOnDeploymentConfigGetter with addon client
func NewAddOnDeploymentConfigGetter(addonClient addonv1alpha1client.Interface) AddOnDeploymentConfigGetter {
return &defaultAddOnDeploymentConfigGetter{addonClient: addonClient}
}

func (g *defaultAddOnDeploymentConfigGetter) Get(
ctx context.Context, namespace, name string) (*addonapiv1alpha1.AddOnDeploymentConfig, error) {
return g.addonClient.AddonV1alpha1().AddOnDeploymentConfigs(namespace).Get(ctx, name, metav1.GetOptions{})
}

// AgentInstallNamespaceFromDeploymentConfigFunc returns an agent install namespace helper function which will get the
// namespace from the addon deployment config. If the addon does not support addon deployment config or there is no
// matched addon deployment config, it will return an empty string.
func AgentInstallNamespaceFromDeploymentConfigFunc(
adcgetter AddOnDeploymentConfigGetter,
) func(*addonapiv1alpha1.ManagedClusterAddOn) string {
return func(addon *addonapiv1alpha1.ManagedClusterAddOn) string {
if addon == nil {
utilruntime.HandleError(fmt.Errorf("failed to get addon install namespace, addon is nil"))
return ""
}

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 ""
}
if config == nil {
return ""
}

return config.Spec.AgentInstallNamespace
}
}

// GetDesiredAddOnDeployment returns the desired addonDeploymentConfig of the addon
func GetDesiredAddOnDeploymentConfig(
addon *addonapiv1alpha1.ManagedClusterAddOn,
adcgetter AddOnDeploymentConfigGetter,
) (*addonapiv1alpha1.AddOnDeploymentConfig, error) {

ok, configRef := GetAddOnConfigRef(addon.Status.ConfigReferences,
AddOnDeploymentConfigGVR.Group, AddOnDeploymentConfigGVR.Resource)
if !ok {
klog.InfoS("Addon deployment config in status is empty", "addonName", addon.Name)
return nil, nil
}

desiredConfig := configRef.DesiredConfig
if desiredConfig == nil || len(desiredConfig.SpecHash) == 0 {
klog.InfoS("Addon deployment config spec hash is empty", "addonName", addon.Name)
return nil, fmt.Errorf("addon %s deployment config desired spec hash is empty", addon.Name)
}

adc, err := adcgetter.Get(context.TODO(), desiredConfig.Namespace, desiredConfig.Name)
if err != nil {
return nil, err
}

specHash, err := GetAddOnDeploymentConfigSpecHash(adc)
if err != nil {
return nil, err
}
if specHash != desiredConfig.SpecHash {
return nil, fmt.Errorf("addon %s deployment config spec hash %s is not equal to desired spec hash %s",
addon.Name, specHash, desiredConfig.SpecHash)
}
return adc.DeepCopy(), nil
}

// GetAddOnDeploymentConfigSpecHash returns the sha256 hash of the spec field of the addon deployment config
func GetAddOnDeploymentConfigSpecHash(config *addonapiv1alpha1.AddOnDeploymentConfig) (string, error) {
if config == nil {
return "", fmt.Errorf("addon deployment config is nil")
}
uadc, err := runtime.DefaultUnstructuredConverter.ToUnstructured(config)
if err != nil {
return "", err
}
return GetSpecHash(&unstructured.Unstructured{
Object: uadc,
})
}

// GetAddOnConfigRef returns the first addon config ref for the given config type
func GetAddOnConfigRef(
configReferences []addonapiv1alpha1.ConfigReference,
group, resource string) (bool, addonapiv1alpha1.ConfigReference) {

for _, config := range configReferences {
if config.Group == group && config.Resource == resource {
return true, config
}
}
return false, addonapiv1alpha1.ConfigReference{}
}
Loading
Loading