Compare commits
10 Commits
Author | SHA1 | Date |
---|---|---|
|
2278737a0c | |
|
514409abda | |
|
b82ad12387 | |
|
e952ce6482 | |
|
4ea1d1f52b | |
|
0fa916778d | |
|
0998ae3927 | |
|
0508524148 | |
|
c8be99e787 | |
|
fb260334ad |
|
@ -1,5 +1,7 @@
|
||||||
# Octopus
|
# Octopus
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
## Octopus Overview
|
## Octopus Overview
|
||||||
|
|
||||||
`Octopus`는 DNS와 systemd-nspawn, [ipvlan](https://www.kernel.org/doc/Documentation/networking/ipvlan.txt) 및 [overlayfs](https://www.kernel.org/doc/Documentation/filesystems/overlayfs.txt)를 이용한 한 머신내의 가볍고 설정가능한 컨테이너를 구동하는 것이 목표입니다.
|
`Octopus`는 DNS와 systemd-nspawn, [ipvlan](https://www.kernel.org/doc/Documentation/networking/ipvlan.txt) 및 [overlayfs](https://www.kernel.org/doc/Documentation/filesystems/overlayfs.txt)를 이용한 한 머신내의 가볍고 설정가능한 컨테이너를 구동하는 것이 목표입니다.
|
||||||
|
|
|
@ -22,16 +22,15 @@ func main(){
|
||||||
|
|
||||||
renameInterface(link,"eth0")
|
renameInterface(link,"eth0")
|
||||||
|
|
||||||
switch linkInterfaceType {
|
if macAddr,err:= net.ParseMAC(getEnvWithDefault("MAC_ADDR","")) ;err == nil{
|
||||||
case "macvlan":
|
|
||||||
macAddr,_ := net.ParseMAC(getEnv("IF_ADDR"))
|
|
||||||
renameMacAddress(link,macAddr)
|
renameMacAddress(link,macAddr)
|
||||||
case "ipvlan":
|
}
|
||||||
ipAddr,_ := netlink.ParseAddr(getEnv("IP_ADDR"))
|
if ipAddr,err:= netlink.ParseAddr(getEnvWithDefault("IP_ADDR","")) ; err ==nil{
|
||||||
gatewayAddr := net.ParseIP(getEnv("GATEWAY_ADDR"))
|
|
||||||
netlink.AddrAdd(link,ipAddr)
|
netlink.AddrAdd(link,ipAddr)
|
||||||
|
}
|
||||||
netlink.LinkSetUp(link)
|
netlink.LinkSetUp(link)
|
||||||
addRoute(gatewayAddr,link)
|
if gatewayAddrStr:= getEnvWithDefault("GATEWAY_ADDR","");len(gatewayAddrStr)>0{
|
||||||
|
addRoute(net.ParseIP(gatewayAddrStr),link)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
|
||||||
"bytes"
|
"bytes"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
@ -14,7 +13,7 @@ import (
|
||||||
|
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
|
|
||||||
kingpin "gopkg.in/alecthomas/kingpin.v2"
|
"gopkg.in/alecthomas/kingpin.v2"
|
||||||
"gopkg.in/yaml.v2"
|
"gopkg.in/yaml.v2"
|
||||||
|
|
||||||
"strconv"
|
"strconv"
|
||||||
|
@ -23,15 +22,40 @@ import (
|
||||||
"github.com/vishvananda/netlink"
|
"github.com/vishvananda/netlink"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type cmdList []string
|
||||||
|
|
||||||
|
func (i *cmdList) Set(value string) error {
|
||||||
|
*i = append(*i, value)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (i *cmdList) String() string {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
func (i *cmdList) IsCumulative() bool {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
func CmdList(s kingpin.Settings) (target *[]string) {
|
||||||
|
target = new([]string)
|
||||||
|
s.SetValue((*cmdList)(target))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
app = kingpin.New("octopus-outside", "nspawn Bootstrapper.").Author("Sangbum Kim<sangbumkim@amuz.es>")
|
app = kingpin.New("octopus-outside", "nspawn Bootstrapper.").Author("Sangbum Kim<sangbumkim@amuz.es>")
|
||||||
verbosePtr = app.Flag("verbose", "Enable verbose mode.").Short('v').Bool()
|
verbosePtr = app.Flag("verbose", "Enable verbose mode.").Short('v').Bool()
|
||||||
clearPtr = app.Flag("clear", "clear os environment.").Short('p').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")
|
||||||
|
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()
|
nspawnPathPtr = app.Flag("nspawn-path", "systemd-nspawn location.").Short('s').String()
|
||||||
containerHomePtr = app.Flag("container-home", "container residence path").Default("/container").Short('d').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()
|
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()
|
nodeNamePtr = app.Arg("nodeName", "nodename to spawn.").Required().String()
|
||||||
bindIfNamePtr = app.Arg("bindInterface", "interface name to bind.").Required().String()
|
bindIfNamePtr = app.Arg("bindInterface", "interface name to bind.").Required().String()
|
||||||
|
cmdListArgsPtr = CmdList(app.Arg("cmd", "execute command rather than boot process"))
|
||||||
)
|
)
|
||||||
|
|
||||||
type mountPoint struct {
|
type mountPoint struct {
|
||||||
|
@ -103,6 +127,97 @@ func getIP(host string) (ip net.IP, err error) {
|
||||||
return addrs[0], nil
|
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 == nil {
|
||||||
|
if verbose {
|
||||||
|
fmt.Printf(" - default gateway : no one!\n")
|
||||||
|
}
|
||||||
|
} else 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 matchedRoute == nil {
|
||||||
|
if verbose {
|
||||||
|
fmt.Println(" - cannot getting routing rule")
|
||||||
|
fmt.Println(" abandon this interface ")
|
||||||
|
}
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
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.Src, cidrData, attrs.Name
|
||||||
|
break
|
||||||
|
} 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) {
|
func getOutboundIPInfo(verbose bool) (gw net.IP, cidr uint64, linkname string, err error) {
|
||||||
// netlink.RouteList
|
// netlink.RouteList
|
||||||
var links []netlink.Link
|
var links []netlink.Link
|
||||||
|
@ -185,14 +300,12 @@ func getOutboundIPInfo(verbose bool) (gw net.IP, cidr uint64, linkname string, e
|
||||||
if verbose {
|
if verbose {
|
||||||
fmt.Printf(" - default network\n")
|
fmt.Printf(" - default network\n")
|
||||||
}
|
}
|
||||||
netSlice := strings.Split(network.IPNet.String(), "/")
|
if cidrData, err := getCidr(*network.IPNet); err == nil {
|
||||||
if len(netSlice) < 2 {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if cidrData, err := strconv.ParseUint(netSlice[len(netSlice)-1], 10, 64); err == nil {
|
|
||||||
matchedCidr = cidrData
|
matchedCidr = cidrData
|
||||||
cidrOk = true
|
cidrOk = true
|
||||||
break
|
break
|
||||||
|
} else if verbose {
|
||||||
|
fmt.Printf(" - cannot getting netmask : %s", err)
|
||||||
}
|
}
|
||||||
} else if verbose {
|
} else if verbose {
|
||||||
fmt.Printf(" - no default network\n")
|
fmt.Printf(" - no default network\n")
|
||||||
|
@ -289,10 +402,14 @@ func main() {
|
||||||
_, err := app.Parse(os.Args[1:])
|
_, err := app.Parse(os.Args[1:])
|
||||||
var (
|
var (
|
||||||
verbose = *verbosePtr
|
verbose = *verbosePtr
|
||||||
|
ifBindType = *ifBindTypePtr
|
||||||
|
macAddr = strings.TrimSpace(*macAddrPtr)
|
||||||
clear = *clearPtr
|
clear = *clearPtr
|
||||||
nodeName = *nodeNamePtr
|
nodeName = *nodeNamePtr
|
||||||
|
isFindSubnet = *isFindSubnetPtr
|
||||||
bindIfName = *bindIfNamePtr
|
bindIfName = *bindIfNamePtr
|
||||||
configFileName = *configFileNamePtr
|
configFileName = *configFileNamePtr
|
||||||
|
cmdListArgs = *cmdListArgsPtr
|
||||||
nspawnPath string
|
nspawnPath string
|
||||||
progress = -1
|
progress = -1
|
||||||
)
|
)
|
||||||
|
@ -361,9 +478,19 @@ func main() {
|
||||||
}
|
}
|
||||||
|
|
||||||
progress++
|
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 {
|
if err != nil {
|
||||||
panic(errs.Wrap(err, "error in getOutboundIPInfo"))
|
panic(errs.Wrap(err, "error in network info"))
|
||||||
}
|
}
|
||||||
|
|
||||||
if verbose {
|
if verbose {
|
||||||
|
@ -371,17 +498,31 @@ func main() {
|
||||||
fmt.Printf(" - bind interface{%s} : valid\n", bindIfName)
|
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(" - 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(" - node{%s} IP address : %s\n", nodeName, nodeAddr.String())
|
||||||
|
fmt.Printf(" - bind interface type : %s\n", ifBindType)
|
||||||
}
|
}
|
||||||
option := []string{
|
option := []string{
|
||||||
"--quiet",
|
"--quiet",
|
||||||
"--boot",
|
|
||||||
"--link-journal=try-host",
|
"--link-journal=try-host",
|
||||||
"--notify-ready=true"}
|
"--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))
|
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))
|
||||||
option = append(option, fmt.Sprintf("--setenv=IP_ADDR=%s/%d", nodeAddr.String(), cidr))
|
option = append(option, fmt.Sprintf("--setenv=IP_ADDR=%s/%d", nodeAddr.String(), cidr))
|
||||||
option = append(option, fmt.Sprintf("--setenv=GATEWAY_ADDR=%s", gw.String()))
|
option = append(option, fmt.Sprintf("--setenv=GATEWAY_ADDR=%s", gw.String()))
|
||||||
option = append(option, fmt.Sprintf("--machine=%s", nodeName))
|
option = append(option, fmt.Sprintf("--machine=%s", nodeName))
|
||||||
option = append(option, fmt.Sprintf("--directory=%s", filepath.Join(nodePath, "merge")))
|
option = append(option, fmt.Sprintf("--directory=%s", filepath.Join(nodePath, "merge")))
|
||||||
|
// 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 {
|
for _, mountPoint := range config.MoundPoint {
|
||||||
if mountOption, err := mountPoint.Option(nodePath); err != nil {
|
if mountOption, err := mountPoint.Option(nodePath); err != nil {
|
||||||
|
@ -390,6 +531,19 @@ func main() {
|
||||||
option = append(option, mountOption)
|
option = append(option, mountOption)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if len(cmdListArgs) == 0 {
|
||||||
|
if verbose {
|
||||||
|
fmt.Println("startup type: using systemd")
|
||||||
|
}
|
||||||
|
option = append(option, "--boot")
|
||||||
|
} else {
|
||||||
|
if verbose {
|
||||||
|
fmt.Println("startup type: using command")
|
||||||
|
}
|
||||||
|
for _, cmdArg := range cmdListArgs {
|
||||||
|
option = append(option, fmt.Sprintf(" %s", cmdArg))
|
||||||
|
}
|
||||||
|
}
|
||||||
var env []string
|
var env []string
|
||||||
if clear {
|
if clear {
|
||||||
env = []string{}
|
env = []string{}
|
||||||
|
@ -415,4 +569,3 @@ func main() {
|
||||||
panic(errs.Wrap(err, "error in systemd-nspawn execution"))
|
panic(errs.Wrap(err, "error in systemd-nspawn execution"))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -15,7 +15,8 @@ After=dnsmasq.service
|
||||||
After=pdnsd.service
|
After=pdnsd.service
|
||||||
|
|
||||||
[Service]
|
[Service]
|
||||||
ExecStart=/container/octopus-outside %I igb0 -v
|
ExecStartPre=/usr/bin/sleep 3s
|
||||||
|
ExecStart=/container/octopus-outside %I igb1 -v -b ipvlan -t
|
||||||
KillMode=mixed
|
KillMode=mixed
|
||||||
Type=notify
|
Type=notify
|
||||||
RestartForceExitStatus=133
|
RestartForceExitStatus=133
|
Loading…
Reference in New Issue