Skip to content

Commit

Permalink
[v17] Fix update and list for DynamicWindowsDesktops (#48159)
Browse files Browse the repository at this point in the history
* proto

* Fix update for DynamicWindowsDesktops

* fix test server

* fix test

* fix test

* fix test

* Update api/proto/teleport/dynamicwindows/v1/dynamicwindows_service.proto

Co-authored-by: Zac Bergquist <[email protected]>

* update proto

* fix tests

---------

Co-authored-by: Zac Bergquist <[email protected]>
  • Loading branch information
probakowski and zmb3 authored Oct 30, 2024
1 parent 346dd40 commit 4bb8cd4
Show file tree
Hide file tree
Showing 15 changed files with 240 additions and 48 deletions.
16 changes: 16 additions & 0 deletions api/client/dynamicwindows/dynamicwindows.go
Original file line number Diff line number Diff line change
Expand Up @@ -85,9 +85,25 @@ func (c *Client) UpdateDynamicWindowsDesktop(ctx context.Context, desktop types.
}
}

func (c *Client) UpsertDynamicWindowsDesktop(ctx context.Context, desktop types.DynamicWindowsDesktop) (types.DynamicWindowsDesktop, error) {
switch desktop := desktop.(type) {
case *types.DynamicWindowsDesktopV1:
desktop, err := c.grpcClient.UpsertDynamicWindowsDesktop(ctx, &dynamicwindows.UpsertDynamicWindowsDesktopRequest{
Desktop: desktop,
})
return desktop, trace.Wrap(err)
default:
return nil, trace.BadParameter("unknown desktop type: %T", desktop)
}
}

func (c *Client) DeleteDynamicWindowsDesktop(ctx context.Context, name string) error {
_, err := c.grpcClient.DeleteDynamicWindowsDesktop(ctx, &dynamicwindows.DeleteDynamicWindowsDesktopRequest{
Name: name,
})
return trace.Wrap(err)
}

func (c *Client) DeleteAllDynamicWindowsDesktops(ctx context.Context) error {
return trace.NotImplemented("DeleteAllDynamicWindowsDesktops is not supported in the gRPC client")
}
147 changes: 106 additions & 41 deletions api/gen/proto/go/teleport/dynamicwindows/v1/dynamicwindows_service.pb.go

Large diffs are not rendered by default.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

12 changes: 10 additions & 2 deletions api/proto/teleport/dynamicwindows/v1/dynamicwindows_service.proto
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,8 @@ service DynamicWindowsService {
rpc CreateDynamicWindowsDesktop(CreateDynamicWindowsDesktopRequest) returns (types.DynamicWindowsDesktopV1);
// UpdateDynamicWindowsDesktop updates an existing dynamic Windows desktop.
rpc UpdateDynamicWindowsDesktop(UpdateDynamicWindowsDesktopRequest) returns (types.DynamicWindowsDesktopV1);
// UpsertDynamicWindowsDesktop updates an existing dynamic Windows desktop or creates new if it doesn't exist.
rpc UpsertDynamicWindowsDesktop(UpsertDynamicWindowsDesktopRequest) returns (types.DynamicWindowsDesktopV1);
// DeleteDynamicWindowsDesktop removes the specified dynamic Windows desktop.
rpc DeleteDynamicWindowsDesktop(DeleteDynamicWindowsDesktopRequest) returns (google.protobuf.Empty);
}
Expand Down Expand Up @@ -63,18 +65,24 @@ message GetDynamicWindowsDesktopRequest {
string name = 1;
}

// CreateDynamicWindowsDesktopRequest is a request for a specific dynamic Windows desktop.
// CreateDynamicWindowsDesktopRequest is used for creating new dynamic Windows desktops.
message CreateDynamicWindowsDesktopRequest {
// desktop to be created
types.DynamicWindowsDesktopV1 desktop = 1;
}

// UpdateDynamicWindowsDesktopRequest is a request for a specific dynamic Windows desktop.
// UpdateDynamicWindowsDesktopRequest is used for updating existing dynamic Windows desktops.
message UpdateDynamicWindowsDesktopRequest {
// desktop to be updated
types.DynamicWindowsDesktopV1 desktop = 1;
}

// UpsertDynamicWindowsDesktopRequest is used for upserting dynamic Windows desktops.
message UpsertDynamicWindowsDesktopRequest {
// desktop to be upserted
types.DynamicWindowsDesktopV1 desktop = 1;
}

// DeleteDynamicWindowsDesktopRequest is a request to delete a Windows desktop host.
message DeleteDynamicWindowsDesktopRequest {
// name is the name of the Windows desktop host.
Expand Down
2 changes: 2 additions & 0 deletions lib/auth/accesspoint/accesspoint.go
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,7 @@ type Config struct {
Users services.UsersService
WebSession types.WebSessionInterface
WebToken types.WebTokenInterface
DynamicWindowsDesktops services.DynamicWindowsDesktops
WindowsDesktops services.WindowsDesktops
AutoUpdateService services.AutoUpdateServiceGetter
ProvisioningStates services.ProvisioningStates
Expand Down Expand Up @@ -201,6 +202,7 @@ func NewCache(cfg Config) (*cache.Cache, error) {
WebSession: cfg.WebSession,
WebToken: cfg.WebToken,
WindowsDesktops: cfg.WindowsDesktops,
DynamicWindowsDesktops: cfg.DynamicWindowsDesktops,
ProvisioningStates: cfg.ProvisioningStates,
IdentityCenter: cfg.IdentityCenter,
}
Expand Down
25 changes: 25 additions & 0 deletions lib/auth/dynamicwindows/dynamicwindowsv1/service.go
Original file line number Diff line number Diff line change
Expand Up @@ -196,6 +196,31 @@ func (s *Service) UpdateDynamicWindowsDesktop(ctx context.Context, req *dynamicw
return updatedDesktop, nil
}

// UpsertDynamicWindowsDesktop updates an existing dynamic Windows desktop or creates one if it doesn't exist.
func (s *Service) UpsertDynamicWindowsDesktop(ctx context.Context, req *dynamicwindowspb.UpsertDynamicWindowsDesktopRequest) (*types.DynamicWindowsDesktopV1, error) {
auth, err := s.authorizer.Authorize(ctx)
if err != nil {
return nil, trace.Wrap(err)
}
if err := auth.AuthorizeAdminAction(); err != nil {
return nil, trace.Wrap(err)
}
if err := auth.CheckAccessToKind(types.KindDynamicWindowsDesktop, types.VerbCreate, types.VerbUpdate); err != nil {
return nil, trace.Wrap(err)
}
d, err := s.backend.UpsertDynamicWindowsDesktop(ctx, req.Desktop)
if err != nil {
return nil, trace.Wrap(err)
}

updatedDesktop, ok := d.(*types.DynamicWindowsDesktopV1)
if !ok {
return nil, trace.BadParameter("unexpected type %T", d)
}

return updatedDesktop, nil
}

// DeleteDynamicWindowsDesktop removes the specified dynamic Windows desktop.
func (s *Service) DeleteDynamicWindowsDesktop(ctx context.Context, req *dynamicwindowspb.DeleteDynamicWindowsDesktopRequest) (*emptypb.Empty, error) {
auth, err := s.authorizer.Authorize(ctx)
Expand Down
9 changes: 9 additions & 0 deletions lib/auth/dynamicwindows/dynamicwindowsv1/service_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,11 @@ func TestServiceAccess(t *testing.T) {
allowedStates: []authz.AdminActionAuthState{authz.AdminActionAuthNotRequired, authz.AdminActionAuthMFAVerified},
allowedVerbs: []string{types.VerbUpdate},
},
{
name: "UpsertDynamicWindowsDesktop",
allowedStates: []authz.AdminActionAuthState{authz.AdminActionAuthNotRequired, authz.AdminActionAuthMFAVerified},
allowedVerbs: []string{types.VerbCreate, types.VerbUpdate},
},
{
name: "DeleteDynamicWindowsDesktop",
allowedStates: []authz.AdminActionAuthState{authz.AdminActionAuthNotRequired, authz.AdminActionAuthMFAVerified},
Expand Down Expand Up @@ -160,6 +165,10 @@ func callMethod(service *Service, method string) error {
arg.Desktop, _ = types.NewDynamicWindowsDesktopV1("test", nil, types.DynamicWindowsDesktopSpecV1{
Addr: "test",
})
case *dynamicwindowsv1.UpsertDynamicWindowsDesktopRequest:
arg.Desktop, _ = types.NewDynamicWindowsDesktopV1("test", nil, types.DynamicWindowsDesktopSpecV1{
Addr: "test",
})
}
return nil
}, nil)
Expand Down
1 change: 1 addition & 0 deletions lib/auth/helpers.go
Original file line number Diff line number Diff line change
Expand Up @@ -366,6 +366,7 @@ func NewTestAuthServer(cfg TestAuthServerConfig) (*TestAuthServer, error) {
WebSession: svces.Identity.WebSessions(),
WebToken: svces.WebTokens(),
WindowsDesktops: svces.WindowsDesktops,
DynamicWindowsDesktops: svces.DynamicWindowsDesktops,
})
if err != nil {
return nil, trace.Wrap(err)
Expand Down
13 changes: 13 additions & 0 deletions lib/cache/cache_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,7 @@ type testPack struct {
webSessionS types.WebSessionInterface
webTokenS types.WebTokenInterface
windowsDesktops services.WindowsDesktops
dynamicWindowsDesktops services.DynamicWindowsDesktops
samlIDPServiceProviders services.SAMLIdPServiceProviders
userGroups services.UserGroups
okta services.Okta
Expand Down Expand Up @@ -269,6 +270,11 @@ func newPackWithoutCache(dir string, opts ...packOption) (*testPack, error) {
return nil, trace.Wrap(err)
}

dynamicWindowsDesktopService, err := local.NewDynamicWindowsDesktopService(p.backend)
if err != nil {
return nil, trace.Wrap(err)
}

p.trustS = local.NewCAService(p.backend)
p.clusterConfigS = clusterConfig
p.provisionerS = local.NewProvisioningService(p.backend)
Expand All @@ -288,6 +294,7 @@ func newPackWithoutCache(dir string, opts ...packOption) (*testPack, error) {
p.databases = local.NewDatabasesService(p.backend)
p.databaseServices = local.NewDatabaseServicesService(p.backend)
p.windowsDesktops = local.NewWindowsDesktopService(p.backend)
p.dynamicWindowsDesktops = dynamicWindowsDesktopService
p.samlIDPServiceProviders, err = local.NewSAMLIdPServiceProviderService(p.backend)
if err != nil {
return nil, trace.Wrap(err)
Expand Down Expand Up @@ -428,6 +435,7 @@ func newPack(dir string, setupConfig func(c Config) Config, opts ...packOption)
DatabaseServices: p.databaseServices,
Databases: p.databases,
WindowsDesktops: p.windowsDesktops,
DynamicWindowsDesktops: p.dynamicWindowsDesktops,
SAMLIdPServiceProviders: p.samlIDPServiceProviders,
UserGroups: p.userGroups,
Okta: p.okta,
Expand Down Expand Up @@ -657,6 +665,7 @@ func TestNodeCAFiltering(t *testing.T) {
WebSession: p.cache.webSessionCache,
WebToken: p.cache.webTokenCache,
WindowsDesktops: p.cache.windowsDesktopsCache,
DynamicWindowsDesktops: p.cache.dynamicWindowsDesktopsCache,
SAMLIdPServiceProviders: p.samlIDPServiceProviders,
UserGroups: p.userGroups,
StaticHostUsers: p.staticHostUsers,
Expand Down Expand Up @@ -838,6 +847,7 @@ func TestCompletenessInit(t *testing.T) {
DatabaseServices: p.databaseServices,
Databases: p.databases,
WindowsDesktops: p.windowsDesktops,
DynamicWindowsDesktops: p.dynamicWindowsDesktops,
SAMLIdPServiceProviders: p.samlIDPServiceProviders,
UserGroups: p.userGroups,
Okta: p.okta,
Expand Down Expand Up @@ -921,6 +931,7 @@ func TestCompletenessReset(t *testing.T) {
DatabaseServices: p.databaseServices,
Databases: p.databases,
WindowsDesktops: p.windowsDesktops,
DynamicWindowsDesktops: p.dynamicWindowsDesktops,
SAMLIdPServiceProviders: p.samlIDPServiceProviders,
UserGroups: p.userGroups,
Okta: p.okta,
Expand Down Expand Up @@ -1130,6 +1141,7 @@ func TestListResources_NodesTTLVariant(t *testing.T) {
DatabaseServices: p.databaseServices,
Databases: p.databases,
WindowsDesktops: p.windowsDesktops,
DynamicWindowsDesktops: p.dynamicWindowsDesktops,
SAMLIdPServiceProviders: p.samlIDPServiceProviders,
UserGroups: p.userGroups,
Okta: p.okta,
Expand Down Expand Up @@ -1224,6 +1236,7 @@ func initStrategy(t *testing.T) {
DatabaseServices: p.databaseServices,
Databases: p.databases,
WindowsDesktops: p.windowsDesktops,
DynamicWindowsDesktops: p.dynamicWindowsDesktops,
SAMLIdPServiceProviders: p.samlIDPServiceProviders,
UserGroups: p.userGroups,
Okta: p.okta,
Expand Down
2 changes: 1 addition & 1 deletion lib/cache/collections.go
Original file line number Diff line number Diff line change
Expand Up @@ -2328,7 +2328,7 @@ func (dynamicWindowsDesktopsExecutor) getAll(ctx context.Context, cache *Cache,
var desktops []types.DynamicWindowsDesktop
next := ""
for {
d, token, err := cache.dynamicWindowsDesktopsCache.ListDynamicWindowsDesktops(ctx, defaults.MaxIterationLimit, next)
d, token, err := cache.Config.DynamicWindowsDesktops.ListDynamicWindowsDesktops(ctx, defaults.MaxIterationLimit, next)
if err != nil {
return nil, err
}
Expand Down
2 changes: 2 additions & 0 deletions lib/service/service.go
Original file line number Diff line number Diff line change
Expand Up @@ -2529,6 +2529,7 @@ func (process *TeleportProcess) newAccessCacheForServices(cfg accesspoint.Config
cfg.WebSession = services.Identity.WebSessions()
cfg.WebToken = services.Identity.WebTokens()
cfg.WindowsDesktops = services.WindowsDesktops
cfg.DynamicWindowsDesktops = services.DynamicWindowsDesktops
cfg.AutoUpdateService = services.AutoUpdateService
cfg.ProvisioningStates = services.ProvisioningStates
cfg.IdentityCenter = services.IdentityCenter
Expand Down Expand Up @@ -2576,6 +2577,7 @@ func (process *TeleportProcess) newAccessCacheForClient(cfg accesspoint.Config,
cfg.WebSession = client.WebSessions()
cfg.WebToken = client.WebTokens()
cfg.WindowsDesktops = client
cfg.DynamicWindowsDesktops = client.DynamicDesktopClient()
cfg.AutoUpdateService = client

return accesspoint.NewCache(cfg)
Expand Down
6 changes: 5 additions & 1 deletion lib/services/local/dynamic_desktops.go
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,11 @@ func (s *DynamicWindowsDesktopService) CreateDynamicWindowsDesktop(ctx context.C

// UpdateDynamicWindowsDesktop updates a dynamic Windows desktop resource.
func (s *DynamicWindowsDesktopService) UpdateDynamicWindowsDesktop(ctx context.Context, desktop types.DynamicWindowsDesktop) (types.DynamicWindowsDesktop, error) {
d, err := s.service.UpdateResource(ctx, desktop)
// ConditionalUpdateResource can return invalid revision instead of not found, so we'll check if resource exists first
if _, err := s.service.GetResource(ctx, desktop.GetName()); trace.IsNotFound(err) {
return nil, err
}
d, err := s.service.ConditionalUpdateResource(ctx, desktop)
if err != nil {
return nil, trace.Wrap(err)
}
Expand Down
9 changes: 8 additions & 1 deletion lib/services/local/dynamic_desktops_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -182,8 +182,15 @@ func TestDynamicWindowsService_UpdateDynamicDesktop(t *testing.T) {
require.Error(t, err)
require.True(t, trace.IsNotFound(err))
})
t.Run("revision doesn't match", func(t *testing.T) {
want := newDynamicDesktop(t, "example1")
_, err := service.CreateDynamicWindowsDesktop(ctx, want.Copy())
require.NoError(t, err)
_, err = service.UpdateDynamicWindowsDesktop(ctx, want)
require.Error(t, err)
})
t.Run("ok", func(t *testing.T) {
want := newDynamicDesktop(t, "example")
want := newDynamicDesktop(t, "example2")
created, err := service.CreateDynamicWindowsDesktop(ctx, want.Copy())
require.NoError(t, err)
updated, err := service.UpdateDynamicWindowsDesktop(ctx, created.Copy())
Expand Down
2 changes: 1 addition & 1 deletion lib/srv/desktop/discovery_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -279,7 +279,7 @@ func TestDynamicWindowsDiscovery(t *testing.T) {
}

desktop.Spec.Addr = "addr2"
_, err = dynamicWindowsClient.UpdateDynamicWindowsDesktop(ctx, desktop)
_, err = dynamicWindowsClient.UpsertDynamicWindowsDesktop(ctx, desktop)
require.NoError(t, err)

time.Sleep(10 * time.Millisecond)
Expand Down
2 changes: 1 addition & 1 deletion tool/tctl/common/resource_command.go
Original file line number Diff line number Diff line change
Expand Up @@ -904,7 +904,7 @@ func (rc *ResourceCommand) createDynamicWindowsDesktop(ctx context.Context, clie
if !rc.force {
return trace.AlreadyExists("application %q already exists", wd.GetName())
}
if _, err := dynamicDesktopClient.UpdateDynamicWindowsDesktop(ctx, wd); err != nil {
if _, err := dynamicDesktopClient.UpsertDynamicWindowsDesktop(ctx, wd); err != nil {
return trace.Wrap(err)
}
fmt.Printf("dynamic windows desktop %q has been updated\n", wd.GetName())
Expand Down

0 comments on commit 4bb8cd4

Please sign in to comment.