@@ -25,7 +25,6 @@ import (
25
25
"github.com/tektoncd/pipeline/pkg/apis/pipeline/v1beta1"
26
26
"github.com/tektoncd/pipeline/pkg/names"
27
27
corev1 "k8s.io/api/core/v1"
28
- metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
29
28
)
30
29
31
30
const (
71
70
72
71
// convertScripts converts any steps and sidecars that specify a Script field into a normal Container.
73
72
func convertScripts (shellImageLinux string , shellImageWin string , steps []v1beta1.Step , sidecars []v1beta1.Sidecar , debugConfig * v1beta1.TaskRunDebug ) (* corev1.Container , []corev1.Container , []corev1.Container ) {
74
- placeScripts := false
75
73
// Place scripts is an init container used for creating scripts in the
76
74
// /tekton/scripts directory which would be later used by the step containers
77
75
// as a Command
@@ -96,140 +94,162 @@ func convertScripts(shellImageLinux string, shellImageWin string, steps []v1beta
96
94
}
97
95
98
96
breakpoints := []string {}
99
- sideCarSteps := []v1beta1.Step {}
100
- for _ , sidecar := range sidecars {
101
- c := sidecar .ToK8sContainer ()
102
- sidecarStep := v1beta1.Step {
103
- Script : sidecar .Script ,
104
- Timeout : & metav1.Duration {},
105
- }
106
- sidecarStep .SetContainerFields (* c )
107
- sideCarSteps = append (sideCarSteps , sidecarStep )
108
- }
109
97
110
98
// Add mounts for debug
111
99
if debugConfig != nil && len (debugConfig .Breakpoint ) > 0 {
112
100
breakpoints = debugConfig .Breakpoint
113
101
placeScriptsInit .VolumeMounts = append (placeScriptsInit .VolumeMounts , debugScriptsVolumeMount )
114
102
}
115
103
116
- convertedStepContainers := convertListOfSteps (steps , & placeScriptsInit , & placeScripts , breakpoints , "script" )
104
+ convertedStepContainers := convertListOfSteps (steps , & placeScriptsInit , breakpoints , "script" )
105
+ sidecarContainers := convertListOfSidecars (sidecars , & placeScriptsInit , "sidecar-script" )
117
106
118
- // Pass empty breakpoint list in "sidecar step to container" converter to not rewrite the scripts and add breakpoints to sidecar
119
- sidecarContainers := convertListOfSteps (sideCarSteps , & placeScriptsInit , & placeScripts , []string {}, "sidecar-script" )
120
- if placeScripts {
107
+ if hasScripts (steps , sidecars , breakpoints ) {
121
108
return & placeScriptsInit , convertedStepContainers , sidecarContainers
122
109
}
123
110
return nil , convertedStepContainers , sidecarContainers
124
111
}
125
112
126
- // convertListOfSteps does the heavy lifting for convertScripts.
127
- //
128
- // It iterates through the list of steps (or sidecars), generates the script file name and heredoc termination string,
129
- // adds an entry to the init container args, sets up the step container to run the script, and sets the volume mounts.
130
- func convertListOfSteps (steps []v1beta1.Step , initContainer * corev1.Container , placeScripts * bool , breakpoints []string , namePrefix string ) []corev1.Container {
131
- containers := []corev1.Container {}
132
- for i , s := range steps {
133
- // Add debug mounts if breakpoints are present
134
- if len (breakpoints ) > 0 {
135
- debugInfoVolumeMount := corev1.VolumeMount {
136
- Name : debugInfoVolumeName ,
137
- MountPath : filepath .Join (debugInfoDir , fmt .Sprintf ("%d" , i )),
138
- }
139
- steps [i ].VolumeMounts = append (steps [i ].VolumeMounts , debugScriptsVolumeMount , debugInfoVolumeMount )
113
+ // hasScripts determines if we need to generate sripts in InitContainer given steps, sidecars and breakpoints.
114
+ func hasScripts (steps []v1beta1.Step , sidecars []v1beta1.Sidecar , breakpoints []string ) bool {
115
+ for _ , s := range steps {
116
+ if s .Script != "" {
117
+ return true
140
118
}
141
-
142
- if s .Script == "" {
143
- // Nothing to convert.
144
- containers = append (containers , * steps [i ].ToK8sContainer ())
145
- continue
119
+ }
120
+ for _ , s := range sidecars {
121
+ if s .Script != "" {
122
+ return true
146
123
}
124
+ }
125
+ if len (breakpoints ) > 0 {
126
+ return true
127
+ }
128
+ return false
129
+ }
147
130
148
- // Check for a shebang, and add a default if it's not set.
149
- // The shebang must be the first non-empty line.
150
- cleaned := strings . TrimSpace ( s . Script )
151
- hasShebang := strings . HasPrefix ( cleaned , "#!" )
152
- requiresWindows := strings . HasPrefix ( cleaned , "#!win" )
153
-
154
- script := s . Script
155
- if ! hasShebang {
156
- script = defaultScriptPreamble + s . Script
157
- }
131
+ // placeScriptInContainer given a piece of script to be executed, placeScriptInContainer firstly modifies initContainer
132
+ // so that it capsules the target script into scriptFile, then it modifies the container so that it can execute the scriptFile
133
+ // in runtime.
134
+ func placeScriptInContainer ( script , scriptFile string , c * corev1. Container , initContainer * corev1. Container ) {
135
+ if script == "" {
136
+ return
137
+ }
138
+ cleaned := strings . TrimSpace ( script )
139
+ hasShebang := strings . HasPrefix ( cleaned , "#!" )
140
+ requiresWindows := strings . HasPrefix ( cleaned , "#!win" )
158
141
159
- // At least one step uses a script, so we should return a
160
- // non-nil init container.
161
- * placeScripts = true
142
+ if ! hasShebang {
143
+ script = defaultScriptPreamble + script
144
+ }
162
145
163
- // Append to the place-scripts script to place the
164
- // script file in a known location in the scripts volume.
165
- scriptFile := filepath .Join (scriptsDir , names .SimpleNameGenerator .RestrictLengthWithRandomSuffix (fmt .Sprintf ("%s-%d" , namePrefix , i )))
166
- if requiresWindows {
167
- command , args , script , scriptFile := extractWindowsScriptComponents (script , scriptFile )
168
- initContainer .Args [1 ] += fmt .Sprintf (`@"
146
+ // Append to the place-scripts script to place the
147
+ // script file in a known location in the scripts volume.
148
+ if requiresWindows {
149
+ command , args , script , scriptFile := extractWindowsScriptComponents (script , scriptFile )
150
+ initContainer .Args [1 ] += fmt .Sprintf (`@"
169
151
%s
170
152
"@ | Out-File -FilePath %s
171
153
` , script , scriptFile )
172
154
173
- steps [ i ] .Command = command
174
- // Append existing args field to end of derived args
175
- args = append (args , steps [ i ] .Args ... )
176
- steps [ i ] .Args = args
177
- } else {
178
- // Only encode the script for linux scripts
179
- // The decode-script subcommand of the entrypoint does not work under windows
180
- script = encodeScript (script )
181
- heredoc := "_EOF_" // underscores because base64 doesnt include them in its alphabet
182
- initContainer .Args [1 ] += fmt .Sprintf (`scriptfile="%s"
155
+ c .Command = command
156
+ // Append existing args field to end of derived args
157
+ args = append (args , c .Args ... )
158
+ c .Args = args
159
+ } else {
160
+ // Only encode the script for linux scripts
161
+ // The decode-script subcommand of the entrypoint does not work under windows
162
+ script = encodeScript (script )
163
+ heredoc := "_EOF_" // underscores because base64 doesn't include them in its alphabet
164
+ initContainer .Args [1 ] += fmt .Sprintf (`scriptfile="%s"
183
165
touch ${scriptfile} && chmod +x ${scriptfile}
184
166
cat > ${scriptfile} << '%s'
185
167
%s
186
168
%s
187
169
/tekton/bin/entrypoint decode-script "${scriptfile}"
188
170
` , scriptFile , heredoc , script , heredoc )
189
171
190
- // Set the command to execute the correct script in the mounted
191
- // volume.
192
- // A previous merge with stepTemplate may have populated
193
- // Command and Args, even though this is not normally valid, so
194
- // we'll clear out the Args and overwrite Command.
195
- steps [ i ]. Command = [] string { scriptFile }
196
- }
197
- steps [ i ]. VolumeMounts = append ( steps [ i ]. VolumeMounts , scriptsVolumeMount )
172
+ // Set the command to execute the correct script in the mounted volume.
173
+ // A previous merge with stepTemplate may have populated
174
+ // Command and Args, even though this is not normally valid, so
175
+ // we'll clear out the Args and overwrite Command.
176
+ c . Command = [] string { scriptFile }
177
+ }
178
+ c . VolumeMounts = append ( c . VolumeMounts , scriptsVolumeMount )
179
+ }
198
180
199
- containers = append (containers , * steps [i ].ToK8sContainer ())
181
+ // placeDebugScriptInContainers inserts debug scripts into containers. It capsules those scripts to files in intiContainer,
182
+ // then execute those scripts in target containers.
183
+ func placeDebugScriptInContainers (containers []corev1.Container , initContainer * corev1.Container ) {
184
+ for i := 0 ; i < len (containers ); i ++ {
185
+ debugInfoVolumeMount := corev1.VolumeMount {
186
+ Name : debugInfoVolumeName ,
187
+ MountPath : filepath .Join (debugInfoDir , fmt .Sprintf ("%d" , i )),
188
+ }
189
+ (& containers [i ]).VolumeMounts = append ((& containers [i ]).VolumeMounts , debugScriptsVolumeMount , debugInfoVolumeMount )
200
190
}
201
191
202
- // Place debug scripts if breakpoints are enabled
203
- if len (breakpoints ) > 0 {
204
- // If breakpoint is not nil then should add the init container
205
- // to write debug script files
206
- * placeScripts = true
192
+ type script struct {
193
+ name string
194
+ content string
195
+ }
196
+ debugScripts := []script {{
197
+ name : "continue" ,
198
+ content : defaultScriptPreamble + fmt .Sprintf (debugContinueScriptTemplate , len (containers ), debugInfoDir , RunDir ),
199
+ }, {
200
+ name : "fail-continue" ,
201
+ content : defaultScriptPreamble + fmt .Sprintf (debugFailScriptTemplate , len (containers ), debugInfoDir , RunDir ),
202
+ }}
203
+
204
+ // Add debug or breakpoint related scripts to /tekton/debug/scripts
205
+ // Iterate through the debugScripts and add routine for each of them in the initContainer for their creation
206
+ for _ , debugScript := range debugScripts {
207
+ tmpFile := filepath .Join (debugScriptsDir , fmt .Sprintf ("%s-%s" , "debug" , debugScript .name ))
208
+ heredoc := names .SimpleNameGenerator .RestrictLengthWithRandomSuffix (fmt .Sprintf ("%s-%s-heredoc-randomly-generated" , "debug" , debugScript .name ))
209
+
210
+ initContainer .Args [1 ] += fmt .Sprintf (initScriptDirective , tmpFile , heredoc , debugScript .content , heredoc )
211
+ }
212
+ }
207
213
208
- type script struct {
209
- name string
210
- content string
211
- }
212
- debugScripts := []script {{
213
- name : "continue" ,
214
- content : defaultScriptPreamble + fmt .Sprintf (debugContinueScriptTemplate , len (steps ), debugInfoDir , RunDir ),
215
- }, {
216
- name : "fail-continue" ,
217
- content : defaultScriptPreamble + fmt .Sprintf (debugFailScriptTemplate , len (steps ), debugInfoDir , RunDir ),
218
- }}
219
-
220
- // Add debug or breakpoint related scripts to /tekton/debug/scripts
221
- // Iterate through the debugScripts and add routine for each of them in the initContainer for their creation
222
- for _ , debugScript := range debugScripts {
223
- tmpFile := filepath .Join (debugScriptsDir , fmt .Sprintf ("%s-%s" , "debug" , debugScript .name ))
224
- heredoc := names .SimpleNameGenerator .RestrictLengthWithRandomSuffix (fmt .Sprintf ("%s-%s-heredoc-randomly-generated" , "debug" , debugScript .name ))
225
-
226
- initContainer .Args [1 ] += fmt .Sprintf (initScriptDirective , tmpFile , heredoc , debugScript .content , heredoc )
214
+ // convertListOfSidecars does the heavy lifting for convertScripts.
215
+ //
216
+ // It iterates through the list of sidecars, generates the script file name and heredoc termination string,
217
+ // adds an entry to the init container args, sets up the step container to run the script, and sets the volume mounts.
218
+ func convertListOfSidecars (sidecars []v1beta1.Sidecar , initContainer * corev1.Container , namePrefix string ) []corev1.Container {
219
+ containers := []corev1.Container {}
220
+ for i , s := range sidecars {
221
+ c := s .ToK8sContainer ()
222
+ if s .Script != "" {
223
+ placeScriptInContainer (s .Script , getScriptFile (scriptsDir , fmt .Sprintf ("%s-%d" , namePrefix , i )), c , initContainer )
227
224
}
225
+ containers = append (containers , * c )
228
226
}
227
+ return containers
228
+ }
229
229
230
+ // convertListOfSteps does the heavy lifting for convertScripts.
231
+ //
232
+ // It iterates through the list of steps, generates the script file name and heredoc termination string,
233
+ // adds an entry to the init container args, sets up the step container to run the script, and sets the volume mounts.
234
+ func convertListOfSteps (steps []v1beta1.Step , initContainer * corev1.Container , breakpoints []string , namePrefix string ) []corev1.Container {
235
+ containers := []corev1.Container {}
236
+ for i , s := range steps {
237
+ c := steps [i ].ToK8sContainer ()
238
+ if s .Script != "" {
239
+ placeScriptInContainer (s .Script , getScriptFile (scriptsDir , fmt .Sprintf ("%s-%d" , namePrefix , i )), c , initContainer )
240
+ }
241
+ containers = append (containers , * c )
242
+ }
243
+ if len (breakpoints ) > 0 {
244
+ placeDebugScriptInContainers (containers , initContainer )
245
+ }
230
246
return containers
231
247
}
232
248
249
+ func getScriptFile (scriptsDir , scriptName string ) string {
250
+ return filepath .Join (scriptsDir , names .SimpleNameGenerator .RestrictLengthWithRandomSuffix (scriptName ))
251
+ }
252
+
233
253
// encodeScript encodes a script field into a format that avoids kubernetes' built-in processing of container args,
234
254
// which can mangle dollar signs and unexpectedly replace variable references in the user's script.
235
255
func encodeScript (script string ) string {
0 commit comments