mirror of
https://github.com/rancher/os.git
synced 2025-07-16 16:11:03 +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/url"
|
||||
"github.com/coreos/coreos-cloudinit/pkg"
|
||||
"github.com/rancher/netconf"
|
||||
"github.com/rancher/os/cmd/cloudinitsave/gce"
|
||||
rancherConfig "github.com/rancher/os/config"
|
||||
"github.com/rancher/os/netconf"
|
||||
"github.com/rancher/os/util"
|
||||
)
|
||||
|
||||
@ -231,8 +231,8 @@ func getDatasources(cfg *rancherConfig.CloudConfig) []datasource.Datasource {
|
||||
}
|
||||
|
||||
func enableDoLinkLocal() {
|
||||
err := netconf.ApplyNetworkConfigs(&netconf.NetworkConfig{
|
||||
Interfaces: map[string]netconf.InterfaceConfig{
|
||||
err := netconf.ApplyNetworkConfigs(&rancherConfig.NetworkConfig{
|
||||
Interfaces: map[string]rancherConfig.InterfaceConfig{
|
||||
"eth0": {
|
||||
IPV4LL: true,
|
||||
},
|
||||
|
@ -12,11 +12,11 @@ import (
|
||||
|
||||
"github.com/Sirupsen/logrus"
|
||||
"github.com/packethost/packngo/metadata"
|
||||
"github.com/rancher/netconf"
|
||||
rancherConfig "github.com/rancher/os/config"
|
||||
"github.com/rancher/os/config"
|
||||
"github.com/rancher/os/netconf"
|
||||
)
|
||||
|
||||
func enablePacketNetwork(cfg *rancherConfig.RancherConfig) {
|
||||
func enablePacketNetwork(cfg *config.RancherConfig) {
|
||||
bootStrapped := false
|
||||
for _, v := range cfg.Network.Interfaces {
|
||||
if v.Address != "" {
|
||||
@ -40,7 +40,7 @@ func enablePacketNetwork(cfg *rancherConfig.RancherConfig) {
|
||||
return
|
||||
}
|
||||
|
||||
bondCfg := netconf.InterfaceConfig{
|
||||
bondCfg := config.InterfaceConfig{
|
||||
Addresses: []string{},
|
||||
BondOpts: map[string]string{
|
||||
"lacp_rate": "1",
|
||||
@ -51,11 +51,11 @@ func enablePacketNetwork(cfg *rancherConfig.RancherConfig) {
|
||||
"mode": "4",
|
||||
},
|
||||
}
|
||||
netCfg := netconf.NetworkConfig{
|
||||
Interfaces: map[string]netconf.InterfaceConfig{},
|
||||
netCfg := config.NetworkConfig{
|
||||
Interfaces: map[string]config.InterfaceConfig{},
|
||||
}
|
||||
for _, iface := range m.Network.Interfaces {
|
||||
netCfg.Interfaces["mac="+iface.Mac] = netconf.InterfaceConfig{
|
||||
netCfg.Interfaces["mac="+iface.Mac] = config.InterfaceConfig{
|
||||
Bond: "bond0",
|
||||
}
|
||||
}
|
||||
@ -80,24 +80,24 @@ func enablePacketNetwork(cfg *rancherConfig.RancherConfig) {
|
||||
b, _ := yaml.Marshal(netCfg)
|
||||
logrus.Debugf("Generated network config: %s", string(b))
|
||||
|
||||
cc := rancherConfig.CloudConfig{
|
||||
Rancher: rancherConfig.RancherConfig{
|
||||
cc := config.CloudConfig{
|
||||
Rancher: config.RancherConfig{
|
||||
Network: netCfg,
|
||||
},
|
||||
}
|
||||
|
||||
// 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 {
|
||||
logrus.Errorf("Failed to post to Packet phone home URL: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
if err := os.MkdirAll(path.Dir(rancherConfig.CloudConfigNetworkFile), 0700); err != nil {
|
||||
logrus.Errorf("Failed to create directory for file %s: %v", rancherConfig.CloudConfigNetworkFile, err)
|
||||
if err := os.MkdirAll(path.Dir(config.CloudConfigNetworkFile), 0700); err != nil {
|
||||
logrus.Errorf("Failed to create directory for file %s: %v", config.CloudConfigNetworkFile, err)
|
||||
}
|
||||
|
||||
if err := rancherConfig.WriteToFile(cc, rancherConfig.CloudConfigNetworkFile); err != nil {
|
||||
logrus.Errorf("Failed to save config file %s: %v", rancherConfig.CloudConfigNetworkFile, err)
|
||||
if err := config.WriteToFile(cc, config.CloudConfigNetworkFile); err != nil {
|
||||
logrus.Errorf("Failed to save config file %s: %v", config.CloudConfigNetworkFile, err)
|
||||
}
|
||||
}
|
||||
|
@ -9,10 +9,10 @@ import (
|
||||
log "github.com/Sirupsen/logrus"
|
||||
|
||||
"github.com/docker/libnetwork/resolvconf"
|
||||
"github.com/rancher/netconf"
|
||||
"github.com/rancher/os/config"
|
||||
"github.com/rancher/os/docker"
|
||||
"github.com/rancher/os/hostname"
|
||||
"github.com/rancher/os/netconf"
|
||||
)
|
||||
|
||||
var (
|
||||
|
@ -7,7 +7,6 @@ import (
|
||||
"github.com/coreos/coreos-cloudinit/config"
|
||||
"github.com/docker/engine-api/types"
|
||||
composeConfig "github.com/docker/libcompose/config"
|
||||
"github.com/rancher/netconf"
|
||||
)
|
||||
|
||||
const (
|
||||
@ -113,8 +112,8 @@ type RancherConfig struct {
|
||||
Disable []string `yaml:"disable,omitempty"`
|
||||
ServicesInclude map[string]bool `yaml:"services_include,omitempty"`
|
||||
Modules []string `yaml:"modules,omitempty"`
|
||||
Network netconf.NetworkConfig `yaml:"network,omitempty"`
|
||||
DefaultNetwork netconf.NetworkConfig `yaml:"default_network,omitempty"`
|
||||
Network NetworkConfig `yaml:"network,omitempty"`
|
||||
DefaultNetwork NetworkConfig `yaml:"default_network,omitempty"`
|
||||
Repositories Repositories `yaml:"repositories,omitempty"`
|
||||
Ssh SshConfig `yaml:"ssh,omitempty"`
|
||||
State StateConfig `yaml:"state,omitempty"`
|
||||
@ -169,6 +168,39 @@ type DockerConfig struct {
|
||||
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 {
|
||||
Keys map[string]string `yaml:"keys,omitempty"`
|
||||
}
|
||||
@ -191,9 +223,9 @@ type CloudInit struct {
|
||||
}
|
||||
|
||||
type Defaults struct {
|
||||
Hostname string `yaml:"hostname,omitempty"`
|
||||
Docker DockerConfig `yaml:"docker,omitempty"`
|
||||
Network netconf.NetworkConfig `yaml:"network,omitempty"`
|
||||
Hostname string `yaml:"hostname,omitempty"`
|
||||
Docker DockerConfig `yaml:"docker,omitempty"`
|
||||
Network NetworkConfig `yaml:"network,omitempty"`
|
||||
}
|
||||
|
||||
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"
|
||||
|
||||
log "github.com/Sirupsen/logrus"
|
||||
"github.com/rancher/docker-from-scratch"
|
||||
"github.com/rancher/os/compose"
|
||||
"github.com/rancher/os/config"
|
||||
"github.com/rancher/os/dfs"
|
||||
"github.com/rancher/os/util"
|
||||
)
|
||||
|
||||
@ -36,7 +36,7 @@ func startDocker(cfg *config.CloudConfig) (chan interface{}, error) {
|
||||
launchConfig.LogFile = ""
|
||||
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 {
|
||||
return nil, err
|
||||
}
|
||||
|
16
init/init.go
16
init/init.go
@ -12,8 +12,8 @@ import (
|
||||
|
||||
log "github.com/Sirupsen/logrus"
|
||||
"github.com/docker/docker/pkg/mount"
|
||||
"github.com/rancher/docker-from-scratch"
|
||||
"github.com/rancher/os/config"
|
||||
"github.com/rancher/os/dfs"
|
||||
"github.com/rancher/os/util"
|
||||
"github.com/rancher/os/util/network"
|
||||
)
|
||||
@ -27,7 +27,7 @@ const (
|
||||
)
|
||||
|
||||
var (
|
||||
mountConfig = dockerlaunch.Config{
|
||||
mountConfig = dfs.Config{
|
||||
CgroupHierarchy: map[string]string{
|
||||
"cpu": "cpu",
|
||||
"cpuacct": "cpu",
|
||||
@ -162,10 +162,10 @@ func tryMountAndBootstrap(cfg *config.CloudConfig) (*config.CloudConfig, error)
|
||||
return mountOem(cfg)
|
||||
}
|
||||
|
||||
func getLaunchConfig(cfg *config.CloudConfig, dockerCfg *config.DockerConfig) (*dockerlaunch.Config, []string) {
|
||||
var launchConfig dockerlaunch.Config
|
||||
func getLaunchConfig(cfg *config.CloudConfig, dockerCfg *config.DockerConfig) (*dfs.Config, []string) {
|
||||
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.Search = cfg.Rancher.Defaults.Network.Dns.Search
|
||||
@ -220,7 +220,7 @@ func RunInit() error {
|
||||
boot2DockerEnvironment := false
|
||||
initFuncs := []config.CfgFunc{
|
||||
func(c *config.CloudConfig) (*config.CloudConfig, error) {
|
||||
return c, dockerlaunch.PrepareFs(&mountConfig)
|
||||
return c, dfs.PrepareFs(&mountConfig)
|
||||
},
|
||||
mountOem,
|
||||
func(_ *config.CloudConfig) (*config.CloudConfig, error) {
|
||||
@ -280,7 +280,7 @@ func RunInit() error {
|
||||
},
|
||||
loadModules,
|
||||
func(c *config.CloudConfig) (*config.CloudConfig, error) {
|
||||
return c, dockerlaunch.PrepareFs(&mountConfig)
|
||||
return c, dfs.PrepareFs(&mountConfig)
|
||||
},
|
||||
func(c *config.CloudConfig) (*config.CloudConfig, error) {
|
||||
network.SetProxyEnvironmentVariables(c)
|
||||
@ -300,7 +300,7 @@ func RunInit() error {
|
||||
launchConfig.Fork = !cfg.Rancher.SystemDocker.Exec
|
||||
|
||||
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 {
|
||||
return err
|
||||
}
|
||||
|
@ -10,8 +10,8 @@ import (
|
||||
|
||||
log "github.com/Sirupsen/logrus"
|
||||
"github.com/docker/docker/pkg/archive"
|
||||
"github.com/rancher/docker-from-scratch"
|
||||
"github.com/rancher/os/config"
|
||||
"github.com/rancher/os/dfs"
|
||||
)
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
|
4
main.go
4
main.go
@ -6,7 +6,6 @@ import (
|
||||
"github.com/docker/docker/docker"
|
||||
"github.com/docker/docker/pkg/reexec"
|
||||
"github.com/rancher/cniglue"
|
||||
"github.com/rancher/docker-from-scratch"
|
||||
"github.com/rancher/os/cmd/cloudinitexecute"
|
||||
"github.com/rancher/os/cmd/cloudinitsave"
|
||||
"github.com/rancher/os/cmd/console"
|
||||
@ -20,6 +19,7 @@ import (
|
||||
"github.com/rancher/os/cmd/systemdocker"
|
||||
"github.com/rancher/os/cmd/userdocker"
|
||||
"github.com/rancher/os/cmd/wait"
|
||||
"github.com/rancher/os/dfs"
|
||||
osInit "github.com/rancher/os/init"
|
||||
)
|
||||
|
||||
@ -30,7 +30,7 @@ var entrypoints = map[string]func(){
|
||||
"console.sh": console.Main,
|
||||
"docker": docker.Main,
|
||||
"docker-init": dockerinit.Main,
|
||||
"dockerlaunch": dockerlaunch.Main,
|
||||
"dockerlaunch": dfs.Main,
|
||||
"halt": power.Halt,
|
||||
"init": osInit.MainInit,
|
||||
"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)
|
||||
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