github.com/containerd/nerdctl@v1.7.7/pkg/containerutil/container_network_manager_linux.go (about) 1 /* 2 Copyright The containerd 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 containerutil 18 19 import ( 20 "context" 21 "errors" 22 "io/fs" 23 "path/filepath" 24 25 "github.com/containerd/containerd" 26 "github.com/containerd/containerd/oci" 27 "github.com/containerd/log" 28 "github.com/containerd/nerdctl/pkg/api/types" 29 "github.com/containerd/nerdctl/pkg/clientutil" 30 "github.com/containerd/nerdctl/pkg/dnsutil" 31 "github.com/containerd/nerdctl/pkg/dnsutil/hostsstore" 32 "github.com/containerd/nerdctl/pkg/netutil" 33 "github.com/containerd/nerdctl/pkg/resolvconf" 34 "github.com/containerd/nerdctl/pkg/rootlessutil" 35 ) 36 37 type cniNetworkManagerPlatform struct { 38 } 39 40 // Verifies that the internal network settings are correct. 41 func (m *cniNetworkManager) VerifyNetworkOptions(_ context.Context) error { 42 e, err := netutil.NewCNIEnv(m.globalOptions.CNIPath, m.globalOptions.CNINetConfPath, netutil.WithDefaultNetwork()) 43 if err != nil { 44 return err 45 } 46 47 if m.netOpts.MACAddress != "" { 48 macValidNetworks := []string{"bridge", "macvlan"} 49 if _, err := verifyNetworkTypes(e, m.netOpts.NetworkSlice, macValidNetworks); err != nil { 50 return err 51 } 52 } 53 54 return validateUtsSettings(m.netOpts) 55 } 56 57 // Performs setup actions required for the container with the given ID. 58 func (m *cniNetworkManager) SetupNetworking(_ context.Context, _ string) error { 59 // NOTE: on non-Windows systems which support OCI hooks, CNI networking setup 60 // is performed via createRuntime and postCreate hooks whose logic can 61 // be found in the pkg/ocihook package. 62 return nil 63 } 64 65 // Performs any required cleanup actions for the given container. 66 // Should only be called to revert any setup steps performed in setupNetworking. 67 func (m *cniNetworkManager) CleanupNetworking(_ context.Context, _ containerd.Container) error { 68 // NOTE: on non-Windows systems which support OCI hooks, CNI networking setup 69 // is performed via createRuntime and postCreate hooks whose logic can 70 // be found in the pkg/ocihook package. 71 return nil 72 } 73 74 // Returns the set of NetworkingOptions which should be set as labels on the container. 75 func (m *cniNetworkManager) InternalNetworkingOptionLabels(_ context.Context) (types.NetworkOptions, error) { 76 return m.netOpts, nil 77 } 78 79 // Returns a slice of `oci.SpecOpts` and `containerd.NewContainerOpts` which represent 80 // the network specs which need to be applied to the container with the given ID. 81 func (m *cniNetworkManager) ContainerNetworkingOpts(_ context.Context, containerID string) ([]oci.SpecOpts, []containerd.NewContainerOpts, error) { 82 opts := []oci.SpecOpts{} 83 cOpts := []containerd.NewContainerOpts{} 84 85 dataStore, err := clientutil.DataStore(m.globalOptions.DataRoot, m.globalOptions.Address) 86 if err != nil { 87 return nil, nil, err 88 } 89 90 stateDir, err := ContainerStateDirPath(m.globalOptions.Namespace, dataStore, containerID) 91 if err != nil { 92 return nil, nil, err 93 } 94 95 resolvConfPath := filepath.Join(stateDir, "resolv.conf") 96 if err := m.buildResolvConf(resolvConfPath); err != nil { 97 return nil, nil, err 98 } 99 100 // the content of /etc/hosts is created in OCI Hook 101 etcHostsPath, err := hostsstore.AllocHostsFile(dataStore, m.globalOptions.Namespace, containerID) 102 if err != nil { 103 return nil, nil, err 104 } 105 opts = append(opts, withCustomResolvConf(resolvConfPath), withCustomHosts(etcHostsPath)) 106 107 if m.netOpts.UTSNamespace != UtsNamespaceHost { 108 // If no hostname is set, default to first 12 characters of the container ID. 109 hostname := m.netOpts.Hostname 110 if hostname == "" { 111 hostname = containerID 112 if len(hostname) > 12 { 113 hostname = hostname[0:12] 114 } 115 } 116 m.netOpts.Hostname = hostname 117 118 hostnameOpts, err := writeEtcHostnameForContainer(m.globalOptions, m.netOpts.Hostname, containerID) 119 if err != nil { 120 return nil, nil, err 121 } 122 if hostnameOpts != nil { 123 opts = append(opts, hostnameOpts...) 124 } 125 } 126 127 return opts, cOpts, nil 128 } 129 130 func (m *cniNetworkManager) buildResolvConf(resolvConfPath string) error { 131 var err error 132 slirp4Dns := []string{} 133 if rootlessutil.IsRootlessChild() { 134 slirp4Dns, err = dnsutil.GetSlirp4netnsDNS() 135 if err != nil { 136 return err 137 } 138 } 139 140 var ( 141 nameServers = m.netOpts.DNSServers 142 searchDomains = m.netOpts.DNSSearchDomains 143 dnsOptions = m.netOpts.DNSResolvConfOptions 144 ) 145 146 // Use host defaults if any DNS settings are missing: 147 if len(nameServers) == 0 || len(searchDomains) == 0 || len(dnsOptions) == 0 { 148 conf, err := resolvconf.Get() 149 if err != nil { 150 if !errors.Is(err, fs.ErrNotExist) { 151 return err 152 } 153 // if resolvConf file does't exist, using default resolvers 154 conf = &resolvconf.File{} 155 log.L.WithError(err).Debugf("resolvConf file doesn't exist on host") 156 } 157 conf, err = resolvconf.FilterResolvDNS(conf.Content, true) 158 if err != nil { 159 return err 160 } 161 if len(nameServers) == 0 { 162 nameServers = resolvconf.GetNameservers(conf.Content, resolvconf.IPv4) 163 } 164 if len(searchDomains) == 0 { 165 searchDomains = resolvconf.GetSearchDomains(conf.Content) 166 } 167 if len(dnsOptions) == 0 { 168 dnsOptions = resolvconf.GetOptions(conf.Content) 169 } 170 } 171 172 _, err = resolvconf.Build(resolvConfPath, append(slirp4Dns, nameServers...), searchDomains, dnsOptions) 173 return err 174 }