1
+ /*
2
+ Copyright 2021 The Skaffold Authors
3
+
4
+ Licensed under the Apache License, Version 2.0 (the "License");
5
+ you may not use this file except in compliance with the License.
6
+ You may obtain a copy of the License at
7
+
8
+ http://www.apache.org/licenses/LICENSE-2.0
9
+
10
+ Unless required by applicable law or agreed to in writing, software
11
+ distributed under the License is distributed on an "AS IS" BASIS,
12
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ See the License for the specific language governing permissions and
14
+ limitations under the License.
15
+ */
16
+
1
17
package debug
2
18
3
19
import (
4
20
"fmt"
5
21
6
- "github.com/GoogleContainerTools/skaffold/pkg/skaffold/debug/annotations"
7
22
shell "github.com/kballard/go-shellquote"
8
23
"github.com/sirupsen/logrus"
9
24
v1 "k8s.io/api/core/v1"
10
25
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
11
- )
12
-
13
- type operableContainer struct {
14
- Name string
15
- Command []string
16
- Args []string
17
- Env containerEnv
18
- Ports []containerPort
19
- }
20
26
21
- // adapted from github.com/kubernetes/api/core/v1/types.go
22
- type containerPort struct {
23
- Name string
24
- HostPort int32
25
- ContainerPort int32
26
- Protocol string
27
- HostIP string
28
- }
29
-
30
- type containerEnv struct {
31
- Order []string
32
- Env map [string ]string
33
- }
27
+ "github.com/GoogleContainerTools/skaffold/pkg/skaffold/debug/annotations"
28
+ "github.com/GoogleContainerTools/skaffold/pkg/skaffold/debug/types"
29
+ "github.com/GoogleContainerTools/skaffold/pkg/skaffold/kubernetes/debugging/adapter"
30
+ )
34
31
35
32
// containerTransforms are the set of configured transformers
36
33
var containerTransforms []containerTransformer
@@ -44,15 +41,17 @@ type containerTransformer interface {
44
41
// and required initContainer (an empty string if not required), or return a non-nil error if
45
42
// the container could not be transformed. The initContainer image is intended to install any
46
43
// required debug support tools.
47
- Apply (container * operableContainer , config imageConfiguration , portAlloc portAllocator , overrideProtocols []string ) (annotations.ContainerDebugConfiguration , string , error )
44
+ Apply (adapter types. ContainerAdapter , config imageConfiguration , portAlloc portAllocator , overrideProtocols []string ) (annotations.ContainerDebugConfiguration , string , error )
48
45
}
49
46
50
47
// transformContainer rewrites the container definition to enable debugging.
51
48
// Returns a debugging configuration description with associated language runtime support
52
49
// container image, or an error if the rewrite was unsuccessful.
53
- func transformContainer (container * operableContainer , config imageConfiguration , portAlloc portAllocator ) (annotations.ContainerDebugConfiguration , string , error ) {
50
+ func transformContainer (adapter types. ContainerAdapter , config imageConfiguration , portAlloc portAllocator ) (annotations.ContainerDebugConfiguration , string , error ) {
54
51
// Update the image configuration's environment with those set in the k8s manifest.
55
52
// (Environment variables in the k8s container's `env` add to the image configuration's `env` settings rather than replace.)
53
+ container := adapter .GetContainer ()
54
+ defer adapter .Apply ()
56
55
for _ , key := range container .Env .Order {
57
56
// FIXME handle ValueFrom?
58
57
if config .env == nil {
@@ -69,13 +68,13 @@ func transformContainer(container *operableContainer, config imageConfiguration,
69
68
}
70
69
71
70
// Apply command-line unwrapping for buildpack images and images using `sh -c`-style command-lines
72
- next := func (container * operableContainer , config imageConfiguration ) (annotations.ContainerDebugConfiguration , string , error ) {
73
- return performContainerTransform (container , config , portAlloc )
71
+ next := func (adapter types. ContainerAdapter , config imageConfiguration ) (annotations.ContainerDebugConfiguration , string , error ) {
72
+ return performContainerTransform (adapter , config , portAlloc )
74
73
}
75
74
if isCNBImage (config ) {
76
- return updateForCNBImage (container , config , next )
75
+ return updateForCNBImage (adapter , config , next )
77
76
}
78
- return updateForShDashC (container , config , next )
77
+ return updateForShDashC (adapter , config , next )
79
78
}
80
79
81
80
func rewriteContainers (metadata * metav1.ObjectMeta , podSpec * v1.PodSpec , retrieveImageConfiguration configurationRetriever , debugHelpersRegistry string ) bool {
@@ -101,16 +100,15 @@ func rewriteContainers(metadata *metav1.ObjectMeta, podSpec *v1.PodSpec, retriev
101
100
if err != nil {
102
101
continue
103
102
}
104
- operable := operableContainerFromK8sContainer (& container )
103
+ a := adapter . NewAdapter (& container )
105
104
// requiredImage, if not empty, is the image ID providing the debugging support files
106
105
// `err != nil` means that the container did not or could not be transformed
107
- if configuration , requiredImage , err := transformContainer (operable , imageConfig , portAlloc ); err == nil {
106
+ if configuration , requiredImage , err := transformContainer (a , imageConfig , portAlloc ); err == nil {
108
107
configuration .Artifact = imageConfig .artifact
109
108
if configuration .WorkingDir == "" {
110
109
configuration .WorkingDir = imageConfig .workingDir
111
110
}
112
111
configurations [container .Name ] = configuration
113
- applyFromOperable (operable , & container )
114
112
podSpec .Containers [i ] = container // apply any configuration changes
115
113
if len (requiredImage ) > 0 {
116
114
logrus .Infof ("%q requires debugging support image %q" , container .Name , requiredImage )
@@ -156,7 +154,7 @@ func rewriteContainers(metadata *metav1.ObjectMeta, podSpec *v1.PodSpec, retriev
156
154
return false
157
155
}
158
156
159
- func updateForShDashC (container * operableContainer , ic imageConfiguration , transformer func (* operableContainer , imageConfiguration ) (annotations.ContainerDebugConfiguration , string , error )) (annotations.ContainerDebugConfiguration , string , error ) {
157
+ func updateForShDashC (adapter types. ContainerAdapter , ic imageConfiguration , transformer func (types. ContainerAdapter , imageConfiguration ) (annotations.ContainerDebugConfiguration , string , error )) (annotations.ContainerDebugConfiguration , string , error ) {
160
158
var rewriter func ([]string )
161
159
copy := ic
162
160
switch {
@@ -166,6 +164,7 @@ func updateForShDashC(container *operableContainer, ic imageConfiguration, trans
166
164
copy .entrypoint = split
167
165
copy .arguments = nil
168
166
rewriter = func (rewrite []string ) {
167
+ container := adapter .GetContainer ()
169
168
container .Command = nil // inherit from container
170
169
container .Args = append ([]string {shJoin (rewrite )}, ic .arguments [1 :]... )
171
170
}
@@ -177,6 +176,7 @@ func updateForShDashC(container *operableContainer, ic imageConfiguration, trans
177
176
copy .entrypoint = split
178
177
copy .arguments = nil
179
178
rewriter = func (rewrite []string ) {
179
+ container := adapter .GetContainer ()
180
180
container .Command = append ([]string {ic .entrypoint [0 ], ic .entrypoint [1 ], shJoin (rewrite )}, ic .entrypoint [3 :]... )
181
181
}
182
182
}
@@ -187,13 +187,15 @@ func updateForShDashC(container *operableContainer, ic imageConfiguration, trans
187
187
copy .entrypoint = split
188
188
copy .arguments = nil
189
189
rewriter = func (rewrite []string ) {
190
+ container := adapter .GetContainer ()
190
191
container .Command = nil
191
192
container .Args = append ([]string {ic .arguments [0 ], ic .arguments [1 ], shJoin (rewrite )}, ic .arguments [3 :]... )
192
193
}
193
194
}
194
195
}
195
196
196
- c , image , err := transformer (container , copy )
197
+ c , image , err := transformer (adapter , copy )
198
+ container := adapter .GetContainer ()
197
199
if err == nil && rewriter != nil && container .Command != nil {
198
200
rewriter (container .Command )
199
201
}
@@ -204,87 +206,12 @@ func isShDashC(cmd, arg string) bool {
204
206
return (cmd == "/bin/sh" || cmd == "/bin/bash" ) && arg == "-c"
205
207
}
206
208
207
- func performContainerTransform (container * operableContainer , config imageConfiguration , portAlloc portAllocator ) (annotations.ContainerDebugConfiguration , string , error ) {
208
- logrus .Tracef ("Examining container %q with config %v" , container .Name , config )
209
+ func performContainerTransform (adapter types. ContainerAdapter , config imageConfiguration , portAlloc portAllocator ) (annotations.ContainerDebugConfiguration , string , error ) {
210
+ logrus .Tracef ("Examining container %q with config %v" , adapter . GetContainer () .Name , config )
209
211
for _ , transform := range containerTransforms {
210
212
if transform .IsApplicable (config ) {
211
- return transform .Apply (container , config , portAlloc , Protocols )
213
+ return transform .Apply (adapter , config , portAlloc , Protocols )
212
214
}
213
215
}
214
- return annotations.ContainerDebugConfiguration {}, "" , fmt .Errorf ("unable to determine runtime for %q" , container .Name )
215
- }
216
-
217
- // operableContainerFromK8sContainer creates an instance of an operableContainer
218
- // from a v1.Container reference. This object will be passed around to accept
219
- // transforms, and will eventually overwrite fields from the creating v1.Container
220
- // in the manifest-under-transformation's pod spec.
221
- func operableContainerFromK8sContainer (c * v1.Container ) * operableContainer {
222
- return & operableContainer {
223
- Command : c .Command ,
224
- Args : c .Args ,
225
- Env : k8sEnvToContainerEnv (c .Env ),
226
- Ports : k8sPortsToContainerPorts (c .Ports ),
227
- }
228
- }
229
-
230
- func k8sEnvToContainerEnv (k8sEnv []v1.EnvVar ) containerEnv {
231
- // TODO(nkubala): ValueFrom is ignored. Do we care?
232
- env := make (map [string ]string , len (k8sEnv ))
233
- var order []string
234
- for _ , entry := range k8sEnv {
235
- order = append (order , entry .Name )
236
- env [entry .Name ] = entry .Value
237
- }
238
- return containerEnv {
239
- Order : order ,
240
- Env : env ,
241
- }
242
- }
243
-
244
- func containerEnvToK8sEnv (env containerEnv ) []v1.EnvVar {
245
- var k8sEnv []v1.EnvVar
246
- for _ , k := range env .Order {
247
- k8sEnv = append (k8sEnv , v1.EnvVar {
248
- Name : k ,
249
- Value : env .Env [k ],
250
- })
251
- }
252
- return k8sEnv
253
- }
254
-
255
- func k8sPortsToContainerPorts (k8sPorts []v1.ContainerPort ) []containerPort {
256
- var containerPorts []containerPort
257
- for _ , port := range k8sPorts {
258
- containerPorts = append (containerPorts , containerPort {
259
- Name : port .Name ,
260
- HostPort : port .HostPort ,
261
- ContainerPort : port .ContainerPort ,
262
- Protocol : string (port .Protocol ),
263
- HostIP : port .HostIP ,
264
- })
265
- }
266
- return containerPorts
267
- }
268
-
269
- func containerPortsToK8sPorts (containerPorts []containerPort ) []v1.ContainerPort {
270
- var k8sPorts []v1.ContainerPort
271
- for _ , port := range containerPorts {
272
- k8sPorts = append (k8sPorts , v1.ContainerPort {
273
- Name : port .Name ,
274
- HostPort : port .HostPort ,
275
- ContainerPort : port .ContainerPort ,
276
- Protocol : v1 .Protocol (port .Protocol ),
277
- HostIP : port .HostIP ,
278
- })
279
- }
280
- return k8sPorts
281
- }
282
-
283
- // applyFromOperable takes the relevant fields from the operable container
284
- // and applies them to the referenced v1.Container from the manifest's pod spec
285
- func applyFromOperable (o * operableContainer , c * v1.Container ) {
286
- c .Args = o .Args
287
- c .Command = o .Command
288
- c .Env = containerEnvToK8sEnv (o .Env )
289
- c .Ports = containerPortsToK8sPorts (o .Ports )
216
+ return annotations.ContainerDebugConfiguration {}, "" , fmt .Errorf ("unable to determine runtime for %q" , adapter .GetContainer ().Name )
290
217
}
0 commit comments