Skip to content

Commit

Permalink
CLOUDP-188104: Deployment Resource Tagging (#1041)
Browse files Browse the repository at this point in the history
Resource tagging feature
  • Loading branch information
cveticm committed Aug 24, 2023
1 parent 1985c85 commit df7db35
Show file tree
Hide file tree
Showing 11 changed files with 352 additions and 13 deletions.
66 changes: 66 additions & 0 deletions config/crd/bases/atlas.mongodb.com_atlasdeployments.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -231,6 +231,28 @@ spec:
type: array
rootCertType:
type: string
tags:
description: Key-value pairs for resource tagging.
items:
description: TagSpec holds a key-value pair for resource tagging
on this deployment.
properties:
key:
maxLength: 255
minLength: 1
pattern: ^[a-zA-Z0-9][a-zA-Z0-9 @_.+`;`-]*$
type: string
value:
maxLength: 255
minLength: 1
pattern: ^[a-zA-Z0-9][a-zA-Z0-9@_.+`;`-]*$
type: string
required:
- key
- value
type: object
maxItems: 50
type: array
versionReleaseSystem:
type: string
type: object
Expand Down Expand Up @@ -574,6 +596,28 @@ spec:
type: string
type: object
type: array
tags:
description: Key-value pairs for resource tagging.
items:
description: TagSpec holds a key-value pair for resource tagging
on this deployment.
properties:
key:
maxLength: 255
minLength: 1
pattern: ^[a-zA-Z0-9][a-zA-Z0-9 @_.+`;`-]*$
type: string
value:
maxLength: 255
minLength: 1
pattern: ^[a-zA-Z0-9][a-zA-Z0-9@_.+`;`-]*$
type: string
required:
- key
- value
type: object
maxItems: 50
type: array
required:
- name
- providerSettings
Expand Down Expand Up @@ -747,6 +791,28 @@ spec:
required:
- providerName
type: object
tags:
description: Key-value pairs for resource tagging.
items:
description: TagSpec holds a key-value pair for resource tagging
on this deployment.
properties:
key:
maxLength: 255
minLength: 1
pattern: ^[a-zA-Z0-9][a-zA-Z0-9 @_.+`;`-]*$
type: string
value:
maxLength: 255
minLength: 1
pattern: ^[a-zA-Z0-9][a-zA-Z0-9@_.+`;`-]*$
type: string
required:
- key
- value
type: object
maxItems: 50
type: array
required:
- name
- providerSettings
Expand Down
1 change: 1 addition & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -322,6 +322,7 @@ github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
github.com/onsi/ginkgo/v2 v2.11.0 h1:WgqUCUt/lT6yXoQ8Wef0fsNn5cAuMK7+KT9UFRz2tcU=
github.com/onsi/ginkgo/v2 v2.11.0/go.mod h1:ZhrRA5XmEE3x3rhlzamx/JJvujdZoJ2uvgI7kR0iZvM=
github.com/onsi/gomega v1.27.10 h1:naR28SdDFlqrG6kScpT8VWpu1xWY5nJRCF3XaYyBjhI=
Expand Down
40 changes: 32 additions & 8 deletions pkg/api/v1/atlasdeployment_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,11 @@ type DeploymentSpec struct {
// +kubebuilder:validation:Pattern:=^[a-zA-Z0-9][a-zA-Z0-9-]*$
Name string `json:"name"`

// Key-value pairs for resource tagging.
// +kubebuilder:validation:MaxItems=50
// +optional
Tags []*TagSpec `json:"tags,omitempty"`

// Positive integer that specifies the number of shards to deploy for a sharded deployment.
// The parameter is required if replicationSpecs are configured
// +kubebuilder:validation:Minimum=1
Expand Down Expand Up @@ -163,12 +168,16 @@ type AdvancedDeploymentSpec struct {
// After Atlas creates the deployment, you can't change its name.
// Can only contain ASCII letters, numbers, and hyphens.
// +kubebuilder:validation:Pattern:=^[a-zA-Z0-9][a-zA-Z0-9-]*$
Name string `json:"name,omitempty"`
Paused *bool `json:"paused,omitempty"`
PitEnabled *bool `json:"pitEnabled,omitempty"`
ReplicationSpecs []*AdvancedReplicationSpec `json:"replicationSpecs,omitempty"`
RootCertType string `json:"rootCertType,omitempty"`
VersionReleaseSystem string `json:"versionReleaseSystem,omitempty"`
Name string `json:"name,omitempty"`
Paused *bool `json:"paused,omitempty"`
PitEnabled *bool `json:"pitEnabled,omitempty"`
ReplicationSpecs []*AdvancedReplicationSpec `json:"replicationSpecs,omitempty"`
RootCertType string `json:"rootCertType,omitempty"`
// Key-value pairs for resource tagging.
// +kubebuilder:validation:MaxItems=50
// +optional
Tags []*TagSpec `json:"tags,omitempty"`
VersionReleaseSystem string `json:"versionReleaseSystem,omitempty"`
// +optional
CustomZoneMapping []CustomZoneMapping `json:"customZoneMapping,omitempty"`
// +optional
Expand Down Expand Up @@ -205,9 +214,12 @@ type ServerlessSpec struct {
// +kubebuilder:validation:Pattern:=^[a-zA-Z0-9][a-zA-Z0-9-]*$
Name string `json:"name"`
// Configuration for the provisioned hosts on which MongoDB runs. The available options are specific to the cloud service provider.
ProviderSettings *ProviderSettingsSpec `json:"providerSettings"`

ProviderSettings *ProviderSettingsSpec `json:"providerSettings"`
PrivateEndpoints []ServerlessPrivateEndpoint `json:"privateEndpoints,omitempty"`
// Key-value pairs for resource tagging.
// +kubebuilder:validation:MaxItems=50
// +optional
Tags []*TagSpec `json:"tags,omitempty"`
}

// ToAtlas converts the ServerlessSpec to native Atlas client Cluster format.
Expand All @@ -223,6 +235,18 @@ type BiConnector struct {
ReadPreference string `json:"readPreference,omitempty"`
}

// TagSpec holds a key-value pair for resource tagging on this deployment.
type TagSpec struct {
// +kubebuilder:validation:MaxLength:=255
// +kubebuilder:validation:MinLength:=1
// +kubebuilder:validation:Pattern:=^[a-zA-Z0-9][a-zA-Z0-9 @_.+`;`-]*$
Key string `json:"key"`
// +kubebuilder:validation:MaxLength:=255
// +kubebuilder:validation:MinLength:=1
// +kubebuilder:validation:Pattern:=^[a-zA-Z0-9][a-zA-Z0-9@_.+`;`-]*$
Value string `json:"value"`
}

// ConnectionStrings configuration for applications use to connect to this deployment.
type ConnectionStrings struct {
Standard string `json:"standard,omitempty"`
Expand Down
1 change: 0 additions & 1 deletion pkg/api/v1/atlasdeployment_types_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,6 @@ func init() {
excludedClusterFieldsTheirs["createDate"] = true
excludedClusterFieldsTheirs["versionReleaseSystem"] = true
excludedClusterFieldsTheirs["serverlessBackupOptions"] = true
excludedClusterFieldsTheirs["tags"] = true
}

func TestCompatibility(t *testing.T) {
Expand Down
51 changes: 50 additions & 1 deletion pkg/api/v1/zz_generated.deepcopy.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

28 changes: 27 additions & 1 deletion pkg/controller/atlasdeployment/atlasdeployment_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -180,6 +180,13 @@ func (r *AtlasDeploymentReconciler) Reconcile(context context.Context, req ctrl.
deployment.Spec.DeploymentSpec = nil
}

if err := uniqueKey(&deployment.Spec); err != nil {
log.Errorw("failed to validate tags", "error", err)
result := workflow.Terminate(workflow.Internal, err.Error())
workflowCtx.SetConditionFromResult(status.DeploymentReadyType, result)
return result.ReconcileResult(), nil
}

handleDeployment := r.selectDeploymentHandler(deployment)
if result, _ := handleDeployment(workflowCtx, project, deployment, req); !result.IsOk() {
workflowCtx.SetConditionFromResult(status.DeploymentReadyType, result)
Expand All @@ -192,7 +199,6 @@ func (r *AtlasDeploymentReconciler) Reconcile(context context.Context, req ctrl.
return result.ReconcileResult(), nil
}
}

return workflow.OK().ReconcileResult(), nil
}

Expand Down Expand Up @@ -680,3 +686,23 @@ func advancedDeploymentMatchesSpec(log *zap.SugaredLogger, atlasSpec *mongodbatl

return d == "", nil
}

// Parse through tags and verfiy that all keys are unique. Return error otherwise.
func uniqueKey(deploymentSpec *mdbv1.AtlasDeploymentSpec) error {
store := make(map[string]string)
var arrTags []*mdbv1.TagSpec

if deploymentSpec.AdvancedDeploymentSpec != nil {
arrTags = deploymentSpec.AdvancedDeploymentSpec.Tags
} else {
arrTags = deploymentSpec.ServerlessSpec.Tags
}
for _, currTag := range arrTags {
if store[currTag.Key] == "" {
store[currTag.Key] = currTag.Value
} else {
return errors.New("duplicate keys found in tags, this is forbidden")
}
}
return nil
}
39 changes: 39 additions & 0 deletions pkg/controller/atlasdeployment/atlasdeployment_controller_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -736,3 +736,42 @@ func testBackupPolicy() *v1.AtlasBackupPolicy {
},
}
}

func TestUniqueKey(t *testing.T) {
t.Run("Test duplicates in Advanced Deployment", func(t *testing.T) {
deploymentSpec := &v1.AtlasDeploymentSpec{
AdvancedDeploymentSpec: &v1.AdvancedDeploymentSpec{
Tags: []*v1.TagSpec{{Key: "foo", Value: "true"}, {Key: "foo", Value: "false"}},
},
}
err := uniqueKey(deploymentSpec)
assert.Error(t, err)
})
t.Run("Test no duplicates in Advanced Deployment", func(t *testing.T) {
deploymentSpec := &v1.AtlasDeploymentSpec{
AdvancedDeploymentSpec: &v1.AdvancedDeploymentSpec{
Tags: []*v1.TagSpec{{Key: "foo", Value: "true"}, {Key: "bar", Value: "false"}, {Key: "foobar", Value: "false"}},
},
}
err := uniqueKey(deploymentSpec)
assert.NoError(t, err)
})
t.Run("Test duplicates in Serverless Instance", func(t *testing.T) {
deploymentSpec := &v1.AtlasDeploymentSpec{
ServerlessSpec: &v1.ServerlessSpec{
Tags: []*v1.TagSpec{{Key: "foo", Value: "true"}, {Key: "bar", Value: "false"}, {Key: "foo", Value: "false"}},
},
}
err := uniqueKey(deploymentSpec)
assert.Error(t, err)
})
t.Run("Test no duplicates in Serverless Instance", func(t *testing.T) {
deploymentSpec := &v1.AtlasDeploymentSpec{
ServerlessSpec: &v1.ServerlessSpec{
Tags: []*v1.TagSpec{{Key: "foo", Value: "true"}, {Key: "bar", Value: "false"}},
},
}
err := uniqueKey(deploymentSpec)
assert.NoError(t, err)
})
}
1 change: 1 addition & 0 deletions pkg/controller/atlasdeployment/deployment.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ func ConvertLegacyDeployment(deploymentSpec *mdbv1.AtlasDeploymentSpec) error {
Labels: legacy.Labels,
MongoDBMajorVersion: legacy.MongoDBMajorVersion,
Name: legacy.Name,
Tags: legacy.Tags,
Paused: legacy.Paused,
PitEnabled: legacy.PitEnabled,
ReplicationSpecs: replicationSpecs,
Expand Down
Loading

0 comments on commit df7db35

Please sign in to comment.