1
1
Fork 0
This commit is contained in:
Sangbum Kim 2017-04-06 17:08:25 +09:00
parent 7746285212
commit 8b3fd2be97
13 changed files with 238 additions and 423 deletions

183
dns/pdnsd.conf Normal file
View File

@ -0,0 +1,183 @@
// Sample pdnsd configuration file. Must be customized to obtain a working pdnsd setup!
// Read the pdnsd.conf(5) manpage for an explanation of the options.
// Add or remove '#' in front of options you want to disable or enable, respectively.
// Remove '/*' and '*/' to enable complete sections.
global {
perm_cache=8192;
cache_dir="/var/cache/pdnsd";
# pid_file = "/var/run/pdnsd.pid";
run_as="pdnsd";
server_ip = any; # Use eth0 here if you want to allow other
# machines on your network to query pdnsd.
status_ctl = on;
# paranoid=on; # This option reduces the chance of cache poisoning
# but may make pdnsd less efficient, unfortunately.
query_method=udp_tcp;
min_ttl=15m; # Retain cached entries at least 15 minutes.
max_ttl=1w; # One week.
timeout=10; # Global timeout option (10 seconds).
neg_domain_pol=on;
udpbufsize=1024; # Upper limit on the size of UDP messages.
strict_setuid=on;
run_ipv4=on;
}
# The following section is most appropriate if you have a fixed connection to
# the Internet and an ISP which provides good DNS servers.
server {
label= "kt";
ip = 168.126.63.1, 168.126.63.2; # Put your ISP's DNS-server address(es) here.
# proxy_only=on; # Do not query any name servers beside your ISP's.
# This may be necessary if you are behind some
# kind of firewall and cannot receive replies
# from outside name servers.
timeout=4; # Server timeout; this may be much shorter
# that the global timeout option.
uptest=if; # Test if the network interface is active.
interface=ip0; # The name of the interface to check.
interval=10m; # Check every 10 minutes.
purge_cache=off; # Keep stale cache entries in case the ISP's
# DNS servers go offline.
edns_query=yes; # Use EDNS for outgoing queries to allow UDP messages
# larger than 512 bytes. May cause trouble with some
# legacy systems.
# exclude=.thepiratebay.org, # If your ISP censors certain names, you may
# .thepiratebay.se, # want to exclude them here, and provide an
# .piratebay.org, # alternative server section below that will
# .piratebay.se; # successfully resolve the names.
}
# The servers provided by OpenDNS are fast, but they do not reply with
# NXDOMAIN for non-existant domains, instead they supply you with an
# address of one of their search engines. They also lie about the addresses of
# of the search engines of google, microsoft and yahoo.
# If you do not like this behaviour the "reject" option may be useful.
server {
label = "opendns";
ip = 208.67.222.222, 208.67.220.220;
reject = 208.69.32.0/24, # You may need to add additional address ranges
208.69.34.0/24, # here if the addresses of their search engines
208.67.219.0/24; # change.
reject_policy = fail; # If you do not provide any alternative server
# sections, like the following root-server
# example, "negate" may be more appropriate here.
timeout = 4;
uptest = ping; # Test availability using ICMP echo requests.
ping_timeout = 100; # ping test will time out after 10 seconds.
interval = 15m; # Test every 15 minutes.
preset = off;
}
# The servers provided by OpenDNS are fast, but they do not reply with
# NXDOMAIN for non-existant domains, instead they supply you with an
# address of one of their search engines. They also lie about the addresses of
# of the search engines of google, microsoft and yahoo.
# If you do not like this behaviour the "reject" option may be useful.
server {
label = "googledns";
ip = 8.8.8.8, 8.8.4.4;
# example, "negate" may be more appropriate here.
timeout = 4;
uptest = ping; # Test availability using ICMP echo requests.
ping_timeout = 100; # ping test will time out after 10 seconds.
interval = 15m; # Test every 15 minutes.
preset = off;
}
# This section is meant for resolving from root servers.
server {
label = "root-servers";
root_server = discover; # Query the name servers listed below
# to obtain a full list of root servers.
randomize_servers = on; # Give every root server an equal chance
# of being queried.
ip = 198.41.0.4, # This list will be expanded to the full
192.228.79.201, # list on start up.
192.33.4.12,
199.7.91.13,
192.203.230.10,
192.5.5.241,
192.112.36.4,
198.97.190.53,
192.36.148.17,
192.58.128.30,
193.0.14.129,
199.7.83.42,
202.12.27.33;
timeout = 5;
uptest = query; # Test availability using empty DNS queries.
query_test_name = .; # To be used if remote servers ignore empty queries.
interval = 30m; # Test every half hour.
ping_timeout = 300; # Test should time out after 30 seconds.
purge_cache = off;
# edns_query = yes; # Use EDNS for outgoing queries to allow UDP messages
# larger than 512 bytes. May cause trouble with some
# legacy systems.
exclude = .localdomain;
policy = included;
preset = off;
}
source {
owner=localhost;
serve_aliases=on;
authrec=on;
file="/etc/hosts";
}
source {
owner=gear.amuz.es;
serve_aliases=on;
authrec=on;
file="/container/hosts";
}
/*
include {file="/etc/pdnsd.include";} # Read additional definitions from /etc/pdnsd.include.
*/
rr {
name=localhost;
reverse=on;
a=127.0.0.1;
owner=localhost;
soa=localhost,root.localhost,42,86400,900,86400,86400;
}
rr {
name = 1.0.0.127.in-addr.arpa;
reverse=on;
ptr = localhost;
owner = localhost;
soa = localhost, root.localhost, 42, 86400, 900, 86400, 86400;
}
rr {
name = gear.amuz.es;
ns = gear.amuz.es;
soa = gear.amuz.es, root.gear.amuz.es, 42, 86400, 900, 86400, 86400;
}
rr {
name = *.gear.amuz.es;
ns = gear.amuz.es;
soa = gear.amuz.es, root.gear.amuz.es, 42, 86400, 900, 86400, 86400;
}
/*
neg {
name=doubleclick.net;
types=domain; # This will also block xxx.doubleclick.net, etc.
}
*/
/*
neg {
name=bad.server.com; # Badly behaved server you don't want to connect to.
types=A,AAAA;
}
*/

3
env
View File

@ -1,3 +0,0 @@
IF_ADDR=fe:3e:13:ef:44:43
BIND_IF=mac0
MOUNTS=""

BIN
gp/gp

Binary file not shown.

@ -1 +0,0 @@
Subproject commit 13fb20a9787c14bfc4c7996ce27d7224aa815812

View File

419
plugin.go
View File

@ -1,419 +0,0 @@
package main
import (
// "github.com/ttacon/libphonenumber"
"bytes"
"errors"
"fmt"
"net"
"os"
"os/exec"
"path/filepath"
"strings"
"syscall"
"io/ioutil"
kingpin "gopkg.in/alecthomas/kingpin.v2"
"gopkg.in/yaml.v2"
"strconv"
errs "github.com/pkg/errors"
"github.com/vishvananda/netlink"
)
var (
app = kingpin.New("plugin", "nspawn Bootstrapper.").Author("Sangbum Kim<sangbumkim@amuz.es>")
verbosePtr = app.Flag("verbose", "Enable verbose mode.").Short('v').Bool()
clearPtr = app.Flag("clear", "clear os environment.").Short('p').Bool()
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()
)
type mountPoint struct {
Name string `yaml:"name"`
Map string `yaml:"map"`
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 _, err = os.Stat(mountPointPath); os.IsNotExist(err) {
err = errors.New(fmt.Sprintf("mount point %s is not exist", mountPointPath))
return
}
var buffer bytes.Buffer
if mp.Readonly {
buffer.WriteString("--bind-ro=")
} else {
buffer.WriteString("--bind=")
}
buffer.WriteString(mountPointPath)
buffer.WriteRune(':')
buffer.WriteString(mp.Map)
option = buffer.String()
return
}
func (mp mountPoint) String() string {
var buffer bytes.Buffer
buffer.WriteString(mp.Name)
if mp.Readonly {
buffer.WriteString("(readonly)")
}
buffer.WriteString("->")
buffer.WriteString(mp.Map)
return buffer.String()
}
type config struct {
MoundPoint []mountPoint `yaml:"mount-point"`
}
func (c config) String() string {
var buffer bytes.Buffer
buffer.WriteString("config:\n")
buffer.WriteString(" mount-point:\n")
for _, entry := range c.MoundPoint {
buffer.WriteString(" - ")
buffer.WriteString(entry.String())
buffer.WriteRune('\n')
}
return buffer.String()
}
// LookupIP looks up host using the local resolver.
// It returns an array of that host's IPv4 and IPv6 addresses.
func getIP(host string) (ip net.IP, err error) {
var addrs []net.IP
addrs, err = net.LookupIP(host)
if err != nil {
return
}
return addrs[0], nil
}
func getOutboundIPInfo(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 (
matchedGw net.IP
matchedCidr uint64
cidrOk = false
)
for _, route := range routes {
if verbose {
fmt.Printf(" routing table %s\n", route.String())
}
if route.Dst == nil {
if verbose {
fmt.Printf(" - default gateway\n")
}
matchedGw = route.Gw
break
} else if verbose {
fmt.Printf(" - no default gateway\n")
}
}
if matchedGw == nil {
if verbose {
fmt.Println(" interface have not a default routing rule.")
}
continue
} else if verbose {
fmt.Printf(" interface have a default routing rule. gateway: %s", matchedGw.String())
}
if verbose {
fmt.Println(" getting networks ")
}
var networks []netlink.Addr
networks, err = netlink.AddrList(link, netlink.FAMILY_V4)
if err != nil {
fmt.Println(" - cannot getting networks ")
continue
}
for _, network := range networks {
if verbose {
fmt.Printf(" network %s\n", network.String())
}
if network.Contains(matchedGw) {
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 {
matchedCidr = cidrData
cidrOk = true
break
}
} else if verbose {
fmt.Printf(" - no default network\n")
}
}
if cidrOk {
gw, cidr, linkname = matchedGw, matchedCidr, attrs.Name
if verbose {
fmt.Println(" ok! matched ")
}
break
} else if verbose {
fmt.Println(" abandon this interface ")
}
}
if gw == nil {
err = errors.New("default gateway or cidr not found!")
}
return
}
func checkInterfaceValid(bindIfName string) (err error) {
var link netlink.Link
link, err = netlink.LinkByName(bindIfName)
if err != nil {
return
}
attrs := link.Attrs()
if (attrs.Flags & net.FlagUp) == 0 {
err = errors.New("bind interface had been deactivated")
}
return
}
func checkNodeBasicDirectory(containerHomePath string, nodeName string, configFileName string) (nodePath string, nodeConfigPath string, err error) {
var containerHomeInfo os.FileInfo
if containerHomeInfo, err = os.Stat(containerHomePath); os.IsNotExist(err) {
err = errors.New(fmt.Sprintf("container home path %s is not exist", containerHomePath))
return
} else if !containerHomeInfo.IsDir() {
err = errors.New(fmt.Sprintf("container home path %s is not a directory", containerHomePath))
return
}
nodePath = filepath.Join(containerHomePath, nodeName)
var nodePathInfo os.FileInfo
if nodePathInfo, err = os.Stat(nodePath); os.IsNotExist(err) {
err = errors.New(fmt.Sprintf("node path %s is not exist", nodePath))
return
} else if !nodePathInfo.IsDir() {
err = errors.New(fmt.Sprintf("node path %s is not a directory", nodePath))
return
} else {
subDirNames := [...]string{"merge", "work", "delta"}
for _, subDirName := range subDirNames {
subPath := filepath.Join(nodePath, subDirName)
var subPathInfo os.FileInfo
if subPathInfo, err = os.Stat(subPath); os.IsNotExist(err) {
err = errors.New(fmt.Sprintf("sub path %s is not exist", subPath))
return
} else if !subPathInfo.IsDir() {
err = errors.New(fmt.Sprintf("sub path %s is not a directory", subPath))
return
}
}
}
nodeConfigPath = filepath.Join(containerHomePath, nodeName, configFileName)
var nodeConfigPathInfo os.FileInfo
if nodeConfigPathInfo, err = os.Stat(nodeConfigPath); os.IsNotExist(err) || nodeConfigPathInfo.IsDir() {
nodeConfigPath = ""
}
return
}
func LoadConfig(path string) (config config, err error) {
var (
source []byte
)
if path == "" {
} else if source, err = ioutil.ReadFile(path); err != nil {
} else if err = yaml.Unmarshal(source, &config); err != nil {
}
return
}
func main() {
_, err := app.Parse(os.Args[1:])
var (
verbose = *verbosePtr
clear = *clearPtr
nodeName = *nodeNamePtr
bindIfName = *bindIfNamePtr
configFileName = *configFileNamePtr
nspawnPath string
progress = -1
)
defer func() {
if r := recover(); r != nil {
fmt.Fprintln(os.Stderr, r)
os.Exit(progress)
}
}()
if err != nil {
panic(err)
}
progress = 1
containerHomePath, err := filepath.Abs(*containerHomePtr)
if err != nil {
panic(err)
}
progress++
nodePath, nodeConfigPath, err := checkNodeBasicDirectory(containerHomePath, nodeName, configFileName)
if err != nil {
panic(err)
} else if verbose {
var nodeConfigPathDesc = "not used"
if nodeConfigPath != "" {
nodeConfigPathDesc = nodeConfigPath
}
fmt.Printf(`sane container environment:
- container home : %s
- node home : %s
- node config : %s
`, containerHomePath, nodePath, nodeConfigPathDesc)
}
config, err := LoadConfig(nodeConfigPath)
if err != nil {
panic(err)
} else if verbose {
fmt.Printf(config.String())
}
progress++
if nspawnPathPtr != nil && *nspawnPathPtr != "" {
nspawnPath = *nspawnPathPtr
} else if nspawnPathData, err := exec.LookPath("systemd-nspawn"); err != nil {
panic(errs.Wrap(err, "cannot find systemd-nspawn"))
} else {
nspawnPath = nspawnPathData
if verbose {
fmt.Printf("systemd-nspawn found : %s\n", nspawnPath)
}
}
progress++
err = checkInterfaceValid(bindIfName)
if err != nil {
panic(errs.Wrap(err, "error in checkInterfaceValid"))
}
progress++
nodeAddr, err := getIP(nodeName)
if err != nil {
panic(errs.Wrap(err, "error in getIP"))
}
progress++
gw, cidr, linkname, err := getOutboundIPInfo(verbose)
if err != nil {
panic(errs.Wrap(err, "error in getOutboundIPInfo"))
}
if verbose {
fmt.Println("network configuration:")
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())
}
option := []string{
"--quiet",
"--boot",
"--link-journal=try-host",
"--notify-ready=true"}
option = append(option, fmt.Sprintf("--network-ipvlan=%s", bindIfName))
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("--machine=%s", nodeName))
option = append(option, fmt.Sprintf("--directory=%s", filepath.Join(nodePath, "merge")))
for _, mountPoint := range config.MoundPoint {
if mountOption, err := mountPoint.Option(nodePath); err != nil {
panic(errs.Wrap(err, "error in mountOption"))
} else {
option = append(option, mountOption)
}
}
var env []string
if clear {
env = []string{}
} else {
env = os.Environ()
if verbose {
fmt.Println("os environment:")
for _, segment := range env {
fmt.Println(" ", segment)
}
}
}
if verbose {
fmt.Println("systemd-nspawn spawning:")
fmt.Println(nspawnPath, " \\")
for _, segment := range option {
fmt.Println(" ", segment, " \\")
}
fmt.Println(" ;")
fmt.Println("bye!")
}
if err := syscall.Exec(nspawnPath, option, env); err != nil {
panic(errs.Wrap(err, "error in systemd-nspawn execution"))
}
}

47
services/plugin.service Normal file
View File

@ -0,0 +1,47 @@
# This file is part of systemd.
#
# systemd is free software; you can redistribute it and/or modify it
# under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation; either version 2.1 of the License, or
# (at your option) any later version.
[Unit]
Description=Container %I
Documentation=man:systemd-nspawn(1)
PartOf=machines.target
Before=machines.target
After=network.target
After=pdnsd.service
[Service]
ExecStart=/container/plugin %I igb0 -v
KillMode=mixed
Type=notify
RestartForceExitStatus=133
SuccessExitStatus=133
Slice=machine.slice
Delegate=yes
TasksMax=8192
# Enforce a strict device policy, similar to the one nspawn configures
# when it allocates its own scope unit. Make sure to keep these
# policies in sync if you change them!
DevicePolicy=strict
DeviceAllow=/dev/null rwm
DeviceAllow=/dev/zero rwm
DeviceAllow=/dev/full rwm
DeviceAllow=/dev/random rwm
DeviceAllow=/dev/urandom rwm
DeviceAllow=/dev/tty rwm
DeviceAllow=/dev/net/tun rwm
DeviceAllow=/dev/pts/ptmx rw
DeviceAllow=char-pts rw
# nspawn itself needs access to /dev/loop-control and /dev/loop, to
# implement the --image= option. Add these here, too.
DeviceAllow=/dev/loop-control rw
DeviceAllow=block-loop rw
DeviceAllow=block-blkext rw
[Install]
WantedBy=machines.target

8
settings.yml Normal file
View File

@ -0,0 +1,8 @@
mount-point:
- name: minio-config
map: /etc/minio
readonly: true
- name: minio-data
map: /var/lib/minio
- name: eden-home
map: /var/lib/eden