Skip to content

Commit

Permalink
Add list generator support (argoproj#3)
Browse files Browse the repository at this point in the history
* Add list generator support

* update item to elements

* Fix build error

* trigger github

* update
  • Loading branch information
xianlubird authored Jul 3, 2020
1 parent a5eea21 commit 6e5adbb
Show file tree
Hide file tree
Showing 13 changed files with 136 additions and 29 deletions.
9 changes: 1 addition & 8 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,11 @@
FROM golang:1.14.1 as builder

WORKDIR /workspace
# Copy the Go Modules manifests
COPY go.mod go.mod
COPY go.sum go.sum
# cache deps before building and copying source so that we don't need to re-download as much
# and so that source changes don't invalidate our downloaded layer
RUN go mod download

# Copy the go source
COPY . .

# Build
RUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -a -o applicationset-controller main.go
RUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -mod=vendor -a -o applicationset-controller main.go

# Use distroless as minimal base image to package the manager binary
FROM debian:10-slim
Expand Down
4 changes: 2 additions & 2 deletions api/v1alpha1/applicationset_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -52,11 +52,11 @@ type ApplicationSetGenerator struct {

// ListGenerator include items info
type ListGenerator struct {
Items []ListGeneratorItem `json:"items"`
Elements []ListGeneratorElement `json:"elements"`
}

// ListGeneratorItem include cluster and url info
type ListGeneratorItem struct {
type ListGeneratorElement struct {
Cluster string `json:"cluster"`
Url string `json:"url"`
}
Expand Down
14 changes: 7 additions & 7 deletions api/v1alpha1/zz_generated.deepcopy.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion examples/list.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ metadata:
spec:
generators:
- list:
items:
elements:
- cluster: engineering-dev
url: https://1.2.3.4
- cluster: engineering-prod
Expand All @@ -17,6 +17,7 @@ spec:
metadata:
name: '{{cluster}}-guestbook'
spec:
project: ""
source:
repoURL: https://github.com/infra-team/cluster-deployments.git
targetRevision: HEAD
Expand Down
4 changes: 2 additions & 2 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,15 @@ require (
github.com/argoproj/argo-cd v1.5.6
github.com/argoproj/pkg v0.0.0-20200424003221-9b858eff18a1 // indirect
github.com/ghodss/yaml v1.0.0 // indirect
github.com/go-logr/logr v0.1.0
github.com/gogo/protobuf v1.3.1 // indirect
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 // indirect
github.com/grpc-ecosystem/grpc-gateway v1.3.1 // indirect
github.com/k0kubun/colorstring v0.0.0-20150214042306-9440f1994b88 // indirect
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 // indirect
github.com/pkg/errors v0.9.1 // indirect
github.com/pkg/errors v0.9.1
github.com/sergi/go-diff v1.1.0 // indirect
github.com/sirupsen/logrus v1.4.2
github.com/valyala/fasttemplate v1.1.1
github.com/yudai/gojsondiff v1.0.1-0.20180504020246-0525c875b75c // indirect
github.com/yudai/golcs v0.0.0-20170316035057-ecda9a501e82 // indirect
github.com/yudai/pp v2.0.1+incompatible // indirect
Expand Down
3 changes: 3 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -526,8 +526,11 @@ github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljT
github.com/ultraware/funlen v0.0.1/go.mod h1:Dp4UiAus7Wdb9KUZsYWZEWiRzGuM2kXM1lPbfaF6xhA=
github.com/ultraware/funlen v0.0.2/go.mod h1:Dp4UiAus7Wdb9KUZsYWZEWiRzGuM2kXM1lPbfaF6xhA=
github.com/urfave/negroni v1.0.0/go.mod h1:Meg73S6kFm/4PpbYdq35yYWoCZ9mS/YSx+lKnmiohz4=
github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw=
github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
github.com/valyala/fasthttp v1.2.0/go.mod h1:4vX61m6KN+xDduDNwXrhIAVZaZaZiQ1luJk8LWSxF3s=
github.com/valyala/fasttemplate v1.1.1 h1:o7HedfIt0u4jgkQnk0jkUOUI45c0CbFgcOOVUpo/txI=
github.com/valyala/fasttemplate v1.1.1/go.mod h1:UQGH1tvbgY+Nz5t2n7tXsz52dQxojPUpymEIMZ47gx8=
github.com/valyala/quicktemplate v1.1.1/go.mod h1:EH+4AkTd43SvgIbQHYu59/cJyxDoOVRUAfrukLPuGJ4=
github.com/valyala/tcplisten v0.0.0-20161114210144-ceec8f93295a/go.mod h1:v3UYOV9WzVtRmSR+PDvWpU/qWl4Wa5LApYYX4ZtKbio=
github.com/vishvananda/netlink v0.0.0-20171020171820-b2de5d10e38e/go.mod h1:+SR5DhBJrl6ZM7CoCKvpw5BKroDKQ+PJqOg65H/2ktk=
Expand Down
6 changes: 2 additions & 4 deletions manifests/crds/argoproj.io_applicationsets.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,6 @@
apiVersion: apiextensions.k8s.io/v1beta1
kind: CustomResourceDefinition
metadata:
annotations:
controller-gen.kubebuilder.io/version: v0.3.0
creationTimestamp: null
name: applicationsets.argoproj.io
spec:
Expand Down Expand Up @@ -110,7 +108,7 @@ spec:
list:
description: ListGenerator include items info
properties:
items:
elements:
items:
description: ListGeneratorItem include cluster and url info
properties:
Expand All @@ -124,7 +122,7 @@ spec:
type: object
type: array
required:
- items
- elements
type: object
type: object
type: array
Expand Down
12 changes: 11 additions & 1 deletion pkg/controllers/applicationset_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ package controllers

import (
"context"
"github.com/argoproj-labs/applicationset/pkg/generators"
"k8s.io/client-go/tools/record"

log "github.com/sirupsen/logrus"
Expand Down Expand Up @@ -45,10 +46,19 @@ func (r *ApplicationSetReconciler) Reconcile(req ctrl.Request) (ctrl.Result, err
var applicationSetInfo argoprojiov1alpha1.ApplicationSet
if err := r.Get(ctx, req.NamespacedName, &applicationSetInfo); err != nil {
log.Info("Unable to fetch applicationSetInfo %v", err)

return ctrl.Result{}, client.IgnoreNotFound(err)
}

var generator generators.Generator
generator = generators.NewListGenerator()
for _, tmpGenerator := range applicationSetInfo.Spec.Generators {
desiredApplications, err := generator.GenerateApplications(&tmpGenerator, &applicationSetInfo)
log.Infof("desiredApplications %+v", desiredApplications)
if err != nil {
log.WithError(err).Error("error generating applications")
}
}

return ctrl.Result{}, nil
}

Expand Down
3 changes: 2 additions & 1 deletion pkg/generators/cluster.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,8 @@ func NewClusterGenerator() Generator {
return g
}

func (g *ClusterGenerator) GenerateApplications(appSet *argoprojiov1alpha1.ApplicationSet) ([]argov1alpha1.Application, error) {
func (g *ClusterGenerator) GenerateApplications(appSet *argoprojiov1alpha1.ApplicationSetGenerator,
appSets *argoprojiov1alpha1.ApplicationSet) ([]argov1alpha1.Application, error) {
if appSet == nil {
return nil, fmt.Errorf("ApplicationSet is empty")
}
Expand Down
3 changes: 2 additions & 1 deletion pkg/generators/interface.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,5 +10,6 @@ type Generator interface {
// GenerateApplications interprets the ApplicationSet and generates all relevant Applications.
// The expected / desired list of Applications is returned, it then needs to be reconciled
// against the current state of the Applications in the cluster.
GenerateApplications(appSet *argoprojiov1alpha1.ApplicationSet) ([]argov1alpha1.Application, error)
GenerateApplications(appSetGenerator *argoprojiov1alpha1.ApplicationSetGenerator,
appSet *argoprojiov1alpha1.ApplicationSet) ([]argov1alpha1.Application, error)
}
30 changes: 28 additions & 2 deletions pkg/generators/list.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@ package generators
import (
"fmt"
argoprojiov1alpha1 "github.com/argoproj-labs/applicationset/api/v1alpha1"
"github.com/argoproj-labs/applicationset/pkg/utils"
argov1alpha1 "github.com/argoproj/argo-cd/pkg/apis/application/v1alpha1"
log "github.com/sirupsen/logrus"
)

var _ Generator = (*ListGenerator)(nil)
Expand All @@ -16,10 +18,34 @@ func NewListGenerator() Generator {
return g
}

func (g *ListGenerator) GenerateApplications(appSet *argoprojiov1alpha1.ApplicationSet) ([]argov1alpha1.Application, error) {
if appSet == nil {
func (g *ListGenerator) GenerateApplications(appSetGenerator *argoprojiov1alpha1.ApplicationSetGenerator,
appSet *argoprojiov1alpha1.ApplicationSet) ([]argov1alpha1.Application, error) {
if appSetGenerator == nil || appSet == nil {
return nil, fmt.Errorf("ApplicationSet is empty")
}

if appSetGenerator.List == nil {
return nil, nil
}

listGenerator := appSetGenerator.List

if listGenerator == nil {
return nil, fmt.Errorf("Empty list generator ")
}

var tmplApplication argov1alpha1.Application
tmplApplication.Namespace = appSet.Spec.Template.Namespace
tmplApplication.Name = appSet.Spec.Template.Name
tmplApplication.Spec = appSet.Spec.Template.Spec

params := make(map[string]string, 2)
for _, tmpItem := range listGenerator.Elements {
params[utils.ClusterListGeneratorKeyName] = tmpItem.Cluster
params[utils.UrlGeneratorKeyName] = tmpItem.Url
tmpApplication, err := utils.RenderTemplateParams(&tmplApplication, params)
log.Debugf("tmpApplication %++v", tmpApplication)
log.Debugf("error %v", err)
}
return nil, nil
}
6 changes: 6 additions & 0 deletions pkg/utils/constants.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package utils

const (
ClusterListGeneratorKeyName = "cluster"
UrlGeneratorKeyName = "url"
)
68 changes: 68 additions & 0 deletions pkg/utils/util.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
package utils

import (
"encoding/json"
"fmt"
argov1alpha1 "github.com/argoproj/argo-cd/pkg/apis/application/v1alpha1"
"github.com/pkg/errors"
"github.com/valyala/fasttemplate"
"io"
"strconv"
)

func RenderTemplateParams(tmpl *argov1alpha1.Application, params map[string]string) (*argov1alpha1.Application, error) {
if tmpl == nil {
return nil, fmt.Errorf("Application template is empty ")
}

if len(params) == 0 {
return tmpl, nil
}

tmplBytes, err := json.Marshal(tmpl)
if err != nil {
return nil, err
}

fstTmpl := fasttemplate.New(string(tmplBytes), "{{", "}}")
replacedTmplStr, err := Replace(fstTmpl, params, true)
if err != nil {
return nil, err
}

var replacedTmpl argov1alpha1.Application
err = json.Unmarshal([]byte(replacedTmplStr), &replacedTmpl)
if err != nil {
return nil, err
}

return &replacedTmpl, nil
}

// Replace executes basic string substitution of a template with replacement values.
// allowUnresolved indicates whether or not it is acceptable to have unresolved variables
// remaining in the substituted template. prefixFilter will apply the replacements only
// to variables with the specified prefix
func Replace(fstTmpl *fasttemplate.Template, replaceMap map[string]string, allowUnresolved bool) (string, error) {
var unresolvedErr error
replacedTmpl := fstTmpl.ExecuteFuncString(func(w io.Writer, tag string) (int, error) {
replacement, ok := replaceMap[tag]
if !ok {
if allowUnresolved {
// just write the same string back
return w.Write([]byte(fmt.Sprintf("{{%s}}", tag)))
}
unresolvedErr = errors.Errorf("failed to resolve {{%s}}", tag)
return 0, nil
}
// The following escapes any special characters (e.g. newlines, tabs, etc...)
// in preparation for substitution
replacement = strconv.Quote(replacement)
replacement = replacement[1 : len(replacement)-1]
return w.Write([]byte(replacement))
})
if unresolvedErr != nil {
return "", unresolvedErr
}
return replacedTmpl, nil
}

0 comments on commit 6e5adbb

Please sign in to comment.