Skip to content

Commit

Permalink
chore: use go-talos-support library
Browse files Browse the repository at this point in the history
The code for collecting Talos `support.zip` was extracted there.

Signed-off-by: Artem Chernyshev <artem.chernyshev@talos-systems.com>
  • Loading branch information
Unix4ever committed Mar 19, 2024
1 parent 89fc68b commit 113fb64
Show file tree
Hide file tree
Showing 5 changed files with 109 additions and 869 deletions.
185 changes: 96 additions & 89 deletions cmd/talosctl/cmd/talos/support.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,26 +5,28 @@
package talos

import (
"archive/zip"
"bufio"
"context"
"errors"
"fmt"
"io"
"os"
"strings"
"sync"
"text/tabwriter"

"github.com/cosi-project/runtime/pkg/resource"
"github.com/cosi-project/runtime/pkg/safe"
"github.com/fatih/color"
"github.com/gosuri/uiprogress"
"github.com/hashicorp/go-multierror"
"github.com/siderolabs/go-talos-support/support"
"github.com/siderolabs/go-talos-support/support/bundle"
"github.com/siderolabs/go-talos-support/support/collectors"
"github.com/spf13/cobra"
"golang.org/x/sync/errgroup"
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
k8s "k8s.io/client-go/kubernetes"
"k8s.io/client-go/tools/clientcmd"

"github.com/siderolabs/talos/pkg/cluster"
"github.com/siderolabs/talos/pkg/machinery/client"
clusterresource "github.com/siderolabs/talos/pkg/machinery/resources/cluster"
)
Expand Down Expand Up @@ -71,108 +73,106 @@ var supportCmd = &cobra.Command{

defer f.Close() //nolint:errcheck

archive := &cluster.BundleArchive{
Archive: zip.NewWriter(f),
}

progress := make(chan cluster.BundleProgress)
progress := make(chan bundle.Progress)

var eg errgroup.Group
var (
eg errgroup.Group
errors supportBundleErrors
)

eg.Go(func() error {
if supportCmdFlags.verbose {
for range progress { //nolint:revive
for p := range progress {
errors.handleProgress(p)
}
} else {
showProgress(progress)
showProgress(progress, &errors)
}

return nil
})

collectErr := collectData(archive, progress)
collectErr := collectData(f, progress)

close(progress)

if e := eg.Wait(); e != nil {
return e
}

if collectErr != nil {
if err = printErrors(collectErr); err != nil {
return err
}
}

fmt.Fprintf(os.Stderr, "Support bundle is written to %s\n", supportCmdFlags.output)

if err = archive.Archive.Close(); err != nil {
if err = errors.print(); err != nil {
return err
}

if collectErr != nil {
os.Exit(1)
}
fmt.Fprintf(os.Stderr, "Support bundle is written to %s\n", supportCmdFlags.output)

return nil
return collectErr
},
}

func collectData(archive *cluster.BundleArchive, progress chan cluster.BundleProgress) error {
func collectData(dest *os.File, progress chan bundle.Progress) error {
return WithClient(func(ctx context.Context, c *client.Client) error {
sources := append([]string{}, GlobalArgs.Nodes...)
sources = append(sources, "cluster")

var (
errsMu sync.Mutex
errs error
)
clientset, err := getKubernetesClient(ctx, c)
if err != nil {
fmt.Fprintf(os.Stderr, "Failed to create kubernetes client %s\n", err)
}

var eg errgroup.Group
opts := []bundle.Option{
bundle.WithArchiveOutput(dest),
bundle.WithKubernetesClient(clientset),
bundle.WithTalosClient(c),
bundle.WithNodes(GlobalArgs.Nodes...),
bundle.WithNumWorkers(supportCmdFlags.numWorkers),
bundle.WithProgressChan(progress),
}

for _, source := range sources {
opts := &cluster.BundleOptions{
Archive: archive,
NumWorkers: supportCmdFlags.numWorkers,
Progress: progress,
Source: source,
Client: c,
}
if !supportCmdFlags.verbose {
opts = append(opts, bundle.WithLogOutput(io.Discard))
}

if !supportCmdFlags.verbose {
opts.LogOutput = io.Discard
}
options := bundle.NewOptions(opts...)

source := source
collectors, err := collectors.GetForOptions(ctx, options)
if err != nil {
return err
}

eg.Go(func() error {
var err error
return support.CreateSupportBundle(ctx, options, collectors...)
})
}

if source == "cluster" {
err = cluster.GetKubernetesSupportBundle(ctx, opts)
} else {
err = cluster.GetNodeSupportBundle(client.WithNodes(ctx, source), opts)
}
func getKubernetesClient(ctx context.Context, c *client.Client) (*k8s.Clientset, error) {
if len(GlobalArgs.Endpoints) == 0 {
fmt.Fprintln(os.Stderr, "No endpoints set for the cluster, the command might not be able to get kubeconfig")
}

if err == nil {
return nil
}
kubeconfig, err := c.Kubeconfig(client.WithNodes(ctx, GlobalArgs.Endpoints...))
if err != nil {
return nil, err
}

errsMu.Lock()
defer errsMu.Unlock()
config, err := clientcmd.NewClientConfigFromBytes(kubeconfig)
if err != nil {
return nil, err
}

errs = multierror.Append(errs, err)
restconfig, err := config.ClientConfig()
if err != nil {
return nil, err
}

return err
})
}
clientset, err := k8s.NewForConfig(restconfig)
if err != nil {
return nil, err
}

// errors are gathered separately as eg.Wait returns only a single error
// while we want to gather all of them
eg.Wait() //nolint:errcheck
// just checking that k8s responds
_, err = clientset.CoreV1().Namespaces().Get(ctx, "kube-system", v1.GetOptions{})
if err != nil {
return nil, err
}

return errs
})
return clientset, nil
}

func getDiscoveryConfig() (*clusterresource.Config, error) {
Expand Down Expand Up @@ -221,49 +221,54 @@ func openArchive() (*os.File, error) {
}

if strings.TrimSpace(strings.ToLower(choice)) != "y" {
return nil, nil
return nil, fmt.Errorf("operation aborted")
}
}

return os.OpenFile(supportCmdFlags.output, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0o644)
}

func printErrors(err error) error {
w := tabwriter.NewWriter(os.Stderr, 0, 0, 3, ' ', 0)

wroteHeader := false
type supportBundleError struct {
source string
value string
}

var errs *multierror.Error
type supportBundleErrors struct {
errors []supportBundleError
}

if !errors.As(err, &errs) {
fmt.Fprintf(os.Stderr, "Processed with errors:\n%s\n", color.RedString(err.Error()))
func (sbe *supportBundleErrors) handleProgress(p bundle.Progress) {
if p.Error != nil {
sbe.errors = append(sbe.errors, supportBundleError{
source: p.Source,
value: p.Error.Error(),
})
}
}

func (sbe *supportBundleErrors) print() error {
if sbe.errors == nil {
return nil
}

for _, err := range errs.Errors {
var wroteHeader bool

w := tabwriter.NewWriter(os.Stderr, 0, 0, 3, ' ', 0)

for _, err := range sbe.errors {
if !wroteHeader {
wroteHeader = true

fmt.Fprintln(os.Stderr, "Processed with errors:")
fmt.Fprintln(w, "\tSOURCE\tERROR")
}

var (
bundleErr *cluster.BundleError
source string
)

if errors.As(err, &bundleErr) {
source = bundleErr.Source
}

details := strings.Split(err.Error(), "\n")
details := strings.Split(err.value, "\n")
for i, d := range details {
details[i] = strings.TrimSpace(d)
}

fmt.Fprintf(w, "\t%s\t%s\n", source, color.RedString(details[0]))
fmt.Fprintf(w, "\t%s\t%s\n", err.source, color.RedString(details[0]))

if len(details) > 1 {
for _, line := range details[1:] {
Expand All @@ -275,7 +280,7 @@ func printErrors(err error) error {
return w.Flush()
}

func showProgress(progress <-chan cluster.BundleProgress) {
func showProgress(progress <-chan bundle.Progress, errors *supportBundleErrors) {
uiprogress.Start()

type nodeProgress struct {
Expand All @@ -286,6 +291,8 @@ func showProgress(progress <-chan cluster.BundleProgress) {
nodes := map[string]*nodeProgress{}

for p := range progress {
errors.handleProgress(p)

var (
np *nodeProgress
ok bool
Expand Down
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,7 @@ require (
github.com/siderolabs/go-retry v0.3.3
github.com/siderolabs/go-smbios v0.3.2
github.com/siderolabs/go-tail v0.1.0
github.com/siderolabs/go-talos-support v0.1.0
github.com/siderolabs/grpc-proxy v0.4.0
github.com/siderolabs/kms-client v0.1.0
github.com/siderolabs/net v0.4.0
Expand Down
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -694,6 +694,8 @@ github.com/siderolabs/go-smbios v0.3.2 h1:/9MCz1h3HYFcNdFG9rIL9EKwtQJsHRPuGuM2ES
github.com/siderolabs/go-smbios v0.3.2/go.mod h1:AKzwL3QdFOgA81h65Hay2bs3BUnH+FBnXqNfgeChpEc=
github.com/siderolabs/go-tail v0.1.0 h1:U+ZClt7BXLGsxDNU/XQ12sz7lQElfFZBYEPdkW78Qro=
github.com/siderolabs/go-tail v0.1.0/go.mod h1:vWxumnRUS3eTZczORCJW3QMjxiTETN31vyuFdaW8rPw=
github.com/siderolabs/go-talos-support v0.1.0 h1:ulf+RI0Wo6UGzKQJZog1uvdQE/zstogs1R46jZpAmvU=
github.com/siderolabs/go-talos-support v0.1.0/go.mod h1:hiYQrdQSBH6ap7LZHyHUZLbYnL2KhC6hPrJ7utqm+P8=
github.com/siderolabs/grpc-proxy v0.4.0 h1:zYrhqLYs8JlYoLHYeel7/XwXDZ4OJ5XyP9wX7JlbPew=
github.com/siderolabs/grpc-proxy v0.4.0/go.mod h1:QDurYOwQD4H8BKyvCuUxMiuG/etYnb/++xaQB644NdU=
github.com/siderolabs/kms-client v0.1.0 h1:rCDWzcDDsNlp6zdyLngOuuhchVILn+vwUQy3tk6rQps=
Expand Down
20 changes: 10 additions & 10 deletions internal/integration/cli/support.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,15 +55,15 @@ func (suite *SupportSuite) TestSupport() {

for _, name := range []string{
"dmesg.log",
"service-logs/apid.log",
"service-logs/apid.state",
"service-logs/machined.log",
"service-logs/machined.state",
"service-logs/kubelet.log",
"service-logs/kubelet.state",
"resources/kernelparamstatuses.runtime.talos.dev.yaml",
"kubernetes-logs/kube-system/kube-apiserver.log",
"controller-runtime.log",
"apid.log",
"apid.state",
"machined.log",
"machined.state",
"kubelet.log",
"kubelet.state",
"talosResources/kernelparamstatuses.runtime.talos.dev.yaml",
"kube-system/kube-apiserver.log",
"mounts",
"processes",
"io",
Expand All @@ -74,8 +74,8 @@ func (suite *SupportSuite) TestSupport() {
}

for _, name := range []string{
"cluster/kubernetesResources/nodes.yaml",
"cluster/kubernetesResources/systemPods.yaml",
"kubernetesResources/nodes.yaml",
"kubernetesResources/systemPods.yaml",
} {
suite.Require().Contains(files, name, "File %s doesn't exist in the support bundle", name)
}
Expand Down

0 comments on commit 113fb64

Please sign in to comment.