diff --git a/cmd/network/network.go b/cmd/network/network.go new file mode 100644 index 00000000..49a1a031 --- /dev/null +++ b/cmd/network/network.go @@ -0,0 +1,100 @@ +package network + +import ( + "errors" + "fmt" + "net" + "os" + "os/exec" + + log "github.com/Sirupsen/logrus" + + "github.com/rancherio/os/config" + "github.com/rancherio/os/docker" + "github.com/ryanuber/go-glob" + "github.com/vishvananda/netlink" +) + +func Main() { + args := os.Args + if len(args) > 1 { + fmt.Println("call " + args[0] + "to load network config from rancher.yml config file") + return + } + cfg, err := config.LoadConfig() + if err != nil { + log.Fatal(err) + } + applyNetworkConfigs(cfg) +} + +func applyNetworkConfigs(cfg *config.Config) error { + links, err := netlink.LinkList() + if err != nil { + return err + } + + //apply network config + for _, netConf := range cfg.Network.Interfaces { + for _, link := range links { + err := applyNetConf(link, netConf) + if err != nil { + log.Fatal(err) + } + } + } + + //post run + if cfg.Network.PostRun != nil { + return docker.StartAndWait(config.DOCKER_HOST, cfg.Network.PostRun) + } + return nil +} + +func applyNetConf(link netlink.Link, netConf config.InterfaceConfig) error { + if matches(link.Attrs().Name, netConf.Match) { + if netConf.DHCP { + cmd := exec.Command("udhcpc", "-i", link.Attrs().Name) + cmd.Stdout = os.Stdout + cmd.Stderr = os.Stderr + if err := cmd.Run(); err != nil { + log.Error(err) + } + } else { + if netConf.Address == "" { + return errors.New("DHCP is false and Address is not set") + } + addr, err := netlink.ParseAddr(netConf.Address) + if err != nil { + return err + } + if err := netlink.AddrAdd(link, addr); err != nil { + log.Error("addr add failed") + return err + } + } + if netConf.MTU > 0 { + if err := netlink.LinkSetMTU(link, netConf.MTU); err != nil { + log.Error("set MTU Failed") + return err + } + } + if netConf.Gateway != "" { + route := netlink.Route{LinkIndex: link.Attrs().Index, Scope: netlink.SCOPE_LINK, Gw: net.ParseIP(netConf.Gateway)} + if err := netlink.RouteAdd(&route); err != nil { + log.Error("gateway set failed") + return err + } + } + if err := netlink.LinkSetUp(link); err != nil { + log.Error("failed to setup link") + return err + } + } + return nil +} + +func matches(link, conf string) bool { + return glob.Glob(conf, link) +} + diff --git a/config/config.go b/config/config.go index 5746c8fb..b270b378 100644 --- a/config/config.go +++ b/config/config.go @@ -55,6 +55,20 @@ type Config struct { SshInfo SshInfo `yaml:"ssh"` EnabledAddons []string `yaml:"enabledAddons,omitempty"` Addons map[string]Config `yaml:"addons,omitempty"` + Network NetworkConfig `yaml:"network_config,omitempty"` +} + +type NetworkConfig struct { + Interfaces []InterfaceConfig `yaml:"config"` + PostRun *ContainerConfig `yaml:"post_run"` +} + +type InterfaceConfig struct { + Match string `yaml:"match"` + DHCP bool `yaml:"dhcp"` + Address string `yaml:"address,omitempty"` + Gateway string `yaml:"gateway,omitempty"` + MTU int `yaml:"mtu,omitempty"` } type UserDockerInfo struct { diff --git a/config/default.go b/config/default.go index e6fbcb70..2205bf65 100644 --- a/config/default.go +++ b/config/default.go @@ -17,6 +17,14 @@ func NewConfig() *Config { Userdocker: UserDockerInfo{ UseTLS: true, }, + Network: NetworkConfig { + Interfaces: []InterfaceConfig { + { + Match: "*", + DHCP: true, + }, + }, + }, CloudInit: CloudInit{ Datasources: []string{"configdrive:/media/config-2"}, }, @@ -41,8 +49,8 @@ func NewConfig() *Config { "-v=/init:/sbin/poweroff:ro " + "-v=/init:/sbin/reboot:ro " + "-v=/init:/sbin/shutdown:ro " + + "-v=/init:/sbin/netconf:ro " + "-v=/init:/usr/bin/cloud-init:ro " + - "-v=/init:/usr/bin/tlsconf:ro " + "-v=/init:/usr/bin/rancherctl:ro " + "-v=/init:/usr/bin/respawn:ro " + "-v=/init:/usr/bin/system-docker:ro " + diff --git a/main.go b/main.go index 39e73a93..729184dc 100644 --- a/main.go +++ b/main.go @@ -12,6 +12,7 @@ import ( "github.com/rancherio/os/cmd/respawn" "github.com/rancherio/os/cmd/sysinit" "github.com/rancherio/os/cmd/systemdocker" + "github.com/rancherio/os/cmd/network" osInit "github.com/rancherio/os/init" ) @@ -44,6 +45,7 @@ func main() { registerCmd("/usr/bin/respawn", respawn.Main) registerCmd("/usr/sbin/rancherctl", control.Main) registerCmd("/usr/bin/cloud-init", cloudinit.Main) + registerCmd("/usr/sbin/netconf", network.Main) if !reexec.Init() { log.Fatalf("Failed to find an entry point for %s", os.Args[0])