mirror of
https://github.com/rancher/os.git
synced 2025-07-06 11:36:15 +00:00
commit
da7abd871e
@ -1,3 +1,3 @@
|
||||
IMAGE_NAME=rancher/os
|
||||
VERSION=v0.4.3-dev
|
||||
DFS_IMAGE=rancher/docker:1.10.0
|
||||
DFS_IMAGE=rancher/docker:v1.10.0-1
|
||||
|
@ -3,6 +3,8 @@ package cloudinit
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"os"
|
||||
"path"
|
||||
"strings"
|
||||
|
||||
yaml "github.com/cloudfoundry-incubator/candiedyaml"
|
||||
@ -40,7 +42,7 @@ func enablePacketNetwork(cfg *rancherConfig.RancherConfig) {
|
||||
bondCfg := netconf.InterfaceConfig{
|
||||
Addresses: []string{},
|
||||
BondOpts: map[string]string{
|
||||
"lacp-rate": "1",
|
||||
"lacp_rate": "1",
|
||||
"xmit_hash_policy": "layer3+4",
|
||||
"downdelay": "200",
|
||||
"updelay": "200",
|
||||
@ -83,6 +85,10 @@ func enablePacketNetwork(cfg *rancherConfig.RancherConfig) {
|
||||
},
|
||||
}
|
||||
|
||||
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 := rancherConfig.WriteToFile(cc, rancherConfig.CloudConfigNetworkFile); err != nil {
|
||||
logrus.Errorf("Failed to save config file %s: %v", rancherConfig.CloudConfigNetworkFile, err)
|
||||
}
|
||||
|
@ -64,11 +64,6 @@ rancher:
|
||||
network:
|
||||
dns:
|
||||
nameservers: [8.8.8.8, 8.8.4.4]
|
||||
interfaces:
|
||||
eth*:
|
||||
dhcp: true
|
||||
lo:
|
||||
address: 127.0.0.1/8
|
||||
repositories:
|
||||
core:
|
||||
url: https://raw.githubusercontent.com/rancher/os-services/v0.4.3-dev
|
||||
|
@ -7,6 +7,8 @@ rancher:
|
||||
kernel-headers: true
|
||||
network:
|
||||
interfaces:
|
||||
eth*:
|
||||
dhcp: true
|
||||
eth1:
|
||||
address: 10.10.2.17/24
|
||||
gateway: 10.10.2.2
|
||||
|
25
tests/integration/assets/test_09/cloud-config.yml
Normal file
25
tests/integration/assets/test_09/cloud-config.yml
Normal file
@ -0,0 +1,25 @@
|
||||
#cloud-config
|
||||
rancher:
|
||||
network:
|
||||
interfaces:
|
||||
eth0:
|
||||
address: 10.0.2.15/24
|
||||
gateway: 10.0.2.2
|
||||
br0:
|
||||
vlans: 100
|
||||
eth1:
|
||||
vlans: 100,200:foobar
|
||||
eth1.100:
|
||||
bridge: br0
|
||||
br0.100:
|
||||
address: 123.123.123.123/32
|
||||
eth6:
|
||||
bond: bond0
|
||||
eth7:
|
||||
bond: bond0
|
||||
bond0:
|
||||
bond_opts:
|
||||
mode: 1
|
||||
address: 123.123.123.124/32
|
||||
ssh_authorized_keys:
|
||||
- ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC85w9stZyiLQp/DkVO6fqwiShYcj1ClKdtCqgHtf+PLpJkFReSFu8y21y+ev09gsSMRRrjF7yt0pUHV6zncQhVeqsZtgc5WbELY2DOYUGmRn/CCvPbXovoBrQjSorqlBmpuPwsStYLr92Xn+VVsMNSUIegHY22DphGbDKG85vrKB8HxUxGIDxFBds/uE8FhSy+xsoyT/jUZDK6pgq2HnGl6D81ViIlKecpOpWlW3B+fea99ADNyZNVvDzbHE5pcI3VRw8u59WmpWOUgT6qacNVACl8GqpBvQk8sw7O/X9DSZHCKafeD9G5k+GYbAUz92fKWrx/lOXfUXPS3+c8dRIF
|
36
tests/integration/rostest/test_09_network.py
Normal file
36
tests/integration/rostest/test_09_network.py
Normal file
@ -0,0 +1,36 @@
|
||||
import pytest
|
||||
import rostest.util as u
|
||||
from rostest.util import SSH
|
||||
|
||||
|
||||
cloud_config_path = './tests/integration/assets/test_09/cloud-config.yml'
|
||||
|
||||
|
||||
@pytest.fixture(scope="module")
|
||||
def qemu(request):
|
||||
q = u.run_qemu(request, run_args=['--cloud-config', cloud_config_path,
|
||||
'-net', 'nic,vlan=0,model=virtio',
|
||||
'-net', 'nic,vlan=0,model=virtio',
|
||||
'-net', 'nic,vlan=0,model=virtio',
|
||||
'-net', 'nic,vlan=0,model=virtio',
|
||||
'-net', 'nic,vlan=0,model=virtio',
|
||||
'-net', 'nic,vlan=0,model=virtio',
|
||||
'-net', 'nic,vlan=0,model=virtio'])
|
||||
u.flush_out(q.stdout)
|
||||
return q
|
||||
|
||||
|
||||
def test_network_conf(qemu):
|
||||
SSH(qemu).check_call('bash', '-c', '''cat > test-merge << "SCRIPT"
|
||||
set -x -e
|
||||
|
||||
ip link show dev br0
|
||||
ip link show dev br0.100 | grep br0.100@br0
|
||||
ip link show dev eth1.100 | grep 'master br0'
|
||||
ip link show dev eth6 | grep 'master bond0'
|
||||
ip link show dev eth7 | grep 'master bond0'
|
||||
[ "$(</sys/class/net/bond0/bonding/mode)" = "active-backup 1" ]
|
||||
|
||||
SCRIPT
|
||||
sudo bash test-merge
|
||||
'''.strip())
|
@ -66,10 +66,10 @@ import:
|
||||
version: 1349b37bd56f4f5ce2690b5b2c0f53f88a261c67
|
||||
|
||||
- package: github.com/rancher/docker-from-scratch
|
||||
version: 1.10.0
|
||||
version: v1.10.0-1
|
||||
|
||||
- package: github.com/rancher/netconf
|
||||
version: 8080e4909627bbdf51d7f427211a7c0517136373
|
||||
version: d7d620ef4ea62a9d04b51c7b3d9dc83fe7ffaa1b
|
||||
|
||||
- package: github.com/ryanuber/go-glob
|
||||
version: 0067a9abd927e50aed5190662702f81231413ae0
|
||||
|
6
vendor/github.com/rancher/docker-from-scratch/README.md
generated
vendored
6
vendor/github.com/rancher/docker-from-scratch/README.md
generated
vendored
@ -51,7 +51,7 @@ This image is really designed to run with overlay. Aufs is known to work but ot
|
||||
|
||||
## Seriously, Why?
|
||||
|
||||
This code and the supporting files were extracted out of RancherOS into a separate library and are still used by RancherOS. RancherOS runs Docker as a PID 1 but before we can exec Docker we need to setup a minimal environment for Docker in which to run. Since RancherOS is executed by the kernel there is absolutely nothing setup in the system. At Rancher we wrote a small amount of code to setup all the required mounts and directories to launch Docker.
|
||||
This code and the supporting files were extracted out of RancherOS into a separate library and are still used by RancherOS. RancherOS runs Docker as the first process but before we can exec Docker we need to setup a minimal environment for Docker in which to run. Since RancherOS is executed by the kernel there is absolutely nothing setup in the system. At Rancher we wrote a small amount of code to setup all the required mounts and directories to launch Docker.
|
||||
|
||||
We moved this code out into a separate project for two reasons. First was simply that we wanted to clean up and modularize the RancherOS code base. Second is that we wanted to demonstrate clearly what exactly Docker requires from the Linux user space. For the most part Docker requires the standard mounts (`/proc`, `/sys`, `/run`, `/var/run`, etc) and the cgroup mounts in `/sys/fs/cgroup` plus the following programs/files:
|
||||
|
||||
@ -90,6 +90,10 @@ If you want to run with a custom bridge name you must pass both `--bip` and `-b`
|
||||
|
||||
# Troubleshooting
|
||||
|
||||
## Zombies
|
||||
|
||||
If you are running containers with `--pid=host` you can get zombies. When you launch docker-from-scratch just add `-e DOCKER_LAUNCH_REAP=true` as a parameter to the `docker run` command to fix this.
|
||||
|
||||
## Weird module loading errors
|
||||
|
||||
For various reasons Docker or iptables may try to load a kernel module. You can either manually load all the needed modules from the host or you can bind mount in the kernel modules by adding `-v /lib/modules/$(uname -r)/lib/modules/$(uname -r)` to your `docker run` command
|
||||
|
23
vendor/github.com/rancher/docker-from-scratch/one.go
generated
vendored
Normal file
23
vendor/github.com/rancher/docker-from-scratch/one.go
generated
vendored
Normal file
@ -0,0 +1,23 @@
|
||||
// +build linux
|
||||
package dockerlaunch
|
||||
|
||||
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
|
||||
}
|
16
vendor/github.com/rancher/docker-from-scratch/scratch.go
generated
vendored
16
vendor/github.com/rancher/docker-from-scratch/scratch.go
generated
vendored
@ -44,6 +44,7 @@ var (
|
||||
|
||||
type Config struct {
|
||||
Fork bool
|
||||
PidOne bool
|
||||
CommandName string
|
||||
DnsConfig netconf.DnsConfig
|
||||
BridgeName string
|
||||
@ -190,6 +191,12 @@ func execDocker(config *Config, docker, cmd string, args []string) (*exec.Cmd, e
|
||||
}
|
||||
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)
|
||||
@ -273,7 +280,7 @@ func setupNetworking(config *Config) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
hostname, err := os.Hostname();
|
||||
hostname, err := os.Hostname()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -299,7 +306,7 @@ ff02::2 ip6-allrouters
|
||||
config.BridgeName: {
|
||||
Address: config.BridgeAddress,
|
||||
MTU: config.BridgeMtu,
|
||||
Bridge: true,
|
||||
Bridge: "true",
|
||||
},
|
||||
},
|
||||
}); err != nil {
|
||||
@ -578,6 +585,11 @@ func Main() {
|
||||
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...)
|
||||
|
5
vendor/github.com/rancher/docker-from-scratch/trash.yml
generated
vendored
5
vendor/github.com/rancher/docker-from-scratch/trash.yml
generated
vendored
@ -19,7 +19,7 @@ import:
|
||||
version: 4f4d2c8983a18e2c9c63a3f339bc9a998c4557bc
|
||||
|
||||
- package: github.com/rancher/netconf
|
||||
version: 02925e7cf5a0f0bb0aa5360ee260ef7378e5eff8
|
||||
version: bf95fd720be9de4f7aa3a4a529b70f2865dd0fc7
|
||||
|
||||
- package: github.com/ryanuber/go-glob
|
||||
version: 0067a9abd927e50aed5190662702f81231413ae0
|
||||
@ -32,3 +32,6 @@ import:
|
||||
|
||||
- package: github.com/vishvananda/netlink
|
||||
version: edcd99c0881a4de0fdb3818af6b24f4ee6948464
|
||||
|
||||
- package: github.com/flynn/go-shlex
|
||||
version: 3f9db97f856818214da2e1057f8ad84803971cff
|
||||
|
1
vendor/github.com/rancher/netconf/.gitignore
generated
vendored
Normal file
1
vendor/github.com/rancher/netconf/.gitignore
generated
vendored
Normal file
@ -0,0 +1 @@
|
||||
/netconf
|
114
vendor/github.com/rancher/netconf/bonding.go
generated
vendored
114
vendor/github.com/rancher/netconf/bonding.go
generated
vendored
@ -17,25 +17,20 @@ const (
|
||||
)
|
||||
|
||||
type Bonding struct {
|
||||
err error
|
||||
name string
|
||||
}
|
||||
|
||||
func (b *Bonding) Error() error {
|
||||
return b.err
|
||||
}
|
||||
|
||||
func (b *Bonding) init() {
|
||||
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
|
||||
b.err = cmd.Run()
|
||||
if b.err != nil {
|
||||
err = cmd.Run()
|
||||
if err != nil {
|
||||
for i := 0; i < 30; i++ {
|
||||
if _, err := os.Stat(bondingMasters); err == nil {
|
||||
if _, err = os.Stat(bondingMasters); err == nil {
|
||||
break
|
||||
}
|
||||
time.Sleep(100 * time.Millisecond)
|
||||
@ -43,9 +38,7 @@ func (b *Bonding) init() {
|
||||
}
|
||||
}
|
||||
_, err = os.Stat(bondingMasters)
|
||||
if err != nil {
|
||||
b.err = err
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func contains(file, word string) (bool, error) {
|
||||
@ -63,67 +56,88 @@ func contains(file, word string) (bool, error) {
|
||||
return false, nil
|
||||
}
|
||||
|
||||
func (b *Bonding) AddSlave(slave string) {
|
||||
if b.err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
if ok, err := contains(base+b.name+"/bonding/slaves", slave); err != nil {
|
||||
b.err = err
|
||||
return
|
||||
} else if ok {
|
||||
return
|
||||
}
|
||||
|
||||
link, err := netlink.LinkByName(slave)
|
||||
func (b *Bonding) linkDown() error {
|
||||
link, err := netlink.LinkByName(b.name)
|
||||
if err != nil {
|
||||
b.err = err
|
||||
return
|
||||
return err
|
||||
}
|
||||
|
||||
b.err = netlink.LinkSetDown(link)
|
||||
if b.err != nil {
|
||||
return
|
||||
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)
|
||||
b.err = ioutil.WriteFile(p, []byte("+"+slave), 0644)
|
||||
return ioutil.WriteFile(p, []byte("+"+slave), 0644)
|
||||
}
|
||||
|
||||
func (b *Bonding) Opt(key, value string) {
|
||||
if b.err != nil {
|
||||
return
|
||||
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
|
||||
b.err = ioutil.WriteFile(p, []byte(value), 0644)
|
||||
if b.err != nil {
|
||||
logrus.Errorf("Failed to set %s=%s on %s", key, value, b.name)
|
||||
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 (b *Bonding) Clear() {
|
||||
b.err = nil
|
||||
}
|
||||
|
||||
func Bond(name string) *Bonding {
|
||||
func Bond(name string) (*Bonding, error) {
|
||||
b := &Bonding{name: name}
|
||||
b.init()
|
||||
if b.err != nil {
|
||||
return b
|
||||
if err := b.init(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if ok, err := contains(bondingMasters, name); err != nil {
|
||||
b.err = err
|
||||
return b
|
||||
return nil, err
|
||||
} else if ok {
|
||||
return b
|
||||
return b, nil
|
||||
}
|
||||
|
||||
logrus.Infof("Creating bond %s", name)
|
||||
b.err = ioutil.WriteFile(bondingMasters, []byte("+"+name), 0644)
|
||||
return b
|
||||
return b, ioutil.WriteFile(bondingMasters, []byte("+"+name), 0644)
|
||||
}
|
||||
|
48
vendor/github.com/rancher/netconf/bridge.go
generated
vendored
Normal file
48
vendor/github.com/rancher/netconf/bridge.go
generated
vendored
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
|
||||
}
|
335
vendor/github.com/rancher/netconf/netconf_linux.go
generated
vendored
335
vendor/github.com/rancher/netconf/netconf_linux.go
generated
vendored
@ -3,11 +3,11 @@ package netconf
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"io/ioutil"
|
||||
"net"
|
||||
"os"
|
||||
"os/exec"
|
||||
"strings"
|
||||
"sync"
|
||||
"syscall"
|
||||
|
||||
log "github.com/Sirupsen/logrus"
|
||||
@ -18,142 +18,206 @@ import (
|
||||
)
|
||||
|
||||
const (
|
||||
CONF = "/var/lib/rancher/conf"
|
||||
NET_SCRIPT = "/var/lib/rancher/conf/network.sh"
|
||||
CONF = "/var/lib/rancher/conf"
|
||||
MODE = "mode"
|
||||
)
|
||||
|
||||
func createInterfaces(netCfg *NetworkConfig) error {
|
||||
for name, iface := range netCfg.Interfaces {
|
||||
if iface.Bridge {
|
||||
bridge := netlink.Bridge{}
|
||||
bridge.LinkAttrs.Name = name
|
||||
var (
|
||||
defaultDhcpArgs = []string{"dhcpcd", "-MA4", "-e", "force_hostname=true"}
|
||||
)
|
||||
|
||||
if err := netlink.LinkAdd(&bridge); err != nil {
|
||||
func createInterfaces(netCfg *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.Bond != "" {
|
||||
bondIface, ok := netCfg.Interfaces[iface.Bond]
|
||||
if !ok {
|
||||
log.Errorf("Failed to find bond configuration for [%s]", iface.Bond)
|
||||
continue
|
||||
} else if iface.Bridge != "" {
|
||||
if _, err := NewBridge(iface.Bridge); err != nil {
|
||||
log.Errorf("Failed to create bridge %s: %v", iface.Bridge, err)
|
||||
}
|
||||
bond := Bond(iface.Bond)
|
||||
if bond.Error() != nil {
|
||||
log.Errorf("Failed to create bond [%s]: %v", iface.Bond, bond.Error())
|
||||
} else if iface.Bond != "" {
|
||||
bond, err := Bond(iface.Bond)
|
||||
if err != nil {
|
||||
log.Errorf("Failed to create bond %s: %v", iface.Bond, err)
|
||||
continue
|
||||
}
|
||||
|
||||
for k, v := range bondIface.BondOpts {
|
||||
bond.Opt(k, v)
|
||||
bond.Clear()
|
||||
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
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func runScript(netCfg *NetworkConfig) error {
|
||||
if netCfg.Script == "" {
|
||||
return nil
|
||||
func createSlaveInterfaces(netCfg *NetworkConfig) {
|
||||
links, err := netlink.LinkList()
|
||||
if err != nil {
|
||||
log.Errorf("Failed to list links: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
if _, err := os.Stat(CONF); os.IsNotExist(err) {
|
||||
if err := os.MkdirAll(CONF, 0700); err != nil {
|
||||
return err
|
||||
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 *NetworkConfig) (InterfaceConfig, bool) {
|
||||
linkName := link.Attrs().Name
|
||||
var match 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
|
||||
}
|
||||
}
|
||||
|
||||
if err := ioutil.WriteFile(NET_SCRIPT, []byte(netCfg.Script), 0700); err != nil {
|
||||
return err
|
||||
return match, exactMatch || found
|
||||
}
|
||||
|
||||
func populateDefault(netCfg *NetworkConfig) {
|
||||
if netCfg.Interfaces == nil {
|
||||
netCfg.Interfaces = map[string]InterfaceConfig{}
|
||||
}
|
||||
|
||||
cmd := exec.Command(NET_SCRIPT)
|
||||
cmd.Stdout = os.Stdout
|
||||
cmd.Stderr = os.Stderr
|
||||
return cmd.Run()
|
||||
if len(netCfg.Interfaces) == 0 {
|
||||
netCfg.Interfaces["eth*"] = InterfaceConfig{
|
||||
DHCP: true,
|
||||
}
|
||||
}
|
||||
|
||||
if _, ok := netCfg.Interfaces["lo"]; !ok {
|
||||
netCfg.Interfaces["lo"] = InterfaceConfig{
|
||||
Address: "127.0.0.1/8",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func ApplyNetworkConfigs(netCfg *NetworkConfig) error {
|
||||
log.Debugf("Config: %#v", netCfg)
|
||||
if err := runScript(netCfg); err != nil {
|
||||
log.Errorf("Failed to run script: %v", err)
|
||||
}
|
||||
populateDefault(netCfg)
|
||||
|
||||
if err := createInterfaces(netCfg); err != nil {
|
||||
return err
|
||||
}
|
||||
log.Debugf("Config: %#v", netCfg)
|
||||
runCmds(netCfg.PreCmds, "")
|
||||
|
||||
createInterfaces(netCfg)
|
||||
|
||||
createSlaveInterfaces(netCfg)
|
||||
|
||||
links, err := netlink.LinkList()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
dhcpLinks := []string{}
|
||||
dhcpLinks := map[string]string{}
|
||||
|
||||
//apply network config
|
||||
for _, link := range links {
|
||||
linkName := link.Attrs().Name
|
||||
var match InterfaceConfig
|
||||
|
||||
for key, netConf := range netCfg.Interfaces {
|
||||
if netConf.Match == "" {
|
||||
netConf.Match = key
|
||||
}
|
||||
|
||||
if netConf.Match == "" {
|
||||
continue
|
||||
}
|
||||
|
||||
if len(netConf.Match) > 4 && strings.ToLower(netConf.Match[:3]) == "mac" {
|
||||
haAddr, err := net.ParseMAC(netConf.Match[4:])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// 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
|
||||
match = netConf
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
// "" means match has not been found
|
||||
if match.Match == "" && matches(linkName, netConf.Match) {
|
||||
match = netConf
|
||||
}
|
||||
|
||||
if netConf.Match == linkName {
|
||||
// Found exact match, use it over wildcard match
|
||||
match = netConf
|
||||
}
|
||||
}
|
||||
|
||||
if match.Match != "" {
|
||||
if match, ok := findMatch(link, netCfg); ok {
|
||||
if match.DHCP {
|
||||
dhcpLinks = append(dhcpLinks, link.Attrs().Name)
|
||||
} else if err = applyNetConf(link, match); err != nil {
|
||||
dhcpLinks[link.Attrs().Name] = match.DHCPArgs
|
||||
} else if err = applyInterfaceConfig(link, match); err != nil {
|
||||
log.Errorf("Failed to apply settings to %s : %v", linkName, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if len(dhcpLinks) > 0 {
|
||||
log.Infof("Running DHCP on %v", dhcpLinks)
|
||||
dhcpcdArgs := append([]string{"-MA4", "-e", "force_hostname=true"}, dhcpLinks...)
|
||||
cmd := exec.Command("dhcpcd", dhcpcdArgs...)
|
||||
cmd.Stdout = os.Stdout
|
||||
cmd.Stderr = os.Stderr
|
||||
if err := cmd.Run(); err != nil {
|
||||
log.Error(err)
|
||||
//run dhcp
|
||||
wg := sync.WaitGroup{}
|
||||
for iface, args := range dhcpLinks {
|
||||
wg.Add(1)
|
||||
go func(iface, args string) {
|
||||
runDhcp(iface, args)
|
||||
wg.Done()
|
||||
}(iface, args)
|
||||
}
|
||||
wg.Wait()
|
||||
|
||||
runCmds(netCfg.PostCmds, "")
|
||||
return err
|
||||
}
|
||||
|
||||
func runDhcp(iface string, argstr string) {
|
||||
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 err != nil {
|
||||
return err
|
||||
if len(args) == 0 {
|
||||
args = defaultDhcpArgs
|
||||
}
|
||||
|
||||
return nil
|
||||
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 InterfaceConfig) error {
|
||||
@ -207,15 +271,27 @@ func setGateway(gateway string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func applyNetConf(link netlink.Link, netConf InterfaceConfig) error {
|
||||
func applyInterfaceConfig(link netlink.Link, netConf InterfaceConfig) error {
|
||||
if netConf.Bond != "" {
|
||||
b := Bond(netConf.Bond)
|
||||
b.AddSlave(link.Attrs().Name)
|
||||
if b.Error() != nil {
|
||||
return b.Error()
|
||||
b, err := Bond(netConf.Bond)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := b.AddSlave(link.Attrs().Name); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
return linkUp(link, netConf)
|
||||
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 nil
|
||||
}
|
||||
|
||||
if netConf.IPV4LL {
|
||||
@ -223,16 +299,18 @@ func applyNetConf(link netlink.Link, netConf InterfaceConfig) error {
|
||||
log.Errorf("IPV4LL set failed: %v", err)
|
||||
return err
|
||||
}
|
||||
} else if netConf.Address == "" && len(netConf.Addresses) == 0 {
|
||||
return nil
|
||||
} else {
|
||||
addresses := []string{}
|
||||
|
||||
if netConf.Address != "" {
|
||||
err := applyAddress(netConf.Address, link, netConf)
|
||||
if err != nil {
|
||||
log.Errorf("Failed to apply address %s to %s: %v", netConf.Address, link.Attrs().Name, err)
|
||||
}
|
||||
addresses = append(addresses, netConf.Address)
|
||||
}
|
||||
for _, address := range netConf.Addresses {
|
||||
|
||||
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)
|
||||
@ -247,6 +325,8 @@ func applyNetConf(link netlink.Link, netConf InterfaceConfig) error {
|
||||
}
|
||||
}
|
||||
|
||||
runCmds(netConf.PreUp, link.Attrs().Name)
|
||||
|
||||
if err := linkUp(link, netConf); err != nil {
|
||||
return err
|
||||
}
|
||||
@ -259,30 +339,31 @@ func applyNetConf(link netlink.Link, netConf InterfaceConfig) error {
|
||||
log.Errorf("Fail to set gateway %s", netConf.Gateway)
|
||||
}
|
||||
|
||||
for _, postUp := range netConf.PostUp {
|
||||
postUp = strings.TrimSpace(postUp)
|
||||
if postUp == "" {
|
||||
continue
|
||||
}
|
||||
|
||||
args, err := shlex.Split(strings.Replace(postUp, "$iface", link.Attrs().Name, -1))
|
||||
if err != nil {
|
||||
log.Errorf("Failed to parse command [%s]: %v", postUp, err)
|
||||
continue
|
||||
}
|
||||
|
||||
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 [%s]: %v", postUp, err)
|
||||
continue
|
||||
}
|
||||
}
|
||||
runCmds(netConf.PostUp, link.Attrs().Name)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func matches(link, conf string) bool {
|
||||
return glob.Glob(conf, link)
|
||||
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 [%s]: %v", cmd, err)
|
||||
continue
|
||||
}
|
||||
}
|
||||
}
|
||||
|
8
vendor/github.com/rancher/netconf/types.go
generated
vendored
8
vendor/github.com/rancher/netconf/types.go
generated
vendored
@ -1,24 +1,28 @@
|
||||
package netconf
|
||||
|
||||
type NetworkConfig struct {
|
||||
Script string `yaml:"script,omitempty"`
|
||||
PreCmds []string `yaml:"pre_cmds,omitempty"`
|
||||
Dns DnsConfig `yaml:"dns,omitempty"`
|
||||
Interfaces map[string]InterfaceConfig `yaml:"interfaces,omitempty"`
|
||||
PostCmds []string `yaml:"post_cmds,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 bool `yaml:"bridge,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 {
|
||||
|
79
vendor/github.com/rancher/netconf/vlan.go
generated
vendored
Normal file
79
vendor/github.com/rancher/netconf/vlan.go
generated
vendored
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
|
||||
}
|
Loading…
Reference in New Issue
Block a user