diff --git a/example/directory/index.html b/example/directory/index.html new file mode 100644 index 0000000..21711b5 --- /dev/null +++ b/example/directory/index.html @@ -0,0 +1,2 @@ + +* diff --git a/example/directory/nginx.$.yml b/example/directory/nginx.$.yml new file mode 100644 index 0000000..07e3600 --- /dev/null +++ b/example/directory/nginx.$.yml @@ -0,0 +1,32 @@ +# kubetpl:syntax:$ + +apiVersion: v1 +kind: ConfigMap +metadata: + name: $NAME +data: + index.html: "$MESSAGE" +--- +apiVersion: apps/v1beta1 +kind: Deployment +metadata: + name: $NAME +spec: + replicas: 1 + template: + metadata: + labels: + app: $NAME + spec: + containers: + - name: nginx + image: nginx:1.7.9 + ports: + - containerPort: 80 + volumeMounts: + - name: $NAME-volume + mountPath: /usr/share/nginx/html + volumes: + - name: $NAME-volume + configMap: + name: $NAME diff --git a/example/directory/nginx.go-template.yml b/example/directory/nginx.go-template.yml new file mode 100644 index 0000000..a240593 --- /dev/null +++ b/example/directory/nginx.go-template.yml @@ -0,0 +1,32 @@ +# kubetpl:syntax:go-template + +apiVersion: v1 +kind: ConfigMap +metadata: + name: {{ .NAME }} +data: + index.html: {{ .MESSAGE | quote }} +--- +apiVersion: apps/v1beta1 +kind: Deployment +metadata: + name: {{ .NAME }} +spec: + replicas: 1 + template: + metadata: + labels: + app: {{ .NAME }} + spec: + containers: + - name: nginx + image: nginx:1.7.9 + ports: + - containerPort: 80 + volumeMounts: + - name: {{ .NAME }}-volume + mountPath: /usr/share/nginx/html + volumes: + - name: {{ .NAME }}-volume + configMap: + name: {{ .NAME }} diff --git a/kubetpl.go b/kubetpl.go index 1392b5b..2321eb2 100644 --- a/kubetpl.go +++ b/kubetpl.go @@ -16,6 +16,7 @@ import ( "net/http" "os" "path/filepath" + "sort" "strings" ) @@ -270,7 +271,55 @@ type renderOpts struct { ignoreUnset bool } +func expandDirectories(templateFiles []string, userSupplied bool) ([]string, error) { + var templates []string + + extensions := sort.StringSlice{".yaml", ".yml", ".json"} + extensionCount := len(extensions) + sort.Strings(extensions) + + for _, filename := range templateFiles { + fileInfo, err := os.Lstat(filename) + if err != nil { + return nil, err + } + + if !fileInfo.Mode().IsDir() { + ext := filepath.Ext(filename) + idx := extensions.Search(ext) + if userSupplied || idx < extensionCount && extensions[idx] == ext { + templates = append(templates, filename) + } + continue + } + + subfiles, err := ioutil.ReadDir(filename) + if err != nil { + return nil, err + } + + var files []string + for _, file := range subfiles { + full := filepath.Join(filename, file.Name()) + files = append(files, full) + } + + files, err = expandDirectories(files, false) + if err != nil { + return nil, err + } + + templates = append(templates, files...) + } + + return templates, nil +} + func render(templateFiles []string, data map[string]interface{}, opts renderOpts) ([]byte, error) { + templateFiles, err := expandDirectories(templateFiles, true) + if err != nil { + return nil, err + } objs, err := renderTemplates(templateFiles, data, opts) if err != nil { return nil, err diff --git a/kubetpl_test.go b/kubetpl_test.go index e287870..bf86045 100644 --- a/kubetpl_test.go +++ b/kubetpl_test.go @@ -36,6 +36,21 @@ func TestRender(t *testing.T) { } } +func TestRenderDirectory(t *testing.T) { + cfg := map[string]interface{}{ + "NAME": "nm", + "MESSAGE": "msg", + } + opts := renderOpts{} + renderedSh, err := render([]string{"example/directory"}, cfg, opts) + if err != nil { + t.Fatal(err) + } + if len(renderedSh) == 0 { + t.Fatal("len(rendered) == 0") + } +} + func TestRenderWithDataFromFile(t *testing.T) { // todo: test secret ("data" must be base64-encoded) src := []string{"example/nginx-with-data-from-file.yml"}