diff --git a/cmd/spire-agent/cli/api/fetch.go b/cmd/spire-agent/cli/api/fetch_cli.go similarity index 76% rename from cmd/spire-agent/cli/api/fetch.go rename to cmd/spire-agent/cli/api/fetch_cli.go index 52d61f9752..4e3a8dcb02 100644 --- a/cmd/spire-agent/cli/api/fetch.go +++ b/cmd/spire-agent/cli/api/fetch_cli.go @@ -60,7 +60,7 @@ func (f *FetchCLI) Run(args []string) int { } if !f.config.silent { - f.printResponse(resp, respTime) + printX509SVIDResponse(resp, respTime) } if f.config.writePath != "" { @@ -102,50 +102,6 @@ func (f *FetchCLI) fetchX509SVID(c workload.SpiffeWorkloadAPIClient) (*workload. return stream.Recv() } -func (f FetchCLI) printResponse(resp *workload.X509SVIDResponse, respTime time.Duration) { - lenMsg := fmt.Sprintf("Fetched %v bundle", len(resp.Svids)) - if len(resp.Svids) != 1 { - lenMsg = lenMsg + "s" - } - lenMsg = lenMsg + fmt.Sprintf(" in %s", respTime) - - fmt.Println(lenMsg) - for _, s := range resp.Svids { - fmt.Println() - f.printSVID(s) - } - - fmt.Println() -} - -func (f FetchCLI) printSVID(msg *workload.X509SVID) { - // Print SPIFFE ID first so if we run into a problem, we - // get to know which record it was - fmt.Printf("SPIFFE ID:\t\t%s\n", msg.SpiffeId) - - // Parse SVID and CA bundle. If we encounter an error, - // simply print it and return so we can go to the next bundle - svid, err := x509.ParseCertificate(msg.X509Svid) - if err != nil { - fmt.Printf("ERROR: Could not parse SVID: %s\n", err) - return - } - - svidBundle, err := x509.ParseCertificates(msg.Bundle) - if err != nil { - fmt.Printf("ERROR: Could not parse CA Certificates: %s\n", err) - return - } - - fmt.Printf("SVID Valid After:\t%v\n", svid.NotBefore) - fmt.Printf("SVID Valid Until:\t%v\n", svid.NotAfter) - for i, ca := range svidBundle { - num := i + 1 - fmt.Printf("CA #%v Valid After:\t%v\n", num, ca.NotBefore) - fmt.Printf("CA #%v Valid Until:\t%v\n", num, ca.NotAfter) - } -} - func (f FetchCLI) writeResponse(resp *workload.X509SVIDResponse) error { for i, svid := range resp.Svids { svidName := fmt.Sprintf("svid.%v.pem", i) diff --git a/cmd/spire-agent/cli/api/printer.go b/cmd/spire-agent/cli/api/printer.go new file mode 100644 index 0000000000..2a31be90e1 --- /dev/null +++ b/cmd/spire-agent/cli/api/printer.go @@ -0,0 +1,53 @@ +package api + +import ( + "crypto/x509" + "fmt" + "time" + + "github.com/spiffe/spire/proto/api/workload" +) + +func printX509SVIDResponse(resp *workload.X509SVIDResponse, respTime time.Duration) { + lenMsg := fmt.Sprintf("Received %v bundle", len(resp.Svids)) + if len(resp.Svids) != 1 { + lenMsg = lenMsg + "s" + } + lenMsg = lenMsg + fmt.Sprintf(" after %s", respTime) + + fmt.Println(lenMsg) + for _, s := range resp.Svids { + fmt.Println() + printX509SVID(s) + } + + fmt.Println() +} + +func printX509SVID(msg *workload.X509SVID) { + // Print SPIFFE ID first so if we run into a problem, we + // get to know which record it was + fmt.Printf("SPIFFE ID:\t\t%s\n", msg.SpiffeId) + + // Parse SVID and CA bundle. If we encounter an error, + // simply print it and return so we can go to the next bundle + svid, err := x509.ParseCertificate(msg.X509Svid) + if err != nil { + fmt.Printf("ERROR: Could not parse SVID: %s\n", err) + return + } + + svidBundle, err := x509.ParseCertificates(msg.Bundle) + if err != nil { + fmt.Printf("ERROR: Could not parse CA Certificates: %s\n", err) + return + } + + fmt.Printf("SVID Valid After:\t%v\n", svid.NotBefore) + fmt.Printf("SVID Valid Until:\t%v\n", svid.NotAfter) + for i, ca := range svidBundle { + num := i + 1 + fmt.Printf("CA #%v Valid After:\t%v\n", num, ca.NotBefore) + fmt.Printf("CA #%v Valid Until:\t%v\n", num, ca.NotAfter) + } +} diff --git a/cmd/spire-agent/cli/api/watch_cli.go b/cmd/spire-agent/cli/api/watch_cli.go new file mode 100644 index 0000000000..510d778d35 --- /dev/null +++ b/cmd/spire-agent/cli/api/watch_cli.go @@ -0,0 +1,93 @@ +package api + +import ( + "flag" + "fmt" + "log" + "net" + "os" + "os/signal" + "syscall" + "time" + + "github.com/spiffe/spire/api/workload" +) + +type WatchConfig struct { + socketPath string +} + +type WatchCLI struct { + config *WatchConfig + + stopChan chan struct{} +} + +func (WatchCLI) Synopsis() string { + return "Attaches to the Workload API and prints updates as they're received" +} + +func (w WatchCLI) Help() string { + err := w.parseConfig([]string{"-h"}) + return err.Error() +} + +func (w *WatchCLI) Run(args []string) int { + err := w.parseConfig(args) + if err != nil { + fmt.Println(err) + return 1 + } + + client, err := w.startClient() + if err != nil { + fmt.Println(err) + return 1 + } + + updateTime := time.Now() + go w.signalListener() + for { + select { + case <-w.stopChan: + return 0 + case u := <-client.UpdateChan(): + printX509SVIDResponse(u, time.Since(updateTime)) + updateTime = time.Now() + } + } +} + +func (w *WatchCLI) parseConfig(args []string) error { + fs := flag.NewFlagSet("watch", flag.ContinueOnError) + c := &WatchConfig{} + fs.StringVar(&c.socketPath, "socketPath", "/tmp/agent.sock", "Path to the Workload API socket") + + w.config = c + return fs.Parse(args) +} + +func (w *WatchCLI) startClient() (workload.Client, error) { + addr := &net.UnixAddr{ + Net: "unix", + Name: w.config.socketPath, + } + + l := log.New(os.Stdout, "", log.LstdFlags) + + c := &workload.ClientConfig{ + Addr: addr, + Logger: l, + } + + client := workload.NewClient(c) + return client, client.Start() +} + +func (w *WatchCLI) signalListener() { + signalChan := make(chan os.Signal, 1) + signal.Notify(signalChan, syscall.SIGINT, syscall.SIGTERM) + + <-signalChan + close(w.stopChan) +} diff --git a/cmd/spire-agent/cli/cli.go b/cmd/spire-agent/cli/cli.go index 8c52bcd535..ba24fdcd81 100644 --- a/cmd/spire-agent/cli/cli.go +++ b/cmd/spire-agent/cli/cli.go @@ -16,6 +16,9 @@ func Run(args []string) int { "api fetch": func() (cli.Command, error) { return &api.FetchCLI{}, nil }, + "api watch": func() (cli.Command, error) { + return &api.WatchCLI{}, nil + }, "run": func() (cli.Command, error) { return &run.RunCLI{}, nil }, diff --git a/script/e2e_test.sh b/script/e2e_test.sh index 46c626df2d..dedc625923 100755 --- a/script/e2e_test.sh +++ b/script/e2e_test.sh @@ -31,7 +31,7 @@ sleep 2 set +e RESULT=$(./cmd/spire-agent/spire-agent api fetch) -echo $RESULT | grep "Fetched 1 bundle" +echo $RESULT | grep "Received 1 bundle" if [ $? != 0 ]; then CODE=1 echo