diff --git a/PROJECT b/PROJECT index 898258962..ded104da9 100644 --- a/PROJECT +++ b/PROJECT @@ -151,4 +151,13 @@ resources: defaulting: true validation: true webhookVersion: v1 +- api: + crdVersion: v1 + namespaced: true + controller: true + domain: oceanbase.com + group: oceanbase + kind: OBTenantVariable + path: github.com/oceanbase/ob-operator/api/v1alpha1 + version: v1alpha1 version: "3" diff --git a/api/types/variable.go b/api/types/variable.go new file mode 100644 index 000000000..8ded7eafd --- /dev/null +++ b/api/types/variable.go @@ -0,0 +1,18 @@ +/* +Copyright (c) 2023 OceanBase +ob-operator is licensed under Mulan PSL v2. +You can use this software according to the terms and conditions of the Mulan PSL v2. +You may obtain a copy of Mulan PSL v2 at: + http://license.coscl.org.cn/MulanPSL2 +THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, +EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, +MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. +See the Mulan PSL v2 for more details. +*/ + +package types + +type Variable struct { + Name string `json:"name"` + Value string `json:"value"` +} diff --git a/api/v1alpha1/obtenant_types.go b/api/v1alpha1/obtenant_types.go index dedb225ca..c0f0a7040 100644 --- a/api/v1alpha1/obtenant_types.go +++ b/api/v1alpha1/obtenant_types.go @@ -52,6 +52,7 @@ type OBTenantSpec struct { Credentials TenantCredentials `json:"credentials,omitempty"` Scenario string `json:"scenario,omitempty"` Parameters []apitypes.Parameter `json:"parameters,omitempty"` + Variables []apitypes.Variable `json:"variables,omitempty"` } type TenantCredentials struct { @@ -106,6 +107,7 @@ type OBTenantStatus struct { Source *TenantSourceStatus `json:"source,omitempty"` Credentials TenantCredentials `json:"credentials,omitempty"` Parameters []apitypes.Parameter `json:"parameters,omitempty"` + Variables []apitypes.Variable `json:"variables,omitempty"` } type TenantSourceStatus struct { diff --git a/api/v1alpha1/obtenantvariable_types.go b/api/v1alpha1/obtenantvariable_types.go new file mode 100644 index 000000000..0cc2910c6 --- /dev/null +++ b/api/v1alpha1/obtenantvariable_types.go @@ -0,0 +1,76 @@ +/* +Copyright 2023. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package v1alpha1 + +import ( + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + + apitypes "github.com/oceanbase/ob-operator/api/types" + tasktypes "github.com/oceanbase/ob-operator/pkg/task/types" +) + +// 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. + +// OBTenantVariableSpec defines the desired state of OBTenantVariable. +type OBTenantVariableSpec struct { + // INSERT ADDITIONAL SPEC FIELDS - desired state of cluster + // Important: Run "make" to regenerate code after modifying this file + + // Foo is an example field of OBTenantVariable. Edit obtenantvariable_types.go to remove/update + OBTenant string `json:"obtenant"` + Variable *apitypes.Variable `json:"variable"` +} + +// OBTenantVariableStatus defines the observed state of OBTenantVariable. +type OBTenantVariableStatus struct { + // INSERT ADDITIONAL STATUS FIELD - define observed state of cluster + // Important: Run "make" to regenerate code after modifying this file + OperationContext *tasktypes.OperationContext `json:"operationContext,omitempty"` + Status string `json:"status"` + Variable apitypes.Variable `json:"variable"` +} + +//+kubebuilder:object:root=true +//+kubebuilder:subresource:status +//+kubebuilder:printcolumn:name="Tenant",type="string",JSONPath=".spec.obtenant" +//+kubebuilder:printcolumn:name="Status",type="string",JSONPath=".status.status" +//+kubebuilder:printcolumn:name="Age",type="date",JSONPath=".metadata.creationTimestamp" +//+kubebuilder:printcolumn:name="Key",type="string",JSONPath=".spec.variable.name" +//+kubebuilder:printcolumn:name="WantedValue",type="string",JSONPath=".spec.variable.value" + +// OBTenantVariable is the Schema for the obtenantvariables API. +type OBTenantVariable struct { + metav1.TypeMeta `json:",inline"` + metav1.ObjectMeta `json:"metadata,omitempty"` + + Spec OBTenantVariableSpec `json:"spec,omitempty"` + Status OBTenantVariableStatus `json:"status,omitempty"` +} + +// +kubebuilder:object:root=true + +// OBTenantVariableList contains a list of OBTenantVariable. +type OBTenantVariableList struct { + metav1.TypeMeta `json:",inline"` + metav1.ListMeta `json:"metadata,omitempty"` + Items []OBTenantVariable `json:"items"` +} + +func init() { + SchemeBuilder.Register(&OBTenantVariable{}, &OBTenantVariableList{}) +} diff --git a/api/v1alpha1/zz_generated.deepcopy.go b/api/v1alpha1/zz_generated.deepcopy.go index ee3152368..1302a44d9 100644 --- a/api/v1alpha1/zz_generated.deepcopy.go +++ b/api/v1alpha1/zz_generated.deepcopy.go @@ -1358,6 +1358,11 @@ func (in *OBTenantSpec) DeepCopyInto(out *OBTenantSpec) { (*in)[i].DeepCopyInto(&(*out)[i]) } } + if in.Variables != nil { + in, out := &in.Variables, &out.Variables + *out = make([]types.Variable, len(*in)) + copy(*out, *in) + } } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new OBTenantSpec. @@ -1370,6 +1375,105 @@ func (in *OBTenantSpec) DeepCopy() *OBTenantSpec { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *OBTenantVariable) DeepCopyInto(out *OBTenantVariable) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + in.Spec.DeepCopyInto(&out.Spec) + in.Status.DeepCopyInto(&out.Status) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new OBTenantVariable. +func (in *OBTenantVariable) DeepCopy() *OBTenantVariable { + if in == nil { + return nil + } + out := new(OBTenantVariable) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *OBTenantVariable) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *OBTenantVariableList) DeepCopyInto(out *OBTenantVariableList) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ListMeta.DeepCopyInto(&out.ListMeta) + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]OBTenantVariable, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new OBTenantVariableList. +func (in *OBTenantVariableList) DeepCopy() *OBTenantVariableList { + if in == nil { + return nil + } + out := new(OBTenantVariableList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *OBTenantVariableList) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *OBTenantVariableSpec) DeepCopyInto(out *OBTenantVariableSpec) { + *out = *in + if in.Variable != nil { + in, out := &in.Variable, &out.Variable + *out = new(types.Variable) + **out = **in + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new OBTenantVariableSpec. +func (in *OBTenantVariableSpec) DeepCopy() *OBTenantVariableSpec { + if in == nil { + return nil + } + out := new(OBTenantVariableSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *OBTenantVariableStatus) DeepCopyInto(out *OBTenantVariableStatus) { + *out = *in + if in.OperationContext != nil { + in, out := &in.OperationContext, &out.OperationContext + *out = (*in).DeepCopy() + } + out.Variable = in.Variable +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new OBTenantVariableStatus. +func (in *OBTenantVariableStatus) DeepCopy() *OBTenantVariableStatus { + if in == nil { + return nil + } + out := new(OBTenantVariableStatus) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *OBZone) DeepCopyInto(out *OBZone) { *out = *in diff --git a/charts/ob-operator/templates/operator.yaml b/charts/ob-operator/templates/operator.yaml index f1c0bb0c5..54641306a 100644 --- a/charts/ob-operator/templates/operator.yaml +++ b/charts/ob-operator/templates/operator.yaml @@ -10277,6 +10277,11 @@ spec: - name - value type: object + tenantId: + format: int64 + type: integer + tenantName: + type: string required: - clusterName - parameter @@ -14039,6 +14044,18 @@ spec: type: boolean obcluster: type: string + parameters: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array pools: items: properties: @@ -14177,6 +14194,18 @@ spec: type: string unitNum: type: integer + variables: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array required: - obcluster - pools @@ -14234,6 +14263,18 @@ spec: - taskStatus - tasks type: object + parameters: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array resourcePool: items: properties: @@ -14516,6 +14557,18 @@ spec: type: object tenantRole: type: string + variables: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array required: - resourcePool - status @@ -15298,6 +15351,18 @@ spec: type: boolean obcluster: type: string + parameters: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array pools: items: properties: @@ -15436,6 +15501,18 @@ spec: type: string unitNum: type: integer + variables: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array required: - obcluster - pools @@ -15493,6 +15570,18 @@ spec: - taskStatus - tasks type: object + parameters: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array resourcePool: items: properties: @@ -15775,6 +15864,18 @@ spec: type: object tenantRole: type: string + variables: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array required: - resourcePool - status @@ -15823,6 +15924,18 @@ spec: type: boolean obcluster: type: string + parameters: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array pools: items: properties: @@ -15961,6 +16074,18 @@ spec: type: string unitNum: type: integer + variables: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array required: - obcluster - pools @@ -16018,6 +16143,18 @@ spec: - taskStatus - tasks type: object + parameters: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array resourcePool: items: properties: @@ -16300,6 +16437,18 @@ spec: type: object tenantRole: type: string + variables: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array required: - resourcePool - status @@ -16704,6 +16853,18 @@ spec: type: boolean obcluster: type: string + parameters: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array pools: items: properties: @@ -16842,6 +17003,18 @@ spec: type: string unitNum: type: integer + variables: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array required: - obcluster - pools @@ -16899,6 +17072,18 @@ spec: - taskStatus - tasks type: object + parameters: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array resourcePool: items: properties: @@ -17181,6 +17366,18 @@ spec: type: object tenantRole: type: string + variables: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array required: - resourcePool - status @@ -17193,6 +17390,150 @@ spec: --- apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition +metadata: + annotations: + cert-manager.io/inject-ca-from: {{ .Release.Namespace }}/oceanbase-serving-cert + controller-gen.kubebuilder.io/version: v0.15.0 + name: obtenantvariables.oceanbase.oceanbase.com +spec: + group: oceanbase.oceanbase.com + names: + kind: OBTenantVariable + listKind: OBTenantVariableList + plural: obtenantvariables + singular: obtenantvariable + scope: Namespaced + versions: + - additionalPrinterColumns: + - jsonPath: .spec.obtenant + name: Tenant + type: string + - jsonPath: .status.status + name: Status + type: string + - jsonPath: .metadata.creationTimestamp + name: Age + type: date + - jsonPath: .spec.variable.name + name: Key + type: string + - jsonPath: .spec.variable.value + name: WantedValue + type: string + name: v1alpha1 + schema: + openAPIV3Schema: + description: OBTenantVariable is the Schema for the obtenantvariables API. + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + type: object + spec: + description: OBTenantVariableSpec defines the desired state of OBTenantVariable. + properties: + obtenant: + description: Foo is an example field of OBTenantVariable. Edit obtenantvariable_types.go + to remove/update + type: string + variable: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + required: + - obtenant + - variable + type: object + status: + description: OBTenantVariableStatus defines the observed state of OBTenantVariable. + properties: + operationContext: + description: |- + INSERT ADDITIONAL STATUS FIELD - define observed state of cluster + Important: Run "make" to regenerate code after modifying this file + properties: + failureRule: + properties: + failureStatus: + type: string + failureStrategy: + type: string + maxRetry: + type: integer + retryCount: + type: integer + required: + - failureStatus + - failureStrategy + type: object + idx: + type: integer + name: + type: string + targetStatus: + type: string + task: + type: string + taskId: + type: string + taskStatus: + type: string + tasks: + items: + type: string + type: array + required: + - idx + - name + - targetStatus + - task + - taskId + - taskStatus + - tasks + type: object + status: + type: string + variable: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + required: + - status + - variable + type: object + type: object + served: true + storage: true + subresources: + status: {} +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition metadata: annotations: cert-manager.io/inject-ca-from: {{ .Release.Namespace }}/oceanbase-serving-cert @@ -21135,6 +21476,32 @@ rules: - get - patch - update +- apiGroups: + - oceanbase.oceanbase.com + resources: + - obtenantvariables + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - oceanbase.oceanbase.com + resources: + - obtenantvariables/finalizers + verbs: + - update +- apiGroups: + - oceanbase.oceanbase.com + resources: + - obtenantvariables/status + verbs: + - get + - patch + - update - apiGroups: - oceanbase.oceanbase.com resources: @@ -21189,6 +21556,56 @@ rules: --- apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRole +metadata: + labels: + app.kubernetes.io/managed-by: kustomize + app.kubernetes.io/name: ob-operator + name: oceanbase-obtenantvariable-editor-role +rules: +- apiGroups: + - oceanbase.oceanbase.com + resources: + - obtenantvariables + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - oceanbase.oceanbase.com + resources: + - obtenantvariables/status + verbs: + - get +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + labels: + app.kubernetes.io/managed-by: kustomize + app.kubernetes.io/name: ob-operator + name: oceanbase-obtenantvariable-viewer-role +rules: +- apiGroups: + - oceanbase.oceanbase.com + resources: + - obtenantvariables + verbs: + - get + - list + - watch +- apiGroups: + - oceanbase.oceanbase.com + resources: + - obtenantvariables/status + verbs: + - get +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole metadata: labels: app.kubernetes.io/component: kube-rbac-proxy diff --git a/cmd/operator/main.go b/cmd/operator/main.go index 6755d4979..800a353a2 100644 --- a/cmd/operator/main.go +++ b/cmd/operator/main.go @@ -167,6 +167,14 @@ func main() { setupLog.Error(err, "Unable to create controller", "controller", "OBParameter") os.Exit(1) } + if err = (&controller.OBTenantVariableReconciler{ + Client: mgr.GetClient(), + Scheme: mgr.GetScheme(), + Recorder: telemetry.NewRecorder(ctx, mgr.GetEventRecorderFor(config.OBTenantVariableControllerName)), + }).SetupWithManager(mgr); err != nil { + setupLog.Error(err, "Unable to create controller", "controller", "OBTenantVariable") + os.Exit(1) + } if err = (&controller.OBTenantReconciler{ Client: mgr.GetClient(), Scheme: mgr.GetScheme(), diff --git a/config/crd/bases/oceanbase.oceanbase.com_obtenantbackuppolicies.yaml b/config/crd/bases/oceanbase.oceanbase.com_obtenantbackuppolicies.yaml index 684c484e7..b0e0a4218 100644 --- a/config/crd/bases/oceanbase.oceanbase.com_obtenantbackuppolicies.yaml +++ b/config/crd/bases/oceanbase.oceanbase.com_obtenantbackuppolicies.yaml @@ -634,6 +634,18 @@ spec: type: string unitNum: type: integer + variables: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array required: - obcluster - pools @@ -985,6 +997,18 @@ spec: type: object tenantRole: type: string + variables: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array required: - resourcePool - status diff --git a/config/crd/bases/oceanbase.oceanbase.com_obtenantoperations.yaml b/config/crd/bases/oceanbase.oceanbase.com_obtenantoperations.yaml index d1e0a9f43..53a2a2d92 100644 --- a/config/crd/bases/oceanbase.oceanbase.com_obtenantoperations.yaml +++ b/config/crd/bases/oceanbase.oceanbase.com_obtenantoperations.yaml @@ -490,6 +490,18 @@ spec: type: string unitNum: type: integer + variables: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array required: - obcluster - pools @@ -841,6 +853,18 @@ spec: type: object tenantRole: type: string + variables: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array required: - resourcePool - status @@ -1039,6 +1063,18 @@ spec: type: string unitNum: type: integer + variables: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array required: - obcluster - pools @@ -1390,6 +1426,18 @@ spec: type: object tenantRole: type: string + variables: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array required: - resourcePool - status diff --git a/config/crd/bases/oceanbase.oceanbase.com_obtenants.yaml b/config/crd/bases/oceanbase.oceanbase.com_obtenants.yaml index 8e1e853fa..852d5ce4c 100644 --- a/config/crd/bases/oceanbase.oceanbase.com_obtenants.yaml +++ b/config/crd/bases/oceanbase.oceanbase.com_obtenants.yaml @@ -241,6 +241,18 @@ spec: type: string unitNum: type: integer + variables: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array required: - obcluster - pools @@ -592,6 +604,18 @@ spec: type: object tenantRole: type: string + variables: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array required: - resourcePool - status diff --git a/config/crd/bases/oceanbase.oceanbase.com_obtenantvariables.yaml b/config/crd/bases/oceanbase.oceanbase.com_obtenantvariables.yaml new file mode 100644 index 000000000..fd841d049 --- /dev/null +++ b/config/crd/bases/oceanbase.oceanbase.com_obtenantvariables.yaml @@ -0,0 +1,143 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.15.0 + name: obtenantvariables.oceanbase.oceanbase.com +spec: + group: oceanbase.oceanbase.com + names: + kind: OBTenantVariable + listKind: OBTenantVariableList + plural: obtenantvariables + singular: obtenantvariable + scope: Namespaced + versions: + - additionalPrinterColumns: + - jsonPath: .spec.obtenant + name: Tenant + type: string + - jsonPath: .status.status + name: Status + type: string + - jsonPath: .metadata.creationTimestamp + name: Age + type: date + - jsonPath: .spec.variable.name + name: Key + type: string + - jsonPath: .spec.variable.value + name: WantedValue + type: string + name: v1alpha1 + schema: + openAPIV3Schema: + description: OBTenantVariable is the Schema for the obtenantvariables API. + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + type: object + spec: + description: OBTenantVariableSpec defines the desired state of OBTenantVariable. + properties: + obtenant: + description: Foo is an example field of OBTenantVariable. Edit obtenantvariable_types.go + to remove/update + type: string + variable: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + required: + - obtenant + - variable + type: object + status: + description: OBTenantVariableStatus defines the observed state of OBTenantVariable. + properties: + operationContext: + description: |- + INSERT ADDITIONAL STATUS FIELD - define observed state of cluster + Important: Run "make" to regenerate code after modifying this file + properties: + failureRule: + properties: + failureStatus: + type: string + failureStrategy: + type: string + maxRetry: + type: integer + retryCount: + type: integer + required: + - failureStatus + - failureStrategy + type: object + idx: + type: integer + name: + type: string + targetStatus: + type: string + task: + type: string + taskId: + type: string + taskStatus: + type: string + tasks: + items: + type: string + type: array + required: + - idx + - name + - targetStatus + - task + - taskId + - taskStatus + - tasks + type: object + status: + type: string + variable: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + required: + - status + - variable + type: object + type: object + served: true + storage: true + subresources: + status: {} diff --git a/config/crd/kustomization.yaml b/config/crd/kustomization.yaml index eb4c7d31d..e6ac223a1 100644 --- a/config/crd/kustomization.yaml +++ b/config/crd/kustomization.yaml @@ -14,6 +14,7 @@ resources: - bases/oceanbase.oceanbase.com_obresourcerescues.yaml - bases/oceanbase.oceanbase.com_obclusteroperations.yaml - bases/k8s.oceanbase.com_k8sclusters.yaml +- bases/oceanbase.oceanbase.com_obtenantvariables.yaml #+kubebuilder:scaffold:crdkustomizeresource patchesStrategicMerge: diff --git a/config/rbac/kustomization.yaml b/config/rbac/kustomization.yaml index 731832a6a..cc6bac29c 100644 --- a/config/rbac/kustomization.yaml +++ b/config/rbac/kustomization.yaml @@ -16,3 +16,10 @@ resources: - auth_proxy_role.yaml - auth_proxy_role_binding.yaml - auth_proxy_client_clusterrole.yaml +# For each CRD, "Editor" and "Viewer" roles are scaffolded by +# default, aiding admins in cluster management. Those roles are +# not used by the Project itself. You can comment the following lines +# if you do not want those helpers be installed with your Project. +- obtenantvariable_editor_role.yaml +- obtenantvariable_viewer_role.yaml + diff --git a/config/rbac/obtenantvariable_editor_role.yaml b/config/rbac/obtenantvariable_editor_role.yaml new file mode 100644 index 000000000..5997fd228 --- /dev/null +++ b/config/rbac/obtenantvariable_editor_role.yaml @@ -0,0 +1,27 @@ +# permissions for end users to edit obtenantvariables. +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + labels: + app.kubernetes.io/name: ob-operator + app.kubernetes.io/managed-by: kustomize + name: obtenantvariable-editor-role +rules: +- apiGroups: + - oceanbase.oceanbase.com + resources: + - obtenantvariables + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - oceanbase.oceanbase.com + resources: + - obtenantvariables/status + verbs: + - get diff --git a/config/rbac/obtenantvariable_viewer_role.yaml b/config/rbac/obtenantvariable_viewer_role.yaml new file mode 100644 index 000000000..9a0b05099 --- /dev/null +++ b/config/rbac/obtenantvariable_viewer_role.yaml @@ -0,0 +1,23 @@ +# permissions for end users to view obtenantvariables. +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + labels: + app.kubernetes.io/name: ob-operator + app.kubernetes.io/managed-by: kustomize + name: obtenantvariable-viewer-role +rules: +- apiGroups: + - oceanbase.oceanbase.com + resources: + - obtenantvariables + verbs: + - get + - list + - watch +- apiGroups: + - oceanbase.oceanbase.com + resources: + - obtenantvariables/status + verbs: + - get diff --git a/config/rbac/role.yaml b/config/rbac/role.yaml index adb99f870..b9854b764 100644 --- a/config/rbac/role.yaml +++ b/config/rbac/role.yaml @@ -483,6 +483,32 @@ rules: - get - patch - update +- apiGroups: + - oceanbase.oceanbase.com + resources: + - obtenantvariables + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - oceanbase.oceanbase.com + resources: + - obtenantvariables/finalizers + verbs: + - update +- apiGroups: + - oceanbase.oceanbase.com + resources: + - obtenantvariables/status + verbs: + - get + - patch + - update - apiGroups: - oceanbase.oceanbase.com resources: diff --git a/deploy/operator.yaml b/deploy/operator.yaml index b71b3c6a4..a835e6b11 100644 --- a/deploy/operator.yaml +++ b/deploy/operator.yaml @@ -14207,6 +14207,18 @@ spec: type: string unitNum: type: integer + variables: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array required: - obcluster - pools @@ -14558,6 +14570,18 @@ spec: type: object tenantRole: type: string + variables: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array required: - resourcePool - status @@ -15490,6 +15514,18 @@ spec: type: string unitNum: type: integer + variables: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array required: - obcluster - pools @@ -15841,6 +15877,18 @@ spec: type: object tenantRole: type: string + variables: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array required: - resourcePool - status @@ -16039,6 +16087,18 @@ spec: type: string unitNum: type: integer + variables: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array required: - obcluster - pools @@ -16390,6 +16450,18 @@ spec: type: object tenantRole: type: string + variables: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array required: - resourcePool - status @@ -16944,6 +17016,18 @@ spec: type: string unitNum: type: integer + variables: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array required: - obcluster - pools @@ -17295,6 +17379,18 @@ spec: type: object tenantRole: type: string + variables: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array required: - resourcePool - status @@ -17307,6 +17403,150 @@ spec: --- apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition +metadata: + annotations: + cert-manager.io/inject-ca-from: oceanbase-system/oceanbase-serving-cert + controller-gen.kubebuilder.io/version: v0.15.0 + name: obtenantvariables.oceanbase.oceanbase.com +spec: + group: oceanbase.oceanbase.com + names: + kind: OBTenantVariable + listKind: OBTenantVariableList + plural: obtenantvariables + singular: obtenantvariable + scope: Namespaced + versions: + - additionalPrinterColumns: + - jsonPath: .spec.obtenant + name: Tenant + type: string + - jsonPath: .status.status + name: Status + type: string + - jsonPath: .metadata.creationTimestamp + name: Age + type: date + - jsonPath: .spec.variable.name + name: Key + type: string + - jsonPath: .spec.variable.value + name: WantedValue + type: string + name: v1alpha1 + schema: + openAPIV3Schema: + description: OBTenantVariable is the Schema for the obtenantvariables API. + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + type: object + spec: + description: OBTenantVariableSpec defines the desired state of OBTenantVariable. + properties: + obtenant: + description: Foo is an example field of OBTenantVariable. Edit obtenantvariable_types.go + to remove/update + type: string + variable: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + required: + - obtenant + - variable + type: object + status: + description: OBTenantVariableStatus defines the observed state of OBTenantVariable. + properties: + operationContext: + description: |- + INSERT ADDITIONAL STATUS FIELD - define observed state of cluster + Important: Run "make" to regenerate code after modifying this file + properties: + failureRule: + properties: + failureStatus: + type: string + failureStrategy: + type: string + maxRetry: + type: integer + retryCount: + type: integer + required: + - failureStatus + - failureStrategy + type: object + idx: + type: integer + name: + type: string + targetStatus: + type: string + task: + type: string + taskId: + type: string + taskStatus: + type: string + tasks: + items: + type: string + type: array + required: + - idx + - name + - targetStatus + - task + - taskId + - taskStatus + - tasks + type: object + status: + type: string + variable: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + required: + - status + - variable + type: object + type: object + served: true + storage: true + subresources: + status: {} +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition metadata: annotations: cert-manager.io/inject-ca-from: oceanbase-system/oceanbase-serving-cert @@ -21249,6 +21489,32 @@ rules: - get - patch - update +- apiGroups: + - oceanbase.oceanbase.com + resources: + - obtenantvariables + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - oceanbase.oceanbase.com + resources: + - obtenantvariables/finalizers + verbs: + - update +- apiGroups: + - oceanbase.oceanbase.com + resources: + - obtenantvariables/status + verbs: + - get + - patch + - update - apiGroups: - oceanbase.oceanbase.com resources: @@ -21303,6 +21569,56 @@ rules: --- apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRole +metadata: + labels: + app.kubernetes.io/managed-by: kustomize + app.kubernetes.io/name: ob-operator + name: oceanbase-obtenantvariable-editor-role +rules: +- apiGroups: + - oceanbase.oceanbase.com + resources: + - obtenantvariables + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - oceanbase.oceanbase.com + resources: + - obtenantvariables/status + verbs: + - get +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + labels: + app.kubernetes.io/managed-by: kustomize + app.kubernetes.io/name: ob-operator + name: oceanbase-obtenantvariable-viewer-role +rules: +- apiGroups: + - oceanbase.oceanbase.com + resources: + - obtenantvariables + verbs: + - get + - list + - watch +- apiGroups: + - oceanbase.oceanbase.com + resources: + - obtenantvariables/status + verbs: + - get +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole metadata: labels: app.kubernetes.io/component: kube-rbac-proxy diff --git a/go.mod b/go.mod index 83a40067e..812909564 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,8 @@ module github.com/oceanbase/ob-operator -go 1.22 +go 1.22.1 + +toolchain go1.22.2 require ( github.com/casbin/casbin/v2 v2.97.0 @@ -30,7 +32,7 @@ require ( github.com/prometheus/prometheus v0.52.0 github.com/robfig/cron/v3 v3.0.1 github.com/sirupsen/logrus v1.9.3 - github.com/spf13/cobra v1.7.0 + github.com/spf13/cobra v1.8.1 github.com/spf13/pflag v1.0.5 github.com/spf13/viper v1.18.2 github.com/swaggo/files v1.0.1 @@ -98,6 +100,7 @@ require ( github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect github.com/golang/protobuf v1.5.4 // indirect github.com/golang/snappy v0.0.4 // indirect + github.com/golangci/golangci-lint v1.62.0 // indirect github.com/google/gnostic-models v0.6.8 // indirect github.com/google/go-cmp v0.6.0 // indirect github.com/google/gofuzz v1.2.0 // indirect @@ -106,7 +109,7 @@ require ( github.com/gorilla/securecookie v1.1.1 // indirect github.com/gorilla/sessions v1.2.1 // indirect github.com/grafana/regexp v0.0.0-20221122212121-6b5c0a4cb7fd // indirect - github.com/hashicorp/go-version v1.6.0 // indirect + github.com/hashicorp/go-version v1.7.0 // indirect github.com/hashicorp/hcl v1.0.0 // indirect github.com/imdario/mergo v0.3.16 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect @@ -128,7 +131,7 @@ require ( github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f // indirect github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f // indirect github.com/oklog/ulid v1.3.1 // indirect - github.com/pelletier/go-toml/v2 v2.1.1 // indirect + github.com/pelletier/go-toml/v2 v2.2.3 // indirect github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c // indirect github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect github.com/prometheus/client_golang v1.19.0 // indirect @@ -156,20 +159,20 @@ require ( go.uber.org/goleak v1.3.0 // indirect go.uber.org/multierr v1.11.0 // indirect golang.org/x/arch v0.7.0 // indirect - golang.org/x/crypto v0.25.0 // indirect - golang.org/x/exp v0.0.0-20240119083558-1b970713d09a // indirect - golang.org/x/net v0.27.0 // indirect + golang.org/x/crypto v0.29.0 // indirect + golang.org/x/exp v0.0.0-20240909161429-701f63a606c0 // indirect + golang.org/x/net v0.31.0 // indirect golang.org/x/oauth2 v0.19.0 // indirect - golang.org/x/sync v0.7.0 // indirect - golang.org/x/sys v0.22.0 // indirect - golang.org/x/term v0.22.0 // indirect - golang.org/x/text v0.16.0 // indirect + golang.org/x/sync v0.9.0 // indirect + golang.org/x/sys v0.27.0 // indirect + golang.org/x/term v0.26.0 // indirect + golang.org/x/text v0.20.0 // indirect golang.org/x/time v0.5.0 // indirect - golang.org/x/tools v0.23.0 // indirect + golang.org/x/tools v0.27.0 // indirect gomodules.xyz/jsonpatch/v2 v2.3.0 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20240415180920-8c6c420018be // indirect google.golang.org/grpc v1.63.2 // indirect - google.golang.org/protobuf v1.33.0 // indirect + google.golang.org/protobuf v1.34.2 // indirect gopkg.in/inf.v0 v0.9.1 // indirect gopkg.in/ini.v1 v1.67.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect diff --git a/go.sum b/go.sum index e45c74497..ad4f37d7f 100644 --- a/go.sum +++ b/go.sum @@ -110,6 +110,7 @@ github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGX github.com/cncf/xds/go v0.0.0-20231128003011-0fa0005c9caa h1:jQCWAUqqlij9Pgj2i/PB79y4KOPYVyFYdROxgaCwdTQ= github.com/cncf/xds/go v0.0.0-20231128003011-0fa0005c9caa/go.mod h1:x/1Gn8zydmfq8dk6e9PdstVsDgu9RuyIIJqAaF//0IM= github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= +github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= @@ -151,6 +152,7 @@ github.com/facette/natsort v0.0.0-20181210072756-2cd4dd1e2dcb h1:IT4JYU7k4ikYg1S github.com/facette/natsort v0.0.0-20181210072756-2cd4dd1e2dcb/go.mod h1:bH6Xx7IW64qjjJq8M2u4dxNaBiDfKK+z/3eGDpXEQhc= github.com/fatih/color v1.15.0 h1:kOqh6YHBtK8aywxGerMG2Eq3H6Qgoqeo13Bk2Mv/nBs= github.com/fatih/color v1.15.0/go.mod h1:0h5ZqXfHYED7Bhv2ZJamyIOUej9KtShiJESRwBDUSsw= +github.com/fatih/color v1.18.0 h1:S8gINlzdQ840/4pfAwic/ZE0djQEH3wM94VfqLTZcOM= github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg= github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8= @@ -277,6 +279,8 @@ github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM= github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/golangci/golangci-lint v1.62.0 h1:/G0g+bi1BhmGJqLdNQkKBWjcim8HjOPc4tsKuHDOhcI= +github.com/golangci/golangci-lint v1.62.0/go.mod h1:jtoOhQcKTz8B6dGNFyfQV3WZkQk+YvBDewDtNpiAJts= github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/gnostic-models v0.6.8 h1:yo/ABAfM5IMRsS1VnXjTBvUb61tFIHozhlYvRgGre9I= @@ -348,6 +352,8 @@ github.com/hashicorp/go-rootcerts v1.0.2 h1:jzhAVGtqPKbwpyCPELlgNWhE1znq+qwJtW5O github.com/hashicorp/go-rootcerts v1.0.2/go.mod h1:pqUvnprVnM5bf7AOirdbb01K4ccR319Vf4pU3K5EGc8= github.com/hashicorp/go-version v1.6.0 h1:feTTfFNnjP967rlCxM/I9g701jU+RN74YKx2mOkIeek= github.com/hashicorp/go-version v1.6.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= +github.com/hashicorp/go-version v1.7.0 h1:5tqGy27NaOTB8yJKUZELlFAS/LTKJkrmONwQKeRZfjY= +github.com/hashicorp/go-version v1.7.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v0.6.0 h1:uL2shRDx7RTrOrTCUZEGP/wJUFiUI8QT6E7z5o8jga4= @@ -479,6 +485,8 @@ github.com/ovh/go-ovh v1.4.3/go.mod h1:AkPXVtgwB6xlKblMjRKJJmjRp+ogrE7fz2lVgcQY8 github.com/pelletier/go-toml/v2 v2.0.1/go.mod h1:r9LEWfGN8R5k0VXJ+0BkIe7MYkRdwZOjgMj2KwnJFUo= github.com/pelletier/go-toml/v2 v2.1.1 h1:LWAJwfNvjQZCFIDKWYQaM62NcYeYViCmWIwmOStowAI= github.com/pelletier/go-toml/v2 v2.1.1/go.mod h1:tJU2Z3ZkXwnxa4DPO899bsyIoywizdUvyaeZurnPPDc= +github.com/pelletier/go-toml/v2 v2.2.3 h1:YmeHyLY8mFWbdkNWwpr+qIL2bEqT0o95WSdkNHvL12M= +github.com/pelletier/go-toml/v2 v2.2.3/go.mod h1:MfCQTFTvCcUyyvvwm1+G6H/jORL20Xlb6rzQu9GuUkc= github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c h1:+mdjkGKdHQG3305AYmdv1U2eRNDiU2ErMBj1gwrq8eQ= github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c/go.mod h1:7rwL4CYBLnjLxUqIJNnCWiEdr3bn6IUYi15bNlnbCCU= github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= @@ -526,6 +534,7 @@ github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTE github.com/rogpeppe/go-internal v1.8.0/go.mod h1:WmiCO8CzOY8rg0OYDC4/i/2WRWAB6poM+XZ2dLUbcbE= github.com/rogpeppe/go-internal v1.11.0 h1:cWPaGQEPrBb5/AsnsZesgZZ9yb1OQ+GOISoDNXVBh4M= github.com/rogpeppe/go-internal v1.11.0/go.mod h1:ddIwULY96R17DhadqLgMfk9H9tvdUzkipdSkR5nkCZA= +github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/sagikazarmark/locafero v0.4.0 h1:HApY1R9zGo4DBgr7dqsTH/JJxLTTsOt7u6keLGt6kNQ= github.com/sagikazarmark/locafero v0.4.0/go.mod h1:Pe1W6UlPYUk/+wc/6KFhbORCfqzgYEpgQ3O5fPuL3H4= @@ -546,6 +555,8 @@ github.com/spf13/cast v1.6.0 h1:GEiTHELF+vaR5dhz3VqZfFSzZjYbgeKDpBxQVS4GYJ0= github.com/spf13/cast v1.6.0/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo= github.com/spf13/cobra v1.7.0 h1:hyqWnYt1ZQShIddO5kBpj3vu05/++x6tJ6dg8EC572I= github.com/spf13/cobra v1.7.0/go.mod h1:uLxZILRyS/50WlhOIKD7W6V5bgeIt+4sICxh6uRMrb0= +github.com/spf13/cobra v1.8.1 h1:e5/vxKd/rZsfSJMUX1agtjeTDf+qv1/JdBF8gg5k9ZM= +github.com/spf13/cobra v1.8.1/go.mod h1:wHxEcudfqmLYa8iTfL+OuZPbBZkmvliBWKIezN3kD9Y= github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/spf13/viper v1.18.2 h1:LUXCnvUvSM6FXAsj6nnfc8Q2tp1dIgUfY9Kc8GsSOiQ= @@ -638,6 +649,8 @@ golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDf golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs= golang.org/x/crypto v0.25.0 h1:ypSNr+bnYL2YhwoMt2zPxHFmbAN1KZs/njMG3hxUp30= golang.org/x/crypto v0.25.0/go.mod h1:T+wALwcMOSE0kXgUAnPAHqTLW+XHgcELELW8VaDgm/M= +golang.org/x/crypto v0.29.0 h1:L5SG1JTTXupVV3n6sUqMTeWbjAyfPwoda2DLX8J8FrQ= +golang.org/x/crypto v0.29.0/go.mod h1:+F4F4N5hv6v38hfeYwTdx20oUvLLc+QfrE9Ax9HtgRg= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= @@ -650,6 +663,8 @@ golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EH golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= golang.org/x/exp v0.0.0-20240119083558-1b970713d09a h1:Q8/wZp0KX97QFTc2ywcOE0YRjZPVIx+MXInMzdvQqcA= golang.org/x/exp v0.0.0-20240119083558-1b970713d09a/go.mod h1:idGWGoKP1toJGkd5/ig9ZLuPcZBC3ewk7SzmH0uou08= +golang.org/x/exp v0.0.0-20240909161429-701f63a606c0 h1:e66Fs6Z+fZTbFBAxKfP3PALWBtpfqks2bwGcexMxgtk= +golang.org/x/exp v0.0.0-20240909161429-701f63a606c0/go.mod h1:2TbTHSBQa924w8M6Xs1QcRcFwyucIwBGpK1p2f1YFFY= golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= @@ -675,6 +690,7 @@ golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91 golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/mod v0.19.0 h1:fEdghXQSo20giMthA7cd28ZC+jts4amQ3YMXiP5oMQ8= golang.org/x/mod v0.19.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= +golang.org/x/mod v0.22.0 h1:D4nJWe9zXqHOmWqj4VMOJhvzj7bEZg4wEYa759z1pH4= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -716,6 +732,8 @@ golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44= golang.org/x/net v0.22.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg= golang.org/x/net v0.27.0 h1:5K3Njcw06/l2y9vpGCSdcxWOYHOUk3dVNGDXN+FvAys= golang.org/x/net v0.27.0/go.mod h1:dDi0PyhWNoiUOrAS8uXv/vnScO4wnHQO4mj9fn/RytE= +golang.org/x/net v0.31.0 h1:68CPQngjLL0r2AlUKiSxtQFKvzRVbnzLwMUn5SzcLHo= +golang.org/x/net v0.31.0/go.mod h1:P4fl1q7dY2hnZFxEk4pPSkDHF+QqjitcnDjUQyMM+pM= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -739,6 +757,8 @@ golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M= golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sync v0.9.0 h1:fEo0HyrW1GIgZdpbhCRO0PkJajUS5H9IFUztCgEo2jQ= +golang.org/x/sync v0.9.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -793,6 +813,8 @@ golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.22.0 h1:RI27ohtqKCnwULzJLqkv897zojh5/DwS/ENaMzUOaWI= golang.org/x/sys v0.22.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.27.0 h1:wBqf8DvsY9Y/2P8gAfPDEYNuS30J4lPHJxXSb/nJZ+s= +golang.org/x/sys v0.27.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= @@ -801,6 +823,8 @@ golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk= golang.org/x/term v0.18.0/go.mod h1:ILwASektA3OnRv7amZ1xhE/KTR+u50pbXfZ03+6Nx58= golang.org/x/term v0.22.0 h1:BbsgPEJULsl2fV/AT3v15Mjva5yXKQDyKf+TbDz7QJk= golang.org/x/term v0.22.0/go.mod h1:F3qCibpT5AMpCRfhfT53vVJwhLtIVHhB9XDjfFvnMI4= +golang.org/x/term v0.26.0 h1:WEQa6V3Gja/BhNxg540hBip/kkaYtRg3cxg4oXSw4AU= +golang.org/x/term v0.26.0/go.mod h1:Si5m1o57C5nBNQo5z1iq+XDijt21BDBDp2bK0QI8e3E= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -813,6 +837,8 @@ golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= golang.org/x/text v0.16.0 h1:a94ExnEXNtEwYLGJSIUxnWoxoRz/ZcCsV63ROupILh4= golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI= +golang.org/x/text v0.20.0 h1:gK/Kv2otX8gz+wn7Rmb3vT96ZwuoxnQlY+HlJVj7Qug= +golang.org/x/text v0.20.0/go.mod h1:D4IsuqiFMhST5bX19pQ9ikHC2GsaKyk/oF+pn3ducp4= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= @@ -865,6 +891,8 @@ golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= golang.org/x/tools v0.23.0 h1:SGsXPZ+2l4JsgaCKkx+FQ9YZ5XEtA1GZYuoDjenLjvg= golang.org/x/tools v0.23.0/go.mod h1:pnu6ufv6vQkll6szChhK3C3L/ruaIv5eBeztNG8wtsI= +golang.org/x/tools v0.27.0 h1:qEKojBykQkQ4EynWy4S8Weg69NumxKdn40Fce3uc/8o= +golang.org/x/tools v0.27.0/go.mod h1:sUi0ZgbwW9ZPAq26Ekut+weQPR5eIM6GQLQ1Yjm1H0Q= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= @@ -955,6 +983,8 @@ google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp0 google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI= google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= +google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg= +google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= diff --git a/internal/const/status/obtenantvariable/obtenantvariable.go b/internal/const/status/obtenantvariable/obtenantvariable.go new file mode 100644 index 000000000..e1caa5f41 --- /dev/null +++ b/internal/const/status/obtenantvariable/obtenantvariable.go @@ -0,0 +1,19 @@ +/* +Copyright (c) 2023 OceanBase +ob-operator is licensed under Mulan PSL v2. +You can use this software according to the terms and conditions of the Mulan PSL v2. +You may obtain a copy of Mulan PSL v2 at: + http://license.coscl.org.cn/MulanPSL2 +THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, +EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, +MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. +See the Mulan PSL v2 for more details. +*/ + +package obtenantvariable + +const ( + New = "new" + Matched = "matched" + NotMatch = "not match" +) diff --git a/internal/const/status/tenantstatus/obtenant_status.go b/internal/const/status/tenantstatus/obtenant_status.go index ebde90e69..3bb74f928 100644 --- a/internal/const/status/tenantstatus/obtenant_status.go +++ b/internal/const/status/tenantstatus/obtenant_status.go @@ -24,6 +24,7 @@ const ( DeletingResourcePool = "deleting resource pool" MaintainingUnitConfig = "maintaining unit config" MaintainingParameters = "maintaining parameters" + MaintainingVariables = "maintaining variables" DeletingTenant = "deleting" FinalizerFinished = "finalizer finished" PausingReconcile = "pausing reconcile" diff --git a/internal/controller/config/const.go b/internal/controller/config/const.go index b5d1dfe4a..1f153b0ce 100644 --- a/internal/controller/config/const.go +++ b/internal/controller/config/const.go @@ -17,6 +17,7 @@ const ( OBZoneControllerName = "obzone-controller" OBServerControllerName = "observer-controller" OBParameterControllerName = "obparameter-controller" + OBTenantVariableControllerName = "obtenantvariable-controller" OBTenantControllerName = "obtenant-controller" OBTenantBackupControllerName = "obtenantbackup-controller" OBTenantRestoreControllerName = "obtenantrestore-controller" diff --git a/internal/controller/obtenantvariable_controller.go b/internal/controller/obtenantvariable_controller.go new file mode 100644 index 000000000..97e7f9c47 --- /dev/null +++ b/internal/controller/obtenantvariable_controller.go @@ -0,0 +1,81 @@ +/* +Copyright 2023. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package controller + +import ( + "context" + + kubeerrors "k8s.io/apimachinery/pkg/api/errors" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/client-go/tools/record" + ctrl "sigs.k8s.io/controller-runtime" + "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/log" + + "github.com/oceanbase/ob-operator/api/v1alpha1" + resobtenantvariable "github.com/oceanbase/ob-operator/internal/resource/obtenantvariable" + "github.com/oceanbase/ob-operator/internal/telemetry" + "github.com/oceanbase/ob-operator/pkg/coordinator" +) + +// OBTenantVariableReconciler reconciles a OBTenantVariable object +type OBTenantVariableReconciler struct { + client.Client + Scheme *runtime.Scheme + Recorder record.EventRecorder +} + +// Reconcile is part of the main kubernetes reconciliation loop which aims to +// move the current state of the cluster closer to the desired state. +// TODO(user): Modify the Reconcile function to compare the state specified by +// the OBTenantVariable object against the actual cluster state, and then +// perform operations to make the cluster state reflect the state specified by +// the user. +// +// For more details, check Reconcile and its Result here: +// - https://pkg.go.dev/sigs.k8s.io/controller-runtime@v0.19.1/pkg/reconcile +func (r *OBTenantVariableReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { + logger := log.FromContext(ctx) + variable := &v1alpha1.OBTenantVariable{} + err := r.Client.Get(ctx, req.NamespacedName, variable) + if err != nil { + if kubeerrors.IsNotFound(err) { + // variable not found, just return + return ctrl.Result{}, nil + } + logger.Error(err, "Get obtenant variable error") + return ctrl.Result{}, err + } + + variableManager := &resobtenantvariable.OBTenantVariableManager{ + Ctx: ctx, + OBTenantVariable: variable, + Client: r.Client, + Logger: &logger, + Recorder: telemetry.NewRecorder(ctx, r.Recorder), + } + coordinator := coordinator.NewCoordinator(variableManager, &logger) + return coordinator.Coordinate() +} + +// SetupWithManager sets up the controller with the Manager. +func (r *OBTenantVariableReconciler) SetupWithManager(mgr ctrl.Manager) error { + return ctrl.NewControllerManagedBy(mgr). + For(&v1alpha1.OBTenantVariable{}). + Named("obtenantvariable"). + Complete(r) +} diff --git a/internal/controller/obtenantvariable_controller_test.go b/internal/controller/obtenantvariable_controller_test.go new file mode 100644 index 000000000..9195c2613 --- /dev/null +++ b/internal/controller/obtenantvariable_controller_test.go @@ -0,0 +1,84 @@ +/* +Copyright 2023. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package controller + +import ( + "context" + + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" + "k8s.io/apimachinery/pkg/api/errors" + "k8s.io/apimachinery/pkg/types" + "sigs.k8s.io/controller-runtime/pkg/reconcile" + + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + + oceanbasev1alpha1 "github.com/oceanbase/ob-operator/api/v1alpha1" +) + +var _ = Describe("OBTenantVariable Controller", func() { + Context("When reconciling a resource", func() { + const resourceName = "test-resource" + + ctx := context.Background() + + typeNamespacedName := types.NamespacedName{ + Name: resourceName, + Namespace: "default", // TODO(user):Modify as needed + } + obtenantvariable := &oceanbasev1alpha1.OBTenantVariable{} + + BeforeEach(func() { + By("creating the custom resource for the Kind OBTenantVariable") + err := k8sClient.Get(ctx, typeNamespacedName, obtenantvariable) + if err != nil && errors.IsNotFound(err) { + resource := &oceanbasev1alpha1.OBTenantVariable{ + ObjectMeta: metav1.ObjectMeta{ + Name: resourceName, + Namespace: "default", + }, + // TODO(user): Specify other spec details if needed. + } + Expect(k8sClient.Create(ctx, resource)).To(Succeed()) + } + }) + + AfterEach(func() { + // TODO(user): Cleanup logic after each test, like removing the resource instance. + resource := &oceanbasev1alpha1.OBTenantVariable{} + err := k8sClient.Get(ctx, typeNamespacedName, resource) + Expect(err).NotTo(HaveOccurred()) + + By("Cleanup the specific resource instance OBTenantVariable") + Expect(k8sClient.Delete(ctx, resource)).To(Succeed()) + }) + It("should successfully reconcile the resource", func() { + By("Reconciling the created resource") + controllerReconciler := &OBTenantVariableReconciler{ + Client: k8sClient, + Scheme: k8sClient.Scheme(), + } + + _, err := controllerReconciler.Reconcile(ctx, reconcile.Request{ + NamespacedName: typeNamespacedName, + }) + Expect(err).NotTo(HaveOccurred()) + // TODO(user): Add more specific assertions depending on your controller's reconciliation logic. + // Example: If you expect a certain status condition after reconciliation, verify it here. + }) + }) +}) diff --git a/internal/controller/rbac_marks.go b/internal/controller/rbac_marks.go index 5acd71099..a440f00ec 100644 --- a/internal/controller/rbac_marks.go +++ b/internal/controller/rbac_marks.go @@ -87,6 +87,10 @@ package controller // +kubebuilder:rbac:groups=oceanbase.oceanbase.com,resources=obzones/status,verbs=get;update;patch // +kubebuilder:rbac:groups=oceanbase.oceanbase.com,resources=obzones/finalizers,verbs=update +// +kubebuilder:rbac:groups=oceanbase.oceanbase.com,resources=obtenantvariables,verbs=get;list;watch;create;update;patch;delete +// +kubebuilder:rbac:groups=oceanbase.oceanbase.com,resources=obtenantvariables/status,verbs=get;update;patch +// +kubebuilder:rbac:groups=oceanbase.oceanbase.com,resources=obtenantvariables/finalizers,verbs=update + /** ** [GROUP] k8s.oceanbase.com **/ diff --git a/internal/resource/obtenant/obtenant_flow.go b/internal/resource/obtenant/obtenant_flow.go index 873085f3d..5b0a67689 100644 --- a/internal/resource/obtenant/obtenant_flow.go +++ b/internal/resource/obtenant/obtenant_flow.go @@ -198,3 +198,15 @@ func genMaintainTenantParametersFlow(_ *OBTenantManager) *tasktypes.TaskFlow { }, } } + +func genMaintainTenantVariablesFlow(_ *OBTenantManager) *tasktypes.TaskFlow { + return &tasktypes.TaskFlow{ + OperationContext: &tasktypes.OperationContext{ + Name: "maintain tenant variables", + Tasks: []tasktypes.TaskName{ + tMaintainTenantVariables, + }, + TargetStatus: tenantstatus.Running, + }, + } +} diff --git a/internal/resource/obtenant/obtenant_manager.go b/internal/resource/obtenant/obtenant_manager.go index 75d2ff79f..00fb9dbf1 100644 --- a/internal/resource/obtenant/obtenant_manager.go +++ b/internal/resource/obtenant/obtenant_manager.go @@ -279,6 +279,8 @@ func (m *OBTenantManager) GetTaskFlow() (*tasktypes.TaskFlow, error) { taskFlow = genCreateEmptyStandbyTenantFlow(m) case tenantstatus.MaintainingParameters: taskFlow = genMaintainTenantParametersFlow(m) + case tenantstatus.MaintainingVariables: + taskFlow = genMaintainTenantVariablesFlow(m) default: m.Logger.V(oceanbaseconst.LogLevelTrace).Info("No need to run anything for obtenant") return nil, nil @@ -380,6 +382,9 @@ func (m *OBTenantManager) NextStatus() (string, error) { if m.hasModifiedParameters() { return tenantstatus.MaintainingParameters, nil } + if m.hasModifiedVariables() { + return tenantstatus.MaintainingVariables, nil + } return tenantstatus.Running, nil } @@ -422,6 +427,30 @@ func (m *OBTenantManager) hasModifiedParameters() bool { return parameterModified } +func (m *OBTenantManager) hasModifiedVariables() bool { + variableModified := false + variableMap := make(map[string]apitypes.Variable) + for _, variable := range m.OBTenant.Status.Variables { + m.Logger.V(oceanbaseconst.LogLevelDebug).Info("Build variable map", "variable", variable.Name) + variableMap[variable.Name] = variable + } + for _, variable := range m.OBTenant.Spec.Variables { + variableStatus, variableExists := variableMap[variable.Name] + // need create or update variable + if !variableExists || variableStatus.Value != variable.Value { + variableModified = true + break + } + delete(variableMap, variable.Name) + } + + // need delete variable + if len(variableMap) > 0 { + variableModified = true + } + return variableModified +} + func (m *OBTenantManager) hasModifiedUnitConfig() (bool, error) { tenantName := m.OBTenant.Spec.TenantName @@ -593,6 +622,18 @@ func (m *OBTenantManager) buildTenantStatus() (*v1alpha1.OBTenantStatus, error) } tenantCurrentStatus.Parameters = obparameterStatusList + // Refresh variable info + variableList, err := m.listOBTenantVariables() + if err != nil { + m.Logger.Error(err, "list obtenantvariables error") + return tenantCurrentStatus, errors.Wrap(err, "list obtenantvariables") + } + variableStatusList := make([]apitypes.Variable, 0) + for _, variable := range variableList.Items { + variableStatusList = append(variableStatusList, *(variable.Spec.Variable)) + } + tenantCurrentStatus.Variables = variableStatusList + return tenantCurrentStatus, nil } diff --git a/internal/resource/obtenant/obtenant_task.go b/internal/resource/obtenant/obtenant_task.go index a8a60d908..0bc5b0b1f 100644 --- a/internal/resource/obtenant/obtenant_task.go +++ b/internal/resource/obtenant/obtenant_task.go @@ -608,3 +608,39 @@ func MaintainTenantParameters(m *OBTenantManager) tasktypes.TaskError { } return nil } + +func MaintainTenantVariables(m *OBTenantManager) tasktypes.TaskError { + variableMap := make(map[string]apitypes.Variable) + for _, variable := range m.OBTenant.Status.Variables { + m.Logger.V(oceanbaseconst.LogLevelDebug).Info("Build variable map", "variable", variable.Name) + variableMap[variable.Name] = variable + } + for _, variable := range m.OBTenant.Spec.Variables { + variableStatus, variableExists := variableMap[variable.Name] + if !variableExists { + m.Logger.V(oceanbaseconst.LogLevelDebug).Info("Variable not exists, need create", "variable", variable.Name) + err := m.createOBTenantVariable(&variable) + if err != nil { + m.Logger.Error(err, "Create obtenantvariable failed", "variable", variable.Name) + } + } else if variableStatus.Value != variable.Value { + m.Logger.V(oceanbaseconst.LogLevelDebug).Info("Variable value not matched, need update", "variable", variable.Name) + err := m.updateOBTenantVariable(&variable) + if err != nil { + m.Logger.Error(err, "Update obtenantvariable failed", "variable", variable.Name) + } + } + m.Logger.V(oceanbaseconst.LogLevelDebug).Info("Remove variable from map", "variable", variable.Name) + delete(variableMap, variable.Name) + } + + // delete variables that not in spec definition + for _, variable := range variableMap { + m.Logger.V(oceanbaseconst.LogLevelDebug).Info("Delete variable", "variable", variable.Name) + err := m.deleteOBTenantVariable(&variable) + if err != nil { + m.Logger.Error(err, "Failed to delete obtenantvariable") + } + } + return nil +} diff --git a/internal/resource/obtenant/obtenant_task_gen.go b/internal/resource/obtenant/obtenant_task_gen.go index e1b3cc0ba..e2459b96b 100644 --- a/internal/resource/obtenant/obtenant_task_gen.go +++ b/internal/resource/obtenant/obtenant_task_gen.go @@ -24,4 +24,5 @@ func init() { taskMap.Register(tOptimizeTenantByScenario, OptimizeTenantByScenario) taskMap.Register(tCreateUserWithCredentialSecrets, CreateUserWithCredentialSecrets) taskMap.Register(tMaintainTenantParameters, MaintainTenantParameters) + taskMap.Register(tMaintainTenantVariables, MaintainTenantVariables) } diff --git a/internal/resource/obtenant/obtenant_taskname_gen.go b/internal/resource/obtenant/obtenant_taskname_gen.go index fcac3c19e..c77ca015c 100644 --- a/internal/resource/obtenant/obtenant_taskname_gen.go +++ b/internal/resource/obtenant/obtenant_taskname_gen.go @@ -26,4 +26,5 @@ const ( tOptimizeTenantByScenario ttypes.TaskName = "optimize tenant by scenario" tCreateUserWithCredentialSecrets ttypes.TaskName = "create user with credential secrets" tMaintainTenantParameters ttypes.TaskName = "maintain tenant parameters" + tMaintainTenantVariables ttypes.TaskName = "maintain tenant variables" ) diff --git a/internal/resource/obtenant/utils.go b/internal/resource/obtenant/utils.go index 1d9d947cd..90d01d22d 100644 --- a/internal/resource/obtenant/utils.go +++ b/internal/resource/obtenant/utils.go @@ -468,18 +468,6 @@ func (m *OBTenantManager) getCharset() (string, error) { return charset.Charset, nil } -func (m *OBTenantManager) getVariable(variableName string) (string, error) { - oceanbaseOperationManager, err := m.getClusterSysClient() - if err != nil { - return "", errors.Wrap(err, "Failed to get sql operator error when getting variable") - } - variable, err := oceanbaseOperationManager.GetVariable(m.Ctx, variableName) - if err != nil { - return "", errors.Wrap(err, "Get sql error when get variable") - } - return variable.Value, nil -} - func (m *OBTenantManager) getTenantByName(tenantName string) (*model.OBTenant, error) { oceanbaseOperationManager, err := m.getClusterSysClient() if err != nil { @@ -923,6 +911,17 @@ func CreateUserWithCredentials(m *OBTenantManager) error { return nil } +func (m *OBTenantManager) listOBTenantVariables() (*v1alpha1.OBTenantVariableList, error) { + variableList := &v1alpha1.OBTenantVariableList{} + err := m.Client.List(m.Ctx, variableList, client.MatchingLabels{ + oceanbaseconst.LabelRefUID: string(m.OBTenant.GetUID()), + }, client.InNamespace(m.OBTenant.Namespace)) + if err != nil { + return nil, errors.Wrap(err, "get obteanntvariable list") + } + return variableList, nil +} + func (m *OBTenantManager) listOBParameters() (*v1alpha1.OBParameterList, error) { obparameterList := &v1alpha1.OBParameterList{} err := m.Client.List(m.Ctx, obparameterList, client.MatchingLabels{ @@ -935,7 +934,11 @@ func (m *OBTenantManager) listOBParameters() (*v1alpha1.OBParameterList, error) } func (m *OBTenantManager) generateParameterName(name string) string { - return fmt.Sprintf("%s-%s-%s", m.OBTenant.Spec.ClusterName, m.OBTenant.Name, strings.ReplaceAll(name, "_", "-")) + return fmt.Sprintf("param-%s-%s-%s", m.OBTenant.Spec.ClusterName, m.OBTenant.Name, strings.ReplaceAll(name, "_", "-")) +} + +func (m *OBTenantManager) generateVariableName(name string) string { + return fmt.Sprintf("var-%s-%s-%s", m.OBTenant.Spec.ClusterName, m.OBTenant.Name, strings.ReplaceAll(name, "_", "-")) } func (m *OBTenantManager) createOBParameter(parameter *apitypes.Parameter) error { @@ -1003,10 +1006,79 @@ func (m *OBTenantManager) deleteOBParameter(parameter *apitypes.Parameter) error if err != nil { return errors.Wrap(err, "Get obparameter") } - obparameter.Spec.Parameter.Value = parameter.Value err = m.Client.Delete(m.Ctx, obparameter) if err != nil { return errors.Wrap(err, "Delete obparameter") } return nil } + +func (m *OBTenantManager) createOBTenantVariable(variable *apitypes.Variable) error { + m.Logger.Info("Create ob tenant variable") + ownerReferenceList := make([]metav1.OwnerReference, 0) + ownerReference := metav1.OwnerReference{ + APIVersion: m.OBTenant.APIVersion, + Kind: m.OBTenant.Kind, + Name: m.OBTenant.Name, + UID: m.OBTenant.GetUID(), + } + ownerReferenceList = append(ownerReferenceList, ownerReference) + labels := make(map[string]string) + labels[oceanbaseconst.LabelRefUID] = string(m.OBTenant.GetUID()) + labels[oceanbaseconst.LabelRefOBTenant] = m.OBTenant.Name + variableName := m.generateVariableName(variable.Name) + obtenantvariable := &v1alpha1.OBTenantVariable{ + ObjectMeta: metav1.ObjectMeta{ + Name: variableName, + Namespace: m.OBTenant.Namespace, + OwnerReferences: ownerReferenceList, + Labels: labels, + }, + Spec: v1alpha1.OBTenantVariableSpec{ + OBTenant: m.OBTenant.Name, + Variable: variable, + }, + } + m.Logger.V(oceanbaseconst.LogLevelDebug).Info("Create obtenantvariable", "variable", variableName) + err := m.Client.Create(m.Ctx, obtenantvariable) + if err != nil { + m.Logger.Error(err, "create obtenantvariable failed") + return errors.Wrap(err, "create obtenantvariable") + } + return nil +} + +func (m *OBTenantManager) updateOBTenantVariable(variable *apitypes.Variable) error { + return retry.RetryOnConflict(retry.DefaultRetry, func() error { + obtenantvariable := &v1alpha1.OBTenantVariable{} + err := m.Client.Get(m.Ctx, types.NamespacedName{ + Namespace: m.OBTenant.Namespace, + Name: m.generateVariableName(variable.Name), + }, obtenantvariable) + if err != nil { + return errors.Wrap(err, "Get obtenantvariable") + } + obtenantvariable.Spec.Variable.Value = variable.Value + err = m.Client.Update(m.Ctx, obtenantvariable) + if err != nil { + return errors.Wrap(err, "Update obtenantvariable") + } + return nil + }) +} + +func (m *OBTenantManager) deleteOBTenantVariable(variable *apitypes.Variable) error { + obtenantvariable := &v1alpha1.OBTenantVariable{} + err := m.Client.Get(m.Ctx, types.NamespacedName{ + Namespace: m.OBTenant.Namespace, + Name: m.generateVariableName(variable.Name), + }, obtenantvariable) + if err != nil { + return errors.Wrap(err, "Get obtenantvariable") + } + err = m.Client.Delete(m.Ctx, obtenantvariable) + if err != nil { + return errors.Wrap(err, "Delete obtenantvariable") + } + return nil +} diff --git a/internal/resource/obtenantvariable/obtenantvariable_flow.go b/internal/resource/obtenantvariable/obtenantvariable_flow.go new file mode 100644 index 000000000..b6e647f0f --- /dev/null +++ b/internal/resource/obtenantvariable/obtenantvariable_flow.go @@ -0,0 +1,28 @@ +/* +Copyright (c) 2023 OceanBase +ob-operator is licensed under Mulan PSL v2. +You can use this software according to the terms and conditions of the Mulan PSL v2. +You may obtain a copy of Mulan PSL v2 at: + http://license.coscl.org.cn/MulanPSL2 +THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, +EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, +MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. +See the Mulan PSL v2 for more details. +*/ + +package obtenantvariable + +import ( + obtenantvariablestatus "github.com/oceanbase/ob-operator/internal/const/status/obtenantvariable" + tasktypes "github.com/oceanbase/ob-operator/pkg/task/types" +) + +func genSetOBTenantVariableFlow(_ *OBTenantVariableManager) *tasktypes.TaskFlow { + return &tasktypes.TaskFlow{ + OperationContext: &tasktypes.OperationContext{ + Name: "set ob tenant variable", + Tasks: []tasktypes.TaskName{tSetOBTenantVariable}, + TargetStatus: obtenantvariablestatus.Matched, + }, + } +} diff --git a/internal/resource/obtenantvariable/obtenantvariable_manager.go b/internal/resource/obtenantvariable/obtenantvariable_manager.go new file mode 100644 index 000000000..5f75fb1fb --- /dev/null +++ b/internal/resource/obtenantvariable/obtenantvariable_manager.go @@ -0,0 +1,174 @@ +/* +Copyright (c) 2023 OceanBase +ob-operator is licensed under Mulan PSL v2. +You can use this software according to the terms and conditions of the Mulan PSL v2. +You may obtain a copy of Mulan PSL v2 at: + http://license.coscl.org.cn/MulanPSL2 +THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, +EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, +MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. +See the Mulan PSL v2 for more details. +*/ + +package obtenantvariable + +import ( + "context" + + "github.com/go-logr/logr" + "github.com/pkg/errors" + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "sigs.k8s.io/controller-runtime/pkg/client" + + apitypes "github.com/oceanbase/ob-operator/api/types" + v1alpha1 "github.com/oceanbase/ob-operator/api/v1alpha1" + oceanbaseconst "github.com/oceanbase/ob-operator/internal/const/oceanbase" + obtenantvariablestatus "github.com/oceanbase/ob-operator/internal/const/status/obtenantvariable" + "github.com/oceanbase/ob-operator/internal/telemetry" + opresource "github.com/oceanbase/ob-operator/pkg/coordinator" + taskstatus "github.com/oceanbase/ob-operator/pkg/task/const/status" + "github.com/oceanbase/ob-operator/pkg/task/const/strategy" + tasktypes "github.com/oceanbase/ob-operator/pkg/task/types" +) + +var _ opresource.ResourceManager = &OBTenantVariableManager{} + +type OBTenantVariableManager struct { + Ctx context.Context + OBTenantVariable *v1alpha1.OBTenantVariable + Client client.Client + Recorder telemetry.Recorder + Logger *logr.Logger +} + +func (m *OBTenantVariableManager) GetMeta() metav1.Object { + return m.OBTenantVariable.GetObjectMeta() +} + +func (m *OBTenantVariableManager) GetStatus() string { + return m.OBTenantVariable.Status.Status +} + +func (m *OBTenantVariableManager) InitStatus() { + m.Logger.Info("Newly created obtenantvariable, init status") + status := v1alpha1.OBTenantVariableStatus{ + Status: obtenantvariablestatus.New, + Variable: apitypes.Variable{ + Name: m.OBTenantVariable.Spec.Variable.Name, + Value: "", + }, + } + m.OBTenantVariable.Status = status +} + +func (m *OBTenantVariableManager) SetOperationContext(c *tasktypes.OperationContext) { + m.OBTenantVariable.Status.OperationContext = c +} + +func (m *OBTenantVariableManager) GetTaskFlow() (*tasktypes.TaskFlow, error) { + // exists unfinished task flow, return the last task flow + if m.OBTenantVariable.Status.OperationContext != nil { + m.Logger.V(oceanbaseconst.LogLevelTrace).Info("Get task flow from obtenantvariable status") + return tasktypes.NewTaskFlow(m.OBTenantVariable.Status.OperationContext), nil + } + + // return task flow depends on status + + var taskFlow *tasktypes.TaskFlow + m.Logger.V(oceanbaseconst.LogLevelTrace).Info("Create task flow according to obtenantvariable status") + switch m.OBTenantVariable.Status.Status { + // only need to handle variable not match + case obtenantvariablestatus.NotMatch: + taskFlow = genSetOBTenantVariableFlow(m) + default: + m.Logger.V(oceanbaseconst.LogLevelTrace).Info("No need to run anything for obtenantvariable") + return nil, nil + } + + if taskFlow.OperationContext.OnFailure.Strategy == "" { + taskFlow.OperationContext.OnFailure.Strategy = strategy.StartOver + if taskFlow.OperationContext.OnFailure.NextTryStatus == "" { + taskFlow.OperationContext.OnFailure.NextTryStatus = obtenantvariablestatus.Matched + } + } + return taskFlow, nil +} + +func (m *OBTenantVariableManager) CheckAndUpdateFinalizers() error { + return nil +} + +func (m *OBTenantVariableManager) UpdateStatus() error { + operationManager, err := m.getOceanbaseOperationManager() + if err != nil { + m.Logger.Error(err, "Get operation manager failed") + return errors.Wrapf(err, "Get operation manager") + } + variable, err := operationManager.GetGlobalVariable(m.Ctx, m.OBTenantVariable.Spec.Variable.Name) + if err != nil { + m.Logger.Error(err, "Get tenant variable info failed") + return errors.Wrapf(err, "Get tenant variable info") + } + m.OBTenantVariable.Status.Variable = apitypes.Variable{ + Name: variable.Name, + Value: variable.Value, + } + if m.OBTenantVariable.Status.Status != obtenantvariablestatus.NotMatch { + if variable.Value != m.OBTenantVariable.Spec.Variable.Value { + m.OBTenantVariable.Status.Status = obtenantvariablestatus.NotMatch + } else { + m.OBTenantVariable.Status.Status = obtenantvariablestatus.Matched + } + } + err = m.retryUpdateStatus() + if err != nil { + m.Logger.Error(err, "Got error when update obtenantvariable status") + } + return nil +} + +func (m *OBTenantVariableManager) ClearTaskInfo() { + m.OBTenantVariable.Status.Status = obtenantvariablestatus.Matched + m.OBTenantVariable.Status.OperationContext = nil +} + +func (m *OBTenantVariableManager) FinishTask() { + m.OBTenantVariable.Status.Status = m.OBTenantVariable.Status.OperationContext.TargetStatus + m.OBTenantVariable.Status.OperationContext = nil +} + +func (m *OBTenantVariableManager) HandleFailure() { + operationContext := m.OBTenantVariable.Status.OperationContext + failureRule := operationContext.OnFailure + switch failureRule.Strategy { + case strategy.StartOver: + if m.OBTenantVariable.Status.Status != failureRule.NextTryStatus { + m.OBTenantVariable.Status.Status = failureRule.NextTryStatus + m.OBTenantVariable.Status.OperationContext = nil + } else { + m.OBTenantVariable.Status.OperationContext.Idx = 0 + m.OBTenantVariable.Status.OperationContext.TaskStatus = "" + m.OBTenantVariable.Status.OperationContext.TaskId = "" + m.OBTenantVariable.Status.OperationContext.Task = "" + } + case strategy.RetryFromCurrent: + operationContext.TaskStatus = taskstatus.Pending + case strategy.Pause: + } +} + +func (m *OBTenantVariableManager) GetTaskFunc(name tasktypes.TaskName) (tasktypes.TaskFunc, error) { + return taskMap.GetTask(name, m) +} + +func (m *OBTenantVariableManager) PrintErrEvent(err error) { + m.Recorder.Event(m.OBTenantVariable, corev1.EventTypeWarning, "Task failed", err.Error()) +} + +func (m *OBTenantVariableManager) ArchiveResource() { + m.Logger.Info("Archive obtenantvariable", "obtenantvariable", m.OBTenantVariable.Name) + m.Recorder.Event(m.OBTenantVariable, "Archive", "", "Archive obtenantvariable") + m.OBTenantVariable.Status.Status = "Failed" + m.OBTenantVariable.Status.OperationContext = nil +} diff --git a/internal/resource/obtenantvariable/obtenantvariable_task.go b/internal/resource/obtenantvariable/obtenantvariable_task.go new file mode 100644 index 000000000..cf0c71870 --- /dev/null +++ b/internal/resource/obtenantvariable/obtenantvariable_task.go @@ -0,0 +1,39 @@ +/* +Copyright (c) 2023 OceanBase +ob-operator is licensed under Mulan PSL v2. +You can use this software according to the terms and conditions of the Mulan PSL v2. +You may obtain a copy of Mulan PSL v2 at: + http://license.coscl.org.cn/MulanPSL2 +THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, +EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, +MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. +See the Mulan PSL v2 for more details. +*/ + +package obtenantvariable + +import ( + "github.com/pkg/errors" + + "github.com/oceanbase/ob-operator/pkg/helper/converter" + "github.com/oceanbase/ob-operator/pkg/task/builder" + tasktypes "github.com/oceanbase/ob-operator/pkg/task/types" +) + +//go:generate task_register $GOFILE + +var taskMap = builder.NewTaskHub[*OBTenantVariableManager]() + +func SetOBTenantVariable(m *OBTenantVariableManager) tasktypes.TaskError { + operationManager, err := m.getOceanbaseOperationManager() + if err != nil { + m.Logger.Error(err, "Get operation manager failed") + return errors.Wrapf(err, "Get operation manager") + } + err = operationManager.SetGlobalVariable(m.Ctx, m.OBTenantVariable.Spec.Variable.Name, converter.AutoConvert(m.OBTenantVariable.Spec.Variable.Value)) + if err != nil { + m.Logger.Error(err, "Set tenant variable failed") + return errors.Wrapf(err, "Set tenant variable") + } + return nil +} diff --git a/internal/resource/obtenantvariable/obtenantvariable_task_gen.go b/internal/resource/obtenantvariable/obtenantvariable_task_gen.go new file mode 100644 index 000000000..c11a53b8a --- /dev/null +++ b/internal/resource/obtenantvariable/obtenantvariable_task_gen.go @@ -0,0 +1,6 @@ +// Code generated by go generate; DO NOT EDIT. +package obtenantvariable + +func init() { + taskMap.Register(tSetOBTenantVariable, SetOBTenantVariable) +} diff --git a/internal/resource/obtenantvariable/obtenantvariable_taskname_gen.go b/internal/resource/obtenantvariable/obtenantvariable_taskname_gen.go new file mode 100644 index 000000000..647e9fb58 --- /dev/null +++ b/internal/resource/obtenantvariable/obtenantvariable_taskname_gen.go @@ -0,0 +1,8 @@ +// Code generated by go generate; DO NOT EDIT. +package obtenantvariable + +import ttypes "github.com/oceanbase/ob-operator/pkg/task/types" + +const ( + tSetOBTenantVariable ttypes.TaskName = "set obtenant variable" +) diff --git a/internal/resource/obtenantvariable/utils.go b/internal/resource/obtenantvariable/utils.go new file mode 100644 index 000000000..e816d5a28 --- /dev/null +++ b/internal/resource/obtenantvariable/utils.go @@ -0,0 +1,68 @@ +/* +Copyright (c) 2023 OceanBase +ob-operator is licensed under Mulan PSL v2. +You can use this software according to the terms and conditions of the Mulan PSL v2. +You may obtain a copy of Mulan PSL v2 at: + http://license.coscl.org.cn/MulanPSL2 +THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, +EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, +MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. +See the Mulan PSL v2 for more details. +*/ + +package obtenantvariable + +import ( + "github.com/pkg/errors" + "k8s.io/apimachinery/pkg/types" + "k8s.io/client-go/util/retry" + "sigs.k8s.io/controller-runtime/pkg/client" + + v1alpha1 "github.com/oceanbase/ob-operator/api/v1alpha1" + resourceutils "github.com/oceanbase/ob-operator/internal/resource/utils" + "github.com/oceanbase/ob-operator/pkg/oceanbase-sdk/operation" +) + +func (m *OBTenantVariableManager) generateNamespacedName(name string) types.NamespacedName { + var namespacedName types.NamespacedName + namespacedName.Namespace = m.OBTenantVariable.Namespace + namespacedName.Name = name + return namespacedName +} + +func (m *OBTenantVariableManager) getOBTenant() (*v1alpha1.OBTenant, error) { + obtenant := &v1alpha1.OBTenant{} + err := m.Client.Get(m.Ctx, m.generateNamespacedName(m.OBTenantVariable.Spec.OBTenant), obtenant) + if err != nil { + return nil, errors.Wrap(err, "get obtenant") + } + return obtenant, nil +} + +func (m *OBTenantVariableManager) getOceanbaseOperationManager() (*operation.OceanbaseOperationManager, error) { + obtenant, err := m.getOBTenant() + if err != nil { + return nil, errors.Wrap(err, "Get obcluster from K8s") + } + obcluster := &v1alpha1.OBCluster{} + err = m.Client.Get(m.Ctx, m.generateNamespacedName(obtenant.Spec.ClusterName), obcluster) + if err != nil { + return nil, errors.Wrap(err, "Get obcluster from K8s") + } + return resourceutils.GetTenantRootOperationClient(m.Client, m.Logger, obcluster, obtenant.Spec.TenantName, obtenant.Status.Credentials.Root) +} + +func (m *OBTenantVariableManager) retryUpdateStatus() error { + return retry.RetryOnConflict(retry.DefaultRetry, func() error { + variable := &v1alpha1.OBTenantVariable{} + err := m.Client.Get(m.Ctx, types.NamespacedName{ + Namespace: m.OBTenantVariable.GetNamespace(), + Name: m.OBTenantVariable.GetName(), + }, variable) + if err != nil { + return client.IgnoreNotFound(err) + } + variable.Status = *m.OBTenantVariable.Status.DeepCopy() + return m.Client.Status().Update(m.Ctx, variable) + }) +} diff --git a/make/build.mk b/make/build.mk index 44b426440..d0bc12f01 100644 --- a/make/build.mk +++ b/make/build.mk @@ -8,7 +8,7 @@ build: dashboard-doc-gen dashboard-bindata-gen cli-bindata-gen manifests generat # (i.e. docker build --platform linux/arm64 ). However, you must enable docker buildKit for it. # More info: https://docs.docker.com/develop/develop-images/build_enhancements/ .PHONY: docker-build -docker-build: ## Build docker image with the manager. +docker-build: generate ## Build docker image with the manager. docker build -t ${IMG} --build-arg GOPROXY=${GOPROXY} --build-arg GOSUMDB=${GOSUMDB} --build-arg RACE=${RACE} -f build/Dockerfile.operator . .PHONY: docker-push diff --git a/make/deps.mk b/make/deps.mk index a6cedb1e4..7aaa0e988 100644 --- a/make/deps.mk +++ b/make/deps.mk @@ -7,6 +7,7 @@ $(LOCALBIN): ## Location to install dependencies to ## Tool Binaries KUSTOMIZE ?= $(LOCALBIN)/kustomize CONTROLLER_GEN ?= $(LOCALBIN)/controller-gen +KUBEBUILDER ?= $(LOCALBIN)/kubebuilder ENVTEST ?= $(LOCALBIN)/setup-envtest ## Tool Versions @@ -23,6 +24,11 @@ $(KUSTOMIZE): $(LOCALBIN) fi test -s $(LOCALBIN)/kustomize || { curl -Ss $(KUSTOMIZE_INSTALL_SCRIPT) --output install_kustomize.sh && bash install_kustomize.sh $(subst v,,$(KUSTOMIZE_VERSION)) $(LOCALBIN); rm install_kustomize.sh; } +.PHONY: kubebuilder +kubebuilder: + test -s $(LOCALBIN)/kubebuilder || mkdir -p $(LOCALBIN) && \ + curl -L -o $(LOCALBIN)/kubebuilder "https://go.kubebuilder.io/dl/latest/$(go env GOOS)/$(go env GOARCH)" && chmod +x $(LOCALBIN)/kubebuilder + .PHONY: controller-gen controller-gen: $(CONTROLLER_GEN) ## Download controller-gen locally if necessary. If wrong version is installed, it will be overwritten. $(CONTROLLER_GEN): $(LOCALBIN) @@ -39,7 +45,7 @@ install-delve: ## Install delve, a debugger for the Go programming language. Mor go install github.com/go-delve/delve/cmd/dlv@master .PHONY: tools -tools: kustomize controller-gen envtest ## Download all tools +tools: kubebuilder kustomize controller-gen envtest ## Download all tools .PHONY: init-generator init-generator: ## Install generator tools diff --git a/pkg/helper/converter/converter.go b/pkg/helper/converter/converter.go index 5d659de90..3dc99cb8f 100644 --- a/pkg/helper/converter/converter.go +++ b/pkg/helper/converter/converter.go @@ -15,6 +15,7 @@ package converter import ( "fmt" "math" + "strconv" ) func ConvertToString(value any) string { @@ -40,3 +41,20 @@ func ConvertFloat(value any) any { return v } } + +func AutoConvert(value string) any { + // try parse to int + if ret, err := strconv.Atoi(value); err == nil { + return ret + } + // try parse to float64 + if ret, err := strconv.ParseFloat(value, 64); err == nil { + return ret + } + // try parse to bool + if ret, err := strconv.ParseBool(value); err == nil { + return ret + } + // return string value + return value +} diff --git a/pkg/oceanbase-sdk/const/sql/tenant.go b/pkg/oceanbase-sdk/const/sql/tenant.go index 48be009ab..8cb431558 100644 --- a/pkg/oceanbase-sdk/const/sql/tenant.go +++ b/pkg/oceanbase-sdk/const/sql/tenant.go @@ -27,7 +27,6 @@ const ( GetResourceTotal = "SELECT cpu_capacity, mem_capacity, data_disk_capacity FROM oceanbase.GV$OB_SERVERS;" GetCharset = "SELECT CHARSET('oceanbase') as charset;" - GetVariableLike = "SHOW VARIABLES LIKE ?;" GetRsJob = "select job_id, job_type, job_status, tenant_id from DBA_OB_TENANT_JOBS where tenant_name=? and job_status ='INPROGRESS' and job_type='ALTER_TENANT_LOCALITY'" GetObVersion = "SELECT ob_version() as version;" diff --git a/pkg/oceanbase-sdk/const/sql/variable.go b/pkg/oceanbase-sdk/const/sql/variable.go index 8de9ca3a4..dae9685cc 100644 --- a/pkg/oceanbase-sdk/const/sql/variable.go +++ b/pkg/oceanbase-sdk/const/sql/variable.go @@ -13,5 +13,6 @@ See the Mulan PSL v2 for more details. package sql const ( + GetGlobalVariable = "select name, coalesce(value, \"\") as value from DBA_OB_SYS_VARIABLES where scope like '%global%' and name = ?" SetGlobalVariable = "set global %s = ?" ) diff --git a/pkg/oceanbase-sdk/model/tenant.go b/pkg/oceanbase-sdk/model/tenant.go index bc3e32271..6807e286b 100644 --- a/pkg/oceanbase-sdk/model/tenant.go +++ b/pkg/oceanbase-sdk/model/tenant.go @@ -73,11 +73,6 @@ type Charset struct { Charset string `json:"charset" db:"charset"` } -type Variable struct { - VariableName string `json:"Variable_name" db:"Variable_name"` - Value string `json:"Value" db:"Value"` -} - type RsJob struct { JobID int64 `json:"job_id" db:"job_id"` JobType string `json:"job_type" db:"job_type"` diff --git a/pkg/oceanbase-sdk/model/variable.go b/pkg/oceanbase-sdk/model/variable.go new file mode 100644 index 000000000..816c1e3ae --- /dev/null +++ b/pkg/oceanbase-sdk/model/variable.go @@ -0,0 +1,18 @@ +/* +Copyright (c) 2023 OceanBase +ob-operator is licensed under Mulan PSL v2. +You can use this software according to the terms and conditions of the Mulan PSL v2. +You may obtain a copy of Mulan PSL v2 at: + http://license.coscl.org.cn/MulanPSL2 +THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, +EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, +MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. +See the Mulan PSL v2 for more details. +*/ + +package model + +type Variable struct { + Name string `json:"name" db:"name"` + Value string `json:"value" db:"value"` +} diff --git a/pkg/oceanbase-sdk/operation/tenant.go b/pkg/oceanbase-sdk/operation/tenant.go index 4fde9a95b..c4ef2b465 100644 --- a/pkg/oceanbase-sdk/operation/tenant.go +++ b/pkg/oceanbase-sdk/operation/tenant.go @@ -130,15 +130,6 @@ func (m *OceanbaseOperationManager) GetCharset(ctx context.Context) (*model.Char return charset, nil } -func (m *OceanbaseOperationManager) GetVariable(ctx context.Context, name string) (*model.Variable, error) { - variable := &model.Variable{} - err := m.QueryRow(ctx, variable, sql.GetVariableLike, name) - if err != nil { - return variable, errors.Wrap(err, "Get variable") - } - return variable, nil -} - func (m *OceanbaseOperationManager) GetRsJob(ctx context.Context, reJobName string) (*model.RsJob, error) { rsJob := &model.RsJob{} err := m.QueryRow(ctx, rsJob, sql.GetRsJob, reJobName) diff --git a/pkg/oceanbase-sdk/operation/variable.go b/pkg/oceanbase-sdk/operation/variable.go index 5f1a1c5e4..041c41ec4 100644 --- a/pkg/oceanbase-sdk/operation/variable.go +++ b/pkg/oceanbase-sdk/operation/variable.go @@ -17,9 +17,16 @@ import ( "fmt" "github.com/oceanbase/ob-operator/pkg/oceanbase-sdk/const/sql" + "github.com/oceanbase/ob-operator/pkg/oceanbase-sdk/model" ) func (m *OceanbaseOperationManager) SetGlobalVariable(ctx context.Context, name string, value any) error { setGlobalVariableSql := fmt.Sprintf(sql.SetGlobalVariable, name) return m.ExecWithDefaultTimeout(ctx, setGlobalVariableSql, value) } + +func (m *OceanbaseOperationManager) GetGlobalVariable(ctx context.Context, name string) (*model.Variable, error) { + variable := &model.Variable{} + err := m.QueryRow(ctx, variable, sql.GetGlobalVariable, name) + return variable, err +}