Skip to content

Commit f6058a1

Browse files
committed
feat: grab support bundle via client factory
Fixes #13491 Fixes #13488 Use new `go-talos-support` bundle library, pass the client factory as the client provider. Aggregate and properly report partial failures. Also, while I'm at it - implement insecure mode for dmesg, memory and service (list) commands. Support bundle can be gathered in maintenance mode now as well. Signed-off-by: Andrey Smirnov <andrey.smirnov@siderolabs.com>
1 parent cdd7197 commit f6058a1

9 files changed

Lines changed: 37 additions & 144 deletions

File tree

cmd/talosctl/cmd/talos/dmesg.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,12 +11,15 @@ import (
1111

1212
"github.com/spf13/cobra"
1313

14+
"github.com/siderolabs/talos/cmd/talosctl/pkg/talos/global"
1415
machineapi "github.com/siderolabs/talos/pkg/machinery/api/machine"
1516
"github.com/siderolabs/talos/pkg/machinery/client"
1617
"github.com/siderolabs/talos/pkg/machinery/client/multiplex"
1718
)
1819

1920
var dmesgCmdFlags struct {
21+
global.InsecureFlags
22+
2023
follow bool
2124
tail bool
2225
}
@@ -66,4 +69,5 @@ func init() {
6669
addCommand(dmesgCmd)
6770
dmesgCmd.Flags().BoolVarP(&dmesgCmdFlags.follow, "follow", "f", false, "specify if the kernel log should be streamed")
6871
dmesgCmd.Flags().BoolVarP(&dmesgCmdFlags.tail, "tail", "", false, "specify if only new messages should be sent (makes sense only when combined with --follow)")
72+
dmesgCmdFlags.InsecureFlags.AddFlags(dmesgCmd)
6973
}

cmd/talosctl/cmd/talos/memory.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,12 +14,15 @@ import (
1414

1515
"github.com/spf13/cobra"
1616

17+
"github.com/siderolabs/talos/cmd/talosctl/pkg/talos/global"
1718
machineapi "github.com/siderolabs/talos/pkg/machinery/api/machine"
1819
"github.com/siderolabs/talos/pkg/machinery/client"
1920
"github.com/siderolabs/talos/pkg/machinery/client/multiplex"
2021
)
2122

2223
var memoryCmdFlags struct {
24+
global.InsecureFlags
25+
2326
verbose bool
2427
}
2528

@@ -170,5 +173,6 @@ func renderVerbose(responseChan <-chan multiplex.Response[*machineapi.MemoryResp
170173

171174
func init() {
172175
memoryCmd.Flags().BoolVarP(&memoryCmdFlags.verbose, "verbose", "v", false, "display extended memory statistics")
176+
memoryCmdFlags.InsecureFlags.AddFlags(memoryCmd)
173177
addCommand(memoryCmd)
174178
}

cmd/talosctl/cmd/talos/service.go

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,10 @@ import (
2121
"github.com/siderolabs/talos/pkg/machinery/client/multiplex"
2222
)
2323

24+
var serviceCmdFlags struct {
25+
global.InsecureFlags
26+
}
27+
2428
// serviceCmd represents the service command.
2529
var serviceCmd = &cobra.Command{
2630
Use: "service [<id> [start|stop|restart|status]]",
@@ -54,7 +58,7 @@ With actions 'start', 'stop', 'restart', service state is updated respectively.`
5458

5559
ctx := cmd.Context()
5660

57-
clientFactory, err := NewClientFactory(ctx, nil)
61+
clientFactory, err := NewClientFactory(ctx, &serviceCmdFlags)
5862
if err != nil {
5963
return err
6064
}
@@ -281,4 +285,5 @@ func (svc serviceInfoWrapper) healthStatus() string {
281285

282286
func init() {
283287
addCommand(serviceCmd)
288+
serviceCmdFlags.InsecureFlags.AddFlags(serviceCmd)
284289
}

cmd/talosctl/cmd/talos/support.go

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,8 @@ import (
3434
)
3535

3636
var supportCmdFlags struct {
37+
global.InsecureFlags
38+
3739
output string
3840
numWorkers int
3941
verbose bool
@@ -169,20 +171,22 @@ Default encryption recipients can be removed by setting --encryption-no-default-
169171
}
170172

171173
func collectData(ctx context.Context, dest io.Writer, progress chan bundle.Progress, clientFactory *global.ClientFactory) error {
174+
var errs error
175+
172176
nodeCtx, c, err := clientFactory.BuildClientFirstNode(ctx)
173177
if err != nil {
174178
return err
175179
}
176180

177181
clientset, err := getKubernetesClient(nodeCtx, c)
178182
if err != nil {
179-
fmt.Fprintf(os.Stderr, "failed to create kubernetes client %s\n", err)
183+
errs = errors.Join(errs, fmt.Errorf("failed to create kubernetes client: %w", err))
180184
}
181185

182186
opts := []bundle.Option{
183187
bundle.WithArchiveOutput(dest),
184188
bundle.WithKubernetesClient(clientset),
185-
bundle.WithTalosClient(c),
189+
bundle.WithTalosClientProvider(clientFactory.BuildClient),
186190
bundle.WithNodes(clientFactory.Nodes()...),
187191
bundle.WithNumWorkers(supportCmdFlags.numWorkers),
188192
bundle.WithProgressChan(progress),
@@ -196,10 +200,10 @@ func collectData(ctx context.Context, dest io.Writer, progress chan bundle.Progr
196200

197201
collectors, err := collectors.GetForOptions(ctx, options)
198202
if err != nil {
199-
return err
203+
errs = errors.Join(errs, fmt.Errorf("failed to create collectors: %w", err))
200204
}
201205

202-
return support.CreateSupportBundle(ctx, options, collectors...)
206+
return errors.Join(errs, support.CreateSupportBundle(ctx, options, collectors...))
203207
}
204208

205209
func getKubernetesClient(ctx context.Context, c *client.Client) (*k8s.Clientset, error) {
@@ -445,4 +449,5 @@ func init() {
445449
&supportCmdFlags.encryptionNoDefaultRecipients, "encryption-no-default-recipients", false,
446450
"do not encrypt to the default recipients, only to the ones provided via --encryption-recipients",
447451
)
452+
supportCmdFlags.InsecureFlags.AddFlags(supportCmd)
448453
}

go.mod

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -149,7 +149,7 @@ require (
149149
github.com/siderolabs/go-retry v0.3.3
150150
github.com/siderolabs/go-smbios v0.3.4
151151
github.com/siderolabs/go-tail v0.1.1
152-
github.com/siderolabs/go-talos-support v0.2.2
152+
github.com/siderolabs/go-talos-support v0.3.0
153153
github.com/siderolabs/grpc-proxy v0.5.2
154154
github.com/siderolabs/kms-client v0.2.0
155155
github.com/siderolabs/net v0.4.0

go.sum

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -833,8 +833,8 @@ github.com/siderolabs/go-smbios v0.3.4 h1:3HvW8lf+kw+HnC67XzdCH8WhkDeX+K9W4VmV54
833833
github.com/siderolabs/go-smbios v0.3.4/go.mod h1:lNA6mNOsqhDQcE7HnAtATOa8F9CU8Q69M5wyNUSU0Co=
834834
github.com/siderolabs/go-tail v0.1.1 h1:3XeJgd97OHyFAIE7nQEMcRhOfnv7DvXbu0BRKbtT6u8=
835835
github.com/siderolabs/go-tail v0.1.1/go.mod h1:IihAL39acadXHfb5fEAOKK2DaDFIrG2+VD3b2H/ziZ0=
836-
github.com/siderolabs/go-talos-support v0.2.2 h1:5urNuBSZdWrJhScWrjuaxf9xXmJFWTdx5YJO/iP3fko=
837-
github.com/siderolabs/go-talos-support v0.2.2/go.mod h1:IB9sOkhUgjGJFuuBs+TZVdjgG01ly8/Ku9SOshINvSU=
836+
github.com/siderolabs/go-talos-support v0.3.0 h1:8+JErCZAc2jRTtSJKkW1xFJxetX/b5m/YesMgVnz2v4=
837+
github.com/siderolabs/go-talos-support v0.3.0/go.mod h1:IB9sOkhUgjGJFuuBs+TZVdjgG01ly8/Ku9SOshINvSU=
838838
github.com/siderolabs/grpc-proxy v0.5.2 h1:o34tS02IxbX3qeXe0MM99zE2XhfWHuvdBtSWWRD9HNI=
839839
github.com/siderolabs/grpc-proxy v0.5.2/go.mod h1:ygf+gqFxWdymAXuP4qMHTa+j6SvasdcFg3XkhpvUvDw=
840840
github.com/siderolabs/kms-client v0.2.0 h1:8RniCStUI75RTZO8qkhHOSVOnEU1AvvsKqJ7FqW/8NA=

pkg/cluster/crashdump.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,9 @@ func Crashdump(ctx context.Context, cluster provision.Cluster, logWriter io.Writ
5151

5252
opts := []bundle.Option{
5353
bundle.WithArchiveOutput(supportFile),
54-
bundle.WithTalosClient(c),
54+
bundle.WithTalosClientProvider(func(ctx context.Context, node string) (context.Context, *client.Client, error) {
55+
return client.WithNode(ctx, node), c, nil
56+
}),
5557
bundle.WithNodes(nodes...),
5658
bundle.WithNumWorkers(4),
5759
bundle.WithLogOutput(io.Discard),

pkg/machinery/formatters/formatters.go

Lines changed: 0 additions & 135 deletions
Original file line numberDiff line numberDiff line change
@@ -9,67 +9,14 @@ import (
99
"context"
1010
"fmt"
1111
"io"
12-
"math"
13-
"slices"
14-
"strings"
15-
"text/tabwriter"
16-
"time"
1712

1813
"github.com/cosi-project/runtime/pkg/resource"
1914
"github.com/emicklei/dot"
20-
"google.golang.org/grpc/peer"
2115

2216
"github.com/siderolabs/talos/pkg/machinery/api/inspect"
23-
"github.com/siderolabs/talos/pkg/machinery/api/machine"
2417
"github.com/siderolabs/talos/pkg/machinery/client"
2518
)
2619

27-
// RenderMounts renders mounts output.
28-
//
29-
// Deprecated: use [RenderMountsStream] which handles multi-node responses via [multiplex.Unary].
30-
func RenderMounts(resp *machine.MountsResponse, output io.Writer, remotePeer *peer.Peer) error {
31-
w := tabwriter.NewWriter(output, 0, 0, 3, ' ', 0)
32-
parts := []string{"FILESYSTEM", "SIZE(GB)", "USED(GB)", "AVAILABLE(GB)", "PERCENT USED", "MOUNTED ON"}
33-
34-
var defaultNode string
35-
36-
if remotePeer != nil {
37-
parts = append([]string{"NODE"}, parts...)
38-
defaultNode = client.AddrFromPeer(remotePeer)
39-
}
40-
41-
fmt.Fprintln(w, strings.Join(parts, "\t"))
42-
43-
for _, msg := range resp.Messages {
44-
for _, r := range msg.Stats {
45-
percentAvailable := 100.0 - 100.0*(float64(r.Available)/float64(r.Size))
46-
47-
if math.IsNaN(percentAvailable) {
48-
continue
49-
}
50-
51-
node := defaultNode
52-
53-
if msg.Metadata != nil {
54-
node = msg.Metadata.Hostname //nolint:staticcheck // deprecated path, kept for backwards compatibility
55-
}
56-
57-
format := "%s\t%.02f\t%.02f\t%.02f\t%.02f%%\t%s\n"
58-
args := []any{r.Filesystem, float64(r.Size) * 1e-9, float64(r.Size-r.Available) * 1e-9, float64(r.Available) * 1e-9, percentAvailable, r.MountedOn}
59-
60-
if defaultNode != "" {
61-
format = "%s\t" + format
62-
63-
args = slices.Insert(args, 0, any(node))
64-
}
65-
66-
fmt.Fprintf(w, format, args...)
67-
}
68-
}
69-
70-
return w.Flush()
71-
}
72-
7320
// RenderGraph renders inspect controller runtime graph.
7421
//
7522
//nolint:gocyclo,cyclop
@@ -195,85 +142,3 @@ func RenderGraph(ctx context.Context, c *client.Client, resp *inspect.Controller
195142

196143
return nil
197144
}
198-
199-
// RenderServicesInfo writes human readable service information to the io.Writer.
200-
//
201-
// Deprecated: this relies on the legacy per-message node metadata; new code should
202-
// format the node explicitly from the multiplexed response (see the `service` command).
203-
func RenderServicesInfo(services []client.ServiceInfo, output io.Writer, defaultNode string, withNodeInfo bool) error {
204-
w := tabwriter.NewWriter(output, 0, 0, 3, ' ', 0)
205-
206-
node := defaultNode
207-
208-
for _, s := range services {
209-
if s.Metadata != nil {
210-
node = s.Metadata.Hostname //nolint:staticcheck // to be refactored next
211-
}
212-
213-
if withNodeInfo {
214-
fmt.Fprintf(w, "NODE\t%s\n", node)
215-
}
216-
217-
svc := ServiceInfoWrapper{s.Service}
218-
fmt.Fprintf(w, "ID\t%s\n", svc.Id)
219-
fmt.Fprintf(w, "STATE\t%s\n", svc.State)
220-
fmt.Fprintf(w, "HEALTH\t%s\n", svc.HealthStatus())
221-
222-
if svc.Health.LastMessage != "" {
223-
fmt.Fprintf(w, "LAST HEALTH MESSAGE\t%s\n", svc.Health.LastMessage)
224-
}
225-
226-
label := "EVENTS"
227-
228-
for i := range svc.Events.Events {
229-
event := svc.Events.Events[len(svc.Events.Events)-1-i]
230-
231-
ts := event.Ts.AsTime()
232-
fmt.Fprintf(w, "%s\t[%s]: %s (%s ago)\n", label, event.State, event.Msg, time.Since(ts).Round(time.Second))
233-
label = ""
234-
}
235-
}
236-
237-
return w.Flush()
238-
}
239-
240-
// ServiceInfoWrapper helper that allows generating rich service information.
241-
//
242-
// Deprecated: new code should format service information from the multiplexed
243-
// response with the node attached explicitly (see the `service` command).
244-
type ServiceInfoWrapper struct {
245-
*machine.ServiceInfo
246-
}
247-
248-
// LastUpdated derive last updated time from events stream.
249-
func (svc ServiceInfoWrapper) LastUpdated() string {
250-
if len(svc.Events.Events) == 0 {
251-
return ""
252-
}
253-
254-
ts := svc.Events.Events[len(svc.Events.Events)-1].Ts.AsTime()
255-
256-
return time.Since(ts).Round(time.Second).String()
257-
}
258-
259-
// LastEvent return last service event.
260-
func (svc ServiceInfoWrapper) LastEvent() string {
261-
if len(svc.Events.Events) == 0 {
262-
return "<none>"
263-
}
264-
265-
return svc.Events.Events[len(svc.Events.Events)-1].Msg
266-
}
267-
268-
// HealthStatus service health status.
269-
func (svc ServiceInfoWrapper) HealthStatus() string {
270-
if svc.Health.Unknown {
271-
return "?"
272-
}
273-
274-
if svc.Health.Healthy {
275-
return "OK"
276-
}
277-
278-
return "Fail"
279-
}

website/content/v1.14/reference/cli.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1338,11 +1338,13 @@ talosctl dmesg [flags]
13381338
### Options
13391339

13401340
```
1341+
--cert-fingerprint strings list of server certificate fingerprints to accept (defaults to no check, only used with --insecure flag)
13411342
-c, --cluster string cluster to connect to if a proxy endpoint is used
13421343
--context string context to be used in command
13431344
-e, --endpoints strings override default endpoints in Talos configuration
13441345
-f, --follow specify if the kernel log should be streamed
13451346
-h, --help help for dmesg
1347+
-i, --insecure use the insecure (encrypted with no auth) maintenance service
13461348
-n, --nodes strings target the specified nodes
13471349
--siderov1-keys-dir string the path to the SideroV1 auth PGP keys directory, defaults to 'SIDEROV1_KEYS_DIR' env variable if set, otherwise '$HOME/.talos/keys'; only valid for Contexts that use SideroV1 auth
13481350
--tail specify if only new messages should be sent (makes sense only when combined with --follow)
@@ -2858,10 +2860,12 @@ talosctl memory [flags]
28582860
### Options
28592861

28602862
```
2863+
--cert-fingerprint strings list of server certificate fingerprints to accept (defaults to no check, only used with --insecure flag)
28612864
-c, --cluster string cluster to connect to if a proxy endpoint is used
28622865
--context string context to be used in command
28632866
-e, --endpoints strings override default endpoints in Talos configuration
28642867
-h, --help help for memory
2868+
-i, --insecure use the insecure (encrypted with no auth) maintenance service
28652869
-n, --nodes strings target the specified nodes
28662870
--siderov1-keys-dir string the path to the SideroV1 auth PGP keys directory, defaults to 'SIDEROV1_KEYS_DIR' env variable if set, otherwise '$HOME/.talos/keys'; only valid for Contexts that use SideroV1 auth
28672871
--talosconfig string the path to the Talos configuration file, defaults to 'TALOSCONFIG' env variable if set, otherwise '$HOME/.talos/config' and '/var/run/secrets/talos.dev/config' in order
@@ -3336,10 +3340,12 @@ talosctl service [<id> [start|stop|restart|status]] [flags]
33363340
### Options
33373341

33383342
```
3343+
--cert-fingerprint strings list of server certificate fingerprints to accept (defaults to no check, only used with --insecure flag)
33393344
-c, --cluster string cluster to connect to if a proxy endpoint is used
33403345
--context string context to be used in command
33413346
-e, --endpoints strings override default endpoints in Talos configuration
33423347
-h, --help help for service
3348+
-i, --insecure use the insecure (encrypted with no auth) maintenance service
33433349
-n, --nodes strings target the specified nodes
33443350
--siderov1-keys-dir string the path to the SideroV1 auth PGP keys directory, defaults to 'SIDEROV1_KEYS_DIR' env variable if set, otherwise '$HOME/.talos/keys'; only valid for Contexts that use SideroV1 auth
33453351
--talosconfig string the path to the Talos configuration file, defaults to 'TALOSCONFIG' env variable if set, otherwise '$HOME/.talos/config' and '/var/run/secrets/talos.dev/config' in order
@@ -3441,12 +3447,14 @@ talosctl support [flags]
34413447
### Options
34423448

34433449
```
3450+
--cert-fingerprint strings list of server certificate fingerprints to accept (defaults to no check, only used with --insecure flag)
34443451
-c, --cluster string cluster to connect to if a proxy endpoint is used
34453452
--context string context to be used in command
34463453
--encryption-no-default-recipients do not encrypt to the default recipients, only to the ones provided via --encryption-recipients
34473454
--encryption-recipients stringArray additional age recipients (SSH or age public keys) to encrypt the support bundle to (can be specified multiple times)
34483455
-e, --endpoints strings override default endpoints in Talos configuration
34493456
-h, --help help for support
3457+
-i, --insecure use the insecure (encrypted with no auth) maintenance service
34503458
--no-encryption do not encrypt the support bundle (output is written as-is)
34513459
-n, --nodes strings target the specified nodes
34523460
-w, --num-workers int number of workers per node (default 1)

0 commit comments

Comments
 (0)