This is an automated email from the ASF dual-hosted git repository. duanzhengqiang pushed a commit to branch main in repository https://gitbox.apache.org/repos/asf/shardingsphere-on-cloud.git
commit 99b6471a85865c5b4e55def84d174bb3362e021a Author: Ghoul_Lee <[email protected]> AuthorDate: Thu May 5 18:50:06 2022 +0800 update some status logic (#6) * ADD: Get cascading resources status and update to CRD status. UPDATE: Change the names of some fields. Log time format. * UPDATE: ADD some Status description .Update status function. * FIX: About Status.Conditions * FIX: Ignore deleting pod * FIX: Init process about Annotations * FIX: Fix typo in log err message * ADD: Update proxy CRD cascaded resource logic FIX: Fix some logs format UPDATE: Status logic and update some status logic function * UPDATE: Status logic and update some status logic function * UPDATE: change some func name --- api/v1alpha1/groupversion_info.go | 28 ++-- api/v1alpha1/proxy_status.go | 78 ++++++++--- api/v1alpha1/proxy_types.go | 31 +++-- api/v1alpha1/proxyconfig_types.go | 28 ++-- api/v1alpha1/serverconfig.go | 16 +++ .../shardingsphere.sphere-ex.com_proxies.yaml | 21 +-- .../shardingsphere.sphere-ex.com_proxyconfigs.yaml | 4 +- config/rbac/role.yaml | 12 ++ config/samples/shardingsphere_v1alpha1_proxy.yaml | 4 +- main.go | 31 ++--- pkg/controllers/proxy_controller.go | 148 +++++++++++++-------- pkg/controllers/proxyconfig_controller.go | 80 +++++------ pkg/controllers/suite_test.go | 28 ++-- pkg/reconcile/resource.go | 62 +++++---- pkg/reconcile/status.go | 54 ++++++++ 15 files changed, 394 insertions(+), 231 deletions(-) diff --git a/api/v1alpha1/groupversion_info.go b/api/v1alpha1/groupversion_info.go index f5e12b4..319ac03 100644 --- a/api/v1alpha1/groupversion_info.go +++ b/api/v1alpha1/groupversion_info.go @@ -1,18 +1,18 @@ /* -Copyright 2022. - -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. -*/ + * Copyright (c) 2022. + * + * 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 contains API Schema definitions for the shardingsphere v1alpha1 API group //+kubebuilder:object:generate=true diff --git a/api/v1alpha1/proxy_status.go b/api/v1alpha1/proxy_status.go index c788e6f..12adbef 100644 --- a/api/v1alpha1/proxy_status.go +++ b/api/v1alpha1/proxy_status.go @@ -1,3 +1,19 @@ +/* + * Copyright (c) 2022. + * + * 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 ( @@ -15,9 +31,10 @@ const ( type ConditionType string const ( - ConditionProcessing ConditionType = "Processing" - ConditionRunning ConditionType = "Running" - ConditionUnknown ConditionType = "Unknown" + ConditionInitialized ConditionType = "Initialized" + ConditionStarted ConditionType = "Started" + ConditionReady ConditionType = "Ready" + ConditionUnknown ConditionType = "Unknown" ) // ProxyStatus defines the observed state of Proxy @@ -29,9 +46,7 @@ type ProxyStatus struct { // TODO:description Conditions Conditions `json:"conditions"` // TODO:description - AvailableNodes int32 `json:"availableNodes"` - // TODO:description - Version string `json:"version"` + ReadyNodes int32 `json:"readyNodes"` } type Conditions []Condition @@ -42,32 +57,59 @@ type Condition struct { LastUpdateTime metav1.Time `json:"lastUpdateTime,omitempty"` } -func (p *Proxy) SetInitStatus() { +func (p *Proxy) SetInitialized() { p.Status.Phase = StatusNotReady - p.Status.Conditions = append(p.Status.Conditions, Condition{ - Type: ConditionProcessing, + p.Status.Conditions = append([]Condition{}, Condition{ + Type: ConditionInitialized, Status: v1.ConditionTrue, LastUpdateTime: metav1.Now(), }) - p.Status.AvailableNodes = 0 - p.Status.Version = p.Spec.Version } -func (p *Proxy) SetInitFailed() { - p.Status.Conditions = append(p.Status.Conditions, Condition{ - Type: ConditionProcessing, +func (p *Proxy) SetInitializationFailed() { + p.Status.Phase = StatusNotReady + p.Status.Conditions = append([]Condition{}, Condition{ + Type: ConditionInitialized, Status: v1.ConditionFalse, LastUpdateTime: metav1.Now(), }) } -func (p *Proxy) SetRunningButNotready(readyCount int32) { +func (p *Proxy) SetPodStarted(readyNodes int32) { p.Status.Phase = StatusNotReady p.Status.Conditions = append([]Condition{}, Condition{ - Type: ConditionRunning, + Type: ConditionStarted, + Status: v1.ConditionTrue, + LastUpdateTime: metav1.Now(), + }) + p.Status.ReadyNodes = readyNodes +} + +func (p *Proxy) SetPodNotStarted() { + p.Status.Phase = StatusNotReady + p.Status.Conditions = append([]Condition{}, Condition{ + Type: ConditionStarted, Status: v1.ConditionFalse, LastUpdateTime: metav1.Now(), }) - p.Status.AvailableNodes = readyCount - p.Status.Version = p.Spec.Version +} + +func (p *Proxy) SetReady(readyNodes int32) { + p.Status.Phase = StatusReady + p.Status.Conditions = append([]Condition{}, Condition{ + Type: ConditionReady, + Status: v1.ConditionTrue, + LastUpdateTime: metav1.Now(), + }) + p.Status.ReadyNodes = readyNodes + +} + +func (p *Proxy) SetFailed() { + p.Status.Phase = StatusNotReady + p.Status.Conditions = append([]Condition{}, Condition{ + Type: ConditionUnknown, + Status: v1.ConditionTrue, + LastUpdateTime: metav1.Now(), + }) } diff --git a/api/v1alpha1/proxy_types.go b/api/v1alpha1/proxy_types.go index 22c4c5f..5b5e569 100644 --- a/api/v1alpha1/proxy_types.go +++ b/api/v1alpha1/proxy_types.go @@ -1,18 +1,18 @@ /* -Copyright 2022. - -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. -*/ + * Copyright (c) 2022. + * + * 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 @@ -64,8 +64,7 @@ type ProxySpec struct { StartupProbe *v1.Probe `json:"startupProbe,omitempty"` } -//+kubebuilder:printcolumn:JSONPath=".status.availableNodes",name=AvailableNodes,type=string -//+kubebuilder:printcolumn:JSONPath=".status.version",name=Version,type=string +//+kubebuilder:printcolumn:JSONPath=".status.readyNodes",name=ReadyNodes,type=integer //+kubebuilder:printcolumn:JSONPath=".status.phase",name=Phase,type=string //+kubebuilder:object:root=true //+kubebuilder:subresource:status diff --git a/api/v1alpha1/proxyconfig_types.go b/api/v1alpha1/proxyconfig_types.go index 02108ad..59156e3 100644 --- a/api/v1alpha1/proxyconfig_types.go +++ b/api/v1alpha1/proxyconfig_types.go @@ -1,18 +1,18 @@ /* -Copyright 2022. - -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. -*/ + * Copyright (c) 2022. + * + * 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 diff --git a/api/v1alpha1/serverconfig.go b/api/v1alpha1/serverconfig.go index a2cb8d7..b4f4518 100644 --- a/api/v1alpha1/serverconfig.go +++ b/api/v1alpha1/serverconfig.go @@ -1,3 +1,19 @@ +/* + * Copyright (c) 2022. + * + * 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 // User TODO: description diff --git a/config/crd/bases/shardingsphere.sphere-ex.com_proxies.yaml b/config/crd/bases/shardingsphere.sphere-ex.com_proxies.yaml index a0b16f7..4ba4dec 100644 --- a/config/crd/bases/shardingsphere.sphere-ex.com_proxies.yaml +++ b/config/crd/bases/shardingsphere.sphere-ex.com_proxies.yaml @@ -16,12 +16,9 @@ spec: scope: Namespaced versions: - additionalPrinterColumns: - - jsonPath: .status.availableNodes - name: AvailableNodes - type: string - - jsonPath: .status.version - name: Version - type: string + - jsonPath: .status.readyNodes + name: ReadyNodes + type: integer - jsonPath: .status.phase name: Phase type: string @@ -542,10 +539,6 @@ spec: status: description: ProxyStatus defines the observed state of Proxy properties: - availableNodes: - description: TODO:description - format: int32 - type: integer conditions: description: TODO:description items: @@ -567,14 +560,14 @@ spec: of cluster Important: Run "make" to regenerate code after modifying this file TODO:description' type: string - version: + readyNodes: description: TODO:description - type: string + format: int32 + type: integer required: - - availableNodes - conditions - phase - - version + - readyNodes type: object type: object served: true diff --git a/config/crd/bases/shardingsphere.sphere-ex.com_proxyconfigs.yaml b/config/crd/bases/shardingsphere.sphere-ex.com_proxyconfigs.yaml index 3536493..2817fd0 100644 --- a/config/crd/bases/shardingsphere.sphere-ex.com_proxyconfigs.yaml +++ b/config/crd/bases/shardingsphere.sphere-ex.com_proxyconfigs.yaml @@ -39,7 +39,7 @@ spec: spec: description: ProxyConfigSpec defines the desired state of ProxyConfig properties: - AUTHORITY: + authority: description: 'Auth TODO: description' properties: provider: @@ -124,7 +124,7 @@ spec: type: integer type: object required: - - AUTHORITY + - authority - mode type: object status: diff --git a/config/rbac/role.yaml b/config/rbac/role.yaml index b2711b0..b5840f8 100644 --- a/config/rbac/role.yaml +++ b/config/rbac/role.yaml @@ -5,6 +5,18 @@ metadata: creationTimestamp: null name: manager-role rules: +- apiGroups: + - "" + resources: + - configmap + verbs: + - create + - delete + - get + - list + - patch + - update + - watch - apiGroups: - "" resources: diff --git a/config/samples/shardingsphere_v1alpha1_proxy.yaml b/config/samples/shardingsphere_v1alpha1_proxy.yaml index 61a1776..aaad174 100644 --- a/config/samples/shardingsphere_v1alpha1_proxy.yaml +++ b/config/samples/shardingsphere_v1alpha1_proxy.yaml @@ -6,12 +6,12 @@ spec: version: "5.1.0" serviceType: type: ClusterIP - replicas: 1 + replicas: 2 proxyConfigName: "sharding-proxy" port: 3307 mySQLDriver: version: "5.1.47" - resource: + resources: limits: cpu: "2" memory: "2Gi" diff --git a/main.go b/main.go index d2ece79..9bba22c 100644 --- a/main.go +++ b/main.go @@ -1,25 +1,25 @@ /* -Copyright 2022. - -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. -*/ + * Copyright (c) 2022. + * + * 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 main import ( "flag" + "go.uber.org/zap/zapcore" "os" - "sphere-ex.com/shardingsphere-operator/pkg/controllers" // Import all Kubernetes client auth plugins (e.g. Azure, GCP, OIDC, etc.) @@ -60,6 +60,7 @@ func main() { "Enabling this will ensure there is only one active controller manager.") opts := zap.Options{ Development: true, + TimeEncoder: zapcore.RFC3339TimeEncoder, } opts.BindFlags(flag.CommandLine) flag.Parse() diff --git a/pkg/controllers/proxy_controller.go b/pkg/controllers/proxy_controller.go index f4fd915..a32612c 100644 --- a/pkg/controllers/proxy_controller.go +++ b/pkg/controllers/proxy_controller.go @@ -1,18 +1,18 @@ /* -Copyright 2022. - -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. -*/ + * Copyright (c) 2022. + * + * 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 controllers @@ -20,9 +20,7 @@ import ( "context" appsv1 "k8s.io/api/apps/v1" v1 "k8s.io/api/core/v1" - "k8s.io/apimachinery/pkg/api/equality" apierrors "k8s.io/apimachinery/pkg/api/errors" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime" ctrl "sigs.k8s.io/controller-runtime" "sigs.k8s.io/controller-runtime/pkg/client" @@ -33,7 +31,9 @@ import ( ) const ( - SyncBuildStatusInterval = 5 * time.Second + //WaitingForReady Time selection reference kubelet restart time + WaitingForReady = 10 * time.Second + MaxRestartedCount = int32(5) ) // ProxyReconciler reconciles a Proxy object @@ -55,63 +55,93 @@ type ProxyReconciler struct { func (r *ProxyReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { log := logger.FromContext(ctx) - run := &shardingspherev1alpha1.Proxy{} + run := &shardingspherev1alpha1.Proxy{} err := r.Get(ctx, req.NamespacedName, run) if apierrors.IsNotFound(err) { - log.Error(err, "Proxy in work queue no longer exists!") - return ctrl.Result{}, client.IgnoreNotFound(err) + log.Info("Resource in work queue no longer exists!") + return ctrl.Result{}, nil } else if err != nil { + log.Error(err, "Error getting CRD resource") return ctrl.Result{}, err } - originStatus := run.Status.DeepCopy() - if run.Status.Phase == "" || len(run.Status.Conditions) == 0 { - run.SetInitStatus() - dp := reconcile.ConstructCascadingDeployment(run) - err = r.Create(ctx, dp) + + runtimeDeployment := &appsv1.Deployment{} + err = r.Get(ctx, req.NamespacedName, runtimeDeployment) + if apierrors.IsNotFound(err) { + cascadingDeployment := reconcile.ConstructCascadingDeployment(run) + err = r.Create(ctx, cascadingDeployment) if err != nil { - if apierrors.IsAlreadyExists(err) { - log.Error(err, "Deployment no longer exists!") - } else if err != nil { - run.SetInitFailed() - _ = r.Status().Update(ctx, run) - log.Error(err, "Create Resources Deployment Error") - return ctrl.Result{RequeueAfter: SyncBuildStatusInterval}, err - } + run.SetInitializationFailed() + _ = r.Status().Update(ctx, run) + log.Error(err, "Error creating cascaded deployment") + return ctrl.Result{}, err } - svc := reconcile.ConstructCascadingService(run) - err = r.Create(ctx, svc) + } else if err != nil { + log.Error(err, "Error getting cascaded deployment") + return ctrl.Result{}, err + } + + // TODO: Whether the service needs to be corrected + runtimeService := &v1.Service{} + err = r.Get(ctx, req.NamespacedName, runtimeService) + if apierrors.IsNotFound(err) { + cascadingService := reconcile.ConstructCascadingService(run) + err = r.Create(ctx, cascadingService) if err != nil { - if apierrors.IsAlreadyExists(err) { - log.Error(err, "Service no longer exists!") - } else { - run.SetInitFailed() - _ = r.Status().Update(ctx, run) - log.Error(err, "Create Resources Service Error") - return ctrl.Result{RequeueAfter: SyncBuildStatusInterval}, err - } + run.SetInitializationFailed() + _ = r.Status().Update(ctx, run) + log.Error(err, "Error creating cascaded service") + return ctrl.Result{}, err } - run.Annotations["ResourcesInit"] = "true" - run.Annotations["UpdateTime"] = metav1.Now().Format(metav1.RFC3339Micro) - } - if equality.Semantic.DeepEqual(originStatus, run.Status) { - log.Info(" status are equal... ", "Status", run.Status) - return ctrl.Result{RequeueAfter: SyncBuildStatusInterval}, nil - } - err = r.Status().Update(ctx, run) - if err != nil { - log.Error(err, "Update CRD Status Error") + run.SetInitialized() + return ctrl.Result{RequeueAfter: WaitingForReady}, nil + } else if err != nil { + log.Error(err, "Error getting cascaded service") return ctrl.Result{}, err } - err = r.Update(ctx, run) + + podList := &v1.PodList{} + err = r.List(ctx, podList, client.InNamespace(req.Namespace), client.MatchingLabels(map[string]string{"apps": req.Name})) if err != nil { - log.Error(err, "Update CRD Resources Error") + log.Error(err, "Error listing cascaded pod") return ctrl.Result{}, err } - log.Info("run spec is ", "spec", run.Spec) - log.Info("run status is ", "status", run.Status) - return ctrl.Result{}, nil + result := ctrl.Result{} + if reconcile.IsRunning(podList) { + readyNodes := reconcile.CountingReadyPods(podList) + if readyNodes != run.Spec.Replicas { + restartTimes := reconcile.CountingPodMaxRestartTimes(podList) + if restartTimes > MaxRestartedCount { + run.SetFailed() + _ = r.Status().Update(ctx, run) + log.Error(nil, "The times of restarts exceeds the threshold") + } + result.RequeueAfter = (time.Duration(restartTimes) + 1) * WaitingForReady + if readyNodes != run.Status.ReadyNodes { + run.SetPodStarted(readyNodes) + } + } else { + if run.Status.Phase != shardingspherev1alpha1.StatusReady { + log.Info("Status is now ready!") + run.SetReady(readyNodes) + } + } + } else { + // TODO: Waiting for pods to start exceeds the maximum number of retries + run.SetPodNotStarted() + result.RequeueAfter = WaitingForReady + } + + // TODO: Compare Status with or without modification + err = r.Status().Update(ctx, run) + if err != nil { + log.Error(err, "Error updating status") + return result, err + } + log.Info("RuntimeCRD status ", "status", run.Status) + return result, nil } // SetupWithManager sets up the controller with the Manager. @@ -119,6 +149,6 @@ func (r *ProxyReconciler) SetupWithManager(mgr ctrl.Manager) error { return ctrl.NewControllerManagedBy(mgr). For(&shardingspherev1alpha1.Proxy{}). Owns(&appsv1.Deployment{}). - Owns(&v1.Service{}). + Owns(&v1.Pod{}). Complete(r) } diff --git a/pkg/controllers/proxyconfig_controller.go b/pkg/controllers/proxyconfig_controller.go index 043087a..184b6b2 100644 --- a/pkg/controllers/proxyconfig_controller.go +++ b/pkg/controllers/proxyconfig_controller.go @@ -1,18 +1,18 @@ /* -Copyright 2022. - -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. -*/ + * Copyright (c) 2022. + * + * 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 controllers @@ -40,6 +40,7 @@ type ProxyConfigReconciler struct { //+kubebuilder:rbac:groups=shardingsphere.sphere-ex.com,resources=proxyconfigs,verbs=get;list;watch;create;update;patch;delete //+kubebuilder:rbac:groups=shardingsphere.sphere-ex.com,resources=proxyconfigs/status,verbs=get;update;patch //+kubebuilder:rbac:groups=shardingsphere.sphere-ex.com,resources=proxyconfigs/finalizers,verbs=update +//+kubebuilder:rbac:groups="",resources=configmap,verbs=get;list;watch;create;update;patch;delete // Reconcile is part of the main kubernetes reconciliation loop which aims to // move the current state of the cluster closer to the desired state. @@ -56,51 +57,52 @@ func (r *ProxyConfigReconciler) Reconcile(ctx context.Context, req ctrl.Request) run := &shardingspherev1alpha1.ProxyConfig{} err := r.Get(ctx, req.NamespacedName, run) if apierrors.IsNotFound(err) { - log.Error(err, "ProxyConfig in work queue no longer exists!") + log.Info("Resource in work queue no longer exists!") return ctrl.Result{}, nil } else if err != nil { - log.Error(err, "Get CRD Resource Error") - return ctrl.Result{RequeueAfter: SyncBuildStatusInterval}, err + log.Error(err, "Error getting CRD resource") + return ctrl.Result{}, err } cm := &v1.ConfigMap{} configmap := reconcile.ConstructCascadingConfigmap(run) err = r.Get(ctx, req.NamespacedName, cm) - if err != nil { - if apierrors.IsNotFound(err) { - log.Info("Create the configmap") - err = r.Create(ctx, configmap) - if err != nil { - log.Error(err, "Create Configmap Resource Error") - return ctrl.Result{RequeueAfter: SyncBuildStatusInterval}, err - } - run.SetMetadataRepository(run.Spec.ClusterConfig.Repository.Type) - err = r.Status().Update(ctx, run) - if err != nil { - log.Error(err, "Update CRD Resource Status Error") - return ctrl.Result{RequeueAfter: SyncBuildStatusInterval}, err - } - return ctrl.Result{}, nil - } else { - log.Error(err, "Get Configmap Resource Error") - return ctrl.Result{RequeueAfter: SyncBuildStatusInterval}, err + if apierrors.IsNotFound(err) { + log.Info("Creating cascaded configmap") + err = r.Create(ctx, configmap) + if err != nil { + log.Error(err, "Error creating cascaded configmap") + return ctrl.Result{}, err + } + run.SetMetadataRepository(run.Spec.ClusterConfig.Repository.Type) + err = r.Status().Update(ctx, run) + if err != nil { + log.Error(err, "Error updating CRD resource status") + return ctrl.Result{}, err } + return ctrl.Result{}, nil + } else if err != nil { + log.Error(err, "Error getting cascaded configmap") + return ctrl.Result{}, err } + if !equality.Semantic.DeepEqual(configmap.Data, cm.Data) { cm = configmap log.Info("Update or correct the configmap") err = r.Update(ctx, configmap) if err != nil { - log.Error(err, "Update Configmap Resource Error") - return ctrl.Result{RequeueAfter: SyncBuildStatusInterval}, err + log.Error(err, "Error updating cascaded configmap") + // 重新排队为了处理冲突错误 + // TODO: Error handling for conflict errors alone + return ctrl.Result{Requeue: true}, err } } if run.Status.MetadataRepository != run.Spec.ClusterConfig.Repository.Type || run.Status.MetadataRepository == "" { run.SetMetadataRepository(run.Spec.ClusterConfig.Repository.Type) err = r.Status().Update(ctx, run) if err != nil { - log.Error(err, "Update CRD Resource Status Error") - return ctrl.Result{RequeueAfter: SyncBuildStatusInterval}, err + log.Error(err, "Error updating CRD resource status") + return ctrl.Result{}, err } } return ctrl.Result{}, nil diff --git a/pkg/controllers/suite_test.go b/pkg/controllers/suite_test.go index 2b623a7..abac13c 100644 --- a/pkg/controllers/suite_test.go +++ b/pkg/controllers/suite_test.go @@ -1,18 +1,18 @@ /* -Copyright 2022. - -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. -*/ + * Copyright (c) 2022. + * + * 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 controllers diff --git a/pkg/reconcile/resource.go b/pkg/reconcile/resource.go index 5f4cc04..3eec9b8 100644 --- a/pkg/reconcile/resource.go +++ b/pkg/reconcile/resource.go @@ -1,3 +1,19 @@ +/* + * Copyright (c) 2022. + * + * 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 reconcile import ( @@ -30,13 +46,13 @@ func ConstructCascadingDeployment(proxy *shardingspherev1alpha1.Proxy) *appsv1.D Replicas: &proxy.Spec.Replicas, Selector: &metav1.LabelSelector{ MatchLabels: map[string]string{ - "apps": "proxy-" + proxy.Name, + "apps": proxy.Name, }, }, Template: v1.PodTemplateSpec{ ObjectMeta: metav1.ObjectMeta{ Labels: map[string]string{ - "apps": "proxy-" + proxy.Name, + "apps": proxy.Name, }, }, Spec: v1.PodSpec{ @@ -61,10 +77,6 @@ func ConstructCascadingDeployment(proxy *shardingspherev1alpha1.Proxy) *appsv1.D Name: "config", MountPath: "/opt/shardingsphere-proxy/conf", }, - { - Name: "mysql-connect-jar", - MountPath: "/opt/shardingsphere-proxy/ext-lib", - }, }, }, }, @@ -79,12 +91,6 @@ func ConstructCascadingDeployment(proxy *shardingspherev1alpha1.Proxy) *appsv1.D }, }, }, - { - Name: "mysql-connect-jar", - VolumeSource: v1.VolumeSource{ - EmptyDir: &v1.EmptyDirVolumeSource{}, - }, - }, }, }, }, @@ -100,16 +106,13 @@ func ConstructCascadingService(proxy *shardingspherev1alpha1.Proxy) *v1.Service ObjectMeta: metav1.ObjectMeta{ Name: proxy.Name, Namespace: proxy.Namespace, - Annotations: map[string]string{ - "UpdateTime": metav1.Now().Format(metav1.RFC3339Micro), - }, OwnerReferences: []metav1.OwnerReference{ *metav1.NewControllerRef(proxy.GetObjectMeta(), proxy.GroupVersionKind()), }, }, Spec: v1.ServiceSpec{ Selector: map[string]string{ - "apps": "proxy-" + proxy.Name, + "apps": proxy.Name, }, Type: proxy.Spec.ServiceType.Type, Ports: []v1.ServicePort{ @@ -130,7 +133,7 @@ func ConstructCascadingService(proxy *shardingspherev1alpha1.Proxy) *v1.Service return &svc } -func addInitContainer(dp *appsv1.Deployment, mysql *shardingspherev1alpha1.MySQLDriver) *appsv1.Deployment { +func addInitContainer(dp *appsv1.Deployment, mysql *shardingspherev1alpha1.MySQLDriver) { scriptStr := strings.Builder{} t1, _ := template.New("shell").Parse(`wget https://repo1.maven.org/maven2/mysql/mysql-connector-java/{{ .Version }}/mysql-connector-java-{{ .Version }}.jar; wget https://repo1.maven.org/maven2/mysql/mysql-connector-java/{{ .Version }}/mysql-connector-java-{{ .Version }}.jar.md5; @@ -151,15 +154,26 @@ else echo failed;exit 1;fi;mv /mysql-connector-java-{{ .Version }}.jar /opt/shar }, }, } - return dp + dp.Spec.Template.Spec.Containers[0].VolumeMounts = append(dp.Spec.Template.Spec.Containers[0].VolumeMounts, v1.VolumeMount{ + Name: "mysql-connect-jar", + MountPath: "/opt/shardingsphere-proxy/ext-lib", + }, + ) + + dp.Spec.Template.Spec.Volumes = append(dp.Spec.Template.Spec.Volumes, v1.Volume{ + Name: "mysql-connect-jar", + VolumeSource: v1.VolumeSource{ + EmptyDir: &v1.EmptyDirVolumeSource{}, + }, + }) + } func processOptionalParameter(proxy *shardingspherev1alpha1.Proxy, dp *appsv1.Deployment) *appsv1.Deployment { if proxy.Spec.MySQLDriver != nil { - dp = addInitContainer(dp, proxy.Spec.MySQLDriver) + addInitContainer(dp, proxy.Spec.MySQLDriver) } - //TODO: 更好的实现默认值添加和非默认值赋值 if proxy.Spec.Resources != nil { dp.Spec.Template.Spec.Containers[0].Resources = *proxy.Spec.Resources } else { @@ -234,10 +248,10 @@ func ConstructCascadingConfigmap(proxyConfig *shardingspherev1alpha1.ProxyConfig // ToYaml Convert ProxyConfig spec content to yaml format func toYaml(proxyConfig *shardingspherev1alpha1.ProxyConfig) string { - for i := 0; i < len(proxyConfig.Spec.AUTHORITY.Users); i++ { - proxyConfig.Spec.AUTHORITY.Users[i].UserConfig = proxyConfig.Spec.AUTHORITY.Users[i].UserName + - "@" + proxyConfig.Spec.AUTHORITY.Users[i].HostName + - ":" + proxyConfig.Spec.AUTHORITY.Users[i].PassWord + for i := 0; i < len(proxyConfig.Spec.Authority.Users); i++ { + proxyConfig.Spec.Authority.Users[i].UserConfig = proxyConfig.Spec.Authority.Users[i].UserName + + "@" + proxyConfig.Spec.Authority.Users[i].HostName + + ":" + proxyConfig.Spec.Authority.Users[i].PassWord } y, _ := yaml.Marshal(proxyConfig.Spec) return string(y) diff --git a/pkg/reconcile/status.go b/pkg/reconcile/status.go new file mode 100644 index 0000000..8d237d7 --- /dev/null +++ b/pkg/reconcile/status.go @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2022. + * + * 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 reconcile + +import ( + v1 "k8s.io/api/core/v1" + "math" +) + +func IsRunning(podList *v1.PodList) bool { + status := true + for _, pod := range podList.Items { + if pod.Status.Phase != v1.PodRunning { + status = false + } + } + + return status +} + +func CountingReadyPods(podList *v1.PodList) int32 { + var readyPods int32 + readyPods = 0 + for _, pod := range podList.Items { + if pod.Status.ContainerStatuses[0].Ready && pod.ObjectMeta.DeletionTimestamp == nil { + readyPods++ + } + } + return readyPods +} + +func CountingPodMaxRestartTimes(podList *v1.PodList) int32 { + var podRestartCount int32 = math.MinInt32 + for _, pod := range podList.Items { + if podRestartCount < pod.Status.ContainerStatuses[0].RestartCount { + podRestartCount = pod.Status.ContainerStatuses[0].RestartCount + } + } + return podRestartCount +}
