// Copyright 2019 Yunion // // 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 command import ( "fmt" "os" "os/exec" "time" "yunion.io/x/jsonutils" "yunion.io/x/log" o "yunion.io/x/onecloud/pkg/webconsole/options" ) type K8sEnv struct { Cluster string Namespace string Pod string Container string Kubeconfig string Data jsonutils.JSONObject } type Kubectl struct { *BaseCommand kubeconfig string } func NewKubectlCommand(kubeconfig, namespace string) *Kubectl { name := o.Options.KubectlPath if len(namespace) == 0 { namespace = "default" } cmd := NewBaseCommand(name, "--namespace", namespace) return &Kubectl{ BaseCommand: cmd, kubeconfig: kubeconfig, } } func (c *Kubectl) GetCommand() *exec.Cmd { cmd := c.BaseCommand.GetCommand() cmd.Env = append(cmd.Env, fmt.Sprintf("KUBECONFIG=%s", c.kubeconfig)) return cmd } func (c Kubectl) GetProtocol() string { return PROTOCOL_TTY } func (c *Kubectl) Cleanup() error { log.Debugf("Remove temp kubeconfig file: %s", c.kubeconfig) return os.Remove(c.kubeconfig) } type KubectlExec struct { *Kubectl } func (c *Kubectl) Exec() *KubectlExec { // Execute a command in a container cmd := &KubectlExec{ Kubectl: c, } cmd.AppendArgs("exec") return cmd } func (c *KubectlExec) Stdin() *KubectlExec { // -i: Pass stdin to the container c.AppendArgs("-i") return c } func (c *KubectlExec) TTY() *KubectlExec { // -t: Stdin is a TTY c.AppendArgs("-t") return c } func (c *KubectlExec) Container(name string) *KubectlExec { if len(name) == 0 { return c } // -c: Container name. If ommitted, the first container in the pod will be chosen c.AppendArgs("-c", name) return c } func (c *KubectlExec) Pod(name string) *KubectlExec { // Pod name c.AppendArgs(name) return c } func (c *KubectlExec) Command(cmd string, args ...string) *KubectlExec { c.AppendArgs("--", cmd) c.AppendArgs(args...) return c } func NewPodBashCommand(env *K8sEnv) ICommand { return NewKubectlCommand(env.Kubeconfig, env.Namespace).Exec(). Stdin(). TTY(). Pod(env.Pod). Container(env.Container). Command("sh") } type KubectlLog struct { *Kubectl } func (c *Kubectl) Logs() *KubectlLog { // Print the logs for a container in a pod cmd := &KubectlLog{ Kubectl: c, } cmd.AppendArgs("logs") return cmd } func (c *KubectlLog) Follow() *KubectlLog { // -f: Specify if the logs should be streamed c.AppendArgs("-f") return c } func (c *KubectlLog) Pod(name string) *KubectlLog { // Pod name c.AppendArgs(name) return c } func (c *KubectlLog) Container(name string) *KubectlLog { if name == "" { return c } // -c, --container='': Print the logs of this container c.AppendArgs("-c", name) return c } func (c *KubectlLog) Since(data jsonutils.JSONObject) *KubectlLog { durationStr, _ := data.GetString("since") if durationStr == "" { return c } // --since: Only return logs newer than a relative duration like 5s, 2m, or 3h. Defaults to all logs. Only one of since-time / since may be used if _, err := time.ParseDuration(durationStr); err != nil { log.Errorf("Failed to parse log since opt: %v", err) return c } c.AppendArgs("--since", durationStr) return c } func NewPodLogCommand(env *K8sEnv) ICommand { return NewKubectlCommand(env.Kubeconfig, env.Namespace).Logs(). Follow(). Pod(env.Pod). Since(env.Data). Container(env.Container) }