| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212 |
- package environment_groups
- import (
- "context"
- "fmt"
- "strconv"
- "github.com/porter-dev/porter/internal/kubernetes"
- "github.com/porter-dev/porter/internal/telemetry"
- v1 "k8s.io/api/core/v1"
- k8serror "k8s.io/apimachinery/pkg/api/errors"
- metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
- )
- // CreateOrUpdateBaseEnvironmentGroup creates a new environment group in the porter-env-group namespace. If porter-env-group does not exist, it will be created.
- // If no existing environmentGroup exists by this name, a new one will be created as version 1, denoted by the label "porter.run/environment-group-version: 1".
- // If an environmentGroup already exists by this name, a new version will be created, and the label will be updated to reflect the new version.
- // Providing the Version field to this function will be ignored in order to not accidentally overwrite versions
- func CreateOrUpdateBaseEnvironmentGroup(ctx context.Context, a *kubernetes.Agent, environmentGroup EnvironmentGroup, additionalLabels map[string]string) error {
- ctx, span := telemetry.NewSpan(ctx, "create-environment-group")
- defer span.End()
- telemetry.WithAttributes(span, telemetry.AttributeKV{Key: "environment-group", Value: environmentGroup.Name})
- if environmentGroup.Name == "" {
- return telemetry.Error(ctx, span, nil, "environment group name cannot be empty")
- }
- _, err := a.Clientset.CoreV1().Namespaces().Get(ctx, Namespace_EnvironmentGroups, metav1.GetOptions{})
- if err != nil {
- if !k8serror.IsNotFound(err) {
- return telemetry.Error(ctx, span, err, "unable to check if global environment group exists")
- }
- _, err = a.Clientset.CoreV1().Namespaces().Create(ctx, &v1.Namespace{ObjectMeta: metav1.ObjectMeta{Name: Namespace_EnvironmentGroups}}, metav1.CreateOptions{})
- if err != nil {
- return telemetry.Error(ctx, span, err, "unable to create global environment group")
- }
- }
- telemetry.WithAttributes(span, telemetry.AttributeKV{Key: "environment-group-namespace", Value: Namespace_EnvironmentGroups})
- latestEnvironmentGroup, err := latestBaseEnvironmentGroup(ctx, a, environmentGroup.Name)
- if err != nil {
- return telemetry.Error(ctx, span, err, "unable to get latest base environment group by name")
- }
- // If any of the secret variables are set to the dummy value (i.e. are unchanged), replace them with the existing value.
- for k, v := range environmentGroup.SecretVariables {
- if v == EnvGroupSecretDummyValue {
- existingValue, ok := latestEnvironmentGroup.SecretVariables[k]
- if !ok {
- return telemetry.Error(ctx, span, nil, "secret variable does not exist in latest environment group")
- }
- if string(existingValue) == "" {
- return telemetry.Error(ctx, span, nil, "secret variable value is empty")
- }
- environmentGroup.SecretVariables[k] = existingValue
- }
- }
- newEnvironmentGroup := EnvironmentGroup{
- Name: environmentGroup.Name,
- Variables: environmentGroup.Variables,
- SecretVariables: environmentGroup.SecretVariables,
- Version: latestEnvironmentGroup.Version + 1,
- CreatedAtUTC: environmentGroup.CreatedAtUTC,
- }
- err = createVersionedEnvironmentGroupInNamespace(ctx, a, newEnvironmentGroup, Namespace_EnvironmentGroups, additionalLabels)
- if err != nil {
- return telemetry.Error(ctx, span, err, "unable to create new versioned environment group")
- }
- return nil
- }
- // createEnvironmentGroupInTargetNamespace creates a new environment group in the target namespace. If you want to create a new base environment group, use CreateOrUpdateBaseEnvironmentGroup instead.
- // This should only be used for sync from a base environment to a target environment.
- // If the target namespace does not exist, it will be created for you.
- func createEnvironmentGroupInTargetNamespace(ctx context.Context, a *kubernetes.Agent, namespace string, environmentGroup EnvironmentGroup, additionalLabels map[string]string) (string, error) {
- ctx, span := telemetry.NewSpan(ctx, "create-environment-group-in-target")
- defer span.End()
- telemetry.WithAttributes(span,
- telemetry.AttributeKV{Key: "environment-group", Value: environmentGroup.Name},
- telemetry.AttributeKV{Key: "target-namespace", Value: namespace},
- )
- // var configMapName string
- configMapName := fmt.Sprintf("%s.%d", environmentGroup.Name, environmentGroup.Version)
- if environmentGroup.Name == "" {
- return configMapName, telemetry.Error(ctx, span, nil, "environment group name cannot be empty")
- }
- if environmentGroup.Version == 0 {
- return configMapName, telemetry.Error(ctx, span, nil, "environment group version cannot be empty")
- }
- if namespace == "" {
- return configMapName, telemetry.Error(ctx, span, nil, "target namespace cannot be empty")
- }
- _, err := a.Clientset.CoreV1().Namespaces().Get(ctx, namespace, metav1.GetOptions{})
- if err != nil {
- if !k8serror.IsNotFound(err) {
- return configMapName, telemetry.Error(ctx, span, err, "unable to check if target namespace exists")
- }
- _, err = a.Clientset.CoreV1().Namespaces().Create(ctx, &v1.Namespace{ObjectMeta: metav1.ObjectMeta{Name: namespace}}, metav1.CreateOptions{})
- if err != nil {
- return configMapName, telemetry.Error(ctx, span, err, "unable to create new target namespace")
- }
- }
- telemetry.WithAttributes(span, telemetry.AttributeKV{Key: "environment-group-namespace", Value: namespace})
- err = createVersionedEnvironmentGroupInNamespace(ctx, a, environmentGroup, namespace, additionalLabels)
- if err != nil {
- return configMapName, telemetry.Error(ctx, span, err, "error creating environment group clone in target namespace")
- }
- return configMapName, nil
- }
- // createVersionedEnvironmentGroupInNamespace creates a new environment group in the target namespace. This is used to keep the configmap and secret version for an environment variable in sync
- func createVersionedEnvironmentGroupInNamespace(ctx context.Context, a *kubernetes.Agent, environmentGroup EnvironmentGroup, targetNamespace string, additionalLabels map[string]string) error {
- ctx, span := telemetry.NewSpan(ctx, "create-environment-group-on-cluster")
- defer span.End()
- configMap := v1.ConfigMap{
- ObjectMeta: metav1.ObjectMeta{
- Name: fmt.Sprintf("%s.%d", environmentGroup.Name, environmentGroup.Version),
- Namespace: targetNamespace,
- Labels: map[string]string{
- LabelKey_EnvironmentGroupName: environmentGroup.Name,
- LabelKey_EnvironmentGroupVersion: strconv.Itoa(environmentGroup.Version),
- LabelKey_PorterManaged: "true",
- },
- },
- Data: environmentGroup.Variables,
- }
- for k, v := range additionalLabels {
- configMap.Labels[k] = v
- }
- err := createConfigMapWithVersion(ctx, a, configMap, environmentGroup.Version)
- if err != nil {
- return telemetry.Error(ctx, span, err, "unable to create new environment group variables version")
- }
- secretData := make(map[string][]byte)
- for k, v := range environmentGroup.SecretVariables {
- secretData[k] = []byte(v)
- }
- secret := v1.Secret{
- ObjectMeta: metav1.ObjectMeta{
- Name: fmt.Sprintf("%s.%d", environmentGroup.Name, environmentGroup.Version),
- Namespace: targetNamespace,
- Labels: map[string]string{
- LabelKey_EnvironmentGroupName: environmentGroup.Name,
- LabelKey_EnvironmentGroupVersion: strconv.Itoa(environmentGroup.Version),
- LabelKey_PorterManaged: "true",
- },
- },
- Data: secretData,
- }
- for k, v := range additionalLabels {
- secret.Labels[k] = v
- }
- err = createSecretWithVersion(ctx, a, secret, environmentGroup.Version)
- if err != nil {
- return telemetry.Error(ctx, span, err, "unable to create new environment group secret variables version")
- }
- return nil
- }
- func createConfigMapWithVersion(ctx context.Context, a *kubernetes.Agent, configMap v1.ConfigMap, version int) error {
- ctx, span := telemetry.NewSpan(ctx, "create-environment-group-configmap")
- defer span.End()
- telemetry.WithAttributes(span,
- telemetry.AttributeKV{Key: "configmap-label", Value: configMap.Labels[LabelKey_EnvironmentGroupName]},
- telemetry.AttributeKV{Key: "configmap-version", Value: configMap.Labels[LabelKey_EnvironmentGroupVersion]},
- telemetry.AttributeKV{Key: "configmap-name", Value: configMap.Name},
- telemetry.AttributeKV{Key: "configmap-namespace", Value: configMap.Namespace},
- )
- _, err := a.Clientset.CoreV1().ConfigMaps(configMap.Namespace).Create(ctx, &configMap, metav1.CreateOptions{})
- if err != nil {
- return telemetry.Error(ctx, span, err, "unable to create environment group configmap")
- }
- return nil
- }
- func createSecretWithVersion(ctx context.Context, a *kubernetes.Agent, secret v1.Secret, version int) error {
- ctx, span := telemetry.NewSpan(ctx, "create-environment-group-secret")
- defer span.End()
- telemetry.WithAttributes(span,
- telemetry.AttributeKV{Key: "secret-label", Value: secret.Labels[LabelKey_EnvironmentGroupName]},
- telemetry.AttributeKV{Key: "secret-version", Value: secret.Labels[LabelKey_EnvironmentGroupVersion]},
- telemetry.AttributeKV{Key: "secret-name", Value: secret.Name},
- telemetry.AttributeKV{Key: "secret-namespace", Value: secret.Namespace},
- )
- _, err := a.Clientset.CoreV1().Secrets(secret.Namespace).Create(ctx, &secret, metav1.CreateOptions{})
- if err != nil {
- return telemetry.Error(ctx, span, err, "unable to create environment group secret")
- }
- return nil
- }
|