Skip to content

Commit

Permalink
feat: allow individual extension configs
Browse files Browse the repository at this point in the history
Signed-off-by: Leonardo Luz Almeida <[email protected]>
  • Loading branch information
leoluz committed Oct 22, 2024
1 parent ea46572 commit 71c8f0f
Show file tree
Hide file tree
Showing 4 changed files with 109 additions and 21 deletions.
54 changes: 36 additions & 18 deletions server/extension/extension.go
Original file line number Diff line number Diff line change
Expand Up @@ -410,28 +410,46 @@ func proxyKey(extName, cName, cServer string) ProxyKey {
}

func parseAndValidateConfig(s *settings.ArgoCDSettings) (*ExtensionConfigs, error) {
if s.ExtensionConfig == "" {
if len(s.ExtensionConfig) == 0 {
return nil, fmt.Errorf("no extensions configurations found")
}

extConfigMap := map[string]interface{}{}
err := yaml.Unmarshal([]byte(s.ExtensionConfig), &extConfigMap)
if err != nil {
return nil, fmt.Errorf("invalid extension config: %w", err)
}

parsedExtConfig := settings.ReplaceMapSecrets(extConfigMap, s.Secrets)
parsedExtConfigBytes, err := yaml.Marshal(parsedExtConfig)
if err != nil {
return nil, fmt.Errorf("error marshaling parsed extension config: %w", err)
}

configs := ExtensionConfigs{}
err = yaml.Unmarshal(parsedExtConfigBytes, &configs)
if err != nil {
return nil, fmt.Errorf("invalid parsed extension config: %w", err)
for extName, extConfig := range s.ExtensionConfig {
extConfigMap := map[string]interface{}{}
err := yaml.Unmarshal([]byte(extConfig), &extConfigMap)
if err != nil {
return nil, fmt.Errorf("invalid extension config: %w", err)
}

parsedExtConfig := settings.ReplaceMapSecrets(extConfigMap, s.Secrets)
parsedExtConfigBytes, err := yaml.Marshal(parsedExtConfig)
if err != nil {
return nil, fmt.Errorf("error marshaling parsed extension config: %w", err)
}
// empty extName means that this is the main configuration defined by
// the 'extension.config' configmap key
if extName == "" {
mainConfig := ExtensionConfigs{}
err = yaml.Unmarshal(parsedExtConfigBytes, &mainConfig)
if err != nil {
return nil, fmt.Errorf("invalid parsed extension config: %w", err)
}
configs.Extensions = append(configs.Extensions, mainConfig.Extensions...)
} else {
backendConfig := BackendConfig{}
err = yaml.Unmarshal(parsedExtConfigBytes, &backendConfig)
if err != nil {
return nil, fmt.Errorf("invalid parsed backend extension config for extension %s: %w", extName, err)
}
ext := ExtensionConfig{
Name: extName,
Backend: backendConfig,
}
configs.Extensions = append(configs.Extensions, ext)
}
}
err = validateConfigs(&configs)
err := validateConfigs(&configs)
if err != nil {
return nil, fmt.Errorf("validation error: %w", err)
}
Expand Down Expand Up @@ -546,7 +564,7 @@ func (m *Manager) RegisterExtensions() error {
if err != nil {
return fmt.Errorf("error getting settings: %w", err)
}
if settings.ExtensionConfig == "" {
if len(settings.ExtensionConfig) == 0 {
m.log.Infof("No extensions configured.")
return nil
}
Expand Down
15 changes: 14 additions & 1 deletion server/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -706,7 +706,7 @@ func (a *ArgoCDServer) watchSettings() {
log.Infof("gogs secret modified. restarting")
break
}
if prevExtConfig != a.settings.ExtensionConfig {
if !equalExtConfig(prevExtConfig, a.settings.ExtensionConfig) {
prevExtConfig = a.settings.ExtensionConfig
log.Infof("extensions configs modified. Updating proxy registry...")
err := a.extensionManager.UpdateExtensionRegistry(a.settings)
Expand All @@ -733,6 +733,19 @@ func (a *ArgoCDServer) watchSettings() {
close(updateCh)
}

func equalExtConfig(config1, config2 map[string]string) bool {
if len(config1) != len(config2) {
return false
}

for key, value := range config1 {
if config2[key] != value {
return false
}
}
return true
}

func (a *ArgoCDServer) rbacPolicyLoader(ctx context.Context) {
err := a.enf.RunPolicyLoader(ctx, func(cm *v1.ConfigMap) error {
var scopes []string
Expand Down
15 changes: 13 additions & 2 deletions util/settings/settings.go
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,7 @@ type ArgoCDSettings struct {
AppsInAnyNamespaceEnabled bool `json:"appsInAnyNamespaceEnabled"`
// ExtensionConfig configurations related to ArgoCD proxy extensions. The value
// is a yaml string defined in extension.ExtensionConfigs struct.
ExtensionConfig string `json:"extensionConfig,omitempty"`
ExtensionConfig map[string]string `json:"extensionConfig,omitempty"`
// ImpersonationEnabled indicates whether Application sync privileges can be decoupled from control plane
// privileges using impersonation
ImpersonationEnabled bool `json:"impersonationEnabled"`
Expand Down Expand Up @@ -1537,10 +1537,21 @@ func updateSettingsFromConfigMap(settings *ArgoCDSettings, argoCDCM *apiv1.Confi
}
settings.TrackingMethod = argoCDCM.Data[settingsResourceTrackingMethodKey]
settings.OIDCTLSInsecureSkipVerify = argoCDCM.Data[oidcTLSInsecureSkipVerifyKey] == "true"
settings.ExtensionConfig = argoCDCM.Data[extensionConfig]
settings.ExtensionConfig = getExtensionConfigs(argoCDCM.Data)
settings.ImpersonationEnabled = argoCDCM.Data[impersonationEnabledKey] == "true"
}

func getExtensionConfigs(cmData map[string]string) map[string]string {
result := make(map[string]string)
for k, v := range cmData {
if strings.HasPrefix(k, extensionConfig) {
extName := strings.TrimPrefix(strings.TrimPrefix(k, extensionConfig), ".")
result[extName] = v
}
}
return result
}

// validateExternalURL ensures the external URL that is set on the configmap is valid
func validateExternalURL(u string) error {
if u == "" {
Expand Down
46 changes: 46 additions & 0 deletions util/settings/settings_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,52 @@ func TestGetRepositories(t *testing.T) {
assert.Equal(t, []Repository{{URL: "http://foo"}}, filter)
}

func TestGetExtensionConfigs(t *testing.T) {
type cases struct {
name string
input map[string]string
expected map[string]string
expectedLen int
}

testCases := []cases{
{
name: "will return main config successfully",
expectedLen: 1,
input: map[string]string{
extensionConfig: "test",
},
expected: map[string]string{
"": "test",
},
},
{
name: "will return main and additional config successfully",
expectedLen: 2,
input: map[string]string{
extensionConfig: "main config",
fmt.Sprintf("%s.anotherExtension", extensionConfig): "another config",
},
expected: map[string]string{
"": "main config",
"anotherExtension": "another config",
},
},
}

for _, tc := range testCases {
tc := tc
t.Run(tc.name, func(t *testing.T) {
// When
output := getExtensionConfigs(tc.input)

// Then
assert.Len(t, output, tc.expectedLen)
assert.Equal(t, tc.expected, output)
})
}
}

func TestSaveRepositories(t *testing.T) {
kubeClient, settingsManager := fixtures(nil)
err := settingsManager.SaveRepositories([]Repository{{URL: "http://foo"}})
Expand Down

0 comments on commit 71c8f0f

Please sign in to comment.