This repository has been archived by the owner on Sep 13, 2024. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
9411e5c
commit a769988
Showing
5 changed files
with
234 additions
and
5 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -14,7 +14,6 @@ dist/ | |
/git | ||
bin | ||
.vscode/settings.json | ||
logs/ | ||
/tmp | ||
lint_log.txt | ||
.idea | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,97 @@ | ||
/* | ||
Copyright 2018 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 ( | ||
"fmt" | ||
|
||
"github.com/spf13/cobra" | ||
|
||
"github.com/PatrickLaabs/frigg/cmd" | ||
"github.com/PatrickLaabs/frigg/pkg/cluster" | ||
"github.com/PatrickLaabs/frigg/pkg/fs" | ||
"github.com/PatrickLaabs/frigg/pkg/log" | ||
|
||
"github.com/PatrickLaabs/frigg/internal/cli" | ||
|
||
"github.com/PatrickLaabs/frigg/internal/runtime" | ||
) | ||
|
||
type flagpole struct { | ||
Name string | ||
} | ||
|
||
// NewCommand returns a new cobra.Command for getting the cluster logs | ||
func NewCommand(logger log.Logger, streams cmd.IOStreams) *cobra.Command { | ||
flags := &flagpole{} | ||
c := &cobra.Command{ | ||
Args: cobra.MaximumNArgs(1), | ||
// TODO(bentheelder): more detailed usage | ||
Use: "logs [output-dir]", | ||
Short: "Exports logs to a tempdir or [output-dir] if specified", | ||
Long: "Exports logs to a tempdir or [output-dir] if specified", | ||
RunE: func(cmd *cobra.Command, args []string) error { | ||
cli.OverrideDefaultName(cmd.Flags()) | ||
return runE(logger, streams, flags, args) | ||
}, | ||
} | ||
c.Flags().StringVarP( | ||
&flags.Name, | ||
"name", | ||
"n", | ||
cluster.DefaultName, | ||
"the cluster context name", | ||
) | ||
return c | ||
} | ||
|
||
func runE(logger log.Logger, streams cmd.IOStreams, flags *flagpole, args []string) error { | ||
provider := cluster.NewProvider( | ||
cluster.ProviderWithLogger(logger), | ||
runtime.GetDefault(logger), | ||
) | ||
|
||
// Check if the cluster has any running nodes | ||
nodes, err := provider.ListNodes(flags.Name) | ||
if err != nil { | ||
return err | ||
} | ||
if len(nodes) == 0 { | ||
return fmt.Errorf("unknown cluster %q", flags.Name) | ||
} | ||
|
||
// get the optional directory argument, or create a tempdir | ||
var dir string | ||
if len(args) == 0 { | ||
t, err := fs.TempDir("", "") | ||
if err != nil { | ||
return err | ||
} | ||
dir = t | ||
} else { | ||
dir = args[0] | ||
} | ||
|
||
// NOTE: the path is the output of this command to be captured by calling tools | ||
// whereas "Exporting logs..." is info / debug (stderr) | ||
logger.V(0).Infof("Exporting logs for cluster %q to:", flags.Name) | ||
fmt.Fprintln(streams.Out, dir) | ||
|
||
// collect the logs | ||
return provider.CollectLogs(flags.Name, dir) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
/* | ||
Copyright 2018 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 contains tooling for obtaining cluster logs | ||
package logs |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,105 @@ | ||
/* | ||
Copyright 2018 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 | ||
|
||
import ( | ||
"archive/tar" | ||
"fmt" | ||
"io" | ||
"os" | ||
"path" | ||
"path/filepath" | ||
|
||
"github.com/alessio/shellescape" | ||
|
||
"github.com/PatrickLaabs/frigg/pkg/cluster/nodes" | ||
"github.com/PatrickLaabs/frigg/pkg/errors" | ||
"github.com/PatrickLaabs/frigg/pkg/exec" | ||
"github.com/PatrickLaabs/frigg/pkg/log" | ||
) | ||
|
||
// DumpDir dumps the dir nodeDir on the node to the dir hostDir on the host | ||
func DumpDir(logger log.Logger, node nodes.Node, nodeDir, hostDir string) (err error) { | ||
cmd := node.Command( | ||
"sh", "-c", | ||
// Tar will exit 1 if a file changed during the archival. | ||
// We don't care about this, so we're invoking it in a shell | ||
// And masking out 1 as a return value. | ||
// Fatal errors will return exit code 2. | ||
// http://man7.org/linux/man-pages/man1/tar.1.html#RETURN_VALUE | ||
fmt.Sprintf( | ||
`tar --hard-dereference -C %s -chf - . || (r=$?; [ $r -eq 1 ] || exit $r)`, | ||
shellescape.Quote(path.Clean(nodeDir)+"/"), | ||
), | ||
) | ||
|
||
return exec.RunWithStdoutReader(cmd, func(outReader io.Reader) error { | ||
if err := untar(logger, outReader, hostDir); err != nil { | ||
return errors.Wrapf(err, "Untarring %q: %v", nodeDir, err) | ||
} | ||
return nil | ||
}) | ||
} | ||
|
||
// untar reads the tar file from r and writes it into dir. | ||
func untar(logger log.Logger, r io.Reader, dir string) (err error) { | ||
tr := tar.NewReader(r) | ||
for { | ||
f, err := tr.Next() | ||
|
||
switch { | ||
case err == io.EOF: | ||
// drain the reader, which may have trailing null bytes | ||
// we don't want to leave the writer hanging | ||
_, err := io.Copy(io.Discard, r) | ||
return err | ||
case err != nil: | ||
return errors.Wrapf(err, "tar reading error: %v", err) | ||
case f == nil: | ||
continue | ||
} | ||
|
||
rel := filepath.FromSlash(f.Name) | ||
abs := filepath.Join(dir, rel) | ||
|
||
switch f.Typeflag { | ||
case tar.TypeReg: | ||
wf, err := os.OpenFile(abs, os.O_CREATE|os.O_RDWR, os.FileMode(f.Mode)) | ||
if err != nil { | ||
return err | ||
} | ||
n, err := io.Copy(wf, tr) | ||
if closeErr := wf.Close(); closeErr != nil && err == nil { | ||
err = closeErr | ||
} | ||
if err != nil { | ||
return errors.Errorf("error writing to %s: %v", abs, err) | ||
} | ||
if n != f.Size { | ||
return errors.Errorf("only wrote %d bytes to %s; expected %d", n, abs, f.Size) | ||
} | ||
case tar.TypeDir: | ||
if _, err := os.Stat(abs); err != nil { | ||
if err := os.MkdirAll(abs, 0755); err != nil { | ||
return err | ||
} | ||
} | ||
default: | ||
logger.Warnf("tar file entry %s contained unsupported file type %v", f.Name, f.Typeflag) | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters