-
Notifications
You must be signed in to change notification settings - Fork 20
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
7 changed files
with
392 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,70 @@ | ||
// Copyright (c) 2024 Aiven, Helsinki, Finland. https://aiven.io/ | ||
|
||
package v1alpha1 | ||
|
||
import ( | ||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" | ||
|
||
alloydbomni "github.com/aiven/aiven-operator/api/v1alpha1/userconfig/service/alloydbomni" | ||
) | ||
|
||
// AlloyDBOmniSpec defines the desired state of AlloyDB Omni instance | ||
type AlloyDBOmniSpec struct { | ||
ServiceCommonSpec `json:",inline"` | ||
|
||
// AlloyDBOmni specific user configuration options | ||
UserConfig *alloydbomni.AlloydbomniUserConfig `json:"userConfig,omitempty"` | ||
} | ||
|
||
// +kubebuilder:object:root=true | ||
// +kubebuilder:subresource:status | ||
|
||
// AlloyDBOmni is the Schema for the alloydbomni API. | ||
// Info "Exposes secret keys": `ALLOYDBOMNI_HOST`, `ALLOYDBOMNI_PORT`, `ALLOYDBOMNI_DATABASE`, `ALLOYDBOMNI_USER`, `ALLOYDBOMNI_PASSWORD`, `ALLOYDBOMNI_SSLMODE`, `ALLOYDBOMNI_DATABASE_URI` | ||
// +kubebuilder:subresource:status | ||
// +kubebuilder:printcolumn:name="Project",type="string",JSONPath=".spec.project" | ||
// +kubebuilder:printcolumn:name="Region",type="string",JSONPath=".spec.cloudName" | ||
// +kubebuilder:printcolumn:name="Plan",type="string",JSONPath=".spec.plan" | ||
// +kubebuilder:printcolumn:name="State",type="string",JSONPath=".status.state" | ||
type AlloyDBOmni struct { | ||
metav1.TypeMeta `json:",inline"` | ||
metav1.ObjectMeta `json:"metadata,omitempty"` | ||
|
||
Spec AlloyDBOmniSpec `json:"spec,omitempty"` | ||
Status ServiceStatus `json:"status,omitempty"` | ||
} | ||
|
||
var _ AivenManagedObject = &AlloyDBOmni{} | ||
|
||
func (in *AlloyDBOmni) NoSecret() bool { | ||
return in.Spec.ConnInfoSecretTargetDisabled != nil && *in.Spec.ConnInfoSecretTargetDisabled | ||
} | ||
|
||
func (in *AlloyDBOmni) AuthSecretRef() *AuthSecretReference { | ||
return in.Spec.AuthSecretRef | ||
} | ||
|
||
func (in *AlloyDBOmni) Conditions() *[]metav1.Condition { | ||
return &in.Status.Conditions | ||
} | ||
|
||
func (in *AlloyDBOmni) GetRefs() []*ResourceReferenceObject { | ||
return in.Spec.GetRefs(in.GetNamespace()) | ||
} | ||
|
||
func (in *AlloyDBOmni) GetConnInfoSecretTarget() ConnInfoSecretTarget { | ||
return in.Spec.ConnInfoSecretTarget | ||
} | ||
|
||
// +kubebuilder:object:root=true | ||
|
||
// AlloyDBOmniList contains a list of AlloyDBOmni instances | ||
type AlloyDBOmniList struct { | ||
metav1.TypeMeta `json:",inline"` | ||
metav1.ListMeta `json:"metadata,omitempty"` | ||
Items []AlloyDBOmni `json:"items"` | ||
} | ||
|
||
func init() { | ||
SchemeBuilder.Register(&AlloyDBOmni{}, &AlloyDBOmniList{}) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,62 @@ | ||
// Copyright (c) 2024 Aiven, Helsinki, Finland. https://aiven.io/ | ||
|
||
package v1alpha1 | ||
|
||
import ( | ||
"errors" | ||
|
||
"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" | ||
) | ||
|
||
// log is for logging in this package. | ||
var alloydbomnilog = logf.Log.WithName("alloydbomni-resource") | ||
|
||
func (in *AlloyDBOmni) SetupWebhookWithManager(mgr ctrl.Manager) error { | ||
return ctrl.NewWebhookManagedBy(mgr). | ||
For(in). | ||
Complete() | ||
} | ||
|
||
//+kubebuilder:webhook:path=/mutate-aiven-io-v1alpha1-alloydbomni,mutating=true,failurePolicy=fail,groups=aiven.io,resources=alloydbomnis,verbs=create;update,versions=v1alpha1,name=mpg.kb.io,sideEffects=none,admissionReviewVersions=v1 | ||
|
||
var _ webhook.Defaulter = &AlloyDBOmni{} | ||
|
||
// Default implements webhook.Defaulter so a webhook will be registered for the type | ||
func (in *AlloyDBOmni) Default() { | ||
alloydbomnilog.Info("default", "name", in.Name) | ||
} | ||
|
||
//+kubebuilder:webhook:verbs=create;update;delete,path=/validate-aiven-io-v1alpha1-alloydbomni,mutating=false,failurePolicy=fail,groups=aiven.io,resources=alloydbomnis,versions=v1alpha1,name=vpg.kb.io,sideEffects=none,admissionReviewVersions=v1 | ||
|
||
var _ webhook.Validator = &AlloyDBOmni{} | ||
|
||
// ValidateCreate implements webhook.Validator so a webhook will be registered for the type | ||
func (in *AlloyDBOmni) ValidateCreate() error { | ||
alloydbomnilog.Info("validate create", "name", in.Name) | ||
|
||
return in.Spec.Validate() | ||
} | ||
|
||
// 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() | ||
} | ||
|
||
// ValidateDelete implements webhook.Validator so a webhook will be registered for the type | ||
func (in *AlloyDBOmni) ValidateDelete() error { | ||
alloydbomnilog.Info("validate delete", "name", in.Name) | ||
|
||
if in.Spec.TerminationProtection != nil && *in.Spec.TerminationProtection { | ||
return errors.New("cannot delete AlloyDBOmni service, termination protection is on") | ||
} | ||
|
||
if in.Spec.ProjectVPCID != "" && in.Spec.ProjectVPCRef != nil { | ||
return errors.New("cannot use both projectVpcId and projectVPCRef") | ||
} | ||
|
||
return nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,136 @@ | ||
// Copyright (c) 2024 Aiven, Helsinki, Finland. https://aiven.io/ | ||
|
||
package controllers | ||
|
||
import ( | ||
"context" | ||
"fmt" | ||
|
||
"github.com/aiven/aiven-go-client/v2" | ||
avngen "github.com/aiven/go-client-codegen" | ||
"github.com/aiven/go-client-codegen/handler/service" | ||
corev1 "k8s.io/api/core/v1" | ||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" | ||
ctrl "sigs.k8s.io/controller-runtime" | ||
"sigs.k8s.io/controller-runtime/pkg/client" | ||
|
||
"github.com/aiven/aiven-operator/api/v1alpha1" | ||
alloydbomniuserconfig "github.com/aiven/aiven-operator/api/v1alpha1/userconfig/service/alloydbomni" | ||
) | ||
|
||
// AlloyDBOmniReconciler reconciles a AlloyDBOmni object | ||
type AlloyDBOmniReconciler struct { | ||
Controller | ||
} | ||
|
||
func newAlloyDBOmniReconciler(c Controller) reconcilerType { | ||
return &AlloyDBOmniReconciler{Controller: c} | ||
} | ||
|
||
//+kubebuilder:rbac:groups=aiven.io,resources=alloydbomnis,verbs=get;list;watch;create;update;patch;delete | ||
//+kubebuilder:rbac:groups=aiven.io,resources=alloydbomnis/status,verbs=get;update;patch | ||
//+kubebuilder:rbac:groups=aiven.io,resources=alloydbomnis/finalizers,verbs=get;create;update | ||
|
||
func (r *AlloyDBOmniReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { | ||
return r.reconcileInstance(ctx, req, newGenericServiceHandler(newAlloyDBOmniAdapter), &v1alpha1.AlloyDBOmni{}) | ||
} | ||
|
||
func (r *AlloyDBOmniReconciler) SetupWithManager(mgr ctrl.Manager) error { | ||
return ctrl.NewControllerManagedBy(mgr). | ||
For(&v1alpha1.AlloyDBOmni{}). | ||
Owns(&corev1.Secret{}). | ||
Complete(r) | ||
} | ||
|
||
func newAlloyDBOmniAdapter(_ *aiven.Client, object client.Object) (serviceAdapter, error) { | ||
adbo, ok := object.(*v1alpha1.AlloyDBOmni) | ||
if !ok { | ||
return nil, fmt.Errorf("object is not of type v1alpha1.AlloyDBOmni") | ||
} | ||
return &alloyDBOmniAdapter{adbo}, nil | ||
} | ||
|
||
// alloyDBOmniAdapter handles an Aiven AlloyDBOmni service | ||
type alloyDBOmniAdapter struct { | ||
*v1alpha1.AlloyDBOmni | ||
} | ||
|
||
func (a *alloyDBOmniAdapter) getObjectMeta() *metav1.ObjectMeta { | ||
return &a.ObjectMeta | ||
} | ||
|
||
func (a *alloyDBOmniAdapter) getServiceStatus() *v1alpha1.ServiceStatus { | ||
return &a.Status | ||
} | ||
|
||
func (a *alloyDBOmniAdapter) getServiceCommonSpec() *v1alpha1.ServiceCommonSpec { | ||
return &a.Spec.ServiceCommonSpec | ||
} | ||
|
||
func (a *alloyDBOmniAdapter) getUserConfig() any { | ||
return a.Spec.UserConfig | ||
} | ||
|
||
func (a *alloyDBOmniAdapter) newSecret(ctx context.Context, s *service.ServiceGetOut) (*corev1.Secret, error) { | ||
prefix := getSecretPrefix(a) | ||
stringData := map[string]string{ | ||
prefix + "HOST": s.ServiceUriParams["host"], | ||
prefix + "PORT": s.ServiceUriParams["port"], | ||
prefix + "DATABASE": s.ServiceUriParams["dbname"], | ||
prefix + "USER": s.ServiceUriParams["user"], | ||
prefix + "PASSWORD": s.ServiceUriParams["password"], | ||
prefix + "SSLMODE": s.ServiceUriParams["sslmode"], | ||
prefix + "DATABASE_URI": s.ServiceUri, | ||
} | ||
|
||
return newSecret(a, stringData, false), nil | ||
} | ||
|
||
func (a *alloyDBOmniAdapter) getServiceType() string { | ||
return "alloydbomni" | ||
} | ||
|
||
func (a *alloyDBOmniAdapter) getDiskSpace() string { | ||
return a.Spec.DiskSpace | ||
} | ||
|
||
func (a *alloyDBOmniAdapter) performUpgradeTaskIfNeeded(ctx context.Context, avn avngen.Client, old *service.ServiceGetOut) error { | ||
var currentVersion string = old.UserConfig["alloydbomni_version"].(string) | ||
targetUserConfig := a.getUserConfig().(*alloydbomniuserconfig.AlloydbomniUserConfig) | ||
if targetUserConfig == nil || targetUserConfig.PgVersion == nil { | ||
return nil | ||
} | ||
var targetVersion string = *targetUserConfig.PgVersion | ||
|
||
// No need to upgrade if alloydbomni_version hasn't changed | ||
if targetVersion == currentVersion { | ||
return nil | ||
} | ||
|
||
task, err := avn.ServiceTaskCreate(ctx, a.getServiceCommonSpec().Project, a.getObjectMeta().Name, &service.ServiceTaskCreateIn{ | ||
TargetVersion: service.TargetVersionType(targetVersion), | ||
TaskType: service.TaskTypeUpgradeCheck, | ||
}) | ||
if err != nil { | ||
return fmt.Errorf("cannot create AlloyDB Omni upgrade check task: %q", err) | ||
} | ||
|
||
finalTaskResult, err := waitForTaskToComplete(ctx, func() (bool, *service.ServiceTaskGetOut, error) { | ||
t, getErr := avn.ServiceTaskGet(ctx, a.getServiceCommonSpec().Project, a.getObjectMeta().Name, task.TaskId) | ||
if getErr != nil { | ||
return true, nil, fmt.Errorf("error fetching service task %s: %q", t.TaskId, getErr) | ||
} | ||
|
||
if !t.Success { | ||
return false, nil, nil | ||
} | ||
return true, t, nil | ||
}) | ||
if err != nil { | ||
return err | ||
} | ||
if !finalTaskResult.Success { | ||
return fmt.Errorf("AlloyDB Omni service upgrade check error, version upgrade from %s to %s, result: %s", currentVersion, targetVersion, finalTaskResult.Result) | ||
} | ||
return nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.