Skip to content

Commit

Permalink
Ceph: Create resources for external cluster
Browse files Browse the repository at this point in the history
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 committed May 20, 2020
1 parent f5b2a03 commit f5f574c
Show file tree
Hide file tree
Showing 9 changed files with 1,597 additions and 1,451 deletions.
4 changes: 4 additions & 0 deletions deploy/crds/ocs_v1_storagecluster_crd.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,10 @@ spec:
- lastTransitionTime
type: object
type: array
externalSecretFound:
description: ExternalSecretFound checks if there's an external secret
found or not
type: boolean
failureDomain:
description: FailureDomain is the base CRUSH element Ceph will use to
distribute its data replicas for the default CephBlockPool
Expand Down
2,840 changes: 1,415 additions & 1,425 deletions deploy/olm-catalog/ocs-operator/4.5.0/ocs-operator.v4.5.0.clusterserviceversion.yaml

Large diffs are not rendered by default.

4 changes: 4 additions & 0 deletions deploy/olm-catalog/ocs-operator/4.5.0/storagecluster.crd.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,10 @@ spec:
- lastTransitionTime
type: object
type: array
externalSecretFound:
description: ExternalSecretFound checks if there's an external secret
found or not
type: boolean
failureDomain:
description: FailureDomain is the base CRUSH element Ceph will use to
distribute its data replicas for the default CephBlockPool
Expand Down
2 changes: 1 addition & 1 deletion hack/latest-csv-checksum.md5
Original file line number Diff line number Diff line change
@@ -1 +1 @@
8d92a45b1b180a7ae94a6febb73602d9
d2dbc6087468e037a919dbcd4b8e54d3
3 changes: 3 additions & 0 deletions pkg/apis/ocs/v1/storagecluster_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,9 @@ type StorageClusterStatus struct {
// +optional
FailureDomain string `json:"failureDomain,omitempty"`

// ExternalSecretFound checks if there's an external secret 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
2 changes: 1 addition & 1 deletion pkg/apis/ocs/v1/zz_generated.deepcopy.go

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

45 changes: 26 additions & 19 deletions pkg/apis/ocs/v1/zz_generated.openapi.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,14 @@ import (

func GetOpenAPIDefinitions(ref common.ReferenceCallback) map[string]common.OpenAPIDefinition {
return map[string]common.OpenAPIDefinition{
"github.com/openshift/ocs-operator/pkg/apis/ocs/v1.OCSInitialization": schema_pkg_apis_ocs_v1_OCSInitialization(ref),
"github.com/openshift/ocs-operator/pkg/apis/ocs/v1.OCSInitializationSpec": schema_pkg_apis_ocs_v1_OCSInitializationSpec(ref),
"github.com/openshift/ocs-operator/pkg/apis/ocs/v1.OCSInitializationStatus": schema_pkg_apis_ocs_v1_OCSInitializationStatus(ref),
"github.com/openshift/ocs-operator/pkg/apis/ocs/v1.StorageCluster": schema_pkg_apis_ocs_v1_StorageCluster(ref),
"github.com/openshift/ocs-operator/pkg/apis/ocs/v1.StorageClusterInitialization": schema_pkg_apis_ocs_v1_StorageClusterInitialization(ref),
"github.com/openshift/ocs-operator/pkg/apis/ocs/v1.StorageClusterInitializationSpec": schema_pkg_apis_ocs_v1_StorageClusterInitializationSpec(ref),
"github.com/openshift/ocs-operator/pkg/apis/ocs/v1.StorageClusterInitializationStatus": schema_pkg_apis_ocs_v1_StorageClusterInitializationStatus(ref),
"github.com/openshift/ocs-operator/pkg/apis/ocs/v1.StorageClusterStatus": schema_pkg_apis_ocs_v1_StorageClusterStatus(ref),
"github.com/ocs-operator/pkg/apis/ocs/v1.OCSInitialization": schema_pkg_apis_ocs_v1_OCSInitialization(ref),
"github.com/ocs-operator/pkg/apis/ocs/v1.OCSInitializationSpec": schema_pkg_apis_ocs_v1_OCSInitializationSpec(ref),
"github.com/ocs-operator/pkg/apis/ocs/v1.OCSInitializationStatus": schema_pkg_apis_ocs_v1_OCSInitializationStatus(ref),
"github.com/ocs-operator/pkg/apis/ocs/v1.StorageCluster": schema_pkg_apis_ocs_v1_StorageCluster(ref),
"github.com/ocs-operator/pkg/apis/ocs/v1.StorageClusterInitialization": schema_pkg_apis_ocs_v1_StorageClusterInitialization(ref),
"github.com/ocs-operator/pkg/apis/ocs/v1.StorageClusterInitializationSpec": schema_pkg_apis_ocs_v1_StorageClusterInitializationSpec(ref),
"github.com/ocs-operator/pkg/apis/ocs/v1.StorageClusterInitializationStatus": schema_pkg_apis_ocs_v1_StorageClusterInitializationStatus(ref),
"github.com/ocs-operator/pkg/apis/ocs/v1.StorageClusterStatus": schema_pkg_apis_ocs_v1_StorageClusterStatus(ref),
}
}

Expand Down Expand Up @@ -49,19 +49,19 @@ func schema_pkg_apis_ocs_v1_OCSInitialization(ref common.ReferenceCallback) comm
},
"spec": {
SchemaProps: spec.SchemaProps{
Ref: ref("github.com/openshift/ocs-operator/pkg/apis/ocs/v1.OCSInitializationSpec"),
Ref: ref("github.com/ocs-operator/pkg/apis/ocs/v1.OCSInitializationSpec"),
},
},
"status": {
SchemaProps: spec.SchemaProps{
Ref: ref("github.com/openshift/ocs-operator/pkg/apis/ocs/v1.OCSInitializationStatus"),
Ref: ref("github.com/ocs-operator/pkg/apis/ocs/v1.OCSInitializationStatus"),
},
},
},
},
},
Dependencies: []string{
"github.com/openshift/ocs-operator/pkg/apis/ocs/v1.OCSInitializationSpec", "github.com/openshift/ocs-operator/pkg/apis/ocs/v1.OCSInitializationStatus", "k8s.io/apimachinery/pkg/apis/meta/v1.ObjectMeta"},
"github.com/ocs-operator/pkg/apis/ocs/v1.OCSInitializationSpec", "github.com/ocs-operator/pkg/apis/ocs/v1.OCSInitializationStatus", "k8s.io/apimachinery/pkg/apis/meta/v1.ObjectMeta"},
}
}

Expand Down Expand Up @@ -171,19 +171,19 @@ func schema_pkg_apis_ocs_v1_StorageCluster(ref common.ReferenceCallback) common.
},
"spec": {
SchemaProps: spec.SchemaProps{
Ref: ref("github.com/openshift/ocs-operator/pkg/apis/ocs/v1.StorageClusterSpec"),
Ref: ref("github.com/ocs-operator/pkg/apis/ocs/v1.StorageClusterSpec"),
},
},
"status": {
SchemaProps: spec.SchemaProps{
Ref: ref("github.com/openshift/ocs-operator/pkg/apis/ocs/v1.StorageClusterStatus"),
Ref: ref("github.com/ocs-operator/pkg/apis/ocs/v1.StorageClusterStatus"),
},
},
},
},
},
Dependencies: []string{
"github.com/openshift/ocs-operator/pkg/apis/ocs/v1.StorageClusterSpec", "github.com/openshift/ocs-operator/pkg/apis/ocs/v1.StorageClusterStatus", "k8s.io/apimachinery/pkg/apis/meta/v1.ObjectMeta"},
"github.com/ocs-operator/pkg/apis/ocs/v1.StorageClusterSpec", "github.com/ocs-operator/pkg/apis/ocs/v1.StorageClusterStatus", "k8s.io/apimachinery/pkg/apis/meta/v1.ObjectMeta"},
}
}

Expand Down Expand Up @@ -214,19 +214,19 @@ func schema_pkg_apis_ocs_v1_StorageClusterInitialization(ref common.ReferenceCal
},
"spec": {
SchemaProps: spec.SchemaProps{
Ref: ref("github.com/openshift/ocs-operator/pkg/apis/ocs/v1.StorageClusterInitializationSpec"),
Ref: ref("github.com/ocs-operator/pkg/apis/ocs/v1.StorageClusterInitializationSpec"),
},
},
"status": {
SchemaProps: spec.SchemaProps{
Ref: ref("github.com/openshift/ocs-operator/pkg/apis/ocs/v1.StorageClusterInitializationStatus"),
Ref: ref("github.com/ocs-operator/pkg/apis/ocs/v1.StorageClusterInitializationStatus"),
},
},
},
},
},
Dependencies: []string{
"github.com/openshift/ocs-operator/pkg/apis/ocs/v1.StorageClusterInitializationSpec", "github.com/openshift/ocs-operator/pkg/apis/ocs/v1.StorageClusterInitializationStatus", "k8s.io/apimachinery/pkg/apis/meta/v1.ObjectMeta"},
"github.com/ocs-operator/pkg/apis/ocs/v1.StorageClusterInitializationSpec", "github.com/ocs-operator/pkg/apis/ocs/v1.StorageClusterInitializationStatus", "k8s.io/apimachinery/pkg/apis/meta/v1.ObjectMeta"},
}
}

Expand Down Expand Up @@ -296,7 +296,7 @@ func schema_pkg_apis_ocs_v1_StorageClusterStatus(ref common.ReferenceCallback) c
"nodeTopologies": {
SchemaProps: spec.SchemaProps{
Description: "NodeTopologies is a list of topology labels on all nodes matching the StorageCluster's placement selector.",
Ref: ref("github.com/openshift/ocs-operator/pkg/apis/ocs/v1.NodeTopologyMap"),
Ref: ref("github.com/ocs-operator/pkg/apis/ocs/v1.NodeTopologyMap"),
},
},
"failureDomain": {
Expand All @@ -306,6 +306,13 @@ func schema_pkg_apis_ocs_v1_StorageClusterStatus(ref common.ReferenceCallback) c
Format: "",
},
},
"externalSecretFound": {
SchemaProps: spec.SchemaProps{
Description: "ExternalSecretFound checks if there's an external secret found or not",
Type: []string{"boolean"},
Format: "",
},
},
"storageClassesCreated": {
SchemaProps: spec.SchemaProps{
Type: []string{"boolean"},
Expand Down Expand Up @@ -340,6 +347,6 @@ func schema_pkg_apis_ocs_v1_StorageClusterStatus(ref common.ReferenceCallback) c
},
},
Dependencies: []string{
"github.com/openshift/custom-resource-status/conditions/v1.Condition", "github.com/openshift/ocs-operator/pkg/apis/ocs/v1.NodeTopologyMap", "k8s.io/api/core/v1.ObjectReference"},
"github.com/ocs-operator/pkg/apis/ocs/v1.NodeTopologyMap", "github.com/openshift/custom-resource-status/conditions/v1.Condition", "k8s.io/api/core/v1.ObjectReference"},
}
}
147 changes: 142 additions & 5 deletions pkg/controller/storagecluster/initialization_reconciler.go
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
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 f5f574c

Please sign in to comment.