run.go 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157
  1. package cmd
  2. import (
  3. "context"
  4. "fmt"
  5. "os"
  6. "github.com/porter-dev/porter/cli/cmd/api"
  7. "github.com/spf13/cobra"
  8. "k8s.io/apimachinery/pkg/runtime"
  9. "k8s.io/apimachinery/pkg/runtime/schema"
  10. "k8s.io/client-go/rest"
  11. "k8s.io/client-go/tools/clientcmd"
  12. "k8s.io/client-go/tools/remotecommand"
  13. "k8s.io/kubectl/pkg/util/term"
  14. )
  15. // runCmd represents the "porter run" base command when called
  16. // without any subcommands
  17. var runCmd = &cobra.Command{
  18. Use: "run [cmd]",
  19. Args: cobra.ExactArgs(1),
  20. Short: "Runs a command inside a connected cluster container.",
  21. Run: func(cmd *cobra.Command, args []string) {
  22. err := checkLoginAndRun(args, run)
  23. if err != nil {
  24. os.Exit(1)
  25. }
  26. },
  27. }
  28. func init() {
  29. rootCmd.AddCommand(runCmd)
  30. runCmd.PersistentFlags().StringVar(
  31. &host,
  32. "host",
  33. getHost(),
  34. "host url of Porter instance",
  35. )
  36. }
  37. func run(_ *api.AuthCheckResponse, client *api.Client, args []string) error {
  38. podNames, err := getPods(client)
  39. if err != nil {
  40. return fmt.Errorf("Could not retrieve list of pods: %s", err.Error())
  41. }
  42. restConf, err := getRESTConfig(client)
  43. if err != nil {
  44. return fmt.Errorf("Could not retrieve kube credentials: %s", err.Error())
  45. }
  46. return executeRun(restConf, "default", podNames[0])
  47. }
  48. func getRESTConfig(client *api.Client) (*rest.Config, error) {
  49. pID := getProjectID()
  50. cID := getClusterID()
  51. kubeResp, err := client.GetKubeconfig(context.TODO(), pID, cID)
  52. if err != nil {
  53. return nil, err
  54. }
  55. kubeBytes := kubeResp.Kubeconfig
  56. cmdConf, err := clientcmd.NewClientConfigFromBytes(kubeBytes)
  57. if err != nil {
  58. return nil, err
  59. }
  60. restConf, err := cmdConf.ClientConfig()
  61. if err != nil {
  62. return nil, err
  63. }
  64. restConf.GroupVersion = &schema.GroupVersion{
  65. Group: "api",
  66. Version: "v1",
  67. }
  68. restConf.NegotiatedSerializer = runtime.NewSimpleNegotiatedSerializer(runtime.SerializerInfo{})
  69. return restConf, nil
  70. }
  71. func getPods(client *api.Client) ([]string, error) {
  72. pID := getProjectID()
  73. cID := getClusterID()
  74. resp, err := client.GetK8sAllPods(context.TODO(), pID, cID, "default", "same-name")
  75. if err != nil {
  76. return nil, err
  77. }
  78. res := make([]string, 0)
  79. for _, pod := range resp {
  80. res = append(res, pod.ObjectMeta.Name)
  81. }
  82. return res, nil
  83. }
  84. func executeRun(config *rest.Config, namespace, name string) error {
  85. restClient, err := rest.RESTClientFor(config)
  86. if err != nil {
  87. return err
  88. }
  89. req := restClient.Post().
  90. Resource("pods").
  91. Name(name).
  92. Namespace(namespace).
  93. SubResource("exec")
  94. // req.Param("container", "web")
  95. req.Param("command", "sh")
  96. req.Param("stdin", "true")
  97. req.Param("stdout", "true")
  98. req.Param("tty", "true")
  99. t := term.TTY{
  100. In: os.Stdin,
  101. Out: os.Stdout,
  102. }
  103. fn := func() error {
  104. exec, err := remotecommand.NewSPDYExecutor(config, "POST", req.URL())
  105. if err != nil {
  106. return err
  107. }
  108. return exec.Stream(remotecommand.StreamOptions{
  109. Stdin: os.Stdin,
  110. Stdout: os.Stdout,
  111. Stderr: os.Stderr,
  112. Tty: true,
  113. })
  114. }
  115. if err := t.Safe(fn); err != nil {
  116. return err
  117. }
  118. return err
  119. }