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  }