github.com/argoproj/argo-cd/v3@v3.2.1/applicationset/generators/plugin.go (about) 1 package generators 2 3 import ( 4 "context" 5 "errors" 6 "fmt" 7 "strconv" 8 "strings" 9 "time" 10 11 "github.com/jeremywohl/flatten" 12 corev1 "k8s.io/api/core/v1" 13 "sigs.k8s.io/controller-runtime/pkg/client" 14 15 argoprojiov1alpha1 "github.com/argoproj/argo-cd/v3/pkg/apis/application/v1alpha1" 16 "github.com/argoproj/argo-cd/v3/util/settings" 17 18 "github.com/argoproj/argo-cd/v3/applicationset/services/plugin" 19 ) 20 21 const ( 22 DefaultPluginRequeueAfter = 30 * time.Minute 23 ) 24 25 var _ Generator = (*PluginGenerator)(nil) 26 27 type PluginGenerator struct { 28 client client.Client 29 namespace string 30 } 31 32 func NewPluginGenerator(client client.Client, namespace string) Generator { 33 g := &PluginGenerator{ 34 client: client, 35 namespace: namespace, 36 } 37 return g 38 } 39 40 func (g *PluginGenerator) GetRequeueAfter(appSetGenerator *argoprojiov1alpha1.ApplicationSetGenerator) time.Duration { 41 // Return a requeue default of 30 minutes, if no default is specified. 42 43 if appSetGenerator.Plugin.RequeueAfterSeconds != nil { 44 return time.Duration(*appSetGenerator.Plugin.RequeueAfterSeconds) * time.Second 45 } 46 47 return DefaultPluginRequeueAfter 48 } 49 50 func (g *PluginGenerator) GetTemplate(appSetGenerator *argoprojiov1alpha1.ApplicationSetGenerator) *argoprojiov1alpha1.ApplicationSetTemplate { 51 return &appSetGenerator.Plugin.Template 52 } 53 54 func (g *PluginGenerator) GenerateParams(appSetGenerator *argoprojiov1alpha1.ApplicationSetGenerator, applicationSetInfo *argoprojiov1alpha1.ApplicationSet, _ client.Client) ([]map[string]any, error) { 55 if appSetGenerator == nil { 56 return nil, ErrEmptyAppSetGenerator 57 } 58 59 if appSetGenerator.Plugin == nil { 60 return nil, ErrEmptyAppSetGenerator 61 } 62 63 ctx := context.Background() 64 65 providerConfig := appSetGenerator.Plugin 66 67 pluginClient, err := g.getPluginFromGenerator(ctx, applicationSetInfo.Name, providerConfig) 68 if err != nil { 69 return nil, fmt.Errorf("error getting plugin from generator: %w", err) 70 } 71 72 list, err := pluginClient.List(ctx, providerConfig.Input.Parameters) 73 if err != nil { 74 return nil, fmt.Errorf("error listing params: %w", err) 75 } 76 77 res, err := g.generateParams(appSetGenerator, applicationSetInfo, list.Output.Parameters, appSetGenerator.Plugin.Input.Parameters, applicationSetInfo.Spec.GoTemplate) 78 if err != nil { 79 return nil, fmt.Errorf("error generating params: %w", err) 80 } 81 82 return res, nil 83 } 84 85 func (g *PluginGenerator) getPluginFromGenerator(ctx context.Context, appSetName string, generatorConfig *argoprojiov1alpha1.PluginGenerator) (*plugin.Service, error) { 86 cm, err := g.getConfigMap(ctx, generatorConfig.ConfigMapRef.Name) 87 if err != nil { 88 return nil, fmt.Errorf("error fetching ConfigMap: %w", err) 89 } 90 token, err := g.getToken(ctx, cm["token"]) 91 if err != nil { 92 return nil, fmt.Errorf("error fetching Secret token: %w", err) 93 } 94 95 var requestTimeout int 96 requestTimeoutStr, ok := cm["requestTimeout"] 97 if ok { 98 requestTimeout, err = strconv.Atoi(requestTimeoutStr) 99 if err != nil { 100 return nil, fmt.Errorf("error set requestTimeout : %w", err) 101 } 102 } 103 104 pluginClient, err := plugin.NewPluginService(appSetName, cm["baseUrl"], token, requestTimeout) 105 if err != nil { 106 return nil, fmt.Errorf("error initializing plugin client: %w", err) 107 } 108 return pluginClient, nil 109 } 110 111 func (g *PluginGenerator) generateParams(appSetGenerator *argoprojiov1alpha1.ApplicationSetGenerator, appSet *argoprojiov1alpha1.ApplicationSet, objectsFound []map[string]any, pluginParams argoprojiov1alpha1.PluginParameters, useGoTemplate bool) ([]map[string]any, error) { 112 res := []map[string]any{} 113 114 for _, objectFound := range objectsFound { 115 params := map[string]any{} 116 117 if useGoTemplate { 118 for k, v := range objectFound { 119 params[k] = v 120 } 121 } else { 122 flat, err := flatten.Flatten(objectFound, "", flatten.DotStyle) 123 if err != nil { 124 return nil, err 125 } 126 for k, v := range flat { 127 params[k] = fmt.Sprintf("%v", v) 128 } 129 } 130 131 params["generator"] = map[string]any{ 132 "input": map[string]argoprojiov1alpha1.PluginParameters{ 133 "parameters": pluginParams, 134 }, 135 } 136 137 err := appendTemplatedValues(appSetGenerator.Plugin.Values, params, appSet.Spec.GoTemplate, appSet.Spec.GoTemplateOptions) 138 if err != nil { 139 return nil, err 140 } 141 142 res = append(res, params) 143 } 144 145 return res, nil 146 } 147 148 func (g *PluginGenerator) getToken(ctx context.Context, tokenRef string) (string, error) { 149 if tokenRef == "" || !strings.HasPrefix(tokenRef, "$") { 150 return "", fmt.Errorf("token is empty, or does not reference a secret key starting with '$': %v", tokenRef) 151 } 152 153 secretName, tokenKey := plugin.ParseSecretKey(tokenRef) 154 155 secret := &corev1.Secret{} 156 err := g.client.Get( 157 ctx, 158 client.ObjectKey{ 159 Name: secretName, 160 Namespace: g.namespace, 161 }, 162 secret) 163 if err != nil { 164 return "", fmt.Errorf("error fetching secret %s/%s: %w", g.namespace, secretName, err) 165 } 166 167 secretValues := make(map[string]string, len(secret.Data)) 168 169 for k, v := range secret.Data { 170 secretValues[k] = string(v) 171 } 172 173 token := settings.ReplaceStringSecret(tokenKey, secretValues) 174 175 return token, err 176 } 177 178 func (g *PluginGenerator) getConfigMap(ctx context.Context, configMapRef string) (map[string]string, error) { 179 cm := &corev1.ConfigMap{} 180 err := g.client.Get( 181 ctx, 182 client.ObjectKey{ 183 Name: configMapRef, 184 Namespace: g.namespace, 185 }, 186 cm) 187 if err != nil { 188 return nil, err 189 } 190 191 baseURL, ok := cm.Data["baseUrl"] 192 if !ok || baseURL == "" { 193 return nil, errors.New("baseUrl not found in ConfigMap") 194 } 195 196 token, ok := cm.Data["token"] 197 if !ok || token == "" { 198 return nil, errors.New("token not found in ConfigMap") 199 } 200 201 return cm.Data, nil 202 }