1
0
Fork 0
mirror of https://github.com/arangodb/kube-arangodb.git synced 2024-12-14 11:57:37 +00:00

[Feature] [Debug Package] Initial commit (#1117)

This commit is contained in:
Adam Janikowski 2022-09-21 11:51:26 +02:00 committed by GitHub
parent efdcd1bd2e
commit 76289415c6
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
8 changed files with 622 additions and 1 deletions

View file

@ -4,8 +4,8 @@
- (Feature) Add new field to DeploymentReplicationStatus with details on DC2DC sync status
- (Feature) Early connections support
- (Bugfix) Fix and document action timeouts
- (Feature) Propagate sidecars' ports to a member's service
- (Debug Package) Initial commit
## [1.2.16](https://github.com/arangodb/kube-arangodb/tree/1.2.16) (2022-09-14)
- (Feature) Add ArangoDeployment ServerGroupStatus

65
cmd/debug.go Normal file
View file

@ -0,0 +1,65 @@
//
// DISCLAIMER
//
// Copyright 2016-2022 ArangoDB GmbH, Cologne, Germany
//
// 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.
//
// Copyright holder is ArangoDB GmbH, Cologne, Germany
//
package cmd
import (
"compress/gzip"
"os"
"github.com/spf13/cobra"
"github.com/arangodb/kube-arangodb/pkg/debug_package"
)
func init() {
cmdMain.AddCommand(debugPackage)
debug_package.InitCommand(debugPackage)
}
var debugPackage = &cobra.Command{
Use: "debugPackage",
Short: "[WiP] Generate debug package for debugging",
RunE: debugPackageFunc,
}
func debugPackageFunc(cmd *cobra.Command, _ []string) error {
f, err := os.OpenFile("./out.tar.gz", os.O_TRUNC|os.O_WRONLY|os.O_CREATE, 0644)
if err != nil {
return err
}
gw := gzip.NewWriter(f)
if err := debug_package.GenerateD(cmd, gw); err != nil {
return err
}
if err := gw.Close(); err != nil {
return err
}
if err := f.Close(); err != nil {
return err
}
return nil
}

View file

@ -0,0 +1,155 @@
//
// DISCLAIMER
//
// Copyright 2016-2022 ArangoDB GmbH, Cologne, Germany
//
// 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.
//
// Copyright holder is ArangoDB GmbH, Cologne, Germany
//
package debug_package
import (
"archive/tar"
"bytes"
"io"
"time"
"github.com/spf13/cobra"
"github.com/arangodb/kube-arangodb/pkg/debug_package/generators/kubernetes"
"github.com/arangodb/kube-arangodb/pkg/debug_package/shared"
"github.com/arangodb/kube-arangodb/pkg/util/errors"
)
var rootFactories = []shared.Factory{
kubernetes.Events(),
kubernetes.Pods(),
kubernetes.Secrets(),
}
func InitCommand(cmd *cobra.Command) {
for _, f := range rootFactories {
f.Init(cmd)
}
}
func GenerateD(cmd *cobra.Command, out io.Writer) error {
return Generate(cmd, out, rootFactories...)
}
func Generate(cmd *cobra.Command, out io.Writer, factories ...shared.Factory) error {
tw := tar.NewWriter(out)
data := bytes.NewBuffer(nil)
log := NewLogger(data)
files := make(chan shared.File)
fileErrors := map[string]error{}
factoryErrors := map[string]error{}
done := make(chan struct{})
n := time.Now()
go func() {
defer close(done)
for file := range files {
log.Info().Msgf("Fetching file %s", file.Path())
data, err := file.Write()
if err != nil {
fileErrors[file.Path()] = err
continue
}
if err := tw.WriteHeader(&tar.Header{
Name: file.Path(),
ModTime: n,
AccessTime: n,
ChangeTime: n,
Mode: 0644,
Uid: 1000,
Gid: 1000,
Size: int64(len(data)),
}); err != nil {
fileErrors[file.Path()] = err
continue
}
if _, err := tw.Write(data); err != nil {
fileErrors[file.Path()] = err
continue
}
}
}()
for _, f := range factories {
log.Info().Msgf("Fetching factory %s", f.Name())
if err := f.Generate(cmd, log, files); err != nil {
factoryErrors[f.Name()] = err
}
}
close(files)
<-done
if len(fileErrors) > 0 {
log.Error().Msgf("%d errors while fetching files:", len(fileErrors))
parsedErrors := map[string]string{}
for f, n := range fileErrors {
parsedErrors[f] = n.Error()
log.Error().Msgf("\t%s: %s", f, n.Error())
}
}
if len(factoryErrors) > 0 {
log.Error().Msgf("%d errors while fetching factories:", len(factoryErrors))
for f, n := range factoryErrors {
log.Error().Msgf("\t%s: %s", f, n.Error())
}
}
if err := tw.WriteHeader(&tar.Header{
Name: "logs",
ModTime: n,
AccessTime: n,
ChangeTime: n,
Mode: 0644,
Uid: 1000,
Gid: 1000,
Size: int64(len(data.Bytes())),
}); err != nil {
return err
}
if _, err := io.Copy(tw, data); err != nil {
return err
}
if err := tw.Close(); err != nil {
return err
}
if len(fileErrors) > 0 || len(factoryErrors) > 0 {
return errors.Newf("Error while receiving data")
}
return nil
}

View file

@ -0,0 +1,84 @@
//
// DISCLAIMER
//
// Copyright 2016-2022 ArangoDB GmbH, Cologne, Germany
//
// 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.
//
// Copyright holder is ArangoDB GmbH, Cologne, Germany
//
package kubernetes
import (
"context"
"github.com/rs/zerolog"
"github.com/spf13/cobra"
eventsv1 "k8s.io/api/events/v1"
meta "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/types"
"github.com/arangodb/kube-arangodb/pkg/debug_package/shared"
"github.com/arangodb/kube-arangodb/pkg/util/errors"
"github.com/arangodb/kube-arangodb/pkg/util/kclient"
)
func Events() shared.Factory {
return shared.NewFactory("kubernetes-events", func(cmd *cobra.Command) {
f := cmd.Flags()
if f.Lookup("namespace") == nil {
f.String("namespace", "default", "Kubernetes namespace")
}
}, func(cmd *cobra.Command, logger zerolog.Logger, files chan<- shared.File) error {
k, ok := kclient.GetDefaultFactory().Client()
if !ok {
return errors.Newf("Client is not initialised")
}
ns, _ := cmd.Flags().GetString("namespace")
events := map[types.UID]*eventsv1.Event{}
next := ""
for {
r, err := k.Kubernetes().EventsV1().Events(ns).List(context.Background(), meta.ListOptions{
Continue: next,
})
if err != nil {
return err
}
for _, e := range r.Items {
events[e.UID] = e.DeepCopy()
}
next = r.Continue
if next == "" {
break
}
}
files <- shared.NewJSONFile("kubernetes/events.json", func() (interface{}, error) {
q := make([]*eventsv1.Event, 0, len(events))
for _, e := range events {
q = append(q, e)
}
return q, nil
})
return nil
})
}

View file

@ -0,0 +1,84 @@
//
// DISCLAIMER
//
// Copyright 2016-2022 ArangoDB GmbH, Cologne, Germany
//
// 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.
//
// Copyright holder is ArangoDB GmbH, Cologne, Germany
//
package kubernetes
import (
"context"
"github.com/rs/zerolog"
"github.com/spf13/cobra"
core "k8s.io/api/core/v1"
meta "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/types"
"github.com/arangodb/kube-arangodb/pkg/debug_package/shared"
"github.com/arangodb/kube-arangodb/pkg/util/errors"
"github.com/arangodb/kube-arangodb/pkg/util/kclient"
)
func Pods() shared.Factory {
return shared.NewFactory("kubernetes-pods", func(cmd *cobra.Command) {
f := cmd.Flags()
if f.Lookup("namespace") == nil {
f.String("namespace", "default", "Kubernetes namespace")
}
}, func(cmd *cobra.Command, logger zerolog.Logger, files chan<- shared.File) error {
k, ok := kclient.GetDefaultFactory().Client()
if !ok {
return errors.Newf("Client is not initialised")
}
ns, _ := cmd.Flags().GetString("namespace")
pods := map[types.UID]*core.Pod{}
next := ""
for {
r, err := k.Kubernetes().CoreV1().Pods(ns).List(context.Background(), meta.ListOptions{
Continue: next,
})
if err != nil {
return err
}
for _, e := range r.Items {
pods[e.UID] = e.DeepCopy()
}
next = r.Continue
if next == "" {
break
}
}
files <- shared.NewJSONFile("kubernetes/pods.json", func() (interface{}, error) {
q := make([]*core.Pod, 0, len(pods))
for _, e := range pods {
q = append(q, e)
}
return q, nil
})
return nil
})
}

View file

@ -0,0 +1,100 @@
//
// DISCLAIMER
//
// Copyright 2016-2022 ArangoDB GmbH, Cologne, Germany
//
// 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.
//
// Copyright holder is ArangoDB GmbH, Cologne, Germany
//
package kubernetes
import (
"context"
"crypto/sha256"
"fmt"
"github.com/rs/zerolog"
"github.com/spf13/cobra"
core "k8s.io/api/core/v1"
meta "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/types"
"github.com/arangodb/kube-arangodb/pkg/debug_package/shared"
"github.com/arangodb/kube-arangodb/pkg/util/errors"
"github.com/arangodb/kube-arangodb/pkg/util/kclient"
)
func Secrets() shared.Factory {
return shared.NewFactory("kubernetes-secrets", func(cmd *cobra.Command) {
f := cmd.Flags()
if f.Lookup("namespace") == nil {
f.String("namespace", "default", "Kubernetes namespace")
}
if f.Lookup("hide-sensitive-data") == nil {
f.Bool("hide-sensitive-data", true, "Hide sensitive data")
}
}, func(cmd *cobra.Command, logger zerolog.Logger, files chan<- shared.File) error {
k, ok := kclient.GetDefaultFactory().Client()
if !ok {
return errors.Newf("Client is not initialised")
}
ns, _ := cmd.Flags().GetString("namespace")
secrets := map[types.UID]*core.Secret{}
next := ""
for {
r, err := k.Kubernetes().CoreV1().Secrets(ns).List(context.Background(), meta.ListOptions{
Continue: next,
})
if err != nil {
return err
}
sensitive, _ := cmd.Flags().GetBool("hide-sensitive-data")
for _, e := range r.Items {
hashed := make(map[string][]byte, len(e.Data))
for k, v := range e.Data {
if sensitive {
hashed[k] = []byte(fmt.Sprintf("%02x", sha256.Sum256(v)))
} else {
hashed[k] = v
}
}
secrets[e.UID] = e.DeepCopy()
secrets[e.UID].Data = hashed
}
next = r.Continue
if next == "" {
break
}
}
files <- shared.NewJSONFile("kubernetes/secrets.json", func() (interface{}, error) {
q := make([]*core.Secret, 0, len(secrets))
for _, e := range secrets {
q = append(q, e)
}
return q, nil
})
return nil
})
}

33
pkg/debug_package/out.go Normal file
View file

@ -0,0 +1,33 @@
//
// DISCLAIMER
//
// Copyright 2016-2022 ArangoDB GmbH, Cologne, Germany
//
// 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.
//
// Copyright holder is ArangoDB GmbH, Cologne, Germany
//
package debug_package
import (
"io"
"os"
"time"
"github.com/rs/zerolog"
)
func NewLogger(out io.Writer) zerolog.Logger {
return zerolog.New(zerolog.ConsoleWriter{Out: io.MultiWriter(out, os.Stdout), TimeFormat: time.RFC3339}).With().Timestamp().Logger()
}

View file

@ -0,0 +1,100 @@
//
// DISCLAIMER
//
// Copyright 2016-2022 ArangoDB GmbH, Cologne, Germany
//
// 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.
//
// Copyright holder is ArangoDB GmbH, Cologne, Germany
//
package shared
import (
"github.com/rs/zerolog"
"github.com/spf13/cobra"
"k8s.io/apimachinery/pkg/util/json"
)
type GenFunc func(cmd *cobra.Command, logger zerolog.Logger, files chan<- File) error
type File interface {
Path() string
Write() ([]byte, error)
}
func NewJSONFile(path string, write func() (interface{}, error)) File {
return NewFile(path, func() ([]byte, error) {
obj, err := write()
if err != nil {
return nil, err
}
return json.Marshal(obj)
})
}
func NewFile(path string, write func() ([]byte, error)) File {
return file{
name: path,
write: write,
}
}
type file struct {
name string
write func() ([]byte, error)
}
func (f file) Path() string {
return f.name
}
func (f file) Write() ([]byte, error) {
return f.write()
}
type Factory interface {
Name() string
Generate(cmd *cobra.Command, logger zerolog.Logger, files chan<- File) error
Init(command *cobra.Command)
}
func NewFactory(name string, cmd func(cmd *cobra.Command), gen GenFunc) Factory {
return factory{
name: name,
generate: gen,
cmd: cmd,
}
}
type factory struct {
name string
generate GenFunc
cmd func(cmd *cobra.Command)
}
func (f factory) Init(command *cobra.Command) {
if c := f.cmd; c != nil {
c(command)
}
}
func (f factory) Name() string {
return f.name
}
func (f factory) Generate(cmd *cobra.Command, logger zerolog.Logger, files chan<- File) error {
return f.generate(cmd, logger, files)
}