github.com/khulnasoft-lab/khulnasoft@v26.0.1-0.20240328202558-330a6f959fe0+incompatible/builder/builder-next/executor_linux.go (about)

     1  package buildkit
     2  
     3  import (
     4  	"context"
     5  	"net"
     6  	"os"
     7  	"path/filepath"
     8  	"strconv"
     9  	"sync"
    10  
    11  	"github.com/containerd/log"
    12  	"github.com/docker/docker/daemon/config"
    13  	"github.com/docker/docker/libnetwork"
    14  	"github.com/docker/docker/pkg/idtools"
    15  	"github.com/docker/docker/pkg/stringid"
    16  	"github.com/moby/buildkit/executor"
    17  	"github.com/moby/buildkit/executor/oci"
    18  	"github.com/moby/buildkit/executor/resources"
    19  	resourcestypes "github.com/moby/buildkit/executor/resources/types"
    20  	"github.com/moby/buildkit/executor/runcexecutor"
    21  	"github.com/moby/buildkit/identity"
    22  	"github.com/moby/buildkit/solver/pb"
    23  	"github.com/moby/buildkit/util/network"
    24  	specs "github.com/opencontainers/runtime-spec/specs-go"
    25  )
    26  
    27  const networkName = "bridge"
    28  
    29  func newExecutor(root, cgroupParent string, net *libnetwork.Controller, dnsConfig *oci.DNSConfig, rootless bool, idmap idtools.IdentityMapping, apparmorProfile string) (executor.Executor, error) {
    30  	netRoot := filepath.Join(root, "net")
    31  	networkProviders := map[pb.NetMode]network.Provider{
    32  		pb.NetMode_UNSET: &bridgeProvider{Controller: net, Root: netRoot},
    33  		pb.NetMode_HOST:  network.NewHostProvider(),
    34  		pb.NetMode_NONE:  network.NewNoneProvider(),
    35  	}
    36  
    37  	// make sure net state directory is cleared from previous state
    38  	fis, err := os.ReadDir(netRoot)
    39  	if err == nil {
    40  		for _, fi := range fis {
    41  			fp := filepath.Join(netRoot, fi.Name())
    42  			if err := os.RemoveAll(fp); err != nil {
    43  				log.G(context.TODO()).WithError(err).Errorf("failed to delete old network state: %v", fp)
    44  			}
    45  		}
    46  	}
    47  
    48  	// Returning a non-nil but empty *IdentityMapping breaks BuildKit:
    49  	// https://github.com/moby/moby/pull/39444
    50  	pidmap := &idmap
    51  	if idmap.Empty() {
    52  		pidmap = nil
    53  	}
    54  
    55  	rm, err := resources.NewMonitor()
    56  	if err != nil {
    57  		return nil, err
    58  	}
    59  
    60  	runcCmds := []string{"runc"}
    61  
    62  	// TODO: FIXME: testing env var, replace with something better or remove in a major version or two
    63  	if runcOverride := os.Getenv("DOCKER_BUILDKIT_RUNC_COMMAND"); runcOverride != "" {
    64  		runcCmds = []string{runcOverride}
    65  	}
    66  
    67  	return runcexecutor.New(runcexecutor.Opt{
    68  		Root:                filepath.Join(root, "executor"),
    69  		CommandCandidates:   runcCmds,
    70  		DefaultCgroupParent: cgroupParent,
    71  		Rootless:            rootless,
    72  		NoPivot:             os.Getenv("DOCKER_RAMDISK") != "",
    73  		IdentityMapping:     pidmap,
    74  		DNS:                 dnsConfig,
    75  		ApparmorProfile:     apparmorProfile,
    76  		ResourceMonitor:     rm,
    77  	}, networkProviders)
    78  }
    79  
    80  type bridgeProvider struct {
    81  	*libnetwork.Controller
    82  	Root string
    83  }
    84  
    85  func (p *bridgeProvider) New(ctx context.Context, hostname string) (network.Namespace, error) {
    86  	n, err := p.NetworkByName(networkName)
    87  	if err != nil {
    88  		return nil, err
    89  	}
    90  
    91  	iface := &lnInterface{ready: make(chan struct{}), provider: p}
    92  	iface.Once.Do(func() {
    93  		go iface.init(p.Controller, n)
    94  	})
    95  
    96  	return iface, nil
    97  }
    98  
    99  func (p *bridgeProvider) Close() error {
   100  	return nil
   101  }
   102  
   103  type lnInterface struct {
   104  	ep  *libnetwork.Endpoint
   105  	sbx *libnetwork.Sandbox
   106  	sync.Once
   107  	err      error
   108  	ready    chan struct{}
   109  	provider *bridgeProvider
   110  }
   111  
   112  func (iface *lnInterface) init(c *libnetwork.Controller, n *libnetwork.Network) {
   113  	defer close(iface.ready)
   114  	id := identity.NewID()
   115  
   116  	ep, err := n.CreateEndpoint(id, libnetwork.CreateOptionDisableResolution())
   117  	if err != nil {
   118  		iface.err = err
   119  		return
   120  	}
   121  
   122  	sbx, err := c.NewSandbox(id, libnetwork.OptionUseExternalKey(), libnetwork.OptionHostsPath(filepath.Join(iface.provider.Root, id, "hosts")),
   123  		libnetwork.OptionResolvConfPath(filepath.Join(iface.provider.Root, id, "resolv.conf")))
   124  	if err != nil {
   125  		iface.err = err
   126  		return
   127  	}
   128  
   129  	if err := ep.Join(sbx); err != nil {
   130  		iface.err = err
   131  		return
   132  	}
   133  
   134  	iface.sbx = sbx
   135  	iface.ep = ep
   136  }
   137  
   138  // TODO(neersighted): Unstub Sample(), and collect data from the libnetwork Endpoint.
   139  func (iface *lnInterface) Sample() (*resourcestypes.NetworkSample, error) {
   140  	return &resourcestypes.NetworkSample{}, nil
   141  }
   142  
   143  func (iface *lnInterface) Set(s *specs.Spec) error {
   144  	<-iface.ready
   145  	if iface.err != nil {
   146  		log.G(context.TODO()).WithError(iface.err).Error("failed to set networking spec")
   147  		return iface.err
   148  	}
   149  	shortNetCtlrID := stringid.TruncateID(iface.provider.Controller.ID())
   150  	// attach netns to bridge within the container namespace, using reexec in a prestart hook
   151  	s.Hooks = &specs.Hooks{
   152  		Prestart: []specs.Hook{{
   153  			Path: filepath.Join("/proc", strconv.Itoa(os.Getpid()), "exe"),
   154  			Args: []string{"libnetwork-setkey", "-exec-root=" + iface.provider.Config().ExecRoot, iface.sbx.ContainerID(), shortNetCtlrID},
   155  		}},
   156  	}
   157  	return nil
   158  }
   159  
   160  func (iface *lnInterface) Close() error {
   161  	<-iface.ready
   162  	if iface.sbx != nil {
   163  		go func() {
   164  			if err := iface.sbx.Delete(); err != nil {
   165  				log.G(context.TODO()).WithError(err).Errorf("failed to delete builder network sandbox")
   166  			}
   167  			if err := os.RemoveAll(filepath.Join(iface.provider.Root, iface.sbx.ContainerID())); err != nil {
   168  				log.G(context.TODO()).WithError(err).Errorf("failed to delete builder sandbox directory")
   169  			}
   170  		}()
   171  	}
   172  	return iface.err
   173  }
   174  
   175  func getDNSConfig(cfg config.DNSConfig) *oci.DNSConfig {
   176  	if cfg.DNS != nil || cfg.DNSSearch != nil || cfg.DNSOptions != nil {
   177  		return &oci.DNSConfig{
   178  			Nameservers:   ipAddresses(cfg.DNS),
   179  			SearchDomains: cfg.DNSSearch,
   180  			Options:       cfg.DNSOptions,
   181  		}
   182  	}
   183  	return nil
   184  }
   185  
   186  func ipAddresses(ips []net.IP) []string {
   187  	var addrs []string
   188  	for _, ip := range ips {
   189  		addrs = append(addrs, ip.String())
   190  	}
   191  	return addrs
   192  }