github.com/juju/juju@v0.0.0-20240430160146-1752b71fcf00/caas/kubernetes/provider/configmap.go (about)

     1  // Copyright 2019 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package provider
     5  
     6  import (
     7  	"context"
     8  
     9  	"github.com/juju/errors"
    10  	core "k8s.io/api/core/v1"
    11  	k8serrors "k8s.io/apimachinery/pkg/api/errors"
    12  	v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    13  	"k8s.io/apimachinery/pkg/types"
    14  
    15  	"github.com/juju/juju/caas/kubernetes/provider/constants"
    16  	"github.com/juju/juju/caas/kubernetes/provider/utils"
    17  	"github.com/juju/juju/caas/specs"
    18  )
    19  
    20  func (k *kubernetesClient) getConfigMapLabels(appName string) map[string]string {
    21  	return utils.LabelsForApp(appName, k.IsLegacyLabels())
    22  }
    23  
    24  func (k *kubernetesClient) ensureConfigMaps(
    25  	appName string,
    26  	annotations map[string]string,
    27  	cms map[string]specs.ConfigMap,
    28  ) (cleanUps []func(), _ error) {
    29  	if k.namespace == "" {
    30  		return nil, errNoNamespace
    31  	}
    32  	for name, v := range cms {
    33  		spec := &core.ConfigMap{
    34  			ObjectMeta: v1.ObjectMeta{
    35  				Name:        name,
    36  				Namespace:   k.namespace,
    37  				Labels:      k.getConfigMapLabels(appName),
    38  				Annotations: annotations,
    39  			},
    40  			Data: v,
    41  		}
    42  		cmCleanup, err := k.ensureConfigMap(spec)
    43  		cleanUps = append(cleanUps, cmCleanup)
    44  		if err != nil {
    45  			return cleanUps, errors.Trace(err)
    46  		}
    47  	}
    48  	return cleanUps, nil
    49  }
    50  
    51  // ensureConfigMapLegacy is a tmp fix for upgrading configmap(no proper labels) created in 2.6.
    52  // TODO(caas): remove this and use "updateConfigMap" once `environupgrader` supports CaaS models.
    53  func (k *kubernetesClient) ensureConfigMapLegacy(cm *core.ConfigMap) (cleanUp func(), err error) {
    54  	cleanUp = func() {}
    55  	if k.namespace == "" {
    56  		return cleanUp, errNoNamespace
    57  	}
    58  	api := k.client().CoreV1().ConfigMaps(k.namespace)
    59  	_, err = api.Update(context.TODO(), cm, v1.UpdateOptions{})
    60  	if k8serrors.IsNotFound(err) {
    61  		var out *core.ConfigMap
    62  		if out, err = api.Create(context.TODO(), cm, v1.CreateOptions{}); err == nil {
    63  			logger.Debugf("configmap %q created", out.GetName())
    64  			cleanUp = func() { _ = k.deleteConfigMap(out.GetName(), out.GetUID()) }
    65  			return cleanUp, nil
    66  		}
    67  	}
    68  	return cleanUp, errors.Trace(err)
    69  }
    70  
    71  // ensureConfigMap ensures a ConfigMap resource.
    72  func (k *kubernetesClient) ensureConfigMap(cm *core.ConfigMap) (func(), error) {
    73  	cleanUp := func() {}
    74  	out, err := k.createConfigMap(cm)
    75  	if err == nil {
    76  		logger.Debugf("configmap %q created", out.GetName())
    77  		cleanUp = func() { _ = k.deleteConfigMap(out.GetName(), out.GetUID()) }
    78  		return cleanUp, nil
    79  	}
    80  	if !errors.IsAlreadyExists(err) {
    81  		return cleanUp, errors.Trace(err)
    82  	}
    83  	err = k.updateConfigMap(cm)
    84  	logger.Debugf("updating configmap %q", cm.GetName())
    85  	return cleanUp, errors.Trace(err)
    86  }
    87  
    88  func (k *kubernetesClient) updateConfigMap(cm *core.ConfigMap) error {
    89  	if k.namespace == "" {
    90  		return errNoNamespace
    91  	}
    92  	_, err := k.client().CoreV1().ConfigMaps(k.namespace).Update(context.TODO(), cm, v1.UpdateOptions{})
    93  	if k8serrors.IsNotFound(err) {
    94  		return errors.NotFoundf("configmap %q", cm.GetName())
    95  	}
    96  	return errors.Trace(err)
    97  }
    98  
    99  // getConfigMap returns a ConfigMap resource.
   100  func (k *kubernetesClient) getConfigMap(name string) (*core.ConfigMap, error) {
   101  	if k.namespace == "" {
   102  		return nil, errNoNamespace
   103  	}
   104  	cm, err := k.client().CoreV1().ConfigMaps(k.namespace).Get(context.TODO(), name, v1.GetOptions{})
   105  	if err != nil {
   106  		if k8serrors.IsNotFound(err) {
   107  			return nil, errors.NotFoundf("configmap %q", name)
   108  		}
   109  		return nil, errors.Trace(err)
   110  	}
   111  	return cm, nil
   112  }
   113  
   114  // createConfigMap creates a ConfigMap resource.
   115  func (k *kubernetesClient) createConfigMap(cm *core.ConfigMap) (*core.ConfigMap, error) {
   116  	if k.namespace == "" {
   117  		return nil, errNoNamespace
   118  	}
   119  	utils.PurifyResource(cm)
   120  	out, err := k.client().CoreV1().ConfigMaps(k.namespace).Create(context.TODO(), cm, v1.CreateOptions{})
   121  	if k8serrors.IsAlreadyExists(err) {
   122  		return nil, errors.AlreadyExistsf("configmap %q", cm.GetName())
   123  	}
   124  	return out, errors.Trace(err)
   125  }
   126  
   127  // deleteConfigMap deletes a ConfigMap resource.
   128  func (k *kubernetesClient) deleteConfigMap(name string, uid types.UID) error {
   129  	if k.namespace == "" {
   130  		return errNoNamespace
   131  	}
   132  	err := k.client().CoreV1().ConfigMaps(k.namespace).Delete(context.TODO(), name, utils.NewPreconditionDeleteOptions(uid))
   133  	if k8serrors.IsNotFound(err) {
   134  		return nil
   135  	}
   136  	return errors.Trace(err)
   137  }
   138  
   139  func (k *kubernetesClient) deleteConfigMaps(appName string) error {
   140  	if k.namespace == "" {
   141  		return errNoNamespace
   142  	}
   143  	err := k.client().CoreV1().ConfigMaps(k.namespace).DeleteCollection(context.TODO(), v1.DeleteOptions{
   144  		PropagationPolicy: constants.DefaultPropagationPolicy(),
   145  	}, v1.ListOptions{
   146  		LabelSelector: utils.LabelsToSelector(k.getConfigMapLabels(appName)).String(),
   147  	})
   148  	if k8serrors.IsNotFound(err) {
   149  		return nil
   150  	}
   151  	return errors.Trace(err)
   152  }