github.com/GoogleContainerTools/skaffold@v1.39.18/pkg/skaffold/docker/debugger/transform.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  
    23  	"github.com/docker/docker/api/types/container"
    24  	"github.com/docker/docker/api/types/volume"
    25  
    26  	"github.com/GoogleContainerTools/skaffold/pkg/skaffold/debug"
    27  	"github.com/GoogleContainerTools/skaffold/pkg/skaffold/debug/types"
    28  	"github.com/GoogleContainerTools/skaffold/pkg/skaffold/graph"
    29  	"github.com/GoogleContainerTools/skaffold/pkg/skaffold/output/log"
    30  	"github.com/GoogleContainerTools/skaffold/pkg/skaffold/util"
    31  )
    32  
    33  var (
    34  	SupportVolumeMount = volume.VolumeCreateBody{Name: debug.DebuggingSupportFilesVolume}
    35  	TransformImage     = transformImage // For testing
    36  )
    37  
    38  type Transform func(string) string
    39  
    40  func transformImage(ctx context.Context, artifact graph.Artifact, cfg *container.Config, insecureRegistries map[string]bool, debugHelpersRegistry string) (map[string]types.ContainerDebugConfiguration, []*container.Config, error) {
    41  	portAvailable := func(port int32) bool {
    42  		return isPortAvailable(cfg, port)
    43  	}
    44  	portAlloc := func(desiredPort int32) int32 {
    45  		return util.AllocatePort(portAvailable, desiredPort)
    46  	}
    47  
    48  	adapter := NewAdapter(cfg)
    49  	imageConfig, err := debug.RetrieveImageConfiguration(ctx, &artifact, insecureRegistries)
    50  	if err != nil {
    51  		return nil, nil, err
    52  	}
    53  
    54  	configurations := make(map[string]types.ContainerDebugConfiguration)
    55  	var initContainers []*container.Config
    56  	// the container images that require debugging support files
    57  	var containersRequiringSupport []*container.Config
    58  	// the set of image IDs required to provide debugging support files
    59  	requiredSupportImages := make(map[string]bool)
    60  
    61  	if configuration, requiredImage, err := debug.TransformContainer(adapter, imageConfig, portAlloc); err == nil {
    62  		configurations[adapter.GetContainer().Name] = configuration
    63  		if len(requiredImage) > 0 {
    64  			log.Entry(ctx).Infof("%q requires debugging support image %q", cfg.Image, requiredImage)
    65  			containersRequiringSupport = append(containersRequiringSupport, cfg)
    66  			requiredSupportImages[requiredImage] = true
    67  		}
    68  	} else {
    69  		log.Entry(ctx).Warnf("Image %q not configured for debugging: %v", cfg.Image, err)
    70  	}
    71  
    72  	// check if we have any images requiring additional debugging support files
    73  	if len(containersRequiringSupport) > 0 {
    74  		log.Entry(ctx).Infof("Configuring installation of debugging support files")
    75  		// the initContainers are responsible for populating the contents of `/dbg`
    76  		for imageID := range requiredSupportImages {
    77  			supportFilesInitContainer := &container.Config{
    78  				Image:   fmt.Sprintf("%s/%s", debugHelpersRegistry, imageID),
    79  				Volumes: map[string]struct{}{"/dbg": {}},
    80  			}
    81  			initContainers = append(initContainers, supportFilesInitContainer)
    82  		}
    83  		// the populated volume is then mounted in the containers at `/dbg` too
    84  		for _, container := range containersRequiringSupport {
    85  			if container.Volumes == nil {
    86  				container.Volumes = make(map[string]struct{})
    87  			}
    88  			container.Volumes["/dbg"] = struct{}{}
    89  		}
    90  	}
    91  
    92  	return configurations, initContainers, nil
    93  }
    94  
    95  // isPortAvailable returns true if none of the pod's containers specify the given port.
    96  func isPortAvailable(cfg *container.Config, port int32) bool {
    97  	for exposedPort := range cfg.ExposedPorts {
    98  		if int32(exposedPort.Int()) == port {
    99  			return false
   100  		}
   101  	}
   102  	return true
   103  }