diff --git a/api/v1alpha1/broker_types.go b/api/v1alpha1/broker_types.go index ae57f3f..a0a1785 100644 --- a/api/v1alpha1/broker_types.go +++ b/api/v1alpha1/broker_types.go @@ -17,6 +17,7 @@ limitations under the License. package v1alpha1 import ( + corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" ) @@ -48,6 +49,10 @@ type BrokerSpec struct { // +optional // default: report-interval: 10s, url: http://broker1:9000/api/v1/write?db=_internal Monitor MonitorSpec `json:"monitor,omitempty"` + + // the resource configuration + // +optional + Resource corev1.ResourceList `json:"resource,omitempty"` } type LoggingSpec struct { diff --git a/api/v1alpha1/cluster_types.go b/api/v1alpha1/cluster_types.go index 5d37c27..8a9fbf0 100644 --- a/api/v1alpha1/cluster_types.go +++ b/api/v1alpha1/cluster_types.go @@ -20,6 +20,18 @@ import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" ) +// +kubebuilder:validation:Type=string +// +kubebuilder:validation:Enum={"Pending", "Running", "Failed"} +// ClusterPhaseStatus is the status of the cluster + +type ClusterPhaseStatus string + +const ( + ClusterPending ClusterPhaseStatus = "Pending" + ClusterRunning ClusterPhaseStatus = "Running" + ClusterFailed ClusterPhaseStatus = "Failed" +) + // ClusterSpec defines the desired state of Cluster type ClusterSpec struct { @@ -87,21 +99,20 @@ type CloudStorageSpec struct { // +kubebuilder:validation:Required // +kubebuilder:default:="/data" MountPath string `json:"mountPath,omitempty"` + + // recycling strategy + // +kubebuilder:validation:Required + // +kubebuilder:default:="Delete" + // +kubebuilder:validation:Enum={"Delete", "Retain"} + RecyclingStrategy string `json:"recyclingStrategy,omitempty"` } // ClusterStatus defines the observed state of Cluster type ClusterStatus struct { // the status of cluster - // +kubebuilder:validation:Optional - ClusterStatus string `json:"clusterStatus,omitempty"` - - // the status of brokers - // +optional - BrokerStatuses BrokerStatus `json:"brokerStatuses,omitempty"` - - // the status of storages - // +optional - StorageStatuses StorageStatus `json:"storageStatuses,omitempty"` + // +kubebuilder:default:="Pending" + // +kubebuilder:printcolumn:name="Phase",type=string,JSONPath=`.status.phaseStatus` + PhaseStatus ClusterPhaseStatus `json:"phaseStatus,omitempty"` } // +kubebuilder:object:root=true diff --git a/api/v1alpha1/storage_types.go b/api/v1alpha1/storage_types.go index 3ca63d4..bd84fb2 100644 --- a/api/v1alpha1/storage_types.go +++ b/api/v1alpha1/storage_types.go @@ -17,6 +17,7 @@ limitations under the License. package v1alpha1 import ( + corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" ) @@ -45,6 +46,10 @@ type StorageSpec struct { // +optional // default: report-interval: 10s, url: http://broker1:9000/api/v1/write?db=_internal Monitor MonitorSpec `json:"monitor,omitempty"` + + // the resource configuration + // +optional + Resource corev1.ResourceList `json:"resource,omitempty"` } // StorageStatus defines the observed state of Storage diff --git a/api/v1alpha1/zz_generated.deepcopy.go b/api/v1alpha1/zz_generated.deepcopy.go index 71763f4..1c496d5 100644 --- a/api/v1alpha1/zz_generated.deepcopy.go +++ b/api/v1alpha1/zz_generated.deepcopy.go @@ -22,6 +22,7 @@ limitations under the License. package v1alpha1 import ( + "k8s.io/api/core/v1" runtime "k8s.io/apimachinery/pkg/runtime" ) @@ -93,6 +94,13 @@ func (in *BrokerSpec) DeepCopyInto(out *BrokerSpec) { **out = **in } out.Monitor = in.Monitor + if in.Resource != nil { + in, out := &in.Resource, &out.Resource + *out = make(v1.ResourceList, len(*in)) + for key, val := range *in { + (*out)[key] = val.DeepCopy() + } + } } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new BrokerSpec. @@ -236,8 +244,6 @@ func (in *ClusterSpec) DeepCopy() *ClusterSpec { // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *ClusterStatus) DeepCopyInto(out *ClusterStatus) { *out = *in - out.BrokerStatuses = in.BrokerStatuses - out.StorageStatuses = in.StorageStatuses } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ClusterStatus. @@ -348,6 +354,13 @@ func (in *StorageSpec) DeepCopyInto(out *StorageSpec) { **out = **in } out.Monitor = in.Monitor + if in.Resource != nil { + in, out := &in.Resource, &out.Resource + *out = make(v1.ResourceList, len(*in)) + for key, val := range *in { + (*out)[key] = val.DeepCopy() + } + } } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new StorageSpec. diff --git a/config/crd/bases/lindb.lindb.io_brokers.yaml b/config/crd/bases/lindb.lindb.io_brokers.yaml index ea66e03..3057b42 100644 --- a/config/crd/bases/lindb.lindb.io_brokers.yaml +++ b/config/crd/bases/lindb.lindb.io_brokers.yaml @@ -65,6 +65,51 @@ spec: identity. If unspecified, defaults to 1. default: 1' format: int32 type: integer + resources: + description: Resources are not allowed for ephemeral containers. Ephemeral + containers use spare resources already allocated to the pod. + properties: + claims: + description: "Claims lists the names of resources, defined in + spec.resourceClaims, that are used by this container. \n This + is an alpha field and requires enabling the DynamicResourceAllocation + feature gate. \n This field is immutable." + items: + description: ResourceClaim references one entry in PodSpec.ResourceClaims. + properties: + name: + description: Name must match the name of one entry in pod.spec.resourceClaims + of the Pod where this field is used. It makes that resource + available inside a container. + type: string + required: + - name + type: object + type: array + x-kubernetes-list-type: set + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: 'Limits describes the maximum amount of compute resources + allowed. More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/' + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: 'Requests describes the minimum amount of compute + resources required. If Requests is omitted for a container, + it defaults to Limits if that is explicitly specified, otherwise + to an implementation-defined value. More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/' + type: object + type: object type: object status: description: BrokerStatus defines the observed state of Broker diff --git a/config/crd/bases/lindb.lindb.io_clusters.yaml b/config/crd/bases/lindb.lindb.io_clusters.yaml index 2739b74..09e4dd3 100644 --- a/config/crd/bases/lindb.lindb.io_clusters.yaml +++ b/config/crd/bases/lindb.lindb.io_clusters.yaml @@ -81,6 +81,53 @@ spec: 1. default: 1' format: int32 type: integer + resources: + description: Resources are not allowed for ephemeral containers. + Ephemeral containers use spare resources already allocated to + the pod. + properties: + claims: + description: "Claims lists the names of resources, defined + in spec.resourceClaims, that are used by this container. + \n This is an alpha field and requires enabling the DynamicResourceAllocation + feature gate. \n This field is immutable." + items: + description: ResourceClaim references one entry in PodSpec.ResourceClaims. + properties: + name: + description: Name must match the name of one entry in + pod.spec.resourceClaims of the Pod where this field + is used. It makes that resource available inside a + container. + type: string + required: + - name + type: object + type: array + x-kubernetes-list-type: set + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: 'Limits describes the maximum amount of compute + resources allowed. More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/' + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: 'Requests describes the minimum amount of compute + resources required. If Requests is omitted for a container, + it defaults to Limits if that is explicitly specified, otherwise + to an implementation-defined value. More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/' + type: object + type: object type: object cloud: description: Cloud is the cloud configuration @@ -92,6 +139,13 @@ spec: default: /data description: mountPath is the mount path of the cloud storage type: string + recyclingStrategy: + default: Delete + description: recycling strategy + enum: + - Delete + - Retain + type: string storageClass: default: gp2 description: storageClass is the storage class of the cloud @@ -135,6 +189,17 @@ spec: storages: description: storage is the storage configuration properties: + Resource: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: Resources are not allowed for ephemeral containers. + Ephemeral containers use spare resources already allocated to + the pod. + type: object grpcPort: description: 'the port of storage grpc server default: 2891' format: int32 @@ -167,27 +232,14 @@ spec: status: description: ClusterStatus defines the observed state of Cluster properties: - brokerStatuses: - description: the status of brokers - properties: - status: - description: the status of broker - type: string - type: object - clusterStatus: + phaseStatus: + default: Pending description: the status of cluster + enum: + - Pending + - Running + - Failed type: string - storageStatuses: - description: the status of storages - properties: - myid: - description: the indicator of storage - format: int32 - type: integer - status: - description: the status of storage - type: string - type: object type: object type: object served: true diff --git a/config/crd/bases/lindb.lindb.io_storages.yaml b/config/crd/bases/lindb.lindb.io_storages.yaml index 8499e4b..2970b4c 100644 --- a/config/crd/bases/lindb.lindb.io_storages.yaml +++ b/config/crd/bases/lindb.lindb.io_storages.yaml @@ -35,6 +35,16 @@ spec: spec: description: StorageSpec defines the desired state of Storage properties: + Resource: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: Resources are not allowed for ephemeral containers. Ephemeral + containers use spare resources already allocated to the pod. + type: object grpcPort: description: 'the port of storage grpc server default: 2891' format: int32 diff --git a/controllers/cluster_controller.go b/controllers/cluster_controller.go index 67c5f13..843bbd8 100644 --- a/controllers/cluster_controller.go +++ b/controllers/cluster_controller.go @@ -70,18 +70,20 @@ type ClusterReconciler struct { func (r *ClusterReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { logger := log.FromContext(ctx) - var lindbCluster = alpha1.Cluster{} - err := r.Get(ctx, req.NamespacedName, &lindbCluster) - if err != nil { - return ctrl.Result{}, err + var cls = alpha1.Cluster{} + + if err := r.Get(ctx, req.NamespacedName, &cls); err != nil { + logger.Error(err, "unable to fetch LindbCluster") + return ctrl.Result{}, client.IgnoreNotFound(err) } - logger.Info("Reconciling Lindb cluster", "cluster", lindbCluster.Namespace+"/"+lindbCluster.Name) - if apierrors.IsNotFound(err) || lindbCluster.GetDeletionTimestamp() != nil { - return r.reconcileDelete(ctx, &lindbCluster) + if cls.GetDeletionTimestamp() != nil { + return r.reconcileNormal(ctx, &cls) } - return r.reconcileNormal(ctx, &lindbCluster) + logger.Info("Reconciling Lindb cluster", "cluster", cls.Namespace+"/"+cls.Name) + + return r.reconcileNormal(ctx, &cls) } func (r *ClusterReconciler) reconcileNormal(ctx context.Context, cluster *alpha1.Cluster) (ctrl.Result, error) {