Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
Ceph: Create resources for external cluster
The JSON BLOB will be passed from the UI and appropiate resources will be created automatically for the external cluster.

Signed-off-by: RAJAT SINGH <rajasing@redhat.com>
  • Loading branch information
RAJAT SINGH authored and jarrpa committed May 22, 2020
1 parent 0966215 commit be86eed
Show file tree
Hide file tree
Showing 4 changed files with 154 additions and 5 deletions.
4 changes: 4 additions & 0 deletions pkg/apis/ocs/v1/storagecluster_types.go
Expand Up @@ -104,6 +104,10 @@ type StorageClusterStatus struct {
// +optional
FailureDomain string `json:"failureDomain,omitempty"`

// ExternalSecretFound indicates whether a Secret containing information
// about an external CephCluster was found or not
ExternalSecretFound bool `json:"externalSecretFound,omitempty"`

StorageClassesCreated bool `json:"storageClassesCreated,omitempty"`
CephObjectStoresCreated bool `json:"cephObjectStoresCreated,omitempty"`
CephBlockPoolsCreated bool `json:"cephBlockPoolsCreated,omitempty"`
Expand Down
7 changes: 7 additions & 0 deletions pkg/apis/ocs/v1/zz_generated.openapi.go
Expand Up @@ -306,6 +306,13 @@ func schema_pkg_apis_ocs_v1_StorageClusterStatus(ref common.ReferenceCallback) c
Format: "",
},
},
"externalSecretFound": {
SchemaProps: spec.SchemaProps{
Description: "ExternalSecretFound indicates whether a Secret containing information about an external CephCluster was found or not",
Type: []string{"boolean"},
Format: "",
},
},
"storageClassesCreated": {
SchemaProps: spec.SchemaProps{
Type: []string{"boolean"},
Expand Down
147 changes: 142 additions & 5 deletions pkg/controller/storagecluster/initialization_reconciler.go
Expand Up @@ -2,6 +2,7 @@ package storagecluster

import (
"context"
"encoding/json"
"fmt"

"github.com/go-logr/logr"
Expand All @@ -16,6 +17,21 @@ import (
"sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"
)

const (
externalClusterDetailsSecret = "rook-ceph-external-cluster-details"
externalClusterDetailsKey = "external_cluster_details"
cephFsStorageClassName = "cephfs"
cephRbdStorageClassName = "ceph-rbd"
cephRgwStorageClassName = "ceph-rgw"
)

// ExternalResource containes a list of External Cluster Resources
type ExternalResource struct {
Kind string `json:"kind"`
Data map[string]string `json:"data"`
Name string `json:"name"`
}

// ensureStorageClasses ensures that StorageClass resources exist in the desired
// state.
func (r *ReconcileStorageCluster) ensureStorageClasses(instance *ocsv1.StorageCluster, reqLogger logr.Logger) error {
Expand All @@ -28,9 +44,18 @@ func (r *ReconcileStorageCluster) ensureStorageClasses(instance *ocsv1.StorageCl
if err != nil {
return err
}
err = r.createStorageClasses(scs, reqLogger)
if err != nil {
return err
}
instance.Status.StorageClassesCreated = true
return nil
}

func (r *ReconcileStorageCluster) createStorageClasses(scs []*storagev1.StorageClass, reqLogger logr.Logger) error {
for _, sc := range scs {
existing := storagev1.StorageClass{}
err = r.client.Get(context.TODO(), types.NamespacedName{Name: sc.Name, Namespace: sc.Namespace}, &existing)
err := r.client.Get(context.TODO(), types.NamespacedName{Name: sc.Name, Namespace: sc.Namespace}, &existing)

switch {
case err == nil:
Expand All @@ -55,9 +80,117 @@ func (r *ReconcileStorageCluster) ensureStorageClasses(instance *ocsv1.StorageCl
}
}
}
return nil
}

instance.Status.StorageClassesCreated = true

// ensureExternalStorageClusterResources ensures that requested resources for the external cluster
// being created
func (r *ReconcileStorageCluster) ensureExternalStorageClusterResources(instance *ocsv1.StorageCluster, reqLogger logr.Logger) error {
// check for the status boolean value accepted or not
if instance.Status.ExternalSecretFound {
return nil
}
found := &corev1.Secret{
ObjectMeta: metav1.ObjectMeta{
Name: externalClusterDetailsSecret,
Namespace: instance.Namespace,
},
}
err := r.client.Get(context.TODO(), types.NamespacedName{Name: found.Name, Namespace: found.Namespace}, found)
if err != nil {
return err
}
ownerRef := metav1.OwnerReference{
UID: instance.UID,
APIVersion: instance.APIVersion,
Kind: instance.Kind,
Name: instance.Name,
}
var data []ExternalResource
err = json.Unmarshal(found.Data[externalClusterDetailsKey], &data)
if err != nil {
reqLogger.Error(err, "could not parse json blob")
return err
}
scs, err := r.newStorageClasses(instance)
if err != nil {
reqLogger.Error(err, "failed to create StorageClasses")
return err
}
for _, d := range data {
objectMeta := metav1.ObjectMeta{
Name: d.Name,
Namespace: instance.Namespace,
OwnerReferences: []metav1.OwnerReference{ownerRef},
}
objectKey := types.NamespacedName{Name: d.Name, Namespace: instance.Namespace}
switch d.Kind {
case "ConfigMap":
cm := &corev1.ConfigMap{
ObjectMeta: objectMeta,
Data: d.Data,
}
found := &corev1.ConfigMap{ObjectMeta: objectMeta}
err := r.client.Get(context.TODO(), objectKey, found)
if err != nil {
if errors.IsNotFound(err) {
reqLogger.Info(fmt.Sprintf("creating configmap: %s", cm.Name))
err = r.client.Create(context.TODO(), cm)
if err != nil {
reqLogger.Error(err, "creation of configmap failed")
return err
}
} else {
reqLogger.Error(err, "unable the get the configmap")
return err
}
}
case "Secret":
sec := &corev1.Secret{
ObjectMeta: objectMeta,
Data: make(map[string][]byte),
}
for k, v := range d.Data {
sec.Data[k] = []byte(v)
}
found := &corev1.Secret{ObjectMeta: objectMeta}
err := r.client.Get(context.TODO(), objectKey, found)
if err != nil {
if errors.IsNotFound(err) {
reqLogger.Info(fmt.Sprintf("creating secret: %s", sec.Name))
err = r.client.Create(context.TODO(), sec)
if err != nil {
reqLogger.Error(err, "creation of secret failed")
return err
}
} else {
reqLogger.Error(err, "unable to get the secret")
return err
}
}
case "StorageClass":
var sc *storagev1.StorageClass
if d.Name == cephFsStorageClassName {
// Setting the fsname for cephfs StorageClass
sc = scs[0]
} else if d.Name == cephRbdStorageClassName {
// Setting the PoolName for RBD StorageClass
sc = scs[1]
} else if d.Name == cephRgwStorageClassName {
// Setting the Endpoint for OBC StorageClass
sc = scs[2]
}
for k, v := range d.Data {
sc.Parameters[k] = v
}
}
}
// creating all the storageClasses once we set the values
err = r.createStorageClasses(scs, reqLogger)
if err != nil {
return err
}
instance.Status.ExternalSecretFound = true
return nil
}

Expand Down Expand Up @@ -124,8 +257,12 @@ func (r *ReconcileStorageCluster) newStorageClasses(initData *ocsv1.StorageClust
},
},
}
// OBC StorageClass will be added only if it is not a cloud platform
if platform, err := r.platform.GetPlatform(r.client); err == nil && !isValidCloudPlatform(platform) {
// OBC storageclass will be returned only in TWO conditions,
// a. either 'externalStorage' is enabled
// OR
// b. current platform is not a cloud-based platform
platform, err := r.platform.GetPlatform(r.client)
if initData.Spec.ExternalStorage.Enable || err == nil && !isValidCloudPlatform(platform) {
ret = append(ret, r.newOBCStorageClass(initData))
}
return ret, nil
Expand Down
1 change: 1 addition & 0 deletions pkg/controller/storagecluster/reconcile.go
Expand Up @@ -231,6 +231,7 @@ func (r *ReconcileStorageCluster) Reconcile(request reconcile.Request) (reconcil
} else {
// for external cluster, we have a different set of ensure functions
ensureFs = []ensureFunc{
r.ensureExternalStorageClusterResources,
r.ensureCephCluster,
}
}
Expand Down

0 comments on commit be86eed

Please sign in to comment.