|
| 1 | +package switchover |
| 2 | + |
| 3 | +import ( |
| 4 | + "fmt" |
| 5 | + "strings" |
| 6 | + |
| 7 | + "github.com/spf13/cobra" |
| 8 | + |
| 9 | + switchoverv1 "github.com/confluentinc/ccloud-sdk-go-v2-internal/switchover/v1" |
| 10 | + |
| 11 | + "github.com/confluentinc/cli/v4/pkg/ccloudv2" |
| 12 | + "github.com/confluentinc/cli/v4/pkg/output" |
| 13 | +) |
| 14 | + |
| 15 | +func (c *command) newEndpointCommand() *cobra.Command { |
| 16 | + cmd := &cobra.Command{ |
| 17 | + Use: "endpoint", |
| 18 | + Short: "Manage switchover endpoints.", |
| 19 | + Long: "Manage endpoint-level Disaster Recovery switchover endpoints for Kafka.", |
| 20 | + Args: cobra.NoArgs, |
| 21 | + } |
| 22 | + |
| 23 | + cmd.AddCommand(c.newEndpointActivateCommand()) |
| 24 | + cmd.AddCommand(c.newEndpointCreateCommand()) |
| 25 | + cmd.AddCommand(c.newEndpointDeleteCommand()) |
| 26 | + cmd.AddCommand(c.newEndpointDescribeCommand()) |
| 27 | + cmd.AddCommand(c.newEndpointListCommand()) |
| 28 | + cmd.AddCommand(c.newEndpointUpdateCommand()) |
| 29 | + |
| 30 | + return cmd |
| 31 | +} |
| 32 | + |
| 33 | +// parseEndpoint parses an `--endpoint` flag value into a SwitchoverV1EndpointConfig. |
| 34 | +// Format: comma-separated key=value pairs, for example: |
| 35 | +// |
| 36 | +// name=west-platt,resource-id=lkc-west,type=PRIVATE,cloud=AWS,region=us-west-2,gateway=n-ccn-west-1 |
| 37 | +// |
| 38 | +// `name`, `resource-id`, and `type` are required; `cloud`, `region`, `gateway`, |
| 39 | +// and `access-point` are optional. |
| 40 | +func parseEndpoint(raw string) (switchoverv1.SwitchoverV1EndpointConfig, error) { |
| 41 | + fields := map[string]string{} |
| 42 | + for _, pair := range strings.Split(raw, ",") { |
| 43 | + if strings.TrimSpace(pair) == "" { |
| 44 | + continue |
| 45 | + } |
| 46 | + kv := strings.SplitN(pair, "=", 2) |
| 47 | + if len(kv) != 2 { |
| 48 | + return switchoverv1.SwitchoverV1EndpointConfig{}, fmt.Errorf(`invalid --endpoint value %q: each field must be "key=value"`, raw) |
| 49 | + } |
| 50 | + fields[strings.TrimSpace(kv[0])] = strings.TrimSpace(kv[1]) |
| 51 | + } |
| 52 | + |
| 53 | + name := fields["name"] |
| 54 | + resourceId := fields["resource-id"] |
| 55 | + endpointType := strings.ToUpper(fields["type"]) |
| 56 | + if name == "" || resourceId == "" || endpointType == "" { |
| 57 | + return switchoverv1.SwitchoverV1EndpointConfig{}, fmt.Errorf(`invalid --endpoint value %q: "name", "resource-id", and "type" are required`, raw) |
| 58 | + } |
| 59 | + |
| 60 | + filter := switchoverv1.SwitchoverV1EndpointFilter{ |
| 61 | + ResourceId: resourceId, |
| 62 | + Type: endpointType, |
| 63 | + } |
| 64 | + if v, ok := fields["cloud"]; ok { |
| 65 | + filter.SetCloud(strings.ToUpper(v)) |
| 66 | + } |
| 67 | + if v, ok := fields["region"]; ok { |
| 68 | + filter.SetRegion(v) |
| 69 | + } |
| 70 | + if v, ok := fields["gateway"]; ok { |
| 71 | + filter.SetGateway(v) |
| 72 | + } |
| 73 | + if v, ok := fields["access-point"]; ok { |
| 74 | + filter.SetAccessPoint(v) |
| 75 | + } |
| 76 | + |
| 77 | + return switchoverv1.SwitchoverV1EndpointConfig{Name: name, EndpointFilter: filter}, nil |
| 78 | +} |
| 79 | + |
| 80 | +func (c *command) validEndpointArgs(cmd *cobra.Command, args []string) []string { |
| 81 | + if len(args) > 0 { |
| 82 | + return nil |
| 83 | + } |
| 84 | + if err := c.PersistentPreRunE(cmd, args); err != nil { |
| 85 | + return nil |
| 86 | + } |
| 87 | + environmentId, err := c.Context.EnvironmentId() |
| 88 | + if err != nil { |
| 89 | + return nil |
| 90 | + } |
| 91 | + return autocompleteEndpoints(c.V2Client, environmentId) |
| 92 | +} |
| 93 | + |
| 94 | +func autocompleteEndpoints(client *ccloudv2.Client, environmentId string) []string { |
| 95 | + endpoints, err := client.ListSwitchoverEndpoints(environmentId) |
| 96 | + if err != nil { |
| 97 | + return nil |
| 98 | + } |
| 99 | + suggestions := make([]string, len(endpoints)) |
| 100 | + for i, endpoint := range endpoints { |
| 101 | + suggestions[i] = fmt.Sprintf("%s\t%s", endpoint.GetId(), endpoint.Spec.GetDisplayName()) |
| 102 | + } |
| 103 | + return suggestions |
| 104 | +} |
| 105 | + |
| 106 | +func endpointNames(endpoint switchoverv1.SwitchoverV1SwitchoverEndpoint) []string { |
| 107 | + if endpoint.Spec == nil { |
| 108 | + return nil |
| 109 | + } |
| 110 | + names := make([]string, 0, len(endpoint.Spec.GetEndpoints())) |
| 111 | + for _, config := range endpoint.Spec.GetEndpoints() { |
| 112 | + names = append(names, config.GetName()) |
| 113 | + } |
| 114 | + return names |
| 115 | +} |
| 116 | + |
| 117 | +func printEndpointTable(cmd *cobra.Command, endpoint switchoverv1.SwitchoverV1SwitchoverEndpoint) error { |
| 118 | + if endpoint.Spec == nil { |
| 119 | + return fmt.Errorf("switchover endpoint response is missing its spec") |
| 120 | + } |
| 121 | + |
| 122 | + out := &endpointOut{ |
| 123 | + Id: endpoint.GetId(), |
| 124 | + Name: endpoint.Spec.GetDisplayName(), |
| 125 | + Environment: endpoint.Spec.Environment.GetId(), |
| 126 | + SwitchoverPair: endpoint.Spec.SwitchoverPair.GetId(), |
| 127 | + Endpoints: endpointNames(endpoint), |
| 128 | + Target: endpoint.Spec.GetTarget(), |
| 129 | + DrEndpoint: endpoint.Spec.GetDrEndpoint(), |
| 130 | + } |
| 131 | + if endpoint.Status != nil { |
| 132 | + out.Phase = endpoint.Status.GetPhase() |
| 133 | + } |
| 134 | + |
| 135 | + table := output.NewTable(cmd) |
| 136 | + table.Add(out) |
| 137 | + return table.Print() |
| 138 | +} |
0 commit comments