Merge pull request #2724 from lonelyCZ/pr-karmadactl-util-idempotency

Fix and unify `CreateOrUpdateXXX` functions for karmadactl
This commit is contained in:
karmada-bot 2022-11-02 11:32:25 +08:00 committed by GitHub
commit f32741e13f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 266 additions and 235 deletions

View File

@ -15,6 +15,7 @@ import (
addonutils "github.com/karmada-io/karmada/pkg/karmadactl/addons/utils"
"github.com/karmada-io/karmada/pkg/karmadactl/cmdinit/kubernetes"
initutils "github.com/karmada-io/karmada/pkg/karmadactl/cmdinit/utils"
cmdutil "github.com/karmada-io/karmada/pkg/karmadactl/util"
)
var karmadaDeschedulerLabels = map[string]string{"app": addoninit.DeschedulerResourceName}
@ -59,7 +60,7 @@ var enableDescheduler = func(opts *addoninit.CommandAddonsEnableOption) error {
return fmt.Errorf("decode descheduler deployment error: %v", err)
}
if err := addonutils.CreateOrUpdateDeployment(opts.KubeClientSet, karmadaDeschedulerDeployment); err != nil {
if err := cmdutil.CreateOrUpdateDeployment(opts.KubeClientSet, karmadaDeschedulerDeployment); err != nil {
return fmt.Errorf("create karmada descheduler deployment error: %v", err)
}

View File

@ -17,6 +17,7 @@ import (
addonutils "github.com/karmada-io/karmada/pkg/karmadactl/addons/utils"
"github.com/karmada-io/karmada/pkg/karmadactl/cmdinit/kubernetes"
initutils "github.com/karmada-io/karmada/pkg/karmadactl/cmdinit/utils"
cmdutil "github.com/karmada-io/karmada/pkg/karmadactl/util"
"github.com/karmada-io/karmada/pkg/util/names"
)
@ -72,7 +73,7 @@ var enableEstimator = func(opts *addoninit.CommandAddonsEnableOption) error {
secretName := fmt.Sprintf("%s-kubeconfig", opts.Cluster)
secret := secretFromSpec(secretName, opts.Namespace, corev1.SecretTypeOpaque, map[string]string{secretName: string(configBytes)})
if err := addonutils.CreateOrUpdateSecret(opts.KubeClientSet, secret); err != nil {
if err := cmdutil.CreateOrUpdateSecret(opts.KubeClientSet, secret); err != nil {
return fmt.Errorf("create or update scheduler estimator secret error: %v", err)
}
@ -89,7 +90,7 @@ var enableEstimator = func(opts *addoninit.CommandAddonsEnableOption) error {
if err := kuberuntime.DecodeInto(clientsetscheme.Codecs.UniversalDecoder(), karmadaEstimatorServiceBytes, karmadaEstimatorService); err != nil {
return fmt.Errorf("decode karmada scheduler estimator service error: %v", err)
}
if err := addonutils.CreateService(opts.KubeClientSet, karmadaEstimatorService); err != nil {
if err := cmdutil.CreateService(opts.KubeClientSet, karmadaEstimatorService); err != nil {
return fmt.Errorf("create or update scheduler estimator service error: %v", err)
}
@ -108,7 +109,7 @@ var enableEstimator = func(opts *addoninit.CommandAddonsEnableOption) error {
if err := kuberuntime.DecodeInto(clientsetscheme.Codecs.UniversalDecoder(), karmadaEstimatorDeploymentBytes, karmadaEstimatorDeployment); err != nil {
return fmt.Errorf("decode karmada scheduler estimator deployment error: %v", err)
}
if err := addonutils.CreateOrUpdateDeployment(opts.KubeClientSet, karmadaEstimatorDeployment); err != nil {
if err := cmdutil.CreateOrUpdateDeployment(opts.KubeClientSet, karmadaEstimatorDeployment); err != nil {
return fmt.Errorf("create or update scheduler estimator deployment error: %v", err)
}

View File

@ -21,6 +21,7 @@ import (
initkarmada "github.com/karmada-io/karmada/pkg/karmadactl/cmdinit/karmada"
"github.com/karmada-io/karmada/pkg/karmadactl/cmdinit/kubernetes"
initutils "github.com/karmada-io/karmada/pkg/karmadactl/cmdinit/utils"
cmdutil "github.com/karmada-io/karmada/pkg/karmadactl/util"
)
const (
@ -135,7 +136,7 @@ func installComponentsOnHostCluster(opts *addoninit.CommandAddonsEnableOption) e
return fmt.Errorf("decode karmada search service error: %v", err)
}
if err := addonutils.CreateService(opts.KubeClientSet, karmadaSearchService); err != nil {
if err := cmdutil.CreateService(opts.KubeClientSet, karmadaSearchService); err != nil {
return fmt.Errorf("create karmada search service error: %v", err)
}
@ -161,7 +162,7 @@ func installComponentsOnHostCluster(opts *addoninit.CommandAddonsEnableOption) e
if err := kuberuntime.DecodeInto(clientsetscheme.Codecs.UniversalDecoder(), karmadaSearchDeploymentBytes, karmadaSearchDeployment); err != nil {
return fmt.Errorf("decode karmada search deployment error: %v", err)
}
if err := addonutils.CreateOrUpdateDeployment(opts.KubeClientSet, karmadaSearchDeployment); err != nil {
if err := cmdutil.CreateOrUpdateDeployment(opts.KubeClientSet, karmadaSearchDeployment); err != nil {
return fmt.Errorf("create karmada search deployment error: %v", err)
}
@ -186,7 +187,7 @@ func installComponentsOnKarmadaControlPlane(opts *addoninit.CommandAddonsEnableO
if err := kuberuntime.DecodeInto(clientsetscheme.Codecs.UniversalDecoder(), aaServiceBytes, aaService); err != nil {
return fmt.Errorf("decode karmada search AA service error: %v", err)
}
if err := addonutils.CreateService(opts.KarmadaKubeClientSet, aaService); err != nil {
if err := cmdutil.CreateService(opts.KarmadaKubeClientSet, aaService); err != nil {
return fmt.Errorf("create karmada search AA service error: %v", err)
}
@ -204,7 +205,7 @@ func installComponentsOnKarmadaControlPlane(opts *addoninit.CommandAddonsEnableO
return fmt.Errorf("decode karmada search AA apiservice error: %v", err)
}
if err = addonutils.CreateOrUpdateAPIService(opts.KarmadaAggregatorClientSet, aaAPIService); err != nil {
if err = cmdutil.CreateOrUpdateAPIService(opts.KarmadaAggregatorClientSet, aaAPIService); err != nil {
return fmt.Errorf("craete karmada search AA apiservice error: %v", err)
}

View File

@ -1,76 +0,0 @@
package utils
import (
"context"
"fmt"
appsv1 "k8s.io/api/apps/v1"
corev1 "k8s.io/api/core/v1"
apierrors "k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/client-go/kubernetes"
"k8s.io/klog/v2"
apiregistrationv1 "k8s.io/kube-aggregator/pkg/apis/apiregistration/v1"
aggregator "k8s.io/kube-aggregator/pkg/client/clientset_generated/clientset"
)
// CreateService creates a Service if the target resource doesn't exist. If the resource exists already, return directly
func CreateService(KubeClientSet *kubernetes.Clientset, service *corev1.Service) error {
if _, err := KubeClientSet.CoreV1().Services(service.ObjectMeta.Namespace).Create(context.TODO(), service, metav1.CreateOptions{}); err != nil {
if !apierrors.IsAlreadyExists(err) {
return fmt.Errorf("unable to create service: %v", err)
}
klog.Warningf("Service %s is existed, creation process will skip", service.ObjectMeta.Name)
}
return nil
}
// CreateOrUpdateSecret creates a Secret if the target resource doesn't exist. If the resource exists already, this function will update the resource instead.
func CreateOrUpdateSecret(KubeClientSet *kubernetes.Clientset, secret *corev1.Secret) error {
if _, err := KubeClientSet.CoreV1().Secrets(secret.ObjectMeta.Namespace).Create(context.TODO(), secret, metav1.CreateOptions{}); err != nil {
if !apierrors.IsAlreadyExists(err) {
return fmt.Errorf("unable to create service: %v", err)
}
if _, err := KubeClientSet.CoreV1().Secrets(secret.ObjectMeta.Namespace).Update(context.TODO(), secret, metav1.UpdateOptions{}); err != nil {
return fmt.Errorf("unable to update deployment: %v", err)
}
}
return nil
}
// CreateOrUpdateDeployment creates a Deployment if the target resource doesn't exist. If the resource exists already, this function will update the resource instead.
func CreateOrUpdateDeployment(client kubernetes.Interface, deploy *appsv1.Deployment) error {
if _, err := client.AppsV1().Deployments(deploy.ObjectMeta.Namespace).Create(context.TODO(), deploy, metav1.CreateOptions{}); err != nil {
if !apierrors.IsAlreadyExists(err) {
return fmt.Errorf("unable to create deployment: %v", err)
}
if _, err := client.AppsV1().Deployments(deploy.ObjectMeta.Namespace).Update(context.TODO(), deploy, metav1.UpdateOptions{}); err != nil {
return fmt.Errorf("unable to update deployment: %v", err)
}
}
return nil
}
// CreateOrUpdateAPIService creates a ApiService if the target resource doesn't exist. If the resource exists already, this function will update the resource instead.
func CreateOrUpdateAPIService(apiRegistrationClient *aggregator.Clientset, apiservice *apiregistrationv1.APIService) error {
if _, err := apiRegistrationClient.ApiregistrationV1().APIServices().Create(context.TODO(), apiservice, metav1.CreateOptions{}); err != nil {
if !apierrors.IsAlreadyExists(err) {
return fmt.Errorf("unable to create apiService: %v", err)
}
existAPIService, err := apiRegistrationClient.ApiregistrationV1().APIServices().Get(context.TODO(), apiservice.ObjectMeta.Name, metav1.GetOptions{})
if err != nil {
return err
}
apiservice.ObjectMeta.ResourceVersion = existAPIService.ObjectMeta.ResourceVersion
if _, err := apiRegistrationClient.ApiregistrationV1().APIServices().Update(context.TODO(), apiservice, metav1.UpdateOptions{}); err != nil {
return fmt.Errorf("unable to update apiService: %v", err)
}
}
return nil
}

View File

@ -13,7 +13,7 @@ import (
bootstrapapi "k8s.io/cluster-bootstrap/token/api"
"k8s.io/klog/v2"
"github.com/karmada-io/karmada/pkg/karmadactl/cmdinit/utils"
cmdutil "github.com/karmada-io/karmada/pkg/karmadactl/util"
)
const (
@ -47,7 +47,7 @@ func CreateBootstrapConfigMapIfNotExists(clientSet *kubernetes.Clientset, file s
// Create or update the ConfigMap in the kube-public namespace
klog.V(1).Infoln("[bootstrap-token] creating/updating ConfigMap in kube-public namespace")
return utils.CreateOrUpdateConfigMap(clientSet, &corev1.ConfigMap{
return cmdutil.CreateOrUpdateConfigMap(clientSet, &corev1.ConfigMap{
ObjectMeta: metav1.ObjectMeta{
Name: bootstrapapi.ConfigMapClusterInfo,
Namespace: metav1.NamespacePublic,
@ -61,7 +61,7 @@ func CreateBootstrapConfigMapIfNotExists(clientSet *kubernetes.Clientset, file s
// CreateClusterInfoRBACRules creates the RBAC rules for exposing the cluster-info ConfigMap in the kube-public namespace to unauthenticated users
func CreateClusterInfoRBACRules(clientSet *kubernetes.Clientset) error {
klog.V(1).Infoln("creating the RBAC rules for exposing the cluster-info ConfigMap in the kube-public namespace")
err := utils.CreateOrUpdateRole(clientSet, &rbacv1.Role{
err := cmdutil.CreateOrUpdateRole(clientSet, &rbacv1.Role{
ObjectMeta: metav1.ObjectMeta{
Name: BootstrapSignerClusterRoleName,
Namespace: metav1.NamespacePublic,
@ -79,7 +79,7 @@ func CreateClusterInfoRBACRules(clientSet *kubernetes.Clientset) error {
return err
}
return utils.CreateOrUpdateRoleBinding(clientSet, &rbacv1.RoleBinding{
return cmdutil.CreateOrUpdateRoleBinding(clientSet, &rbacv1.RoleBinding{
ObjectMeta: metav1.ObjectMeta{
Name: BootstrapSignerClusterRoleName,
Namespace: metav1.NamespacePublic,

View File

@ -1,28 +0,0 @@
package utils
import (
"context"
"fmt"
corev1 "k8s.io/api/core/v1"
apierrors "k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/client-go/kubernetes"
"k8s.io/klog/v2"
)
// CreateOrUpdateConfigMap creates a ConfigMap if the target resource doesn't exist. If the resource exists already, this function will update the resource instead.
func CreateOrUpdateConfigMap(clientSet *kubernetes.Clientset, cm *corev1.ConfigMap) error {
if _, err := clientSet.CoreV1().ConfigMaps(cm.ObjectMeta.Namespace).Create(context.TODO(), cm, metav1.CreateOptions{}); err != nil {
if !apierrors.IsAlreadyExists(err) {
return fmt.Errorf("unable to create ConfigMap: %v", err)
}
if _, err := clientSet.CoreV1().ConfigMaps(cm.ObjectMeta.Namespace).Update(context.TODO(), cm, metav1.UpdateOptions{}); err != nil {
return fmt.Errorf("unable to update ConfigMap: %v", err)
}
}
klog.Infof("ConfigMap %s/%s has been created or updated.", cm.ObjectMeta.Namespace, cm.ObjectMeta.Name)
return nil
}

View File

@ -87,35 +87,3 @@ func CreateIfNotExistClusterRoleBinding(clientSet kubernetes.Interface, binding
return nil
}
// CreateOrUpdateRole creates a Role if the target resource doesn't exist. If the resource exists already, this function will update the resource instead.
func CreateOrUpdateRole(clientSet kubernetes.Interface, role *rbacv1.Role) error {
if _, err := clientSet.RbacV1().Roles(role.ObjectMeta.Namespace).Create(context.TODO(), role, metav1.CreateOptions{}); err != nil {
if !apierrors.IsAlreadyExists(err) {
return fmt.Errorf("unable to create RBAC role: %v", err)
}
if _, err := clientSet.RbacV1().Roles(role.ObjectMeta.Namespace).Update(context.TODO(), role, metav1.UpdateOptions{}); err != nil {
return fmt.Errorf("unable to update RBAC role: %v", err)
}
}
klog.Infof("Role %s%s has been created or updated.", role.ObjectMeta.Namespace, role.ObjectMeta.Name)
return nil
}
// CreateOrUpdateRoleBinding creates a RoleBinding if the target resource doesn't exist. If the resource exists already, this function will update the resource instead.
func CreateOrUpdateRoleBinding(clientSet kubernetes.Interface, roleBinding *rbacv1.RoleBinding) error {
if _, err := clientSet.RbacV1().RoleBindings(roleBinding.ObjectMeta.Namespace).Create(context.TODO(), roleBinding, metav1.CreateOptions{}); err != nil {
if !apierrors.IsAlreadyExists(err) {
return fmt.Errorf("unable to create RBAC rolebinding: %v", err)
}
if _, err := clientSet.RbacV1().RoleBindings(roleBinding.ObjectMeta.Namespace).Update(context.TODO(), roleBinding, metav1.UpdateOptions{}); err != nil {
return fmt.Errorf("unable to update RBAC rolebinding: %v", err)
}
}
klog.Infof("RoleBinding %s/%s has been created or updated.", roleBinding.ObjectMeta.Namespace, roleBinding.ObjectMeta.Name)
return nil
}

View File

@ -37,7 +37,7 @@ import (
check "github.com/karmada-io/karmada/pkg/karmadactl/cmdinit/kubernetes"
"github.com/karmada-io/karmada/pkg/karmadactl/cmdinit/utils"
"github.com/karmada-io/karmada/pkg/karmadactl/options"
"github.com/karmada-io/karmada/pkg/karmadactl/util"
cmdutil "github.com/karmada-io/karmada/pkg/karmadactl/util"
tokenutil "github.com/karmada-io/karmada/pkg/karmadactl/util/bootstraptoken"
karmadautil "github.com/karmada-io/karmada/pkg/util"
"github.com/karmada-io/karmada/pkg/util/lifted/pubkeypin"
@ -148,7 +148,7 @@ func NewCmdRegister(parentCommand string) *cobra.Command {
return nil
},
Annotations: map[string]string{
util.TagCommandGroup: util.GroupClusterRegistration,
cmdutil.TagCommandGroup: cmdutil.GroupClusterRegistration,
},
}
flags := cmd.Flags()
@ -570,7 +570,7 @@ func (o *CommandRegisterOption) createSecretAndRBACInMemberCluster(karmadaAgentC
}
// cerate karmada-kubeconfig secret to be used by karmada-agent component.
if err := karmadautil.CreateOrUpdateSecret(o.memberClusterClient, kubeConfigSecret); err != nil {
if err := cmdutil.CreateOrUpdateSecret(o.memberClusterClient, kubeConfigSecret); err != nil {
return fmt.Errorf("create secret %s failed: %v", kubeConfigSecret.Name, err)
}

View File

@ -20,7 +20,7 @@ import (
bootstrapsecretutil "k8s.io/cluster-bootstrap/util/secrets"
"k8s.io/klog/v2"
karmadautil "github.com/karmada-io/karmada/pkg/util"
cmdutil "github.com/karmada-io/karmada/pkg/karmadactl/util"
"github.com/karmada-io/karmada/pkg/util/lifted/pubkeypin"
)
@ -322,7 +322,7 @@ func UpdateOrCreateToken(client kubeclient.Interface, failIfExists bool, token *
updatedOrNewSecret := ConvertBootstrapTokenToSecret(token)
// Try to create or update the token with an exponential backoff
err = TryRunCommand(func() error {
if err := karmadautil.CreateOrUpdateSecret(client, updatedOrNewSecret); err != nil {
if err := cmdutil.CreateOrUpdateSecret(client, updatedOrNewSecret); err != nil {
return fmt.Errorf("failed to create or update bootstrap token with name %s, err: %w", secretName, err)
}
return nil

View File

@ -0,0 +1,160 @@
package util
import (
"context"
"fmt"
appsv1 "k8s.io/api/apps/v1"
corev1 "k8s.io/api/core/v1"
rbacv1 "k8s.io/api/rbac/v1"
apierrors "k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
kubeclient "k8s.io/client-go/kubernetes"
"k8s.io/klog/v2"
apiregistrationv1 "k8s.io/kube-aggregator/pkg/apis/apiregistration/v1"
aggregator "k8s.io/kube-aggregator/pkg/client/clientset_generated/clientset"
)
// CreateService creates a Service if the target resource doesn't exist. If the resource exists already, return directly
func CreateService(client kubeclient.Interface, service *corev1.Service) error {
if _, err := client.CoreV1().Services(service.ObjectMeta.Namespace).Create(context.TODO(), service, metav1.CreateOptions{}); err != nil {
if !apierrors.IsAlreadyExists(err) {
return fmt.Errorf("unable to create service: %v", err)
}
klog.Warningf("Service %s is existed, creation process will skip", service.ObjectMeta.Name)
}
return nil
}
// CreateOrUpdateSecret creates a Secret if the target resource doesn't exist. If the resource exists already, this function will update the resource instead.
func CreateOrUpdateSecret(client kubeclient.Interface, secret *corev1.Secret) error {
if _, err := client.CoreV1().Secrets(secret.Namespace).Create(context.TODO(), secret, metav1.CreateOptions{}); err != nil {
if !apierrors.IsAlreadyExists(err) {
return fmt.Errorf("unable to create service: %v", err)
}
existSecret, err := client.CoreV1().Secrets(secret.Namespace).Get(context.TODO(), secret.Name, metav1.GetOptions{})
if err != nil {
return err
}
secret.ResourceVersion = existSecret.ResourceVersion
if _, err := client.CoreV1().Secrets(secret.ObjectMeta.Namespace).Update(context.TODO(), secret, metav1.UpdateOptions{}); err != nil {
return fmt.Errorf("unable to update deployment: %v", err)
}
}
return nil
}
// CreateOrUpdateDeployment creates a Deployment if the target resource doesn't exist. If the resource exists already, this function will update the resource instead.
func CreateOrUpdateDeployment(client kubeclient.Interface, deploy *appsv1.Deployment) error {
if _, err := client.AppsV1().Deployments(deploy.Namespace).Create(context.TODO(), deploy, metav1.CreateOptions{}); err != nil {
if !apierrors.IsAlreadyExists(err) {
return fmt.Errorf("unable to create deployment: %v", err)
}
existDeployment, err := client.AppsV1().Deployments(deploy.Namespace).Get(context.TODO(), deploy.Name, metav1.GetOptions{})
if err != nil {
return err
}
deploy.ResourceVersion = existDeployment.ResourceVersion
if _, err := client.AppsV1().Deployments(deploy.ObjectMeta.Namespace).Update(context.TODO(), deploy, metav1.UpdateOptions{}); err != nil {
return fmt.Errorf("unable to update deployment: %v", err)
}
}
return nil
}
// CreateOrUpdateAPIService creates a ApiService if the target resource doesn't exist. If the resource exists already, this function will update the resource instead.
func CreateOrUpdateAPIService(apiRegistrationClient *aggregator.Clientset, apiservice *apiregistrationv1.APIService) error {
if _, err := apiRegistrationClient.ApiregistrationV1().APIServices().Create(context.TODO(), apiservice, metav1.CreateOptions{}); err != nil {
if !apierrors.IsAlreadyExists(err) {
return fmt.Errorf("unable to create apiService: %v", err)
}
existAPIService, err := apiRegistrationClient.ApiregistrationV1().APIServices().Get(context.TODO(), apiservice.ObjectMeta.Name, metav1.GetOptions{})
if err != nil {
return err
}
apiservice.ObjectMeta.ResourceVersion = existAPIService.ObjectMeta.ResourceVersion
if _, err := apiRegistrationClient.ApiregistrationV1().APIServices().Update(context.TODO(), apiservice, metav1.UpdateOptions{}); err != nil {
return fmt.Errorf("unable to update apiService: %v", err)
}
}
return nil
}
// CreateOrUpdateRole creates a Role if the target resource doesn't exist. If the resource exists already, this function will update the resource instead.
func CreateOrUpdateRole(client kubeclient.Interface, role *rbacv1.Role) error {
if _, err := client.RbacV1().Roles(role.ObjectMeta.Namespace).Create(context.TODO(), role, metav1.CreateOptions{}); err != nil {
if !apierrors.IsAlreadyExists(err) {
return fmt.Errorf("unable to create RBAC role: %v", err)
}
existRole, err := client.AppsV1().Deployments(role.Namespace).Get(context.TODO(), role.Name, metav1.GetOptions{})
if err != nil {
return err
}
role.ResourceVersion = existRole.ResourceVersion
if _, err := client.RbacV1().Roles(role.ObjectMeta.Namespace).Update(context.TODO(), role, metav1.UpdateOptions{}); err != nil {
return fmt.Errorf("unable to update RBAC role: %v", err)
}
}
klog.V(2).Infof("Role %s%s has been created or updated.", role.ObjectMeta.Namespace, role.ObjectMeta.Name)
return nil
}
// CreateOrUpdateRoleBinding creates a RoleBinding if the target resource doesn't exist. If the resource exists already, this function will update the resource instead.
func CreateOrUpdateRoleBinding(client kubeclient.Interface, roleBinding *rbacv1.RoleBinding) error {
if _, err := client.RbacV1().RoleBindings(roleBinding.ObjectMeta.Namespace).Create(context.TODO(), roleBinding, metav1.CreateOptions{}); err != nil {
if !apierrors.IsAlreadyExists(err) {
return fmt.Errorf("unable to create RBAC rolebinding: %v", err)
}
existRoleBinding, err := client.AppsV1().Deployments(roleBinding.Namespace).Get(context.TODO(), roleBinding.Name, metav1.GetOptions{})
if err != nil {
return err
}
roleBinding.ResourceVersion = existRoleBinding.ResourceVersion
if _, err := client.RbacV1().RoleBindings(roleBinding.ObjectMeta.Namespace).Update(context.TODO(), roleBinding, metav1.UpdateOptions{}); err != nil {
return fmt.Errorf("unable to update RBAC rolebinding: %v", err)
}
}
klog.V(2).Infof("RoleBinding %s/%s has been created or updated.", roleBinding.ObjectMeta.Namespace, roleBinding.ObjectMeta.Name)
return nil
}
// CreateOrUpdateConfigMap creates a ConfigMap if the target resource doesn't exist. If the resource exists already, this function will update the resource instead.
func CreateOrUpdateConfigMap(client *kubeclient.Clientset, cm *corev1.ConfigMap) error {
if _, err := client.CoreV1().ConfigMaps(cm.ObjectMeta.Namespace).Create(context.TODO(), cm, metav1.CreateOptions{}); err != nil {
if !apierrors.IsAlreadyExists(err) {
return fmt.Errorf("unable to create ConfigMap: %v", err)
}
existCm, err := client.AppsV1().Deployments(cm.Namespace).Get(context.TODO(), cm.Name, metav1.GetOptions{})
if err != nil {
return err
}
cm.ResourceVersion = existCm.ResourceVersion
if _, err := client.CoreV1().ConfigMaps(cm.ObjectMeta.Namespace).Update(context.TODO(), cm, metav1.UpdateOptions{}); err != nil {
return fmt.Errorf("unable to update ConfigMap: %v", err)
}
}
klog.V(2).Infof("ConfigMap %s/%s has been created or updated.", cm.ObjectMeta.Namespace, cm.ObjectMeta.Name)
return nil
}

View File

@ -0,0 +1,86 @@
package util
import (
"errors"
"testing"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/client-go/kubernetes"
"k8s.io/client-go/kubernetes/fake"
coretesting "k8s.io/client-go/testing"
)
func TestCreateOrUpdateSecret(t *testing.T) {
type args struct {
client kubernetes.Interface
secret *corev1.Secret
}
tests := []struct {
name string
args args
wantErr bool
}{
{
name: "create success",
args: args{
client: fake.NewSimpleClientset(),
secret: makeSecret("test"),
},
wantErr: false,
},
{
name: "update success",
args: args{
client: fake.NewSimpleClientset(makeSecret("test")),
secret: makeSecret("test"),
},
wantErr: false,
},
{
name: "create error",
args: args{
client: func() kubernetes.Interface {
c := fake.NewSimpleClientset()
c.PrependReactor("create", "*", func(action coretesting.Action) (handled bool, ret runtime.Object, err error) {
return true, nil, errors.New("create secret error")
})
return c
}(),
secret: makeSecret("test"),
},
wantErr: true,
},
{
name: "update error",
args: args{
client: func() kubernetes.Interface {
c := fake.NewSimpleClientset(makeSecret("test"))
c.PrependReactor("update", "*", func(action coretesting.Action) (handled bool, ret runtime.Object, err error) {
return true, nil, errors.New("update secret error")
})
return c
}(),
secret: makeSecret("test"),
},
wantErr: true,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if err := CreateOrUpdateSecret(tt.args.client, tt.args.secret); (err != nil) != tt.wantErr {
t.Errorf("CreateOrUpdateSecret() error = %v, wantErr %v", err, tt.wantErr)
}
})
}
}
func makeSecret(name string) *corev1.Secret {
return &corev1.Secret{
ObjectMeta: metav1.ObjectMeta{
Namespace: metav1.NamespaceDefault,
Name: name,
},
}
}

View File

@ -3,7 +3,6 @@ package util
import (
"context"
"encoding/json"
"fmt"
corev1 "k8s.io/api/core/v1"
apierrors "k8s.io/apimachinery/pkg/api/errors"
@ -45,17 +44,3 @@ func PatchSecret(client kubeclient.Interface, namespace, name string, pt types.P
}
return nil
}
// CreateOrUpdateSecret creates a Secret if the target resource doesn't exist. If the resource exists already, this function will update the resource instead.
func CreateOrUpdateSecret(client kubeclient.Interface, secret *corev1.Secret) error {
if _, err := client.CoreV1().Secrets(secret.ObjectMeta.Namespace).Create(context.TODO(), secret, metav1.CreateOptions{}); err != nil {
if !apierrors.IsAlreadyExists(err) {
return fmt.Errorf("unable to create secret, err: %w", err)
}
if _, err := client.CoreV1().Secrets(secret.ObjectMeta.Namespace).Update(context.TODO(), secret, metav1.UpdateOptions{}); err != nil {
return fmt.Errorf("unable to update secret, err: %w", err)
}
}
return nil
}

View File

@ -1,83 +1,16 @@
package util
import (
"errors"
"reflect"
"testing"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/types"
"k8s.io/client-go/kubernetes"
"k8s.io/client-go/kubernetes/fake"
coretesting "k8s.io/client-go/testing"
)
func TestCreateOrUpdateSecret(t *testing.T) {
type args struct {
client kubernetes.Interface
secret *corev1.Secret
}
tests := []struct {
name string
args args
wantErr bool
}{
{
name: "create success",
args: args{
client: fake.NewSimpleClientset(),
secret: makeSecret("test"),
},
wantErr: false,
},
{
name: "update success",
args: args{
client: fake.NewSimpleClientset(makeSecret("test")),
secret: makeSecret("test"),
},
wantErr: false,
},
{
name: "create error",
args: args{
client: func() kubernetes.Interface {
c := fake.NewSimpleClientset()
c.PrependReactor("create", "*", func(action coretesting.Action) (handled bool, ret runtime.Object, err error) {
return true, nil, errors.New("create secret error")
})
return c
}(),
secret: makeSecret("test"),
},
wantErr: true,
},
{
name: "update error",
args: args{
client: func() kubernetes.Interface {
c := fake.NewSimpleClientset(makeSecret("test"))
c.PrependReactor("update", "*", func(action coretesting.Action) (handled bool, ret runtime.Object, err error) {
return true, nil, errors.New("update secret error")
})
return c
}(),
secret: makeSecret("test"),
},
wantErr: true,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if err := CreateOrUpdateSecret(tt.args.client, tt.args.secret); (err != nil) != tt.wantErr {
t.Errorf("CreateOrUpdateSecret() error = %v, wantErr %v", err, tt.wantErr)
}
})
}
}
func TestCreateSecret(t *testing.T) {
type args struct {
client kubernetes.Interface