github.com/1aal/kubeblocks@v0.0.0-20231107070852-e1c03e598921/controllers/apps/configuration/reconcile_task.go (about)

     1  /*
     2  Copyright (C) 2022-2023 ApeCloud Co., Ltd
     3  
     4  This file is part of KubeBlocks project
     5  
     6  This program is free software: you can redistribute it and/or modify
     7  it under the terms of the GNU Affero General Public License as published by
     8  the Free Software Foundation, either version 3 of the License, or
     9  (at your option) any later version.
    10  
    11  This program is distributed in the hope that it will be useful
    12  but WITHOUT ANY WARRANTY; without even the implied warranty of
    13  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    14  GNU Affero General Public License for more details.
    15  
    16  You should have received a copy of the GNU Affero General Public License
    17  along with this program.  If not, see <http://www.gnu.org/licenses/>.
    18  */
    19  
    20  package configuration
    21  
    22  import (
    23  	"strconv"
    24  
    25  	corev1 "k8s.io/api/core/v1"
    26  
    27  	appsv1alpha1 "github.com/1aal/kubeblocks/apis/apps/v1alpha1"
    28  	"github.com/1aal/kubeblocks/pkg/configuration/core"
    29  	cfgutil "github.com/1aal/kubeblocks/pkg/configuration/util"
    30  	"github.com/1aal/kubeblocks/pkg/controller/component"
    31  	"github.com/1aal/kubeblocks/pkg/controller/configuration"
    32  	intctrlutil "github.com/1aal/kubeblocks/pkg/controllerutil"
    33  )
    34  
    35  type Task struct {
    36  	intctrlutil.ResourceFetcher[Task]
    37  
    38  	Status *appsv1alpha1.ConfigurationItemDetailStatus
    39  	Name   string
    40  
    41  	Do func(fetcher *Task, component *component.SynthesizedComponent, revision string) error
    42  }
    43  
    44  type TaskContext struct {
    45  	configuration *appsv1alpha1.Configuration
    46  	reqCtx        intctrlutil.RequestCtx
    47  	fetcher       *Task
    48  }
    49  
    50  func NewTask(item appsv1alpha1.ConfigurationItemDetail, status *appsv1alpha1.ConfigurationItemDetailStatus) Task {
    51  	return Task{
    52  		Name: item.Name,
    53  		Do: func(fetcher *Task, synComponent *component.SynthesizedComponent, revision string) error {
    54  			configSpec := item.ConfigSpec
    55  			if configSpec == nil {
    56  				return core.MakeError("not found config spec: %s", item.Name)
    57  			}
    58  			if err := fetcher.ConfigMap(item.Name).Complete(); err != nil {
    59  				return err
    60  			}
    61  			// Do reconcile for config template
    62  			configMap := fetcher.ConfigMapObj
    63  			switch intctrlutil.GetConfigSpecReconcilePhase(configMap, item, status) {
    64  			default:
    65  				return syncStatus(configMap, status)
    66  			case appsv1alpha1.CPendingPhase,
    67  				appsv1alpha1.CMergeFailedPhase:
    68  				return syncImpl(fetcher, item, status, synComponent, revision, configSpec)
    69  			case appsv1alpha1.CCreatingPhase:
    70  				return nil
    71  			}
    72  		},
    73  		Status: status,
    74  	}
    75  }
    76  
    77  func syncImpl(fetcher *Task,
    78  	item appsv1alpha1.ConfigurationItemDetail,
    79  	status *appsv1alpha1.ConfigurationItemDetailStatus,
    80  	component *component.SynthesizedComponent,
    81  	revision string,
    82  	configSpec *appsv1alpha1.ComponentConfigSpec) (err error) {
    83  	err = configuration.NewReconcilePipeline(configuration.ReconcileCtx{
    84  		ResourceCtx: fetcher.ResourceCtx,
    85  		Cluster:     fetcher.ClusterObj,
    86  		ClusterVer:  fetcher.ClusterVerObj,
    87  		Component:   component,
    88  		PodSpec:     component.PodSpec,
    89  	}, item, status, configSpec).
    90  		ConfigMap(item.Name).
    91  		ConfigConstraints(configSpec.ConfigConstraintRef).
    92  		PrepareForTemplate().
    93  		RerenderTemplate().
    94  		ApplyParameters().
    95  		UpdateConfigVersion(revision).
    96  		Sync().
    97  		Complete()
    98  
    99  	if err != nil {
   100  		status.Message = cfgutil.ToPointer(err.Error())
   101  		status.Phase = appsv1alpha1.CMergeFailedPhase
   102  	} else {
   103  		status.Message = nil
   104  		status.Phase = appsv1alpha1.CMergedPhase
   105  	}
   106  	status.UpdateRevision = revision
   107  	return err
   108  }
   109  
   110  func syncStatus(configMap *corev1.ConfigMap, status *appsv1alpha1.ConfigurationItemDetailStatus) (err error) {
   111  	annotations := configMap.GetAnnotations()
   112  	// status.CurrentRevision = GetCurrentRevision(annotations)
   113  	revisions := RetrieveRevision(annotations)
   114  	if len(revisions) == 0 {
   115  		return
   116  	}
   117  
   118  	for i := 0; i < len(revisions); i++ {
   119  		updateRevision(revisions[i], status)
   120  		updateLastDoneRevision(revisions[i], status)
   121  	}
   122  
   123  	return
   124  }
   125  
   126  func updateLastDoneRevision(revision ConfigurationRevision, status *appsv1alpha1.ConfigurationItemDetailStatus) {
   127  	if revision.Phase == appsv1alpha1.CFinishedPhase {
   128  		status.LastDoneRevision = strconv.FormatInt(revision.Revision, 10)
   129  	}
   130  }
   131  
   132  func updateRevision(revision ConfigurationRevision, status *appsv1alpha1.ConfigurationItemDetailStatus) {
   133  	if revision.StrRevision == status.UpdateRevision {
   134  		status.Phase = revision.Phase
   135  		status.ReconcileDetail = &appsv1alpha1.ReconcileDetail{
   136  			CurrentRevision: revision.StrRevision,
   137  			Policy:          revision.Result.Policy,
   138  			SucceedCount:    revision.Result.SucceedCount,
   139  			ExpectedCount:   revision.Result.ExpectedCount,
   140  			ExecResult:      revision.Result.ExecResult,
   141  			ErrMessage:      revision.Result.Message,
   142  		}
   143  	}
   144  }