Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(appset): Implement Plugin Generator #13017

Merged
merged 33 commits into from
Jun 2, 2023
Merged
Show file tree
Hide file tree
Changes from 12 commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
68c565a
add internal http package
binboum Mar 27, 2023
cab141f
add services plugin
binboum Mar 27, 2023
c8d04c2
add generator plugin
binboum Mar 27, 2023
ca99d37
adapted matrix && merge generator
binboum Mar 27, 2023
ed8aaa5
adapted plugin to webhook
binboum Mar 27, 2023
a8a5b23
update applicationset controller and types for plugin
binboum Mar 27, 2023
2b7ad8e
add proposal for applicationset plugin generator
binboum Mar 27, 2023
12f51ad
execute codegen
binboum Mar 27, 2023
f4ff505
First draft of documentation
binboum Mar 27, 2023
4fde010
Fix wrong expected error on client_test
binboum Mar 27, 2023
08af198
docs(plugin-generator): minor improvements
scrocquesel Mar 30, 2023
e73918d
Merge pull request #1 from binboum/plugin-generator-doc
binboum Apr 23, 2023
511d6f9
update and codegen
binboum May 15, 2023
d8916f5
Improvement
crenshaw-dev May 19, 2023
3c74089
update and codegen
binboum May 19, 2023
93507ac
Add plugin to GetRequeueAfter function (merge && matrix)
binboum May 19, 2023
3467e9a
Improvement : renaming
crenshaw-dev May 24, 2023
15631f7
Fix typo renaming
binboum May 25, 2023
6272b46
Improve docs
binboum May 25, 2023
e4d39bd
Webhook implementation
binboum May 26, 2023
27e9712
Typo docs
binboum May 26, 2023
d75c456
fix plugin generator nil panic
crenshaw-dev May 26, 2023
f8bc0d1
Add company to USERS.md
binboum May 26, 2023
264fcd4
input.parameters
crenshaw-dev May 26, 2023
10c915d
Merge branch 'master' into feature/plugin-generator
binboum May 26, 2023
ce50b47
Change param structure
crenshaw-dev May 30, 2023
9a5b249
Fix conflicts
binboum May 30, 2023
304afd8
Merge branch 'master' into feature/plugin-generator
binboum May 30, 2023
752e894
Merge branch 'master' into feature/plugin-generator
binboum May 30, 2023
6f4607b
Fix conflicts
binboum May 30, 2023
23fa4a9
Fix docs
binboum May 30, 2023
9a4fda4
Fix docs
binboum May 30, 2023
1f7ff87
Merge branch 'master' into feature/plugin-generator
binboum Jun 1, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions applicationset/generators/matrix.go
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,7 @@ func (m *MatrixGenerator) getParams(appSetBaseGenerator argoprojiov1alpha1.Appli
Git: appSetBaseGenerator.Git,
SCMProvider: appSetBaseGenerator.SCMProvider,
ClusterDecisionResource: appSetBaseGenerator.ClusterDecisionResource,
Plugin: appSetBaseGenerator.Plugin,
PullRequest: appSetBaseGenerator.PullRequest,
Matrix: matrixGen,
Merge: mergeGen,
Expand Down
1 change: 1 addition & 0 deletions applicationset/generators/merge.go
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,7 @@ func (m *MergeGenerator) getParams(appSetBaseGenerator argoprojiov1alpha1.Applic
Git: appSetBaseGenerator.Git,
SCMProvider: appSetBaseGenerator.SCMProvider,
ClusterDecisionResource: appSetBaseGenerator.ClusterDecisionResource,
Plugin: appSetBaseGenerator.Plugin,
PullRequest: appSetBaseGenerator.PullRequest,
Matrix: matrixGen,
Merge: mergeGen,
Expand Down
208 changes: 208 additions & 0 deletions applicationset/generators/plugin.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,208 @@
package generators

import (
"context"
"fmt"
"strconv"
"strings"
"time"

"github.com/jeremywohl/flatten"

argoprojiov1alpha1 "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1"
corev1 "k8s.io/api/core/v1"
"k8s.io/client-go/kubernetes"
"sigs.k8s.io/controller-runtime/pkg/client"

plugin "github.com/argoproj/argo-cd/v2/applicationset/services/plugin"
)

const (
DefaultPluginRequeueAfterSeconds = 30 * time.Minute
)

var _ Generator = (*PluginGenerator)(nil)

type PluginGenerator struct {
client client.Client
ctx context.Context
clientset kubernetes.Interface
namespace string
}

func NewPluginGenerator(client client.Client, ctx context.Context, clientset kubernetes.Interface, namespace string) Generator {
g := &PluginGenerator{
client: client,
ctx: ctx,
clientset: clientset,
namespace: namespace,
}
return g
}

func (g *PluginGenerator) GetRequeueAfter(appSetGenerator *argoprojiov1alpha1.ApplicationSetGenerator) time.Duration {
// Return a requeue default of 30 minutes, if no default is specified.

if appSetGenerator.Plugin.RequeueAfterSeconds != nil {
return time.Duration(*appSetGenerator.Plugin.RequeueAfterSeconds) * time.Second
}

return DefaultPluginRequeueAfterSeconds
}

func (g *PluginGenerator) GetTemplate(appSetGenerator *argoprojiov1alpha1.ApplicationSetGenerator) *argoprojiov1alpha1.ApplicationSetTemplate {
return &appSetGenerator.Plugin.Template
}

func (g *PluginGenerator) GenerateParams(appSetGenerator *argoprojiov1alpha1.ApplicationSetGenerator, applicationSetInfo *argoprojiov1alpha1.ApplicationSet) ([]map[string]interface{}, error) {

if appSetGenerator == nil {
return nil, EmptyAppSetGeneratorError
}

if appSetGenerator.Plugin == nil {
return nil, EmptyAppSetGeneratorError
}

ctx := context.Background()

providerConfig := appSetGenerator.Plugin

plugin, err := g.getPluginFromGenerator(ctx, providerConfig)
if err != nil {
return nil, err
}

list, _, err := plugin.List(ctx, providerConfig.Params)
if err != nil {
return nil, fmt.Errorf("error listing params : %v", err)
}

res, err := g.generateParams(list, appSetGenerator.Plugin.Params, appSetGenerator.Plugin.AppendParamsToValues, applicationSetInfo.Spec.GoTemplate)
if err != nil {
return nil, err
}

return res, nil
}

func (g *PluginGenerator) getPluginFromGenerator(ctx context.Context, generatorConfig *argoprojiov1alpha1.PluginGenerator) (*plugin.PluginService, error) {
cm, err := g.getConfigMap(ctx, generatorConfig.ConfigMapRef)
if err != nil {
return nil, fmt.Errorf("error fetching ConfigMap: %v", err)
}
token, err := g.getToken(ctx, cm["token"])
if err != nil {
return nil, fmt.Errorf("error fetching Secret token: %v", err)
}

var requestTimeout int
requestTimeoutStr, ok := cm["requestTimeout"]
if ok {
requestTimeout, err = strconv.Atoi(requestTimeoutStr)
if err != nil {
return nil, fmt.Errorf("error set requestTimeout : %v", err)
}
}

plugin, err := plugin.NewPluginService(ctx, generatorConfig.Name, cm["baseUrl"], token, requestTimeout)
if err != nil {
return nil, err
}
return plugin, nil
}

func (g *PluginGenerator) generateParams(objectsFound []map[string]interface{}, pluginParams map[string]string, appendParamsToValues bool, useGoTemplate bool) ([]map[string]interface{}, error) {
res := []map[string]interface{}{}

for _, objectFound := range objectsFound {

params := map[string]interface{}{}

if useGoTemplate {
for k, v := range objectFound {
params[k] = v
}
} else {
flat, err := flatten.Flatten(objectFound, "", flatten.DotStyle)
if err != nil {
return nil, err
}
for k, v := range flat {
params[k] = fmt.Sprintf("%v", v)
}
}

if appendParamsToValues {
for k, v := range pluginParams {
// value returned by the plugin has precedence
if _, present := params[k]; !present {
params[k] = v
}
}
}

res = append(res, params)
}

return res, nil
}

func (g *PluginGenerator) getToken(ctx context.Context, tokenRef string) (string, error) {

if tokenRef == "" || !strings.HasPrefix(tokenRef, "$") {
return "", fmt.Errorf("token is empty, or does not reference a secret key starting with $ : %v", tokenRef)
}

secretName, tokenKey := plugin.ParseSecretKey(tokenRef)

secret := &corev1.Secret{}
err := g.client.Get(
ctx,
client.ObjectKey{
Name: secretName,
Namespace: g.namespace,
},
secret)

if err != nil {
return "", fmt.Errorf("error fetching secret %s/%s: %v", g.namespace, secretName, err)
}

secretValues := make(map[string]string, len(secret.Data))

for k, v := range secret.Data {
secretValues[k] = string(v)
}

token := plugin.ReplaceStringSecret(tokenKey, secretValues)

return token, err
}

func (g *PluginGenerator) getConfigMap(ctx context.Context, configMapRef string) (map[string]string, error) {
cm := &corev1.ConfigMap{}
err := g.client.Get(
ctx,
client.ObjectKey{
Name: configMapRef,
Namespace: g.namespace,
},
cm)

if err != nil {
return nil, err
}

baseUrl, ok := cm.Data["baseUrl"]
if !ok || baseUrl == "" {
return nil, fmt.Errorf("baseUrl not found in ConfigMap")
}

token, ok := cm.Data["token"]
if !ok || token == "" {
return nil, fmt.Errorf("token not found in ConfigMap")
}

return cm.Data, nil
}
Loading