From 0e1933d8b60e6f5d7649c271f0c09802126ffeef Mon Sep 17 00:00:00 2001 From: David Schmitt Date: Tue, 25 Jul 2023 09:46:53 +0200 Subject: [PATCH 1/4] Cleanup, additional output --- cmd/getbookmark.go | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/cmd/getbookmark.go b/cmd/getbookmark.go index be58a8b4..42c5d8b8 100644 --- a/cmd/getbookmark.go +++ b/cmd/getbookmark.go @@ -2,6 +2,7 @@ package cmd import ( "context" + "encoding/json" "fmt" "os" "os/signal" @@ -84,7 +85,7 @@ func GetBookmark(signals chan os.Signal, ready chan bool) int { return 1 } log.WithContext(ctx).WithFields(log.Fields{ - "bookmark-uuid": response.Msg.Bookmark.Metadata.UUID, + "bookmark-uuid": uuid.UUID(response.Msg.Bookmark.Metadata.UUID), "bookmark-created": response.Msg.Bookmark.Metadata.Created, "bookmark-name": response.Msg.Bookmark.Properties.Name, "bookmark-description": response.Msg.Bookmark.Properties.Description, @@ -99,6 +100,10 @@ func GetBookmark(signals chan os.Signal, ready chan bool) int { "bookmark-excluded-item": i, }).Info("found bookmark excluded item") } + + b, _ := json.MarshalIndent(response.Msg.Bookmark.Properties, "", " ") + log.Info(string(b)) + return 0 } @@ -106,7 +111,6 @@ func init() { rootCmd.AddCommand(getBookmarkCmd) getBookmarkCmd.PersistentFlags().String("bookmark-url", "", "The bookmark service API endpoint (defaults to --url)") - getBookmarkCmd.PersistentFlags().String("frontend", "https://app.overmind.tech/", "The frontend base URL") getBookmarkCmd.PersistentFlags().String("uuid", "", "The UUID of the bookmark that should be displayed.") From e280a3b4a8535186e897dffeb1c54a7e980ba193 Mon Sep 17 00:00:00 2001 From: David Schmitt Date: Tue, 25 Jul 2023 09:47:09 +0200 Subject: [PATCH 2/4] Send configured loglevels to honeycomb --- cmd/root.go | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/cmd/root.go b/cmd/root.go index 6a0a115d..b0e5a524 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -233,10 +233,7 @@ func init() { } log.AddHook(otellogrus.NewHook(otellogrus.WithLevels( - log.PanicLevel, - log.FatalLevel, - log.ErrorLevel, - log.WarnLevel, + log.AllLevels[:log.GetLevel()]..., ))) } // shut down tracing at the end of the process From 760ad05fe38b9de7c4f0ec34bbee7dead3bbd689 Mon Sep 17 00:00:00 2001 From: David Schmitt Date: Tue, 25 Jul 2023 09:47:24 +0200 Subject: [PATCH 3/4] Implement create-bookmark command --- cmd/createbookmark.go | 135 ++++++++++++++++++++++++++++++++++ examples/create-bookmark.json | 11 +++ 2 files changed, 146 insertions(+) create mode 100644 cmd/createbookmark.go create mode 100644 examples/create-bookmark.json diff --git a/cmd/createbookmark.go b/cmd/createbookmark.go new file mode 100644 index 00000000..a685c53e --- /dev/null +++ b/cmd/createbookmark.go @@ -0,0 +1,135 @@ +package cmd + +import ( + "context" + "encoding/json" + "fmt" + "io" + "os" + "os/signal" + "syscall" + "time" + + "github.com/bufbuild/connect-go" + "github.com/google/uuid" + "github.com/overmindtech/ovm-cli/tracing" + "github.com/overmindtech/sdp-go" + log "github.com/sirupsen/logrus" + "github.com/spf13/cobra" + "github.com/spf13/viper" + "go.opentelemetry.io/otel/attribute" + "go.opentelemetry.io/otel/trace" +) + +// createBookmarkCmd represents the get-bookmark command +var createBookmarkCmd = &cobra.Command{ + Use: "create-bookmark [--file FILE]", + Short: "Creates a bookmark from JSON.", + PreRun: func(cmd *cobra.Command, args []string) { + // Bind these to viper + err := viper.BindPFlags(cmd.Flags()) + if err != nil { + log.WithError(err).Fatal("could not bind `create-bookmark` flags") + } + }, + Run: func(cmd *cobra.Command, args []string) { + sigs := make(chan os.Signal, 1) + signal.Notify(sigs, syscall.SIGINT, syscall.SIGTERM) + + exitcode := CreateBookmark(sigs, nil) + tracing.ShutdownTracer() + os.Exit(exitcode) + }, +} + +func CreateBookmark(signals chan os.Signal, ready chan bool) int { + timeout, err := time.ParseDuration(viper.GetString("timeout")) + if err != nil { + log.Errorf("invalid --timeout value '%v', error: %v", viper.GetString("timeout"), err) + return 1 + } + + in := os.Stdin + if viper.GetString("file") != "" { + in, err = os.Open(viper.GetString("file")) + if err != nil { + log.WithError(err).WithFields(log.Fields{ + "file": viper.GetString("file"), + }).Error("failed to open input") + return 1 + } + } + + ctx := context.Background() + ctx, span := tracing.Tracer().Start(ctx, "CLI CreateBookmark", trace.WithAttributes( + attribute.String("om.config", fmt.Sprintf("%v", viper.AllSettings())), + )) + defer span.End() + + ctx, err = ensureToken(ctx, signals) + if err != nil { + log.WithContext(ctx).WithError(err).WithFields(log.Fields{ + "url": viper.GetString("url"), + }).Error("failed to authenticate") + return 1 + } + + // apply a timeout to the main body of processing + ctx, cancel := context.WithTimeout(ctx, timeout) + defer cancel() + + contents, err := io.ReadAll(in) + if err != nil { + log.WithContext(ctx).WithError(err).Error("failed to read file") + return 1 + } + msg := sdp.BookmarkProperties{} + err = json.Unmarshal(contents, &msg) + if err != nil { + log.WithContext(ctx).WithError(err).Error("failed to parse input") + return 1 + } + client := AuthenticatedBookmarkClient(ctx) + response, err := client.CreateBookmark(ctx, &connect.Request[sdp.CreateBookmarkRequest]{ + Msg: &sdp.CreateBookmarkRequest{ + Properties: &msg, + }, + }) + if err != nil { + log.WithContext(ctx).WithError(err).WithFields(log.Fields{ + "bookmark-url": viper.GetString("bookmark-url"), + }).Error("failed to get bookmark") + return 1 + } + log.WithContext(ctx).WithFields(log.Fields{ + "bookmark-uuid": uuid.UUID(response.Msg.Bookmark.Metadata.UUID), + "bookmark-created": response.Msg.Bookmark.Metadata.Created, + "bookmark-name": response.Msg.Bookmark.Properties.Name, + "bookmark-description": response.Msg.Bookmark.Properties.Description, + }).Info("created bookmark") + for _, q := range response.Msg.Bookmark.Properties.Queries { + log.WithContext(ctx).WithFields(log.Fields{ + "bookmark-query": q, + }).Info("created bookmark query") + } + for _, i := range response.Msg.Bookmark.Properties.ExcludedItems { + log.WithContext(ctx).WithFields(log.Fields{ + "bookmark-excluded-item": i, + }).Info("created bookmark excluded item") + } + + b, _ := json.MarshalIndent(response.Msg.Bookmark.Properties, "", " ") + log.Info(string(b)) + + return 0 +} + +func init() { + rootCmd.AddCommand(createBookmarkCmd) + + createBookmarkCmd.PersistentFlags().String("bookmark-url", "", "The bookmark service API endpoint (defaults to --url)") + + createBookmarkCmd.PersistentFlags().String("file", "", "JSON formatted file to read bookmark. (defaults to stdin)") + + createBookmarkCmd.PersistentFlags().String("timeout", "1m", "How long to wait for responses") +} diff --git a/examples/create-bookmark.json b/examples/create-bookmark.json new file mode 100644 index 00000000..68f13829 --- /dev/null +++ b/examples/create-bookmark.json @@ -0,0 +1,11 @@ +{ + "name": "Changing items for 'CN=GTS Root R1,O=Google Trust Services'", + "description": "This bookmark contains the items that are changing as part of the 'CN=GTS Root R1,O=Google Trust Services' change. Generated using UpdateChangingItems", + "queries": [ + { + "type": "certificate", + "query": "CN=GTS Root R1,O=Google Trust Services", + "scope": "global" + } + ] +} \ No newline at end of file From 2b3243945b0385c81a445de3f5bfe86724b842a7 Mon Sep 17 00:00:00 2001 From: David Schmitt Date: Thu, 3 Aug 2023 09:22:24 +0200 Subject: [PATCH 4/4] Implement start-change and end-change --- cmd/endchange.go | 108 +++++++++++++++++++++++++++++++++++++++++++++ cmd/startchange.go | 108 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 216 insertions(+) create mode 100644 cmd/endchange.go create mode 100644 cmd/startchange.go diff --git a/cmd/endchange.go b/cmd/endchange.go new file mode 100644 index 00000000..c6aa13fd --- /dev/null +++ b/cmd/endchange.go @@ -0,0 +1,108 @@ +package cmd + +import ( + "context" + "fmt" + "os" + "os/signal" + "syscall" + "time" + + "github.com/bufbuild/connect-go" + "github.com/google/uuid" + "github.com/overmindtech/ovm-cli/tracing" + "github.com/overmindtech/sdp-go" + log "github.com/sirupsen/logrus" + "github.com/spf13/cobra" + "github.com/spf13/viper" + "go.opentelemetry.io/otel/attribute" + "go.opentelemetry.io/otel/trace" +) + +// endChangeCmd represents the end-change command +var endChangeCmd = &cobra.Command{ + Use: "end-change --uuid ID", + Short: "Finishes the specified change. Call this just after you finished the change. This will store a snapshot of the current system state for later reference.", + PreRun: func(cmd *cobra.Command, args []string) { + // Bind these to viper + err := viper.BindPFlags(cmd.Flags()) + if err != nil { + log.WithError(err).Fatal("could not bind `end-change` flags") + } + }, + Run: func(cmd *cobra.Command, args []string) { + sigs := make(chan os.Signal, 1) + signal.Notify(sigs, syscall.SIGINT, syscall.SIGTERM) + + exitcode := EndChange(sigs, nil) + tracing.ShutdownTracer() + os.Exit(exitcode) + }, +} + +func EndChange(signals chan os.Signal, ready chan bool) int { + timeout, err := time.ParseDuration(viper.GetString("timeout")) + if err != nil { + log.Errorf("invalid --timeout value '%v', error: %v", viper.GetString("timeout"), err) + return 1 + } + + snapshotUuid, err := uuid.Parse(viper.GetString("uuid")) + if err != nil { + log.Errorf("invalid --uuid value '%v', error: %v", viper.GetString("uuid"), err) + return 1 + } + + ctx := context.Background() + ctx, span := tracing.Tracer().Start(ctx, "CLI EndChange", trace.WithAttributes( + attribute.String("om.config", fmt.Sprintf("%v", viper.AllSettings())), + )) + defer span.End() + + lf := log.Fields{ + "uuid": snapshotUuid.String(), + } + + ctx, err = ensureToken(ctx, signals) + if err != nil { + log.WithContext(ctx).WithFields(lf).WithError(err).Error("failed to authenticate") + return 1 + } + + // apply a timeout to the main body of processing + ctx, cancel := context.WithTimeout(ctx, timeout) + defer cancel() + + // snapClient := AuthenticatedSnapshotsClient(ctx) + client := AuthenticatedChangesClient(ctx) + stream, err := client.EndChange(ctx, &connect.Request[sdp.EndChangeRequest]{ + Msg: &sdp.EndChangeRequest{ + ChangeUUID: snapshotUuid[:], + }, + }) + if err != nil { + log.WithContext(ctx).WithFields(lf).WithError(err).Error("failed to start change") + return 1 + } + log.WithContext(ctx).WithFields(lf).Info("processing") + for stream.Receive() { + msg := stream.Msg() + log.WithContext(ctx).WithFields(lf).WithFields(log.Fields{ + "state": msg.State, + "items": msg.NumItems, + "edges": msg.NumEdges, + }).Info("progress") + } + log.WithContext(ctx).WithFields(lf).Info("started change") + return 0 +} + +func init() { + rootCmd.AddCommand(endChangeCmd) + + endChangeCmd.PersistentFlags().String("frontend", "https://app.overmind.tech/", "The frontend base URL") + + endChangeCmd.PersistentFlags().String("uuid", "", "The UUID of the snapshot that should be displayed.") + + endChangeCmd.PersistentFlags().String("timeout", "1m", "How long to wait for responses") +} diff --git a/cmd/startchange.go b/cmd/startchange.go new file mode 100644 index 00000000..e7095db7 --- /dev/null +++ b/cmd/startchange.go @@ -0,0 +1,108 @@ +package cmd + +import ( + "context" + "fmt" + "os" + "os/signal" + "syscall" + "time" + + "github.com/bufbuild/connect-go" + "github.com/google/uuid" + "github.com/overmindtech/ovm-cli/tracing" + "github.com/overmindtech/sdp-go" + log "github.com/sirupsen/logrus" + "github.com/spf13/cobra" + "github.com/spf13/viper" + "go.opentelemetry.io/otel/attribute" + "go.opentelemetry.io/otel/trace" +) + +// startChangeCmd represents the start-change command +var startChangeCmd = &cobra.Command{ + Use: "start-change --uuid ID", + Short: "Starts the specified change. Call this just before you're about to start the change. This will store a snapshot of the current system state for later reference.", + PreRun: func(cmd *cobra.Command, args []string) { + // Bind these to viper + err := viper.BindPFlags(cmd.Flags()) + if err != nil { + log.WithError(err).Fatal("could not bind `start-change` flags") + } + }, + Run: func(cmd *cobra.Command, args []string) { + sigs := make(chan os.Signal, 1) + signal.Notify(sigs, syscall.SIGINT, syscall.SIGTERM) + + exitcode := StartChange(sigs, nil) + tracing.ShutdownTracer() + os.Exit(exitcode) + }, +} + +func StartChange(signals chan os.Signal, ready chan bool) int { + timeout, err := time.ParseDuration(viper.GetString("timeout")) + if err != nil { + log.Errorf("invalid --timeout value '%v', error: %v", viper.GetString("timeout"), err) + return 1 + } + + snapshotUuid, err := uuid.Parse(viper.GetString("uuid")) + if err != nil { + log.Errorf("invalid --uuid value '%v', error: %v", viper.GetString("uuid"), err) + return 1 + } + + ctx := context.Background() + ctx, span := tracing.Tracer().Start(ctx, "CLI StartChange", trace.WithAttributes( + attribute.String("om.config", fmt.Sprintf("%v", viper.AllSettings())), + )) + defer span.End() + + lf := log.Fields{ + "uuid": snapshotUuid.String(), + } + + ctx, err = ensureToken(ctx, signals) + if err != nil { + log.WithContext(ctx).WithFields(lf).WithError(err).Error("failed to authenticate") + return 1 + } + + // apply a timeout to the main body of processing + ctx, cancel := context.WithTimeout(ctx, timeout) + defer cancel() + + // snapClient := AuthenticatedSnapshotsClient(ctx) + client := AuthenticatedChangesClient(ctx) + stream, err := client.StartChange(ctx, &connect.Request[sdp.StartChangeRequest]{ + Msg: &sdp.StartChangeRequest{ + ChangeUUID: snapshotUuid[:], + }, + }) + if err != nil { + log.WithContext(ctx).WithFields(lf).WithError(err).Error("failed to start change") + return 1 + } + log.WithContext(ctx).WithFields(lf).Info("processing") + for stream.Receive() { + msg := stream.Msg() + log.WithContext(ctx).WithFields(lf).WithFields(log.Fields{ + "state": msg.State, + "items": msg.NumItems, + "edges": msg.NumEdges, + }).Info("progress") + } + log.WithContext(ctx).WithFields(lf).Info("started change") + return 0 +} + +func init() { + rootCmd.AddCommand(startChangeCmd) + + startChangeCmd.PersistentFlags().String("frontend", "https://app.overmind.tech/", "The frontend base URL") + + startChangeCmd.PersistentFlags().String("uuid", "", "The UUID of the snapshot that should be displayed.") + + startChangeCmd.PersistentFlags().String("timeout", "1m", "How long to wait for responses") +}