controllers/sonar/chain/update_settings.go (101 lines of code) (raw):

package chain import ( "context" "encoding/json" "fmt" "net/url" "sort" "strings" ctrl "sigs.k8s.io/controller-runtime" "sigs.k8s.io/controller-runtime/pkg/client" sonarApi "github.com/epam/edp-sonar-operator/api/v1alpha1" "github.com/epam/edp-sonar-operator/pkg/client/sonar" "github.com/epam/edp-sonar-operator/pkg/sourceref" ) type UpdateSettings struct { sonarApiClient sonar.Settings k8sClient client.Client } func NewUpdateSettings(sonarApiClient sonar.Settings, k8sClient client.Client) *UpdateSettings { return &UpdateSettings{sonarApiClient: sonarApiClient, k8sClient: k8sClient} } func (h *UpdateSettings) ServeRequest(ctx context.Context, sonar *sonarApi.Sonar) error { log := ctrl.LoggerFrom(ctx) log.Info("Start updating settings to sonar") // if the user removes a setting from the CR, we need to reset it in Sonar settingsToReset := getSettingsKeysMap(sonar.Status) // we need to save processed settings to know which settings we need to reset processedSettings := make([]string, 0, len(sonar.Spec.Settings)) for _, s := range sonar.Spec.Settings { setting, err := h.makeSetting(ctx, s, sonar.Namespace) if err != nil { return err } if err = h.sonarApiClient.SetSetting(ctx, setting); err != nil { return fmt.Errorf("failed to set setting %s: %w", s.Key, err) } processedSettings = append(processedSettings, s.Key) delete(settingsToReset, s.Key) } if len(settingsToReset) != 0 { if err := h.sonarApiClient.ResetSettings(ctx, settingsKeysMapToSlice(settingsToReset)); err != nil { return fmt.Errorf("failed to reset settings: %w", err) } } setProcessedSettings(&sonar.Status, processedSettings) log.Info("Sonar settings have been updated") return nil } func getSettingsKeysMap(status sonarApi.SonarStatus) map[string]struct{} { var processedSettings []string if status.ProcessedSettings != "" { processedSettings = strings.Split(status.ProcessedSettings, ",") } m := make(map[string]struct{}, len(processedSettings)) for _, s := range processedSettings { m[s] = struct{}{} } return m } func settingsKeysMapToSlice(m map[string]struct{}) []string { s := make([]string, 0, len(m)) for k := range m { s = append(s, k) } return s } func (h *UpdateSettings) makeSetting( ctx context.Context, setting sonarApi.SonarSetting, namespace string, ) (url.Values, error) { if setting.FieldValues != nil { // nolint:errchkjson //we can skip error for marshal map[string]string fv, _ := json.Marshal(setting.FieldValues) return url.Values{ "key": []string{setting.Key}, "fieldValues": []string{string(fv)}, }, nil } if setting.Values != nil { return url.Values{ "key": []string{setting.Key}, "values": setting.Values, }, nil } if setting.ValueRef != nil { val, err := sourceref.GetValueFromSourceRef(ctx, setting.ValueRef, namespace, h.k8sClient) if err != nil { return url.Values{}, fmt.Errorf("failed to get sonar setting from source ref: %w", err) } return newSettingValue(setting.Key, val), nil } return newSettingValue(setting.Key, setting.Value), nil } func newSettingValue(key, value string) url.Values { return url.Values{ "key": []string{key}, "value": []string{value}, } } func setProcessedSettings(status *sonarApi.SonarStatus, settingsKeys []string) { // we need to sort keys to make sure that we have the same order of keys in the status // to not update ProcessedSettings filed every time sort.Strings(settingsKeys) status.ProcessedSettings = strings.Join(settingsKeys, ",") }