package hostnames import ( "fmt" "io/ioutil" "net" "os" "path/filepath" "strings" "github.com/hashicorp/nomad/plugins/drivers" ) // GenerateEtcHostsMount writes a /etc/hosts file using the network spec's // hosts configuration, and returns a mount config so that task drivers can // bind-mount it into the resulting task's filesystem. The extraHosts // parameter is expected to be the same format as the extra_hosts field from // the Docker or containerd drivers: []string{":"} func GenerateEtcHostsMount(taskDir string, conf *drivers.NetworkIsolationSpec, extraHosts []string) (*drivers.MountConfig, error) { if conf == nil || conf.Mode != drivers.NetIsolationModeGroup { return nil, nil } hostsCfg := conf.HostsConfig if hostsCfg == nil || hostsCfg.Address == "" || hostsCfg.Hostname == "" { return nil, nil } var content strings.Builder fmt.Fprintf(&content, `# this file was generated by Nomad 127.0.0.1 localhost ::1 localhost ::1 ip6-localhost ip6-loopback fe00::0 ip6-localnet ff00::0 ip6-mcastprefix ff02::1 ip6-allnodes ff02::2 ip6-allrouters ff02::3 ip6-allhosts # this entry is the IP address and hostname of the allocation # shared with tasks in the task group's network %s %s `, hostsCfg.Address, hostsCfg.Hostname) if len(extraHosts) > 0 { content.WriteString("\n# these entries are extra hosts added by the task config") for _, hostLine := range extraHosts { hostsEntry := strings.SplitN(hostLine, ":", 2) if len(hostsEntry) != 2 { return nil, fmt.Errorf("invalid hosts entry %q", hostLine) } if net.ParseIP(hostsEntry[1]) == nil { return nil, fmt.Errorf("invalid IP address %q", hostLine) } content.WriteString(fmt.Sprintf("\n%s %s", hostsEntry[1], hostsEntry[0])) } content.WriteString("\n") } path := filepath.Join(taskDir, "hosts") // tasks within an alloc should be able to share and modify the file, so // only write to it if it doesn't exist if _, err := os.Stat(path); os.IsNotExist(err) { err := ioutil.WriteFile(path, []byte(content.String()), 0644) if err != nil { return nil, err } } // Note that we're not setting readonly. The file is in the task dir // anyways, so this lets the task overwrite its own hosts file if the // application knows better than Nomad here. Task drivers may override // this behavior. mount := &drivers.MountConfig{ TaskPath: "/etc/hosts", HostPath: path, Readonly: false, PropagationMode: "private", } return mount, nil }