From 4ea1d1f52bed807c8a0261cca8fc0bb7df0876e8 Mon Sep 17 00:00:00 2001 From: Sangbum Kim Date: Sun, 13 May 2018 18:16:43 +0900 Subject: [PATCH] =?UTF-8?q?subnet=20=EC=B0=BE=EB=8A=94=20=EB=AA=A8?= =?UTF-8?q?=EB=93=9C=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- octopus-outside/main.go | 164 +++++++++++++++++++++++------- services/octopus-outside@.service | 2 +- 2 files changed, 126 insertions(+), 40 deletions(-) diff --git a/octopus-outside/main.go b/octopus-outside/main.go index 27e9376..01a4aac 100644 --- a/octopus-outside/main.go +++ b/octopus-outside/main.go @@ -1,7 +1,6 @@ package main import ( - "bytes" "errors" "fmt" @@ -14,7 +13,7 @@ import ( "io/ioutil" - kingpin "gopkg.in/alecthomas/kingpin.v2" + "gopkg.in/alecthomas/kingpin.v2" "gopkg.in/yaml.v2" "strconv" @@ -26,36 +25,37 @@ import ( type cmdList []string func (i *cmdList) Set(value string) error { - *i = append(*i, value) - return nil + *i = append(*i, value) + return nil } func (i *cmdList) String() string { - return "" + return "" } func (i *cmdList) IsCumulative() bool { - return true + return true } func CmdList(s kingpin.Settings) (target *[]string) { - target = new([]string) - s.SetValue((*cmdList)(target)) - return + target = new([]string) + s.SetValue((*cmdList)(target)) + return } var ( app = kingpin.New("octopus-outside", "nspawn Bootstrapper.").Author("Sangbum Kim") verbosePtr = app.Flag("verbose", "Enable verbose mode.").Short('v').Bool() clearPtr = app.Flag("clear", "clear os environment.").Short('p').Bool() - ifBindTypePtr = app.Flag("if-bind-type", "choose virtual ethernet bind type(ipvlan,macvlan).").Default("ipvlan").Short('b').Enum("ipvlan","macvlan") + ifBindTypePtr = app.Flag("if-bind-type", "choose virtual ethernet bind type(ipvlan,macvlan).").Default("ipvlan").Short('b').Enum("ipvlan", "macvlan") + isFindSubnetPtr = app.Flag("subnet-scan", "find subnet mode. if not specify, use default network scan mode.").Short('t').Default("false").Bool() macAddrPtr = app.Flag("mac-address", "Specify MAC address of macvlan mode. if not specify, use random.").Short('a').String() nspawnPathPtr = app.Flag("nspawn-path", "systemd-nspawn location.").Short('s').String() containerHomePtr = app.Flag("container-home", "container residence path").Default("/container").Short('d').String() configFileNamePtr = app.Flag("config-file", "config file name").Default("settings.yml").HintOptions("FILENAME").Short('c').String() nodeNamePtr = app.Arg("nodeName", "nodename to spawn.").Required().String() bindIfNamePtr = app.Arg("bindInterface", "interface name to bind.").Required().String() - cmdListArgsPtr = CmdList(app.Arg("cmd","execute command rather than boot process")) + cmdListArgsPtr = CmdList(app.Arg("cmd", "execute command rather than boot process")) ) type mountPoint struct { @@ -64,13 +64,12 @@ type mountPoint struct { Readonly bool `yaml:"readonly"` } - func (mp mountPoint) Option(nodePath string) (option string, err error) { var mountPointPath string - if filepath.IsAbs(mp.Name){ - mountPointPath= mp.Name - }else{ - mountPointPath= filepath.Clean(filepath.Join(nodePath, "volume", mp.Name)) + if filepath.IsAbs(mp.Name) { + mountPointPath = mp.Name + } else { + mountPointPath = filepath.Clean(filepath.Join(nodePath, "volume", mp.Name)) } if _, err = os.Stat(mountPointPath); os.IsNotExist(err) { @@ -128,6 +127,84 @@ func getIP(host string) (ip net.IP, err error) { return addrs[0], nil } +func getCidr(network net.IPNet) (cidr uint64, err error) { + netSlice := strings.Split(network.String(), "/") + if len(netSlice) < 2 { + err = errors.New("cannot get netmask") + return + } + cidr, err = strconv.ParseUint(netSlice[len(netSlice)-1], 10, 64) + return +} +func getSubnetIPInfo(ip net.IP, verbose bool) (gw net.IP, cidr uint64, linkname string, err error) { + // netlink.RouteList + var links []netlink.Link + links, err = netlink.LinkList() + if err != nil { + return + } + + if verbose { + fmt.Println("scan system network interfaces:") + } + + for _, link := range links { + attrs := link.Attrs() + + if verbose { + fmt.Printf(" interface %s : ", attrs.Name) + } + if (attrs.Flags & net.FlagUp) == 0 { + if verbose { + fmt.Printf(" not up -- abandon!\n") + } + continue + } else { + if verbose { + fmt.Printf(" up!\n") + } + } + if verbose { + fmt.Println(" getting routing tables ") + } + var routes []netlink.Route + routes, err = netlink.RouteList(link, netlink.FAMILY_V4) + if err != nil { + continue + } + var ( + matchedRoute *netlink.Route + ) + for _, route := range routes { + + if verbose { + fmt.Printf(" routing table %s\n", route.String()) + } + if route.Dst.Contains(ip) { + if verbose { + fmt.Printf(" - matched routing role : %s\n", route.String()) + } + matchedRoute = &route + break + } else if verbose { + fmt.Printf(" - no subnet gateway\n") + } + } + + if cidrData, err := getCidr(*matchedRoute.Dst); err == nil { + cidr = cidrData + if verbose { + fmt.Printf(" interface have a subnet routing rule. gateway: %s", matchedRoute) + fmt.Println(" ok! matched ") + } + gw, cidr, linkname = matchedRoute.Gw, cidrData, attrs.Name + } else if verbose { + fmt.Printf(" - cannot getting netmask : %s", err) + fmt.Println(" abandon this interface ") + } + } + return +} func getOutboundIPInfo(verbose bool) (gw net.IP, cidr uint64, linkname string, err error) { // netlink.RouteList var links []netlink.Link @@ -210,14 +287,12 @@ func getOutboundIPInfo(verbose bool) (gw net.IP, cidr uint64, linkname string, e if verbose { fmt.Printf(" - default network\n") } - netSlice := strings.Split(network.IPNet.String(), "/") - if len(netSlice) < 2 { - continue - } - if cidrData, err := strconv.ParseUint(netSlice[len(netSlice)-1], 10, 64); err == nil { + if cidrData, err := getCidr(*network.IPNet); err == nil { matchedCidr = cidrData cidrOk = true break + } else if verbose { + fmt.Printf(" - cannot getting netmask : %s", err) } } else if verbose { fmt.Printf(" - no default network\n") @@ -315,9 +390,10 @@ func main() { var ( verbose = *verbosePtr ifBindType = *ifBindTypePtr - macAddr = strings.TrimSpace(*macAddrPtr) + macAddr = strings.TrimSpace(*macAddrPtr) clear = *clearPtr nodeName = *nodeNamePtr + isFindSubnet = *isFindSubnetPtr bindIfName = *bindIfNamePtr configFileName = *configFileNamePtr cmdListArgs = *cmdListArgsPtr @@ -389,9 +465,19 @@ func main() { } progress++ - gw, cidr, linkname, err := getOutboundIPInfo(verbose) + var ( + gw net.IP + cidr uint64 + linkname string + ) + if isFindSubnet { + gw, cidr, linkname, err = getSubnetIPInfo(nodeAddr, verbose) + } else { + gw, cidr, linkname, err = getOutboundIPInfo(verbose) + + } if err != nil { - panic(errs.Wrap(err, "error in getOutboundIPInfo")) + panic(errs.Wrap(err, "error in network info")) } if verbose { @@ -399,22 +485,22 @@ func main() { fmt.Printf(" - bind interface{%s} : valid\n", bindIfName) fmt.Printf(" - default routing info : ip %s/%d link %s\n", gw.String(), cidr, linkname) fmt.Printf(" - node{%s} IP address : %s\n", nodeName, nodeAddr.String()) - fmt.Printf(" - bind interface type : %s\n",ifBindType) + fmt.Printf(" - bind interface type : %s\n", ifBindType) } option := []string{ "--quiet", "--link-journal=try-host", "--notify-ready=true"} switch ifBindType { - case "macvlan": - option = append(option, fmt.Sprintf("--network-macvlan=%s", bindIfName)) - if len(macAddr)>0{ - option = append(option, fmt.Sprintf("--setenv=MAC_ADDR=%s", macAddr)) - } - case "ipvlan": - option = append(option, fmt.Sprintf("--network-ipvlan=%s", bindIfName)) - default: - panic(errors.New("unknown bind type")) + case "macvlan": + option = append(option, fmt.Sprintf("--network-macvlan=%s", bindIfName)) + if len(macAddr) > 0 { + option = append(option, fmt.Sprintf("--setenv=MAC_ADDR=%s", macAddr)) + } + case "ipvlan": + option = append(option, fmt.Sprintf("--network-ipvlan=%s", bindIfName)) + default: + panic(errors.New("unknown bind type")) } option = append(option, fmt.Sprintf("--setenv=IF_TYPE=%s", ifBindType)) @@ -422,7 +508,8 @@ func main() { option = append(option, fmt.Sprintf("--setenv=GATEWAY_ADDR=%s", gw.String())) option = append(option, fmt.Sprintf("--machine=%s", nodeName)) option = append(option, fmt.Sprintf("--directory=%s", filepath.Join(nodePath, "merge"))) - option = append(option, "--keep-unit", "--register=no", "--settings=override") + # option = append(option, "--keep-unit", "--register=yes", "--settings=override", "--private-users=1354956800:65536", "--private-users-chown") + option = append(option, "--keep-unit", "--register=yes", "--settings=override") for _, mountPoint := range config.MoundPoint { if mountOption, err := mountPoint.Option(nodePath); err != nil { @@ -436,12 +523,12 @@ func main() { fmt.Println("startup type: using systemd") } option = append(option, "--boot") - }else { + } else { if verbose { fmt.Println("startup type: using command") } for _, cmdArg := range cmdListArgs { - option = append(option, fmt.Sprintf(" %s",cmdArg)) + option = append(option, fmt.Sprintf(" %s", cmdArg)) } } var env []string @@ -463,10 +550,9 @@ func main() { fmt.Println(" ", segment, " \\") } fmt.Println(" ;") - fmt.Println("bye!") + fmt.Println("bye!") } if err := syscall.Exec(nspawnPath, option, env); err != nil { panic(errs.Wrap(err, "error in systemd-nspawn execution")) } } - diff --git a/services/octopus-outside@.service b/services/octopus-outside@.service index 1d23815..efe7689 100644 --- a/services/octopus-outside@.service +++ b/services/octopus-outside@.service @@ -16,7 +16,7 @@ After=pdnsd.service [Service] ExecStartPre=/usr/bin/sleep 3s -ExecStart=/container/octopus-outside %I igb0 -v -b macvlan +ExecStart=/container/octopus-outside %I igb1 -v -b ipvlan -s KillMode=mixed Type=notify RestartForceExitStatus=133