@@ -81,6 +81,78 @@ func AddPostStartLifecycleHooks(wksp *dw.DevWorkspaceTemplateSpec, containers []
8181 return nil
8282}
8383
84+ // processCommandsForPostStart processes a list of DevWorkspace commands
85+ // and generates a corev1.LifecycleHandler for the PostStart lifecycle hook.
86+ func processCommandsForPostStart (commands []dw.Command , postStartTimeout * int32 ) (* corev1.LifecycleHandler , error ) {
87+ if postStartTimeout == nil || * postStartTimeout == 0 {
88+ // use the fallback if no timeout propagated
89+ return processCommandsWithoutTimeoutFallback (commands )
90+ }
91+
92+ originalUserScript , err := buildUserScript (commands )
93+ if err != nil {
94+ return nil , fmt .Errorf ("failed to build aggregated user script: %w" , err )
95+ }
96+
97+ // The user script needs 'set -e' to ensure it exits on error.
98+ // This script is then passed to `sh -c '...'`, so single quotes within it must be escaped.
99+ scriptToExecute := "set -e\n " + originalUserScript
100+ escapedUserScriptForTimeoutWrapper := strings .ReplaceAll (scriptToExecute , "'" , `'\''` )
101+
102+ fullScriptWithTimeout := generateScriptWithTimeout (escapedUserScriptForTimeoutWrapper , * postStartTimeout )
103+
104+ finalScriptForHook := fmt .Sprintf (redirectOutputFmt , fullScriptWithTimeout )
105+
106+ handler := & corev1.LifecycleHandler {
107+ Exec : & corev1.ExecAction {
108+ Command : []string {
109+ "/bin/sh" ,
110+ "-c" ,
111+ finalScriptForHook ,
112+ },
113+ },
114+ }
115+ return handler , nil
116+ }
117+
118+ // processCommandsWithoutTimeoutFallback builds a lifecycle handler that runs the provided command(s)
119+ // The command has the format
120+ //
121+ // exec:
122+ //
123+ // command:
124+ // - "/bin/sh"
125+ // - "-c"
126+ // - |
127+ // cd <workingDir>
128+ // <commandline>
129+ func processCommandsWithoutTimeoutFallback (commands []dw.Command ) (* corev1.LifecycleHandler , error ) {
130+ var dwCommands []string
131+ for _ , command := range commands {
132+ execCmd := command .Exec
133+ if len (execCmd .Env ) > 0 {
134+ return nil , fmt .Errorf ("env vars in postStart command %s are unsupported" , command .Id )
135+ }
136+ if execCmd .WorkingDir != "" {
137+ dwCommands = append (dwCommands , fmt .Sprintf ("cd %s" , execCmd .WorkingDir ))
138+ }
139+ dwCommands = append (dwCommands , execCmd .CommandLine )
140+ }
141+
142+ joinedCommands := strings .Join (dwCommands , "\n " )
143+
144+ handler := & corev1.LifecycleHandler {
145+ Exec : & corev1.ExecAction {
146+ Command : []string {
147+ "/bin/sh" ,
148+ "-c" ,
149+ fmt .Sprintf (noTimeoutRedirectOutputFmt , joinedCommands ),
150+ },
151+ },
152+ }
153+ return handler , nil
154+ }
155+
84156// buildUserScript takes a list of DevWorkspace commands and constructs a single
85157// shell script string that executes them sequentially.
86158func buildUserScript (commands []dw.Command ) (string , error ) {
156228exit $exit_code
157229` , timeoutSeconds , escapedUserScript )
158230}
159-
160- // processCommandsForPostStart processes a list of DevWorkspace commands
161- // and generates a corev1.LifecycleHandler for the PostStart lifecycle hook.
162- func processCommandsForPostStart (commands []dw.Command , postStartTimeout * int32 ) (* corev1.LifecycleHandler , error ) {
163- if postStartTimeout == nil || * postStartTimeout == 0 {
164- // use the fallback if no timeout propagated
165- return processCommandsWithoutTimeoutFallback (commands )
166- }
167-
168- originalUserScript , err := buildUserScript (commands )
169- if err != nil {
170- return nil , fmt .Errorf ("failed to build aggregated user script: %w" , err )
171- }
172-
173- // The user script needs 'set -e' to ensure it exits on error.
174- // This script is then passed to `sh -c '...'`, so single quotes within it must be escaped.
175- scriptToExecute := "set -e\n " + originalUserScript
176- escapedUserScriptForTimeoutWrapper := strings .ReplaceAll (scriptToExecute , "'" , `'\''` )
177-
178- fullScriptWithTimeout := generateScriptWithTimeout (escapedUserScriptForTimeoutWrapper , * postStartTimeout )
179-
180- finalScriptForHook := fmt .Sprintf (redirectOutputFmt , fullScriptWithTimeout )
181-
182- handler := & corev1.LifecycleHandler {
183- Exec : & corev1.ExecAction {
184- Command : []string {
185- "/bin/sh" ,
186- "-c" ,
187- finalScriptForHook ,
188- },
189- },
190- }
191- return handler , nil
192- }
193-
194- // processCommandsForPostStart builds a lifecycle handler that runs the provided command(s)
195- // The command has the format
196- //
197- // exec:
198- //
199- // command:
200- // - "/bin/sh"
201- // - "-c"
202- // - |
203- // cd <workingDir>
204- // <commandline>
205- func processCommandsWithoutTimeoutFallback (commands []dw.Command ) (* corev1.LifecycleHandler , error ) {
206- var dwCommands []string
207- for _ , command := range commands {
208- execCmd := command .Exec
209- if len (execCmd .Env ) > 0 {
210- return nil , fmt .Errorf ("env vars in postStart command %s are unsupported" , command .Id )
211- }
212- if execCmd .WorkingDir != "" {
213- dwCommands = append (dwCommands , fmt .Sprintf ("cd %s" , execCmd .WorkingDir ))
214- }
215- dwCommands = append (dwCommands , execCmd .CommandLine )
216- }
217-
218- joinedCommands := strings .Join (dwCommands , "\n " )
219-
220- handler := & corev1.LifecycleHandler {
221- Exec : & corev1.ExecAction {
222- Command : []string {
223- "/bin/sh" ,
224- "-c" ,
225- fmt .Sprintf (noTimeoutRedirectOutputFmt , joinedCommands ),
226- },
227- },
228- }
229- return handler , nil
230- }
0 commit comments