diff --git a/pkg/instance/storage.go b/pkg/instance/storage.go index 8b515ba..4287a4d 100644 --- a/pkg/instance/storage.go +++ b/pkg/instance/storage.go @@ -351,14 +351,14 @@ func (s *storage) deployFiles(ctx context.Context) error { data[keyName] = fileContent } - // create configmap - _, err := s.instance.K8sClient.CreateConfigMap(ctx, s.instance.name, s.instance.execution.Labels(), data) + // If the configmap already exists, we update it + // This ensures long-running tests and image upgrade tests function correctly. + _, err := s.instance.K8sClient.CreateOrUpdateConfigMap(ctx, s.instance.name, s.instance.execution.Labels(), data) if err != nil { return ErrFailedToCreateConfigMap.Wrap(err) } s.instance.Logger.WithField("configmap", s.instance.name).Debug("deployed configmap") - return nil } diff --git a/pkg/k8s/configmap.go b/pkg/k8s/configmap.go index da18a4c..b4bd75f 100644 --- a/pkg/k8s/configmap.go +++ b/pkg/k8s/configmap.go @@ -2,6 +2,7 @@ package k8s import ( "context" + "errors" v1 "k8s.io/api/core/v1" apierrs "k8s.io/apimachinery/pkg/api/errors" @@ -37,31 +38,60 @@ func (c *Client) CreateConfigMap( return nil, ErrClientTerminated } - if err := validateConfigMapName(name); err != nil { + if err := validateConfigMap(name, labels, data); err != nil { return nil, err } - if err := validateLabels(labels); err != nil { - return nil, err + + cm := prepareConfigMap(c.namespace, name, labels, data) + created, err := c.clientset.CoreV1().ConfigMaps(c.namespace).Create(ctx, cm, metav1.CreateOptions{}) + if err == nil { + return created, nil } - if err := validateConfigMapKeys(data); err != nil { - return nil, err + + if apierrs.IsAlreadyExists(err) { + return nil, ErrConfigmapAlreadyExists.WithParams(name).Wrap(err) } + return nil, ErrCreatingConfigmap.WithParams(name).Wrap(err) +} - exists, err := c.ConfigMapExists(ctx, name) - if err != nil { - return nil, err +func (c *Client) UpdateConfigMap( + ctx context.Context, name string, + labels, data map[string]string, +) (*v1.ConfigMap, error) { + if c.terminated { + return nil, ErrClientTerminated } - if exists { - return nil, ErrConfigmapAlreadyExists.WithParams(name) + + if err := validateConfigMap(name, labels, data); err != nil { + return nil, err } cm := prepareConfigMap(c.namespace, name, labels, data) - created, err := c.clientset.CoreV1().ConfigMaps(c.namespace).Create(ctx, cm, metav1.CreateOptions{}) - if err != nil { - return nil, ErrCreatingConfigmap.WithParams(name).Wrap(err) + updated, err := c.clientset.CoreV1().ConfigMaps(c.namespace).Update(ctx, cm, metav1.UpdateOptions{}) + if err == nil { + return updated, nil + } + + if apierrs.IsNotFound(err) { + return nil, ErrConfigmapDoesNotExist.WithParams(name).Wrap(err) + } + return nil, ErrUpdatingConfigmap.WithParams(name).Wrap(err) +} + +func (c *Client) CreateOrUpdateConfigMap( + ctx context.Context, name string, + labels, data map[string]string, +) (*v1.ConfigMap, error) { + updated, err := c.UpdateConfigMap(ctx, name, labels, data) + if err == nil { + return updated, nil + } + + if errors.Is(err, ErrConfigmapDoesNotExist) { + return c.CreateConfigMap(ctx, name, labels, data) } - return created, nil + return nil, ErrUpdatingConfigmap.WithParams(name).Wrap(err) } func (c *Client) DeleteConfigMap(ctx context.Context, name string) error { diff --git a/pkg/k8s/errors.go b/pkg/k8s/errors.go index 0d0d9ee..6cfa710 100644 --- a/pkg/k8s/errors.go +++ b/pkg/k8s/errors.go @@ -136,4 +136,5 @@ var ( ErrClientTerminated = errors.New("ClientTerminated", "terminated by user") ErrListingPods = errors.New("ListingPods", "failed to list pods") ErrGetPodStatus = errors.New("GetPodStatus", "failed to get pod status for pod %s") + ErrUpdatingConfigmap = errors.New("UpdatingConfigmap", "failed to update configmap %s") ) diff --git a/pkg/k8s/types.go b/pkg/k8s/types.go index 767e35c..9e964da 100644 --- a/pkg/k8s/types.go +++ b/pkg/k8s/types.go @@ -20,6 +20,7 @@ type KubeManager interface { CreateClusterRole(ctx context.Context, name string, labels map[string]string, policyRules []rbacv1.PolicyRule) error CreateClusterRoleBinding(ctx context.Context, name string, labels map[string]string, clusterRole, serviceAccount string) error CreateConfigMap(ctx context.Context, name string, labels, data map[string]string) (*corev1.ConfigMap, error) + CreateOrUpdateConfigMap(ctx context.Context, name string, labels, data map[string]string) (*corev1.ConfigMap, error) CreateCustomResource(ctx context.Context, name string, gvr *schema.GroupVersionResource, obj *map[string]interface{}) error CreateDaemonSet(ctx context.Context, name string, labels map[string]string, initContainers []corev1.Container, containers []corev1.Container) (*appv1.DaemonSet, error) CreateNamespace(ctx context.Context, name string) error @@ -74,6 +75,7 @@ type KubeManager interface { RunCommandInPod(ctx context.Context, podName, containerName string, cmd []string) (string, error) ConfigMapExists(ctx context.Context, name string) (bool, error) UpdateDaemonSet(ctx context.Context, name string, labels map[string]string, initContainers []corev1.Container, containers []corev1.Container) (*appv1.DaemonSet, error) + UpdateConfigMap(ctx context.Context, name string, labels, data map[string]string) (*corev1.ConfigMap, error) WaitForDeployment(ctx context.Context, name string) error WaitForService(ctx context.Context, name string) error Terminate() diff --git a/pkg/k8s/validate.go b/pkg/k8s/validate.go index 3eecb73..ee1502e 100644 --- a/pkg/k8s/validate.go +++ b/pkg/k8s/validate.go @@ -276,3 +276,13 @@ func validatePorts(ports []int) error { } return nil } + +func validateConfigMap(name string, labels, data map[string]string) error { + if err := validateConfigMapName(name); err != nil { + return err + } + if err := validateLabels(labels); err != nil { + return err + } + return validateConfigMapKeys(data) +}