Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add operator cluster commands #460

Merged
merged 2 commits into from
Feb 15, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
122 changes: 122 additions & 0 deletions temporalcli/commands.gen.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ func NewTemporalCommand(cctx *CommandContext) *TemporalCommand {
s.Command.Args = cobra.NoArgs
s.Command.AddCommand(&NewTemporalActivityCommand(cctx, &s).Command)
s.Command.AddCommand(&NewTemporalEnvCommand(cctx, &s).Command)
s.Command.AddCommand(&NewTemporalOperatorCommand(cctx, &s).Command)
s.Command.AddCommand(&NewTemporalServerCommand(cctx, &s).Command)
s.Command.AddCommand(&NewTemporalTaskQueueCommand(cctx, &s).Command)
s.Command.AddCommand(&NewTemporalWorkflowCommand(cctx, &s).Command)
Expand Down Expand Up @@ -262,6 +263,127 @@ func NewTemporalEnvSetCommand(cctx *CommandContext, parent *TemporalEnvCommand)
return &s
}

type TemporalOperatorCommand struct {
Parent *TemporalCommand
Command cobra.Command
ClientOptions
}

func NewTemporalOperatorCommand(cctx *CommandContext, parent *TemporalCommand) *TemporalOperatorCommand {
var s TemporalOperatorCommand
s.Parent = parent
s.Command.Use = "operator"
s.Command.Short = "Manage a Temporal deployment."
if hasHighlighting {
s.Command.Long = "Operator commands enable actions on Namespaces, Search Attributes, and Temporal Clusters. These actions are performed through subcommands.\n\nTo run an Operator command, \x1b[1mrun temporal operator [command] [subcommand] [command options]\x1b[0m"
} else {
s.Command.Long = "Operator commands enable actions on Namespaces, Search Attributes, and Temporal Clusters. These actions are performed through subcommands.\n\nTo run an Operator command, `run temporal operator [command] [subcommand] [command options]`"
}
s.Command.Args = cobra.NoArgs
s.Command.AddCommand(&NewTemporalOperatorClusterCommand(cctx, &s).Command)
s.ClientOptions.buildFlags(cctx, s.Command.PersistentFlags())
return &s
}

type TemporalOperatorClusterCommand struct {
Parent *TemporalOperatorCommand
Command cobra.Command
}

func NewTemporalOperatorClusterCommand(cctx *CommandContext, parent *TemporalOperatorCommand) *TemporalOperatorClusterCommand {
var s TemporalOperatorClusterCommand
s.Parent = parent
s.Command.Use = "cluster"
s.Command.Short = "Operations for running a Temporal Cluster."
if hasHighlighting {
s.Command.Long = "Cluster commands enable actions on Temporal Clusters.\n\nCluster commands follow this syntax: \x1b[1mtemporal operator cluster [command] [command options]\x1b[0m"
} else {
s.Command.Long = "Cluster commands enable actions on Temporal Clusters.\n\nCluster commands follow this syntax: `temporal operator cluster [command] [command options]`"
}
s.Command.Args = cobra.NoArgs
s.Command.AddCommand(&NewTemporalOperatorClusterDescribeCommand(cctx, &s).Command)
s.Command.AddCommand(&NewTemporalOperatorClusterHealthCommand(cctx, &s).Command)
s.Command.AddCommand(&NewTemporalOperatorClusterSystemCommand(cctx, &s).Command)
return &s
}

type TemporalOperatorClusterDescribeCommand struct {
Parent *TemporalOperatorClusterCommand
Command cobra.Command
Detail bool
}

func NewTemporalOperatorClusterDescribeCommand(cctx *CommandContext, parent *TemporalOperatorClusterCommand) *TemporalOperatorClusterDescribeCommand {
var s TemporalOperatorClusterDescribeCommand
s.Parent = parent
s.Command.DisableFlagsInUseLine = true
s.Command.Use = "describe [flags]"
s.Command.Short = "Describe a cluster"
if hasHighlighting {
s.Command.Long = "\x1b[1mtemporal operator cluster describe\x1b[0m command shows information about the Cluster."
} else {
s.Command.Long = "`temporal operator cluster describe` command shows information about the Cluster."
}
s.Command.Args = cobra.NoArgs
s.Command.Flags().BoolVar(&s.Detail, "detail", false, "Prints extra details.")
s.Command.Run = func(c *cobra.Command, args []string) {
if err := s.run(cctx, args); err != nil {
cctx.Options.Fail(err)
}
}
return &s
}

type TemporalOperatorClusterHealthCommand struct {
Parent *TemporalOperatorClusterCommand
Command cobra.Command
}

func NewTemporalOperatorClusterHealthCommand(cctx *CommandContext, parent *TemporalOperatorClusterCommand) *TemporalOperatorClusterHealthCommand {
var s TemporalOperatorClusterHealthCommand
s.Parent = parent
s.Command.DisableFlagsInUseLine = true
s.Command.Use = "health [flags]"
s.Command.Short = "Checks the health of a cluster"
if hasHighlighting {
s.Command.Long = "\x1b[1mtemporal operator cluster health\x1b[0m command checks the health of the Frontend Service."
} else {
s.Command.Long = "`temporal operator cluster health` command checks the health of the Frontend Service."
}
s.Command.Args = cobra.NoArgs
s.Command.Run = func(c *cobra.Command, args []string) {
if err := s.run(cctx, args); err != nil {
cctx.Options.Fail(err)
}
}
return &s
}

type TemporalOperatorClusterSystemCommand struct {
Parent *TemporalOperatorClusterCommand
Command cobra.Command
}

func NewTemporalOperatorClusterSystemCommand(cctx *CommandContext, parent *TemporalOperatorClusterCommand) *TemporalOperatorClusterSystemCommand {
var s TemporalOperatorClusterSystemCommand
s.Parent = parent
s.Command.DisableFlagsInUseLine = true
s.Command.Use = "system [flags]"
s.Command.Short = "Provide system info"
if hasHighlighting {
s.Command.Long = "\x1b[1mtemporal operator cluster system\x1b[0m command provides information about the system the Cluster is running on. This information can be used to diagnose problems occurring in the Temporal Server."
} else {
s.Command.Long = "`temporal operator cluster system` command provides information about the system the Cluster is running on. This information can be used to diagnose problems occurring in the Temporal Server."
}
s.Command.Args = cobra.NoArgs
s.Command.Run = func(c *cobra.Command, args []string) {
if err := s.run(cctx, args); err != nil {
cctx.Options.Fail(err)
}
}
return &s
}

type TemporalServerCommand struct {
Parent *TemporalCommand
Command cobra.Command
Expand Down
88 changes: 88 additions & 0 deletions temporalcli/commands.operator.go
Quinn-With-Two-Ns marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
package temporalcli

import (
"fmt"

"github.com/fatih/color"
"github.com/temporalio/cli/temporalcli/internal/printer"
"go.temporal.io/api/workflowservice/v1"
"go.temporal.io/sdk/client"
)

func (c *TemporalOperatorClusterHealthCommand) run(cctx *CommandContext, args []string) error {
cl, err := c.Parent.Parent.ClientOptions.dialClient(cctx)
if err != nil {
return err
}
defer cl.Close()
_, err = cl.CheckHealth(cctx, &client.CheckHealthRequest{})
if err != nil {
return fmt.Errorf("failed checking cluster health: %w", err)
}
if cctx.JSONOutput {
return cctx.Printer.PrintStructured(
struct {
Status string `json:"status"`
}{"SERVING"},
Quinn-With-Two-Ns marked this conversation as resolved.
Show resolved Hide resolved
printer.StructuredOptions{})
}
cctx.Printer.Println(color.GreenString("SERVING"))
return nil
}

func (c *TemporalOperatorClusterSystemCommand) run(cctx *CommandContext, args []string) error {
cl, err := c.Parent.Parent.ClientOptions.dialClient(cctx)
if err != nil {
return err
}
defer cl.Close()
resp, err := cl.WorkflowService().GetSystemInfo(cctx, &workflowservice.GetSystemInfoRequest{})
if err != nil {
return fmt.Errorf("unable to get system information: %w", err)
}
// For JSON, we'll just dump the proto
if cctx.JSONOutput {
return cctx.Printer.PrintStructured(resp, printer.StructuredOptions{})
}
return cctx.Printer.PrintStructured(
struct {
ServerVersion string
SupportsSchedules bool
UpsertMemo bool
EagerWorkflowStart bool
}{
ServerVersion: resp.GetServerVersion(),
SupportsSchedules: resp.GetCapabilities().SupportsSchedules,
UpsertMemo: resp.GetCapabilities().UpsertMemo,
EagerWorkflowStart: resp.GetCapabilities().EagerWorkflowStart,
},
printer.StructuredOptions{
Table: &printer.TableOptions{},
})
Quinn-With-Two-Ns marked this conversation as resolved.
Show resolved Hide resolved
}

func (c *TemporalOperatorClusterDescribeCommand) run(cctx *CommandContext, args []string) error {
cl, err := c.Parent.Parent.ClientOptions.dialClient(cctx)
if err != nil {
return err
}
defer cl.Close()
resp, err := cl.WorkflowService().GetClusterInfo(cctx, &workflowservice.GetClusterInfoRequest{})
if err != nil {
return fmt.Errorf("unable to get cluster information: %w", err)
}
// For JSON, we'll just dump the proto
if cctx.JSONOutput {
return cctx.Printer.PrintStructured(resp, printer.StructuredOptions{})
}

fields := []string{"ClusterName", "PersistenceStore", "VisibilityStore"}
if c.Detail {
fields = append(fields, "HistoryShardCount", "VersionInfo")
}

return cctx.Printer.PrintStructured(resp, printer.StructuredOptions{
Fields: fields,
Table: &printer.TableOptions{},
})
}
81 changes: 81 additions & 0 deletions temporalcli/commands.operator_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
package temporalcli_test

import (
"encoding/json"

"github.com/temporalio/cli/temporalcli"
"go.temporal.io/api/workflowservice/v1"
)

func (s *SharedServerSuite) TestOperator_Cluster_System() {
// Text
res := s.Execute(
"operator", "cluster", "system",
"--address", s.Address(),
)
s.NoError(res.Err)
out := res.Stdout.String()
s.ContainsOnSameLine(out, "ServerVersion", "SupportsSchedules", "UpsertMemo", "EagerWorkflowStart")
s.ContainsOnSameLine(out, "true", "true", "true")

// JSON
res = s.Execute(
"operator", "cluster", "system",
"-o", "json",
"--address", s.Address(),
)
s.NoError(res.Err)
var jsonOut workflowservice.GetSystemInfoResponse
s.NoError(temporalcli.UnmarshalProtoJSONWithOptions(res.Stdout.Bytes(), &jsonOut, true))
s.NotEmpty(jsonOut.ServerVersion)
s.True(jsonOut.Capabilities.SupportsSchedules)
s.True(jsonOut.Capabilities.UpsertMemo)
s.True(jsonOut.Capabilities.EagerWorkflowStart)
}

func (s *SharedServerSuite) TestOperator_Cluster_Describe() {
// Text
res := s.Execute(
"operator", "cluster", "describe",
"--address", s.Address(),
)
s.NoError(res.Err)
out := res.Stdout.String()
s.ContainsOnSameLine(out, "ClusterName", "PersistenceStore", "VisibilityStore")
s.ContainsOnSameLine(out, "active", "sqlite", "sqlite")

// JSON
res = s.Execute(
"operator", "cluster", "describe",
"--address", s.Address(),
"-o", "json",
)
s.NoError(res.Err)
var jsonOut workflowservice.GetClusterInfoResponse
s.NoError(temporalcli.UnmarshalProtoJSONWithOptions(res.Stdout.Bytes(), &jsonOut, true))
s.Equal("active", jsonOut.ClusterName)
s.Equal("sqlite", jsonOut.PersistenceStore)
s.Equal("sqlite", jsonOut.VisibilityStore)
}

func (s *SharedServerSuite) TestOperator_Cluster_Health() {
// Text
res := s.Execute(
"operator", "cluster", "health",
"--address", s.Address(),
)
s.NoError(res.Err)
out := res.Stdout.String()
s.Equal(out, "SERVING\n")

// JSON
res = s.Execute(
"operator", "cluster", "health",
"--address", s.Address(),
"-o", "json",
)
s.NoError(res.Err)
var jsonOut map[string]string
s.NoError(json.Unmarshal(res.Stdout.Bytes(), &jsonOut))
s.Equal(jsonOut["status"], "SERVING")
}
32 changes: 32 additions & 0 deletions temporalcli/commandsmd/commands.md
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,38 @@ Property names match CLI option names, for example '--address' and '--tls-cert-p
* exact-args=2
-->

### temporal operator: Manage a Temporal deployment.

Operator commands enable actions on Namespaces, Search Attributes, and Temporal Clusters. These actions are performed through subcommands.

To run an Operator command, `run temporal operator [command] [subcommand] [command options]`

#### Options

Includes options set for [client](#options-set-for-client).

### temporal operator cluster: Operations for running a Temporal Cluster.

Cluster commands enable actions on Temporal Clusters.

Cluster commands follow this syntax: `temporal operator cluster [command] [command options]`

### temporal operator cluster describe: Describe a cluster

`temporal operator cluster describe` command shows information about the Cluster.

#### Options

* `--detail` (bool) - Prints extra details.

### temporal operator cluster health: Checks the health of a cluster

`temporal operator cluster health` command checks the health of the Frontend Service.

### temporal operator cluster system: Provide system info

`temporal operator cluster system` command provides information about the system the Cluster is running on. This information can be used to diagnose problems occurring in the Temporal Server.

### temporal server: Run Temporal Server.

Start a development version of [Temporal Server](/concepts/what-is-the-temporal-server):
Expand Down
Loading