1
1
Fork 0

Compare commits

..

10 Commits
0.3 ... develop

Author SHA1 Message Date
Sangbum Kim 2278737a0c Merge branch 'develop' of ssh://amuz.es:29418/infra/octopus into develop
* 'develop' of ssh://amuz.es:29418/infra/octopus:
  nil ㅂㅓ그 수정
  subnet 찾는 모드 추가

# Conflicts:
#	octopus-outside/main.go
2018-08-22 01:07:06 +09:00
Sangbum Kim 514409abda nil ㅂㅓ그 수정 2018-05-15 03:07:05 +09:00
Sangbum Kim b82ad12387 subnet 찾는 모드 추가 2018-05-13 18:23:33 +09:00
Sangbum Kim e952ce6482 오타 수정 2018-05-13 18:20:11 +09:00
Sangbum Kim 4ea1d1f52b subnet 찾는 모드 추가 2018-05-13 18:16:43 +09:00
Sangbum Kim 0fa916778d applied new nspawn option 2017-11-07 01:34:10 +09:00
Sangbum Kim 0998ae3927 added startup waiting 2017-04-28 15:59:28 +09:00
Sangbum Kim 0508524148 macvlan 설정 가능하도록 함 2017-04-24 00:07:11 +09:00
Sangbum Kim c8be99e787 logo추가 2017-04-06 23:35:31 +09:00
Sangbum Kim fb260334ad renaming service file 2017-04-06 21:32:20 +09:00
5 changed files with 184 additions and 29 deletions

View File

@ -1,5 +1,7 @@
# Octopus # Octopus
![](logo.png)
## 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)를 이용한 한 머신내의 가볍고 설정가능한 컨테이너를 구동하는 것이 목표입니다.

BIN
logo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

View File

@ -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)
} }
} }

View File

@ -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 {
@ -42,10 +66,10 @@ type mountPoint struct {
func (mp mountPoint) Option(nodePath string) (option string, err error) { func (mp mountPoint) Option(nodePath string) (option string, err error) {
var mountPointPath string var mountPointPath string
if filepath.IsAbs(mp.Name){ if filepath.IsAbs(mp.Name) {
mountPointPath= mp.Name mountPointPath = mp.Name
}else{ } else {
mountPointPath= filepath.Clean(filepath.Join(nodePath, "volume", mp.Name)) mountPointPath = filepath.Clean(filepath.Join(nodePath, "volume", mp.Name))
} }
if _, err = os.Stat(mountPointPath); os.IsNotExist(err) { if _, err = os.Stat(mountPointPath); os.IsNotExist(err) {
@ -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"))
} }
} }

View File

@ -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