Skip to content

Commit

Permalink
feat(service): add service technical email support
Browse files Browse the repository at this point in the history
  • Loading branch information
rriski committed Jan 10, 2024
1 parent 27aab44 commit 88900ca
Show file tree
Hide file tree
Showing 4 changed files with 94 additions and 4 deletions.
10 changes: 10 additions & 0 deletions api/v1alpha1/common.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,12 @@ type ServiceStatus struct {
State string `json:"state,omitempty"`
}

type ServiceTechEmail struct {
// +kubebuilder:validation:Format="^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}$"
// Email address.
Email string `json:"email"`
}

type ServiceCommonSpec struct {
// +kubebuilder:validation:MaxLength=63
// +kubebuilder:validation:Format="^[a-zA-Z0-9_-]*$"
Expand Down Expand Up @@ -87,6 +93,10 @@ type ServiceCommonSpec struct {
// +kubebuilder:validation:XValidation:rule="self == oldSelf",message="Value is immutable"
// Service integrations to specify when creating a service. Not applied after initial service creation
ServiceIntegrations []*ServiceIntegrationItem `json:"serviceIntegrations,omitempty"`

// +kubebuilder:validation:MaxItems=10
// Defines the email addresses that will receive alerts about upcoming maintenance updates or warnings about service instability.
TechnicalEmails []ServiceTechEmail `json:"technicalEmails,omitempty"`
}

// Validate runs complex validation on ServiceCommonSpec
Expand Down
20 changes: 20 additions & 0 deletions api/v1alpha1/zz_generated.deepcopy.go

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

7 changes: 7 additions & 0 deletions controllers/generic_service_handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,11 @@ func (h *genericServiceHandler) createOrUpdate(ctx context.Context, avn *aiven.C
return fmt.Errorf("failed to fetch service: %w", err)
}

technicalEmails := make([]aiven.ContactEmail, 0)
for _, email := range spec.TechnicalEmails {
technicalEmails = append(technicalEmails, aiven.ContactEmail(email))
}

// Creates if not exists or updates existing service
var reason string
if !exists {
Expand All @@ -68,6 +73,7 @@ func (h *genericServiceHandler) createOrUpdate(ctx context.Context, avn *aiven.C
ServiceType: o.getServiceType(),
TerminationProtection: fromAnyPointer(spec.TerminationProtection),
UserConfig: userConfig,
TechnicalEmails: &technicalEmails,
}

for _, s := range spec.ServiceIntegrations {
Expand Down Expand Up @@ -98,6 +104,7 @@ func (h *genericServiceHandler) createOrUpdate(ctx context.Context, avn *aiven.C
ProjectVPCID: toOptionalStringPointer(projectVPCID),
TerminationProtection: fromAnyPointer(spec.TerminationProtection),
UserConfig: userConfig,
TechnicalEmails: &technicalEmails,
}
_, err = avn.Services.Update(ctx, spec.Project, ometa.Name, req)
if err != nil {
Expand Down
61 changes: 57 additions & 4 deletions tests/mysql_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@ import (
mysqluserconfig "github.com/aiven/aiven-operator/api/v1alpha1/userconfig/service/mysql"
)

func getMySQLYaml(project, name, cloudName string) string {
return fmt.Sprintf(`
func getMySQLYaml(project, name, cloudName string, includeTechnicalEmails bool) string {
baseYaml := `
apiVersion: aiven.io/v1alpha1
kind: MySQL
metadata:
Expand All @@ -39,8 +39,16 @@ spec:
- network: 0.0.0.0/32
description: bar
- network: 10.20.0.0/16
`

`, project, name, cloudName)
if includeTechnicalEmails {
baseYaml += `
technicalEmails:
- email: "[email protected]"
`
}

return fmt.Sprintf(baseYaml, project, name, cloudName)
}

func TestMySQL(t *testing.T) {
Expand All @@ -50,7 +58,7 @@ func TestMySQL(t *testing.T) {
// GIVEN
ctx := context.Background()
name := randName("mysql")
yml := getMySQLYaml(testProject, name, testPrimaryCloudName)
yml := getMySQLYaml(testProject, name, testPrimaryCloudName, false)
s := NewSession(k8sClient, avnClient, testProject)

// Cleans test afterwards
Expand Down Expand Up @@ -112,3 +120,48 @@ func TestMySQL(t *testing.T) {
assert.NotEmpty(t, secret.Data["MYSQL_URI"])
assert.NotEmpty(t, secret.Data["MYSQL_REPLICA_URI"]) // business-4 has replica
}

func TestMySQLTechnicalEmails(t *testing.T) {
t.Parallel()
defer recoverPanic(t)

// GIVEN
ctx := context.Background()
name := randName("mysql")
yml := getMySQLYaml(testProject, name, testPrimaryCloudName, true)
s := NewSession(k8sClient, avnClient, testProject)

// Cleans test afterwards
defer s.Destroy()

// WHEN
// Applies given manifest
require.NoError(t, s.Apply(yml))

// Waits kube objects
ms := new(v1alpha1.MySQL)
require.NoError(t, s.GetRunning(ms, name))

// THEN
// Technical emails are set
msAvn, err := avnClient.Services.Get(ctx, testProject, name)
require.NoError(t, err)
assert.Len(t, ms.Spec.TechnicalEmails, 1)
assert.Equal(t, "[email protected]", msAvn.TechnicalEmails[0].Email)

// WHEN
// Technical emails are removed from manifest
updatedYml := getMySQLYaml(testProject, name, testPrimaryCloudName, false)

// Applies updated manifest
require.NoError(t, s.Apply(updatedYml))

// Waits kube objects
require.NoError(t, s.GetRunning(ms, name))

// THEN
// Technical emails are removed from service
msAvnUpdated, err := avnClient.Services.Get(ctx, testProject, name)
require.NoError(t, err)
assert.Empty(t, msAvnUpdated.TechnicalEmails)
}

0 comments on commit 88900ca

Please sign in to comment.