Skip to content

Commit

Permalink
feat(exec): add exec support
Browse files Browse the repository at this point in the history
add exec support

Signed-off-by: ysicing <[email protected]>
  • Loading branch information
ysicing committed Jul 21, 2022
1 parent 2422953 commit 3dbd45d
Show file tree
Hide file tree
Showing 11 changed files with 156 additions and 10 deletions.
2 changes: 1 addition & 1 deletion VERSION
Original file line number Diff line number Diff line change
@@ -1 +1 @@
1.0.9
1.0.10
4 changes: 2 additions & 2 deletions cmd/boot/boot.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,8 @@ func initRootDirectory() error {
return errors.Errorf("failed to mkdir %s, err: %s", dir, err)
}
}
if err := os.MkdirAll(common.DefaultQuickonDir, common.FileMode0777); err != nil {
return errors.Errorf("failed to mkdir %s, err: %s", common.DefaultQuickonDir, err)
if err := os.MkdirAll(common.GetDefaultQuickonDir(), common.FileMode0777); err != nil {
return errors.Errorf("failed to mkdir %s, err: %s", common.GetDefaultQuickonDir(), err)
}
return nil
}
Expand Down
9 changes: 9 additions & 0 deletions cmd/manage.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,3 +33,12 @@ func newCmdManageGet(f factory.Factory) *cobra.Command {
m.AddCommand(manage.NewCmdGetApp(f))
return m
}

func newCmdManageExec(f factory.Factory) *cobra.Command {
m := &cobra.Command{
Use: "exec",
Short: "Execute a command in a app",
}
m.AddCommand(manage.NewCmdExecApp(f))
return m
}
72 changes: 72 additions & 0 deletions cmd/manage/exec.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
// Copyright (c) 2021-2022 北京渠成软件有限公司(Beijing Qucheng Software Co., Ltd. www.qucheng.com) All rights reserved.
// Use of this source code is covered by the following dual licenses:
// (1) Z PUBLIC LICENSE 1.2 (ZPL 1.2)
// (2) Affero General Public License 3.0 (AGPL 3.0)
// license that can be found in the LICENSE file.

package manage

import (
"context"
"fmt"

"github.com/easysoft/qcadmin/internal/app/debug"
"github.com/easysoft/qcadmin/internal/pkg/k8s"
"github.com/easysoft/qcadmin/internal/pkg/util/factory"
"github.com/manifoldco/promptui"
"github.com/sirupsen/logrus"
"github.com/spf13/cobra"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/labels"
)

func NewCmdExecApp(f factory.Factory) *cobra.Command {
log := f.GetLog()
app := &cobra.Command{
Use: "app",
Aliases: []string{"apps"},
Short: "exec app",
Args: cobra.ExactArgs(1),
Example: `q exec app http://console.efbb.haogs.cn/instance-view-39.html`,
RunE: func(cmd *cobra.Command, args []string) error {
url := args[0]
apidebug := log.GetLevel() == logrus.DebugLevel
log.Infof("start exec app: %s", url)
appdata, err := debug.GetNameByURL(url, apidebug)
if err != nil {
return err
}
k8sClient, err := k8s.NewSimpleClient()
if err != nil {
log.Errorf("k8s client err: %v", err)
return err
}
ctx := context.Background()
podlist, _ := k8sClient.ListPods(ctx, "default", metav1.ListOptions{
LabelSelector: labels.SelectorFromSet(map[string]string{
"release": appdata.K8Name,
}).String(),
})
if len(podlist.Items) < 1 {
return fmt.Errorf("podnum %d, app maybe not running", len(podlist.Items))
}
templates := &promptui.SelectTemplates{
Label: "{{ . }}?",
Active: "\U0001F44F {{ .Name | cyan }}",
Inactive: " {{ .Name | cyan }}",
Selected: "\U0001F31D {{ .Name | red | cyan }}",
}

prompt := promptui.Select{
Label: "select pod",
Items: podlist.Items,
Templates: templates,
Size: 5,
}
it, _, _ := prompt.Run()

return k8sClient.ExecPodWithTTY(ctx, "default", podlist.Items[it].Name, podlist.Items[it].Spec.Containers[0].Name, []string{"/bin/sh", "-c", "sh"})
},
}
return app
}
2 changes: 1 addition & 1 deletion cmd/manage/get.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ func NewCmdGetApp(f factory.Factory) *cobra.Command {
// if apidebug {
// spew.Dump(appdata)
// }
extargs := []string{"exp", "kubectl", "get", "-o", "wide", "pods,deploy,pvc,svc,ing", "-l", "release=" + appdata.K8Name, "-l", "app=" + appdata.Chart}
extargs := []string{"exp", "kubectl", "get", "-o", "wide", "pods,deploy,pvc,svc,ing", "-l", "release=" + appdata.K8Name}
// extargs = append(extargs, args...)
return qcexec.CommandRun(os.Args[0], extargs...)
},
Expand Down
1 change: 1 addition & 0 deletions cmd/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ func BuildRoot(f factory.Factory) *cobra.Command {
rootCmd.AddCommand(newCmdUpgrade(f))
rootCmd.AddCommand(newCmdManage(f))
rootCmd.AddCommand(newCmdManageGet(f))
rootCmd.AddCommand(newCmdManageExec(f))
// Add plugin commands

rootCmd.AddCommand(NewCmdExperimental(f))
Expand Down
7 changes: 7 additions & 0 deletions common/func.go
Original file line number Diff line number Diff line change
Expand Up @@ -113,3 +113,10 @@ func GetAPI(path string) string {
path = strings.TrimLeft(path, "/")
return fmt.Sprintf("https://api.qucheng.com/%s", path)
}

func GetDefaultQuickonDir() string {
if zos.IsMacOS() {
return fmt.Sprintf("%v/%v", zos.GetHomeDir(), DefaultQuickonDir)
}
return DefaultQuickonDir
}
4 changes: 3 additions & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ require (
github.com/spf13/pflag v1.0.5
github.com/ulikunitz/xz v0.5.10
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c
golang.org/x/sys v0.0.0-20220704084225-05e143d24a9e
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8
gopkg.in/natefinch/lumberjack.v2 v2.0.0
gopkg.in/yaml.v2 v2.4.0
gotest.tools v2.2.0+incompatible
Expand Down Expand Up @@ -64,6 +64,7 @@ require (
github.com/cespare/xxhash/v2 v2.1.2 // indirect
github.com/chai2010/gettext-go v0.0.0-20160711120539-c6fed771bfd5 // indirect
github.com/cheekybits/genny v1.0.0 // indirect
github.com/chzyer/readline v1.5.1 // indirect
github.com/containerd/containerd v1.6.6 // indirect
github.com/cpuguy83/go-md2man/v2 v2.0.2 // indirect
github.com/cyphar/filepath-securejoin v0.2.3 // indirect
Expand Down Expand Up @@ -117,6 +118,7 @@ require (
github.com/lithammer/dedent v1.1.0 // indirect
github.com/lucas-clemente/quic-go v0.28.0 // indirect
github.com/mailru/easyjson v0.7.6 // indirect
github.com/manifoldco/promptui v0.9.0 // indirect
github.com/marten-seemann/qpack v0.2.1 // indirect
github.com/marten-seemann/qtls-go1-16 v0.1.5 // indirect
github.com/marten-seemann/qtls-go1-17 v0.1.2 // indirect
Expand Down
10 changes: 10 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -211,8 +211,12 @@ github.com/cheekybits/genny v1.0.0/go.mod h1:+tQajlRqAUrPI7DOSpB0XAqZYtQakVtB7wX
github.com/cheggaaa/pb/v3 v3.1.0 h1:3uouEsl32RL7gTiQsuaXD4Bzbfl5tGztXGUvXbs4O04=
github.com/cheggaaa/pb/v3 v3.1.0/go.mod h1:YjrevcBqadFDaGQKRdmZxTY42pXEqda48Ea3lt0K/BE=
github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
github.com/chzyer/logex v1.2.1/go.mod h1:JLbx6lG2kDbNRFnfkgvh4eRJRPX1QCoOIWomwysCBrQ=
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
github.com/chzyer/readline v1.5.1 h1:upd/6fQk4src78LMRzh5vItIt361/o4uq553V8B5sGI=
github.com/chzyer/readline v1.5.1/go.mod h1:Eh+b79XXUwfKfcPLepksvw2tcLE/Ct21YObkaSkeBlk=
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
github.com/chzyer/test v1.0.0/go.mod h1:2JlltgoNkt4TW/z9V/IzDdFaMTM2JPIi26O1pF38GC8=
github.com/cilium/ebpf v0.0.0-20200110133405-4032b1d8aae3/go.mod h1:MA5e5Lr8slmEg9bt0VpxxWqJlO4iwu3FBdHUzV7wQVg=
github.com/cilium/ebpf v0.0.0-20200702112145-1c8d4c9ef775/go.mod h1:7cR51M8ViRLIdUjrmSXlK9pkrsDlLHbO8jiB8X8JnOc=
github.com/cilium/ebpf v0.2.0/go.mod h1:To2CFviqOWL/M0gIMsvSMlqe7em/l1ALkX1PyjrX2Qs=
Expand Down Expand Up @@ -821,6 +825,8 @@ github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN
github.com/mailru/easyjson v0.7.0/go.mod h1:KAzv3t3aY1NaHWoQz1+4F1ccyAH66Jk7yos7ldAVICs=
github.com/mailru/easyjson v0.7.6 h1:8yTIVnZgCoiM1TgqoeTl+LfU5Jg6/xL3QhGQnimLYnA=
github.com/mailru/easyjson v0.7.6/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
github.com/manifoldco/promptui v0.9.0 h1:3V4HzJk1TtXW1MTZMP7mdlwbBpIinw3HztaIlYthEiA=
github.com/manifoldco/promptui v0.9.0/go.mod h1:ka04sppxSGFAtxX0qhlYQjISsg9mR4GWtQEhdbn6Pgg=
github.com/markbates/errx v1.1.0 h1:QDFeR+UP95dO12JgW+tgi2UVfo0V8YBHiUIOaeBPiEI=
github.com/markbates/errx v1.1.0/go.mod h1:PLa46Oex9KNbVDZhKel8v1OT7hD5JZ2eI7AHhA0wswc=
github.com/markbates/oncer v1.0.0 h1:E83IaVAHygyndzPimgUYJjbshhDTALZyXxvk9FOlQRY=
Expand Down Expand Up @@ -1502,6 +1508,7 @@ golang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5/go.mod h1:STP8DvDyc/dI5b8T5h
golang.org/x/sys v0.0.0-20181029174526-d69651ed3497/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20181122145206-62eef0e2fa9b/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
Expand Down Expand Up @@ -1615,11 +1622,14 @@ golang.org/x/sys v0.0.0-20211205182925-97ca703d548d/go.mod h1:oPkhp1MJrh7nUepCBc
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220209214540-3681064d5158/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220310020820-b874c991c1a5/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220704084225-05e143d24a9e h1:CsOuNlbOuf0mzxJIefr6Q4uAUetRUwZE4qt7VfzP+xo=
golang.org/x/sys v0.0.0-20220704084225-05e143d24a9e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8 h1:0A+M6Uqn+Eje4kHMK80dtF3JCXC4ykBgQG4Fe06QRhQ=
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210615171337-6886f2dfbf5b/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
Expand Down
5 changes: 4 additions & 1 deletion internal/app/debug/fetch.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,10 @@ type AppData struct {
func GetNameByURL(url string, debug bool) (*AppData, error) {
// 获取ID
k := strings.Split(url, "-")
key := strings.Trim(k[len(k)-1], ".html")
if len(k) < 3 {
return nil, fmt.Errorf("url err")
}
key := k[2]

cfg, _ := config.LoadConfig()
if cfg.APIToken == "" {
Expand Down
50 changes: 46 additions & 4 deletions internal/pkg/k8s/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import (
"time"

"github.com/ergoapi/util/exmap"
"golang.org/x/term"
appsv1 "k8s.io/api/apps/v1"
corev1 "k8s.io/api/core/v1"
networkingv1 "k8s.io/api/networking/v1"
Expand All @@ -29,6 +30,8 @@ import (
"k8s.io/client-go/rest"
"k8s.io/client-go/tools/clientcmd"
clientcmdapi "k8s.io/client-go/tools/clientcmd/api"
"k8s.io/client-go/tools/remotecommand"
"k8s.io/kubectl/pkg/scheme"
metrics "k8s.io/metrics/pkg/client/clientset/versioned"
)

Expand All @@ -43,11 +46,14 @@ type Client struct {
}

func NewSimpleClient() (*Client, error) {
dir, err := os.UserHomeDir()
if err != nil {
return nil, err
kubeconfig := os.Getenv("KUBECONFIG")
if kubeconfig == "" {
dir, err := os.UserHomeDir()
if err != nil {
return nil, err
}
kubeconfig = filepath.Join(dir, ".kube", "config")
}
kubeconfig := filepath.Join(dir, ".kube", "config")
config, err := clientcmd.BuildConfigFromFlags("", kubeconfig)
if err != nil {
return nil, err
Expand Down Expand Up @@ -428,6 +434,42 @@ func (c *Client) ExecInPod(ctx context.Context, namespace, pod, container string
return result.Stdout, nil
}

func (c *Client) ExecPodWithTTY(ctx context.Context, namespace, podName, container string, command []string) error {
req := c.Clientset.CoreV1().RESTClient().Post().
Resource("pods").
Name(podName).
Namespace(namespace).
SubResource("exec").
VersionedParams(&corev1.PodExecOptions{
Command: command,
Stdin: true,
Stdout: true,
Stderr: true,
TTY: true,
}, scheme.ParameterCodec)
exec, err := remotecommand.NewSPDYExecutor(c.Config, "POST", req.URL())
if err != nil {
return err
}
if !term.IsTerminal(0) || !term.IsTerminal(1) {
return fmt.Errorf("stdin/stdout must be a terminal")
}
oldstate, _ := term.MakeRaw(0)
defer term.Restore(0, oldstate)
screen := struct {
io.Reader
io.Writer
}{os.Stdin, os.Stdout}

err = exec.Stream(remotecommand.StreamOptions{
Stdin: screen,
Stdout: screen,
Stderr: screen,
Tty: true,
})
return err
}

func (c *Client) CreateIngressClass(ctx context.Context, ingressClass *networkingv1.IngressClass, opts metav1.CreateOptions) (*networkingv1.IngressClass, error) {
return c.Clientset.NetworkingV1().IngressClasses().Create(ctx, ingressClass, opts)
}
Expand Down

0 comments on commit 3dbd45d

Please sign in to comment.