Skip to content

Commit

Permalink
Add tctl resource commands for AutoUpdateConfig and AutoUpdateVersion (
Browse files Browse the repository at this point in the history
…#46771)

* Add autoupdate command for resource

* Reuse client methods

* Implement all exposed auto update methods for service client

* Fix linter
  • Loading branch information
vapopov committed Sep 21, 2024
1 parent 15fcdf4 commit e4d644d
Show file tree
Hide file tree
Showing 6 changed files with 384 additions and 0 deletions.
107 changes: 107 additions & 0 deletions api/client/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ import (
accesslistv1 "github.com/gravitational/teleport/api/gen/proto/go/teleport/accesslist/v1"
accessmonitoringrulev1 "github.com/gravitational/teleport/api/gen/proto/go/teleport/accessmonitoringrules/v1"
auditlogpb "github.com/gravitational/teleport/api/gen/proto/go/teleport/auditlog/v1"
autoupdatev1pb "github.com/gravitational/teleport/api/gen/proto/go/teleport/autoupdate/v1"
clusterconfigpb "github.com/gravitational/teleport/api/gen/proto/go/teleport/clusterconfig/v1"
crownjewelv1 "github.com/gravitational/teleport/api/gen/proto/go/teleport/crownjewel/v1"
dbobjectv1 "github.com/gravitational/teleport/api/gen/proto/go/teleport/dbobject/v1"
Expand Down Expand Up @@ -3143,6 +3144,112 @@ func (c *Client) GetClusterAuditConfig(ctx context.Context) (types.ClusterAuditC
return resp, nil
}

// CreateAutoUpdateConfig creates AutoUpdateConfig resource.
func (c *Client) CreateAutoUpdateConfig(ctx context.Context, config *autoupdatev1pb.AutoUpdateConfig) (*autoupdatev1pb.AutoUpdateConfig, error) {
client := autoupdatev1pb.NewAutoUpdateServiceClient(c.conn)
resp, err := client.CreateAutoUpdateConfig(ctx, &autoupdatev1pb.CreateAutoUpdateConfigRequest{
Config: config,
})
if err != nil {
return nil, trace.Wrap(err)
}
return resp, nil
}

// GetAutoUpdateConfig gets AutoUpdateConfig resource.
func (c *Client) GetAutoUpdateConfig(ctx context.Context) (*autoupdatev1pb.AutoUpdateConfig, error) {
client := autoupdatev1pb.NewAutoUpdateServiceClient(c.conn)
resp, err := client.GetAutoUpdateConfig(ctx, &autoupdatev1pb.GetAutoUpdateConfigRequest{})
if err != nil {
return nil, trace.Wrap(err)
}
return resp, nil
}

// UpdateAutoUpdateConfig updates AutoUpdateConfig resource.
func (c *Client) UpdateAutoUpdateConfig(ctx context.Context, config *autoupdatev1pb.AutoUpdateConfig) (*autoupdatev1pb.AutoUpdateConfig, error) {
client := autoupdatev1pb.NewAutoUpdateServiceClient(c.conn)
resp, err := client.UpdateAutoUpdateConfig(ctx, &autoupdatev1pb.UpdateAutoUpdateConfigRequest{
Config: config,
})
if err != nil {
return nil, trace.Wrap(err)
}
return resp, nil
}

// UpsertAutoUpdateConfig updates or creates AutoUpdateConfig resource.
func (c *Client) UpsertAutoUpdateConfig(ctx context.Context, config *autoupdatev1pb.AutoUpdateConfig) (*autoupdatev1pb.AutoUpdateConfig, error) {
client := autoupdatev1pb.NewAutoUpdateServiceClient(c.conn)
resp, err := client.UpsertAutoUpdateConfig(ctx, &autoupdatev1pb.UpsertAutoUpdateConfigRequest{
Config: config,
})
if err != nil {
return nil, trace.Wrap(err)
}
return resp, nil
}

// DeleteAutoUpdateConfig deletes AutoUpdateConfig resource.
func (c *Client) DeleteAutoUpdateConfig(ctx context.Context) error {
client := autoupdatev1pb.NewAutoUpdateServiceClient(c.conn)
_, err := client.DeleteAutoUpdateConfig(ctx, &autoupdatev1pb.DeleteAutoUpdateConfigRequest{})
return trace.Wrap(err)
}

// CreateAutoUpdateVersion creates AutoUpdateVersion resource.
func (c *Client) CreateAutoUpdateVersion(ctx context.Context, version *autoupdatev1pb.AutoUpdateVersion) (*autoupdatev1pb.AutoUpdateVersion, error) {
client := autoupdatev1pb.NewAutoUpdateServiceClient(c.conn)
resp, err := client.CreateAutoUpdateVersion(ctx, &autoupdatev1pb.CreateAutoUpdateVersionRequest{
Version: version,
})
if err != nil {
return nil, trace.Wrap(err)
}
return resp, nil
}

// GetAutoUpdateVersion gets AutoUpdateVersion resource.
func (c *Client) GetAutoUpdateVersion(ctx context.Context) (*autoupdatev1pb.AutoUpdateVersion, error) {
client := autoupdatev1pb.NewAutoUpdateServiceClient(c.conn)
resp, err := client.GetAutoUpdateVersion(ctx, &autoupdatev1pb.GetAutoUpdateVersionRequest{})
if err != nil {
return nil, trace.Wrap(err)
}
return resp, nil
}

// UpdateAutoUpdateVersion updates AutoUpdateVersion resource.
func (c *Client) UpdateAutoUpdateVersion(ctx context.Context, version *autoupdatev1pb.AutoUpdateVersion) (*autoupdatev1pb.AutoUpdateVersion, error) {
client := autoupdatev1pb.NewAutoUpdateServiceClient(c.conn)
resp, err := client.UpdateAutoUpdateVersion(ctx, &autoupdatev1pb.UpdateAutoUpdateVersionRequest{
Version: version,
})
if err != nil {
return nil, trace.Wrap(err)
}
return resp, nil
}

// UpsertAutoUpdateVersion updates or creates AutoUpdateVersion resource.
func (c *Client) UpsertAutoUpdateVersion(ctx context.Context, version *autoupdatev1pb.AutoUpdateVersion) (*autoupdatev1pb.AutoUpdateVersion, error) {
client := autoupdatev1pb.NewAutoUpdateServiceClient(c.conn)
resp, err := client.UpsertAutoUpdateVersion(ctx, &autoupdatev1pb.UpsertAutoUpdateVersionRequest{
Version: version,
})
if err != nil {
return nil, trace.Wrap(err)
}
return resp, nil
}

// DeleteAutoUpdateVersion deletes AutoUpdateVersion resource.
func (c *Client) DeleteAutoUpdateVersion(ctx context.Context) error {
client := autoupdatev1pb.NewAutoUpdateServiceClient(c.conn)
_, err := client.DeleteAutoUpdateVersion(ctx, &autoupdatev1pb.DeleteAutoUpdateVersionRequest{})
return trace.Wrap(err)
}

// GetClusterAccessGraphConfig retrieves the Cluster Access Graph configuration from Auth server.
func (c *Client) GetClusterAccessGraphConfig(ctx context.Context) (*clusterconfigpb.AccessGraphConfig, error) {
rsp, err := c.ClusterConfigClient().GetClusterAccessGraphConfig(ctx, &clusterconfigpb.GetClusterAccessGraphConfigRequest{})
Expand Down
4 changes: 4 additions & 0 deletions lib/services/resource.go
Original file line number Diff line number Diff line change
Expand Up @@ -250,6 +250,10 @@ func ParseShortcut(in string) (string, error) {
return types.KindAccessGraphSettings, nil
case types.KindSPIFFEFederation, types.KindSPIFFEFederation + "s":
return types.KindSPIFFEFederation, nil
case types.KindAutoUpdateConfig:
return types.KindAutoUpdateConfig, nil
case types.KindAutoUpdateVersion:
return types.KindAutoUpdateVersion, nil
}
return "", trace.BadParameter("unsupported resource: %q - resources should be expressed as 'type/name', for example 'connector/github'", in)
}
Expand Down
37 changes: 37 additions & 0 deletions tool/tctl/common/collection.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ import (
"github.com/gravitational/trace"

"github.com/gravitational/teleport/api/constants"
autoupdatev1pb "github.com/gravitational/teleport/api/gen/proto/go/teleport/autoupdate/v1"
crownjewelv1 "github.com/gravitational/teleport/api/gen/proto/go/teleport/crownjewel/v1"
dbobjectv1 "github.com/gravitational/teleport/api/gen/proto/go/teleport/dbobject/v1"
dbobjectimportrulev1 "github.com/gravitational/teleport/api/gen/proto/go/teleport/dbobjectimportrule/v1"
Expand Down Expand Up @@ -1677,3 +1678,39 @@ func (c *spiffeFederationCollection) writeText(w io.Writer, verbose bool) error
_, err := t.AsBuffer().WriteTo(w)
return trace.Wrap(err)
}

type autoUpdateConfigCollection struct {
config *autoupdatev1pb.AutoUpdateConfig
}

func (c *autoUpdateConfigCollection) resources() []types.Resource {
return []types.Resource{types.Resource153ToLegacy(c.config)}
}

func (c *autoUpdateConfigCollection) writeText(w io.Writer, verbose bool) error {
t := asciitable.MakeTable([]string{"Name", "Tools AutoUpdate Enabled"})
t.AddRow([]string{
c.config.GetMetadata().GetName(),
fmt.Sprintf("%v", c.config.GetSpec().GetToolsAutoupdate()),
})
_, err := t.AsBuffer().WriteTo(w)
return trace.Wrap(err)
}

type autoUpdateVersionCollection struct {
version *autoupdatev1pb.AutoUpdateVersion
}

func (c *autoUpdateVersionCollection) resources() []types.Resource {
return []types.Resource{types.Resource153ToLegacy(c.version)}
}

func (c *autoUpdateVersionCollection) writeText(w io.Writer, verbose bool) error {
t := asciitable.MakeTable([]string{"Name", "Tools AutoUpdate Version"})
t.AddRow([]string{
c.version.GetMetadata().GetName(),
fmt.Sprintf("%v", c.version.GetSpec().GetToolsVersion()),
})
_, err := t.AsBuffer().WriteTo(w)
return trace.Wrap(err)
}

Check failure on line 1716 in tool/tctl/common/collection.go

View workflow job for this annotation

GitHub Actions / Lint (Go)

File is not `gci`-ed with --skip-generated -s standard -s default -s prefix(github.com/gravitational/teleport) --custom-order (gci)

Check failure on line 1716 in tool/tctl/common/collection.go

View workflow job for this annotation

GitHub Actions / Lint (Go)

File is not `goimports`-ed (goimports)
78 changes: 78 additions & 0 deletions tool/tctl/common/edit_command_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,9 @@ import (
"github.com/stretchr/testify/require"

"github.com/gravitational/teleport/api/constants"
autoupdatev1pb "github.com/gravitational/teleport/api/gen/proto/go/teleport/autoupdate/v1"
"github.com/gravitational/teleport/api/types"
"github.com/gravitational/teleport/api/types/autoupdate"
"github.com/gravitational/teleport/lib/auth/authclient"
"github.com/gravitational/teleport/lib/backend"
"github.com/gravitational/teleport/lib/modules"
Expand Down Expand Up @@ -72,6 +74,14 @@ func TestEditResources(t *testing.T) {
kind: types.KindSessionRecordingConfig,
edit: testEditSessionRecordingConfig,
},
{
kind: types.KindAutoUpdateConfig,
edit: testEditAutoUpdateConfig,
},
{
kind: types.KindAutoUpdateVersion,
edit: testEditAutoUpdateVersion,
},
}

for _, test := range tests {
Expand Down Expand Up @@ -482,3 +492,71 @@ func testEditSAMLConnector(t *testing.T, clt *authclient.Client) {
assert.Error(t, err, "stale connector was allowed to be updated")
require.ErrorIs(t, err, backend.ErrIncorrectRevision, "expected an incorrect revision error, got %T", err)
}

func testEditAutoUpdateConfig(t *testing.T, clt *authclient.Client) {
ctx := context.Background()

expected, err := autoupdate.NewAutoUpdateConfig(&autoupdatev1pb.AutoUpdateConfigSpec{ToolsAutoupdate: true})
require.NoError(t, err)

initial, err := autoupdate.NewAutoUpdateConfig(&autoupdatev1pb.AutoUpdateConfigSpec{ToolsAutoupdate: false})
require.NoError(t, err)

serviceClient := autoupdatev1pb.NewAutoUpdateServiceClient(clt.GetConnection())
_, err = serviceClient.CreateAutoUpdateConfig(ctx, &autoupdatev1pb.CreateAutoUpdateConfigRequest{Config: initial})
require.NoError(t, err, "creating initial autoupdate config")

editor := func(name string) error {
f, err := os.Create(name)
if err != nil {
return trace.Wrap(err, "opening file to edit")
}
expected.GetMetadata().Revision = initial.GetMetadata().GetRevision()
collection := &autoUpdateConfigCollection{config: expected}
return trace.NewAggregate(writeYAML(collection, f), f.Close())
}

// Edit the AutoUpdateConfig resource.
_, err = runEditCommand(t, clt, []string{"edit", "autoupdate_config"}, withEditor(editor))
require.NoError(t, err, "expected editing autoupdate config to succeed")

actual, err := clt.GetAutoUpdateConfig(ctx)
require.NoError(t, err, "failed to get autoupdate config after edit")
assert.NotEqual(t, initial.GetSpec().GetToolsAutoupdate(), actual.GetSpec().GetToolsAutoupdate(),
"tools_autoupdate should have been modified by edit")
assert.Equal(t, expected.GetSpec().GetToolsAutoupdate(), actual.GetSpec().GetToolsAutoupdate())
}

func testEditAutoUpdateVersion(t *testing.T, clt *authclient.Client) {
ctx := context.Background()

expected, err := autoupdate.NewAutoUpdateVersion(&autoupdatev1pb.AutoUpdateVersionSpec{ToolsVersion: "3.2.1"})
require.NoError(t, err)

initial, err := autoupdate.NewAutoUpdateVersion(&autoupdatev1pb.AutoUpdateVersionSpec{ToolsVersion: "1.2.3"})
require.NoError(t, err)

serviceClient := autoupdatev1pb.NewAutoUpdateServiceClient(clt.GetConnection())
_, err = serviceClient.CreateAutoUpdateVersion(ctx, &autoupdatev1pb.CreateAutoUpdateVersionRequest{Version: initial})
require.NoError(t, err, "creating initial autoupdate version")

editor := func(name string) error {
f, err := os.Create(name)
if err != nil {
return trace.Wrap(err, "opening file to edit")
}
expected.GetMetadata().Revision = initial.GetMetadata().GetRevision()
collection := &autoUpdateVersionCollection{version: expected}
return trace.NewAggregate(writeYAML(collection, f), f.Close())
}

// Edit the AutoUpdateVersion resource.
_, err = runEditCommand(t, clt, []string{"edit", "autoupdate_version"}, withEditor(editor))
require.NoError(t, err, "expected editing autoupdate version to succeed")

actual, err := clt.GetAutoUpdateVersion(ctx)
require.NoError(t, err, "failed to get autoupdate version after edit")
assert.NotEqual(t, initial.GetSpec().GetToolsVersion(), actual.GetSpec().GetToolsVersion(),
"tools_autoupdate should have been modified by edit")
assert.Equal(t, expected.GetSpec().GetToolsVersion(), actual.GetSpec().GetToolsVersion())
}
79 changes: 79 additions & 0 deletions tool/tctl/common/resource_command.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ import (
apiclient "github.com/gravitational/teleport/api/client"
"github.com/gravitational/teleport/api/client/proto"
apidefaults "github.com/gravitational/teleport/api/defaults"
autoupdatev1pb "github.com/gravitational/teleport/api/gen/proto/go/teleport/autoupdate/v1"
clusterconfigpb "github.com/gravitational/teleport/api/gen/proto/go/teleport/clusterconfig/v1"
crownjewelv1 "github.com/gravitational/teleport/api/gen/proto/go/teleport/crownjewel/v1"
dbobjectv1 "github.com/gravitational/teleport/api/gen/proto/go/teleport/dbobject/v1"
Expand Down Expand Up @@ -164,6 +165,8 @@ func (rc *ResourceCommand) Initialize(app *kingpin.Application, config *servicec
types.KindAccessGraphSettings: rc.upsertAccessGraphSettings,
types.KindPlugin: rc.createPlugin,
types.KindSPIFFEFederation: rc.createSPIFFEFederation,
types.KindAutoUpdateConfig: rc.createAutoUpdateConfig,
types.KindAutoUpdateVersion: rc.createAutoUpdateVersion,
}
rc.UpdateHandlers = map[ResourceKind]ResourceCreateHandler{
types.KindUser: rc.updateUser,
Expand All @@ -178,6 +181,8 @@ func (rc *ResourceCommand) Initialize(app *kingpin.Application, config *servicec
types.KindCrownJewel: rc.updateCrownJewel,
types.KindAccessGraphSettings: rc.updateAccessGraphSettings,
types.KindPlugin: rc.updatePlugin,
types.KindAutoUpdateConfig: rc.updateAutoUpdateConfig,
types.KindAutoUpdateVersion: rc.updateAutoUpdateVersion,
}
rc.config = config

Expand Down Expand Up @@ -2885,6 +2890,18 @@ func (rc *ResourceCommand) getCollection(ctx context.Context, client *authclient
}

return &spiffeFederationCollection{items: resources}, nil
case types.KindAutoUpdateConfig:
config, err := client.GetAutoUpdateConfig(ctx)
if err != nil {
return nil, trace.Wrap(err)
}
return &autoUpdateConfigCollection{config}, nil
case types.KindAutoUpdateVersion:
version, err := client.GetAutoUpdateVersion(ctx)
if err != nil {
return nil, trace.Wrap(err)
}
return &autoUpdateVersionCollection{version}, nil
}
return nil, trace.BadParameter("getting %q is not supported", rc.ref.String())
}
Expand Down Expand Up @@ -3199,3 +3216,65 @@ func (rc *ResourceCommand) updateAccessGraphSettings(ctx context.Context, client
fmt.Println("access_graph_settings has been updated")
return nil
}

func (rc *ResourceCommand) createAutoUpdateConfig(ctx context.Context, client *authclient.Client, raw services.UnknownResource) error {
config, err := services.UnmarshalProtoResource[*autoupdatev1pb.AutoUpdateConfig](raw.Raw)
if err != nil {
return trace.Wrap(err)
}

if rc.IsForced() {
_, err = client.UpsertAutoUpdateConfig(ctx, config)
} else {
_, err = client.CreateAutoUpdateConfig(ctx, config)
}
if err != nil {
return trace.Wrap(err)
}

fmt.Println("autoupdate_config has been created")
return nil
}

func (rc *ResourceCommand) updateAutoUpdateConfig(ctx context.Context, client *authclient.Client, raw services.UnknownResource) error {
config, err := services.UnmarshalProtoResource[*autoupdatev1pb.AutoUpdateConfig](raw.Raw)
if err != nil {
return trace.Wrap(err)
}
if _, err := client.UpdateAutoUpdateConfig(ctx, config); err != nil {
return trace.Wrap(err)
}
fmt.Println("autoupdate_config has been updated")
return nil
}

func (rc *ResourceCommand) createAutoUpdateVersion(ctx context.Context, client *authclient.Client, raw services.UnknownResource) error {
version, err := services.UnmarshalProtoResource[*autoupdatev1pb.AutoUpdateVersion](raw.Raw)
if err != nil {
return trace.Wrap(err)
}

if rc.IsForced() {
_, err = client.UpsertAutoUpdateVersion(ctx, version)
} else {
_, err = client.CreateAutoUpdateVersion(ctx, version)
}
if err != nil {
return trace.Wrap(err)
}

fmt.Println("autoupdate_version has been created")
return nil
}

func (rc *ResourceCommand) updateAutoUpdateVersion(ctx context.Context, client *authclient.Client, raw services.UnknownResource) error {
version, err := services.UnmarshalProtoResource[*autoupdatev1pb.AutoUpdateVersion](raw.Raw)
if err != nil {
return trace.Wrap(err)
}
if _, err := client.UpdateAutoUpdateVersion(ctx, version); err != nil {
return trace.Wrap(err)
}
fmt.Println("autoupdate_version has been updated")
return nil
}
Loading

0 comments on commit e4d644d

Please sign in to comment.