mirror of
https://github.com/rancher/os.git
synced 2025-07-18 17:11:04 +00:00
Move in code from netconf and docker-from-scratch
This commit is contained in:
parent
1f4d23bf50
commit
691f7cb42c
@ -36,9 +36,9 @@ import (
|
|||||||
"github.com/coreos/coreos-cloudinit/datasource/proc_cmdline"
|
"github.com/coreos/coreos-cloudinit/datasource/proc_cmdline"
|
||||||
"github.com/coreos/coreos-cloudinit/datasource/url"
|
"github.com/coreos/coreos-cloudinit/datasource/url"
|
||||||
"github.com/coreos/coreos-cloudinit/pkg"
|
"github.com/coreos/coreos-cloudinit/pkg"
|
||||||
"github.com/rancher/netconf"
|
|
||||||
"github.com/rancher/os/cmd/cloudinitsave/gce"
|
"github.com/rancher/os/cmd/cloudinitsave/gce"
|
||||||
rancherConfig "github.com/rancher/os/config"
|
rancherConfig "github.com/rancher/os/config"
|
||||||
|
"github.com/rancher/os/netconf"
|
||||||
"github.com/rancher/os/util"
|
"github.com/rancher/os/util"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -231,8 +231,8 @@ func getDatasources(cfg *rancherConfig.CloudConfig) []datasource.Datasource {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func enableDoLinkLocal() {
|
func enableDoLinkLocal() {
|
||||||
err := netconf.ApplyNetworkConfigs(&netconf.NetworkConfig{
|
err := netconf.ApplyNetworkConfigs(&rancherConfig.NetworkConfig{
|
||||||
Interfaces: map[string]netconf.InterfaceConfig{
|
Interfaces: map[string]rancherConfig.InterfaceConfig{
|
||||||
"eth0": {
|
"eth0": {
|
||||||
IPV4LL: true,
|
IPV4LL: true,
|
||||||
},
|
},
|
||||||
|
@ -12,11 +12,11 @@ import (
|
|||||||
|
|
||||||
"github.com/Sirupsen/logrus"
|
"github.com/Sirupsen/logrus"
|
||||||
"github.com/packethost/packngo/metadata"
|
"github.com/packethost/packngo/metadata"
|
||||||
"github.com/rancher/netconf"
|
"github.com/rancher/os/config"
|
||||||
rancherConfig "github.com/rancher/os/config"
|
"github.com/rancher/os/netconf"
|
||||||
)
|
)
|
||||||
|
|
||||||
func enablePacketNetwork(cfg *rancherConfig.RancherConfig) {
|
func enablePacketNetwork(cfg *config.RancherConfig) {
|
||||||
bootStrapped := false
|
bootStrapped := false
|
||||||
for _, v := range cfg.Network.Interfaces {
|
for _, v := range cfg.Network.Interfaces {
|
||||||
if v.Address != "" {
|
if v.Address != "" {
|
||||||
@ -40,7 +40,7 @@ func enablePacketNetwork(cfg *rancherConfig.RancherConfig) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
bondCfg := netconf.InterfaceConfig{
|
bondCfg := config.InterfaceConfig{
|
||||||
Addresses: []string{},
|
Addresses: []string{},
|
||||||
BondOpts: map[string]string{
|
BondOpts: map[string]string{
|
||||||
"lacp_rate": "1",
|
"lacp_rate": "1",
|
||||||
@ -51,11 +51,11 @@ func enablePacketNetwork(cfg *rancherConfig.RancherConfig) {
|
|||||||
"mode": "4",
|
"mode": "4",
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
netCfg := netconf.NetworkConfig{
|
netCfg := config.NetworkConfig{
|
||||||
Interfaces: map[string]netconf.InterfaceConfig{},
|
Interfaces: map[string]config.InterfaceConfig{},
|
||||||
}
|
}
|
||||||
for _, iface := range m.Network.Interfaces {
|
for _, iface := range m.Network.Interfaces {
|
||||||
netCfg.Interfaces["mac="+iface.Mac] = netconf.InterfaceConfig{
|
netCfg.Interfaces["mac="+iface.Mac] = config.InterfaceConfig{
|
||||||
Bond: "bond0",
|
Bond: "bond0",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -80,24 +80,24 @@ func enablePacketNetwork(cfg *rancherConfig.RancherConfig) {
|
|||||||
b, _ := yaml.Marshal(netCfg)
|
b, _ := yaml.Marshal(netCfg)
|
||||||
logrus.Debugf("Generated network config: %s", string(b))
|
logrus.Debugf("Generated network config: %s", string(b))
|
||||||
|
|
||||||
cc := rancherConfig.CloudConfig{
|
cc := config.CloudConfig{
|
||||||
Rancher: rancherConfig.RancherConfig{
|
Rancher: config.RancherConfig{
|
||||||
Network: netCfg,
|
Network: netCfg,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
// Post to phone home URL on first boot
|
// Post to phone home URL on first boot
|
||||||
if _, err = os.Stat(rancherConfig.CloudConfigNetworkFile); err != nil {
|
if _, err = os.Stat(config.CloudConfigNetworkFile); err != nil {
|
||||||
if _, err = http.Post(m.PhoneHomeURL, "application/json", bytes.NewReader([]byte{})); err != nil {
|
if _, err = http.Post(m.PhoneHomeURL, "application/json", bytes.NewReader([]byte{})); err != nil {
|
||||||
logrus.Errorf("Failed to post to Packet phone home URL: %v", err)
|
logrus.Errorf("Failed to post to Packet phone home URL: %v", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := os.MkdirAll(path.Dir(rancherConfig.CloudConfigNetworkFile), 0700); err != nil {
|
if err := os.MkdirAll(path.Dir(config.CloudConfigNetworkFile), 0700); err != nil {
|
||||||
logrus.Errorf("Failed to create directory for file %s: %v", rancherConfig.CloudConfigNetworkFile, err)
|
logrus.Errorf("Failed to create directory for file %s: %v", config.CloudConfigNetworkFile, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := rancherConfig.WriteToFile(cc, rancherConfig.CloudConfigNetworkFile); err != nil {
|
if err := config.WriteToFile(cc, config.CloudConfigNetworkFile); err != nil {
|
||||||
logrus.Errorf("Failed to save config file %s: %v", rancherConfig.CloudConfigNetworkFile, err)
|
logrus.Errorf("Failed to save config file %s: %v", config.CloudConfigNetworkFile, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -9,10 +9,10 @@ import (
|
|||||||
log "github.com/Sirupsen/logrus"
|
log "github.com/Sirupsen/logrus"
|
||||||
|
|
||||||
"github.com/docker/libnetwork/resolvconf"
|
"github.com/docker/libnetwork/resolvconf"
|
||||||
"github.com/rancher/netconf"
|
|
||||||
"github.com/rancher/os/config"
|
"github.com/rancher/os/config"
|
||||||
"github.com/rancher/os/docker"
|
"github.com/rancher/os/docker"
|
||||||
"github.com/rancher/os/hostname"
|
"github.com/rancher/os/hostname"
|
||||||
|
"github.com/rancher/os/netconf"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
@ -7,7 +7,6 @@ import (
|
|||||||
"github.com/coreos/coreos-cloudinit/config"
|
"github.com/coreos/coreos-cloudinit/config"
|
||||||
"github.com/docker/engine-api/types"
|
"github.com/docker/engine-api/types"
|
||||||
composeConfig "github.com/docker/libcompose/config"
|
composeConfig "github.com/docker/libcompose/config"
|
||||||
"github.com/rancher/netconf"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@ -113,8 +112,8 @@ type RancherConfig struct {
|
|||||||
Disable []string `yaml:"disable,omitempty"`
|
Disable []string `yaml:"disable,omitempty"`
|
||||||
ServicesInclude map[string]bool `yaml:"services_include,omitempty"`
|
ServicesInclude map[string]bool `yaml:"services_include,omitempty"`
|
||||||
Modules []string `yaml:"modules,omitempty"`
|
Modules []string `yaml:"modules,omitempty"`
|
||||||
Network netconf.NetworkConfig `yaml:"network,omitempty"`
|
Network NetworkConfig `yaml:"network,omitempty"`
|
||||||
DefaultNetwork netconf.NetworkConfig `yaml:"default_network,omitempty"`
|
DefaultNetwork NetworkConfig `yaml:"default_network,omitempty"`
|
||||||
Repositories Repositories `yaml:"repositories,omitempty"`
|
Repositories Repositories `yaml:"repositories,omitempty"`
|
||||||
Ssh SshConfig `yaml:"ssh,omitempty"`
|
Ssh SshConfig `yaml:"ssh,omitempty"`
|
||||||
State StateConfig `yaml:"state,omitempty"`
|
State StateConfig `yaml:"state,omitempty"`
|
||||||
@ -169,6 +168,39 @@ type DockerConfig struct {
|
|||||||
Exec bool `yaml:"exec,omitempty"`
|
Exec bool `yaml:"exec,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type NetworkConfig struct {
|
||||||
|
PreCmds []string `yaml:"pre_cmds,omitempty"`
|
||||||
|
Dns DnsConfig `yaml:"dns,omitempty"`
|
||||||
|
Interfaces map[string]InterfaceConfig `yaml:"interfaces,omitempty"`
|
||||||
|
PostCmds []string `yaml:"post_cmds,omitempty"`
|
||||||
|
HttpProxy string `yaml:"http_proxy,omitempty"`
|
||||||
|
HttpsProxy string `yaml:"https_proxy,omitempty"`
|
||||||
|
NoProxy string `yaml:"no_proxy,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type InterfaceConfig struct {
|
||||||
|
Match string `yaml:"match,omitempty"`
|
||||||
|
DHCP bool `yaml:"dhcp,omitempty"`
|
||||||
|
DHCPArgs string `yaml:"dhcp_args,omitempty"`
|
||||||
|
Address string `yaml:"address,omitempty"`
|
||||||
|
Addresses []string `yaml:"addresses,omitempty"`
|
||||||
|
IPV4LL bool `yaml:"ipv4ll,omitempty"`
|
||||||
|
Gateway string `yaml:"gateway,omitempty"`
|
||||||
|
GatewayIpv6 string `yaml:"gateway_ipv6,omitempty"`
|
||||||
|
MTU int `yaml:"mtu,omitempty"`
|
||||||
|
Bridge string `yaml:"bridge,omitempty"`
|
||||||
|
Bond string `yaml:"bond,omitempty"`
|
||||||
|
BondOpts map[string]string `yaml:"bond_opts,omitempty"`
|
||||||
|
PostUp []string `yaml:"post_up,omitempty"`
|
||||||
|
PreUp []string `yaml:"pre_up,omitempty"`
|
||||||
|
Vlans string `yaml:"vlans,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type DnsConfig struct {
|
||||||
|
Nameservers []string `yaml:"nameservers,flow,omitempty"`
|
||||||
|
Search []string `yaml:"search,flow,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
type SshConfig struct {
|
type SshConfig struct {
|
||||||
Keys map[string]string `yaml:"keys,omitempty"`
|
Keys map[string]string `yaml:"keys,omitempty"`
|
||||||
}
|
}
|
||||||
@ -193,7 +225,7 @@ type CloudInit struct {
|
|||||||
type Defaults struct {
|
type Defaults struct {
|
||||||
Hostname string `yaml:"hostname,omitempty"`
|
Hostname string `yaml:"hostname,omitempty"`
|
||||||
Docker DockerConfig `yaml:"docker,omitempty"`
|
Docker DockerConfig `yaml:"docker,omitempty"`
|
||||||
Network netconf.NetworkConfig `yaml:"network,omitempty"`
|
Network NetworkConfig `yaml:"network,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r Repositories) ToArray() []string {
|
func (r Repositories) ToArray() []string {
|
||||||
|
24
dfs/one.go
Normal file
24
dfs/one.go
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
// +build linux
|
||||||
|
|
||||||
|
package dfs
|
||||||
|
|
||||||
|
import (
|
||||||
|
"os"
|
||||||
|
"os/signal"
|
||||||
|
"syscall"
|
||||||
|
)
|
||||||
|
|
||||||
|
func PidOne() error {
|
||||||
|
c := make(chan os.Signal, 2048)
|
||||||
|
signal.Notify(c, syscall.SIGCHLD)
|
||||||
|
|
||||||
|
for range c {
|
||||||
|
for {
|
||||||
|
if pid, err := syscall.Wait4(-1, nil, syscall.WNOHANG, nil); err != nil || pid <= 0 {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
727
dfs/scratch.go
Normal file
727
dfs/scratch.go
Normal file
@ -0,0 +1,727 @@
|
|||||||
|
package dfs
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bufio"
|
||||||
|
"io"
|
||||||
|
"io/ioutil"
|
||||||
|
"os"
|
||||||
|
"os/exec"
|
||||||
|
"path"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
"syscall"
|
||||||
|
|
||||||
|
log "github.com/Sirupsen/logrus"
|
||||||
|
"github.com/docker/libnetwork/resolvconf"
|
||||||
|
"github.com/rancher/os/config"
|
||||||
|
"github.com/rancher/os/netconf"
|
||||||
|
"github.com/rancher/os/selinux"
|
||||||
|
"github.com/rancher/os/util"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
defaultPrefix = "/usr"
|
||||||
|
iptables = "/sbin/iptables"
|
||||||
|
modprobe = "/sbin/modprobe"
|
||||||
|
distSuffix = ".dist"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
mounts = [][]string{
|
||||||
|
{"devtmpfs", "/dev", "devtmpfs", ""},
|
||||||
|
{"none", "/dev/pts", "devpts", ""},
|
||||||
|
{"shm", "/dev/shm", "tmpfs", "rw,nosuid,nodev,noexec,relatime,size=65536k"},
|
||||||
|
{"mqueue", "/dev/mqueue", "mqueue", "rw,nosuid,nodev,noexec,relatime"},
|
||||||
|
{"none", "/proc", "proc", ""},
|
||||||
|
{"none", "/run", "tmpfs", ""},
|
||||||
|
{"none", "/sys", "sysfs", ""},
|
||||||
|
{"none", "/sys/fs/cgroup", "tmpfs", ""},
|
||||||
|
}
|
||||||
|
optionalMounts = [][]string{
|
||||||
|
{"none", "/sys/fs/selinux", "selinuxfs", ""},
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
type Config struct {
|
||||||
|
Fork bool
|
||||||
|
PidOne bool
|
||||||
|
CommandName string
|
||||||
|
DnsConfig config.DnsConfig
|
||||||
|
BridgeName string
|
||||||
|
BridgeAddress string
|
||||||
|
BridgeMtu int
|
||||||
|
CgroupHierarchy map[string]string
|
||||||
|
LogFile string
|
||||||
|
NoLog bool
|
||||||
|
NoFiles uint64
|
||||||
|
Environment []string
|
||||||
|
GraphDirectory string
|
||||||
|
DaemonConfig string
|
||||||
|
}
|
||||||
|
|
||||||
|
func createMounts(mounts ...[]string) error {
|
||||||
|
for _, mount := range mounts {
|
||||||
|
log.Debugf("Mounting %s %s %s %s", mount[0], mount[1], mount[2], mount[3])
|
||||||
|
err := util.Mount(mount[0], mount[1], mount[2], mount[3])
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func createOptionalMounts(mounts ...[]string) {
|
||||||
|
for _, mount := range mounts {
|
||||||
|
log.Debugf("Mounting %s %s %s %s", mount[0], mount[1], mount[2], mount[3])
|
||||||
|
err := util.Mount(mount[0], mount[1], mount[2], mount[3])
|
||||||
|
if err != nil {
|
||||||
|
log.Debugf("Unable to mount %s %s %s %s: %s", mount[0], mount[1], mount[2], mount[3], err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func createDirs(dirs ...string) error {
|
||||||
|
for _, dir := range dirs {
|
||||||
|
if _, err := os.Stat(dir); os.IsNotExist(err) {
|
||||||
|
log.Debugf("Creating %s", dir)
|
||||||
|
err = os.MkdirAll(dir, 0755)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func mountCgroups(hierarchyConfig map[string]string) error {
|
||||||
|
f, err := os.Open("/proc/cgroups")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer f.Close()
|
||||||
|
|
||||||
|
scanner := bufio.NewScanner(f)
|
||||||
|
|
||||||
|
hierarchies := make(map[string][]string)
|
||||||
|
|
||||||
|
for scanner.Scan() {
|
||||||
|
text := scanner.Text()
|
||||||
|
log.Debugf("/proc/cgroups: %s", text)
|
||||||
|
fields := strings.Split(text, "\t")
|
||||||
|
cgroup := fields[0]
|
||||||
|
if cgroup == "" || cgroup[0] == '#' || (len(fields) > 3 && fields[3] == "0") {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
hierarchy := hierarchyConfig[cgroup]
|
||||||
|
if hierarchy == "" {
|
||||||
|
hierarchy = fields[1]
|
||||||
|
}
|
||||||
|
|
||||||
|
if hierarchy == "0" {
|
||||||
|
hierarchy = cgroup
|
||||||
|
}
|
||||||
|
|
||||||
|
hierarchies[hierarchy] = append(hierarchies[hierarchy], cgroup)
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, hierarchy := range hierarchies {
|
||||||
|
if err := mountCgroup(strings.Join(hierarchy, ",")); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if err = scanner.Err(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Debug("Done mouting cgroupfs")
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func CreateSymlinks(pathSets [][]string) error {
|
||||||
|
for _, paths := range pathSets {
|
||||||
|
if err := CreateSymlink(paths[0], paths[1]); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func CreateSymlink(src, dest string) error {
|
||||||
|
if _, err := os.Lstat(dest); os.IsNotExist(err) {
|
||||||
|
log.Debugf("Symlinking %s => %s", dest, src)
|
||||||
|
if err = os.Symlink(src, dest); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func mountCgroup(cgroup string) error {
|
||||||
|
if err := createDirs("/sys/fs/cgroup/" + cgroup); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := createMounts([][]string{{"none", "/sys/fs/cgroup/" + cgroup, "cgroup", cgroup}}...); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
parts := strings.Split(cgroup, ",")
|
||||||
|
if len(parts) > 1 {
|
||||||
|
for _, part := range parts {
|
||||||
|
if err := CreateSymlink("/sys/fs/cgroup/"+cgroup, "/sys/fs/cgroup/"+part); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func execDocker(config *Config, docker, cmd string, args []string) (*exec.Cmd, error) {
|
||||||
|
if len(args) > 0 && args[0] == "docker" {
|
||||||
|
args = args[1:]
|
||||||
|
}
|
||||||
|
log.Debugf("Launching Docker %s %s %v", docker, cmd, args)
|
||||||
|
|
||||||
|
env := os.Environ()
|
||||||
|
if len(config.Environment) != 0 {
|
||||||
|
env = append(env, config.Environment...)
|
||||||
|
}
|
||||||
|
|
||||||
|
if config.Fork {
|
||||||
|
cmd := exec.Command(docker, args...)
|
||||||
|
if !config.NoLog {
|
||||||
|
cmd.Stdout = os.Stdout
|
||||||
|
cmd.Stderr = os.Stderr
|
||||||
|
}
|
||||||
|
cmd.Env = env
|
||||||
|
err := cmd.Start()
|
||||||
|
if err != nil {
|
||||||
|
return cmd, err
|
||||||
|
}
|
||||||
|
if config.PidOne {
|
||||||
|
PidOne()
|
||||||
|
}
|
||||||
|
return cmd, err
|
||||||
|
} else {
|
||||||
|
err := syscall.Exec(expand(docker), append([]string{cmd}, args...), env)
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func copyDefault(folder, name string) error {
|
||||||
|
defaultFile := path.Join(defaultPrefix, folder, name)
|
||||||
|
if err := CopyFile(defaultFile, folder, name); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func copyDefaultFolder(folder string) error {
|
||||||
|
log.Debugf("Copying folder %s", folder)
|
||||||
|
defaultFolder := path.Join(defaultPrefix, folder)
|
||||||
|
files, _ := ioutil.ReadDir(defaultFolder)
|
||||||
|
for _, file := range files {
|
||||||
|
var err error
|
||||||
|
if file.IsDir() {
|
||||||
|
err = copyDefaultFolder(path.Join(folder, file.Name()))
|
||||||
|
} else {
|
||||||
|
err = copyDefault(folder, file.Name())
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func defaultFiles(files ...string) error {
|
||||||
|
for _, file := range files {
|
||||||
|
dir := path.Dir(file)
|
||||||
|
name := path.Base(file)
|
||||||
|
if err := copyDefault(dir, name); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func defaultFolders(folders ...string) error {
|
||||||
|
for _, folder := range folders {
|
||||||
|
if err := copyDefaultFolder(folder); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func CopyFile(src, folder, name string) error {
|
||||||
|
if _, err := os.Lstat(src); os.IsNotExist(err) {
|
||||||
|
log.Debugf("Not copying %s, does not exists", src)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
dst := path.Join(folder, name)
|
||||||
|
if _, err := os.Lstat(dst); err == nil {
|
||||||
|
log.Debugf("Not copying %s => %s already exists", src, dst)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := createDirs(folder); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
stat, err := os.Lstat(src)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if stat.Mode()&os.ModeSymlink != 0 {
|
||||||
|
symDst, err := os.Readlink(src)
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf("Failed to readlink: %v", err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
// file is a symlink
|
||||||
|
log.Debugf("Symlinking %s => %s", dst, symDst)
|
||||||
|
return os.Symlink(symDst, dst)
|
||||||
|
}
|
||||||
|
|
||||||
|
srcFile, err := os.Open(src)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer srcFile.Close()
|
||||||
|
|
||||||
|
dstFile, err := os.Create(dst)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer dstFile.Close()
|
||||||
|
|
||||||
|
log.Debugf("Copying %s => %s", src, dst)
|
||||||
|
_, err = io.Copy(dstFile, srcFile)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func tryCreateFile(name, content string) error {
|
||||||
|
if _, err := os.Stat(name); err == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := createDirs(path.Dir(name)); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return ioutil.WriteFile(name, []byte(content), 0644)
|
||||||
|
}
|
||||||
|
|
||||||
|
func createPasswd() error {
|
||||||
|
return tryCreateFile("/etc/passwd", "root:x:0:0:root:/root:/bin/sh\n")
|
||||||
|
}
|
||||||
|
|
||||||
|
func createGroup() error {
|
||||||
|
return tryCreateFile("/etc/group", "root:x:0:\n")
|
||||||
|
}
|
||||||
|
|
||||||
|
func setupNetworking(cfg *Config) error {
|
||||||
|
if cfg == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
hostname, err := os.Hostname()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
tryCreateFile("/etc/hosts", `127.0.0.1 localhost
|
||||||
|
::1 localhost ip6-localhost ip6-loopback
|
||||||
|
fe00::0 ip6-localnet
|
||||||
|
ff00::0 ip6-mcastprefix
|
||||||
|
ff02::1 ip6-allnodes
|
||||||
|
ff02::2 ip6-allrouters
|
||||||
|
|
||||||
|
127.0.1.1 `+hostname)
|
||||||
|
|
||||||
|
if len(cfg.DnsConfig.Nameservers) != 0 {
|
||||||
|
if _, err := resolvconf.Build("/etc/resolv.conf", cfg.DnsConfig.Nameservers, cfg.DnsConfig.Search, nil); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if cfg.BridgeName != "" && cfg.BridgeName != "none" {
|
||||||
|
log.Debugf("Creating bridge %s (%s)", cfg.BridgeName, cfg.BridgeAddress)
|
||||||
|
if err := netconf.ApplyNetworkConfigs(&config.NetworkConfig{
|
||||||
|
Interfaces: map[string]config.InterfaceConfig{
|
||||||
|
cfg.BridgeName: {
|
||||||
|
Address: cfg.BridgeAddress,
|
||||||
|
MTU: cfg.BridgeMtu,
|
||||||
|
Bridge: "true",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetValue(index int, args []string) string {
|
||||||
|
val := args[index]
|
||||||
|
parts := strings.SplitN(val, "=", 2)
|
||||||
|
if len(parts) == 1 {
|
||||||
|
if len(args) > index+1 {
|
||||||
|
return args[index+1]
|
||||||
|
} else {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return parts[1]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func ParseConfig(config *Config, args ...string) []string {
|
||||||
|
for i, arg := range args {
|
||||||
|
if strings.HasPrefix(arg, "--bip") {
|
||||||
|
config.BridgeAddress = GetValue(i, args)
|
||||||
|
} else if strings.HasPrefix(arg, "--fixed-cidr") {
|
||||||
|
config.BridgeAddress = GetValue(i, args)
|
||||||
|
} else if strings.HasPrefix(arg, "-b") || strings.HasPrefix(arg, "--bridge") {
|
||||||
|
config.BridgeName = GetValue(i, args)
|
||||||
|
} else if strings.HasPrefix(arg, "--config-file") {
|
||||||
|
config.DaemonConfig = GetValue(i, args)
|
||||||
|
} else if strings.HasPrefix(arg, "--mtu") {
|
||||||
|
mtu, err := strconv.Atoi(GetValue(i, args))
|
||||||
|
if err != nil {
|
||||||
|
config.BridgeMtu = mtu
|
||||||
|
}
|
||||||
|
} else if strings.HasPrefix(arg, "-g") || strings.HasPrefix(arg, "--graph") {
|
||||||
|
config.GraphDirectory = GetValue(i, args)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if config.BridgeName != "" && config.BridgeAddress != "" {
|
||||||
|
newArgs := []string{}
|
||||||
|
skip := false
|
||||||
|
for _, arg := range args {
|
||||||
|
if skip {
|
||||||
|
skip = false
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if arg == "--bip" {
|
||||||
|
skip = true
|
||||||
|
continue
|
||||||
|
} else if strings.HasPrefix(arg, "--bip=") {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
newArgs = append(newArgs, arg)
|
||||||
|
}
|
||||||
|
|
||||||
|
args = newArgs
|
||||||
|
}
|
||||||
|
|
||||||
|
return args
|
||||||
|
}
|
||||||
|
|
||||||
|
func PrepareFs(config *Config) error {
|
||||||
|
if err := createMounts(mounts...); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
createOptionalMounts(optionalMounts...)
|
||||||
|
|
||||||
|
if err := mountCgroups(config.CgroupHierarchy); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := createLayout(config); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := firstPrepare(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func touchSocket(path string) error {
|
||||||
|
if err := syscall.Unlink(path); err != nil && !os.IsNotExist(err) {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return ioutil.WriteFile(path, []byte{}, 0700)
|
||||||
|
}
|
||||||
|
|
||||||
|
func touchSockets(args ...string) error {
|
||||||
|
touched := false
|
||||||
|
|
||||||
|
for i, arg := range args {
|
||||||
|
if strings.HasPrefix(arg, "-H") {
|
||||||
|
val := GetValue(i, args)
|
||||||
|
if strings.HasPrefix(val, "unix://") {
|
||||||
|
val = val[len("unix://"):]
|
||||||
|
log.Debugf("Creating temp file at %s", val)
|
||||||
|
if err := touchSocket(val); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
touched = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if !touched {
|
||||||
|
return touchSocket("/var/run/docker.sock")
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func createDaemonConfig(config *Config) error {
|
||||||
|
if config.DaemonConfig == "" {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, err := os.Stat(config.DaemonConfig); os.IsNotExist(err) {
|
||||||
|
if err := os.MkdirAll(path.Dir(config.DaemonConfig), 0755); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return ioutil.WriteFile(config.DaemonConfig, []byte("{}"), 0600)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func cleanupFiles(graphDirectory string) {
|
||||||
|
zeroFiles := []string{
|
||||||
|
"/etc/docker/key.json",
|
||||||
|
"/etc/docker/daemon.json",
|
||||||
|
"/etc/docker/system-daemon.json",
|
||||||
|
path.Join(graphDirectory, "image/overlay/repositories.json"),
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, file := range zeroFiles {
|
||||||
|
if stat, err := os.Stat(file); err == nil {
|
||||||
|
if stat.Size() < 2 {
|
||||||
|
log.Warnf("Deleting invalid json file: %s", file)
|
||||||
|
os.Remove(file)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func createLayout(config *Config) error {
|
||||||
|
if err := createDirs("/tmp", "/root/.ssh", "/var", "/usr/lib"); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
graphDirectory := config.GraphDirectory
|
||||||
|
|
||||||
|
if config.GraphDirectory == "" {
|
||||||
|
graphDirectory = "/var/lib/docker"
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := createDirs(graphDirectory); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := createDaemonConfig(config); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
cleanupFiles(graphDirectory)
|
||||||
|
|
||||||
|
selinux.SetFileContext(graphDirectory, "system_u:object_r:var_lib_t:s0")
|
||||||
|
|
||||||
|
return CreateSymlinks([][]string{
|
||||||
|
{"usr/lib", "/lib"},
|
||||||
|
{"usr/sbin", "/sbin"},
|
||||||
|
{"../run", "/var/run"},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func firstPrepare() error {
|
||||||
|
os.Setenv("PATH", "/sbin:/usr/sbin:/usr/bin")
|
||||||
|
|
||||||
|
if err := defaultFiles(
|
||||||
|
"/etc/ssl/certs/ca-certificates.crt",
|
||||||
|
"/etc/passwd",
|
||||||
|
"/etc/group",
|
||||||
|
); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := defaultFolders(
|
||||||
|
"/etc/docker",
|
||||||
|
"/etc/selinux",
|
||||||
|
"/etc/selinux/ros",
|
||||||
|
"/etc/selinux/ros/policy",
|
||||||
|
"/etc/selinux/ros/contexts",
|
||||||
|
"/var/lib/cni",
|
||||||
|
); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := createPasswd(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := createGroup(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func secondPrepare(config *Config, docker string, args ...string) error {
|
||||||
|
|
||||||
|
if err := setupNetworking(config); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := touchSockets(args...); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := setupLogging(config); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, i := range []string{docker, iptables, modprobe} {
|
||||||
|
if err := setupBin(config, i); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := setUlimit(config); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
ioutil.WriteFile("/proc/sys/net/ipv4/ip_forward", []byte("1"), 0655)
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func expand(bin string) string {
|
||||||
|
expanded, err := exec.LookPath(bin)
|
||||||
|
if err == nil {
|
||||||
|
return expanded
|
||||||
|
}
|
||||||
|
return bin
|
||||||
|
}
|
||||||
|
|
||||||
|
func setupBin(config *Config, bin string) error {
|
||||||
|
expanded, err := exec.LookPath(bin)
|
||||||
|
if err == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
expanded, err = exec.LookPath(bin + distSuffix)
|
||||||
|
if err != nil {
|
||||||
|
// Purposely not returning error
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return CreateSymlink(expanded, expanded[:len(expanded)-len(distSuffix)])
|
||||||
|
}
|
||||||
|
|
||||||
|
func setupLogging(config *Config) error {
|
||||||
|
if config.LogFile == "" {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := createDirs(path.Dir(config.LogFile)); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
output, err := os.OpenFile(config.LogFile, os.O_RDWR|os.O_CREATE|os.O_APPEND, 0666)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
syscall.Dup3(int(output.Fd()), int(os.Stdout.Fd()), 0)
|
||||||
|
syscall.Dup3(int(output.Fd()), int(os.Stderr.Fd()), 0)
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func setUlimit(cfg *Config) error {
|
||||||
|
var rLimit syscall.Rlimit
|
||||||
|
if err := syscall.Getrlimit(syscall.RLIMIT_NOFILE, &rLimit); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if cfg.NoFiles == 0 {
|
||||||
|
rLimit.Max = 1000000
|
||||||
|
} else {
|
||||||
|
rLimit.Max = cfg.NoFiles
|
||||||
|
}
|
||||||
|
rLimit.Cur = rLimit.Max
|
||||||
|
return syscall.Setrlimit(syscall.RLIMIT_NOFILE, &rLimit)
|
||||||
|
}
|
||||||
|
|
||||||
|
func runOrExec(config *Config, docker string, args ...string) (*exec.Cmd, error) {
|
||||||
|
if err := secondPrepare(config, docker, args...); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
cmd := path.Base(docker)
|
||||||
|
if config != nil && config.CommandName != "" {
|
||||||
|
cmd = config.CommandName
|
||||||
|
}
|
||||||
|
|
||||||
|
if cmd == "dockerd" && len(args) > 1 && args[0] == "daemon" {
|
||||||
|
args = args[1:]
|
||||||
|
}
|
||||||
|
|
||||||
|
return execDocker(config, docker, cmd, args)
|
||||||
|
}
|
||||||
|
|
||||||
|
func LaunchDocker(config *Config, docker string, args ...string) (*exec.Cmd, error) {
|
||||||
|
if err := PrepareFs(config); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return runOrExec(config, docker, args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func Main() {
|
||||||
|
if os.Getenv("DOCKER_LAUNCH_DEBUG") == "true" {
|
||||||
|
log.SetLevel(log.DebugLevel)
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(os.Args) < 2 {
|
||||||
|
log.Fatalf("Usage Example: %s /usr/bin/docker -d -D", os.Args[0])
|
||||||
|
}
|
||||||
|
|
||||||
|
args := []string{}
|
||||||
|
if len(os.Args) > 1 {
|
||||||
|
args = os.Args[2:]
|
||||||
|
}
|
||||||
|
|
||||||
|
var config Config
|
||||||
|
args = ParseConfig(&config, args...)
|
||||||
|
|
||||||
|
if os.Getenv("DOCKER_LAUNCH_REAP") == "true" {
|
||||||
|
config.Fork = true
|
||||||
|
config.PidOne = true
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Debugf("Launch config %#v", config)
|
||||||
|
|
||||||
|
_, err := LaunchDocker(&config, os.Args[1], args...)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
@ -6,9 +6,9 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
log "github.com/Sirupsen/logrus"
|
log "github.com/Sirupsen/logrus"
|
||||||
"github.com/rancher/docker-from-scratch"
|
|
||||||
"github.com/rancher/os/compose"
|
"github.com/rancher/os/compose"
|
||||||
"github.com/rancher/os/config"
|
"github.com/rancher/os/config"
|
||||||
|
"github.com/rancher/os/dfs"
|
||||||
"github.com/rancher/os/util"
|
"github.com/rancher/os/util"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -36,7 +36,7 @@ func startDocker(cfg *config.CloudConfig) (chan interface{}, error) {
|
|||||||
launchConfig.LogFile = ""
|
launchConfig.LogFile = ""
|
||||||
launchConfig.NoLog = true
|
launchConfig.NoLog = true
|
||||||
|
|
||||||
cmd, err := dockerlaunch.LaunchDocker(launchConfig, config.SYSTEM_DOCKER_BIN, args...)
|
cmd, err := dfs.LaunchDocker(launchConfig, config.SYSTEM_DOCKER_BIN, args...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
16
init/init.go
16
init/init.go
@ -12,8 +12,8 @@ import (
|
|||||||
|
|
||||||
log "github.com/Sirupsen/logrus"
|
log "github.com/Sirupsen/logrus"
|
||||||
"github.com/docker/docker/pkg/mount"
|
"github.com/docker/docker/pkg/mount"
|
||||||
"github.com/rancher/docker-from-scratch"
|
|
||||||
"github.com/rancher/os/config"
|
"github.com/rancher/os/config"
|
||||||
|
"github.com/rancher/os/dfs"
|
||||||
"github.com/rancher/os/util"
|
"github.com/rancher/os/util"
|
||||||
"github.com/rancher/os/util/network"
|
"github.com/rancher/os/util/network"
|
||||||
)
|
)
|
||||||
@ -27,7 +27,7 @@ const (
|
|||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
mountConfig = dockerlaunch.Config{
|
mountConfig = dfs.Config{
|
||||||
CgroupHierarchy: map[string]string{
|
CgroupHierarchy: map[string]string{
|
||||||
"cpu": "cpu",
|
"cpu": "cpu",
|
||||||
"cpuacct": "cpu",
|
"cpuacct": "cpu",
|
||||||
@ -162,10 +162,10 @@ func tryMountAndBootstrap(cfg *config.CloudConfig) (*config.CloudConfig, error)
|
|||||||
return mountOem(cfg)
|
return mountOem(cfg)
|
||||||
}
|
}
|
||||||
|
|
||||||
func getLaunchConfig(cfg *config.CloudConfig, dockerCfg *config.DockerConfig) (*dockerlaunch.Config, []string) {
|
func getLaunchConfig(cfg *config.CloudConfig, dockerCfg *config.DockerConfig) (*dfs.Config, []string) {
|
||||||
var launchConfig dockerlaunch.Config
|
var launchConfig dfs.Config
|
||||||
|
|
||||||
args := dockerlaunch.ParseConfig(&launchConfig, dockerCfg.FullArgs()...)
|
args := dfs.ParseConfig(&launchConfig, dockerCfg.FullArgs()...)
|
||||||
|
|
||||||
launchConfig.DnsConfig.Nameservers = cfg.Rancher.Defaults.Network.Dns.Nameservers
|
launchConfig.DnsConfig.Nameservers = cfg.Rancher.Defaults.Network.Dns.Nameservers
|
||||||
launchConfig.DnsConfig.Search = cfg.Rancher.Defaults.Network.Dns.Search
|
launchConfig.DnsConfig.Search = cfg.Rancher.Defaults.Network.Dns.Search
|
||||||
@ -220,7 +220,7 @@ func RunInit() error {
|
|||||||
boot2DockerEnvironment := false
|
boot2DockerEnvironment := false
|
||||||
initFuncs := []config.CfgFunc{
|
initFuncs := []config.CfgFunc{
|
||||||
func(c *config.CloudConfig) (*config.CloudConfig, error) {
|
func(c *config.CloudConfig) (*config.CloudConfig, error) {
|
||||||
return c, dockerlaunch.PrepareFs(&mountConfig)
|
return c, dfs.PrepareFs(&mountConfig)
|
||||||
},
|
},
|
||||||
mountOem,
|
mountOem,
|
||||||
func(_ *config.CloudConfig) (*config.CloudConfig, error) {
|
func(_ *config.CloudConfig) (*config.CloudConfig, error) {
|
||||||
@ -280,7 +280,7 @@ func RunInit() error {
|
|||||||
},
|
},
|
||||||
loadModules,
|
loadModules,
|
||||||
func(c *config.CloudConfig) (*config.CloudConfig, error) {
|
func(c *config.CloudConfig) (*config.CloudConfig, error) {
|
||||||
return c, dockerlaunch.PrepareFs(&mountConfig)
|
return c, dfs.PrepareFs(&mountConfig)
|
||||||
},
|
},
|
||||||
func(c *config.CloudConfig) (*config.CloudConfig, error) {
|
func(c *config.CloudConfig) (*config.CloudConfig, error) {
|
||||||
network.SetProxyEnvironmentVariables(c)
|
network.SetProxyEnvironmentVariables(c)
|
||||||
@ -300,7 +300,7 @@ func RunInit() error {
|
|||||||
launchConfig.Fork = !cfg.Rancher.SystemDocker.Exec
|
launchConfig.Fork = !cfg.Rancher.SystemDocker.Exec
|
||||||
|
|
||||||
log.Info("Launching System Docker")
|
log.Info("Launching System Docker")
|
||||||
_, err = dockerlaunch.LaunchDocker(launchConfig, config.SYSTEM_DOCKER_BIN, args...)
|
_, err = dfs.LaunchDocker(launchConfig, config.SYSTEM_DOCKER_BIN, args...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -10,8 +10,8 @@ import (
|
|||||||
|
|
||||||
log "github.com/Sirupsen/logrus"
|
log "github.com/Sirupsen/logrus"
|
||||||
"github.com/docker/docker/pkg/archive"
|
"github.com/docker/docker/pkg/archive"
|
||||||
"github.com/rancher/docker-from-scratch"
|
|
||||||
"github.com/rancher/os/config"
|
"github.com/rancher/os/config"
|
||||||
|
"github.com/rancher/os/dfs"
|
||||||
)
|
)
|
||||||
|
|
||||||
func cleanupTarget(rootfs, targetUsr, usr, usrVer, tmpDir string) (bool, error) {
|
func cleanupTarget(rootfs, targetUsr, usr, usrVer, tmpDir string) (bool, error) {
|
||||||
@ -21,7 +21,7 @@ func cleanupTarget(rootfs, targetUsr, usr, usrVer, tmpDir string) (bool, error)
|
|||||||
return false, err
|
return false, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := dockerlaunch.CreateSymlink(usrVer, path.Join(rootfs, "usr")); err != nil {
|
if err := dfs.CreateSymlink(usrVer, path.Join(rootfs, "usr")); err != nil {
|
||||||
return false, err
|
return false, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
4
main.go
4
main.go
@ -6,7 +6,6 @@ import (
|
|||||||
"github.com/docker/docker/docker"
|
"github.com/docker/docker/docker"
|
||||||
"github.com/docker/docker/pkg/reexec"
|
"github.com/docker/docker/pkg/reexec"
|
||||||
"github.com/rancher/cniglue"
|
"github.com/rancher/cniglue"
|
||||||
"github.com/rancher/docker-from-scratch"
|
|
||||||
"github.com/rancher/os/cmd/cloudinitexecute"
|
"github.com/rancher/os/cmd/cloudinitexecute"
|
||||||
"github.com/rancher/os/cmd/cloudinitsave"
|
"github.com/rancher/os/cmd/cloudinitsave"
|
||||||
"github.com/rancher/os/cmd/console"
|
"github.com/rancher/os/cmd/console"
|
||||||
@ -20,6 +19,7 @@ import (
|
|||||||
"github.com/rancher/os/cmd/systemdocker"
|
"github.com/rancher/os/cmd/systemdocker"
|
||||||
"github.com/rancher/os/cmd/userdocker"
|
"github.com/rancher/os/cmd/userdocker"
|
||||||
"github.com/rancher/os/cmd/wait"
|
"github.com/rancher/os/cmd/wait"
|
||||||
|
"github.com/rancher/os/dfs"
|
||||||
osInit "github.com/rancher/os/init"
|
osInit "github.com/rancher/os/init"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -30,7 +30,7 @@ var entrypoints = map[string]func(){
|
|||||||
"console.sh": console.Main,
|
"console.sh": console.Main,
|
||||||
"docker": docker.Main,
|
"docker": docker.Main,
|
||||||
"docker-init": dockerinit.Main,
|
"docker-init": dockerinit.Main,
|
||||||
"dockerlaunch": dockerlaunch.Main,
|
"dockerlaunch": dfs.Main,
|
||||||
"halt": power.Halt,
|
"halt": power.Halt,
|
||||||
"init": osInit.MainInit,
|
"init": osInit.MainInit,
|
||||||
"netconf": network.Main,
|
"netconf": network.Main,
|
||||||
|
143
netconf/bonding.go
Normal file
143
netconf/bonding.go
Normal file
@ -0,0 +1,143 @@
|
|||||||
|
package netconf
|
||||||
|
|
||||||
|
import (
|
||||||
|
"io/ioutil"
|
||||||
|
"os"
|
||||||
|
"os/exec"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/Sirupsen/logrus"
|
||||||
|
"github.com/vishvananda/netlink"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
base = "/sys/class/net/"
|
||||||
|
bondingMasters = "/sys/class/net/bonding_masters"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Bonding struct {
|
||||||
|
name string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *Bonding) init() error {
|
||||||
|
_, err := os.Stat(bondingMasters)
|
||||||
|
if os.IsNotExist(err) {
|
||||||
|
logrus.Info("Loading bonding kernel module")
|
||||||
|
cmd := exec.Command("modprobe", "bonding")
|
||||||
|
cmd.Stderr = os.Stderr
|
||||||
|
cmd.Stdout = os.Stdin
|
||||||
|
err = cmd.Run()
|
||||||
|
if err != nil {
|
||||||
|
for i := 0; i < 30; i++ {
|
||||||
|
if _, err = os.Stat(bondingMasters); err == nil {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
time.Sleep(100 * time.Millisecond)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_, err = os.Stat(bondingMasters)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func contains(file, word string) (bool, error) {
|
||||||
|
words, err := ioutil.ReadFile(file)
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, s := range strings.Split(strings.TrimSpace(string(words)), " ") {
|
||||||
|
if s == strings.TrimSpace(word) {
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *Bonding) linkDown() error {
|
||||||
|
link, err := netlink.LinkByName(b.name)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return netlink.LinkSetDown(link)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *Bonding) ListSlaves() ([]string, error) {
|
||||||
|
file := base + b.name + "/bonding/slaves"
|
||||||
|
words, err := ioutil.ReadFile(file)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
result := []string{}
|
||||||
|
for _, s := range strings.Split(strings.TrimSpace(string(words)), " ") {
|
||||||
|
if s != "" {
|
||||||
|
result = append(result, s)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *Bonding) RemoveSlave(slave string) error {
|
||||||
|
if ok, err := contains(base+b.name+"/bonding/slaves", slave); err != nil {
|
||||||
|
return err
|
||||||
|
} else if !ok {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
p := base + b.name + "/bonding/slaves"
|
||||||
|
logrus.Infof("Removing slave %s from master %s", slave, b.name)
|
||||||
|
return ioutil.WriteFile(p, []byte("-"+slave), 0644)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *Bonding) AddSlave(slave string) error {
|
||||||
|
if ok, err := contains(base+b.name+"/bonding/slaves", slave); err != nil {
|
||||||
|
return err
|
||||||
|
} else if ok {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
p := base + b.name + "/bonding/slaves"
|
||||||
|
logrus.Infof("Adding slave %s to master %s", slave, b.name)
|
||||||
|
return ioutil.WriteFile(p, []byte("+"+slave), 0644)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *Bonding) Opt(key, value string) error {
|
||||||
|
if key == "mode" {
|
||||||
|
// Don't care about errors here
|
||||||
|
b.linkDown()
|
||||||
|
slaves, _ := b.ListSlaves()
|
||||||
|
for _, slave := range slaves {
|
||||||
|
b.RemoveSlave(slave)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
p := base + b.name + "/bonding/" + key
|
||||||
|
if err := ioutil.WriteFile(p, []byte(value), 0644); err != nil {
|
||||||
|
logrus.Errorf("Failed to set %s=%s on %s: %v", key, value, b.name, err)
|
||||||
|
return err
|
||||||
|
} else {
|
||||||
|
logrus.Infof("Set %s=%s on %s", key, value, b.name)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func Bond(name string) (*Bonding, error) {
|
||||||
|
b := &Bonding{name: name}
|
||||||
|
if err := b.init(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if ok, err := contains(bondingMasters, name); err != nil {
|
||||||
|
return nil, err
|
||||||
|
} else if ok {
|
||||||
|
return b, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
logrus.Infof("Creating bond %s", name)
|
||||||
|
return b, ioutil.WriteFile(bondingMasters, []byte("+"+name), 0644)
|
||||||
|
}
|
48
netconf/bridge.go
Normal file
48
netconf/bridge.go
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
package netconf
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/vishvananda/netlink"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Bridge struct {
|
||||||
|
name string
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewBridge(name string) (*Bridge, error) {
|
||||||
|
b := &Bridge{name: name}
|
||||||
|
return b, b.init()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *Bridge) init() error {
|
||||||
|
link, err := netlink.LinkByName(b.name)
|
||||||
|
if err == nil {
|
||||||
|
if _, ok := link.(*netlink.Bridge); !ok {
|
||||||
|
return fmt.Errorf("%s is not a bridge device", b.name)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
bridge := netlink.Bridge{}
|
||||||
|
bridge.LinkAttrs.Name = b.name
|
||||||
|
|
||||||
|
return netlink.LinkAdd(&bridge)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *Bridge) AddLink(link netlink.Link) error {
|
||||||
|
existing, err := netlink.LinkByName(b.name)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if bridge, ok := existing.(*netlink.Bridge); ok {
|
||||||
|
if link.Attrs().MasterIndex != bridge.Index {
|
||||||
|
return netlink.LinkSetMaster(link, bridge)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return fmt.Errorf("%s is not a bridge", b.name)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
75
netconf/ipv4ll_linux.go
Normal file
75
netconf/ipv4ll_linux.go
Normal file
@ -0,0 +1,75 @@
|
|||||||
|
package netconf
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/binary"
|
||||||
|
"fmt"
|
||||||
|
"math/rand"
|
||||||
|
"net"
|
||||||
|
|
||||||
|
log "github.com/Sirupsen/logrus"
|
||||||
|
|
||||||
|
"github.com/j-keck/arping"
|
||||||
|
"github.com/vishvananda/netlink"
|
||||||
|
)
|
||||||
|
|
||||||
|
func AssignLinkLocalIP(link netlink.Link) error {
|
||||||
|
ifaceName := link.Attrs().Name
|
||||||
|
iface, err := net.InterfaceByName(ifaceName)
|
||||||
|
if err != nil {
|
||||||
|
log.Error("could not get information about interface")
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
addrs, err := iface.Addrs()
|
||||||
|
if err != nil {
|
||||||
|
log.Error("Error fetching existing ip on interface")
|
||||||
|
}
|
||||||
|
for _, addr := range addrs {
|
||||||
|
if addr.String()[:7] == "169.254" {
|
||||||
|
log.Info("Link Local IP already set on interface")
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
randSource, err := getPseudoRandomGenerator(link.Attrs().HardwareAddr)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
// try a random address upto 10 times
|
||||||
|
for i := 0; i < 10; i++ {
|
||||||
|
randGenerator := rand.New(*randSource)
|
||||||
|
randomNum := randGenerator.Uint32()
|
||||||
|
dstIP := getNewIPV4LLAddr(randomNum)
|
||||||
|
if dstIP[2] == 0 || dstIP[2] == 255 {
|
||||||
|
i--
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
_, _, err := arping.PingOverIfaceByName(dstIP, ifaceName)
|
||||||
|
if err != nil {
|
||||||
|
// this ip is not being used
|
||||||
|
addr, err := netlink.ParseAddr(dstIP.String() + "/16")
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf("error while parsing ipv4ll addr, err = %v", err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := netlink.AddrAdd(link, addr); err != nil {
|
||||||
|
log.Error("ipv4ll addr add failed")
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
log.Infof("Set %s on %s", dstIP.String(), link.Attrs().Name)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
log.Error("Could not find a suitable ipv4ll")
|
||||||
|
return fmt.Errorf("Could not find a suitable ipv4ll")
|
||||||
|
}
|
||||||
|
|
||||||
|
func getNewIPV4LLAddr(randomNum uint32) net.IP {
|
||||||
|
byte1 := randomNum & 255 // use least significant 8 bits
|
||||||
|
byte2 := randomNum >> 24 // use most significant 8 bits
|
||||||
|
return []byte{169, 254, byte(byte1), byte(byte2)}
|
||||||
|
}
|
||||||
|
|
||||||
|
func getPseudoRandomGenerator(haAddr []byte) (*rand.Source, error) {
|
||||||
|
seed, _ := binary.Varint(haAddr)
|
||||||
|
src := rand.NewSource(seed)
|
||||||
|
return &src, nil
|
||||||
|
}
|
396
netconf/netconf_linux.go
Normal file
396
netconf/netconf_linux.go
Normal file
@ -0,0 +1,396 @@
|
|||||||
|
package netconf
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"errors"
|
||||||
|
"net"
|
||||||
|
"os"
|
||||||
|
"os/exec"
|
||||||
|
"strings"
|
||||||
|
"sync"
|
||||||
|
"syscall"
|
||||||
|
|
||||||
|
log "github.com/Sirupsen/logrus"
|
||||||
|
"github.com/flynn/go-shlex"
|
||||||
|
|
||||||
|
"github.com/rancher/os/config"
|
||||||
|
"github.com/ryanuber/go-glob"
|
||||||
|
"github.com/vishvananda/netlink"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
CONF = "/var/lib/rancher/conf"
|
||||||
|
MODE = "mode"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
defaultDhcpArgs = []string{"dhcpcd", "-MA4"}
|
||||||
|
)
|
||||||
|
|
||||||
|
func createInterfaces(netCfg *config.NetworkConfig) {
|
||||||
|
configured := map[string]bool{}
|
||||||
|
|
||||||
|
for name, iface := range netCfg.Interfaces {
|
||||||
|
if iface.Bridge == "true" {
|
||||||
|
if _, err := NewBridge(name); err != nil {
|
||||||
|
log.Errorf("Failed to create bridge %s: %v", name, err)
|
||||||
|
}
|
||||||
|
} else if iface.Bridge != "" {
|
||||||
|
if _, err := NewBridge(iface.Bridge); err != nil {
|
||||||
|
log.Errorf("Failed to create bridge %s: %v", iface.Bridge, err)
|
||||||
|
}
|
||||||
|
} else if iface.Bond != "" {
|
||||||
|
bond, err := Bond(iface.Bond)
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf("Failed to create bond %s: %v", iface.Bond, err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if !configured[iface.Bond] {
|
||||||
|
if bondIface, ok := netCfg.Interfaces[iface.Bond]; ok {
|
||||||
|
// Other settings depends on mode, so set it first
|
||||||
|
if v, ok := bondIface.BondOpts[MODE]; ok {
|
||||||
|
bond.Opt(MODE, v)
|
||||||
|
}
|
||||||
|
|
||||||
|
for k, v := range bondIface.BondOpts {
|
||||||
|
if k != MODE {
|
||||||
|
bond.Opt(k, v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
configured[iface.Bond] = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func createSlaveInterfaces(netCfg *config.NetworkConfig) {
|
||||||
|
links, err := netlink.LinkList()
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf("Failed to list links: %v", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, link := range links {
|
||||||
|
match, ok := findMatch(link, netCfg)
|
||||||
|
if !ok {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
vlanDefs, err := ParseVlanDefinitions(match.Vlans)
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf("Failed to create vlans on device %s: %v", link.Attrs().Name, err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, vlanDef := range vlanDefs {
|
||||||
|
if _, err = NewVlan(link, vlanDef.Name, vlanDef.Id); err != nil {
|
||||||
|
log.Errorf("Failed to create vlans on device %s, id %d: %v", link.Attrs().Name, vlanDef.Id, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func findMatch(link netlink.Link, netCfg *config.NetworkConfig) (config.InterfaceConfig, bool) {
|
||||||
|
linkName := link.Attrs().Name
|
||||||
|
var match config.InterfaceConfig
|
||||||
|
exactMatch := false
|
||||||
|
found := false
|
||||||
|
|
||||||
|
for key, netConf := range netCfg.Interfaces {
|
||||||
|
if netConf.Match == "" {
|
||||||
|
netConf.Match = key
|
||||||
|
}
|
||||||
|
|
||||||
|
if netConf.Match == "" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if strings.HasPrefix(netConf.Match, "mac") {
|
||||||
|
haAddr, err := net.ParseMAC(netConf.Match[4:])
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf("Failed to parse mac %s: %v", netConf.Match[4:], err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// Don't match mac address of the bond because it is the same as the slave
|
||||||
|
if bytes.Compare(haAddr, link.Attrs().HardwareAddr) == 0 && link.Attrs().Name != netConf.Bond {
|
||||||
|
// MAC address match is used over all other matches
|
||||||
|
return netConf, true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if !exactMatch && glob.Glob(netConf.Match, linkName) {
|
||||||
|
match = netConf
|
||||||
|
found = true
|
||||||
|
}
|
||||||
|
|
||||||
|
if netConf.Match == linkName {
|
||||||
|
// Found exact match, use it over wildcard match
|
||||||
|
match = netConf
|
||||||
|
exactMatch = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return match, exactMatch || found
|
||||||
|
}
|
||||||
|
|
||||||
|
func populateDefault(netCfg *config.NetworkConfig) {
|
||||||
|
if netCfg.Interfaces == nil {
|
||||||
|
netCfg.Interfaces = map[string]config.InterfaceConfig{}
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(netCfg.Interfaces) == 0 {
|
||||||
|
netCfg.Interfaces["eth*"] = config.InterfaceConfig{
|
||||||
|
DHCP: true,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, ok := netCfg.Interfaces["lo"]; !ok {
|
||||||
|
netCfg.Interfaces["lo"] = config.InterfaceConfig{
|
||||||
|
Address: "127.0.0.1/8",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func ApplyNetworkConfigs(netCfg *config.NetworkConfig) error {
|
||||||
|
populateDefault(netCfg)
|
||||||
|
|
||||||
|
log.Debugf("Config: %#v", netCfg)
|
||||||
|
runCmds(netCfg.PreCmds, "")
|
||||||
|
|
||||||
|
createInterfaces(netCfg)
|
||||||
|
|
||||||
|
createSlaveInterfaces(netCfg)
|
||||||
|
|
||||||
|
links, err := netlink.LinkList()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
//apply network config
|
||||||
|
for _, link := range links {
|
||||||
|
linkName := link.Attrs().Name
|
||||||
|
if match, ok := findMatch(link, netCfg); ok && !match.DHCP {
|
||||||
|
if err := applyInterfaceConfig(link, match); err != nil {
|
||||||
|
log.Errorf("Failed to apply settings to %s : %v", linkName, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
runCmds(netCfg.PostCmds, "")
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func RunDhcp(netCfg *config.NetworkConfig, setHostname, setDns bool) error {
|
||||||
|
populateDefault(netCfg)
|
||||||
|
|
||||||
|
links, err := netlink.LinkList()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
dhcpLinks := map[string]string{}
|
||||||
|
for _, link := range links {
|
||||||
|
if match, ok := findMatch(link, netCfg); ok && match.DHCP {
|
||||||
|
dhcpLinks[link.Attrs().Name] = match.DHCPArgs
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//run dhcp
|
||||||
|
wg := sync.WaitGroup{}
|
||||||
|
for iface, args := range dhcpLinks {
|
||||||
|
wg.Add(1)
|
||||||
|
go func(iface, args string) {
|
||||||
|
runDhcp(netCfg, iface, args, setHostname, setDns)
|
||||||
|
wg.Done()
|
||||||
|
}(iface, args)
|
||||||
|
}
|
||||||
|
wg.Wait()
|
||||||
|
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func runDhcp(netCfg *config.NetworkConfig, iface string, argstr string, setHostname, setDns bool) {
|
||||||
|
log.Infof("Running DHCP on %s", iface)
|
||||||
|
args := []string{}
|
||||||
|
if argstr != "" {
|
||||||
|
var err error
|
||||||
|
args, err = shlex.Split(argstr)
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf("Failed to parse [%s]: %v", argstr, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if len(args) == 0 {
|
||||||
|
args = defaultDhcpArgs
|
||||||
|
}
|
||||||
|
|
||||||
|
if setHostname {
|
||||||
|
args = append(args, "-e", "force_hostname=true")
|
||||||
|
}
|
||||||
|
|
||||||
|
if !setDns {
|
||||||
|
args = append(args, "--nohook", "resolv.conf")
|
||||||
|
}
|
||||||
|
|
||||||
|
args = append(args, iface)
|
||||||
|
cmd := exec.Command(args[0], args[1:]...)
|
||||||
|
cmd.Stdout = os.Stdout
|
||||||
|
cmd.Stderr = os.Stderr
|
||||||
|
if err := cmd.Run(); err != nil {
|
||||||
|
log.Error(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func linkUp(link netlink.Link, netConf config.InterfaceConfig) error {
|
||||||
|
if err := netlink.LinkSetUp(link); err != nil {
|
||||||
|
log.Errorf("failed to setup link: %v", err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func applyAddress(address string, link netlink.Link, netConf config.InterfaceConfig) error {
|
||||||
|
addr, err := netlink.ParseAddr(address)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := netlink.AddrAdd(link, addr); err == syscall.EEXIST {
|
||||||
|
//Ignore this error
|
||||||
|
} else if err != nil {
|
||||||
|
log.Errorf("addr add failed: %v", err)
|
||||||
|
} else {
|
||||||
|
log.Infof("Set %s on %s", netConf.Address, link.Attrs().Name)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func setGateway(gateway string) error {
|
||||||
|
if gateway == "" {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
gatewayIp := net.ParseIP(gateway)
|
||||||
|
if gatewayIp == nil {
|
||||||
|
return errors.New("Invalid gateway address " + gateway)
|
||||||
|
}
|
||||||
|
|
||||||
|
route := netlink.Route{
|
||||||
|
Scope: netlink.SCOPE_UNIVERSE,
|
||||||
|
Gw: gatewayIp,
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := netlink.RouteAdd(&route); err == syscall.EEXIST {
|
||||||
|
//Ignore this error
|
||||||
|
} else if err != nil {
|
||||||
|
log.Errorf("gateway set failed: %v", err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Infof("Set default gateway %s", gateway)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func applyInterfaceConfig(link netlink.Link, netConf config.InterfaceConfig) error {
|
||||||
|
if netConf.Bond != "" {
|
||||||
|
if err := netlink.LinkSetDown(link); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
b, err := Bond(netConf.Bond)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := b.AddSlave(link.Attrs().Name); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if netConf.Bridge != "" && netConf.Bridge != "true" {
|
||||||
|
b, err := NewBridge(netConf.Bridge)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := b.AddLink(link); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return linkUp(link, netConf)
|
||||||
|
}
|
||||||
|
|
||||||
|
if netConf.IPV4LL {
|
||||||
|
if err := AssignLinkLocalIP(link); err != nil {
|
||||||
|
log.Errorf("IPV4LL set failed: %v", err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
addresses := []string{}
|
||||||
|
|
||||||
|
if netConf.Address != "" {
|
||||||
|
addresses = append(addresses, netConf.Address)
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(netConf.Addresses) > 0 {
|
||||||
|
addresses = append(addresses, netConf.Addresses...)
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, address := range addresses {
|
||||||
|
err := applyAddress(address, link, netConf)
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf("Failed to apply address %s to %s: %v", address, link.Attrs().Name, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if netConf.MTU > 0 {
|
||||||
|
if err := netlink.LinkSetMTU(link, netConf.MTU); err != nil {
|
||||||
|
log.Errorf("set MTU Failed: %v", err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
runCmds(netConf.PreUp, link.Attrs().Name)
|
||||||
|
|
||||||
|
if err := linkUp(link, netConf); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := setGateway(netConf.Gateway); err != nil {
|
||||||
|
log.Errorf("Fail to set gateway %s", netConf.Gateway)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := setGateway(netConf.GatewayIpv6); err != nil {
|
||||||
|
log.Errorf("Fail to set gateway %s", netConf.GatewayIpv6)
|
||||||
|
}
|
||||||
|
|
||||||
|
runCmds(netConf.PostUp, link.Attrs().Name)
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func runCmds(cmds []string, iface string) {
|
||||||
|
for _, cmd := range cmds {
|
||||||
|
cmd = strings.TrimSpace(cmd)
|
||||||
|
if cmd == "" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
args, err := shlex.Split(strings.Replace(cmd, "$iface", iface, -1))
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf("Failed to parse command [%s]: %v", cmd, err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Infof("Running command %s %v", args[0], args[1:])
|
||||||
|
cmd := exec.Command(args[0], args[1:]...)
|
||||||
|
cmd.Stdout = os.Stdout
|
||||||
|
cmd.Stderr = os.Stderr
|
||||||
|
if err := cmd.Run(); err != nil {
|
||||||
|
log.Errorf("Failed to run command [%v]: %v", cmd, err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
79
netconf/vlan.go
Normal file
79
netconf/vlan.go
Normal file
@ -0,0 +1,79 @@
|
|||||||
|
package netconf
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/vishvananda/netlink"
|
||||||
|
)
|
||||||
|
|
||||||
|
type VlanDefinition struct {
|
||||||
|
Id int
|
||||||
|
Name string
|
||||||
|
}
|
||||||
|
|
||||||
|
type Vlan struct {
|
||||||
|
name string
|
||||||
|
link netlink.Link
|
||||||
|
id int
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewVlan(link netlink.Link, name string, id int) (*Vlan, error) {
|
||||||
|
if name == "" {
|
||||||
|
name = fmt.Sprintf("%s.%d", link.Attrs().Name, id)
|
||||||
|
}
|
||||||
|
|
||||||
|
v := &Vlan{
|
||||||
|
name: name,
|
||||||
|
link: link,
|
||||||
|
id: id,
|
||||||
|
}
|
||||||
|
return v, v.init()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *Vlan) init() error {
|
||||||
|
link, err := netlink.LinkByName(v.name)
|
||||||
|
if err == nil {
|
||||||
|
if _, ok := link.(*netlink.Vlan); !ok {
|
||||||
|
return fmt.Errorf("%s is not a VLAN device", v.name)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
vlan := netlink.Vlan{}
|
||||||
|
vlan.ParentIndex = v.link.Attrs().Index
|
||||||
|
vlan.Name = v.name
|
||||||
|
vlan.VlanId = v.id
|
||||||
|
|
||||||
|
return netlink.LinkAdd(&vlan)
|
||||||
|
}
|
||||||
|
|
||||||
|
func ParseVlanDefinitions(vlans string) ([]VlanDefinition, error) {
|
||||||
|
vlans = strings.TrimSpace(vlans)
|
||||||
|
if vlans == "" {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
result := []VlanDefinition{}
|
||||||
|
|
||||||
|
for _, vlan := range strings.Split(vlans, ",") {
|
||||||
|
idName := strings.SplitN(strings.TrimSpace(vlan), ":", 2)
|
||||||
|
id, err := strconv.Atoi(idName[0])
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("Invalid format in %s: %v", vlans, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
def := VlanDefinition{
|
||||||
|
Id: id,
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(idName) > 1 {
|
||||||
|
def.Name = idName[1]
|
||||||
|
}
|
||||||
|
|
||||||
|
result = append(result, def)
|
||||||
|
}
|
||||||
|
|
||||||
|
return result, nil
|
||||||
|
}
|
@ -9,3 +9,8 @@ func InitializeSelinux() (int, error) {
|
|||||||
ret, err := C.selinux_init_load_policy(&enforce)
|
ret, err := C.selinux_init_load_policy(&enforce)
|
||||||
return int(ret), err
|
return int(ret), err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func SetFileContext(path string, context string) (int, error) {
|
||||||
|
ret, err := C.setfilecon(C.CString(path), C.CString(context))
|
||||||
|
return int(ret), err
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user