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

Fix update and list for DynamicWindowsDesktops #48046

Merged
merged 11 commits into from
Oct 29, 2024
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
Loading