From 3e3daecf112b3a834703ffddcb8f506c45c727d8 Mon Sep 17 00:00:00 2001 From: Hugo Shaka Date: Thu, 19 Dec 2024 13:57:58 -0500 Subject: [PATCH] add tctl create/get/edit support for autoupdate_agent_rollout (#50393) * add tctl create/get/edit support for autoupdate_agent_rollout * fix bad copy paste --- tool/tctl/common/collection.go | 22 +++++++++ tool/tctl/common/resource_command.go | 45 ++++++++++++++++++ tool/tctl/common/resource_command_test.go | 56 +++++++++++++++++++++++ 3 files changed, 123 insertions(+) diff --git a/tool/tctl/common/collection.go b/tool/tctl/common/collection.go index 3c844a28637a7..c31d2a25ed0bf 100644 --- a/tool/tctl/common/collection.go +++ b/tool/tctl/common/collection.go @@ -1939,6 +1939,28 @@ func (c *autoUpdateVersionCollection) writeText(w io.Writer, verbose bool) error return trace.Wrap(err) } +type autoUpdateAgentRolloutCollection struct { + rollout *autoupdatev1pb.AutoUpdateAgentRollout +} + +func (c *autoUpdateAgentRolloutCollection) resources() []types.Resource { + return []types.Resource{types.Resource153ToLegacy(c.rollout)} +} + +func (c *autoUpdateAgentRolloutCollection) writeText(w io.Writer, verbose bool) error { + t := asciitable.MakeTable([]string{"Name", "Start Version", "Target Version", "Mode", "Schedule", "Strategy"}) + t.AddRow([]string{ + c.rollout.GetMetadata().GetName(), + fmt.Sprintf("%v", c.rollout.GetSpec().GetStartVersion()), + fmt.Sprintf("%v", c.rollout.GetSpec().GetTargetVersion()), + fmt.Sprintf("%v", c.rollout.GetSpec().GetAutoupdateMode()), + fmt.Sprintf("%v", c.rollout.GetSpec().GetSchedule()), + fmt.Sprintf("%v", c.rollout.GetSpec().GetStrategy()), + }) + _, err := t.AsBuffer().WriteTo(w) + return trace.Wrap(err) +} + type accessMonitoringRuleCollection struct { items []*accessmonitoringrulesv1pb.AccessMonitoringRule } diff --git a/tool/tctl/common/resource_command.go b/tool/tctl/common/resource_command.go index e77b7eb4aaf4a..dd9d5ea13af20 100644 --- a/tool/tctl/common/resource_command.go +++ b/tool/tctl/common/resource_command.go @@ -180,6 +180,7 @@ func (rc *ResourceCommand) Initialize(app *kingpin.Application, _ *tctlcfg.Globa types.KindAutoUpdateConfig: rc.createAutoUpdateConfig, types.KindAutoUpdateVersion: rc.createAutoUpdateVersion, types.KindGitServer: rc.createGitServer, + types.KindAutoUpdateAgentRollout: rc.createAutoUpdateAgentRollout, } rc.UpdateHandlers = map[ResourceKind]ResourceCreateHandler{ types.KindUser: rc.updateUser, @@ -201,6 +202,7 @@ func (rc *ResourceCommand) Initialize(app *kingpin.Application, _ *tctlcfg.Globa types.KindAutoUpdateVersion: rc.updateAutoUpdateVersion, types.KindDynamicWindowsDesktop: rc.updateDynamicWindowsDesktop, types.KindGitServer: rc.updateGitServer, + types.KindAutoUpdateAgentRollout: rc.updateAutoUpdateAgentRollout, } rc.config = config @@ -1617,6 +1619,7 @@ func (rc *ResourceCommand) Delete(ctx context.Context, client *authclient.Client types.KindNetworkRestrictions, types.KindAutoUpdateConfig, types.KindAutoUpdateVersion, + types.KindAutoUpdateAgentRollout, } if !slices.Contains(singletonResources, rc.ref.Kind) && (rc.ref.Kind == "" || rc.ref.Name == "") { return trace.BadParameter("provide a full resource name to delete, for example:\n$ tctl rm cluster/east\n") @@ -2039,6 +2042,11 @@ func (rc *ResourceCommand) Delete(ctx context.Context, client *authclient.Client return trace.Wrap(err) } fmt.Printf("AutoUpdateVersion has been deleted\n") + case types.KindAutoUpdateAgentRollout: + if err := client.DeleteAutoUpdateAgentRollout(ctx); err != nil { + return trace.Wrap(err) + } + fmt.Printf("AutoUpdateAgentRollout has been deleted\n") default: return trace.BadParameter("deleting resources of type %q is not supported", rc.ref.Kind) } @@ -3283,6 +3291,12 @@ func (rc *ResourceCommand) getCollection(ctx context.Context, client *authclient return nil, trace.Wrap(err) } return &autoUpdateVersionCollection{version}, nil + case types.KindAutoUpdateAgentRollout: + version, err := client.GetAutoUpdateAgentRollout(ctx) + if err != nil { + return nil, trace.Wrap(err) + } + return &autoUpdateAgentRolloutCollection{version}, nil case types.KindAccessMonitoringRule: if rc.ref.Name != "" { rule, err := client.AccessMonitoringRuleClient().GetAccessMonitoringRule(ctx, rc.ref.Name) @@ -3744,6 +3758,37 @@ func (rc *ResourceCommand) updateAutoUpdateVersion(ctx context.Context, client * return nil } +func (rc *ResourceCommand) createAutoUpdateAgentRollout(ctx context.Context, client *authclient.Client, raw services.UnknownResource) error { + version, err := services.UnmarshalProtoResource[*autoupdatev1pb.AutoUpdateAgentRollout](raw.Raw) + if err != nil { + return trace.Wrap(err) + } + + if rc.IsForced() { + _, err = client.UpsertAutoUpdateAgentRollout(ctx, version) + } else { + _, err = client.CreateAutoUpdateAgentRollout(ctx, version) + } + if err != nil { + return trace.Wrap(err) + } + + fmt.Println("autoupdate_agent_rollout has been created") + return nil +} + +func (rc *ResourceCommand) updateAutoUpdateAgentRollout(ctx context.Context, client *authclient.Client, raw services.UnknownResource) error { + version, err := services.UnmarshalProtoResource[*autoupdatev1pb.AutoUpdateAgentRollout](raw.Raw) + if err != nil { + return trace.Wrap(err) + } + if _, err := client.UpdateAutoUpdateAgentRollout(ctx, version); err != nil { + return trace.Wrap(err) + } + fmt.Println("autoupdate_version has been updated") + return nil +} + func (rc *ResourceCommand) createGitServer(ctx context.Context, client *authclient.Client, raw services.UnknownResource) error { server, err := services.UnmarshalGitServer(raw.Raw) if err != nil { diff --git a/tool/tctl/common/resource_command_test.go b/tool/tctl/common/resource_command_test.go index b3e13e9bffb6d..61b2c2650f53a 100644 --- a/tool/tctl/common/resource_command_test.go +++ b/tool/tctl/common/resource_command_test.go @@ -1427,6 +1427,10 @@ func TestCreateResources(t *testing.T) { kind: types.KindAutoUpdateVersion, create: testCreateAutoUpdateVersion, }, + { + kind: types.KindAutoUpdateAgentRollout, + create: testCreateAutoUpdateAgentRollout, + }, { kind: types.KindDynamicWindowsDesktop, create: testCreateDynamicWindowsDesktop, @@ -2387,6 +2391,58 @@ version: v1 require.ErrorContains(t, err, "autoupdate_version \"autoupdate-version\" doesn't exist") } +func testCreateAutoUpdateAgentRollout(t *testing.T, clt *authclient.Client) { + const resourceYAML = `kind: autoupdate_agent_rollout +metadata: + name: autoupdate-agent-rollout + revision: 3a43b44a-201e-4d7f-aef1-ae2f6d9811ed +spec: + start_version: 1.2.3 + target_version: 1.2.3 + autoupdate_mode: "suspended" + schedule: "regular" + strategy: "halt-on-error" +status: + groups: + - name: my-group + state: 1 + config_days: ["*"] + config_start_hour: 12 + config_wait_hours: 0 +version: v1 +` + _, err := runResourceCommand(t, clt, []string{"get", types.KindAutoUpdateAgentRollout, "--format=json"}) + require.ErrorContains(t, err, "doesn't exist") + + // Create the resource. + resourceYAMLPath := filepath.Join(t.TempDir(), "resource.yaml") + require.NoError(t, os.WriteFile(resourceYAMLPath, []byte(resourceYAML), 0644)) + _, err = runResourceCommand(t, clt, []string{"create", resourceYAMLPath}) + require.NoError(t, err) + + // Get the resource + buf, err := runResourceCommand(t, clt, []string{"get", types.KindAutoUpdateAgentRollout, "--format=json"}) + require.NoError(t, err) + resources := mustDecodeJSON[[]*autoupdate.AutoUpdateAgentRollout](t, buf) + require.Len(t, resources, 1) + + var expected autoupdate.AutoUpdateAgentRollout + require.NoError(t, yaml.Unmarshal([]byte(resourceYAML), &expected)) + + require.Empty(t, cmp.Diff( + []*autoupdate.AutoUpdateAgentRollout{&expected}, + resources, + protocmp.IgnoreFields(&headerv1.Metadata{}, "revision"), + protocmp.Transform(), + )) + + // Delete the resource + _, err = runResourceCommand(t, clt, []string{"rm", types.KindAutoUpdateAgentRollout}) + require.NoError(t, err) + _, err = runResourceCommand(t, clt, []string{"get", types.KindAutoUpdateAgentRollout}) + require.ErrorContains(t, err, "autoupdate_agent_rollout \"autoupdate-agent-rollout\" doesn't exist") +} + func testCreateDynamicWindowsDesktop(t *testing.T, clt *authclient.Client) { const resourceYAML = `kind: dynamic_windows_desktop metadata: