Skip to content

Commit

Permalink
Merge pull request #630 from Zhuzhenghao/feature/export-log
Browse files Browse the repository at this point in the history
add export logs command
  • Loading branch information
k8s-ci-robot authored Jun 20, 2023
2 parents 98f5ebf + f65c522 commit 945c89e
Show file tree
Hide file tree
Showing 25 changed files with 733 additions and 31 deletions.
12 changes: 12 additions & 0 deletions .github/workflows/test.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -311,6 +311,11 @@ jobs:
run: |
./hack/e2e-test.sh kwokctl/kwokctl_${{ matrix.kwokctl-runtime }}_logs
- name: Test Export Logs
shell: bash
run: |
./hack/e2e-test.sh kwokctl/kwokctl_${{ matrix.kwokctl-runtime }}_export_logs
- name: Test Attach
shell: bash
run: |
Expand Down Expand Up @@ -346,3 +351,10 @@ jobs:
KWOK_MODE: StableFeatureGateAndAPI
run: |
./hack/e2e-test.sh kwokctl/kwokctl_${{ matrix.kwokctl-runtime }}
- name: Upload logs
uses: actions/upload-artifact@v3
if: failure()
with:
name: kwok-logs-${{ github.run_id }}-${{ matrix.os }}-${{ matrix.kwokctl-runtime }}${{ matrix.nerdctl-version && '-nerdctl' || '' }}${{ matrix.nerdctl-version }}
path: /tmp/kwok/logs
41 changes: 41 additions & 0 deletions pkg/kwokctl/cmd/export/export.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
/*
Copyright 2023 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

// Package export implements the `export` command
package export

import (
"context"

"github.com/spf13/cobra"

"sigs.k8s.io/kwok/pkg/kwokctl/cmd/export/logs"
)

// NewCommand returns a new cobra.Command for export
func NewCommand(ctx context.Context) *cobra.Command {
cmd := &cobra.Command{
Args: cobra.NoArgs,
Use: "export",
Short: "Exports one of [logs]",
RunE: func(cmd *cobra.Command, args []string) error {
return cmd.Help()
},
}
// add subcommands
cmd.AddCommand(logs.NewCommand(ctx))
return cmd
}
105 changes: 105 additions & 0 deletions pkg/kwokctl/cmd/export/logs/logs.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
/*
Copyright 2023 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

// Package logs implements the `logs` command
package logs

import (
"context"
"errors"
"fmt"
"os"
"path"
"path/filepath"

"github.com/spf13/cobra"

"sigs.k8s.io/kwok/pkg/config"
"sigs.k8s.io/kwok/pkg/kwokctl/runtime"
"sigs.k8s.io/kwok/pkg/log"
"sigs.k8s.io/kwok/pkg/utils/file"
)

type flagpole struct {
Name string
}

// NewCommand returns a new cobra.Command for getting the cluster logs
func NewCommand(ctx context.Context) *cobra.Command {
flags := &flagpole{}
cmd := &cobra.Command{
Args: cobra.MaximumNArgs(1),
Use: "logs [output-dir]",
Short: "Exports logs to a tempdir or [output-dir] if specified",
RunE: func(cmd *cobra.Command, args []string) error {
flags.Name = config.DefaultCluster
return runE(ctx, flags, args)
},
}
return cmd
}

func runE(ctx context.Context, flags *flagpole, args []string) error {
name := config.ClusterName(flags.Name)
workdir := path.Join(config.ClustersDir, flags.Name)

logger := log.FromContext(ctx).With("cluster", flags.Name)
ctx = log.NewContext(ctx, logger)

rt, err := runtime.DefaultRegistry.Load(ctx, name, workdir)
if err != nil {
if errors.Is(err, os.ErrNotExist) {
logger.Warn("Cluster is not exists")
}
return err
}

// get the optional directory argument, or create a tempdir under the kwok default working directory
var dir string
if len(args) == 0 || args[0] == "" {
tmp := filepath.Join(workdir, "tmp")
if err := os.MkdirAll(tmp, 0750); err != nil {
return fmt.Errorf("failed to create tmp directory: %w", err)
}
t, err := os.MkdirTemp(tmp, "log-")
if err != nil {
return err
}
dir = t
} else {
dir = filepath.Join(args[0], name)
}
if err := os.MkdirAll(dir, 0750); err != nil {
return fmt.Errorf("failed to create logs directory: %w", err)
}

kwokConfigPath := filepath.Join(dir, "kwok.yaml")
if _, err := os.Stat(kwokConfigPath); err == nil {
return fmt.Errorf("%s already exists", kwokConfigPath)
}
logger.Info("Exporting logs", "dir", dir)

err = file.Copy(rt.GetWorkdirPath(runtime.ConfigName), kwokConfigPath)
if err != nil {
return err
}

if err = rt.CollectLogs(ctx, name, dir); err != nil {
return err
}

return nil
}
2 changes: 2 additions & 0 deletions pkg/kwokctl/cmd/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import (
"sigs.k8s.io/kwok/pkg/kwokctl/cmd/create"
del "sigs.k8s.io/kwok/pkg/kwokctl/cmd/delete"
"sigs.k8s.io/kwok/pkg/kwokctl/cmd/etcdctl"
"sigs.k8s.io/kwok/pkg/kwokctl/cmd/export"
"sigs.k8s.io/kwok/pkg/kwokctl/cmd/get"
"sigs.k8s.io/kwok/pkg/kwokctl/cmd/kubectl"
"sigs.k8s.io/kwok/pkg/kwokctl/cmd/logs"
Expand Down Expand Up @@ -62,6 +63,7 @@ func NewCommand(ctx context.Context) *cobra.Command {
etcdctl.NewCommand(ctx),
logs.NewCommand(ctx),
snapshot.NewCommand(ctx),
export.NewCommand(ctx),
)
return cmd
}
42 changes: 42 additions & 0 deletions pkg/kwokctl/runtime/binary/cluster.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,13 @@ import (
"io"
"os"
"path/filepath"
rt "runtime"
"time"

"github.com/nxadm/tail"

"sigs.k8s.io/kwok/pkg/apis/internalversion"
"sigs.k8s.io/kwok/pkg/consts"
"sigs.k8s.io/kwok/pkg/kwokctl/components"
"sigs.k8s.io/kwok/pkg/kwokctl/k8s"
"sigs.k8s.io/kwok/pkg/kwokctl/pki"
Expand Down Expand Up @@ -748,6 +750,46 @@ func (c *Cluster) LogsFollow(ctx context.Context, name string, out io.Writer) er
return nil
}

// CollectLogs returns the logs of the specified component.
func (c *Cluster) CollectLogs(ctx context.Context, name string, dir string) error {
conf, err := c.Config(ctx)
if err != nil {
return err
}

path := filepath.Join(dir, consts.RuntimeTypeBinary+"-info.txt")
f, err := file.Open(path, 0640)
if err != nil {
return err
}
_, err = f.WriteString(fmt.Sprintf("%s/%s", rt.GOOS, rt.GOARCH))
if err != nil {
return err
}
if err = f.Close(); err != nil {
return err
}

componentsDir := filepath.Join(dir, "components")
logger := log.FromContext(ctx)
for _, component := range conf.Components {
src := c.GetLogPath(filepath.Base(component.Name) + ".log")
dest := filepath.Join(componentsDir, component.Name+".log")
if err = file.Copy(src, dest); err != nil {
logger.Error("Failed to copy file", err)
}
}
if conf.Options.KubeAuditPolicy != "" {
src := c.GetLogPath(runtime.AuditLogName)
dest := filepath.Join(componentsDir, runtime.AuditLogName)
if err = file.Copy(src, dest); err != nil {
logger.Error("Failed to copy file", err)
}
}

return nil
}

// ListBinaries list binaries in the cluster
func (c *Cluster) ListBinaries(ctx context.Context) ([]string, error) {
config, err := c.Config(ctx)
Expand Down
60 changes: 60 additions & 0 deletions pkg/kwokctl/runtime/compose/cluster.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import (
"fmt"
"io"
"os"
"path/filepath"
"strconv"
"strings"
"time"
Expand Down Expand Up @@ -752,6 +753,65 @@ func (c *Cluster) LogsFollow(ctx context.Context, name string, out io.Writer) er
return c.logs(ctx, name, out, true)
}

// CollectLogs returns the logs of the specified component.
func (c *Cluster) CollectLogs(ctx context.Context, name string, dir string) error {
conf, err := c.Config(ctx)
if err != nil {
return err
}

err = exec.WriteToPath(ctx, filepath.Join(dir, c.runtime+"-info.txt"), []string{c.runtime, "info"})
if err != nil {
return err
}

componentsDir := filepath.Join(dir, "components")
logger := log.FromContext(ctx)
for _, component := range conf.Components {
path := filepath.Join(componentsDir, component.Name+".log")
f, err := file.Open(path, 0640)
if err != nil {
logger.Error("Failed to open file", err)
continue
}
if err = c.Logs(ctx, component.Name, f); err != nil {
logger.Error("Failed to get log", err)
if err = f.Close(); err != nil {
logger.Error("Failed to close file", err)
if err = os.Remove(path); err != nil {
logger.Error("Failed to remove file", err)
}
}
}
if err = f.Close(); err != nil {
logger.Error("Failed to close file", err)
if err = os.Remove(path); err != nil {
logger.Error("Failed to remove file", err)
}
}
}

if conf.Options.KubeAuditPolicy != "" {
filePath := filepath.Join(componentsDir, "audit.log")
f, err := file.Open(filePath, 0640)
if err != nil {
logger.Error("Failed to open file", err)
} else {
if err = c.AuditLogs(ctx, f); err != nil {
logger.Error("Failed to get audit log", err)
}
if err = f.Close(); err != nil {
logger.Error("Failed to close file", err)
if err = os.Remove(filePath); err != nil {
logger.Error("Failed to remove file", err)
}
}
}
}

return nil
}

// ListBinaries list binaries in the cluster
func (c *Cluster) ListBinaries(ctx context.Context) ([]string, error) {
config, err := c.Config(ctx)
Expand Down
3 changes: 3 additions & 0 deletions pkg/kwokctl/runtime/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,9 @@ type Runtime interface {
// LogsFollow follow logs of a component with follow
LogsFollow(ctx context.Context, name string, out io.Writer) error

// CollectLogs will populate dir with cluster logs and other debug files
CollectLogs(ctx context.Context, name string, dir string) error

// AuditLogs audit logs of apiserver
AuditLogs(ctx context.Context, out io.Writer) error

Expand Down
Loading

0 comments on commit 945c89e

Please sign in to comment.