mirror of
https://github.com/gravitational/teleport.git
synced 2026-10-12 02:15:01 +00:00
tctl support for DynamicWindowsDesktop (#46988)
* Add DynamicWindowsDesktop to proto * Add resource matchers to Windows desktop service config * Implement API and backend for DynamicWindowsDesktop * tctl support for DynamicWindowsDesktop * Fix imports * Remove unused methods * move rpc to separate server * rework api and grpc more towards 153-style * e * remove dynamic windows from paginated resource * add tests * add tests * update client * Update api/proto/teleport/legacy/types/types.proto Co-authored-by: rosstimothy <[email protected]> * lint * gci * cleanup * cleanup * use generic service * cleanup * cleanup * cleanup * cleanup * cleanup * gci * add admin action checks * move service * add service test * add tests * gci * review comments * review comments * review comments * review comments * review comments * review comments --------- Co-authored-by: rosstimothy <[email protected]>
This commit is contained in:
co-authored by
rosstimothy
parent
5de066049c
commit
d391ccc792
@@ -866,6 +866,35 @@ func (c *windowsDesktopCollection) writeJSON(w io.Writer) error {
|
||||
return utils.WriteJSONArray(w, c.desktops)
|
||||
}
|
||||
|
||||
type dynamicWindowsDesktopCollection struct {
|
||||
desktops []types.DynamicWindowsDesktop
|
||||
}
|
||||
|
||||
func (c *dynamicWindowsDesktopCollection) resources() (r []types.Resource) {
|
||||
r = make([]types.Resource, 0, len(c.desktops))
|
||||
for _, resource := range c.desktops {
|
||||
r = append(r, resource)
|
||||
}
|
||||
return r
|
||||
}
|
||||
|
||||
func (c *dynamicWindowsDesktopCollection) writeText(w io.Writer, verbose bool) error {
|
||||
var rows [][]string
|
||||
for _, d := range c.desktops {
|
||||
labels := common.FormatLabels(d.GetAllLabels(), verbose)
|
||||
rows = append(rows, []string{d.GetName(), d.GetAddr(), d.GetDomain(), labels})
|
||||
}
|
||||
headers := []string{"Name", "Address", "AD Domain", "Labels"}
|
||||
var t asciitable.Table
|
||||
if verbose {
|
||||
t = asciitable.MakeTable(headers, rows...)
|
||||
} else {
|
||||
t = asciitable.MakeTableWithTruncatedColumn(headers, rows, "Labels")
|
||||
}
|
||||
_, err := t.AsBuffer().WriteTo(w)
|
||||
return trace.Wrap(err)
|
||||
}
|
||||
|
||||
type tokenCollection struct {
|
||||
tokens []types.ProvisionToken
|
||||
}
|
||||
|
||||
@@ -91,6 +91,10 @@ func TestEditResources(t *testing.T) {
|
||||
kind: types.KindAutoUpdateVersion,
|
||||
edit: testEditAutoUpdateVersion,
|
||||
},
|
||||
{
|
||||
kind: types.KindDynamicWindowsDesktop,
|
||||
edit: testEditDynamicWindowsDesktop,
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
@@ -635,3 +639,35 @@ func testEditAutoUpdateVersion(t *testing.T, clt *authclient.Client) {
|
||||
"tools_autoupdate should have been modified by edit")
|
||||
assert.Equal(t, expected.GetSpec().GetTools().GetTargetVersion(), actual.GetSpec().GetTools().GetTargetVersion())
|
||||
}
|
||||
|
||||
func testEditDynamicWindowsDesktop(t *testing.T, clt *authclient.Client) {
|
||||
ctx := context.Background()
|
||||
|
||||
expected, err := types.NewDynamicWindowsDesktopV1("test", nil, types.DynamicWindowsDesktopSpecV1{
|
||||
Addr: "test",
|
||||
})
|
||||
require.NoError(t, err)
|
||||
created, err := clt.DynamicDesktopClient().CreateDynamicWindowsDesktop(ctx, expected)
|
||||
require.NoError(t, err)
|
||||
|
||||
editor := func(name string) error {
|
||||
f, err := os.Create(name)
|
||||
if err != nil {
|
||||
return trace.Wrap(err, "opening file to edit")
|
||||
}
|
||||
|
||||
expected.SetRevision(created.GetRevision())
|
||||
expected.Spec.Addr = "test2"
|
||||
|
||||
collection := &dynamicWindowsDesktopCollection{desktops: []types.DynamicWindowsDesktop{expected}}
|
||||
return trace.NewAggregate(writeYAML(collection, f), f.Close())
|
||||
}
|
||||
|
||||
_, err = runEditCommand(t, clt, []string{"edit", "dynamic_windows_desktop/test"}, withEditor(editor))
|
||||
require.NoError(t, err)
|
||||
|
||||
actual, err := clt.DynamicDesktopClient().GetDynamicWindowsDesktop(ctx, expected.GetName())
|
||||
require.NoError(t, err)
|
||||
expected.SetRevision(actual.GetRevision())
|
||||
require.Empty(t, cmp.Diff(expected, actual, protocmp.Transform()))
|
||||
}
|
||||
|
||||
@@ -156,6 +156,7 @@ func (rc *ResourceCommand) Initialize(app *kingpin.Application, config *servicec
|
||||
types.KindOktaImportRule: rc.createOktaImportRule,
|
||||
types.KindIntegration: rc.createIntegration,
|
||||
types.KindWindowsDesktop: rc.createWindowsDesktop,
|
||||
types.KindDynamicWindowsDesktop: rc.createDynamicWindowsDesktop,
|
||||
types.KindAccessList: rc.createAccessList,
|
||||
types.KindDiscoveryConfig: rc.createDiscoveryConfig,
|
||||
types.KindAuditQuery: rc.createAuditQuery,
|
||||
@@ -193,6 +194,7 @@ func (rc *ResourceCommand) Initialize(app *kingpin.Application, config *servicec
|
||||
types.KindUserTask: rc.updateUserTask,
|
||||
types.KindAutoUpdateConfig: rc.updateAutoUpdateConfig,
|
||||
types.KindAutoUpdateVersion: rc.updateAutoUpdateVersion,
|
||||
types.KindDynamicWindowsDesktop: rc.updateDynamicWindowsDesktop,
|
||||
}
|
||||
rc.config = config
|
||||
|
||||
@@ -891,6 +893,45 @@ func (rc *ResourceCommand) createWindowsDesktop(ctx context.Context, client *aut
|
||||
return nil
|
||||
}
|
||||
|
||||
func (rc *ResourceCommand) createDynamicWindowsDesktop(ctx context.Context, client *authclient.Client, raw services.UnknownResource) error {
|
||||
wd, err := services.UnmarshalDynamicWindowsDesktop(raw.Raw)
|
||||
if err != nil {
|
||||
return trace.Wrap(err)
|
||||
}
|
||||
dynamicDesktopClient := client.DynamicDesktopClient()
|
||||
if _, err := dynamicDesktopClient.CreateDynamicWindowsDesktop(ctx, wd); err != nil {
|
||||
if trace.IsAlreadyExists(err) {
|
||||
if !rc.force {
|
||||
return trace.AlreadyExists("application %q already exists", wd.GetName())
|
||||
}
|
||||
if _, err := dynamicDesktopClient.UpdateDynamicWindowsDesktop(ctx, wd); err != nil {
|
||||
return trace.Wrap(err)
|
||||
}
|
||||
fmt.Printf("dynamic windows desktop %q has been updated\n", wd.GetName())
|
||||
return nil
|
||||
}
|
||||
return trace.Wrap(err)
|
||||
}
|
||||
|
||||
fmt.Printf("dynamic windows desktop %q has been updated\n", wd.GetName())
|
||||
return nil
|
||||
}
|
||||
|
||||
func (rc *ResourceCommand) updateDynamicWindowsDesktop(ctx context.Context, client *authclient.Client, raw services.UnknownResource) error {
|
||||
wd, err := services.UnmarshalDynamicWindowsDesktop(raw.Raw)
|
||||
if err != nil {
|
||||
return trace.Wrap(err)
|
||||
}
|
||||
|
||||
dynamicDesktopClient := client.DynamicDesktopClient()
|
||||
if _, err := dynamicDesktopClient.UpdateDynamicWindowsDesktop(ctx, wd); err != nil {
|
||||
return trace.Wrap(err)
|
||||
}
|
||||
|
||||
fmt.Printf("dynamic windows desktop %q has been updated\n", wd.GetName())
|
||||
return nil
|
||||
}
|
||||
|
||||
func (rc *ResourceCommand) createAppServer(ctx context.Context, client *authclient.Client, raw services.UnknownResource) error {
|
||||
appServer, err := services.UnmarshalAppServer(raw.Raw)
|
||||
if err != nil {
|
||||
@@ -1688,6 +1729,11 @@ func (rc *ResourceCommand) Delete(ctx context.Context, client *authclient.Client
|
||||
return trace.Wrap(err)
|
||||
}
|
||||
fmt.Printf("windows desktop service %q has been deleted\n", rc.ref.Name)
|
||||
case types.KindDynamicWindowsDesktop:
|
||||
if err = client.DynamicDesktopClient().DeleteDynamicWindowsDesktop(ctx, rc.ref.Name); err != nil {
|
||||
return trace.Wrap(err)
|
||||
}
|
||||
fmt.Printf("dynamic windows desktop %q has been deleted\n", rc.ref.Name)
|
||||
case types.KindWindowsDesktop:
|
||||
desktops, err := client.GetWindowsDesktops(ctx,
|
||||
types.WindowsDesktopFilter{Name: rc.ref.Name})
|
||||
@@ -2461,6 +2507,41 @@ func (rc *ResourceCommand) getCollection(ctx context.Context, client *authclient
|
||||
return nil, trace.NotFound("Windows desktop %q not found", rc.ref.Name)
|
||||
}
|
||||
return &windowsDesktopCollection{desktops: out}, nil
|
||||
case types.KindDynamicWindowsDesktop:
|
||||
dynamicDesktopClient := client.DynamicDesktopClient()
|
||||
if rc.ref.Name != "" {
|
||||
desktop, err := dynamicDesktopClient.GetDynamicWindowsDesktop(ctx, rc.ref.Name)
|
||||
if err != nil {
|
||||
return nil, trace.Wrap(err)
|
||||
}
|
||||
return &dynamicWindowsDesktopCollection{
|
||||
desktops: []types.DynamicWindowsDesktop{desktop},
|
||||
}, nil
|
||||
}
|
||||
|
||||
pageToken := ""
|
||||
desktops := make([]types.DynamicWindowsDesktop, 0, 100)
|
||||
for {
|
||||
d, next, err := dynamicDesktopClient.ListDynamicWindowsDesktop(ctx, 100, pageToken)
|
||||
if err != nil {
|
||||
return nil, trace.Wrap(err)
|
||||
}
|
||||
if rc.ref.Name == "" {
|
||||
desktops = append(desktops, d...)
|
||||
} else {
|
||||
for _, desktop := range desktops {
|
||||
if desktop.GetName() == rc.ref.Name {
|
||||
desktops = append(desktops, desktop)
|
||||
}
|
||||
}
|
||||
}
|
||||
pageToken = next
|
||||
if next == "" {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
return &dynamicWindowsDesktopCollection{desktops}, nil
|
||||
case types.KindToken:
|
||||
if rc.ref.Name == "" {
|
||||
tokens, err := client.GetTokens(ctx)
|
||||
|
||||
@@ -1419,6 +1419,10 @@ func TestCreateResources(t *testing.T) {
|
||||
kind: types.KindAutoUpdateVersion,
|
||||
create: testCreateAutoUpdateVersion,
|
||||
},
|
||||
{
|
||||
kind: types.KindDynamicWindowsDesktop,
|
||||
create: testCreateDynamicWindowsDesktop,
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
@@ -2359,6 +2363,35 @@ version: v1
|
||||
))
|
||||
}
|
||||
|
||||
func testCreateDynamicWindowsDesktop(t *testing.T, clt *authclient.Client) {
|
||||
const resourceYAML = `kind: dynamic_windows_desktop
|
||||
metadata:
|
||||
name: test
|
||||
revision: 3a43b44a-201e-4d7f-aef1-ae2f6d9811ed
|
||||
spec:
|
||||
addr: test
|
||||
version: v1
|
||||
`
|
||||
|
||||
// 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.KindDynamicWindowsDesktop, "--format=json"})
|
||||
require.NoError(t, err)
|
||||
resources := mustDecodeJSON[[]types.DynamicWindowsDesktopV1](t, buf)
|
||||
require.Len(t, resources, 1)
|
||||
|
||||
var expected types.DynamicWindowsDesktopV1
|
||||
require.NoError(t, yaml.Unmarshal([]byte(resourceYAML), &expected))
|
||||
expected.SetRevision(resources[0].GetRevision())
|
||||
|
||||
require.Empty(t, cmp.Diff([]types.DynamicWindowsDesktopV1{expected}, resources, protocmp.Transform()))
|
||||
}
|
||||
|
||||
func TestPluginResourceWrapper(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
|
||||
Reference in New Issue
Block a user