| // Licensed to the Apache Software Foundation (ASF) under one | |
| // or more contributor license agreements. See the NOTICE file | |
| // distributed with this work for additional information | |
| // regarding copyright ownership. The ASF licenses this file | |
| // to you 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 broker | |
| import ( | |
| "context" | |
| v1 "github.com/apache/doris-operator/api/doris/v1" | |
| "github.com/apache/doris-operator/pkg/common/utils" | |
| "github.com/apache/doris-operator/pkg/common/utils/k8s" | |
| "github.com/apache/doris-operator/pkg/common/utils/resource" | |
| "github.com/apache/doris-operator/pkg/controller/sub_controller" | |
| appv1 "k8s.io/api/apps/v1" | |
| metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" | |
| "k8s.io/client-go/tools/record" | |
| "k8s.io/klog/v2" | |
| "sigs.k8s.io/controller-runtime/pkg/client" | |
| "time" | |
| ) | |
| type Controller struct { | |
| sub_controller.SubDefaultController | |
| } | |
| const ( | |
| BROKER_SEARCH_SUFFIX = "-search" | |
| ) | |
| func New(k8sclient client.Client, k8srecorder record.EventRecorder) *Controller { | |
| return &Controller{ | |
| SubDefaultController: sub_controller.SubDefaultController{ | |
| K8sclient: k8sclient, | |
| K8srecorder: k8srecorder, | |
| }, | |
| } | |
| } | |
| func (bk *Controller) GetControllerName() string { | |
| return "brokerController" | |
| } | |
| func (bk *Controller) Sync(ctx context.Context, dcr *v1.DorisCluster) error { | |
| if dcr.Spec.BrokerSpec == nil { | |
| return nil | |
| } | |
| if !bk.FeAvailable(dcr) { | |
| return nil | |
| } | |
| brokerSpec := dcr.Spec.BrokerSpec | |
| //get the broker configMap for resolve ports. | |
| //2. get config for generate statefulset and service. | |
| config, err := bk.GetConfig(ctx, &brokerSpec.ConfigMapInfo, dcr.Namespace, v1.Component_Broker) | |
| if err != nil { | |
| klog.Error("BrokerController Sync ", "resolve broker configmap failed, namespace ", dcr.Namespace, " error ", err) | |
| return err | |
| } | |
| bk.CheckConfigMountPath(dcr, v1.Component_Broker) | |
| bk.CheckSecretMountPath(dcr, v1.Component_Broker) | |
| bk.CheckSecretExist(ctx, dcr, v1.Component_Broker) | |
| internalService := resource.BuildInternalService(dcr, v1.Component_Broker, config) | |
| if err := k8s.ApplyService(ctx, bk.K8sclient, &internalService, resource.ServiceDeepEqual); err != nil { | |
| klog.Errorf("broker controller sync apply internalService name=%s, namespace=%s, clusterName=%s failed.message=%s.", | |
| internalService.Name, internalService.Namespace, dcr.Name, err.Error()) | |
| return err | |
| } | |
| st := bk.buildBKStatefulSet(dcr, config) | |
| if err = k8s.ApplyStatefulSet(ctx, bk.K8sclient, &st, func(new *appv1.StatefulSet, est *appv1.StatefulSet) bool { | |
| // if have restart annotation, we should exclude the interference for comparison. | |
| return resource.StatefulSetDeepEqual(new, est, false) | |
| }); err != nil { | |
| klog.Errorf("broker controller sync statefulset name=%s, namespace=%s, clusterName=%s failed. message=%s.", | |
| st.Name, st.Namespace, dcr.Name, err.Error()) | |
| return err | |
| } | |
| return nil | |
| } | |
| func (bk *Controller) UpdateComponentStatus(cluster *v1.DorisCluster) error { | |
| if cluster.Spec.BrokerSpec == nil { | |
| cluster.Status.BrokerStatus = nil | |
| return nil | |
| } | |
| bs := &v1.ComponentStatus{ | |
| ComponentCondition: v1.ComponentCondition{ | |
| SubResourceName: v1.GenerateComponentStatefulSetName(cluster, v1.Component_Broker), | |
| Phase: v1.Reconciling, | |
| LastTransitionTime: metav1.NewTime(time.Now()), | |
| }, | |
| } | |
| if cluster.Status.BrokerStatus != nil { | |
| bs = cluster.Status.BrokerStatus.DeepCopy() | |
| } | |
| cluster.Status.BrokerStatus = bs | |
| bs.AccessService = v1.GenerateExternalServiceName(cluster, v1.Component_Broker) | |
| return bk.ClassifyPodsByStatus(cluster.Namespace, bs, v1.GenerateStatefulSetSelector(cluster, v1.Component_Broker), *cluster.Spec.BrokerSpec.Replicas, v1.Component_Broker) | |
| } | |
| func (bk *Controller) ClearResources(ctx context.Context, dcr *v1.DorisCluster) (bool, error) { | |
| //if the doris is not have broker. | |
| if dcr.Status.BrokerStatus == nil { | |
| return true, nil | |
| } | |
| if dcr.Spec.BrokerSpec == nil { | |
| return bk.ClearCommonResources(ctx, dcr, v1.Component_Broker) | |
| } | |
| return true, nil | |
| } | |
| func (bk *Controller) getFeConfig(ctx context.Context, feconfigMapInfo *v1.ConfigMapInfo, namespace string) (map[string]interface{}, error) { | |
| cms := resource.GetMountConfigMapInfo(*feconfigMapInfo) | |
| if len(cms) == 0 { | |
| return make(map[string]interface{}), nil | |
| } | |
| feconfigMaps, err := k8s.GetConfigMaps(ctx, bk.K8sclient, namespace, cms) | |
| if err != nil { | |
| klog.Errorf("BrokerController getFeConfig fe config failed, namespace: %s,err: %s \n", namespace, err.Error()) | |
| } | |
| res, resolveErr := resource.ResolveConfigMaps(feconfigMaps, v1.Component_FE) | |
| return res, utils.MergeError(err, resolveErr) | |
| } |