kube_command.go 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224
  1. // Copyright 2019 Yunion
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. package command
  15. import (
  16. "fmt"
  17. "os"
  18. "os/exec"
  19. "time"
  20. "yunion.io/x/jsonutils"
  21. "yunion.io/x/log"
  22. webconsole_api "yunion.io/x/onecloud/pkg/apis/webconsole"
  23. "yunion.io/x/onecloud/pkg/mcclient"
  24. o "yunion.io/x/onecloud/pkg/webconsole/options"
  25. )
  26. type K8sEnv struct {
  27. Session *mcclient.ClientSession
  28. Cluster string
  29. Namespace string
  30. Pod string
  31. Container string
  32. Kubeconfig string
  33. Data jsonutils.JSONObject
  34. }
  35. type Kubectl struct {
  36. *BaseCommand
  37. kubeconfig string
  38. // For display info
  39. InstanceName string
  40. IPs []string
  41. }
  42. func NewKubectlCommand(s *mcclient.ClientSession, kubeconfig, namespace string) *Kubectl {
  43. name := o.Options.KubectlPath
  44. if len(namespace) == 0 {
  45. namespace = "default"
  46. }
  47. cmd := NewBaseCommand(s, name, "--namespace", namespace)
  48. return &Kubectl{
  49. BaseCommand: cmd,
  50. kubeconfig: kubeconfig,
  51. }
  52. }
  53. func (c *Kubectl) SetInstanceName(name string) {
  54. c.InstanceName = name
  55. }
  56. func (c *Kubectl) GetInstanceName() string {
  57. return c.InstanceName
  58. }
  59. func (c *Kubectl) SetIPs(ips []string) {
  60. c.IPs = ips
  61. }
  62. func (c *Kubectl) GetIPs() []string {
  63. return c.IPs
  64. }
  65. func (c *Kubectl) GetCommand() *exec.Cmd {
  66. cmd := c.BaseCommand.GetCommand()
  67. cmd.Env = append(cmd.Env, fmt.Sprintf("KUBECONFIG=%s", c.kubeconfig))
  68. return cmd
  69. }
  70. func (c Kubectl) GetProtocol() string {
  71. return PROTOCOL_TTY
  72. }
  73. func (c *Kubectl) Cleanup() error {
  74. log.Debugf("Remove temp kubeconfig file: %s", c.kubeconfig)
  75. return os.Remove(c.kubeconfig)
  76. }
  77. type KubectlExec struct {
  78. *Kubectl
  79. }
  80. func (c *Kubectl) Exec() *KubectlExec {
  81. // Execute a command in a container
  82. cmd := &KubectlExec{
  83. Kubectl: c,
  84. }
  85. cmd.AppendArgs("exec")
  86. return cmd
  87. }
  88. func (c *KubectlExec) Stdin() *KubectlExec {
  89. // -i: Pass stdin to the container
  90. c.AppendArgs("-i")
  91. return c
  92. }
  93. func (c *KubectlExec) TTY() *KubectlExec {
  94. // -t: Stdin is a TTY
  95. c.AppendArgs("-t")
  96. return c
  97. }
  98. func (c *KubectlExec) Container(name string) *KubectlExec {
  99. if len(name) == 0 {
  100. return c
  101. }
  102. // -c: Container name. If ommitted, the first container in the pod will be chosen
  103. c.AppendArgs("-c", name)
  104. return c
  105. }
  106. func (c *KubectlExec) Pod(name string) *KubectlExec {
  107. // Pod name
  108. c.AppendArgs(name)
  109. return c
  110. }
  111. func (c *KubectlExec) Command(cmd string, args ...string) *KubectlExec {
  112. c.AppendArgs("--", cmd)
  113. c.AppendArgs(args...)
  114. return c
  115. }
  116. func NewPodBashCommand(env *K8sEnv) ICommand {
  117. shellRequest := webconsole_api.SK8sShellRequest{}
  118. err := env.Data.Unmarshal(&shellRequest)
  119. if err != nil {
  120. log.Errorf("env.Data.Unmarshal SK8sShellRequest: %s", err)
  121. }
  122. if shellRequest.Command == "" {
  123. shellRequest.Command = "sh"
  124. }
  125. args := make([]string, 0)
  126. if len(shellRequest.Env) > 0 {
  127. for k, v := range shellRequest.Env {
  128. args = append(args, fmt.Sprintf("%s=%s", k, v))
  129. }
  130. args = append(args, shellRequest.Command)
  131. shellRequest.Command = "env"
  132. }
  133. args = append(args, shellRequest.Args...)
  134. kExec := NewKubectlCommand(env.Session, env.Kubeconfig, env.Namespace).Exec().
  135. Stdin().
  136. TTY().
  137. Pod(env.Pod).
  138. Container(env.Container).
  139. Command(shellRequest.Command, args...)
  140. if shellRequest.DisplayInfo != nil {
  141. kExec.SetInstanceName(shellRequest.DisplayInfo.InstanceName)
  142. kExec.SetIPs(shellRequest.DisplayInfo.IPs)
  143. }
  144. return kExec
  145. }
  146. type KubectlLog struct {
  147. *Kubectl
  148. }
  149. func (c *Kubectl) Logs() *KubectlLog {
  150. // Print the logs for a container in a pod
  151. cmd := &KubectlLog{
  152. Kubectl: c,
  153. }
  154. cmd.AppendArgs("logs")
  155. return cmd
  156. }
  157. func (c *KubectlLog) Follow() *KubectlLog {
  158. // -f: Specify if the logs should be streamed
  159. c.AppendArgs("-f")
  160. return c
  161. }
  162. func (c *KubectlLog) Pod(name string) *KubectlLog {
  163. // Pod name
  164. c.AppendArgs(name)
  165. return c
  166. }
  167. func (c *KubectlLog) Container(name string) *KubectlLog {
  168. if name == "" {
  169. return c
  170. }
  171. // -c, --container='': Print the logs of this container
  172. c.AppendArgs("-c", name)
  173. return c
  174. }
  175. func (c *KubectlLog) Since(data jsonutils.JSONObject) *KubectlLog {
  176. durationStr, _ := data.GetString("since")
  177. if durationStr == "" {
  178. return c
  179. }
  180. // --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
  181. if _, err := time.ParseDuration(durationStr); err != nil {
  182. log.Errorf("Failed to parse log since opt: %v", err)
  183. return c
  184. }
  185. c.AppendArgs("--since", durationStr)
  186. return c
  187. }
  188. func NewPodLogCommand(env *K8sEnv) ICommand {
  189. return NewKubectlCommand(env.Session, env.Kubeconfig, env.Namespace).Logs().
  190. Follow().
  191. Pod(env.Pod).
  192. Since(env.Data).
  193. Container(env.Container)
  194. }