diff --git a/Makefile b/Makefile index 89583e16d..1cf381c25 100644 --- a/Makefile +++ b/Makefile @@ -99,10 +99,16 @@ spire-images: spire-server-image spire-agent-image ## Builds SPIRE Server and Ag .PHONY: spire-server-image spire-server-image: Dockerfile.server ## Builds SPIRE Server docker image docker build --build-arg goversion=$(goversion-required) -t spire-server -f Dockerfile.server . + # tag the image for local use (in systems tests, for example). "latest" + # isn't preferred since that can impact image pull policy (.e.g kubelet) + docker tag spire-server:latest spire-server:latest-local .PHONY: spire-agent-image spire-agent-image: Dockerfile.agent ## Builds SPIRE Agent docker image docker build --build-arg goversion=$(goversion-required) -t spire-agent -f Dockerfile.agent . + # tag the image for local use (in systems tests, for example). "latest" + # isn't preferred since that can impact image pull policy (.e.g kubelet) + docker tag spire-agent:latest spire-agent:latest-local ##@ Others utils: $(utils) ## Go-get SPIRE utils diff --git a/tools/k8s-test/config.go b/tools/k8s-test/config.go index 129eafbbd..ff4cdee04 100644 --- a/tools/k8s-test/config.go +++ b/tools/k8s-test/config.go @@ -1,13 +1,35 @@ package main import ( + "bytes" "context" "encoding/json" + "fmt" + "io/ioutil" + "regexp" + + "github.com/zeebo/errs" +) + +var ( + // multi-line, ungreedy match for a YAML configuration line for a non-local spire-* image + reSpireImage = regexp.MustCompile(`(?mU)^(\s*-?\s*image:\s*)gcr.io/spiffe-io/(spire-.+)(?::.*)?$`) ) -func ApplyConfig(ctx context.Context, path string) ([]Object, error) { +func ApplyConfig(ctx context.Context, path string, useLocalImage bool) ([]Object, error) { + // read the config file in so we can replace the image + configBytes, err := ioutil.ReadFile(path) + if err != nil { + return nil, errs.Wrap(err) + } + + if useLocalImage { + configBytes = replaceSpireImageWithLocal(configBytes) + fmt.Println("APPLYING:\n", string(configBytes)) + } + var raw json.RawMessage - if err := kubectlCmdJSON(ctx, &raw, "apply", "-f", path); err != nil { + if err := kubectlCmdJSON(ctx, bytes.NewReader(configBytes), &raw, "apply", "-f", "-"); err != nil { return nil, err } @@ -48,3 +70,7 @@ func ApplyConfig(ctx context.Context, path string) ([]Object, error) { return objects, nil } + +func replaceSpireImageWithLocal(configBytes []byte) []byte { + return reSpireImage.ReplaceAll(configBytes, []byte("$1$2:latest-local")) +} diff --git a/tools/k8s-test/go.mod b/tools/k8s-test/go.mod index 1b8d48dbe..fed170036 100644 --- a/tools/k8s-test/go.mod +++ b/tools/k8s-test/go.mod @@ -8,6 +8,7 @@ require ( github.com/mattn/go-isatty v0.0.4 // indirect github.com/spf13/cobra v0.0.3 github.com/spf13/pflag v1.0.3 // indirect + github.com/stretchr/testify v1.3.0 github.com/zeebo/errs v1.1.1 golang.org/x/net v0.0.0-20190213061140-3a22650c66bd // indirect golang.org/x/text v0.3.0 // indirect diff --git a/tools/k8s-test/go.sum b/tools/k8s-test/go.sum index 4dfad9314..15ee3df16 100644 --- a/tools/k8s-test/go.sum +++ b/tools/k8s-test/go.sum @@ -1,3 +1,5 @@ +github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/fatih/color v1.7.0 h1:DkWD4oS2D8LGGgTQ6IvwJJXSL5Vp2ffcQg58nFV38Ys= github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= github.com/gogo/protobuf v1.2.1 h1:/s5zKNz0uPFCZ5hddgPdo2TK2TVrUNMn0OOX8/aZMTE= @@ -10,11 +12,16 @@ github.com/mattn/go-colorable v0.1.0 h1:v2XXALHHh6zHfYTJ+cSkwtyffnaOyR1MXaA91mTr github.com/mattn/go-colorable v0.1.0/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= github.com/mattn/go-isatty v0.0.4 h1:bnP0vzxcAdeI1zdubAl5PjU6zsERjGZb7raWodagDYs= github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/spf13/cobra v0.0.3 h1:ZlrZ4XsMRm04Fr5pSFxBgfND2EBVa1nLpiy1stUsX/8= github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= github.com/spf13/pflag v1.0.3 h1:zPAT6CGy6wXeQ7NtTnaTerfKOsV6V6F8agHXFiazDkg= github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= github.com/spiffe/spire v0.0.0-20190221165849-bdb096dc6c0b h1:Sw007mCb5z9H8l5kzmIo2+5dBPBbXkZnmw2+9wKgyy4= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/zeebo/errs v1.1.1 h1:Cs5Noqj/tj3Ql/hLkD9WdumKlssx/IN2zr7CRGNOKZA= github.com/zeebo/errs v1.1.1/go.mod h1:Yj8dHrUQwls1bF3dr/vcSIu+qf4mI7idnTcHfoACc6I= golang.org/x/net v0.0.0-20190213061140-3a22650c66bd h1:HuTn7WObtcDo9uEEU7rEqL0jYthdXAmZ6PP+meazmaU= diff --git a/tools/k8s-test/kubectl.go b/tools/k8s-test/kubectl.go index 7aacc84ff..b235e15a4 100644 --- a/tools/k8s-test/kubectl.go +++ b/tools/k8s-test/kubectl.go @@ -48,12 +48,15 @@ func kubectlGet(ctx context.Context, typ, name string, obj interface{}) error { if name != "" { args = append(args, name, "--ignore-not-found") } - return kubectlCmdJSON(ctx, obj, args...) + return kubectlCmdJSON(ctx, nil, obj, args...) } -func kubectlCmdJSON(ctx context.Context, obj interface{}, args ...string) error { +func kubectlCmdJSON(ctx context.Context, stdin io.Reader, obj interface{}, args ...string) error { + // TODO: support context cancellation + stderr := new(bytes.Buffer) cmd := kubectlCmd(append([]string{"-o", "json"}, args...)...) + cmd.Stdin = stdin cmd.Stderr = stderr stdout, err := cmd.StdoutPipe() if err != nil { @@ -85,6 +88,8 @@ func kubectlCmdJSON(ctx context.Context, obj interface{}, args ...string) error } func kubectlStreamLogs(ctx context.Context, object string, w io.Writer) error { + // TODO: support context cancellation + stderr := new(bytes.Buffer) cmd := kubectlCmd("logs", "-f", object) cmd.Stdout = w diff --git a/tools/k8s-test/main.go b/tools/k8s-test/main.go index f2141d152..567fb23b2 100644 --- a/tools/k8s-test/main.go +++ b/tools/k8s-test/main.go @@ -13,6 +13,7 @@ func main() { var count int var noWait bool + var noLocal bool var timeout time.Duration var interval time.Duration @@ -104,10 +105,11 @@ func main() { Use: "apply", Args: cobra.MinimumNArgs(1), Run: func(cmd *cobra.Command, args []string) { - runCmd(ApplyConfigCmd(ctx, args, !noWait, interval)) + runCmd(ApplyConfigCmd(ctx, args, !noWait, !noLocal, interval)) }, } - applyCmd.LocalFlags().BoolVarP(&noWait, "nowait", "", false, "don't wait for all objects after applying") + applyCmd.LocalFlags().BoolVarP(&noWait, "no-wait", "", false, "don't wait for all objects after applying") + applyCmd.LocalFlags().BoolVarP(&noLocal, "no-local", "", false, "don't use locally built SPIRE images") applyCmd.LocalFlags().DurationVarP(&interval, "interval", "i", defaultInterval, "polling interval for object status") root.AddCommand(applyCmd) @@ -152,11 +154,11 @@ func WaitForNodeAttestationCmd(ctx context.Context, ident string, count int) err return WaitForNodeAttestation(ctx, server, count) } -func ApplyConfigCmd(ctx context.Context, paths []string, wait bool, interval time.Duration) error { +func ApplyConfigCmd(ctx context.Context, paths []string, wait, local bool, interval time.Duration) error { var all []Object for _, path := range paths { - objects, err := ApplyConfig(ctx, path) + objects, err := ApplyConfig(ctx, path, local) if err != nil { Alertln("failed to apply %s", path) return err