@@ -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,144 +94,159 @@ 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,
113
+ // convertListOfSidecars iterates through the list of sidecars, generates the script file name and heredoc termination string,
129
114
// 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 {
115
+ func convertListOfSidecars ( sidecars []v1beta1.Sidecar , initContainer * corev1.Container , namePrefix string ) []corev1.Container {
131
116
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 )
117
+ for i , s := range sidecars {
118
+ c := s .ToK8sContainer ()
119
+ if s .Script != "" {
120
+ placeScriptInContainer (s .Script , getScriptFile (scriptsDir , fmt .Sprintf ("%s-%d" , namePrefix , i )), c , initContainer )
140
121
}
122
+ containers = append (containers , * c )
123
+ }
124
+ return containers
125
+ }
141
126
142
- if s .Script == "" {
143
- // Nothing to convert.
144
- containers = append (containers , * steps [i ].ToK8sContainer ())
145
- continue
127
+ // convertListOfSteps iterates through the list of steps, generates the script file name and heredoc termination string,
128
+ // adds an entry to the init container args, sets up the step container to run the script, and sets the volume mounts.
129
+ func convertListOfSteps (steps []v1beta1.Step , initContainer * corev1.Container , breakpoints []string , namePrefix string ) []corev1.Container {
130
+ containers := []corev1.Container {}
131
+ for i , s := range steps {
132
+ c := steps [i ].ToK8sContainer ()
133
+ if s .Script != "" {
134
+ placeScriptInContainer (s .Script , getScriptFile (scriptsDir , fmt .Sprintf ("%s-%d" , namePrefix , i )), c , initContainer )
146
135
}
136
+ containers = append (containers , * c )
137
+ }
138
+ if len (breakpoints ) > 0 {
139
+ placeDebugScriptInContainers (containers , initContainer )
140
+ }
141
+ return containers
142
+ }
147
143
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" )
144
+ func getScriptFile (scriptsDir , scriptName string ) string {
145
+ return filepath .Join (scriptsDir , names .SimpleNameGenerator .RestrictLengthWithRandomSuffix (scriptName ))
146
+ }
153
147
154
- script := s .Script
155
- if ! hasShebang {
156
- script = defaultScriptPreamble + s .Script
157
- }
148
+ // placeScriptInContainer given a piece of script to be executed, placeScriptInContainer firstly modifies initContainer
149
+ // so that it capsules the target script into scriptFile, then it modifies the container so that it can execute the scriptFile
150
+ // in runtime.
151
+ func placeScriptInContainer (script , scriptFile string , c * corev1.Container , initContainer * corev1.Container ) {
152
+ if script == "" {
153
+ return
154
+ }
155
+ cleaned := strings .TrimSpace (script )
156
+ hasShebang := strings .HasPrefix (cleaned , "#!" )
157
+ requiresWindows := strings .HasPrefix (cleaned , "#!win" )
158
158
159
- // At least one step uses a script, so we should return a
160
- // non-nil init container.
161
- * placeScripts = true
159
+ if ! hasShebang {
160
+ script = defaultScriptPreamble + script
161
+ }
162
162
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 (`@"
163
+ // Append to the place-scripts script to place the
164
+ // script file in a known location in the scripts volume.
165
+ if requiresWindows {
166
+ command , args , script , scriptFile := extractWindowsScriptComponents (script , scriptFile )
167
+ initContainer .Args [1 ] += fmt .Sprintf (`@"
169
168
%s
170
169
"@ | Out-File -FilePath %s
171
170
` , script , scriptFile )
172
171
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"
172
+ c .Command = command
173
+ // Append existing args field to end of derived args
174
+ args = append (args , c .Args ... )
175
+ c .Args = args
176
+ } else {
177
+ // Only encode the script for linux scripts
178
+ // The decode-script subcommand of the entrypoint does not work under windows
179
+ script = encodeScript (script )
180
+ heredoc := "_EOF_" // underscores because base64 doesn't include them in its alphabet
181
+ initContainer .Args [1 ] += fmt .Sprintf (`scriptfile="%s"
183
182
touch ${scriptfile} && chmod +x ${scriptfile}
184
183
cat > ${scriptfile} << '%s'
185
184
%s
186
185
%s
187
186
/tekton/bin/entrypoint decode-script "${scriptfile}"
188
187
` , scriptFile , heredoc , script , heredoc )
189
188
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 )
198
-
199
- containers = append (containers , * steps [i ].ToK8sContainer ())
189
+ // Set the command to execute the correct script in the mounted volume.
190
+ // A previous merge with stepTemplate may have populated
191
+ // Command and Args, even though this is not normally valid, so
192
+ // we'll clear out the Args and overwrite Command.
193
+ c .Command = []string {scriptFile }
200
194
}
195
+ c .VolumeMounts = append (c .VolumeMounts , scriptsVolumeMount )
196
+ }
201
197
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
198
+ // encodeScript encodes a script field into a format that avoids kubernetes' built-in processing of container args,
199
+ // which can mangle dollar signs and unexpectedly replace variable references in the user's script.
200
+ func encodeScript ( script string ) string {
201
+ return base64 . StdEncoding . EncodeToString ([] byte ( script ))
202
+ }
207
203
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 )
204
+ // placeDebugScriptInContainers inserts debug scripts into containers. It capsules those scripts to files in initContainer,
205
+ // then executes those scripts in target containers.
206
+ func placeDebugScriptInContainers (containers []corev1.Container , initContainer * corev1.Container ) {
207
+ for i := 0 ; i < len (containers ); i ++ {
208
+ debugInfoVolumeMount := corev1.VolumeMount {
209
+ Name : debugInfoVolumeName ,
210
+ MountPath : filepath .Join (debugInfoDir , fmt .Sprintf ("%d" , i )),
227
211
}
212
+ (& containers [i ]).VolumeMounts = append ((& containers [i ]).VolumeMounts , debugScriptsVolumeMount , debugInfoVolumeMount )
228
213
}
229
214
230
- return containers
215
+ type script struct {
216
+ name string
217
+ content string
218
+ }
219
+ debugScripts := []script {{
220
+ name : "continue" ,
221
+ content : defaultScriptPreamble + fmt .Sprintf (debugContinueScriptTemplate , len (containers ), debugInfoDir , RunDir ),
222
+ }, {
223
+ name : "fail-continue" ,
224
+ content : defaultScriptPreamble + fmt .Sprintf (debugFailScriptTemplate , len (containers ), debugInfoDir , RunDir ),
225
+ }}
226
+
227
+ // Add debug or breakpoint related scripts to /tekton/debug/scripts
228
+ // Iterate through the debugScripts and add routine for each of them in the initContainer for their creation
229
+ for _ , debugScript := range debugScripts {
230
+ tmpFile := filepath .Join (debugScriptsDir , fmt .Sprintf ("%s-%s" , "debug" , debugScript .name ))
231
+ heredoc := names .SimpleNameGenerator .RestrictLengthWithRandomSuffix (fmt .Sprintf ("%s-%s-heredoc-randomly-generated" , "debug" , debugScript .name ))
232
+
233
+ initContainer .Args [1 ] += fmt .Sprintf (initScriptDirective , tmpFile , heredoc , debugScript .content , heredoc )
234
+ }
231
235
}
232
236
233
- // encodeScript encodes a script field into a format that avoids kubernetes' built-in processing of container args,
234
- // which can mangle dollar signs and unexpectedly replace variable references in the user's script.
235
- func encodeScript (script string ) string {
236
- return base64 .StdEncoding .EncodeToString ([]byte (script ))
237
+ // hasScripts determines if we need to generate scripts in InitContainer given steps, sidecars and breakpoints.
238
+ func hasScripts (steps []v1beta1.Step , sidecars []v1beta1.Sidecar , breakpoints []string ) bool {
239
+ for _ , s := range steps {
240
+ if s .Script != "" {
241
+ return true
242
+ }
243
+ }
244
+ for _ , s := range sidecars {
245
+ if s .Script != "" {
246
+ return true
247
+ }
248
+ }
249
+ return len (breakpoints ) > 0
237
250
}
238
251
239
252
func checkWindowsRequirement (steps []v1beta1.Step , sidecars []v1beta1.Sidecar ) bool {
0 commit comments