diff --git a/pkg/splunk/controller/configmap.go b/pkg/splunk/controller/configmap.go index ee3dd2fbf..66d1b6a6c 100644 --- a/pkg/splunk/controller/configmap.go +++ b/pkg/splunk/controller/configmap.go @@ -39,7 +39,7 @@ func ApplyConfigMap(client splcommon.ControllerClient, configMap *corev1.ConfigM var dataUpdated bool if err == nil { if !reflect.DeepEqual(configMap.Data, current.Data) { - scopedLog.Info("Updating existing ConfigMap") + scopedLog.Info("Updating existing ConfigMap", "ResourceVerison", current.GetResourceVersion()) current.Data = configMap.Data err = splutil.UpdateResource(client, ¤t) if err == nil { diff --git a/pkg/splunk/enterprise/standalone.go b/pkg/splunk/enterprise/standalone.go index 4e1509b3c..82f713dc9 100644 --- a/pkg/splunk/enterprise/standalone.go +++ b/pkg/splunk/enterprise/standalone.go @@ -145,7 +145,7 @@ func ApplyStandalone(client splcommon.ControllerClient, cr *enterpriseApi.Standa } // Now apply the configMap will full app listing. - _, _, err = ApplyAppListingConfigMap(client, cr, &cr.Spec.AppFrameworkConfig, appStatusContext.AppsSrcDeployStatus) + _, _, err = ApplyAppListingConfigMap(client, cr, &cr.Spec.AppFrameworkConfig, appStatusContext.AppsSrcDeployStatus, false) if err != nil { return result, err } diff --git a/pkg/splunk/enterprise/util.go b/pkg/splunk/enterprise/util.go index 743e67ad9..e826f53d5 100644 --- a/pkg/splunk/enterprise/util.go +++ b/pkg/splunk/enterprise/util.go @@ -226,7 +226,7 @@ func GetSmartstoreRemoteVolumeSecrets(volume enterpriseApi.VolumeSpec, client sp // Once the configMap is mounted on the Pod, Ansible handles the apps listed in these files // ToDo: Deletes to be handled for phase-3 func ApplyAppListingConfigMap(client splcommon.ControllerClient, cr splcommon.MetaObject, - appConf *enterpriseApi.AppFrameworkSpec, appsSrcDeployStatus map[string]enterpriseApi.AppSrcDeployInfo) (*corev1.ConfigMap, bool, error) { + appConf *enterpriseApi.AppFrameworkSpec, appsSrcDeployStatus map[string]enterpriseApi.AppSrcDeployInfo, appsModified bool) (*corev1.ConfigMap, bool, error) { var err error var crKind string @@ -332,6 +332,18 @@ func ApplyAppListingConfigMap(client splcommon.ControllerClient, cr splcommon.Me appListingConfigMap.SetOwnerReferences(append(appListingConfigMap.GetOwnerReferences(), splcommon.AsOwner(cr, true))) if len(appListingConfigMap.Data) > 0 { + if appsModified { + // App packages are modified, reset configmap to ensure a new resourceVersion + scopedLog.Info("Resetting App ConfigMap to force new resourceVersion", "configMapName", configMapName) + savedData := appListingConfigMap.Data + appListingConfigMap.Data = make(map[string]string) + _, err = splctrl.ApplyConfigMap(client, appListingConfigMap) + if err != nil { + scopedLog.Error(err, "failed reset of configmap", "configMapName", configMapName) + } + appListingConfigMap.Data = savedData + } + configMapDataChanged, err = splctrl.ApplyConfigMap(client, appListingConfigMap) if err != nil { @@ -619,10 +631,11 @@ func setStateAndStatusForAppDeployInfoList(appDeployList []enterpriseApi.AppDepl // handleAppRepoChanges parses the remote storage listing and updates the repoState and deployStatus accordingly // client and cr are used when we put the glue logic to hand-off to the side car func handleAppRepoChanges(client splcommon.ControllerClient, cr splcommon.MetaObject, - appDeployContext *enterpriseApi.AppDeploymentContext, remoteObjListingMap map[string]splclient.S3Response, appFrameworkConfig *enterpriseApi.AppFrameworkSpec) error { + appDeployContext *enterpriseApi.AppDeploymentContext, remoteObjListingMap map[string]splclient.S3Response, appFrameworkConfig *enterpriseApi.AppFrameworkSpec) (bool, error) { crKind := cr.GetObjectKind().GroupVersionKind().Kind scopedLog := log.WithName("handleAppRepoChanges").WithValues("kind", crKind, "name", cr.GetName(), "namespace", cr.GetNamespace()) var err error + appsModified := false scopedLog.Info("received App listing", "for App sources", len(remoteObjListingMap)) if remoteObjListingMap == nil || len(remoteObjListingMap) == 0 { @@ -633,7 +646,7 @@ func handleAppRepoChanges(client splcommon.ControllerClient, cr splcommon.MetaOb for appSrc := range remoteObjListingMap { if !CheckIfAppSrcExistsInConfig(appFrameworkConfig, appSrc) { err = fmt.Errorf("App source: %s no more exists, this should never happen", appSrc) - return err + return appsModified, err } } @@ -680,13 +693,14 @@ func handleAppRepoChanges(client splcommon.ControllerClient, cr splcommon.MetaOb // 2.2 Check for any App changes(Ex. A new App source, a new App added/updated) if AddOrUpdateAppSrcDeploymentInfoList(&appSrcDeploymentInfo, s3Response.Objects) { appDeployContext.IsDeploymentInProgress = true + appsModified = true } // Finally update the Map entry with latest info appDeployContext.AppsSrcDeployStatus[appSrc] = appSrcDeploymentInfo } - return err + return appsModified, err } // isAppExtentionValid checks if an app extention is supported or not @@ -735,13 +749,13 @@ func AddOrUpdateAppSrcDeploymentInfoList(appSrcDeploymentInfo *enterpriseApi.App if appList[idx].AppName == appName { found = true if appList[idx].ObjectHash != *remoteObj.Etag || appList[idx].RepoState == enterpriseApi.RepoStateDeleted { - scopedLog.Info("App change detected.", "App name: ", appName, "marking for an update") + scopedLog.Info("App change detected. Marking for an update.", "appName", appName) appList[idx].ObjectHash = *remoteObj.Etag appList[idx].DeployStatus = enterpriseApi.DeployStatusPending // Make the state active for an app that was deleted earlier, and got activated again if appList[idx].RepoState == enterpriseApi.RepoStateDeleted { - scopedLog.Info("App change", "enabling the App name: ", appName, "that was previously disabled/deleted") + scopedLog.Info("App change. Enabling the App that was previously disabled/deleted", "appName", appName) appList[idx].RepoState = enterpriseApi.RepoStateActive } appChangesDetected = true @@ -754,7 +768,7 @@ func AddOrUpdateAppSrcDeploymentInfoList(appSrcDeploymentInfo *enterpriseApi.App // Update our local list if it is a new app if !found { - scopedLog.Info("New App", "found: ", appName) + scopedLog.Info("New App found", "appName", appName) appDeployInfo.AppName = appName appDeployInfo.ObjectHash = *remoteObj.Etag appDeployInfo.RepoState = enterpriseApi.RepoStateActive @@ -963,6 +977,7 @@ func initAndCheckAppInfoStatus(client splcommon.ControllerClient, cr splcommon.M //check if the apps need to be downloaded from remote storage if HasAppRepoCheckTimerExpired(appStatusContext) || !reflect.DeepEqual(appStatusContext.AppFrameworkConfig, *appFrameworkConf) { var sourceToAppsList map[string]splclient.S3Response + appsModified := false scopedLog.Info("Checking status of apps on remote storage...") @@ -979,13 +994,13 @@ func initAndCheckAppInfoStatus(client splcommon.ControllerClient, cr splcommon.M } // Only handle the app repo changes if we were able to successfully get the apps list - err = handleAppRepoChanges(client, cr, appStatusContext, sourceToAppsList, appFrameworkConf) + appsModified, err = handleAppRepoChanges(client, cr, appStatusContext, sourceToAppsList, appFrameworkConf) if err != nil { scopedLog.Error(err, "Unable to use the App list retrieved from the remote storage") return err } - _, _, err = ApplyAppListingConfigMap(client, cr, appFrameworkConf, appStatusContext.AppsSrcDeployStatus) + _, _, err = ApplyAppListingConfigMap(client, cr, appFrameworkConf, appStatusContext.AppsSrcDeployStatus, appsModified) if err != nil { return err } diff --git a/pkg/splunk/enterprise/util_test.go b/pkg/splunk/enterprise/util_test.go index 501e9eea1..77b7ae2f1 100644 --- a/pkg/splunk/enterprise/util_test.go +++ b/pkg/splunk/enterprise/util_test.go @@ -259,7 +259,7 @@ func TestApplyAppListingConfigMap(t *testing.T) { // set the status context initAppFrameWorkContext(&cr.Spec.AppFrameworkConfig, &cr.Status.AppContext) - err := handleAppRepoChanges(client, &cr, &cr.Status.AppContext, remoteObjListMap, &cr.Spec.AppFrameworkConfig) + appsModified, err := handleAppRepoChanges(client, &cr, &cr.Status.AppContext, remoteObjListMap, &cr.Spec.AppFrameworkConfig) if err != nil { t.Errorf("Empty remote Object list should not trigger an error, but got error : %v", err) @@ -267,7 +267,7 @@ func TestApplyAppListingConfigMap(t *testing.T) { testAppListingConfigMap := func(client *spltest.MockClient, cr splcommon.MetaObject, appConf *enterpriseApi.AppFrameworkSpec, appsSrcDeployStatus map[string]enterpriseApi.AppSrcDeployInfo, want string) { f := func() (interface{}, error) { - configMap, _, err := ApplyAppListingConfigMap(client, cr, appConf, appsSrcDeployStatus) + configMap, _, err := ApplyAppListingConfigMap(client, cr, appConf, appsSrcDeployStatus, appsModified) // Make the config token as predictable configMap.Data[appsUpdateToken] = "1601945361" return configMap, err @@ -513,7 +513,7 @@ func TestHandleAppRepoChanges(t *testing.T) { var S3Response splclient.S3Response // Test-1: Empty remoteObjectList Map should return an error - err = handleAppRepoChanges(client, &cr, &appDeployContext, remoteObjListMap, &appFramworkConf) + _, err = handleAppRepoChanges(client, &cr, &appDeployContext, remoteObjListMap, &appFramworkConf) if err != nil { t.Errorf("Empty remote Object list should not trigger an error, but got error : %v", err) @@ -527,7 +527,7 @@ func TestHandleAppRepoChanges(t *testing.T) { // Set the app source with a matching one remoteObjListMap[appFramworkConf.AppSources[0].Name] = S3Response - err = handleAppRepoChanges(client, &cr, &appDeployContext, remoteObjListMap, &appFramworkConf) + _, err = handleAppRepoChanges(client, &cr, &appDeployContext, remoteObjListMap, &appFramworkConf) if err != nil { t.Errorf("Could not handle a valid remote listing. Error: %v", err) } @@ -539,7 +539,7 @@ func TestHandleAppRepoChanges(t *testing.T) { // Test-3: If the App Resource is not found in the remote object listing, all the corresponding Apps should be deleted/disabled delete(remoteObjListMap, appFramworkConf.AppSources[0].Name) - err = handleAppRepoChanges(client, &cr, &appDeployContext, remoteObjListMap, &appFramworkConf) + _, err = handleAppRepoChanges(client, &cr, &appDeployContext, remoteObjListMap, &appFramworkConf) if err != nil { t.Errorf("Could not handle a valid remote listing. Error: %v", err) } @@ -553,7 +553,7 @@ func TestHandleAppRepoChanges(t *testing.T) { // Test-4: If the App Resource is not found in the config, all the corresponding Apps should be deleted/disabled tmpAppSrcName := appFramworkConf.AppSources[0].Name appFramworkConf.AppSources[0].Name = "invalidName" - err = handleAppRepoChanges(client, &cr, &appDeployContext, remoteObjListMap, &appFramworkConf) + _, err = handleAppRepoChanges(client, &cr, &appDeployContext, remoteObjListMap, &appFramworkConf) if err != nil { t.Errorf("Could not handle a valid remote listing. Error: %v", err) } @@ -579,7 +579,7 @@ func TestHandleAppRepoChanges(t *testing.T) { tmpS3Response.Objects = append(tmpS3Response.Objects[:0], tmpS3Response.Objects[1:]...) remoteObjListMap[appFramworkConf.AppSources[0].Name] = tmpS3Response - err = handleAppRepoChanges(client, &cr, &appDeployContext, remoteObjListMap, &appFramworkConf) + _, err = handleAppRepoChanges(client, &cr, &appDeployContext, remoteObjListMap, &appFramworkConf) if err != nil { t.Errorf("Could not handle a valid remote listing. Error: %v", err) } @@ -595,7 +595,7 @@ func TestHandleAppRepoChanges(t *testing.T) { setStateAndStatusForAppDeployInfoList(appDeployContext.AppsSrcDeployStatus[appFramworkConf.AppSources[0].Name].AppDeploymentInfoList, enterpriseApi.RepoStateDeleted, enterpriseApi.DeployStatusComplete) - err = handleAppRepoChanges(client, &cr, &appDeployContext, remoteObjListMap, &appFramworkConf) + _, err = handleAppRepoChanges(client, &cr, &appDeployContext, remoteObjListMap, &appFramworkConf) if err != nil { t.Errorf("Could not handle a valid remote listing. Error: %v", err) } @@ -608,7 +608,7 @@ func TestHandleAppRepoChanges(t *testing.T) { // Test-8: For an AppSrc, when all the Apps are deleted on remote store and re-introduced, should modify the state to active and pending setStateAndStatusForAppDeployInfoList(appDeployContext.AppsSrcDeployStatus[appFramworkConf.AppSources[0].Name].AppDeploymentInfoList, enterpriseApi.RepoStateDeleted, enterpriseApi.DeployStatusComplete) - err = handleAppRepoChanges(client, &cr, &appDeployContext, remoteObjListMap, &appFramworkConf) + _, err = handleAppRepoChanges(client, &cr, &appDeployContext, remoteObjListMap, &appFramworkConf) if err != nil { t.Errorf("Could not handle a valid remote listing. Error: %v", err) } @@ -623,7 +623,7 @@ func TestHandleAppRepoChanges(t *testing.T) { S3Response.Objects = createRemoteObjectList("d41d8cd98f00", startAppPathAndName, 2322, nil, 10) invalidAppSourceName := "UnknownAppSourceInConfig" remoteObjListMap[invalidAppSourceName] = S3Response - err = handleAppRepoChanges(client, &cr, &appDeployContext, remoteObjListMap, &appFramworkConf) + _, err = handleAppRepoChanges(client, &cr, &appDeployContext, remoteObjListMap, &appFramworkConf) if err == nil { t.Errorf("Unable to return an error, when the remote listing contain unknown App source")