github.com/GoogleContainerTools/skaffold@v1.39.18/pkg/skaffold/docker/debugger/adapter.go (about) 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 17 package debugger 18 19 import ( 20 "context" 21 "fmt" 22 "strconv" 23 "strings" 24 25 "github.com/docker/docker/api/types/container" 26 "github.com/docker/go-connections/nat" 27 28 "github.com/GoogleContainerTools/skaffold/pkg/skaffold/debug/types" 29 "github.com/GoogleContainerTools/skaffold/pkg/skaffold/output/log" 30 ) 31 32 type DockerAdapter struct { 33 cfg *container.Config 34 executable *types.ExecutableContainer 35 } 36 37 func NewAdapter(cfg *container.Config) *DockerAdapter { 38 return &DockerAdapter{ 39 cfg: cfg, 40 executable: ExecutableContainerForConfig(cfg), 41 } 42 } 43 44 func (d *DockerAdapter) GetContainer() *types.ExecutableContainer { 45 return d.executable 46 } 47 48 func ExecutableContainerForConfig(cfg *container.Config) *types.ExecutableContainer { 49 return &types.ExecutableContainer{ 50 Name: cfg.Image, 51 Command: cfg.Cmd, 52 Env: dockerEnvToContainerEnv(cfg.Env), 53 Ports: dockerPortsToContainerPorts(cfg.ExposedPorts), 54 } 55 } 56 57 // Apply transfers the configuration changes from the intermediate container 58 // to the underlying container config. 59 // Since container.Config doesn't have an Args field, we use the 60 // ExecutableContainer Command as the Entrypoint, or the Args as the Cmd. 61 // Note: these are mutually exclusive transformations. 62 func (d *DockerAdapter) Apply() { 63 if len(d.executable.Command) > 0 { 64 d.cfg.Entrypoint = d.executable.Command 65 } 66 if len(d.executable.Args) > 0 { 67 d.cfg.Cmd = d.executable.Args 68 } 69 d.cfg.Env = containerEnvToDockerEnv(d.executable.Env) 70 d.cfg.ExposedPorts = containerPortsToDockerPorts(d.executable.Ports) 71 } 72 73 func dockerEnvToContainerEnv(dockerEnv []string) types.ContainerEnv { 74 env := make(map[string]string, len(dockerEnv)) 75 var order []string 76 for _, entry := range dockerEnv { 77 parts := strings.SplitN(entry, "=", 2) // split to max 2 substrings, `=` is a valid character in the env value 78 if len(parts) != 2 { 79 log.Entry(context.TODO()).Warnf("malformed env entry %s: skipping", entry) 80 continue 81 } 82 order = append(order, parts[0]) 83 env[parts[0]] = parts[1] 84 } 85 return types.ContainerEnv{ 86 Order: order, 87 Env: env, 88 } 89 } 90 91 func containerEnvToDockerEnv(env types.ContainerEnv) []string { 92 var dockerEnv []string 93 for _, k := range env.Order { 94 dockerEnv = append(dockerEnv, fmt.Sprintf("%s=%s", k, env.Env[k])) 95 } 96 return dockerEnv 97 } 98 99 func dockerPortsToContainerPorts(ports nat.PortSet) []types.ContainerPort { 100 var containerPorts []types.ContainerPort 101 for k := range ports { 102 // net.Port is a typecast of a string 103 containerPorts = append(containerPorts, types.ContainerPort{ 104 Name: string(k), 105 ContainerPort: int32(k.Int()), 106 Protocol: k.Proto(), 107 }) 108 } 109 return containerPorts 110 } 111 112 func containerPortsToDockerPorts(containerPorts []types.ContainerPort) nat.PortSet { 113 dockerPorts := make(nat.PortSet, len(containerPorts)) 114 for _, port := range containerPorts { 115 portStr := strconv.Itoa(int(port.ContainerPort)) 116 dockerPort, err := nat.NewPort(port.Protocol, portStr) 117 if err != nil { 118 log.Entry(context.TODO()).Warnf("error translating port %s - debug might not work correctly!", portStr) 119 } 120 dockerPorts[dockerPort] = struct{}{} 121 } 122 return dockerPorts 123 }