1 package component
2
3 import (
4 "context"
5 "fmt"
6 "io"
7
8 "github.com/devfile/api/v2/pkg/apis/workspaces/v1alpha2"
9 devfilev1 "github.com/devfile/api/v2/pkg/apis/workspaces/v1alpha2"
10 "github.com/redhat-developer/odo/pkg/exec"
11 "github.com/redhat-developer/odo/pkg/log"
12 "github.com/redhat-developer/odo/pkg/machineoutput"
13 "github.com/redhat-developer/odo/pkg/platform"
14 "github.com/redhat-developer/odo/pkg/util"
15 "k8s.io/klog"
16 "k8s.io/utils/pointer"
17 )
18
19 const ShellExecutable string = "/bin/sh"
20
21 func ExecuteTerminatingCommand(
22 ctx context.Context,
23 execClient exec.Client,
24 platformClient platform.Client,
25 command devfilev1.Command,
26 componentExists bool,
27 podName string,
28 appName string,
29 componentName string,
30 msg string,
31 directRun bool,
32 ) error {
33
34 if componentExists && command.Exec != nil && pointer.BoolDeref(command.Exec.HotReloadCapable, false) {
35 klog.V(2).Infof("command is hot-reload capable, not executing %q again", command.Id)
36 return nil
37 }
38
39
40 var spinner *log.Status
41 var stdoutWriter, stderrWriter *io.PipeWriter
42 var stdoutChannel, stderrChannel chan interface{}
43
44 if !directRun {
45 if msg == "" {
46 msg = fmt.Sprintf("Executing %s command on container %q", command.Id, command.Exec.Component)
47 } else {
48 msg += " (command: " + command.Id + ")"
49 }
50 spinner = log.Spinner(msg)
51 defer spinner.End(false)
52
53 logger := machineoutput.NewMachineEventLoggingClient()
54 stdoutWriter, stdoutChannel, stderrWriter, stderrChannel = logger.CreateContainerOutputWriter()
55 }
56
57 cmdline := getCmdline(command, !directRun)
58 _, _, err := execClient.ExecuteCommand(ctx, cmdline, podName, command.Exec.Component, directRun, stdoutWriter, stderrWriter)
59
60 if !directRun {
61 closeWriterAndWaitForAck(stdoutWriter, stdoutChannel, stderrWriter, stderrChannel)
62 spinner.End(err == nil)
63
64 if err != nil {
65 rd, errLog := Log(platformClient, componentName, appName, false, command)
66 if errLog != nil {
67 return fmt.Errorf("unable to log error %v: %w", err, errLog)
68 }
69
70
71
72 errLog = util.DisplayLog(false, rd, log.GetStderr(), componentName, -1)
73 if errLog != nil {
74 return fmt.Errorf("unable to log error %v: %w", err, errLog)
75 }
76 }
77 }
78 return err
79 }
80
81 func getCmdline(command v1alpha2.Command, redirectToPid1 bool) []string {
82
83 var cmdLine string
84 setEnvVariable := util.GetCommandStringFromEnvs(command.Exec.Env)
85
86 if setEnvVariable == "" {
87 cmdLine = command.Exec.CommandLine
88 } else {
89 cmdLine = setEnvVariable + " && " + command.Exec.CommandLine
90 }
91
92
93
94
95
96 redirectString := ""
97 if redirectToPid1 {
98 redirectString = "1>>/proc/1/fd/1 2>>/proc/1/fd/2"
99 }
100 var cmd []string
101 if command.Exec.WorkingDir != "" {
102
103 cmd = []string{ShellExecutable, "-c", "cd " + command.Exec.WorkingDir + " && (" + cmdLine + ") " + redirectString}
104 } else {
105 cmd = []string{ShellExecutable, "-c", "(" + cmdLine + ") " + redirectString}
106 }
107 return cmd
108 }
109
110 func closeWriterAndWaitForAck(stdoutWriter *io.PipeWriter, stdoutChannel chan interface{}, stderrWriter *io.PipeWriter, stderrChannel chan interface{}) {
111 if stdoutWriter != nil {
112 _ = stdoutWriter.Close()
113 <-stdoutChannel
114 }
115 if stderrWriter != nil {
116 _ = stderrWriter.Close()
117 <-stderrChannel
118 }
119 }
120
View as plain text