2021-08-23 13:14:53 +00:00
|
|
|
//go:build !windows
|
2016-01-30 01:08:11 +00:00
|
|
|
|
|
|
|
package libnetwork
|
|
|
|
|
|
|
|
import (
|
2023-06-23 00:33:17 +00:00
|
|
|
"context"
|
2024-01-03 09:10:51 +00:00
|
|
|
"io/fs"
|
2024-01-11 16:44:58 +00:00
|
|
|
"net/netip"
|
2016-01-30 01:08:11 +00:00
|
|
|
"os"
|
|
|
|
"path/filepath"
|
2016-09-10 04:45:03 +00:00
|
|
|
"strings"
|
2016-01-30 01:08:11 +00:00
|
|
|
|
2023-09-13 15:41:45 +00:00
|
|
|
"github.com/containerd/log"
|
2024-01-11 16:44:58 +00:00
|
|
|
"github.com/docker/docker/errdefs"
|
2021-04-06 00:24:47 +00:00
|
|
|
"github.com/docker/docker/libnetwork/etchosts"
|
2024-01-03 09:10:51 +00:00
|
|
|
"github.com/docker/docker/libnetwork/internal/resolvconf"
|
2021-04-06 00:24:47 +00:00
|
|
|
"github.com/docker/docker/libnetwork/types"
|
2024-01-03 09:10:51 +00:00
|
|
|
"github.com/pkg/errors"
|
2016-01-30 01:08:11 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
const (
|
|
|
|
defaultPrefix = "/var/lib/docker/network/files"
|
2022-10-01 23:02:22 +00:00
|
|
|
dirPerm = 0o755
|
|
|
|
filePerm = 0o644
|
2023-08-09 18:07:19 +00:00
|
|
|
|
|
|
|
resolverIPSandbox = "127.0.0.11"
|
2016-01-30 01:08:11 +00:00
|
|
|
)
|
|
|
|
|
2024-01-11 16:44:58 +00:00
|
|
|
// finishInitDNS is to be called after the container namespace has been created,
|
|
|
|
// before it the user process is started. The container's support for IPv6 can be
|
|
|
|
// determined at this point.
|
|
|
|
func (sb *Sandbox) finishInitDNS() error {
|
|
|
|
if err := sb.buildHostsFile(); err != nil {
|
|
|
|
return errdefs.System(err)
|
|
|
|
}
|
|
|
|
for _, ep := range sb.Endpoints() {
|
|
|
|
if err := sb.updateHostsFile(ep.getEtcHostsAddrs()); err != nil {
|
|
|
|
return errdefs.System(err)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2023-01-12 01:10:09 +00:00
|
|
|
func (sb *Sandbox) startResolver(restore bool) {
|
2016-01-30 01:08:11 +00:00
|
|
|
sb.resolverOnce.Do(func() {
|
|
|
|
var err error
|
2023-10-09 23:13:25 +00:00
|
|
|
// The resolver is started with proxyDNS=false if the sandbox does not currently
|
|
|
|
// have a gateway. So, if the Sandbox is only connected to an 'internal' network,
|
|
|
|
// it will not forward DNS requests to external resolvers. The resolver's
|
|
|
|
// proxyDNS setting is then updated as network Endpoints are added/removed.
|
|
|
|
sb.resolver = NewResolver(resolverIPSandbox, sb.getGatewayEndpoint() != nil, sb)
|
2016-01-30 01:08:11 +00:00
|
|
|
defer func() {
|
|
|
|
if err != nil {
|
|
|
|
sb.resolver = nil
|
|
|
|
}
|
|
|
|
}()
|
|
|
|
|
2016-06-09 23:05:11 +00:00
|
|
|
// In the case of live restore container is already running with
|
|
|
|
// right resolv.conf contents created before. Just update the
|
|
|
|
// external DNS servers from the restored sandbox for embedded
|
|
|
|
// server to use.
|
|
|
|
if !restore {
|
|
|
|
err = sb.rebuildDNS()
|
|
|
|
if err != nil {
|
2023-06-23 00:33:17 +00:00
|
|
|
log.G(context.TODO()).Errorf("Updating resolv.conf failed for container %s, %q", sb.ContainerID(), err)
|
2016-06-09 23:05:11 +00:00
|
|
|
return
|
|
|
|
}
|
2016-01-30 01:08:11 +00:00
|
|
|
}
|
|
|
|
sb.resolver.SetExtServers(sb.extDNS)
|
|
|
|
|
2016-09-21 20:38:29 +00:00
|
|
|
if err = sb.osSbox.InvokeFunc(sb.resolver.SetupFunc(0)); err != nil {
|
2023-06-23 00:33:17 +00:00
|
|
|
log.G(context.TODO()).Errorf("Resolver Setup function failed for container %s, %q", sb.ContainerID(), err)
|
2016-09-21 20:38:29 +00:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2016-01-30 01:08:11 +00:00
|
|
|
if err = sb.resolver.Start(); err != nil {
|
2023-06-23 00:33:17 +00:00
|
|
|
log.G(context.TODO()).Errorf("Resolver Start failed for container %s, %q", sb.ContainerID(), err)
|
2016-01-30 01:08:11 +00:00
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2023-01-12 01:10:09 +00:00
|
|
|
func (sb *Sandbox) setupResolutionFiles() error {
|
2024-01-11 16:44:58 +00:00
|
|
|
// Create a hosts file that can be mounted during container setup. For most
|
|
|
|
// networking modes (not host networking) it will be re-created before the
|
|
|
|
// container start, once its support for IPv6 is known.
|
|
|
|
if sb.config.hostsPath == "" {
|
|
|
|
sb.config.hostsPath = defaultPrefix + "/" + sb.id + "/hosts"
|
|
|
|
}
|
|
|
|
dir, _ := filepath.Split(sb.config.hostsPath)
|
|
|
|
if err := createBasePath(dir); err != nil {
|
2016-01-30 01:08:11 +00:00
|
|
|
return err
|
|
|
|
}
|
2024-01-11 16:44:58 +00:00
|
|
|
if err := sb.buildHostsFile(); err != nil {
|
2016-01-30 01:08:11 +00:00
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2017-09-20 15:57:02 +00:00
|
|
|
return sb.setupDNS()
|
2016-01-30 01:08:11 +00:00
|
|
|
}
|
|
|
|
|
2023-01-12 01:10:09 +00:00
|
|
|
func (sb *Sandbox) buildHostsFile() error {
|
2024-01-03 09:10:51 +00:00
|
|
|
sb.restoreHostsPath()
|
|
|
|
|
|
|
|
dir, _ := filepath.Split(sb.config.hostsPath)
|
|
|
|
if err := createBasePath(dir); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2016-01-30 01:08:11 +00:00
|
|
|
// This is for the host mode networking
|
2018-07-17 00:35:03 +00:00
|
|
|
if sb.config.useDefaultSandBox && len(sb.config.extraHosts) == 0 {
|
|
|
|
// We are working under the assumption that the origin file option had been properly expressed by the upper layer
|
|
|
|
// if not here we are going to error out
|
2016-01-30 01:08:11 +00:00
|
|
|
if err := copyFile(sb.config.originHostsPath, sb.config.hostsPath); err != nil && !os.IsNotExist(err) {
|
|
|
|
return types.InternalErrorf("could not copy source hosts file %s to %s: %v", sb.config.originHostsPath, sb.config.hostsPath, err)
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
extraContent := make([]etchosts.Record, 0, len(sb.config.extraHosts))
|
|
|
|
for _, extraHost := range sb.config.extraHosts {
|
|
|
|
extraContent = append(extraContent, etchosts.Record{Hosts: extraHost.name, IP: extraHost.IP})
|
|
|
|
}
|
|
|
|
|
2024-01-11 16:44:58 +00:00
|
|
|
// Assume IPv6 support, unless it's definitely disabled.
|
|
|
|
buildf := etchosts.Build
|
|
|
|
if en, ok := sb.ipv6Enabled(); ok && !en {
|
|
|
|
buildf = etchosts.BuildNoIPv6
|
|
|
|
}
|
2024-01-29 15:24:52 +00:00
|
|
|
if err := buildf(sb.config.hostsPath, extraContent); err != nil {
|
2024-01-11 16:44:58 +00:00
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
return sb.updateParentHosts()
|
2016-01-30 01:08:11 +00:00
|
|
|
}
|
|
|
|
|
2023-01-12 01:10:09 +00:00
|
|
|
func (sb *Sandbox) updateHostsFile(ifaceIPs []string) error {
|
2021-05-28 00:15:56 +00:00
|
|
|
if len(ifaceIPs) == 0 {
|
2016-05-01 03:47:24 +00:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2016-01-30 01:08:11 +00:00
|
|
|
if sb.config.originHostsPath != "" {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2016-12-09 13:25:46 +00:00
|
|
|
// User might have provided a FQDN in hostname or split it across hostname
|
|
|
|
// and domainname. We want the FQDN and the bare hostname.
|
|
|
|
fqdn := sb.config.hostName
|
2016-01-30 01:08:11 +00:00
|
|
|
if sb.config.domainName != "" {
|
2022-11-01 11:50:18 +00:00
|
|
|
fqdn += "." + sb.config.domainName
|
2016-12-09 13:25:46 +00:00
|
|
|
}
|
2022-11-01 11:50:18 +00:00
|
|
|
hosts := fqdn
|
2016-12-09 13:25:46 +00:00
|
|
|
|
2022-11-01 11:50:18 +00:00
|
|
|
if hostName, _, ok := strings.Cut(fqdn, "."); ok {
|
|
|
|
hosts += " " + hostName
|
2016-01-30 01:08:11 +00:00
|
|
|
}
|
|
|
|
|
2019-08-30 21:22:46 +00:00
|
|
|
var extraContent []etchosts.Record
|
|
|
|
for _, ip := range ifaceIPs {
|
2022-11-01 11:50:18 +00:00
|
|
|
extraContent = append(extraContent, etchosts.Record{Hosts: hosts, IP: ip})
|
2019-08-30 21:22:46 +00:00
|
|
|
}
|
2016-01-30 01:08:11 +00:00
|
|
|
|
|
|
|
sb.addHostsEntries(extraContent)
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2023-01-12 01:10:09 +00:00
|
|
|
func (sb *Sandbox) addHostsEntries(recs []etchosts.Record) {
|
2024-01-11 16:44:58 +00:00
|
|
|
// Assume IPv6 support, unless it's definitely disabled.
|
|
|
|
if en, ok := sb.ipv6Enabled(); ok && !en {
|
|
|
|
var filtered []etchosts.Record
|
|
|
|
for _, rec := range recs {
|
|
|
|
if addr, err := netip.ParseAddr(rec.IP); err == nil && !addr.Is6() {
|
|
|
|
filtered = append(filtered, rec)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
recs = filtered
|
|
|
|
}
|
2016-01-30 01:08:11 +00:00
|
|
|
if err := etchosts.Add(sb.config.hostsPath, recs); err != nil {
|
2023-06-23 00:33:17 +00:00
|
|
|
log.G(context.TODO()).Warnf("Failed adding service host entries to the running container: %v", err)
|
2016-01-30 01:08:11 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-01-12 01:10:09 +00:00
|
|
|
func (sb *Sandbox) deleteHostsEntries(recs []etchosts.Record) {
|
2016-01-30 01:08:11 +00:00
|
|
|
if err := etchosts.Delete(sb.config.hostsPath, recs); err != nil {
|
2023-06-23 00:33:17 +00:00
|
|
|
log.G(context.TODO()).Warnf("Failed deleting service host entries to the running container: %v", err)
|
2016-01-30 01:08:11 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-01-12 01:10:09 +00:00
|
|
|
func (sb *Sandbox) updateParentHosts() error {
|
|
|
|
var pSb *Sandbox
|
2016-01-30 01:08:11 +00:00
|
|
|
|
|
|
|
for _, update := range sb.config.parentUpdates {
|
2023-08-12 12:38:43 +00:00
|
|
|
// TODO(thaJeztah): was it intentional for this loop to re-use prior results of pSB? If not, we should make pSb local and always replace here.
|
|
|
|
if s, _ := sb.controller.GetSandbox(update.cid); s != nil {
|
|
|
|
pSb = s
|
|
|
|
}
|
2016-01-30 01:08:11 +00:00
|
|
|
if pSb == nil {
|
|
|
|
continue
|
|
|
|
}
|
2024-01-11 16:44:58 +00:00
|
|
|
// TODO(robmry) - filter out IPv6 addresses here if !sb.ipv6Enabled() but...
|
|
|
|
// - this is part of the implementation of '--link', which will be removed along
|
|
|
|
// with the rest of legacy networking.
|
|
|
|
// - IPv6 addresses shouldn't be allocated if IPv6 is not available in a container,
|
|
|
|
// and that change will come along later.
|
|
|
|
// - I think this may be dead code, it's not possible to start a parent container with
|
|
|
|
// '--link child' unless the child has already started ("Error response from daemon:
|
|
|
|
// Cannot link to a non running container"). So, when the child starts and this method
|
|
|
|
// is called with updates for parents, the parents aren't running and GetSandbox()
|
|
|
|
// returns nil.)
|
2023-01-12 01:10:09 +00:00
|
|
|
if err := etchosts.Update(pSb.config.hostsPath, update.ip, update.name); err != nil {
|
2016-01-30 01:08:11 +00:00
|
|
|
return err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2024-01-03 09:10:51 +00:00
|
|
|
func (sb *Sandbox) restoreResolvConfPath() {
|
2016-06-11 00:32:19 +00:00
|
|
|
if sb.config.resolvConfPath == "" {
|
|
|
|
sb.config.resolvConfPath = defaultPrefix + "/" + sb.id + "/resolv.conf"
|
|
|
|
}
|
|
|
|
sb.config.resolvConfHashFile = sb.config.resolvConfPath + ".hash"
|
2024-01-03 09:10:51 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func (sb *Sandbox) restoreHostsPath() {
|
2016-06-11 00:32:19 +00:00
|
|
|
if sb.config.hostsPath == "" {
|
|
|
|
sb.config.hostsPath = defaultPrefix + "/" + sb.id + "/hosts"
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-01-03 09:10:51 +00:00
|
|
|
func (sb *Sandbox) setExternalResolvers(entries []resolvconf.ExtDNSEntry) {
|
|
|
|
sb.extDNS = make([]extDNSEntry, 0, len(entries))
|
|
|
|
for _, entry := range entries {
|
2016-12-19 02:27:13 +00:00
|
|
|
sb.extDNS = append(sb.extDNS, extDNSEntry{
|
2024-01-03 09:10:51 +00:00
|
|
|
IPStr: entry.Addr.String(),
|
|
|
|
HostLoopback: entry.HostLoopback,
|
2016-12-19 02:27:13 +00:00
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-01-03 09:10:51 +00:00
|
|
|
func (c *containerConfig) getOriginResolvConfPath() string {
|
|
|
|
if c.originResolvConfPath != "" {
|
|
|
|
return c.originResolvConfPath
|
2021-08-18 11:15:23 +00:00
|
|
|
}
|
2024-01-03 09:10:51 +00:00
|
|
|
// Fallback if not specified.
|
|
|
|
return resolvconf.Path()
|
2021-08-18 11:15:23 +00:00
|
|
|
}
|
|
|
|
|
2024-01-03 09:10:51 +00:00
|
|
|
// loadResolvConf reads the resolv.conf file at path, and merges in overrides for
|
|
|
|
// nameservers, options, and search domains.
|
|
|
|
func (sb *Sandbox) loadResolvConf(path string) (*resolvconf.ResolvConf, error) {
|
|
|
|
rc, err := resolvconf.Load(path)
|
|
|
|
if err != nil && !errors.Is(err, fs.ErrNotExist) {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
// Proceed with rc, which might be zero-valued if path does not exist.
|
|
|
|
|
|
|
|
rc.SetHeader(`# Generated by Docker Engine.
|
|
|
|
# This file can be edited; Docker Engine will not make further changes once it
|
|
|
|
# has been modified.`)
|
|
|
|
if len(sb.config.dnsList) > 0 {
|
|
|
|
var dnsAddrs []netip.Addr
|
|
|
|
for _, ns := range sb.config.dnsList {
|
|
|
|
addr, err := netip.ParseAddr(ns)
|
|
|
|
if err != nil {
|
|
|
|
return nil, errors.Wrapf(err, "bad nameserver address %s", ns)
|
|
|
|
}
|
|
|
|
dnsAddrs = append(dnsAddrs, addr)
|
|
|
|
}
|
|
|
|
rc.OverrideNameServers(dnsAddrs)
|
2016-01-30 01:08:11 +00:00
|
|
|
}
|
2024-01-03 09:10:51 +00:00
|
|
|
if len(sb.config.dnsSearchList) > 0 {
|
|
|
|
rc.OverrideSearch(sb.config.dnsSearchList)
|
|
|
|
}
|
|
|
|
if len(sb.config.dnsOptionsList) > 0 {
|
|
|
|
rc.OverrideOptions(sb.config.dnsOptionsList)
|
|
|
|
}
|
|
|
|
return &rc, nil
|
|
|
|
}
|
2016-01-30 01:08:11 +00:00
|
|
|
|
2024-01-03 09:10:51 +00:00
|
|
|
// For a new sandbox, write an initial version of the container's resolv.conf. It'll
|
|
|
|
// be a copy of the host's file, with overrides for nameservers, options and search
|
|
|
|
// domains applied.
|
|
|
|
func (sb *Sandbox) setupDNS() error {
|
|
|
|
// Make sure the directory exists.
|
|
|
|
sb.restoreResolvConfPath()
|
2016-01-30 01:08:11 +00:00
|
|
|
dir, _ := filepath.Split(sb.config.resolvConfPath)
|
|
|
|
if err := createBasePath(dir); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2024-01-03 09:10:51 +00:00
|
|
|
rc, err := sb.loadResolvConf(sb.config.getOriginResolvConfPath())
|
2016-01-30 01:08:11 +00:00
|
|
|
if err != nil {
|
2024-01-03 09:10:51 +00:00
|
|
|
return err
|
2016-01-30 01:08:11 +00:00
|
|
|
}
|
2024-01-03 09:10:51 +00:00
|
|
|
return rc.WriteFile(sb.config.resolvConfPath, sb.config.resolvConfHashFile, filePerm)
|
2016-01-30 01:08:11 +00:00
|
|
|
}
|
|
|
|
|
2024-01-03 09:10:51 +00:00
|
|
|
// Called when an endpoint has joined the sandbox.
|
2023-01-12 01:10:09 +00:00
|
|
|
func (sb *Sandbox) updateDNS(ipv6Enabled bool) error {
|
2024-01-03 09:10:51 +00:00
|
|
|
if mod, err := resolvconf.UserModified(sb.config.resolvConfPath, sb.config.resolvConfHashFile); err != nil || mod {
|
|
|
|
return err
|
2016-01-30 01:08:11 +00:00
|
|
|
}
|
|
|
|
|
2024-01-03 09:10:51 +00:00
|
|
|
// Load the host's resolv.conf as a starting point.
|
|
|
|
rc, err := sb.loadResolvConf(sb.config.getOriginResolvConfPath())
|
2016-01-30 01:08:11 +00:00
|
|
|
if err != nil {
|
2024-01-03 09:10:51 +00:00
|
|
|
return err
|
2016-01-30 01:08:11 +00:00
|
|
|
}
|
2024-01-03 09:10:51 +00:00
|
|
|
// For host-networking, no further change is needed.
|
|
|
|
if !sb.config.useDefaultSandBox {
|
|
|
|
// The legacy bridge network has no internal nameserver. So, strip localhost
|
|
|
|
// nameservers from the host's config, then add default nameservers if there
|
|
|
|
// are none remaining.
|
|
|
|
rc.TransformForLegacyNw(ipv6Enabled)
|
2016-01-30 01:08:11 +00:00
|
|
|
}
|
2024-01-03 09:10:51 +00:00
|
|
|
return rc.WriteFile(sb.config.resolvConfPath, sb.config.resolvConfHashFile, filePerm)
|
|
|
|
}
|
2016-01-30 01:08:11 +00:00
|
|
|
|
2024-01-03 09:10:51 +00:00
|
|
|
// Embedded DNS server has to be enabled for this sandbox. Rebuild the container's resolv.conf.
|
|
|
|
func (sb *Sandbox) rebuildDNS() error {
|
|
|
|
// Don't touch the file if the user has modified it.
|
|
|
|
if mod, err := resolvconf.UserModified(sb.config.resolvConfPath, sb.config.resolvConfHashFile); err != nil || mod {
|
2016-01-30 01:08:11 +00:00
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2024-01-03 09:10:51 +00:00
|
|
|
// Load the host's resolv.conf as a starting point.
|
|
|
|
rc, err := sb.loadResolvConf(sb.config.getOriginResolvConfPath())
|
2016-01-30 01:08:11 +00:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2024-01-03 09:10:51 +00:00
|
|
|
|
2024-03-06 10:47:18 +00:00
|
|
|
// Check for IPv6 endpoints in this sandbox. If there are any, and the container has
|
|
|
|
// IPv6 enabled, upstream requests from the internal DNS resolver can be made from
|
|
|
|
// the container's namespace.
|
|
|
|
// TODO(robmry) - this can only check networks connected when the resolver is set up,
|
|
|
|
// the configuration won't be updated if the container gets an IPv6 address later.
|
2024-01-03 09:10:51 +00:00
|
|
|
ipv6 := false
|
|
|
|
for _, ep := range sb.endpoints {
|
|
|
|
if ep.network.enableIPv6 {
|
2024-03-06 10:47:18 +00:00
|
|
|
if en, ok := sb.ipv6Enabled(); ok {
|
|
|
|
ipv6 = en
|
|
|
|
}
|
2024-01-03 09:10:51 +00:00
|
|
|
break
|
|
|
|
}
|
2016-07-01 23:29:51 +00:00
|
|
|
}
|
2024-01-03 09:10:51 +00:00
|
|
|
|
|
|
|
intNS, err := netip.ParseAddr(sb.resolver.NameServer())
|
2016-07-01 23:29:51 +00:00
|
|
|
if err != nil {
|
2016-01-30 01:08:11 +00:00
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2024-01-03 09:10:51 +00:00
|
|
|
// Work out whether ndots has been set from host config or overrides.
|
|
|
|
_, sb.ndotsSet = rc.Option("ndots")
|
|
|
|
// Swap nameservers for the internal one, and make sure the required options are set.
|
|
|
|
var extNameServers []resolvconf.ExtDNSEntry
|
|
|
|
extNameServers, err = rc.TransformForIntNS(ipv6, intNS, sb.resolver.ResolverOptions())
|
2016-01-30 01:08:11 +00:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2024-01-03 09:10:51 +00:00
|
|
|
// Extract the list of nameservers that just got swapped out, and store them as
|
|
|
|
// upstream nameservers.
|
|
|
|
sb.setExternalResolvers(extNameServers)
|
|
|
|
|
|
|
|
// Write the file for the container - preserving old behaviour, not updating the
|
|
|
|
// hash file (so, no further updates will be made).
|
|
|
|
// TODO(robmry) - I think that's probably accidental, I can't find a reason for it,
|
|
|
|
// and the old resolvconf.Build() function wrote the file but not the hash, which
|
|
|
|
// is surprising. But, before fixing it, a guard/flag needs to be added to
|
|
|
|
// sb.updateDNS() to make sure that when an endpoint joins a sandbox that already
|
|
|
|
// has an internal resolver, the container's resolv.conf is still (re)configured
|
|
|
|
// for an internal resolver.
|
|
|
|
return rc.WriteFile(sb.config.resolvConfPath, "", filePerm)
|
2016-01-30 01:08:11 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func createBasePath(dir string) error {
|
|
|
|
return os.MkdirAll(dir, dirPerm)
|
|
|
|
}
|
|
|
|
|
|
|
|
func copyFile(src, dst string) error {
|
2021-08-24 10:10:50 +00:00
|
|
|
sBytes, err := os.ReadFile(src)
|
2016-01-30 01:08:11 +00:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2021-08-24 10:10:50 +00:00
|
|
|
return os.WriteFile(dst, sBytes, filePerm)
|
2016-01-30 01:08:11 +00:00
|
|
|
}
|