Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -34,3 +34,6 @@ test/__debug_bin
automation/sandbox
automation/tests/**/*.log
*.env
kubectl
.gitignore
ndb-operator.code-workspace
Binary file added NDB_Secret_Securing_With_RBAC.pdf
Binary file not shown.
6 changes: 6 additions & 0 deletions api/v1alpha1/database_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -86,8 +86,11 @@ type Instance struct {
// Description of the database instance
Description string `json:"description"`
// Id of the cluster to provision the database on
// +optional
ClusterId string `json:"clusterId"`
// +optional
ClusterName string `json:"clusterName"`
// +optional
Profiles *Profiles `json:"profiles"`
// Name of the secret holding the credentials for the database instance (password and ssh key)
CredentialSecret string `json:"credentialSecret"`
Expand Down Expand Up @@ -118,8 +121,11 @@ type Clone struct {
// Type of parent clone
Type string `json:"type"`
// Id of the cluster to clone the database on
// +optional
ClusterId string `json:"clusterId"`
// +optional
ClusterName string `json:"clusterName"`
// +optional
Profiles *Profiles `json:"profiles"`
// Name of the secret holding the credentials for the database instance (password and ssh key)
CredentialSecret string `json:"credentialSecret"`
Expand Down
20 changes: 16 additions & 4 deletions api/v1alpha1/webhook_helpers.go
Original file line number Diff line number Diff line change
Expand Up @@ -59,8 +59,14 @@ func (v *CloningWebhookHandler) validateCreate(spec *DatabaseSpec, errors *field
*errors = append(*errors, field.Invalid(clonePath.Child("name"), clone.Name, "A valid Clone Name must be specified"))
}

if err := util.ValidateUUID(clone.ClusterId); err != nil {
*errors = append(*errors, field.Invalid(clonePath.Child("clusterId"), clone.ClusterId, "ClusterId field must be a valid UUID"))
if clone.ClusterId == "" && clone.ClusterName == "" {
*errors = append(*errors, field.Invalid(clonePath.Child("clusterName"), clone.ClusterId, "ClusterId and ClusterName field cannot be blank"))
}

if clone.ClusterId != "" {
if err := util.ValidateUUID(clone.ClusterId); err != nil {
*errors = append(*errors, field.Invalid(clonePath.Child("clusterId"), clone.ClusterId, "ClusterId field must be a valid UUID"))
}
}

if clone.CredentialSecret == "" {
Expand Down Expand Up @@ -174,8 +180,14 @@ func (v *ProvisioningWebhookHandler) validateCreate(spec *DatabaseSpec, errors *
*errors = append(*errors, field.Invalid(instancePath.Child("name"), instance.Name, "A valid Database Instance Name must be specified"))
}

if err := util.ValidateUUID(instance.ClusterId); err != nil {
*errors = append(*errors, field.Invalid(instancePath.Child("clusterId"), instance.ClusterId, "ClusterId field must be a valid UUID"))
if instance.ClusterId == "" && instance.ClusterName == "" {
*errors = append(*errors, field.Invalid(instancePath.Child("clusterName"), instance.ClusterId, "ClusterId and ClusterName field cannot be blank"))
}

if instance.ClusterId != "" {
if err := util.ValidateUUID(instance.ClusterId); err != nil {
*errors = append(*errors, field.Invalid(instancePath.Child("clusterId"), instance.ClusterId, "ClusterId field must be a valid UUID"))
}
}

if instance.Size < 10 {
Expand Down
82 changes: 52 additions & 30 deletions api/v1alpha1/webhook_suite_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -172,8 +172,19 @@ var _ = Describe("Webhook Tests", func() {
Expect(errMsg).To(ContainSubstring("ClusterId field must be a valid UUID"))
})

It("Should check for missing CredentialSecret", func() {
It("Should check for missing ClusterId and ClusterName", func() {
database := createDefaultDatabase("db3")
database.Spec.Instance.ClusterId = ""
database.Spec.Instance.ClusterName = ""

err := k8sClient.Create(context.Background(), database)
Expect(err).To(HaveOccurred())
errMsg := err.(*errors.StatusError).ErrStatus.Message
Expect(errMsg).To(ContainSubstring("ClusterId and ClusterName field cannot be blank"))
})

It("Should check for missing CredentialSecret", func() {
database := createDefaultDatabase("db4")
database.Spec.Instance.CredentialSecret = ""

err := k8sClient.Create(context.Background(), database)
Expand All @@ -183,7 +194,7 @@ var _ = Describe("Webhook Tests", func() {
})

It("Should check for size < 10'", func() {
database := createDefaultDatabase("db4")
database := createDefaultDatabase("db5")
database.Spec.Instance.Size = 1

err := k8sClient.Create(context.Background(), database)
Expand All @@ -193,7 +204,7 @@ var _ = Describe("Webhook Tests", func() {
})

It("Should check for missing Type", func() {
database := createDefaultDatabase("db5")
database := createDefaultDatabase("db6")
database.Spec.Instance.Type = ""

err := k8sClient.Create(context.Background(), database)
Expand All @@ -203,7 +214,7 @@ var _ = Describe("Webhook Tests", func() {
})

It("Should check for invalid Type'", func() {
database := createDefaultDatabase("db6")
database := createDefaultDatabase("db7")
database.Spec.Instance.Type = "invalid"

err := k8sClient.Create(context.Background(), database)
Expand All @@ -214,13 +225,13 @@ var _ = Describe("Webhook Tests", func() {

When("Profiles missing", func() {
It("Should not error out for missing Profiles: Open-source engines", func() {
database := createDefaultDatabase("db7")
database := createDefaultDatabase("db8")

err := k8sClient.Create(context.Background(), database)
Expect(err).ToNot(HaveOccurred())
})
It("Should error out for missing Profiles: Closed-source engines", func() {
database := createDefaultDatabase("db8")
database := createDefaultDatabase("db9")
database.Spec.Instance.Type = common.DATABASE_TYPE_MSSQL

err := k8sClient.Create(context.Background(), database)
Expand All @@ -232,7 +243,7 @@ var _ = Describe("Webhook Tests", func() {

When("AdditionalArguments for MYSQL specified", func() {
It("Should not error for valid MYSQL additionalArguments", func() {
database := createDefaultDatabase("db9")
database := createDefaultDatabase("db10")
database.Spec.Instance.Type = common.DATABASE_TYPE_MYSQL
database.Spec.Instance.AdditionalArguments = map[string]string{
"listener_port": "3306",
Expand All @@ -242,7 +253,7 @@ var _ = Describe("Webhook Tests", func() {
Expect(err).ToNot(HaveOccurred())
})
It("Should error out for invalid MYSQL additionalArguments", func() {
database := createDefaultDatabase("db10")
database := createDefaultDatabase("db11")
database.Spec.Instance.Type = common.DATABASE_TYPE_MYSQL
database.Spec.Instance.AdditionalArguments = map[string]string{
"invalid": "invalid",
Expand All @@ -257,7 +268,7 @@ var _ = Describe("Webhook Tests", func() {

When("AdditionalArguments for PostGres specified", func() {
It("Should not error for valid Postgres additionalArguments", func() {
database := createDefaultDatabase("db11")
database := createDefaultDatabase("db12")
database.Spec.Instance.AdditionalArguments = map[string]string{
"listener_port": "5432",
}
Expand All @@ -267,7 +278,7 @@ var _ = Describe("Webhook Tests", func() {
})

It("Should error out for invalid Postgres additionalArguments", func() {
database := createDefaultDatabase("db12")
database := createDefaultDatabase("db13")
database.Spec.Instance.AdditionalArguments = map[string]string{
"listener_port": "5432",
"invalid": "invalid",
Expand All @@ -282,7 +293,7 @@ var _ = Describe("Webhook Tests", func() {

When("AdditionalArguments for MongoDB specified", func() {
It("Should not error for valid MongoDB additionalArguments", func() {
database := createDefaultDatabase("db13")
database := createDefaultDatabase("db14")
database.Spec.Instance.Type = common.DATABASE_TYPE_MONGODB
database.Spec.Instance.AdditionalArguments = map[string]string{
"listener_port": "5432",
Expand All @@ -295,7 +306,7 @@ var _ = Describe("Webhook Tests", func() {
})

It("Should error out for invalid MongoDB additionalArguments", func() {
database := createDefaultDatabase("db14")
database := createDefaultDatabase("db15")
database.Spec.Instance.Type = common.DATABASE_TYPE_MONGODB
database.Spec.Instance.AdditionalArguments = map[string]string{
"listener_port": "5432",
Expand All @@ -312,7 +323,7 @@ var _ = Describe("Webhook Tests", func() {

When("AdditionalArguments for MSSQL specified", func() {
It("Should not error for valid MSSQL additionalArguments", func() {
database := createDefaultDatabase("db15")
database := createDefaultDatabase("db16")
database.Spec.Instance.Type = common.DATABASE_TYPE_MSSQL
database.Spec.Instance.Profiles = &Profiles{
Software: Profile{
Expand All @@ -335,7 +346,7 @@ var _ = Describe("Webhook Tests", func() {
Expect(err).ToNot(HaveOccurred())
})
It("Should error out for invalid MSSQL additionalArguments", func() {
database := createDefaultDatabase("db16")
database := createDefaultDatabase("db17")
database.Spec.Instance.Type = common.DATABASE_TYPE_MSSQL
database.Spec.Instance.AdditionalArguments = map[string]string{
"invalid": "invalid",
Expand Down Expand Up @@ -376,8 +387,19 @@ var _ = Describe("Webhook Tests", func() {
Expect(errMsg).To(ContainSubstring("ClusterId field must be a valid UUID"))
})

It("Should check for missing ClusterId and ClusterName", func() {
database := createDefaultDatabase("clone3")
database.Spec.Instance.ClusterId = ""
database.Spec.Instance.ClusterName = ""

err := k8sClient.Create(context.Background(), database)
Expect(err).To(HaveOccurred())
errMsg := err.(*errors.StatusError).ErrStatus.Message
Expect(errMsg).To(ContainSubstring("ClusterId and ClusterName field cannot be blank"))
})

It("Should check for missing CredentialSecret", func() {
clone := createDefaultClone("clone3")
clone := createDefaultClone("clone4")
clone.Spec.Clone.CredentialSecret = ""

err := k8sClient.Create(context.Background(), clone)
Expand All @@ -387,7 +409,7 @@ var _ = Describe("Webhook Tests", func() {
})

It("Should check for missing TimeZone", func() {
clone := createDefaultClone("clone4")
clone := createDefaultClone("clone5")
clone.Spec.Clone.TimeZone = ""

err := k8sClient.Create(context.Background(), clone)
Expand All @@ -397,7 +419,7 @@ var _ = Describe("Webhook Tests", func() {
})

It("Should check for missing/invalid Type", func() {
clone := createDefaultClone("clone5")
clone := createDefaultClone("clone6")
clone.Spec.Clone.Type = ""

err := k8sClient.Create(context.Background(), clone)
Expand All @@ -407,7 +429,7 @@ var _ = Describe("Webhook Tests", func() {
})

It("Should check for sourceDatabaseId", func() {
clone := createDefaultClone("clone6")
clone := createDefaultClone("clone7")
clone.Spec.Clone.SourceDatabaseId = ""

err := k8sClient.Create(context.Background(), clone)
Expand All @@ -417,7 +439,7 @@ var _ = Describe("Webhook Tests", func() {
})

It("Should check for snapshotId", func() {
clone := createDefaultClone("clone7")
clone := createDefaultClone("clone8")
clone.Spec.Clone.SnapshotId = ""

err := k8sClient.Create(context.Background(), clone)
Expand All @@ -427,7 +449,7 @@ var _ = Describe("Webhook Tests", func() {
})

It("Should check for invalid Type'", func() {
clone := createDefaultClone("clone8")
clone := createDefaultClone("clone9")
clone.Spec.Clone.Type = "invalid"

err := k8sClient.Create(context.Background(), clone)
Expand All @@ -438,13 +460,13 @@ var _ = Describe("Webhook Tests", func() {

When("Profiles missing", func() {
It("Should not error out for missing Profiles: Open-source engines", func() {
clone := createDefaultClone("clone9")
clone := createDefaultClone("clone10")

err := k8sClient.Create(context.Background(), clone)
Expect(err).ToNot(HaveOccurred())
})
It("Should error out for missing Profiles: Closed-source engines", func() {
clone := createDefaultClone("clone10")
clone := createDefaultClone("clone11")
clone.Spec.Clone.Type = common.DATABASE_TYPE_MSSQL

err := k8sClient.Create(context.Background(), clone)
Expand All @@ -456,7 +478,7 @@ var _ = Describe("Webhook Tests", func() {

When("AdditionalArguments for MYSQL specified", func() {
It("Should not error for valid MYSQL additionalArguments", func() {
clone := createDefaultClone("clone11")
clone := createDefaultClone("clone12")
clone.Spec.Clone.Type = common.DATABASE_TYPE_MYSQL
clone.Spec.Clone.AdditionalArguments = map[string]string{
"expireInDays": "30",
Expand All @@ -471,7 +493,7 @@ var _ = Describe("Webhook Tests", func() {
Expect(err).ToNot(HaveOccurred())
})
It("Should error out for invalid MYSQL additionalArguments", func() {
clone := createDefaultClone("clone12")
clone := createDefaultClone("clone13")
clone.Spec.Clone.Type = common.DATABASE_TYPE_MYSQL
clone.Spec.Clone.AdditionalArguments = map[string]string{
"invalid": "invalid",
Expand All @@ -486,7 +508,7 @@ var _ = Describe("Webhook Tests", func() {

When("AdditionalArguments for PostGres specified", func() {
It("Should not error for valid Postgres additionalArguments", func() {
clone := createDefaultClone("clone13")
clone := createDefaultClone("clone14")
clone.Spec.Clone.AdditionalArguments = map[string]string{
"expireInDays": "30",
"expiryDateTimezone": common.TIMEZONE_UTC,
Expand All @@ -501,7 +523,7 @@ var _ = Describe("Webhook Tests", func() {
})

It("Should error out for invalid Postgres additionalArguments", func() {
clone := createDefaultClone("clone14")
clone := createDefaultClone("clone15")
clone.Spec.Clone.AdditionalArguments = map[string]string{
"invalid": "invalid",
}
Expand All @@ -515,7 +537,7 @@ var _ = Describe("Webhook Tests", func() {

When("AdditionalArguments for MongoDB specified", func() {
It("Should not error for valid MongoDB additionalArguments", func() {
clone := createDefaultClone("clone15")
clone := createDefaultClone("clone16")
clone.Spec.Clone.Type = common.DATABASE_TYPE_MONGODB
clone.Spec.Clone.AdditionalArguments = map[string]string{
"expireInDays": "30",
Expand All @@ -531,7 +553,7 @@ var _ = Describe("Webhook Tests", func() {
})

It("Should error out for invalid MongoDB additionalArguments", func() {
clone := createDefaultClone("clone16")
clone := createDefaultClone("clone17")
clone.Spec.Clone.Type = common.DATABASE_TYPE_MONGODB
clone.Spec.Clone.AdditionalArguments = map[string]string{
"invalid": "invalid",
Expand All @@ -546,7 +568,7 @@ var _ = Describe("Webhook Tests", func() {

When("AdditionalArguments for MSSQL specified", func() {
It("Should not error for valid MSSQL additionalArguments", func() {
clone := createDefaultClone("clone17")
clone := createDefaultClone("clone18")
clone.Spec.Clone.Type = common.DATABASE_TYPE_MSSQL
clone.Spec.Clone.Profiles = &Profiles{
Software: Profile{
Expand Down Expand Up @@ -578,7 +600,7 @@ var _ = Describe("Webhook Tests", func() {
Expect(err).ToNot(HaveOccurred())
})
It("Should error out for invalid MSSQL additionalArguments", func() {
clone := createDefaultClone("clone18")
clone := createDefaultClone("clone19")
clone.Spec.Clone.Type = common.DATABASE_TYPE_MSSQL
clone.Spec.Clone.AdditionalArguments = map[string]string{
"invalid": "invalid",
Expand Down
6 changes: 4 additions & 2 deletions config/crd/bases/ndb.nutanix.com_databases.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,8 @@ spec:
clusterId:
description: Id of the cluster to clone the database on
type: string
clusterName:
type: string
credentialSecret:
description: Name of the secret holding the credentials for the
database instance (password and ssh key)
Expand Down Expand Up @@ -119,7 +121,6 @@ spec:
description: Type of parent clone
type: string
required:
- clusterId
- credentialSecret
- name
- snapshotId
Expand All @@ -137,6 +138,8 @@ spec:
clusterId:
description: Id of the cluster to provision the database on
type: string
clusterName:
type: string
credentialSecret:
description: Name of the secret holding the credentials for the
database instance (password and ssh key)
Expand Down Expand Up @@ -233,7 +236,6 @@ spec:
type:
type: string
required:
- clusterId
- credentialSecret
- name
- size
Expand Down
Loading