Skip to content

Commit 3979c19

Browse files
committed
tctl resources: convert Auth, Proxy, Node
Updates #60370.
1 parent 0218493 commit 3979c19

File tree

9 files changed

+330
-169
lines changed

9 files changed

+330
-169
lines changed

tool/tctl/common/auth_command.go

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ import (
5555
"github.com/gravitational/teleport/lib/winpki"
5656
commonclient "github.com/gravitational/teleport/tool/tctl/common/client"
5757
tctlcfg "github.com/gravitational/teleport/tool/tctl/common/config"
58+
"github.com/gravitational/teleport/tool/tctl/common/resources"
5859
)
5960

6061
// authCommandClient is aggregated client interface for auth command.
@@ -478,17 +479,17 @@ func (a *AuthCommand) ListAuthServers(ctx context.Context, clusterAPI authComman
478479
return trace.Wrap(err)
479480
}
480481

481-
sc := &serverCollection{servers}
482+
sc := resources.NewServerCollection(servers)
482483

483484
switch a.format {
484485
case teleport.Text:
485486
// auth servers don't have labels.
486487
verbose := false
487488
return sc.WriteText(os.Stdout, verbose)
488489
case teleport.YAML:
489-
return writeYAML(sc, os.Stdout)
490+
return sc.WriteYAML(os.Stdout)
490491
case teleport.JSON:
491-
return writeJSON(sc, os.Stdout)
492+
return sc.WriteJSON(os.Stdout)
492493
}
493494

494495
return nil

tool/tctl/common/collection.go

Lines changed: 0 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -113,45 +113,6 @@ func printMetadataLabels(labels map[string]string) string {
113113
return strings.Join(pairs, ",")
114114
}
115115

116-
type serverCollection struct {
117-
servers []types.Server
118-
}
119-
120-
func (s *serverCollection) Resources() (r []types.Resource) {
121-
for _, resource := range s.servers {
122-
r = append(r, resource)
123-
}
124-
return r
125-
}
126-
127-
func (s *serverCollection) WriteText(w io.Writer, verbose bool) error {
128-
var rows [][]string
129-
for _, se := range s.servers {
130-
labels := common.FormatLabels(se.GetAllLabels(), verbose)
131-
rows = append(rows, []string{
132-
se.GetHostname(), se.GetName(), se.GetAddr(), labels, se.GetTeleportVersion(),
133-
})
134-
}
135-
headers := []string{"Host", "UUID", "Public Address", "Labels", "Version"}
136-
var t asciitable.Table
137-
if verbose {
138-
t = asciitable.MakeTable(headers, rows...)
139-
} else {
140-
t = asciitable.MakeTableWithTruncatedColumn(headers, rows, "Labels")
141-
}
142-
143-
_, err := t.AsBuffer().WriteTo(w)
144-
return trace.Wrap(err)
145-
}
146-
147-
func (s *serverCollection) writeYAML(w io.Writer) error {
148-
return utils.WriteYAML(w, s.servers)
149-
}
150-
151-
func (s *serverCollection) writeJSON(w io.Writer) error {
152-
return utils.WriteJSONArray(w, s.servers)
153-
}
154-
155116
type authorityCollection struct {
156117
cas []types.CertAuthority
157118
}

tool/tctl/common/node_command.go

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ import (
4444
"github.com/gravitational/teleport/lib/utils"
4545
commonclient "github.com/gravitational/teleport/tool/tctl/common/client"
4646
tctlcfg "github.com/gravitational/teleport/tool/tctl/common/config"
47+
"github.com/gravitational/teleport/tool/tctl/common/resources"
4748
)
4849

4950
// NodeCommand implements `tctl nodes` group of commands
@@ -258,18 +259,18 @@ func (c *NodeCommand) ListActive(ctx context.Context, clt *authclient.Client) er
258259
return trace.Wrap(err)
259260
}
260261

261-
coll := &serverCollection{servers: nodes}
262+
coll := resources.NewServerCollection(nodes)
262263
switch c.lsFormat {
263264
case teleport.Text:
264265
if err := coll.WriteText(os.Stdout, c.verbose); err != nil {
265266
return trace.Wrap(err)
266267
}
267268
case teleport.YAML:
268-
if err := coll.writeYAML(os.Stdout); err != nil {
269+
if err := coll.WriteYAML(os.Stdout); err != nil {
269270
return trace.Wrap(err)
270271
}
271272
case teleport.JSON:
272-
if err := coll.writeJSON(os.Stdout); err != nil {
273+
if err := coll.WriteJSON(os.Stdout); err != nil {
273274
return trace.Wrap(err)
274275
}
275276
default:

tool/tctl/common/proxy_command.go

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ import (
3030
"github.com/gravitational/teleport/lib/service/servicecfg"
3131
commonclient "github.com/gravitational/teleport/tool/tctl/common/client"
3232
tctlcfg "github.com/gravitational/teleport/tool/tctl/common/config"
33+
"github.com/gravitational/teleport/tool/tctl/common/resources"
3334
)
3435

3536
// ProxyCommand returns information about connected proxies
@@ -57,17 +58,17 @@ func (p *ProxyCommand) ListProxies(ctx context.Context, clusterAPI *authclient.C
5758
return trace.Wrap(err)
5859
}
5960

60-
sc := &serverCollection{proxies}
61+
sc := resources.NewServerCollection(proxies)
6162

6263
switch p.format {
6364
case teleport.Text:
6465
// proxies don't have labels.
6566
verbose := false
6667
return sc.WriteText(os.Stdout, verbose)
6768
case teleport.YAML:
68-
return writeYAML(sc, os.Stdout)
69+
return sc.WriteYAML(os.Stdout)
6970
case teleport.JSON:
70-
return writeJSON(sc, os.Stdout)
71+
return sc.WriteJSON(os.Stdout)
7172
}
7273

7374
return nil

tool/tctl/common/resource_command.go

Lines changed: 2 additions & 118 deletions
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,6 @@ import (
7777
"github.com/gravitational/teleport/lib/service/servicecfg"
7878
"github.com/gravitational/teleport/lib/services"
7979
"github.com/gravitational/teleport/lib/utils"
80-
logutils "github.com/gravitational/teleport/lib/utils/log"
8180
commonclient "github.com/gravitational/teleport/tool/tctl/common/client"
8281
clusterconfigrec "github.com/gravitational/teleport/tool/tctl/common/clusterconfig"
8382
tctlcfg "github.com/gravitational/teleport/tool/tctl/common/config"
@@ -152,7 +151,6 @@ func (rc *ResourceCommand) Initialize(app *kingpin.Application, _ *tctlcfg.Globa
152151
types.KindKubernetesCluster: rc.createKubeCluster,
153152
types.KindToken: rc.createToken,
154153
types.KindInstaller: rc.createInstaller,
155-
types.KindNode: rc.createNode,
156154
types.KindOIDCConnector: rc.createOIDCConnector,
157155
types.KindSAMLConnector: rc.createSAMLConnector,
158156
types.KindLoginRule: rc.createLoginRule,
@@ -1307,34 +1305,6 @@ func (rc *ResourceCommand) createUIConfig(ctx context.Context, client *authclien
13071305
return nil
13081306
}
13091307

1310-
func (rc *ResourceCommand) createNode(ctx context.Context, client *authclient.Client, raw services.UnknownResource) error {
1311-
server, err := services.UnmarshalServer(raw.Raw, types.KindNode, services.DisallowUnknown())
1312-
if err != nil {
1313-
return trace.Wrap(err)
1314-
}
1315-
1316-
name := server.GetName()
1317-
_, err = client.GetNode(ctx, server.GetNamespace(), name)
1318-
if err != nil && !trace.IsNotFound(err) {
1319-
return trace.Wrap(err)
1320-
}
1321-
exists := (err == nil)
1322-
if !rc.IsForced() && exists {
1323-
return trace.AlreadyExists("node %q with Hostname %q and Addr %q already exists, use --force flag to override",
1324-
name,
1325-
server.GetHostname(),
1326-
server.GetAddr(),
1327-
)
1328-
}
1329-
1330-
_, err = client.UpsertNode(ctx, server)
1331-
if err != nil {
1332-
return trace.Wrap(err)
1333-
}
1334-
fmt.Printf("node %q has been %s\n", name, UpsertVerb(exists, rc.IsForced()))
1335-
return nil
1336-
}
1337-
13381308
func (rc *ResourceCommand) createOIDCConnector(ctx context.Context, client *authclient.Client, raw services.UnknownResource) error {
13391309
conn, err := services.UnmarshalOIDCConnector(raw.Raw, services.DisallowUnknown())
13401310
if err != nil {
@@ -1745,11 +1715,6 @@ func (rc *ResourceCommand) Delete(ctx context.Context, client *authclient.Client
17451715
}
17461716

17471717
switch rc.ref.Kind {
1748-
case types.KindNode:
1749-
if err = client.DeleteNode(ctx, apidefaults.Namespace, rc.ref.Name); err != nil {
1750-
return trace.Wrap(err)
1751-
}
1752-
fmt.Printf("node %v has been deleted\n", rc.ref.Name)
17531718
case types.KindToken:
17541719
if err = client.DeleteToken(ctx, rc.ref.Name); err != nil {
17551720
return trace.Wrap(err)
@@ -2055,11 +2020,6 @@ func (rc *ResourceCommand) Delete(ctx context.Context, client *authclient.Client
20552020
return trace.Wrap(err)
20562021
}
20572022
fmt.Printf("User group %q has been deleted\n", rc.ref.Name)
2058-
case types.KindProxy:
2059-
if err := client.DeleteProxy(ctx, rc.ref.Name); err != nil {
2060-
return trace.Wrap(err)
2061-
}
2062-
fmt.Printf("Proxy %q has been deleted\n", rc.ref.Name)
20632023
case types.KindAccessList:
20642024
if err := client.AccessListClient().DeleteAccessList(ctx, rc.ref.Name); err != nil {
20652025
return trace.Wrap(err)
@@ -2424,82 +2384,6 @@ func (rc *ResourceCommand) getCollection(ctx context.Context, client *authclient
24242384
return nil, trace.Wrap(err)
24252385
}
24262386
return &authorityCollection{cas: []types.CertAuthority{authority}}, nil
2427-
case types.KindNode:
2428-
var search []string
2429-
if rc.ref.Name != "" {
2430-
search = []string{rc.ref.Name}
2431-
}
2432-
2433-
req := proto.ListUnifiedResourcesRequest{
2434-
Kinds: []string{types.KindNode},
2435-
SearchKeywords: search,
2436-
SortBy: types.SortBy{Field: types.ResourceKind},
2437-
}
2438-
2439-
var collection serverCollection
2440-
for {
2441-
page, next, err := apiclient.GetUnifiedResourcePage(ctx, client, &req)
2442-
if err != nil {
2443-
return nil, trace.Wrap(err)
2444-
}
2445-
2446-
for _, r := range page {
2447-
srv, ok := r.ResourceWithLabels.(types.Server)
2448-
if !ok {
2449-
slog.WarnContext(ctx, "expected types.Server but received unexpected type", "resource_type", logutils.TypeAttr(r))
2450-
continue
2451-
}
2452-
2453-
if rc.ref.Name == "" {
2454-
collection.servers = append(collection.servers, srv)
2455-
continue
2456-
}
2457-
2458-
if srv.GetName() == rc.ref.Name || srv.GetHostname() == rc.ref.Name {
2459-
collection.servers = []types.Server{srv}
2460-
return &collection, nil
2461-
}
2462-
}
2463-
2464-
req.StartKey = next
2465-
if req.StartKey == "" {
2466-
break
2467-
}
2468-
}
2469-
2470-
if len(collection.servers) == 0 && rc.ref.Name != "" {
2471-
return nil, trace.NotFound("node with ID %q not found", rc.ref.Name)
2472-
}
2473-
2474-
return &collection, nil
2475-
case types.KindAuthServer:
2476-
servers, err := client.GetAuthServers()
2477-
if err != nil {
2478-
return nil, trace.Wrap(err)
2479-
}
2480-
if rc.ref.Name == "" {
2481-
return &serverCollection{servers: servers}, nil
2482-
}
2483-
for _, server := range servers {
2484-
if server.GetName() == rc.ref.Name || server.GetHostname() == rc.ref.Name {
2485-
return &serverCollection{servers: []types.Server{server}}, nil
2486-
}
2487-
}
2488-
return nil, trace.NotFound("auth server with ID %q not found", rc.ref.Name)
2489-
case types.KindProxy:
2490-
servers, err := client.GetProxies()
2491-
if err != nil {
2492-
return nil, trace.Wrap(err)
2493-
}
2494-
if rc.ref.Name == "" {
2495-
return &serverCollection{servers: servers}, nil
2496-
}
2497-
for _, server := range servers {
2498-
if server.GetName() == rc.ref.Name || server.GetHostname() == rc.ref.Name {
2499-
return &serverCollection{servers: []types.Server{server}}, nil
2500-
}
2501-
}
2502-
return nil, trace.NotFound("proxy with ID %q not found", rc.ref.Name)
25032387
case types.KindNamespace:
25042388
return &namespaceCollection{namespaces: []types.Namespace{types.DefaultNamespace()}}, nil
25052389
case types.KindTrustedCluster:
@@ -3386,7 +3270,7 @@ func (rc *ResourceCommand) getCollection(ctx context.Context, client *authclient
33863270
if err != nil {
33873271
return nil, trace.Wrap(err)
33883272
}
3389-
return &serverCollection{servers: []types.Server{server}}, nil
3273+
return resources.NewServerCollection([]types.Server{server}), nil
33903274
}
33913275

33923276
servers, err := stream.Collect(clientutils.Resources(ctx, client.GitServerClient().ListGitServers))
@@ -3395,7 +3279,7 @@ func (rc *ResourceCommand) getCollection(ctx context.Context, client *authclient
33953279
}
33963280

33973281
// TODO(greedy52) consider making dedicated git server collection.
3398-
return &serverCollection{servers: servers}, nil
3282+
return resources.NewServerCollection(servers), nil
33993283

34003284
case types.KindWorkloadIdentityX509IssuerOverride:
34013285
c := client.WorkloadIdentityX509OverridesClient()

tool/tctl/common/resources/auth.go

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
// Teleport
2+
// Copyright (C) 2025 Gravitational, Inc.
3+
//
4+
// This program is free software: you can redistribute it and/or modify
5+
// it under the terms of the GNU Affero General Public License as published by
6+
// the Free Software Foundation, either version 3 of the License, or
7+
// (at your option) any later version.
8+
//
9+
// This program is distributed in the hope that it will be useful,
10+
// but WITHOUT ANY WARRANTY; without even the implied warranty of
11+
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12+
// GNU Affero General Public License for more details.
13+
//
14+
// You should have received a copy of the GNU Affero General Public License
15+
// along with this program. If not, see <http://www.gnu.org/licenses/>.
16+
17+
package resources
18+
19+
import (
20+
"context"
21+
22+
"github.com/gravitational/trace"
23+
24+
"github.com/gravitational/teleport/api/types"
25+
"github.com/gravitational/teleport/lib/auth/authclient"
26+
"github.com/gravitational/teleport/lib/services"
27+
)
28+
29+
func authHandler() Handler {
30+
return Handler{
31+
getHandler: getAuth,
32+
singleton: false,
33+
mfaRequired: false,
34+
description: "The central authority of the Teleport cluster.",
35+
}
36+
}
37+
38+
func getAuth(ctx context.Context, client *authclient.Client, ref services.Ref, opts GetOpts) (Collection, error) {
39+
servers, err := client.GetAuthServers()
40+
if err != nil {
41+
return nil, trace.Wrap(err)
42+
}
43+
if ref.Name == "" {
44+
return &ServerCollection{servers: servers}, nil
45+
}
46+
for _, server := range servers {
47+
if server.GetName() == ref.Name || server.GetHostname() == ref.Name {
48+
return &ServerCollection{servers: []types.Server{server}}, nil
49+
}
50+
}
51+
return nil, trace.NotFound("auth server with ID %q not found", ref.Name)
52+
}

0 commit comments

Comments
 (0)