Skip to content
This repository has been archived by the owner on May 8, 2022. It is now read-only.

Commit

Permalink
Merge pull request #1 from bedag/feature-templating
Browse files Browse the repository at this point in the history
Feature templating
  • Loading branch information
Michael Grüner committed Jan 26, 2021
2 parents 2c8f734 + 7d7d94c commit f5bf265
Show file tree
Hide file tree
Showing 23 changed files with 423 additions and 318 deletions.
5 changes: 2 additions & 3 deletions api/v1/kubernetesdbaas_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,6 @@ import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)

// EDIT THIS FILE! THIS IS SCAFFOLDING FOR YOU TO OWN!
// NOTE: json tags are required. Any new fields you add must have json tags for the fields to be serialized.

// KubernetesDbaasSpec defines the desired state of KubernetesDbaas.
//
// Important: Run "make" to regenerate code after modifying this file. Json tags are required.
Expand All @@ -31,6 +28,8 @@ type KubernetesDbaasSpec struct {
Provisioner string `json:"provisioner,omitempty"`
// Endpoint associates this resource with a particular endpoint (must be already configured on the operator side)
Endpoint string `json:"endpoint,omitempty"`
// Params is a map containing parameters to be mapped to the database instance
Params map[string]string `json:"params,omitempty"`
}

// KubernetesDbaasStatus defines the observed state of KubernetesDbaas.
Expand Down
9 changes: 8 additions & 1 deletion api/v1/zz_generated.deepcopy.go

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

6 changes: 6 additions & 0 deletions config/crd/bases/dbaas.bedag.ch_kubernetesdbaas.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,12 @@ spec:
description: Endpoint associates this resource with a particular endpoint
(must be already configured on the operator side)
type: string
params:
additionalProperties:
type: string
description: Params is a map containing parameters to be mapped to
the database instance
type: object
provisioner:
description: Provisioner identifies the type of system responsible
for provisioning resources (must be supported)
Expand Down
106 changes: 96 additions & 10 deletions controllers/kubernetesdbaas_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,15 +14,19 @@ See the License for the specific language governing permissions and
limitations under the License.
*/

// Package controllers contain the Kubernetes controllers responsible for their Custom Resource.
package controllers

import (
"context"
"fmt"
"github.com/bedag/kubernetes-dbaas/pkg/config"
"github.com/bedag/kubernetes-dbaas/pkg/database"
"github.com/bedag/kubernetes-dbaas/pkg/pool"
v1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/util/json"
"k8s.io/apimachinery/pkg/util/rand"
"sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"
"sigs.k8s.io/controller-runtime/pkg/reconcile"
"time"
Expand All @@ -48,6 +52,7 @@ const (
DateTimeLayout = time.UnixDate
)

// Reconcile tries to reconcile the state of the cluster with the state of KubernetesDbaas resources.
// +kubebuilder:rbac:groups=dbaas.bedag.ch,resources=kubernetesdbaas,verbs=list;watch;update
// +kubebuilder:rbac:groups=dbaas.bedag.ch,resources=kubernetesdbaas/status,verbs=get;update;patch
// +kubebuilder:rbac:groups="",resources=secrets,verbs=list;watch;create;update;delete
Expand Down Expand Up @@ -241,18 +246,30 @@ func (r *KubernetesDbaasReconciler) createDb(dbaasResource *KubernetesDbaas) err
return err
}

output := conn.CreateDb(string(dbaasResource.UID))
if output.Err != nil {
return fmt.Errorf("could not create database: %s", output.Err)
dbms, err := config.
GetDbmsConfig().
GetByDriverAndEndpoint(dbaasResource.Spec.Provisioner, dbaasResource.Spec.Endpoint)
if err != nil {
return fmt.Errorf("could not get dbms entry: %s", err)
}

dsn, err := pool.GetDsnByDriverAndEndpointName(dbaasResource.Spec.Provisioner, dbaasResource.Spec.Endpoint)
opValues, err := newOpValuesFromResource(dbaasResource)
if err != nil {
return err
return fmt.Errorf("could not get generate operation values from resource: %s", err)
}

createOp, err := dbms.RenderOperation(database.CreateMapKey, opValues)
if err != nil {
return fmt.Errorf("could not render create operation values: %s", err)
}

output := conn.CreateDb(createOp)
if output.Err != nil {
return fmt.Errorf("could not create database: %s", output.Err)
}

// Create Secret
err = r.createSecret(dbaasResource, output, dsn)
err = r.createSecret(dbaasResource, output)
if err != nil {
return fmt.Errorf("could not create secret: %s", err)
}
Expand All @@ -268,14 +285,33 @@ func (r *KubernetesDbaasReconciler) deleteDb(dbaasResource *KubernetesDbaas) err
return err
}

if err = conn.DeleteDb(string(dbaasResource.UID)).Err; err != nil {
return err
dbms, err := config.
GetDbmsConfig().
GetByDriverAndEndpoint(dbaasResource.Spec.Provisioner, dbaasResource.Spec.Endpoint)
if err != nil {
return fmt.Errorf("could not get dbms entry: %s", err)
}

opValues, err := newOpValuesFromResource(dbaasResource)
if err != nil {
return fmt.Errorf("could not get generate operation values from resource: %s", err)
}

deleteOp, err := dbms.RenderOperation(database.DeleteMapKey, opValues)
if err != nil {
return fmt.Errorf("could not render create operation values: %s", err)
}

output := conn.DeleteDb(deleteOp)
if output.Err != nil {
return fmt.Errorf("could not delete database: %s", output.Err)
}

return nil
}

// createSecret creates a new K8s secret owned by owner with the data contained in output and dsn.
func (r *KubernetesDbaasReconciler) createSecret(owner *KubernetesDbaas, output database.OpOutput, dsn database.Dsn) error {
func (r *KubernetesDbaasReconciler) createSecret(owner *KubernetesDbaas, output database.OpOutput) error {
var ownerRefs []metav1.OwnerReference

ownerRefs = append(ownerRefs, metav1.OwnerReference{
Expand All @@ -295,7 +331,11 @@ func (r *KubernetesDbaasReconciler) createSecret(owner *KubernetesDbaas, output
StringData: map[string]string{
"username": output.Out[0],
"password": output.Out[1],
"dsn": dsn.WithTable(output.Out[2]).String(),
"host": output.Out[3],
"port": output.Out[4],
"dbName": output.Out[2],
"dsn": database.NewDsn(owner.Spec.Provisioner,
output.Out[0], output.Out[1], output.Out[3], output.Out[4], output.Out[2]) .String(),
},
}

Expand All @@ -316,6 +356,39 @@ func (r *KubernetesDbaasReconciler) createSecret(owner *KubernetesDbaas, output
return r.Client.Update(context.Background(), newSecret)
}

// newOpValuesFromResource constructs a database.OpValues struct starting from a KubernetesDbaas resource.
func newOpValuesFromResource(resource *KubernetesDbaas) (database.OpValues, error) {
metaIn := resource.ObjectMeta
var metadata map[string]interface{}
temp, _ := json.Marshal(metaIn)
err := json.Unmarshal(temp, &metadata)
if err != nil {
return database.OpValues{}, err
}
specIn := resource.Spec.Params
var spec map[string]string
temp, err = json.Marshal(specIn)
err = json.Unmarshal(temp, &spec)
if err != nil {
return database.OpValues{}, err
}

// Ensure meta.namespace and meta.name are set
if metadata["namespace"] == "" {
metadata["namespace"] = "default"
}
if metadata["name"] == "" {
// Generate name randomly
metadata["name"] = randSeq(16)
}

return database.OpValues{
Metadata: metadata,
Parameters: spec,
}, nil
}

// contains is a very small utility function which returns true if s has been found in list.
func contains(list []string, s string) bool {
for _, v := range list {
if v == s {
Expand All @@ -324,3 +397,16 @@ func contains(list []string, s string) bool {
}
return false
}

// randSeq generates a random alphanumeric string of length n
func randSeq(n int) string {
rand.Seed(time.Now().UnixNano())

var alphabet = []rune("0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ")

b := make([]rune, n)
for i := range b {
b[i] = alphabet[rand.Intn(len(alphabet))]
}
return string(b)
}
79 changes: 0 additions & 79 deletions controllers/suite_test.go

This file was deleted.

24 changes: 20 additions & 4 deletions docs/enduser_guide.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
Here's an example;

```
apiVersion: dbaas.bedag.ch/v1alpha1
apiVersion: dbaas.bedag.ch/v1
kind: KubernetesDbaas
metadata:
name: kubernetesdbaas-sample
Expand All @@ -20,9 +20,25 @@ spec:
endpoint: us-sqlserver-test
```

- "provisioner" tells the Operator which driver to use
- "endpoint" tells the Operator where to create the operator. Your endpoint names are configured in the Operator
configuration and should be properly documented inside of your organization.
- `provisioner` tells the Operator which driver to use (sqlserver)

- `endpoint` tells the Operator where to create the operator. Your endpoint names are configured in the Operator configuration and should be properly documented inside of your organization.

- You can supply other key values pairs if your Operator configuration is prepared to read them.

- Example:

```
apiVersion: dbaas.bedag.ch/v1
kind: KubernetesDbaas
metadata:
name: kubernetesdbaas-sample
spec:
provisioner: sqlserver
endpoint: us-sqlserver-test
params:
myCustomUserParam: "myvalue"
```

2. Apply the configuration in your cluster:

Expand Down
1 change: 0 additions & 1 deletion docs/resources/system_arch_diag.puml
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,6 @@ namespace database {
class Dsn << (S,Aquamarine) >> {
+ GetDriver() string
+ String() string
+ WithTable(table string) Dsn

}
class Endpoint << (S,Aquamarine) >> {
Expand Down
Binary file added docs/resources/system_diag_ctx.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading

0 comments on commit f5bf265

Please sign in to comment.