Skip to content
This repository has been archived by the owner on Nov 1, 2022. It is now read-only.

Commit

Permalink
Break cyclical dependency of generated template fs
Browse files Browse the repository at this point in the history
For `fluxctl install`, we embed a set of templates in the fluxctl
binary by generating a fake filesystem as Go code
(pkg/install/generated_templates.gogen.go).

But the code that generates the fake filesystem also _depends_ on the
fake filesystem, since it does double duty as a program for generating
example manifests from those templates.

This leads to a problem: if anything has upset the generation process,
it's not possible to regenerate the files, since the generation tool
won't build.

A related problem, worked around elsewhere (#2473), is that it's easy
to introduce spurious differences in the generated code -- which,
since it's checked in -- means painful merges.

In general we don't care about the generated Go code, only about what
it produces. This commit removes it from git and from the uncommitted
change detection (`make check-generated`); and uses `fluxctl install`
to generate the example files, removing the need for the code
generating program to depend on the code it's generating.
  • Loading branch information
squaremo committed Oct 17, 2019
1 parent 64534d4 commit c906d37
Show file tree
Hide file tree
Showing 4 changed files with 27 additions and 297 deletions.
25 changes: 16 additions & 9 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,11 @@ BUILD_DATE:=$(shell date -u +'%Y-%m-%dT%H:%M:%SZ')

DOCS_PORT:=8000

GENERATED_TEMPLATES_FILE=pkg/install/generated_templates.gogen.go

all: $(GOBIN)/fluxctl $(GOBIN)/fluxd build/.flux.done

release-bins:
release-bins: $(GENERATED_TEMPLATES_FILE)
for arch in amd64; do \
for os in linux darwin windows; do \
CGO_ENABLED=0 GOOS=$$os GOARCH=$$arch go build -o "build/fluxctl_"$$os"_$$arch" $(LDFLAGS) -ldflags "-X main.version=$(shell ./docker/image-tag)" ./cmd/fluxctl/; \
Expand All @@ -51,7 +53,7 @@ clean:
realclean: clean
rm -rf ./cache

test: test/bin/helm test/bin/kubectl test/bin/kustomize
test: test/bin/helm test/bin/kubectl test/bin/kustomize $(GENERATED_TEMPLATES_FILE)
PATH="${PWD}/bin:${PWD}/test/bin:${PATH}" go test ${TEST_FLAGS} $(shell go list ./... | grep -v "^github.com/fluxcd/flux/vendor" | sort -u)

e2e: test/bin/helm test/bin/kubectl build/.flux.done
Expand Down Expand Up @@ -104,7 +106,7 @@ cache/%/helm-$(HELM_VERSION): docker/helm.version
tar -m -C ./cache -xzf cache/$*/helm-$(HELM_VERSION).tar.gz $*/helm
mv cache/$*/helm $@

$(GOBIN)/fluxctl: $(FLUXCTL_DEPS)
$(GOBIN)/fluxctl: $(FLUXCTL_DEPS) $(GENERATED_TEMPLATES_FILE)
go install ./cmd/fluxctl

$(GOBIN)/fluxd: $(FLUXD_DEPS)
Expand All @@ -113,14 +115,19 @@ $(GOBIN)/fluxd: $(FLUXD_DEPS)
integration-test: all
test/bin/test-flux

generate-deploy: pkg/install/generated_templates.gogen.go
cd deploy && go run ../pkg/install/generate.go deploy
generate-deploy: $(GOBIN)/fluxctl
$(GOBIN)/fluxctl install -o ./deploy \
--git-url git@github.com:fluxcd/flux-get-started \
--git-email flux@example.com \
--git-user 'Flux automation' \
--git-label flux \
--namespace flux

pkg/install/generated_templates.gogen.go: pkg/install/templates/*
cd pkg/install && go run generate.go embedded-templates
$(GENERATED_TEMPLATES_FILE): pkg/install/templates/*.tmpl pkg/install/generate.go
cd pkg/install && go run generate.go

check-generated: generate-deploy pkg/install/generated_templates.gogen.go
git diff --exit-code -- integrations/apis integrations/client pkg/install/generated_templates.gogen.go
check-generated: generate-deploy
git diff --exit-code -- deploy/

build-docs:
@cd docs && docker build -t flux-docs .
Expand Down
3 changes: 3 additions & 0 deletions deploy/flux-deployment.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,9 @@ spec:
# Include this if you want to restrict the manifests considered by flux
# to those under the following relative paths in the git repository
# - --git-path=subdir1,subdir2
- --git-label=flux
- --git-user=Flux automation
- --git-email=flux@example.com

# Include these two to enable git commit signing
# - --git-gpg-key-import=/root/gpg-import
Expand Down
80 changes: 8 additions & 72 deletions pkg/install/generate.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,92 +4,28 @@ package main

import (
"fmt"
"io/ioutil"
"log"
"net/http"
"os"
"time"

"github.com/shurcooL/vfsgen"

"github.com/fluxcd/flux/pkg/install"
)

func main() {
usage := func() {
fmt.Fprintf(os.Stderr, "usage: %s {embedded-templates,deploy}\n", os.Args[0])
fmt.Fprintf(os.Stderr, "usage: %s\n", os.Args[0])
os.Exit(1)
}
if len(os.Args) != 2 {
if len(os.Args) != 1 {
usage()
}
switch os.Args[1] {
case "embedded-templates":
var fs http.FileSystem = modTimeFS{
fs: http.Dir("templates/"),
}
err := vfsgen.Generate(fs, vfsgen.Options{
Filename: "generated_templates.gogen.go",
PackageName: "install",
VariableName: "templates",
})
if err != nil {
log.Fatalln(err)
}
case "deploy":
params := install.TemplateParameters{
GitURL: "git@github.com:fluxcd/flux-get-started",
GitBranch: "master",
Namespace: "flux",
}
manifests, err := install.FillInTemplates(params)
if err != nil {
fmt.Fprintf(os.Stderr, "error: failed to fill in templates: %s\n", err)
os.Exit(1)
}
for fileName, contents := range manifests {
if err := ioutil.WriteFile(fileName, contents, 0600); err != nil {
fmt.Fprintf(os.Stderr, "error: failed to write deploy file %s: %s\n", fileName, err)
os.Exit(1)
}
}

default:
usage()
}
}

// modTimeFS is a wrapper that rewrites all mod times to Unix epoch.
// This is to ensure `generated_templates.gogen.go` only changes when
// the folder and/or file contents change.
type modTimeFS struct {
fs http.FileSystem
}

func (fs modTimeFS) Open(name string) (http.File, error) {
f, err := fs.fs.Open(name)
err := vfsgen.Generate(http.Dir("templates/"), vfsgen.Options{
Filename: "generated_templates.gogen.go",
PackageName: "install",
VariableName: "templates",
})
if err != nil {
return nil, err
log.Fatalln(err)
}
return modTimeFile{f}, nil
}

type modTimeFile struct {
http.File
}

func (f modTimeFile) Stat() (os.FileInfo, error) {
fi, err := f.File.Stat()
if err != nil {
return nil, err
}
return modTimeFileInfo{fi}, nil
}

type modTimeFileInfo struct {
os.FileInfo
}

func (modTimeFileInfo) ModTime() time.Time {
return time.Unix(0, 0)
}
Loading

0 comments on commit c906d37

Please sign in to comment.