create.go 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183
  1. package environment_groups
  2. import (
  3. "context"
  4. "fmt"
  5. "strconv"
  6. "github.com/porter-dev/porter/internal/kubernetes"
  7. "github.com/porter-dev/porter/internal/telemetry"
  8. v1 "k8s.io/api/core/v1"
  9. k8serror "k8s.io/apimachinery/pkg/api/errors"
  10. metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
  11. )
  12. // CreateOrUpdateBaseEnvironmentGroup creates a new environment group in the porter-env-group namespace. If porter-env-group does not exist, it will be created.
  13. // 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".
  14. // 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.
  15. // Providing the Version field to this function will be ignored in order to not accidentally overwrite versions
  16. func CreateOrUpdateBaseEnvironmentGroup(ctx context.Context, a *kubernetes.Agent, environmentGroup EnvironmentGroup) error {
  17. ctx, span := telemetry.NewSpan(ctx, "create-environment-group")
  18. defer span.End()
  19. telemetry.WithAttributes(span, telemetry.AttributeKV{Key: "environment-group", Value: environmentGroup.Name})
  20. if environmentGroup.Name == "" {
  21. return telemetry.Error(ctx, span, nil, "environment group name cannot be empty")
  22. }
  23. _, err := a.Clientset.CoreV1().Namespaces().Get(ctx, Namespace_EnvironmentGroups, metav1.GetOptions{})
  24. if err != nil {
  25. if !k8serror.IsNotFound(err) {
  26. return telemetry.Error(ctx, span, err, "unable to check if global environment group exists")
  27. }
  28. _, err = a.Clientset.CoreV1().Namespaces().Create(ctx, &v1.Namespace{ObjectMeta: metav1.ObjectMeta{Name: Namespace_EnvironmentGroups}}, metav1.CreateOptions{})
  29. if err != nil {
  30. return telemetry.Error(ctx, span, err, "unable to create global environment group")
  31. }
  32. }
  33. telemetry.WithAttributes(span, telemetry.AttributeKV{Key: "environment-group-namespace", Value: Namespace_EnvironmentGroups})
  34. latestEnvironmentGroup, err := LatestBaseEnvironmentGroup(ctx, a, environmentGroup.Name)
  35. if err != nil {
  36. return telemetry.Error(ctx, span, err, "unable to get latest base environment group by name")
  37. }
  38. newEnvironmentGroup := EnvironmentGroup{
  39. Name: environmentGroup.Name,
  40. Variables: environmentGroup.Variables,
  41. SecretVariables: environmentGroup.SecretVariables,
  42. Version: latestEnvironmentGroup.Version + 1,
  43. CreatedAtUTC: environmentGroup.CreatedAtUTC,
  44. }
  45. err = createVersionedEnvironmentGroupInNamespace(ctx, a, newEnvironmentGroup, Namespace_EnvironmentGroups)
  46. if err != nil {
  47. return telemetry.Error(ctx, span, err, "unable to create new versioned environment group")
  48. }
  49. return nil
  50. }
  51. // createEnvironmentGroupInTargetNamespace creates a new environment group in the target namespace. If you want to create a new base environment group, use CreateOrUpdateBaseEnvironmentGroup instead.
  52. // This should only be used for sync from a base environment to a target environment.
  53. // If the target namespace does not exist, it will be created for you.
  54. func createEnvironmentGroupInTargetNamespace(ctx context.Context, a *kubernetes.Agent, namespace string, environmentGroup EnvironmentGroup) (string, error) {
  55. ctx, span := telemetry.NewSpan(ctx, "create-environment-group-in-target")
  56. defer span.End()
  57. telemetry.WithAttributes(span,
  58. telemetry.AttributeKV{Key: "environment-group", Value: environmentGroup.Name},
  59. telemetry.AttributeKV{Key: "target-namespace", Value: namespace},
  60. )
  61. // var configMapName string
  62. configMapName := fmt.Sprintf("%s.%d", environmentGroup.Name, environmentGroup.Version)
  63. if environmentGroup.Name == "" {
  64. return configMapName, telemetry.Error(ctx, span, nil, "environment group name cannot be empty")
  65. }
  66. if environmentGroup.Version == 0 {
  67. return configMapName, telemetry.Error(ctx, span, nil, "environment group version cannot be empty")
  68. }
  69. if namespace == "" {
  70. return configMapName, telemetry.Error(ctx, span, nil, "target namespace cannot be empty")
  71. }
  72. _, err := a.Clientset.CoreV1().Namespaces().Get(ctx, namespace, metav1.GetOptions{})
  73. if err != nil {
  74. if !k8serror.IsNotFound(err) {
  75. return configMapName, telemetry.Error(ctx, span, err, "unable to check if target namespace exists")
  76. }
  77. _, err = a.Clientset.CoreV1().Namespaces().Create(ctx, &v1.Namespace{ObjectMeta: metav1.ObjectMeta{Name: namespace}}, metav1.CreateOptions{})
  78. if err != nil {
  79. return configMapName, telemetry.Error(ctx, span, err, "unable to create new target namespace")
  80. }
  81. }
  82. telemetry.WithAttributes(span, telemetry.AttributeKV{Key: "environment-group-namespace", Value: namespace})
  83. err = createVersionedEnvironmentGroupInNamespace(ctx, a, environmentGroup, namespace)
  84. if err != nil {
  85. return configMapName, telemetry.Error(ctx, span, err, "error creating environment group clone in target namespace")
  86. }
  87. return configMapName, nil
  88. }
  89. // 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
  90. func createVersionedEnvironmentGroupInNamespace(ctx context.Context, a *kubernetes.Agent, environmentGroup EnvironmentGroup, targetNamespace string) error {
  91. ctx, span := telemetry.NewSpan(ctx, "create-environment-group-on-cluster")
  92. defer span.End()
  93. configMap := v1.ConfigMap{
  94. ObjectMeta: metav1.ObjectMeta{
  95. Name: fmt.Sprintf("%s.%d", environmentGroup.Name, environmentGroup.Version),
  96. Namespace: targetNamespace,
  97. Labels: map[string]string{
  98. LabelKey_EnvironmentGroupName: environmentGroup.Name,
  99. LabelKey_EnvironmentGroupVersion: strconv.Itoa(environmentGroup.Version),
  100. },
  101. },
  102. Data: environmentGroup.Variables,
  103. }
  104. err := createConfigMapWithVersion(ctx, a, configMap, environmentGroup.Version)
  105. if err != nil {
  106. return telemetry.Error(ctx, span, err, "unable to create new environment group variables version")
  107. }
  108. secret := v1.Secret{
  109. ObjectMeta: metav1.ObjectMeta{
  110. Name: fmt.Sprintf("%s.%d", environmentGroup.Name, environmentGroup.Version),
  111. Namespace: targetNamespace,
  112. Labels: map[string]string{
  113. LabelKey_EnvironmentGroupName: environmentGroup.Name,
  114. LabelKey_EnvironmentGroupVersion: strconv.Itoa(environmentGroup.Version),
  115. },
  116. },
  117. Data: environmentGroup.SecretVariables,
  118. }
  119. err = createSecretWithVersion(ctx, a, secret, environmentGroup.Version)
  120. if err != nil {
  121. return telemetry.Error(ctx, span, err, "unable to create new environment group secret variables version")
  122. }
  123. return nil
  124. }
  125. func createConfigMapWithVersion(ctx context.Context, a *kubernetes.Agent, configMap v1.ConfigMap, version int) error {
  126. ctx, span := telemetry.NewSpan(ctx, "create-environment-group-configmap")
  127. defer span.End()
  128. telemetry.WithAttributes(span,
  129. telemetry.AttributeKV{Key: "configmap-label", Value: configMap.Labels[LabelKey_EnvironmentGroupName]},
  130. telemetry.AttributeKV{Key: "configmap-version", Value: configMap.Labels[LabelKey_EnvironmentGroupVersion]},
  131. telemetry.AttributeKV{Key: "configmap-name", Value: configMap.Name},
  132. telemetry.AttributeKV{Key: "configmap-namespace", Value: configMap.Namespace},
  133. )
  134. _, err := a.Clientset.CoreV1().ConfigMaps(configMap.Namespace).Create(ctx, &configMap, metav1.CreateOptions{})
  135. if err != nil {
  136. return telemetry.Error(ctx, span, err, "unable to create environment group configmap")
  137. }
  138. return nil
  139. }
  140. func createSecretWithVersion(ctx context.Context, a *kubernetes.Agent, secret v1.Secret, version int) error {
  141. ctx, span := telemetry.NewSpan(ctx, "create-environment-group-secret")
  142. defer span.End()
  143. telemetry.WithAttributes(span,
  144. telemetry.AttributeKV{Key: "secret-label", Value: secret.Labels[LabelKey_EnvironmentGroupName]},
  145. telemetry.AttributeKV{Key: "secret-version", Value: secret.Labels[LabelKey_EnvironmentGroupVersion]},
  146. telemetry.AttributeKV{Key: "secret-name", Value: secret.Name},
  147. telemetry.AttributeKV{Key: "secret-namespace", Value: secret.Namespace},
  148. )
  149. _, err := a.Clientset.CoreV1().Secrets(secret.Namespace).Create(ctx, &secret, metav1.CreateOptions{})
  150. if err != nil {
  151. return telemetry.Error(ctx, span, err, "unable to create environment group secret")
  152. }
  153. return nil
  154. }