Skip to content

Commit

Permalink
feat: add alloydbomni service account validation
Browse files Browse the repository at this point in the history
  • Loading branch information
rriski committed Dec 12, 2024
1 parent 8762ce7 commit 16ce11f
Showing 21 changed files with 370 additions and 69 deletions.
5 changes: 5 additions & 0 deletions api/v1alpha1/alloydbomni_types.go
Original file line number Diff line number Diff line change
@@ -12,6 +12,11 @@ import (
type AlloyDBOmniSpec struct {
ServiceCommonSpec `json:",inline"`

// +kubebuilder:validation:Schemaless
// +kubebuilder:validation:Type=string
// Your [Google service account key](https://cloud.google.com/iam/docs/service-account-creds#key-types) in JSON format.
ServiceAccountCredentials string `json:"serviceAccountCredentials,omitempty"`

// AlloyDBOmni specific user configuration options
UserConfig *alloydbomni.AlloydbomniUserConfig `json:"userConfig,omitempty"`
}
16 changes: 14 additions & 2 deletions api/v1alpha1/alloydbomni_webhook.go
Original file line number Diff line number Diff line change
@@ -4,11 +4,14 @@ package v1alpha1

import (
"errors"
"fmt"

"k8s.io/apimachinery/pkg/runtime"
ctrl "sigs.k8s.io/controller-runtime"
logf "sigs.k8s.io/controller-runtime/pkg/log"
"sigs.k8s.io/controller-runtime/pkg/webhook"

alloydbomniUtils "github.com/aiven/aiven-operator/utils/alloydbomni"
)

// log is for logging in this package.
@@ -37,13 +40,22 @@ var _ webhook.Validator = &AlloyDBOmni{}
func (in *AlloyDBOmni) ValidateCreate() error {
alloydbomnilog.Info("validate create", "name", in.Name)

return in.Spec.Validate()
if err := alloydbomniUtils.ValidateServiceAccountCredentials(in.Spec.ServiceAccountCredentials); err != nil {
return fmt.Errorf("invalid serviceAccountCredentials: %w", err)
}

return nil
}

// ValidateUpdate implements webhook.Validator so a webhook will be registered for the type
func (in *AlloyDBOmni) ValidateUpdate(old runtime.Object) error {
alloydbomnilog.Info("validate update", "name", in.Name)
return in.Spec.Validate()

if err := alloydbomniUtils.ValidateServiceAccountCredentials(in.Spec.ServiceAccountCredentials); err != nil {
return fmt.Errorf("invalid serviceAccountCredentials: %w", err)
}

return nil
}

// ValidateDelete implements webhook.Validator so a webhook will be registered for the type
Original file line number Diff line number Diff line change
@@ -170,6 +170,11 @@ spec:
description: Identifier of the VPC the service should be in, if any.
maxLength: 36
type: string
serviceAccountCredentials:
description:
Your [Google service account key](https://cloud.google.com/iam/docs/service-account-creds#key-types)
in JSON format.
type: string
serviceIntegrations:
description:
Service integrations to specify when creating a service.
5 changes: 5 additions & 0 deletions config/crd/bases/aiven.io_alloydbomnis.yaml
Original file line number Diff line number Diff line change
@@ -170,6 +170,11 @@ spec:
description: Identifier of the VPC the service should be in, if any.
maxLength: 36
type: string
serviceAccountCredentials:
description:
Your [Google service account key](https://cloud.google.com/iam/docs/service-account-creds#key-types)
in JSON format.
type: string
serviceIntegrations:
description:
Service integrations to specify when creating a service.
12 changes: 12 additions & 0 deletions controllers/alloydbomni_controller.go
Original file line number Diff line number Diff line change
@@ -8,6 +8,7 @@ import (

"github.com/aiven/aiven-go-client/v2"
avngen "github.com/aiven/go-client-codegen"
"github.com/aiven/go-client-codegen/handler/alloydbomni"
"github.com/aiven/go-client-codegen/handler/service"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
@@ -95,3 +96,14 @@ func (a *alloyDBOmniAdapter) getDiskSpace() string {
func (a *alloyDBOmniAdapter) performUpgradeTaskIfNeeded(ctx context.Context, avn avngen.Client, old *service.ServiceGetOut) error {
return nil
}

func (a *alloyDBOmniAdapter) createOrUpdateServiceSpecific(ctx context.Context, avnGen avngen.Client, old *service.ServiceGetOut) error {
if a.Spec.ServiceAccountCredentials == "" {
_, err := avnGen.AlloyDbOmniGoogleCloudPrivateKeyRemove(ctx, a.Spec.Project, a.Name)
return err
}

req := &alloydbomni.AlloyDbOmniGoogleCloudPrivateKeySetIn{PrivateKey: a.Spec.ServiceAccountCredentials}
_, err := avnGen.AlloyDbOmniGoogleCloudPrivateKeySet(ctx, a.Spec.Project, a.Name, req)
return err
}
4 changes: 4 additions & 0 deletions controllers/cassandra_controller.go
Original file line number Diff line number Diff line change
@@ -96,3 +96,7 @@ func (a *cassandraAdapter) getDiskSpace() string {
func (a *cassandraAdapter) performUpgradeTaskIfNeeded(ctx context.Context, avn avngen.Client, old *service.ServiceGetOut) error {
return nil
}

func (a *cassandraAdapter) createOrUpdateServiceSpecific(ctx context.Context, avn avngen.Client, old *service.ServiceGetOut) error {
return nil
}
4 changes: 4 additions & 0 deletions controllers/clickhouse_controller.go
Original file line number Diff line number Diff line change
@@ -99,3 +99,7 @@ func (a *clickhouseAdapter) getDiskSpace() string {
func (a *clickhouseAdapter) performUpgradeTaskIfNeeded(ctx context.Context, avn avngen.Client, old *service.ServiceGetOut) error {
return nil
}

func (a *clickhouseAdapter) createOrUpdateServiceSpecific(ctx context.Context, avn avngen.Client, old *service.ServiceGetOut) error {
return nil
}
4 changes: 4 additions & 0 deletions controllers/flink_controller.go
Original file line number Diff line number Diff line change
@@ -95,3 +95,7 @@ func (a *flinkAdapter) getDiskSpace() string {
func (a *flinkAdapter) performUpgradeTaskIfNeeded(ctx context.Context, avn avngen.Client, old *service.ServiceGetOut) error {
return nil
}

func (a *flinkAdapter) createOrUpdateServiceSpecific(ctx context.Context, avn avngen.Client, old *service.ServiceGetOut) error {
return nil
}
6 changes: 6 additions & 0 deletions controllers/generic_service_handler.go
Original file line number Diff line number Diff line change
@@ -129,6 +129,11 @@ func (h *genericServiceHandler) createOrUpdate(ctx context.Context, avn *aiven.C
}
}

// Call service-specific createOrUpdate if it exists
if err := o.createOrUpdateServiceSpecific(ctx, avnGen, oldService); err != nil {
return fmt.Errorf("failed to create or update service-specific: %w", err)
}

// Updates tags.
// Four scenarios: service created/updated * with/without tags
// By sending empty tags it clears existing list
@@ -271,4 +276,5 @@ type serviceAdapter interface {
getUserConfig() any
newSecret(ctx context.Context, s *service.ServiceGetOut) (*corev1.Secret, error)
performUpgradeTaskIfNeeded(ctx context.Context, avn avngen.Client, old *service.ServiceGetOut) error
createOrUpdateServiceSpecific(ctx context.Context, avnGen avngen.Client, old *service.ServiceGetOut) error
}
4 changes: 4 additions & 0 deletions controllers/grafana_controller.go
Original file line number Diff line number Diff line change
@@ -96,3 +96,7 @@ func (a *grafanaAdapter) getDiskSpace() string {
func (a *grafanaAdapter) performUpgradeTaskIfNeeded(ctx context.Context, avn avngen.Client, old *service.ServiceGetOut) error {
return nil
}

func (a *grafanaAdapter) createOrUpdateServiceSpecific(ctx context.Context, avn avngen.Client, old *service.ServiceGetOut) error {
return nil
}
4 changes: 4 additions & 0 deletions controllers/kafka_controller.go
Original file line number Diff line number Diff line change
@@ -131,3 +131,7 @@ func (a *kafkaAdapter) getDiskSpace() string {
func (a *kafkaAdapter) performUpgradeTaskIfNeeded(ctx context.Context, avn avngen.Client, old *service.ServiceGetOut) error {
return nil
}

func (a *kafkaAdapter) createOrUpdateServiceSpecific(ctx context.Context, avn avngen.Client, old *service.ServiceGetOut) error {
return nil
}
4 changes: 4 additions & 0 deletions controllers/kafkaconnect_controller.go
Original file line number Diff line number Diff line change
@@ -88,3 +88,7 @@ func (a *kafkaConnectAdapter) GetConnInfoSecretTarget() v1alpha1.ConnInfoSecretT
func (a *kafkaConnectAdapter) performUpgradeTaskIfNeeded(ctx context.Context, avn avngen.Client, old *service.ServiceGetOut) error {
return nil
}

func (a *kafkaConnectAdapter) createOrUpdateServiceSpecific(ctx context.Context, avn avngen.Client, old *service.ServiceGetOut) error {
return nil
}
4 changes: 4 additions & 0 deletions controllers/mysql_controller.go
Original file line number Diff line number Diff line change
@@ -97,3 +97,7 @@ func (a *mySQLAdapter) getDiskSpace() string {
func (a *mySQLAdapter) performUpgradeTaskIfNeeded(ctx context.Context, avn avngen.Client, old *service.ServiceGetOut) error {
return nil
}

func (a *mySQLAdapter) createOrUpdateServiceSpecific(ctx context.Context, avn avngen.Client, old *service.ServiceGetOut) error {
return nil
}
4 changes: 4 additions & 0 deletions controllers/opensearch_controller.go
Original file line number Diff line number Diff line change
@@ -101,3 +101,7 @@ func (a *opensearchAdapter) getDiskSpace() string {
func (a *opensearchAdapter) performUpgradeTaskIfNeeded(ctx context.Context, avn avngen.Client, old *service.ServiceGetOut) error {
return nil
}

func (a *opensearchAdapter) createOrUpdateServiceSpecific(ctx context.Context, avn avngen.Client, old *service.ServiceGetOut) error {
return nil
}
4 changes: 4 additions & 0 deletions controllers/postgresql_controller.go
Original file line number Diff line number Diff line change
@@ -160,3 +160,7 @@ func waitForTaskToComplete[T any](ctx context.Context, f func() (bool, *T, error
}
}
}

func (a *postgreSQLAdapter) createOrUpdateServiceSpecific(ctx context.Context, avn avngen.Client, old *service.ServiceGetOut) error {
return nil
}
4 changes: 4 additions & 0 deletions controllers/redis_controller.go
Original file line number Diff line number Diff line change
@@ -103,3 +103,7 @@ func (a *redisAdapter) getDiskSpace() string {
func (a *redisAdapter) performUpgradeTaskIfNeeded(ctx context.Context, avn avngen.Client, old *service.ServiceGetOut) error {
return nil
}

func (a *redisAdapter) createOrUpdateServiceSpecific(ctx context.Context, avn avngen.Client, old *service.ServiceGetOut) error {
return nil
}
1 change: 1 addition & 0 deletions docs/docs/api-reference/alloydbomni.md
Original file line number Diff line number Diff line change
@@ -41,6 +41,7 @@ The removal of this field does not change the value.
- [`maintenanceWindowTime`](#spec.maintenanceWindowTime-property){: name='spec.maintenanceWindowTime-property'} (string, MaxLength: 8). Time of day when maintenance operations should be performed. UTC time in HH:mm:ss format.
- [`projectVPCRef`](#spec.projectVPCRef-property){: name='spec.projectVPCRef-property'} (object). ProjectVPCRef reference to ProjectVPC resource to use its ID as ProjectVPCID automatically. See below for [nested schema](#spec.projectVPCRef).
- [`projectVpcId`](#spec.projectVpcId-property){: name='spec.projectVpcId-property'} (string, MaxLength: 36). Identifier of the VPC the service should be in, if any.
- [`serviceAccountCredentials`](#spec.serviceAccountCredentials-property){: name='spec.serviceAccountCredentials-property'} (string). Your [Google service account key](https://cloud.google.com/iam/docs/service-account-creds#key-types) in JSON format.
- [`serviceIntegrations`](#spec.serviceIntegrations-property){: name='spec.serviceIntegrations-property'} (array of objects, Immutable, MaxItems: 1). Service integrations to specify when creating a service. Not applied after initial service creation. See below for [nested schema](#spec.serviceIntegrations).
- [`tags`](#spec.tags-property){: name='spec.tags-property'} (object, AdditionalProperties: string). Tags are key-value pairs that allow you to categorize services.
- [`technicalEmails`](#spec.technicalEmails-property){: name='spec.technicalEmails-property'} (array of objects, MaxItems: 10). Defines the email addresses that will receive alerts about upcoming maintenance updates or warnings about service instability. See below for [nested schema](#spec.technicalEmails).
22 changes: 12 additions & 10 deletions generators/docs/validator.go
Original file line number Diff line number Diff line change
@@ -109,14 +109,17 @@ func newSchemaValidator(kind string, crd []byte) (schemaValidator, error) {
// If not to do so, new properties allowed on validation,
// but won't work when applied with kubectl
func patchSchema(m map[string]any) map[string]any {
if m["type"].(string) != "object" {
t, ok := m["type"].(string)
if !ok || t != "object" {
return m
}

if p, ok := m["properties"]; ok {
prop := p.(map[string]any)
for k, v := range prop {
vv := v.(map[string]any)
if p, ok := m["properties"].(map[string]any); ok {
for k, v := range p {
vv, ok := v.(map[string]any)
if !ok {
continue
}

// metadata schema is empty, replaces with a good one
if k == "metadata" && len(vv) == 1 {
@@ -133,14 +136,13 @@ func patchSchema(m map[string]any) map[string]any {
continue
}

prop[k] = patchSchema(vv)
p[k] = patchSchema(vv)
}
m["properties"] = prop
m["properties"] = p
}

if i, ok := m["items"]; ok {
items := i.(map[string]any)
m["items"] = patchSchema(items)
if i, ok := m["items"].(map[string]any); ok {
m["items"] = patchSchema(i)
}

if _, ok := m["additionalProperties"]; !ok {
Loading

0 comments on commit 16ce11f

Please sign in to comment.