Skip to content

Commit

Permalink
WIP
Browse files Browse the repository at this point in the history
  • Loading branch information
Kidswiss committed Oct 14, 2024
1 parent cbfb45d commit 73a8130
Show file tree
Hide file tree
Showing 4 changed files with 270 additions and 9 deletions.
4 changes: 2 additions & 2 deletions apis/vshn/v1/dbaas_vshn_mariadb.go
Original file line number Diff line number Diff line change
Expand Up @@ -99,8 +99,8 @@ type VSHNMariaDBServiceSpec struct {
// ServiceLevel defines the service level of this service. Either Best Effort or Guaranteed Availability is allowed.
ServiceLevel VSHNDBaaSServiceLevel `json:"serviceLevel,omitempty"`

// +kubebuilder:default="standalone"
// +kubebuilder:validation:Enum=replication;standalone
// Access defines additional users and databases for this instance.
Access []VSHNAccess `json:"access,omitempty"`
}

// VSHNMariaDBTLSSpec contains settings to control tls traffic of a service.
Expand Down
1 change: 1 addition & 0 deletions apis/vshn/v1/dbaas_vshn_postgresql.go
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,7 @@ type VSHNPostgreSQLServiceSpec struct {
// +kubebuilder:default=false
VacuumEnabled bool `json:"vacuumEnabled,omitempty"`

// Access defines additional users and databases for this instance.
Access []VSHNAccess `json:"access,omitempty"`
}

Expand Down
260 changes: 260 additions & 0 deletions pkg/comp-functions/functions/vshnmariadb/user_management.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,260 @@
package vshnmariadb

import (
"context"
"fmt"

xpv1 "github.com/crossplane/crossplane-runtime/apis/common/v1"
xfnproto "github.com/crossplane/function-sdk-go/proto/v1beta1"
my1alpha1 "github.com/vshn/appcat/v4/apis/sql/mysql/v1alpha1"
vshnv1 "github.com/vshn/appcat/v4/apis/vshn/v1"
"github.com/vshn/appcat/v4/pkg/comp-functions/functions/common"
"github.com/vshn/appcat/v4/pkg/comp-functions/runtime"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)

func UserManagement(ctx context.Context, comp *vshnv1.VSHNMariaDB, svc *runtime.ServiceRuntime) *xfnproto.Result {

// Nothing defined, let's return early
if len(comp.Spec.Parameters.Service.Access) == 0 {
return nil
}

addProviderConfig(comp, svc)

for _, access := range comp.Spec.Parameters.Service.Access {

userPasswordRef := addUser(comp, svc, *access.User)

dbname := *access.User
if access.Database != nil {
dbname = *access.Database
}

addDatabase(comp, svc, dbname)

addGrants(comp, svc, *access.User, dbname, access.Privileges)

addConnectionDetail(comp, svc, userPasswordRef, *access.User, dbname, access.WriteConnectionSecretToReference)
}

return nil
}

func addUser(comp common.Composite, svc *runtime.ServiceRuntime, username string) string {
secretName, err := common.AddGenericSecret(comp, svc, "userpass-"+username, []string{"userpass"})
if err != nil {
svc.Log.Error(err, "cannot deploy user password secret")
svc.AddResult(runtime.NewWarningResult(fmt.Sprintf("cannot deploy user password secret: %s", err)))
}

role := &my1alpha1.User{
ObjectMeta: metav1.ObjectMeta{
Name: fmt.Sprintf("%s-%s-role", comp.GetName(), username),
Annotations: map[string]string{
"crossplane.io/external-name": username,
},
Labels: map[string]string{
runtime.ProviderConfigIgnoreLabel: "true",
},
},
Spec: my1alpha1.UserSpec{
ForProvider: my1alpha1.UserParameters{},
ResourceSpec: xpv1.ResourceSpec{
ProviderConfigReference: &xpv1.Reference{
Name: comp.GetName(),
},
},
},
}

err = svc.SetDesiredComposedResource(role, runtime.ComposedOptionProtects(comp.GetName()+"-provider-conf-credentials"), runtime.ComposedOptionProtects(secretName))
if err != nil {
svc.Log.Error(err, "cannot apply user")
svc.AddResult(runtime.NewWarningResult(fmt.Sprintf("cannot apply user: %s", err)))
}

return secretName
}

func addConnectionDetail(comp common.Composite, svc *runtime.ServiceRuntime, secretName, username, dbname string, connectionDetailRef *xpv1.SecretReference) {
userpassCD, err := svc.GetObservedComposedResourceConnectionDetails(secretName)
if err != nil {
svc.Log.Error(err, "cannot get userpassword from secret")
svc.AddResult(runtime.NewWarningResult(fmt.Sprintf("cannot get userpassword from secret: %s", err)))
}

compositeCD := svc.GetConnectionDetails()

// url := getPostgresURLCustomUser(compositeCD, string(compositeCD["MARIADB_HOST"]), username)

om := metav1.ObjectMeta{
Name: comp.GetLabels()["crossplane.io/claim-name"] + "-" + username,
Namespace: comp.GetClaimNamespace(),
}
if connectionDetailRef != nil {
om.Name = connectionDetailRef.Name
om.Namespace = connectionDetailRef.Namespace
}

userpassSecret := &corev1.Secret{
ObjectMeta: om,
Type: corev1.SecretType("connection.crossplane.io/v1alpha1"),
Data: map[string][]byte{
"MARIADB_USER": []byte(username),
"MARIADB_PASSWORD": userpassCD["userpass"],
"MARIADB_DB": []byte(dbname),
"MARIADB_HOST": compositeCD["MARIADB_HOST"],
"MARIADB_PORT": compositeCD["MARIADB_PORT"],
// "MARIADB_URL": []byte(url),
"ca.crt": compositeCD["ca.crt"],
"tls.crt": compositeCD["tls.crt"],
"tls.key": compositeCD["tls.key"],
},
}

err = svc.SetDesiredKubeObject(userpassSecret, fmt.Sprintf("%s-user-%s", comp.GetName(), username))
if err != nil {
svc.Log.Error(err, "cannot get userpassword from secret")
svc.AddResult(runtime.NewWarningResult(fmt.Sprintf("cannot get userpassword from secret: %s", err)))
}
}

func addProviderConfig(comp *vshnv1.VSHNMariaDB, svc *runtime.ServiceRuntime) {
cd := svc.GetConnectionDetails()

secret := &corev1.Secret{
ObjectMeta: metav1.ObjectMeta{
Name: "provider-conf-credentials",
Namespace: comp.GetInstanceNamespace(),
},
Data: map[string][]byte{
"username": cd["MARIADB_USER"],
"password": cd["MARIADB_PASSWORD"],
"endpoint": cd["MARIADB_HOST"],
"port": cd["MARIADB_PORT"],
},
}

err := svc.SetDesiredKubeObject(secret, comp.GetName()+"-provider-conf-credentials",
runtime.KubeOptionProtects("namespace-conditions"),
runtime.KubeOptionProtects("cluster"),
runtime.KubeOptionProtects(comp.GetName()+"-netpol"))
if err != nil {
svc.AddResult(runtime.NewWarningResult(fmt.Sprintf("cannot set credential secret for provider-sql: %s", err)))
svc.Log.Error(err, "cannot set credential secret for provider-sql")
}

tls := "preferred"
if comp.Spec.Parameters.TLS.TLSEnabled {
tls = "skip-verify"
}

config := &my1alpha1.ProviderConfig{
ObjectMeta: metav1.ObjectMeta{
Name: comp.GetName(),
},
Spec: my1alpha1.ProviderConfigSpec{
TLS: &tls,
Credentials: my1alpha1.ProviderCredentials{
Source: "MySQLConnectionSecret",
ConnectionSecretRef: &xpv1.SecretReference{
Name: "provider-conf-credentials",
Namespace: comp.GetInstanceNamespace(),
},
},
},
}

err = svc.SetDesiredKubeObject(config, comp.GetName()+"-providerconfig")
if err != nil {
svc.AddResult(runtime.NewWarningResult(fmt.Sprintf("cannot apply the provider config for provider sql: %s", err)))
svc.Log.Error(err, "cannot apply the provider config for provider sql")
}
}

// We check if the database is already specified.
// If not it will be added.
// This should handle cases where there are mutliple users pointing to the same
// database, and one is deleted, that the database is not dropped.
func addDatabase(comp common.Composite, svc *runtime.ServiceRuntime, name string) {
resname := fmt.Sprintf("%s-%s-database", comp.GetName(), name)

xdb := &my1alpha1.Database{}

// If there's a database with the same name we will just return
err := svc.GetDesiredComposedResourceByName(xdb, resname)
if err == nil {
return
}
if err != runtime.ErrNotFound {
svc.AddResult(runtime.NewWarningResult(fmt.Sprintf("cannot check if database exists: %s", err)))
svc.Log.Error(err, "cannot check if database exists")
}

xdb = &my1alpha1.Database{
ObjectMeta: metav1.ObjectMeta{
Name: resname,
Annotations: map[string]string{
"crossplane.io/external-name": name,
},
Labels: map[string]string{
runtime.ProviderConfigIgnoreLabel: "true",
},
},
Spec: my1alpha1.DatabaseSpec{
ForProvider: my1alpha1.DatabaseParameters{},
ResourceSpec: xpv1.ResourceSpec{
ProviderConfigReference: &xpv1.Reference{
Name: comp.GetName(),
},
},
},
}

err = svc.SetDesiredComposedResource(xdb, runtime.ComposedOptionProtects(comp.GetName()+"-provider-conf-credentials"))
if err != nil {
svc.AddResult(runtime.NewWarningResult(fmt.Sprintf("cannot apply database: %s", err)))
svc.Log.Error(err, "cannot apply database")
}
}

func addGrants(comp common.Composite, svc *runtime.ServiceRuntime, username, dbname string, privileges []string) {
privs := []my1alpha1.GrantPrivilege{}

if len(privileges) == 0 {
privs = append(privs, "ALL")
}

for _, priv := range privileges {
privs = append(privs, my1alpha1.GrantPrivilege(priv))
}

grant := &my1alpha1.Grant{
ObjectMeta: metav1.ObjectMeta{
Name: fmt.Sprintf("%s-%s-%s-grants", comp.GetName(), username, dbname),
Labels: map[string]string{
runtime.ProviderConfigIgnoreLabel: "true",
},
},
Spec: my1alpha1.GrantSpec{
ForProvider: my1alpha1.GrantParameters{
Privileges: privs,
User: &username,
Database: &dbname,
},
ResourceSpec: xpv1.ResourceSpec{
ProviderConfigReference: &xpv1.Reference{
Name: comp.GetName(),
},
},
},
}

err := svc.SetDesiredComposedResource(grant, runtime.ComposedOptionProtects(comp.GetName()+"-provider-conf-credentials"))
if err != nil {
svc.AddResult(runtime.NewWarningResult(fmt.Sprintf("cannot apply database: %s", err)))
svc.Log.Error(err, "cannot apply database")
}
}
14 changes: 7 additions & 7 deletions pkg/comp-functions/functions/vshnpostgres/user_management.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ func UserManagement(ctx context.Context, comp *vshnv1.VSHNPostgreSQL, svc *runti
}

// Nothing defined, let's return early
if comp.Spec.Parameters.Service.Access == nil || len(comp.Spec.Parameters.Service.Access) == 0 {
if len(comp.Spec.Parameters.Service.Access) == 0 {
return nil
}

Expand All @@ -47,7 +47,7 @@ func UserManagement(ctx context.Context, comp *vshnv1.VSHNPostgreSQL, svc *runti
return nil
}

func addUser(comp *vshnv1.VSHNPostgreSQL, svc *runtime.ServiceRuntime, username string) string {
func addUser(comp common.Composite, svc *runtime.ServiceRuntime, username string) string {
secretName, err := common.AddGenericSecret(comp, svc, "userpass-"+username, []string{"userpass"})
if err != nil {
svc.Log.Error(err, "cannot deploy user password secret")
Expand All @@ -72,7 +72,7 @@ func addUser(comp *vshnv1.VSHNPostgreSQL, svc *runtime.ServiceRuntime, username
PasswordSecretRef: &xpv1.SecretKeySelector{
SecretReference: xpv1.SecretReference{
Name: secretName,
Namespace: comp.Status.InstanceNamespace,
Namespace: comp.GetInstanceNamespace(),
},
Key: "userpass",
},
Expand All @@ -94,7 +94,7 @@ func addUser(comp *vshnv1.VSHNPostgreSQL, svc *runtime.ServiceRuntime, username
return secretName
}

func addConnectionDetail(comp *vshnv1.VSHNPostgreSQL, svc *runtime.ServiceRuntime, secretName, username, dbname string, connectionDetailRef *xpv1.SecretReference) {
func addConnectionDetail(comp common.Composite, svc *runtime.ServiceRuntime, secretName, username, dbname string, connectionDetailRef *xpv1.SecretReference) {
userpassCD, err := svc.GetObservedComposedResourceConnectionDetails(secretName)
if err != nil {
svc.Log.Error(err, "cannot get userpassword from secret")
Expand Down Expand Up @@ -137,7 +137,7 @@ func addConnectionDetail(comp *vshnv1.VSHNPostgreSQL, svc *runtime.ServiceRuntim
}
}

func addProviderConfig(comp *vshnv1.VSHNPostgreSQL, svc *runtime.ServiceRuntime) {
func addProviderConfig(comp common.Composite, svc *runtime.ServiceRuntime) {
cd := svc.GetConnectionDetails()

secret := &corev1.Secret{
Expand Down Expand Up @@ -191,7 +191,7 @@ func addProviderConfig(comp *vshnv1.VSHNPostgreSQL, svc *runtime.ServiceRuntime)
// If not it will be added.
// This should handle cases where there are mutliple users pointing to the same
// database, and one is deleted, that the database is not dropped.
func addDatabase(comp *vshnv1.VSHNPostgreSQL, svc *runtime.ServiceRuntime, name string) {
func addDatabase(comp common.Composite, svc *runtime.ServiceRuntime, name string) {
resname := fmt.Sprintf("%s-%s-database", comp.GetName(), name)

xdb := &pgv1alpha1.Database{}
Expand Down Expand Up @@ -233,7 +233,7 @@ func addDatabase(comp *vshnv1.VSHNPostgreSQL, svc *runtime.ServiceRuntime, name
}
}

func addGrants(comp *vshnv1.VSHNPostgreSQL, svc *runtime.ServiceRuntime, username, dbname string, privileges []string) {
func addGrants(comp common.Composite, svc *runtime.ServiceRuntime, username, dbname string, privileges []string) {
privs := []pgv1alpha1.GrantPrivilege{}

if len(privileges) == 0 {
Expand Down

0 comments on commit 73a8130

Please sign in to comment.