in internal/controller/appconfigurationprovider_controller.go [86:296]
func (reconciler *AzureAppConfigurationProviderReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) {
provider := &acpv1.AzureAppConfigurationProvider{}
err := reconciler.Get(ctx, req.NamespacedName, provider)
//Get object, if not exists, exit reconcile
if err != nil && apierrors.IsNotFound(err) {
delete(reconciler.ProvidersReconcileState, req.NamespacedName)
return reconcile.Result{}, nil
} else if err != nil {
klog.ErrorS(err, "Fail to get AzureAppConfigurationProvider object.")
return reconcile.Result{}, err
}
/* Patch the object status when finish processing. */
var patch client.Patch = client.MergeFrom(provider.DeepCopy())
defer func() {
retry := RetryAttempt
patchSuccess := false
for retry > 0 {
err = reconciler.Status().Patch(ctx, provider, patch)
if err != nil {
retry--
} else {
patchSuccess = true
break
}
}
if !patchSuccess {
klog.ErrorS(err, "Fail to patch the status of AzureAppConfigurationProvider.")
}
}()
/* Status initialization and resource object verification. */
if provider.Status.Phase == "" {
provider.Status.Phase = acpv1.PhasePending
}
if provider.Status.Phase == acpv1.PhaseRunning {
klog.V(3).Infof("The reconcile for AzureAppConfigurationProvider '%s' is running, just exit.", provider.Name)
return reconcile.Result{}, nil
}
provider.Status = newProviderStatus(acpv1.PhaseRunning, acpv1.SyncRunningMessage, provider.Status.LastSyncTime, provider.Status.RefreshStatus)
klog.V(3).Infof("Start reconcile AzureAppConfigurationProvider %q in %q namespace ", provider.Name, provider.Namespace)
err = verifyObject(provider.Spec)
if err != nil {
reconciler.logAndSetFailStatus(provider, err)
return reconcile.Result{Requeue: false}, nil
}
existingConfigMap := corev1.ConfigMap{}
isExisting := false
_, err = reconciler.verifyTargetObjectExistence(ctx, provider, &existingConfigMap)
if err != nil {
reconciler.logAndSetFailStatus(provider, err)
return reconcile.Result{Requeue: true, RequeueAfter: RequeueReconcileAfter}, nil
}
existingSecrets := make(map[string]corev1.Secret)
var existingSecret corev1.Secret
if provider.Spec.Secret != nil {
existingSecret = corev1.Secret{
ObjectMeta: metav1.ObjectMeta{
Name: provider.Spec.Secret.Target.SecretName,
},
}
isExisting, err = reconciler.verifyTargetObjectExistence(ctx, provider, &existingSecret)
if err != nil {
reconciler.logAndSetFailStatus(provider, err)
return reconcile.Result{Requeue: true, RequeueAfter: RequeueReconcileAfter}, nil
}
if isExisting {
existingSecrets[provider.Spec.Secret.Target.SecretName] = existingSecret
}
}
if reconciler.ProvidersReconcileState[req.NamespacedName] != nil {
for name := range reconciler.ProvidersReconcileState[req.NamespacedName].ExistingK8sSecrets {
if _, ok := existingSecrets[name]; !ok {
existingSecret = corev1.Secret{
ObjectMeta: metav1.ObjectMeta{
Name: name,
},
}
isExisting, err = reconciler.verifyTargetObjectExistence(ctx, provider, &existingSecret)
if err != nil {
reconciler.logAndSetFailStatus(provider, err)
return reconcile.Result{Requeue: true, RequeueAfter: RequeueReconcileAfter}, nil
}
if isExisting {
existingSecrets[name] = existingSecret
}
}
}
} else {
// Initialize the ReconcileState for the provider
reconciler.ProvidersReconcileState[req.NamespacedName] = &ReconciliationState{
Generation: -1,
ConfigMapResourceVersion: nil,
Annotations: make(map[string]string),
SentinelETags: make(map[acpv1.Sentinel]*azcore.ETag),
KeyValueETags: make(map[acpv1.Selector][]*azcore.ETag),
FeatureFlagETags: make(map[acpv1.Selector][]*azcore.ETag),
ExistingK8sSecrets: make(map[string]*loader.TargetK8sSecretMetadata),
ClientManager: nil,
}
}
// Reset the resource version if the configmap or secret was unexpected deleted
if existingConfigMap.Name == "" {
reconciler.ProvidersReconcileState[req.NamespacedName].ConfigMapResourceVersion = nil
}
if provider.Spec.Secret == nil {
reconciler.ProvidersReconcileState[req.NamespacedName].ExistingK8sSecrets = make(map[string]*loader.TargetK8sSecretMetadata)
} else {
for name := range reconciler.ProvidersReconcileState[req.NamespacedName].ExistingK8sSecrets {
if _, ok := existingSecrets[name]; !ok {
reconciler.ProvidersReconcileState[req.NamespacedName].ExistingK8sSecrets[name].SecretResourceVersion = ""
}
}
}
if reconciler.ProvidersReconcileState[req.NamespacedName].ClientManager == nil ||
reconciler.ProvidersReconcileState[req.NamespacedName].Generation != provider.Generation {
clientManager, err := loader.NewConfigurationClientManager(ctx, *provider)
if err != nil {
reconciler.logAndSetFailStatus(provider, err)
return reconcile.Result{Requeue: true, RequeueAfter: RequeueReconcileAfter}, nil
}
reconciler.ProvidersReconcileState[req.NamespacedName].ClientManager = clientManager
}
/* Create ConfigurationSettingLoader to get the key-value settings from Azure AppConfiguration. */
clientManager := reconciler.ProvidersReconcileState[req.NamespacedName].ClientManager
configLoader, err := loader.NewConfigurationSettingLoader(*provider, clientManager, nil)
if err != nil {
reconciler.logAndSetFailStatus(provider, err)
return reconcile.Result{Requeue: true, RequeueAfter: RequeueReconcileAfter}, nil
}
var retriever loader.ConfigurationSettingsRetriever
if reconciler.Retriever == nil {
retriever = configLoader
} else {
retriever = reconciler.Retriever
}
ctx = context.WithValue(ctx, loader.RequestTracingKey, loader.RequestTracing{
IsStartUp: reconciler.ProvidersReconcileState[req.NamespacedName].ConfigMapResourceVersion == nil,
})
// Initialize the processor setting in this reconcile
processor := &AppConfigurationProviderProcessor{
Context: ctx,
Provider: provider,
Retriever: retriever,
CurrentTime: metav1.Now(),
ReconciliationState: reconciler.ProvidersReconcileState[req.NamespacedName],
Settings: &loader.TargetKeyValueSettings{},
RefreshOptions: NewRefreshOptions(),
SecretReferenceResolver: nil,
}
if err := processor.PopulateSettings(&existingConfigMap, existingSecrets); err != nil {
return reconciler.requeueWhenGetSettingsFailed(provider, err)
}
/* Create ConfigMap from key-value settings */
if processor.RefreshOptions.ConfigMapSettingPopulated {
result, err := reconciler.createOrUpdateConfigMap(ctx, &existingConfigMap, provider, processor.Settings)
if err != nil {
return result, nil
}
}
/* Create secret when there are secret settings */
if processor.RefreshOptions.SecretSettingPopulated {
// Verify the existence of the secret which is not owned by the current provider
for name := range processor.Settings.SecretSettings {
if _, ok := existingSecrets[name]; !ok {
_, err := reconciler.verifyTargetObjectExistence(ctx, provider, &corev1.Secret{
ObjectMeta: metav1.ObjectMeta{
Name: name,
},
})
if err != nil {
reconciler.logAndSetFailStatus(provider, err)
return reconcile.Result{Requeue: true, RequeueAfter: RequeueReconcileAfter}, nil
}
}
}
result, err := reconciler.createOrUpdateSecrets(ctx, provider, processor, existingSecrets)
if err != nil {
return result, nil
}
}
// Expel the secrets which are no longer selected by the provider.
if provider.Spec.Secret == nil || processor.RefreshOptions.SecretSettingPopulated {
result, err := reconciler.expelRemovedSecrets(ctx, provider, existingSecrets, processor.Settings.K8sSecrets)
if err != nil {
return result, nil
}
}
/* Finish the reconcile */
provider.Status = newProviderStatus(acpv1.PhaseComplete, acpv1.SyncCompleteMessage, metav1.Now(), provider.Status.RefreshStatus)
return processor.Finish()
}