diff --git a/cmd/diag/command/aduit.go b/cmd/diag/command/aduit.go index 97bb2ea3..a35a47c1 100644 --- a/cmd/diag/command/aduit.go +++ b/cmd/diag/command/aduit.go @@ -20,7 +20,7 @@ import ( "github.com/spf13/cobra" ) -// retainDays number of days to keep audit logs for deletion +// retainDays number of days to keep audit logs for deletion var retainDays int func newAuditCmd() *cobra.Command { diff --git a/cmd/diag/command/root.go b/cmd/diag/command/root.go index eee3be30..65675031 100644 --- a/cmd/diag/command/root.go +++ b/cmd/diag/command/root.go @@ -31,11 +31,9 @@ import ( operator "github.com/pingcap/tiup/pkg/cluster/operation" "github.com/pingcap/tiup/pkg/cluster/spec" "github.com/pingcap/tiup/pkg/environment" - tiupmeta "github.com/pingcap/tiup/pkg/environment" "github.com/pingcap/tiup/pkg/localdata" "github.com/pingcap/tiup/pkg/logger" logprinter "github.com/pingcap/tiup/pkg/logger/printer" - "github.com/pingcap/tiup/pkg/repository" tiuptelemetry "github.com/pingcap/tiup/pkg/telemetry" "github.com/pingcap/tiup/pkg/tui" "github.com/pingcap/tiup/pkg/utils" @@ -92,7 +90,7 @@ func init() { log.SetDisplayModeFromString(gOpt.DisplayMode) var err error - var env *tiupmeta.Environment + // var env *tiupmeta.Environment // unset component data dir to use clusters' os.Unsetenv(localdata.EnvNameComponentDataDir) if err = spec.Initialize("diag"); err != nil { @@ -100,12 +98,12 @@ func init() { } // Running in other OS/ARCH Should be fine we only download manifest file. - env, err = tiupmeta.InitEnv(repository.Options{}, repository.MirrorOptions{}) + /*env, err = tiupmeta.InitEnv(repository.Options{}, repository.MirrorOptions{}) if err != nil { return err } tiupmeta.SetGlobalEnv(env) - + */ logger.EnableAuditLog(spec.AuditDir()) teleCommand = getParentNames(cmd) @@ -120,7 +118,8 @@ func init() { return nil }, PersistentPostRunE: func(cmd *cobra.Command, args []string) error { - return tiupmeta.GlobalEnv().V1Repository().Mirror().Close() + // return tiupmeta.GlobalEnv().V1Repository().Mirror().Close() + return nil }, } @@ -140,8 +139,8 @@ func init() { _ = rootCmd.PersistentFlags().MarkHidden("native-ssh") rootCmd.AddCommand( - newCollectCmd(), - newCollectDMCmd(), + //newCollectCmd(), + //newCollectDMCmd(), newPackageCmd(), newRebuildCmd(), newUploadCommand(), diff --git a/cmd/diag/command/util.go b/cmd/diag/command/util.go index 97a4dafe..c0caaa01 100644 --- a/cmd/diag/command/util.go +++ b/cmd/diag/command/util.go @@ -33,6 +33,7 @@ func newUtilCmd() *cobra.Command { utilCmd.AddCommand( newMetricDumpCmd(), newPlanReplayerCmd(), + newkubeDumpCmd(), ) return utilCmd diff --git a/cmd/diag/command/util_kubedump.go b/cmd/diag/command/util_kubedump.go new file mode 100644 index 00000000..28793fc6 --- /dev/null +++ b/cmd/diag/command/util_kubedump.go @@ -0,0 +1,184 @@ +// Copyright 2022 PingCAP, Inc. +// +// 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, +// See the License for the specific language governing permissions and +// limitations under the License. + +package command + +import ( + "context" + "encoding/json" + "fmt" + "os" + "strings" + "time" + + "github.com/pingcap/diag/collector" + "github.com/pingcap/tidb-operator/pkg/apis/label" + pingcapv1alpha1 "github.com/pingcap/tidb-operator/pkg/apis/pingcap/v1alpha1" + "github.com/spf13/cobra" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime/schema" + "k8s.io/client-go/dynamic" + "k8s.io/client-go/kubernetes" + "k8s.io/client-go/rest" + "k8s.io/client-go/tools/clientcmd" + "k8s.io/klog" +) + +func newkubeDumpCmd() *cobra.Command { + opt := collector.BaseOptions{} + cOpt := collector.CollectOptions{} + cOpt.Collectors, _ = collector.ParseCollectTree([]string{collector.CollectTypeMonitor}, nil) + var ( + clsName string + clsID string + caPath string + certPath string + keyPath string + ) + + cmd := &cobra.Command{ + Use: "kubedump", + Short: "Dump TSDB files from a Prometheus pod.", + RunE: func(cmd *cobra.Command, args []string) error { + log.SetDisplayModeFromString(gOpt.DisplayMode) + + cfg, err := clientcmd.BuildConfigFromFlags("", opt.Kubeconfig) + if err != nil { + return err + } + clsID, cOpt.PodName, err = bbuildTopoForK8sCluster(clsName, opt.Namespace, cfg) + if err != nil { + return err + } + + cm := collector.NewManager("tidb", nil, log) + + cOpt.Collectors, _ = collector.ParseCollectTree([]string{"monitor.metric"}, nil) + opt.Cluster = clsName + cOpt.RawMonitor = true + cOpt.RawRequest = strings.Join(os.Args[1:], " ") + cOpt.Mode = collector.CollectModeManual // set collect mode + cOpt.ExtendedAttrs = make(map[string]string) // init attributes map + cOpt.ExtendedAttrs[collector.AttrKeyClusterID] = clsID + cOpt.ExtendedAttrs[collector.AttrKeyTLSCAFile] = caPath + cOpt.ExtendedAttrs[collector.AttrKeyTLSCertFile] = certPath + cOpt.ExtendedAttrs[collector.AttrKeyTLSKeyFile] = keyPath + + _, err = cm.CollectClusterInfo(&opt, &cOpt, &gOpt, nil, nil, skipConfirm) + + return err + }, + } + + cmd.Flags().StringVar(&opt.Kubeconfig, "kubeconfig", "", "path of kubeconfig") + cmd.Flags().StringVar(&clsName, "name", "", "name of the TiDB cluster") + //cmd.Flags().StringVar(&clsID, "cluster-id", "", "ID of the TiDB cluster") + cmd.Flags().StringVar(&opt.Namespace, "namespace", "", "namespace of prometheus") + //cmd.Flags().StringVar(&cOpt.PodName, "pod", "", "pod name of prometheus") + //cmd.Flags().StringVar(&cOpt.ContainerName, "container", "", "container name of prometheus") + // cmd.Flags().StringVar(&caPath, "ca-file", "", "path to the CA of TLS enabled cluster") + // cmd.Flags().StringVar(&certPath, "cert-file", "", "path to the client certification of TLS enabled cluster") + // cmd.Flags().StringVar(&keyPath, "key-file", "", "path to the private key of client certification of TLS enabled cluster") + cmd.Flags().StringVarP(&opt.ScrapeBegin, "from", "f", time.Now().Add(time.Hour*-2).Format(time.RFC3339), "start timepoint when collecting timeseries data") + cmd.Flags().StringVarP(&opt.ScrapeEnd, "to", "t", time.Now().Format(time.RFC3339), "stop timepoint when collecting timeseries data") + cmd.Flags().StringVarP(&cOpt.Dir, "output", "o", "", "output directory of collected data") + + cobra.MarkFlagRequired(cmd.Flags(), "kubeconfig") + cobra.MarkFlagRequired(cmd.Flags(), "name") + // cobra.MarkFlagRequired(cmd.Flags(), "cluster-id") + cobra.MarkFlagRequired(cmd.Flags(), "namespace") + // cobra.MarkFlagRequired(cmd.Flags(), "pod") + // cobra.MarkFlagRequired(cmd.Flags(), "container") + + return cmd +} + +// buildTopoForK8sCluster creates an abstract topo from tiup-cluster metadata +func bbuildTopoForK8sCluster( + clusterName string, + namespace string, + cfg *rest.Config, +) (clusterID, + podName string, + err error) { + kubeCli, err := kubernetes.NewForConfig(cfg) + if err != nil { + return "", "", fmt.Errorf("failed to get kubernetes Clientset: %v", err) + } + dynCli, err := dynamic.NewForConfig(cfg) + if err != nil { + return "", "", fmt.Errorf("failed to get kubernetes dynamic client interface: %v", err) + } + + gvrMonitor := schema.GroupVersionResource{ + Group: "pingcap.com", + Version: "v1alpha1", + Resource: "tidbmonitors", + } + + monList, err := dynCli.Resource(gvrMonitor).Namespace(namespace).List(context.TODO(), metav1.ListOptions{}) + if err != nil { + msg := fmt.Sprintf("failed to list tidbmonitors in namespace %s: %v", namespace, err) + klog.Errorf(msg) + return + } + monData, err := monList.MarshalJSON() + if err != nil { + msg := fmt.Sprintf("failed to marshal tidbmonitors to json: %v", err) + klog.Errorf(msg) + return + } + var mon pingcapv1alpha1.TidbMonitorList + if err := json.Unmarshal(monData, &mon); err != nil { + return "", "", err + } + if len(mon.Items) == 0 { + return "", "", fmt.Errorf("no tidbmonitors found in namespace '%s'", namespace) + } + + // find monitor pod + var matchedMon pingcapv1alpha1.TidbMonitor + monMatched := false + for _, m := range mon.Items { + for _, clsRef := range m.Spec.Clusters { + if clsRef.Name == clusterName { + monMatched = true + break + } + } + matchedMon = m + break + } + + // get monitor pod + if monMatched { + labels := &metav1.LabelSelector{ + MatchLabels: map[string]string{ + label.ManagedByLabelKey: "tidb-operator", + label.NameLabelKey: "tidb-cluster", + label.ComponentLabelKey: "monitor", + label.InstanceLabelKey: matchedMon.Name, + }, + } + selector, err := metav1.LabelSelectorAsSelector(labels) + if err != nil { + return "", "", err + } + pods, err := kubeCli.CoreV1().Pods(namespace).List(context.TODO(), metav1.ListOptions{ + LabelSelector: selector.String(), + }) + return pods.Items[0].Labels[label.ClusterIDLabelKey], pods.Items[0].Name, nil + } + + return "", "", fmt.Errorf("cannot found monitor pod") +} diff --git a/collector/collect.go b/collector/collect.go index e6b5ca93..a3ca3f49 100644 --- a/collector/collect.go +++ b/collector/collect.go @@ -95,6 +95,7 @@ type BaseOptions struct { Cluster string // cluster name Namespace string // k8s namespace of the cluster MonitorNamespace string // k8s namespace of the monitor + Kubeconfig string // path of kubeconfig User string // username to login to the SSH server UsePassword bool // use password instead of identity file for ssh connection SSH *tui.SSHConnectionProps // SSH credentials @@ -122,6 +123,8 @@ type CollectOptions struct { ExplainSQLPath string // File path for explain sql ExplainSqls []string // explain sqls CurrDB string + PodName string + ContainerName string } // CollectStat is estimated size stats of data to be collected @@ -296,6 +299,7 @@ func (m *Manager) CollectClusterInfo( fileStats: make(map[string][]CollectStat), limit: cOpt.Limit, compress: cOpt.CompressScp, + pod: cOpt.PodName, }, ) } diff --git a/collector/prometheus.go b/collector/prometheus.go index e1eba0c4..74589b0d 100644 --- a/collector/prometheus.go +++ b/collector/prometheus.go @@ -14,6 +14,8 @@ package collector import ( + "archive/tar" + "bytes" "context" "fmt" "io" @@ -32,6 +34,7 @@ import ( "github.com/klauspost/compress/zstd" "github.com/pingcap/diag/pkg/models" "github.com/pingcap/diag/pkg/utils" + "github.com/pingcap/diag/scraper" perrs "github.com/pingcap/errors" "github.com/pingcap/tiup/pkg/cluster/ctxt" operator "github.com/pingcap/tiup/pkg/cluster/operation" @@ -41,6 +44,8 @@ import ( "github.com/pingcap/tiup/pkg/set" "github.com/pingcap/tiup/pkg/tui/progress" tiuputils "github.com/pingcap/tiup/pkg/utils" + k8sutils "github.com/qiffang/k8sutils/pkg/exec" + "k8s.io/client-go/tools/clientcmd" ) const ( @@ -523,6 +528,8 @@ type TSDBCollectOptions struct { fileStats map[string][]CollectStat compress bool limit int + fCli *k8sutils.Client + pod string } // Desc implements the Collector interface @@ -553,7 +560,7 @@ func (c *TSDBCollectOptions) SetDir(dir string) { // Prepare implements the Collector interface func (c *TSDBCollectOptions) Prepare(m *Manager, cls *models.TiDBCluster) (map[string][]CollectStat, error) { if m.mode != CollectModeTiUP { - return nil, nil + return c.kubePrepare(m, cls) } if len(cls.Monitors) < 1 { if m.logger.GetDisplayMode() == logprinter.DisplayModeDefault { @@ -684,7 +691,7 @@ func (c *TSDBCollectOptions) Prepare(m *Manager, cls *models.TiDBCluster) (map[s // Collect implements the Collector interface func (c *TSDBCollectOptions) Collect(m *Manager, cls *models.TiDBCluster) error { if m.mode != CollectModeTiUP { - return nil + return c.kubeCollect(m, cls) } topo := cls.Attributes[CollectModeTiUP].(spec.Topology) @@ -766,3 +773,126 @@ func (c *TSDBCollectOptions) Collect(m *Manager, cls *models.TiDBCluster) error return nil } + +func (c *TSDBCollectOptions) kubePrepare(m *Manager, cls *models.TiDBCluster) (map[string][]CollectStat, error) { + cfg, err := clientcmd.BuildConfigFromFlags("", c.BaseOptions.Kubeconfig) + if err != nil { + return nil, err + } + c.fCli, err = k8sutils.NewClient(&k8sutils.ClientOpt{ + K8sConfig: cfg, + Namespace: c.Namespace, + PodName: c.pod, + ContainerName: "prometheus", + }) + if err != nil { + return nil, err + } + + datadir := "/data/prometheus" + + err = c.fCli.CanExec() + if err != nil { + fmt.Print(err) + return nil, err + } + + binpath, err := os.Executable() + if err != nil { + return nil, err + } + scraperPath := path.Join(path.Dir(binpath), "scraper") + + // todo: copy scraper to pod + cpCommand := []string{"tar", "--no-same-permissions", "--no-same-owner", "-xmf", "-", "-C", "/tmp"} + + reader, writer := io.Pipe() + defer reader.Close() + + go func() { + tarW := tar.NewWriter(writer) + defer tarW.Close() + fi, err := os.Stat(scraperPath) + if err != nil { + return + } + header, _ := tar.FileInfoHeader(fi, "") + + err = tarW.WriteHeader(header) + if err != nil { + return + } + + fd, err := os.Open(scraperPath) + if err != nil { + return + } + defer fd.Close() + + _, err = io.Copy(tarW, fd) + if err != nil { + return + } + + tarW.Close() + writer.Close() + }() + + err = c.fCli.ExecPod(cpCommand, reader, nil, nil, false, 40*(time.Second)) + if err != nil { + println(err) + } + + out := &bytes.Buffer{} + scraperCommand := []string{"/tmp/scraper", "--prometheus", datadir, "-f", c.ScrapeBegin, "-t", c.ScrapeEnd} + err = c.fCli.ExecPod(scraperCommand, nil, out, nil, false, 40*(time.Second)) + if err != nil { + println(err) + } + + stats, err := parseScraperTSDB(out.Bytes()) + if err != nil { + return nil, err + } + c.fileStats[c.pod] = stats + + return c.fileStats, nil +} + +func (c *TSDBCollectOptions) kubeCollect(m *Manager, cls *models.TiDBCluster) error { + for _, f := range c.fileStats[c.pod] { + downloadCommand := []string{"tar", "cf", "-", "-C", f.Target, "."} + r, w := io.Pipe() + go func() { + utils.Untar(r, filepath.Join(c.resultDir, subdirMonitor, subdirRaw, c.pod, filepath.Base(f.Target))) + }() + err := c.fCli.ExecPod(downloadCommand, nil, w, nil, false, 400*(time.Second)) + w.Close() + if err != nil { + println(err) + } + } + + // f.Target, + // filepath.Join(c.resultDir, subdirMonitor, subdirRaw, fmt.Sprintf("%s-%d", inst.GetHost(), inst.GetMainPort()), filepath.Base(f.Target)), + + return nil +} + +func parseScraperTSDB(stdout []byte) ([]CollectStat, error) { + var s scraper.Sample + if err := json.Unmarshal(stdout, &s); err != nil { + // save output directly on parsing errors + return nil, fmt.Errorf("error parsing scraped stats: %s", stdout) + } + + stats := make([]CollectStat, 0) + for k, v := range s.TSDB { + stats = append(stats, CollectStat{ + Target: k, + Size: v, + }) + } + + return stats, nil +} diff --git a/go.mod b/go.mod index e8606da5..9c3de58a 100644 --- a/go.mod +++ b/go.mod @@ -44,6 +44,7 @@ require ( github.com/pkg/errors v0.9.1 github.com/prometheus/common v0.39.0 github.com/prometheus/prom2json v1.3.2 // indirect + github.com/qiffang/k8sutils v0.0.0-20230303100957-2c68696ecd73 github.com/rivo/uniseg v0.4.3 // indirect github.com/sergi/go-diff v1.3.1 // indirect github.com/shirou/gopsutil v3.21.11+incompatible diff --git a/go.sum b/go.sum index de610b36..82141fe2 100644 --- a/go.sum +++ b/go.sum @@ -412,11 +412,13 @@ github.com/Azure/go-autorest v14.2.0+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSW github.com/Azure/go-autorest/autorest v0.9.0/go.mod h1:xyHB1BMZT0cuDHU7I0+g046+BFDTQ8rEZB0s4Yfa6bI= github.com/Azure/go-autorest/autorest v0.9.6/go.mod h1:/FALq9T/kS7b5J5qsQ+RSTUdAmGFqi0vUdVNNx8q630= github.com/Azure/go-autorest/autorest v0.10.0/go.mod h1:/FALq9T/kS7b5J5qsQ+RSTUdAmGFqi0vUdVNNx8q630= +github.com/Azure/go-autorest/autorest v0.11.1/go.mod h1:JFgpikqFJ/MleTTxwepExTKnFUKKszPS8UavbQYUMuw= github.com/Azure/go-autorest/autorest v0.11.9/go.mod h1:eipySxLmqSyC5s5k1CLupqet0PSENBEDP93LQ9a8QYw= github.com/Azure/go-autorest/autorest v0.11.18/go.mod h1:dSiJPy22c3u0OtOKDNttNgqpNFY/GeWa7GH/Pz56QRA= github.com/Azure/go-autorest/autorest/adal v0.5.0/go.mod h1:8Z9fGy2MpX0PvDjB1pEgQTmVqjGhiHBW7RJJEciWzS0= github.com/Azure/go-autorest/autorest/adal v0.8.2/go.mod h1:ZjhuQClTqx435SRJ2iMlOxPYt3d2C/T/7TiQCVZSn3Q= github.com/Azure/go-autorest/autorest/adal v0.8.3/go.mod h1:ZjhuQClTqx435SRJ2iMlOxPYt3d2C/T/7TiQCVZSn3Q= +github.com/Azure/go-autorest/autorest/adal v0.9.0/go.mod h1:/c022QCutn2P7uY+/oQWWNcK9YU+MH96NgK+jErpbcg= github.com/Azure/go-autorest/autorest/adal v0.9.5/go.mod h1:B7KF7jKIeC9Mct5spmyCB/A8CG/sEz1vwIRGv/bbw7A= github.com/Azure/go-autorest/autorest/adal v0.9.13/go.mod h1:W/MM4U6nLxnIskrw4UwWzlHfGjwUS50aOsc/I3yuU8M= github.com/Azure/go-autorest/autorest/azure/auth v0.5.3/go.mod h1:4bJZhUhcq8LB20TruwHbAQsmUs2Xh+QR7utuJpLXX3A= @@ -427,6 +429,7 @@ github.com/Azure/go-autorest/autorest/date v0.3.0/go.mod h1:BI0uouVdmngYNUzGWeSY github.com/Azure/go-autorest/autorest/mocks v0.1.0/go.mod h1:OTyCOPRA2IgIlWxVYxBee2F5Gr4kF2zd2J5cFRaIDN0= github.com/Azure/go-autorest/autorest/mocks v0.2.0/go.mod h1:OTyCOPRA2IgIlWxVYxBee2F5Gr4kF2zd2J5cFRaIDN0= github.com/Azure/go-autorest/autorest/mocks v0.3.0/go.mod h1:a8FDP3DYzQ4RYfVAxAN3SVSiiO77gL2j2ronKKP0syM= +github.com/Azure/go-autorest/autorest/mocks v0.4.0/go.mod h1:LTp+uSrOhSkaKrUy935gNZuuIPPVsHlr9DSOxSayd+k= github.com/Azure/go-autorest/autorest/mocks v0.4.1/go.mod h1:LTp+uSrOhSkaKrUy935gNZuuIPPVsHlr9DSOxSayd+k= github.com/Azure/go-autorest/autorest/to v0.3.0/go.mod h1:MgwOyqaIuKdG4TL/2ywSsIWKAfJfgHDo8ObuUk3t5sA= github.com/Azure/go-autorest/autorest/validation v0.2.0/go.mod h1:3EEqHnBxQGHXRYq3HT1WyXAvT7LLY3tl70hw6tQIbjI= @@ -692,6 +695,7 @@ github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFP github.com/eclipse/paho.mqtt.golang v1.2.0/go.mod h1:H9keYFcgq3Qr5OUJm/JZI/i6U7joQ8SYLhZwfeOo6Ts= github.com/edsrzf/mmap-go v1.0.0/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M= github.com/elazarl/goproxy v0.0.0-20170405201442-c4fc26588b6e/go.mod h1:/Zj4wYkgs4iZTTu3o/KG3Itv/qCCa8VVMlb3i9OVuzc= +github.com/elazarl/goproxy v0.0.0-20180725130230-947c36da3153 h1:yUdfgN0XgIJw7foRItutHYUIhlcKzcSf5vDpdhQAKTc= github.com/elazarl/goproxy v0.0.0-20180725130230-947c36da3153/go.mod h1:/Zj4wYkgs4iZTTu3o/KG3Itv/qCCa8VVMlb3i9OVuzc= github.com/emicklei/go-restful v0.0.0-20170410110728-ff4f55a20633/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs= github.com/emicklei/go-restful v2.9.5+incompatible h1:spTtZBk5DYEvbxMVutUuTyh1Ao2r4iyvLdACqsl/Ljk= @@ -1226,6 +1230,7 @@ github.com/lensesio/tableprinter v0.0.0-20201125135848-89e81fc956e7/go.mod h1:YR github.com/leodido/go-urn v1.2.1 h1:BqpAaACuzVSgi/VLzGZIobT2z4v53pjosyNd9Yv6n/w= github.com/leodido/go-urn v1.2.1/go.mod h1:zt4jvISO2HfUBqxjfIshjdMTYS56ZS/qv49ictyFfxY= github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= +github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de/go.mod h1:zAbeS9B/r2mtpb6U+EI2rYA5OAXxsYw6wTamcNW+zcE= github.com/lightstep/lightstep-tracer-common/golang/gogo v0.0.0-20190605223551-bc2310a04743/go.mod h1:qklhhLq1aX+mtWk9cPHPzaBjWImj5ULL6C7HFJtXQMM= github.com/lightstep/lightstep-tracer-go v0.18.1/go.mod h1:jlF1pusYV4pidLvZ+XD0UBX0ZE6WURAspgAczcDHrL4= github.com/lorenzosaino/go-sysctl v0.3.1 h1:3phX80tdITw2fJjZlwbXQnDWs4S30beNcMbw0cn0HtY= @@ -1305,6 +1310,7 @@ github.com/mitchellh/mapstructure v1.2.2/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RR github.com/mitchellh/mapstructure v1.3.3/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/mitchellh/mapstructure v1.4.3 h1:OVowDSCllw/YjdLkam3/sm7wEtOy59d8ndGgCcyj8cs= github.com/mitchellh/mapstructure v1.4.3/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/moby/spdystream v0.2.0 h1:cjW1zVyyoiM0T7b6UoySUFqzXMoqRckQtXwGPiBhOM8= github.com/moby/spdystream v0.2.0/go.mod h1:f7i0iNDQJ059oMTcWxx8MA/zKFIuD/lY+0GqbN2Wy8c= github.com/moby/term v0.0.0-20200312100748-672ec06f55cd/go.mod h1:DdlQx2hp0Ss5/fLikoLlEeIYiATotOjgB//nb973jeo= github.com/moby/term v0.0.0-20210610120745-9d4ed1856297/go.mod h1:vgPCkQMyxTZ7IDy8SXRufE172gr8+K/JE/7hHFxHW3A= @@ -1519,6 +1525,12 @@ github.com/prometheus/prometheus v0.0.0-20200609090129-a6600f564e3c/go.mod h1:S5 github.com/prometheus/prometheus v1.8.2 h1:PAL466mnJw1VolZPm1OarpdUpqukUy/eX4tagia17DM= github.com/prometheus/prometheus v1.8.2/go.mod h1:oAIUtOny2rjMX0OWN5vPR5/q/twIROJvdqnQKDdil/s= github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU= +github.com/qiffang/k8sutils v0.0.0-20230303063426-efef1899ca94 h1:yYhOLzQwaQJjT5wT/pIT1eMeTEUTBcFzsAArWzVSakM= +github.com/qiffang/k8sutils v0.0.0-20230303063426-efef1899ca94/go.mod h1:H8JW60xOKMrPYgE27uCwm01ePkDuuSJwEldcJYQ3rpk= +github.com/qiffang/k8sutils v0.0.0-20230303084506-1495c3a85102 h1:uetKduKSxxcWyggZk0DnQucCMv/tJ7SYNpj47yMuIBE= +github.com/qiffang/k8sutils v0.0.0-20230303084506-1495c3a85102/go.mod h1:H8JW60xOKMrPYgE27uCwm01ePkDuuSJwEldcJYQ3rpk= +github.com/qiffang/k8sutils v0.0.0-20230303100957-2c68696ecd73 h1:JHnnsruNupduvqSpkfHvyHdciLlqObDV0blGruPwqpo= +github.com/qiffang/k8sutils v0.0.0-20230303100957-2c68696ecd73/go.mod h1:iRDqtlk7p7OjLU0yuQoFNS8AWbbHGqAJDtEvhXQmDYU= github.com/r3labs/diff/v2 v2.15.1 h1:EOrVqPUzi+njlumoqJwiS/TgGgmZo83619FNDB9xQUg= github.com/r3labs/diff/v2 v2.15.1/go.mod h1:I8noH9Fc2fjSaMxqF3G2lhDdC0b+JXCfyx85tWFM9kc= github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= @@ -1593,6 +1605,7 @@ github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkU github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU= github.com/spf13/cobra v1.0.0/go.mod h1:/6GTrnGXV9HjY+aR4k0oJ5tcvakLuG6EuKReYlHNrgE= +github.com/spf13/cobra v1.1.1/go.mod h1:WnodtKOvamDL/PwE2M4iKs8aMDBZ5Q5klgD3qfVJQMI= github.com/spf13/cobra v1.1.3/go.mod h1:pGADOWyqRD/YMrPZigI/zbliZ2wVD/23d+is3pSWzOo= github.com/spf13/cobra v1.5.0/go.mod h1:dWXEIy2H428czQCjInthrTRUg7yKbok+2Qi/yBIJoUM= github.com/spf13/cobra v1.6.1 h1:o94oiPyS4KD1mPy2fmcYYHHfCxLqYjJOhGsCHFZtEzA= @@ -1824,6 +1837,7 @@ golang.org/x/crypto v0.0.0-20211108221036-ceb1ce70b4fa/go.mod h1:GvvjBRRGRdwPK5y golang.org/x/crypto v0.0.0-20211117183948-ae814b36b871/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.0.0-20220331220935-ae2d96664a29/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= +golang.org/x/crypto v0.0.0-20220525230936-793ad666bf5e/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.0.0-20220829220503-c86fa9a7ed90/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.1.0/go.mod h1:RecgLatLF4+eUMCP1PoPZQb+cVrJcOPbHkTkbkB9sbw= @@ -2205,6 +2219,7 @@ golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxb golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20200416051211-89c76fbcd5d1/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20200630173020-3af7569d3a1e/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20201208040808-7e3f01d25324/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= @@ -2635,6 +2650,7 @@ honnef.co/go/tools v0.3.2 h1:ytYb4rOqyp1TSa2EPvNVwtPQJctSELKaMyLfqNP4+34= honnef.co/go/tools v0.3.2/go.mod h1:jzwdWgg7Jdq75wlfblQxO4neNaFFSvgc1tD5Wv8U0Yw= k8s.io/api v0.17.5/go.mod h1:0zV5/ungglgy2Rlm3QK8fbxkXVs+BSJWpJP/+8gUVLY= k8s.io/api v0.19.16/go.mod h1:Vz9ZfXbI/35CtXGfM4mUDPuTQw7dLeZY31EO0OohMSQ= +k8s.io/api v0.20.5/go.mod h1:FQjAceXnVaWDeov2YUWhOb6Yt+5UjErkp6UO3nczO1Y= k8s.io/api v0.22.4 h1:UvyHW0ezB2oIgHAxlYoo6UJQObYXU7awuNarwoHEOjw= k8s.io/api v0.22.4/go.mod h1:Rgs+9gIGYC5laXQSZZ9JqT5NevNgoGiOdVWi1BAB3qk= k8s.io/apiextensions-apiserver v0.19.16/go.mod h1:ANwivpVIPO7hqIJa1CexpWyfix6opRvJzl3B/ayzc7E= @@ -2642,12 +2658,15 @@ k8s.io/apiextensions-apiserver v0.22.4 h1:2iGpcVyw4MnAyyXVJU2Xg6ZsbIxAOfRHo0LF5A k8s.io/apiextensions-apiserver v0.22.4/go.mod h1:kH9lxD8dbJ+k0ZizGET55lFgdGjO8t45fgZnCVdZEpw= k8s.io/apimachinery v0.17.5/go.mod h1:ioIo1G/a+uONV7Tv+ZmCbMG1/a3kVw5YcDdncd8ugQ0= k8s.io/apimachinery v0.19.16/go.mod h1:RMyblyny2ZcDQ/oVE+lC31u7XTHUaSXEK2IhgtwGxfc= +k8s.io/apimachinery v0.20.5/go.mod h1:WlLqWAHZGg07AeltaI0MV5uk1Omp8xaN0JGLY6gkRpU= k8s.io/apimachinery v0.22.4 h1:9uwcvPpukBw/Ri0EUmWz+49cnFtaoiyEhQTK+xOe7Ck= k8s.io/apimachinery v0.22.4/go.mod h1:yU6oA6Gnax9RrxGzVvPFFJ+mpnW6PBSqp0sx0I0HHW0= k8s.io/apiserver v0.19.16/go.mod h1:9NCHA3a+/b2rLeRkVOOaTBfmfu1Z9vWuH6usDK7EKWw= k8s.io/apiserver v0.22.4/go.mod h1:38WmcUZiiy41A7Aty8/VorWRa8vDGqoUzDf2XYlku0E= +k8s.io/cli-runtime v0.20.5/go.mod h1:ihjPeQWDk7NGVIkNEvpwxA3gJvqtU+LtkDj11TvyXn4= k8s.io/client-go v0.17.5/go.mod h1:S8uZpBpjJJdEH/fEyxcqg7Rn0P5jH+ilkgBHjriSmNo= k8s.io/client-go v0.19.16/go.mod h1:aEi/M7URDBWUIzdFt/l/WkngaqCTYtDo0cIMIQgvXmI= +k8s.io/client-go v0.20.5/go.mod h1:Ee5OOMMYvlH8FCZhDsacjMlCBwetbGZETwo1OA+e6Zw= k8s.io/client-go v0.22.4 h1:aAQ1Wk+I3bjCNk35YWUqbaueqrIonkfDPJSPDDe8Kfg= k8s.io/client-go v0.22.4/go.mod h1:Yzw4e5e7h1LNHA4uqnMVrpEpUs1hJOiuBsJKIlRCHDA= k8s.io/code-generator v0.19.16/go.mod h1:ADrDvaUQWGn4a8lX0ONtzb7uFmDRQOMSYIMk1qWIAx8= @@ -2663,6 +2682,7 @@ k8s.io/klog v1.0.0/go.mod h1:4Bi6QPql/J/LkTDqv7R/cd3hPo4k2DG6Ptcz060Ez5I= k8s.io/klog/v2 v2.0.0/go.mod h1:PBfzABfn139FHAV07az/IF9Wp1bkk3vpT2XSJ76fSDE= k8s.io/klog/v2 v2.2.0/go.mod h1:Od+F08eJP+W3HUb4pSrPpgp9DGU4GzlpG/TmITuYh/Y= k8s.io/klog/v2 v2.3.0/go.mod h1:Od+F08eJP+W3HUb4pSrPpgp9DGU4GzlpG/TmITuYh/Y= +k8s.io/klog/v2 v2.4.0/go.mod h1:Od+F08eJP+W3HUb4pSrPpgp9DGU4GzlpG/TmITuYh/Y= k8s.io/klog/v2 v2.9.0/go.mod h1:hy9LJ/NvuK+iVyP4Ehqva4HxZG/oXyIS3n3Jmire4Ec= k8s.io/klog/v2 v2.90.0 h1:VkTxIV/FjRXn1fgNNcKGM8cfmL1Z33ZjXRTVxKCoF5M= k8s.io/klog/v2 v2.90.0/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0= @@ -2672,6 +2692,7 @@ k8s.io/utils v0.0.0-20191114184206-e782cd3c129f/go.mod h1:sZAwmy6armz5eXlNoLmJcl k8s.io/utils v0.0.0-20200414100711-2df71ebbae66/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= k8s.io/utils v0.0.0-20200729134348-d5654de09c73/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= k8s.io/utils v0.0.0-20200912215256-4140de9c8800/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= +k8s.io/utils v0.0.0-20201110183641-67b214c5f920/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= k8s.io/utils v0.0.0-20210819203725-bdf08cb9a70a h1:8dYfu/Fc9Gz2rNJKB9IQRGgQOh2clmRzNIPPY1xLY5g= k8s.io/utils v0.0.0-20210819203725-bdf08cb9a70a/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= modernc.org/fileutil v1.0.0/go.mod h1:JHsWpkrk/CnVV1H/eGlFf85BEpfkrp56ro8nojIq9Q8= @@ -2693,7 +2714,9 @@ rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.0.15/go.mod h1:LEScyzhFmoF5pso/YSeBstl57mOzx9xlU9n85RGrDQg= sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.0.22/go.mod h1:LEScyzhFmoF5pso/YSeBstl57mOzx9xlU9n85RGrDQg= +sigs.k8s.io/kustomize v2.0.3+incompatible/go.mod h1:MkjgH3RdOWrievjo6c9T245dYlB5QeXV4WCbnt/PEpU= sigs.k8s.io/structured-merge-diff/v4 v4.0.1/go.mod h1:bJZC9H9iH24zzfZ/41RGcq60oK1F7G282QMXDPYydCw= +sigs.k8s.io/structured-merge-diff/v4 v4.0.2/go.mod h1:bJZC9H9iH24zzfZ/41RGcq60oK1F7G282QMXDPYydCw= sigs.k8s.io/structured-merge-diff/v4 v4.1.2 h1:Hr/htKFmJEbtMgS/UD0N+gtgctAqz81t3nu+sPzynno= sigs.k8s.io/structured-merge-diff/v4 v4.1.2/go.mod h1:j/nl6xW8vLS49O8YvXW1ocPhZawJtm+Yrr7PPRQ0Vg4= sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o= diff --git a/pkg/kubecp/kubecp.go b/pkg/kubecp/kubecp.go new file mode 100644 index 00000000..d8b12922 --- /dev/null +++ b/pkg/kubecp/kubecp.go @@ -0,0 +1,9 @@ +package kubecp + +func Push(src string, pod string, dst string) error { + return nil +} + +func Pull(pod string, src string, dst string) error { + return nil +} diff --git a/pkg/utils/tar.go b/pkg/utils/tar.go new file mode 100644 index 00000000..bcf1645c --- /dev/null +++ b/pkg/utils/tar.go @@ -0,0 +1,54 @@ +package utils + +import ( + "archive/tar" + "io" + "os" + "path" + "path/filepath" +) + +func Untar(reader io.Reader, to string) error { + tr := tar.NewReader(reader) + + decFile := func(hdr *tar.Header) error { + file := path.Join(to, hdr.Name) + err := os.MkdirAll(filepath.Dir(file), 0755) + if err != nil { + return err + } + fw, err := os.OpenFile(file, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, hdr.FileInfo().Mode()) + if err != nil { + return err + } + defer fw.Close() + + _, err = io.Copy(fw, tr) + return err + } + + for { + hdr, err := tr.Next() + if err == io.EOF { + break + } + if err != nil { + return err + } + switch hdr.Typeflag { + case tar.TypeDir: + if err := os.MkdirAll(path.Join(to, hdr.Name), hdr.FileInfo().Mode()); err != nil { + return err + } + case tar.TypeSymlink: + if err = os.Symlink(hdr.Linkname, filepath.Join(to, hdr.Name)); err != nil { + return err + } + default: + if err := decFile(hdr); err != nil { + return err + } + } + } + return nil +}