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

Cache and watcher support for DynamicWindowsDesktop #46989

Open
wants to merge 8 commits into
base: probakowski/register-resources-api
Choose a base branch
from
7 changes: 7 additions & 0 deletions api/client/events.go
Original file line number Diff line number Diff line change
Expand Up @@ -254,6 +254,10 @@ func EventToGRPC(in types.Event) (*proto.Event, error) {
out.Resource = &proto.Event_WindowsDesktop{
WindowsDesktop: r,
}
case *types.DynamicWindowsDesktopV1:
out.Resource = &proto.Event_DynamicWindowsDesktop{
DynamicWindowsDesktop: r,
}
case *types.InstallerV1:
out.Resource = &proto.Event_Installer{
Installer: r,
Expand Down Expand Up @@ -444,6 +448,9 @@ func EventFromGRPC(in *proto.Event) (*types.Event, error) {
} else if r := in.GetWindowsDesktop(); r != nil {
out.Resource = r
return &out, nil
} else if r := in.GetDynamicWindowsDesktop(); r != nil {
out.Resource = r
return &out, nil
} else if r := in.GetKubernetesServer(); r != nil {
out.Resource = r
return &out, nil
Expand Down
39 changes: 39 additions & 0 deletions lib/cache/cache.go
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,7 @@ func ForAuth(cfg Config) Config {
{Kind: types.KindLock},
{Kind: types.KindWindowsDesktopService},
{Kind: types.KindWindowsDesktop},
{Kind: types.KindDynamicWindowsDesktop},
{Kind: types.KindKubeServer},
{Kind: types.KindInstaller},
{Kind: types.KindKubernetesCluster},
Expand Down Expand Up @@ -233,6 +234,7 @@ func ForProxy(cfg Config) Config {
{Kind: types.KindDatabase},
{Kind: types.KindWindowsDesktopService},
{Kind: types.KindWindowsDesktop},
{Kind: types.KindDynamicWindowsDesktop},
{Kind: types.KindKubeServer},
{Kind: types.KindInstaller},
{Kind: types.KindKubernetesCluster},
Expand Down Expand Up @@ -392,6 +394,7 @@ func ForWindowsDesktop(cfg Config) Config {
{Kind: types.KindNamespace, Name: apidefaults.Namespace},
{Kind: types.KindWindowsDesktopService},
{Kind: types.KindWindowsDesktop},
{Kind: types.KindDynamicWindowsDesktop},
}
cfg.QueueSize = defaults.WindowsDesktopQueueSize
return cfg
Expand Down Expand Up @@ -520,6 +523,7 @@ type Cache struct {
webSessionCache types.WebSessionInterface
webTokenCache types.WebTokenInterface
windowsDesktopsCache services.WindowsDesktops
dynamicWindowsDesktopsCache services.DynamicWindowsDesktops
samlIdPServiceProvidersCache services.SAMLIdPServiceProviders //nolint:revive // Because we want this to be IdP.
userGroupsCache services.UserGroups
oktaCache services.Okta
Expand Down Expand Up @@ -690,6 +694,8 @@ type Config struct {
WebToken types.WebTokenInterface
// WindowsDesktops is a windows desktop service.
WindowsDesktops services.WindowsDesktops
// DynamicWindowsDesktops is a dynamic Windows desktop service.
DynamicWindowsDesktops services.DynamicWindowsDesktops
// SAMLIdPServiceProviders is a SAML IdP service providers service.
SAMLIdPServiceProviders services.SAMLIdPServiceProviders
// UserGroups is a user groups service.
Expand Down Expand Up @@ -993,6 +999,12 @@ func New(config Config) (*Cache, error) {
return nil, trace.Wrap(err)
}

dynamicDesktopsService, err := local.NewDynamicWindowsDesktopService(config.Backend)
if err != nil {
cancel()
return nil, trace.Wrap(err)
}

cs := &Cache{
ctx: ctx,
cancel: cancel,
Expand All @@ -1019,6 +1031,7 @@ func New(config Config) (*Cache, error) {
webSessionCache: identityService.WebSessions(),
webTokenCache: identityService.WebTokens(),
windowsDesktopsCache: local.NewWindowsDesktopService(config.Backend),
dynamicWindowsDesktopsCache: dynamicDesktopsService,
accessMontoringRuleCache: accessMonitoringRuleCache,
samlIdPServiceProvidersCache: samlIdPServiceProvidersCache,
userGroupsCache: userGroupsCache,
Expand Down Expand Up @@ -2822,6 +2835,32 @@ func (c *Cache) ListWindowsDesktopServices(ctx context.Context, req types.ListWi
return rg.reader.ListWindowsDesktopServices(ctx, req)
}

// GetDynamicWindowsDesktop returns registered dynamic Windows desktop by name.
func (c *Cache) GetDynamicWindowsDesktop(ctx context.Context, name string) (types.DynamicWindowsDesktop, error) {
ctx, span := c.Tracer.Start(ctx, "cache/GetDynamicWindowsDesktop")
defer span.End()

rg, err := readCollectionCache(c, c.collections.dynamicWindowsDesktops)
if err != nil {
return nil, trace.Wrap(err)
}
defer rg.Release()
return rg.reader.GetDynamicWindowsDesktop(ctx, name)
}

// ListDynamicWindowsDesktops returns all registered dynamic Windows desktop.
func (c *Cache) ListDynamicWindowsDesktops(ctx context.Context, pageSize int, nextPage string) ([]types.DynamicWindowsDesktop, string, error) {
ctx, span := c.Tracer.Start(ctx, "cache/ListDynamicWindowsDesktops")
defer span.End()

rg, err := readCollectionCache(c, c.collections.dynamicWindowsDesktops)
if err != nil {
return nil, "", trace.Wrap(err)
}
defer rg.Release()
return rg.reader.ListDynamicWindowsDesktops(ctx, pageSize, nextPage)
}

// ListSAMLIdPServiceProviders returns a paginated list of SAML IdP service provider resources.
func (c *Cache) ListSAMLIdPServiceProviders(ctx context.Context, pageSize int, nextKey string) ([]types.SAMLIdPServiceProvider, string, error) {
ctx, span := c.Tracer.Start(ctx, "cache/ListSAMLIdPServiceProviders")
Expand Down
1 change: 1 addition & 0 deletions lib/cache/cache_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3424,6 +3424,7 @@ func TestCacheWatchKindExistsInEvents(t *testing.T) {
types.KindLock: &types.LockV2{},
types.KindWindowsDesktopService: &types.WindowsDesktopServiceV3{},
types.KindWindowsDesktop: &types.WindowsDesktopV3{},
types.KindDynamicWindowsDesktop: &types.DynamicWindowsDesktopV1{},
types.KindInstaller: &types.InstallerV1{},
types.KindKubernetesCluster: &types.KubernetesClusterV3{},
types.KindSAMLIdPServiceProvider: &types.SAMLIdPServiceProviderV1{},
Expand Down
59 changes: 59 additions & 0 deletions lib/cache/collections.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ package cache
import (
"context"
"fmt"
"github.com/gravitational/teleport/lib/defaults"

"github.com/gravitational/trace"

Expand Down Expand Up @@ -258,6 +259,7 @@ type cacheCollections struct {
webSessions collectionReader[webSessionGetter]
webTokens collectionReader[webTokenGetter]
windowsDesktops collectionReader[windowsDesktopsGetter]
dynamicWindowsDesktops collectionReader[dynamicWindowsDesktopsGetter]
windowsDesktopServices collectionReader[windowsDesktopServiceGetter]
userNotifications collectionReader[notificationGetter]
accessGraphSettings collectionReader[accessGraphSettingsGetter]
Expand Down Expand Up @@ -621,6 +623,15 @@ func setupCollections(c *Cache, watches []types.WatchKind) (*cacheCollections, e
watch: watch,
}
collections.byKind[resourceKind] = collections.windowsDesktops
case types.KindDynamicWindowsDesktop:
if c.WindowsDesktops == nil {
return nil, trace.BadParameter("missing parameter DynamicWindowsDesktops")
}
collections.dynamicWindowsDesktops = &genericCollection[types.DynamicWindowsDesktop, dynamicWindowsDesktopsGetter, dynamicWindowsDesktopsExecutor]{
cache: c,
watch: watch,
}
collections.byKind[resourceKind] = collections.dynamicWindowsDesktops
case types.KindSAMLIdPServiceProvider:
if c.SAMLIdPServiceProviders == nil {
return nil, trace.BadParameter("missing parameter SAMLIdPServiceProviders")
Expand Down Expand Up @@ -2318,6 +2329,54 @@ type windowsDesktopsGetter interface {

var _ executor[types.WindowsDesktop, windowsDesktopsGetter] = windowsDesktopsExecutor{}

type dynamicWindowsDesktopsExecutor struct{}

func (dynamicWindowsDesktopsExecutor) getAll(ctx context.Context, cache *Cache, loadSecrets bool) ([]types.DynamicWindowsDesktop, error) {
var desktops []types.DynamicWindowsDesktop
next := ""
for {
d, token, err := cache.dynamicWindowsDesktopsCache.ListDynamicWindowsDesktops(ctx, defaults.MaxIterationLimit, next)
if err != nil {
return nil, err
}
desktops = append(desktops, d...)
if token == "" {
break
}
next = token
}
return desktops, nil
}

func (dynamicWindowsDesktopsExecutor) upsert(ctx context.Context, cache *Cache, resource types.DynamicWindowsDesktop) error {
_, err := cache.dynamicWindowsDesktopsCache.UpsertDynamicWindowsDesktop(ctx, resource)
return err
}

func (dynamicWindowsDesktopsExecutor) deleteAll(ctx context.Context, cache *Cache) error {
return cache.dynamicWindowsDesktopsCache.DeleteAllDynamicWindowsDesktops(ctx)
}

func (dynamicWindowsDesktopsExecutor) delete(ctx context.Context, cache *Cache, resource types.Resource) error {
return cache.dynamicWindowsDesktopsCache.DeleteDynamicWindowsDesktop(ctx, resource.GetName())
}

func (dynamicWindowsDesktopsExecutor) isSingleton() bool { return false }

func (dynamicWindowsDesktopsExecutor) getReader(cache *Cache, cacheOK bool) dynamicWindowsDesktopsGetter {
if cacheOK {
return cache.dynamicWindowsDesktopsCache
}
return cache.Config.DynamicWindowsDesktops
}

type dynamicWindowsDesktopsGetter interface {
GetDynamicWindowsDesktop(ctx context.Context, name string) (types.DynamicWindowsDesktop, error)
ListDynamicWindowsDesktops(ctx context.Context, pageSize int, nextPage string) ([]types.DynamicWindowsDesktop, string, error)
}

var _ executor[types.DynamicWindowsDesktop, dynamicWindowsDesktopsGetter] = dynamicWindowsDesktopsExecutor{}

type kubeClusterExecutor struct{}

func (kubeClusterExecutor) getAll(ctx context.Context, cache *Cache, loadSecrets bool) ([]types.KubeCluster, error) {
Expand Down
5 changes: 3 additions & 2 deletions lib/services/dynamic_desktop.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,16 +30,17 @@ import (
// DynamicWindowsDesktops defines an interface for managing dynamic Windows desktops.
type DynamicWindowsDesktops interface {
DynamicWindowsDesktopGetter
GetDynamicWindowsDesktop(ctx context.Context, name string) (types.DynamicWindowsDesktop, error)
CreateDynamicWindowsDesktop(context.Context, types.DynamicWindowsDesktop) (types.DynamicWindowsDesktop, error)
UpdateDynamicWindowsDesktop(context.Context, types.DynamicWindowsDesktop) (types.DynamicWindowsDesktop, error)
UpsertDynamicWindowsDesktop(context.Context, types.DynamicWindowsDesktop) (types.DynamicWindowsDesktop, error)
DeleteDynamicWindowsDesktop(ctx context.Context, name string) error
ListDynamicWindowsDesktops(ctx context.Context, pageSize int, pageToken string) ([]types.DynamicWindowsDesktop, string, error)
DeleteAllDynamicWindowsDesktops(ctx context.Context) error
}

// DynamicWindowsDesktopGetter is an interface for fetching DynamicWindowsDesktop resources.
type DynamicWindowsDesktopGetter interface {
GetDynamicWindowsDesktop(ctx context.Context, name string) (types.DynamicWindowsDesktop, error)
ListDynamicWindowsDesktops(ctx context.Context, pageSize int, pageToken string) ([]types.DynamicWindowsDesktop, string, error)
}

// MarshalDynamicWindowsDesktop marshals the DynamicWindowsDesktop resource to JSON.
Expand Down
39 changes: 39 additions & 0 deletions lib/services/local/events.go
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,8 @@ func (e *EventsService) NewWatcher(ctx context.Context, watch types.Watch) (type
parser = newWindowsDesktopServicesParser()
case types.KindWindowsDesktop:
parser = newWindowsDesktopsParser()
case types.KindDynamicWindowsDesktop:
parser = newDynamicWindowsDesktopsParser()
case types.KindInstaller:
parser = newInstallerParser()
case types.KindKubernetesCluster:
Expand Down Expand Up @@ -1851,6 +1853,43 @@ func (p *windowsDesktopServicesParser) parse(event backend.Event) (types.Resourc
}
}

func newDynamicWindowsDesktopsParser() *dynamicWindowsDesktopsParser {
return &dynamicWindowsDesktopsParser{
baseParser: newBaseParser(backend.NewKey(dynamicWindowsDesktopsPrefix, "")),
}
}

type dynamicWindowsDesktopsParser struct {
baseParser
}

func (p *dynamicWindowsDesktopsParser) parse(event backend.Event) (types.Resource, error) {
switch event.Type {
case types.OpDelete:
name := event.Item.Key.TrimPrefix(backend.NewKey(dynamicWindowsDesktopsPrefix, "")).String()
if name == "" {
return nil, trace.NotFound("failed parsing %v", event.Item.Key.String())
}

return &types.ResourceHeader{
Kind: types.KindDynamicWindowsDesktop,
Version: types.V1,
Metadata: types.Metadata{
Name: strings.TrimPrefix(name, backend.SeparatorString),
Namespace: apidefaults.Namespace,
},
}, nil
case types.OpPut:
return services.UnmarshalDynamicWindowsDesktop(
event.Item.Value,
services.WithExpires(event.Item.Expires),
services.WithRevision(event.Item.Revision),
)
default:
return nil, trace.BadParameter("event %v is not supported", event.Type)
}
}

func newWindowsDesktopsParser() *windowsDesktopsParser {
return &windowsDesktopsParser{
baseParser: newBaseParser(backend.NewKey(windowsDesktopsPrefix, "")),
Expand Down
Loading
Loading