浏览代码

Apply changes to etcdv2 code after package move

Packaging and support for ikev2

Vendoring goStrongswanVici

Make ESP proposals configurable & default to Suite-B-GCM-128

goStrongswanVici dependency update

Removed CreateBackendData/GetBackendData

 * As flannel doesn't support multiple networks, this is not needed any
more

Splitting launch and management of charon

 * Transitional, (WIP)
 * Support for bundled/remote charon.
 * Cleanup after removal of CreateBackendData/GetBackendData

Some packaging

 * It builds amd64.
 * Still much to do.

RegisterNetwork can correctly shutdown spawned processes

 * Added sync.WaitGroup, so spawned processes can correctly shutdown.
 * Bundled charon daemon correctly shuts down.
Max Kutsevol 8 年之前
父节点
当前提交
9a83d0bdcf
共有 42 个文件被更改,包括 1428 次插入2442 次删除
  1. 7 0
      Dockerfile.arm
  2. 3 3
      backend/alivpc/alivpc.go
  3. 2 2
      backend/alloc/alloc.go
  4. 3 3
      backend/awsvpc/awsvpc.go
  5. 2 1
      backend/common.go
  6. 3 3
      backend/extension/extension.go
  7. 3 4
      backend/gce/gce.go
  8. 76 28
      backend/ipsec/handle_charon.go
  9. 2 2
      backend/ipsec/handle_xfrm.go
  10. 25 53
      backend/ipsec/ipsec.go
  11. 13 18
      backend/ipsec/network.go
  12. 3 3
      backend/vxlan/vxlan.go
  13. 2 0
      glide.lock
  14. 1 1
      glide.yaml
  15. 7 7
      main.go
  16. 0 408
      remote/client.go
  17. 0 447
      remote/server.go
  18. 1 0
      subnet/etcdv2/mock_registry.go
  19. 21 0
      subnet/etcdv2/registry.go
  20. 0 8
      subnet/kube/kube.go
  21. 0 516
      subnet/local_manager.go
  22. 0 488
      subnet/mock_registry.go
  23. 0 444
      subnet/registry.go
  24. 0 3
      subnet/subnet.go
  25. 20 0
      vendor/github.com/bronze1man/goStrongswanVici/LICENSE
  26. 79 0
      vendor/github.com/bronze1man/goStrongswanVici/client.go
  27. 154 0
      vendor/github.com/bronze1man/goStrongswanVici/clientConn.go
  28. 5 0
      vendor/github.com/bronze1man/goStrongswanVici/doc.go
  29. 24 0
      vendor/github.com/bronze1man/goStrongswanVici/err.go
  30. 47 0
      vendor/github.com/bronze1man/goStrongswanVici/listConns.go
  31. 174 0
      vendor/github.com/bronze1man/goStrongswanVici/listSas.go
  32. 37 0
      vendor/github.com/bronze1man/goStrongswanVici/loadCert.go
  33. 66 0
      vendor/github.com/bronze1man/goStrongswanVici/loadConn.go
  34. 66 0
      vendor/github.com/bronze1man/goStrongswanVici/loadPrivateKey.go
  35. 29 0
      vendor/github.com/bronze1man/goStrongswanVici/marshal.go
  36. 359 0
      vendor/github.com/bronze1man/goStrongswanVici/msg.go
  37. 36 0
      vendor/github.com/bronze1man/goStrongswanVici/pools.go
  38. 76 0
      vendor/github.com/bronze1man/goStrongswanVici/shared.go
  39. 7 0
      vendor/github.com/bronze1man/goStrongswanVici/stats.go
  40. 32 0
      vendor/github.com/bronze1man/goStrongswanVici/terminate.go
  41. 24 0
      vendor/github.com/bronze1man/goStrongswanVici/unloadConn.go
  42. 19 0
      vendor/github.com/bronze1man/goStrongswanVici/version.go

+ 7 - 0
Dockerfile.arm

@@ -9,5 +9,12 @@ RUN apk add --no-cache iproute2 net-tools ca-certificates iptables && update-ca-
 RUN apk add wireguard-tools --no-cache --repository http://dl-cdn.alpinelinux.org/alpine/edge/testing
 COPY dist/flanneld-$FLANNEL_ARCH /opt/bin/flanneld
 COPY dist/mk-docker-opts.sh /opt/bin/
+COPY dist/libpthread.so.0-$FLANNEL_ARCH /lib/libpthread.so.0
+COPY dist/ld64.so.1-$FLANNEL_ARCH /lib/ld64.so.1
+COPY dist/libc.so.6-$FLANNEL_ARCH /lib/libc.so.6
+
+COPY dist/strongswan-$FLANNEL_ARCH /usr/local/strongswan-arm
+COPY dist/libatomic.so.1-$FLANNEL_ARCH /lib/libatomic.so.1
+COPY dist/libdl.so.2-$FLANNEL_ARCH /lib/libdl.so.2
 
 ENTRYPOINT ["/opt/bin/flanneld"]

+ 3 - 3
backend/alivpc/alivpc.go

@@ -18,10 +18,10 @@ package alivpc
 import (
 	"encoding/json"
 	"fmt"
-	"os"
-
 	log "github.com/golang/glog"
 	"golang.org/x/net/context"
+	"os"
+	"sync"
 
 	"github.com/coreos/flannel/backend"
 	"github.com/coreos/flannel/pkg/ip"
@@ -48,7 +48,7 @@ func New(sm subnet.Manager, extIface *backend.ExternalInterface) (backend.Backen
 	return &be, nil
 }
 
-func (be *AliVpcBackend) RegisterNetwork(ctx context.Context, config *subnet.Config) (backend.Network, error) {
+func (be *AliVpcBackend) RegisterNetwork(ctx context.Context, wg sync.WaitGroup, config *subnet.Config) (backend.Network, error) {
 	// 1. Parse our configuration
 	cfg := struct {
 		AccessKeyID     string

+ 2 - 2
backend/alloc/alloc.go

@@ -16,11 +16,11 @@ package alloc
 
 import (
 	"fmt"
-
 	"github.com/coreos/flannel/backend"
 	"github.com/coreos/flannel/pkg/ip"
 	"github.com/coreos/flannel/subnet"
 	"golang.org/x/net/context"
+	"sync"
 )
 
 func init() {
@@ -40,7 +40,7 @@ func New(sm subnet.Manager, extIface *backend.ExternalInterface) (backend.Backen
 	return &be, nil
 }
 
-func (be *AllocBackend) RegisterNetwork(ctx context.Context, config *subnet.Config) (backend.Network, error) {
+func (be *AllocBackend) RegisterNetwork(ctx context.Context, wg sync.WaitGroup, config *subnet.Config) (backend.Network, error) {
 	attrs := subnet.LeaseAttrs{
 		PublicIP: ip.FromIP(be.extIface.ExtAddr),
 	}

+ 3 - 3
backend/awsvpc/awsvpc.go

@@ -18,8 +18,6 @@ package awsvpc
 import (
 	"encoding/json"
 	"fmt"
-	"net"
-
 	"github.com/aws/aws-sdk-go/aws"
 	"github.com/aws/aws-sdk-go/aws/awserr"
 	"github.com/aws/aws-sdk-go/aws/ec2metadata"
@@ -27,6 +25,8 @@ import (
 	"github.com/aws/aws-sdk-go/service/ec2"
 	log "github.com/golang/glog"
 	"golang.org/x/net/context"
+	"net"
+	"sync"
 
 	"github.com/coreos/flannel/backend"
 	"github.com/coreos/flannel/pkg/ip"
@@ -80,7 +80,7 @@ func (conf *backendConfig) routeTableConfigured() bool {
 	return configured
 }
 
-func (be *AwsVpcBackend) RegisterNetwork(ctx context.Context, config *subnet.Config) (backend.Network, error) {
+func (be *AwsVpcBackend) RegisterNetwork(ctx context.Context, wg sync.WaitGroup, config *subnet.Config) (backend.Network, error) {
 	// Parse our configuration
 	var cfg backendConfig
 

+ 2 - 1
backend/common.go

@@ -16,6 +16,7 @@ package backend
 
 import (
 	"net"
+	"sync"
 
 	"golang.org/x/net/context"
 
@@ -34,7 +35,7 @@ type ExternalInterface struct {
 // needed.
 type Backend interface {
 	// Called when the backend should create or begin managing a new network
-	RegisterNetwork(ctx context.Context, config *subnet.Config) (Network, error)
+	RegisterNetwork(ctx context.Context, wg sync.WaitGroup, config *subnet.Config) (Network, error)
 }
 
 type Network interface {

+ 3 - 3
backend/extension/extension.go

@@ -19,9 +19,9 @@ import (
 	"io"
 	"strings"
 
-	"os/exec"
-
 	"encoding/json"
+	"os/exec"
+	"sync"
 
 	log "github.com/golang/glog"
 
@@ -55,7 +55,7 @@ func (_ *ExtensionBackend) Run(ctx context.Context) {
 	<-ctx.Done()
 }
 
-func (be *ExtensionBackend) RegisterNetwork(ctx context.Context, config *subnet.Config) (backend.Network, error) {
+func (be *ExtensionBackend) RegisterNetwork(ctx context.Context, wg sync.WaitGroup, config *subnet.Config) (backend.Network, error) {
 	n := &network{
 		extIface: be.extIface,
 		sm:       be.sm,

+ 3 - 4
backend/gce/gce.go

@@ -40,12 +40,11 @@ package gce
 
 import (
 	"fmt"
-	"strings"
-	"sync"
-
 	log "github.com/golang/glog"
 	"golang.org/x/net/context"
 	"google.golang.org/api/googleapi"
+	"strings"
+	"sync"
 
 	"github.com/coreos/flannel/backend"
 	"github.com/coreos/flannel/pkg/ip"
@@ -83,7 +82,7 @@ func (g *GCEBackend) ensureAPI() error {
 	return err
 }
 
-func (g *GCEBackend) RegisterNetwork(ctx context.Context, config *subnet.Config) (backend.Network, error) {
+func (g *GCEBackend) RegisterNetwork(ctx context.Context, wg sync.WaitGroup, config *subnet.Config) (backend.Network, error) {
 	attrs := subnet.LeaseAttrs{
 		PublicIP: ip.FromIP(g.extIface.ExtAddr),
 	}

+ 76 - 28
backend/ipsec/handle_charon.go

@@ -16,45 +16,90 @@ package ipsec
 
 import (
 	"fmt"
+	"github.com/bronze1man/goStrongswanVici"
+	"github.com/coreos/flannel/subnet"
+	log "github.com/golang/glog"
+	"golang.org/x/net/context"
+	"net"
 	"os"
 	"os/exec"
+	"strings"
+	"sync"
 	"syscall"
 	"time"
+)
 
-	"github.com/bronze1man/goStrongswanVici"
-	log "github.com/golang/glog"
-
-	"github.com/coreos/flannel/subnet"
+const (
+	charonExecutablePath = "/opt/strongswan/libexec/ipsec/charon"
 )
 
+var defaultViciUri = Uri{"unix", "/var/run/charon.vici"}
+
+type Uri struct {
+	network, address string
+}
+
 type CharonIKEDaemon struct {
-	path string
+	viciUri     Uri
+	espProposal string
 }
 
-func NewCharonIKEDaemon(charonPath string) (*CharonIKEDaemon, error) {
-	path, err := exec.LookPath(charonPath)
-	if err != nil {
-		return nil, err
+func NewCharonIKEDaemon(ctx context.Context, wg sync.WaitGroup, charonViciUri string,
+	espProposal string) (*CharonIKEDaemon, error) {
+
+	charon := &CharonIKEDaemon{viciUri: defaultViciUri, espProposal: espProposal}
+	log.Infof("Using ESP proposal: %s", espProposal)
+	if charonViciUri == "" {
+		cmd, err := charon.runBundled()
+
+		if err != nil {
+			log.Errorf("Error starting bundled charon daemon: %v", err)
+			return nil, err
+		} else {
+			log.Info("Bundled charon daemon started")
+		}
+		wg.Add(1)
+		go func() {
+			select {
+			case <-ctx.Done():
+				cmd.Process.Signal(syscall.SIGTERM)
+				log.Infof("Stopped bundled charon daemon")
+				wg.Done()
+				return
+			}
+		}()
+	} else {
+		log.Infof("Using external charon at: %s", charonViciUri)
+		addr := strings.Split(charonViciUri, "://")
+		charon.viciUri = Uri{addr[0], addr[1]}
 	}
 
-	log.Info("Launching IKE charon path: ", path)
+	return charon, nil
+}
 
-	return &CharonIKEDaemon{
-		path: path,
-	}, nil
+func (charon *CharonIKEDaemon) getClient() (
+	client *goStrongswanVici.ClientConn, err error) {
+	conn, err := net.Dial(charon.viciUri.network, charon.viciUri.address)
+	if err != nil {
+		return
+	}
+	return goStrongswanVici.NewClientConn(conn), nil
 }
 
-func (charon *CharonIKEDaemon) Run() error {
-	cmd := exec.Cmd{
-		Path: charon.path,
+func (charon *CharonIKEDaemon) runBundled() (cmd *exec.Cmd, err error) {
+	path, err := exec.LookPath(charonExecutablePath)
+	if err != nil {
+		return nil, err
+	}
+	cmd = &exec.Cmd{
+		Path: path,
 		SysProcAttr: &syscall.SysProcAttr{
 			Pdeathsig: syscall.SIGTERM,
 		},
 	}
-
 	cmd.Stderr = os.Stderr
-
-	return cmd.Run()
+	err = cmd.Start()
+	return
 }
 
 func (charon *CharonIKEDaemon) LoadSharedKey(remotePublicIP, password string) error {
@@ -62,12 +107,12 @@ func (charon *CharonIKEDaemon) LoadSharedKey(remotePublicIP, password string) er
 	var client *goStrongswanVici.ClientConn
 
 	for {
-		client, err = goStrongswanVici.NewClientConnFromDefaultSocket()
+		client, err = charon.getClient()
 		if err == nil {
 			break
 		} else {
 			log.Error("ClientConnection failed: ", err)
-			log.Infof("Retrying in 1 second ...")
+			log.Info("Retrying in 1 second ...")
 			time.Sleep(1 * time.Second)
 		}
 	}
@@ -89,12 +134,13 @@ func (charon *CharonIKEDaemon) LoadSharedKey(remotePublicIP, password string) er
 	return nil
 }
 
-func (charon *CharonIKEDaemon) LoadConnection(localLease, remoteLease *subnet.Lease, reqID, encap string) error {
+func (charon *CharonIKEDaemon) LoadConnection(localLease, remoteLease *subnet.Lease,
+	reqID, encap string) error {
 	var err error
 	var client *goStrongswanVici.ClientConn
 
 	for {
-		client, err = goStrongswanVici.NewClientConnFromDefaultSocket()
+		client, err = charon.getClient()
 		if err == nil {
 			break
 		} else {
@@ -109,7 +155,7 @@ func (charon *CharonIKEDaemon) LoadConnection(localLease, remoteLease *subnet.Le
 	childSAConf := goStrongswanVici.ChildSAConf{
 		Local_ts:     []string{localLease.Subnet.String()},
 		Remote_ts:    []string{remoteLease.Subnet.String()},
-		ESPProposals: []string{"aes256-sha256-modp4096"},
+		ESPProposals: []string{charon.espProposal},
 		StartAction:  "start",
 		CloseAction:  "trap",
 		Mode:         "tunnel",
@@ -133,7 +179,7 @@ func (charon *CharonIKEDaemon) LoadConnection(localLease, remoteLease *subnet.Le
 		LocalAddrs:  []string{localLease.Attrs.PublicIP.String()},
 		RemoteAddrs: []string{remoteLease.Attrs.PublicIP.String()},
 		Proposals:   []string{"aes256-sha256-modp4096"},
-		Version:     "1",
+		Version:     "2",
 		KeyingTries: "0", //continues to retry
 		LocalAuth:   localAuthConf,
 		RemoteAuth:  remoteAuthConf,
@@ -154,8 +200,9 @@ func (charon *CharonIKEDaemon) LoadConnection(localLease, remoteLease *subnet.Le
 	return nil
 }
 
-func (charon *CharonIKEDaemon) UnloadCharonConnection(localLease, remoteLease *subnet.Lease) error {
-	client, err := goStrongswanVici.NewClientConnFromDefaultSocket()
+func (charon *CharonIKEDaemon) UnloadCharonConnection(localLease,
+	remoteLease *subnet.Lease) error {
+	client, err := charon.getClient()
 	if err != nil {
 		return err
 	}
@@ -176,7 +223,8 @@ func (charon *CharonIKEDaemon) UnloadCharonConnection(localLease, remoteLease *s
 }
 
 func formatConnectionName(localLease, remoteLease *subnet.Lease) string {
-	return fmt.Sprintf("%s-%s-%s-%s", localLease.Attrs.PublicIP, localLease.Subnet, remoteLease.Subnet, remoteLease.Attrs.PublicIP)
+	return fmt.Sprintf("%s-%s-%s-%s", localLease.Attrs.PublicIP,
+		localLease.Subnet, remoteLease.Subnet, remoteLease.Attrs.PublicIP)
 }
 
 func formatChildSAConfName(localLease, remoteLease *subnet.Lease) string {

+ 2 - 2
backend/ipsec/handle_xfrm.go

@@ -19,8 +19,8 @@ import (
 	"net"
 	"syscall"
 
-	log "github.com/coreos/flannel/Godeps/_workspace/src/github.com/golang/glog"
-	"github.com/coreos/flannel/Godeps/_workspace/src/github.com/vishvananda/netlink"
+	log "github.com/golang/glog"
+	"github.com/vishvananda/netlink"
 
 	"github.com/coreos/flannel/subnet"
 )

+ 25 - 53
backend/ipsec/ipsec.go

@@ -15,24 +15,22 @@
 package ipsec
 
 import (
-	"crypto/rand"
-	"encoding/base64"
 	"encoding/json"
 	"fmt"
-
 	log "github.com/golang/glog"
 	"golang.org/x/net/context"
+	"sync"
 
 	"github.com/coreos/flannel/backend"
 	"github.com/coreos/flannel/pkg/ip"
 	"github.com/coreos/flannel/subnet"
 )
 
-var CharonPath string
+var CharonViciUri string
 
 const (
-	defaultCharonPath = "/opt/flannel/libexec/ipsec/charon"
-	passwordLength    = 40
+	defaultESPProposal = "aes128gcm16-sha256-prfsha256-ecp256"
+	minPasswordLength  = 96
 )
 
 func init() {
@@ -44,7 +42,8 @@ type IPSECBackend struct {
 	extIface *backend.ExternalInterface
 }
 
-func New(sm subnet.Manager, extIface *backend.ExternalInterface) (backend.Backend, error) {
+func New(sm subnet.Manager, extIface *backend.ExternalInterface) (
+	backend.Backend, error) {
 	be := &IPSECBackend{
 		sm:       sm,
 		extIface: extIface,
@@ -53,10 +52,17 @@ func New(sm subnet.Manager, extIface *backend.ExternalInterface) (backend.Backen
 	return be, nil
 }
 
-func (be *IPSECBackend) RegisterNetwork(ctx context.Context, netname string, config *subnet.Config) (backend.Network, error) {
+func (be *IPSECBackend) RegisterNetwork(
+	ctx context.Context, wg sync.WaitGroup, config *subnet.Config) (backend.Network, error) {
+
 	cfg := struct {
-		UDPEncap bool
-	}{}
+		UDPEncap    bool
+		ESPProposal string
+		PSK         string
+	}{
+		UDPEncap:    false,
+		ESPProposal: defaultESPProposal,
+	}
 
 	if len(config.Backend) > 0 {
 		log.Info("i.config.backend length > 0")
@@ -65,12 +71,18 @@ func (be *IPSECBackend) RegisterNetwork(ctx context.Context, netname string, con
 		}
 	}
 
+	if len(cfg.PSK) < minPasswordLength {
+		return nil, fmt.Errorf(
+			"config error, password should be at least %s characters long",
+			minPasswordLength)
+	}
+
 	attrs := subnet.LeaseAttrs{
 		PublicIP:    ip.FromIP(be.extIface.ExtAddr),
 		BackendType: "ipsec",
 	}
 
-	l, err := be.sm.AcquireLease(ctx, netname, &attrs)
+	l, err := be.sm.AcquireLease(ctx, &attrs)
 
 	switch err {
 	case nil:
@@ -82,56 +94,16 @@ func (be *IPSECBackend) RegisterNetwork(ctx context.Context, netname string, con
 		return nil, fmt.Errorf("failed to acquire lease: %v", err)
 	}
 
-	if CharonPath == "" {
-		CharonPath = defaultCharonPath
-	}
-
-	ikeDaemon, err := NewCharonIKEDaemon(CharonPath)
+	ikeDaemon, err := NewCharonIKEDaemon(ctx, wg, CharonViciUri, cfg.ESPProposal)
 	if err != nil {
 		return nil, fmt.Errorf("error creating CharonIKEDaemon struct: %v", err)
 	}
 
 	log.Info("UDPEncap: ", cfg.UDPEncap)
 
-	password, err := GenerateRandomString(passwordLength)
-	if err != nil {
-		return nil, fmt.Errorf("error generating random string: %v", err)
-	}
-
-	err = be.sm.CreateBackendData(ctx, netname, password)
-	if err != nil {
-		return nil, fmt.Errorf("error creating password: %v", err)
-	}
-
-	password, err = be.sm.GetBackendData(ctx, netname)
-	if err != nil {
-		return nil, fmt.Errorf("error getting password: %v", err)
-	}
-
-	return newNetwork(netname, be.sm, be.extIface, cfg.UDPEncap, password, ikeDaemon, l)
+	return newNetwork(be.sm, be.extIface, cfg.UDPEncap, cfg.PSK, ikeDaemon, l)
 }
 
 func (be *IPSECBackend) Run(ctx context.Context) {
 	<-ctx.Done()
 }
-
-func generateRandomBytes(n int) ([]byte, error) {
-	b := make([]byte, n)
-	_, err := rand.Read(b)
-
-	if err != nil {
-		return nil, err
-	}
-
-	return b, nil
-}
-
-func GenerateRandomString(s int) (string, error) {
-	b, err := generateRandomBytes(s)
-
-	if err != nil {
-		return "", err
-	}
-
-	return base64.StdEncoding.EncodeToString(b), nil
-}

+ 13 - 18
backend/ipsec/network.go

@@ -47,20 +47,20 @@ const (
 
 type network struct {
 	backend.SimpleNetwork
-	name     string
 	password string
 	UDPEncap bool
 	sm       subnet.Manager
 	iked     *CharonIKEDaemon
 }
 
-func newNetwork(name string, sm subnet.Manager, extIface *backend.ExternalInterface, UDPEncap bool, password string, ikeDaemon *CharonIKEDaemon, l *subnet.Lease) (*network, error) {
+func newNetwork(sm subnet.Manager, extIface *backend.ExternalInterface,
+	UDPEncap bool, password string, ikeDaemon *CharonIKEDaemon,
+	l *subnet.Lease) (*network, error) {
 	n := &network{
 		SimpleNetwork: backend.SimpleNetwork{
 			SubnetLease: l,
 			ExtIface:    extIface,
 		},
-		name:     name,
 		sm:       sm,
 		iked:     ikeDaemon,
 		password: password,
@@ -74,25 +74,26 @@ func (n *network) Run(ctx context.Context) {
 	wg := sync.WaitGroup{}
 	defer wg.Wait()
 
-	wg.Add(1)
-	go func() {
-		log.Info("Starting charon \n")
-		n.startIKEDaemon()
-		log.Info("Charon daemon exited")
-		wg.Done()
-	}()
-
 	log.Info("Watching for new subnet leases")
 
 	evts := make(chan []subnet.Event)
 
 	wg.Add(1)
 	go func() {
-		subnet.WatchLeases(ctx, n.sm, n.name, n.SubnetLease, evts)
+		subnet.WatchLeases(ctx, n.sm, n.SubnetLease, evts)
 		log.Info("WatchLeases exited")
 		wg.Done()
 	}()
 
+	for {
+		err := n.iked.LoadSharedKey(n.SimpleNetwork.SubnetLease.Attrs.PublicIP.ToIP().String(), n.password)
+		if err == nil {
+			break
+		}
+		log.Error(err, " Failed to load my key. Retrying")
+		time.Sleep(time.Second)
+	}
+
 	initialEvtsBatch := <-evts
 	for {
 		err := n.handleInitialSubnetEvents(initialEvtsBatch)
@@ -230,12 +231,6 @@ func (n *network) handleSubnetEvents(batch []subnet.Event) {
 	}
 }
 
-func (n *network) startIKEDaemon() {
-	if err := n.iked.Run(); err != nil {
-		log.Info("error starting IKE daemon: ", err)
-	}
-}
-
 func (n *network) MTU() int {
 	mtu := n.ExtIface.Iface.MTU - ipsecOverhead
 	if n.UDPEncap {

+ 3 - 3
backend/vxlan/vxlan.go

@@ -55,9 +55,9 @@ package vxlan
 import (
 	"encoding/json"
 	"fmt"
-	"net"
-
 	log "github.com/golang/glog"
+	"net"
+	"sync"
 
 	"golang.org/x/net/context"
 
@@ -101,7 +101,7 @@ func newSubnetAttrs(publicIP net.IP, mac net.HardwareAddr) (*subnet.LeaseAttrs,
 	}, nil
 }
 
-func (be *VXLANBackend) RegisterNetwork(ctx context.Context, config *subnet.Config) (backend.Network, error) {
+func (be *VXLANBackend) RegisterNetwork(ctx context.Context, wg sync.WaitGroup, config *subnet.Config) (backend.Network, error) {
 	// Parse our configuration
 	cfg := struct {
 		VNI           int

+ 2 - 0
glide.lock

@@ -33,6 +33,8 @@ imports:
   - private/protocol/xml/xmlutil
   - service/ec2
   - service/sts
+- name: github.com/bronze1man/goStrongswanVici
+  version: 4d72634a2f113aa48347dbc7dcb14adb806b6534
 - name: github.com/coreos/etcd
   version: 0f4a535c2fb7a2920e13e2e19b9eaf6b2e9285e5
   subpackages:

+ 1 - 1
glide.yaml

@@ -60,5 +60,5 @@ import:
 - package: github.com/joho/godotenv
   version: v1.1
 - package: github.com/bronze1man/goStrongswanVici
-  version: 385ce24ffa11c0831da96e3e28b603464eaaa1a7
+  version: 4d72634a2f113aa48347dbc7dcb14adb806b6534
 

+ 7 - 7
main.go

@@ -93,7 +93,7 @@ type CmdLineOpts struct {
 	subnetLeaseRenewMargin int
 	healthzIP              string
 	healthzPort            int
-	charonPath     string
+	charonViciUri          string
 }
 
 var (
@@ -123,7 +123,7 @@ func init() {
 	flannelFlags.BoolVar(&opts.version, "version", false, "print version and exit")
 	flannelFlags.StringVar(&opts.healthzIP, "healthz-ip", "0.0.0.0", "the IP address for healthz server to listen")
 	flannelFlags.IntVar(&opts.healthzPort, "healthz-port", 0, "the port for healthz server to listen(0 to disable)")
-	flag.StringVar(&opts.charonPath, "charon-path", "", "path to charon executable")
+	flannelFlags.StringVar(&opts.charonViciUri, "vici-uri", "", "Charon vici URI (default: launch a bundled one)")
 
 	// glog will log to tmp files by default. override so all entries
 	// can flow into journald (if running under systemd)
@@ -230,6 +230,10 @@ func main() {
 		}
 	}
 
+	if opts.charonViciUri != "" {
+		ipsec.CharonViciUri = opts.charonViciUri
+	}
+
 	sm, err := newSubnetManager()
 	if err != nil {
 		log.Error("Failed to create SubnetManager: ", err)
@@ -278,7 +282,7 @@ func main() {
 		os.Exit(1)
 	}
 
-	bn, err := be.RegisterNetwork(ctx, config)
+	bn, err := be.RegisterNetwork(ctx, wg, config)
 	if err != nil {
 		log.Errorf("Error registering network: %s", err)
 		cancel()
@@ -286,10 +290,6 @@ func main() {
 		os.Exit(1)
 	}
 
-	if opts.charonPath != "" {
-		ipsec.CharonPath = opts.charonPath
-	}
-
 	// Set up ipMasq if needed
 	if opts.ipMasq {
 		go network.SetupAndEnsureIPTables(network.MasqRules(config.Network, bn.Lease()))

+ 0 - 408
remote/client.go

@@ -1,408 +0,0 @@
-// Copyright 2015 flannel authors
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//     http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package remote
-
-import (
-	"bytes"
-	"encoding/json"
-	"fmt"
-	"io"
-	"io/ioutil"
-	"net"
-	"net/http"
-	"path"
-	"time"
-
-	"github.com/coreos/etcd/pkg/transport"
-	"golang.org/x/net/context"
-
-	"github.com/coreos/flannel/pkg/ip"
-	"github.com/coreos/flannel/subnet"
-)
-
-// implements subnet.Manager by sending requests to the server
-type RemoteManager struct {
-	base      string // includes scheme, host, and port, and version
-	transport *Transport
-}
-
-func NewTransport(info transport.TLSInfo) (*Transport, error) {
-	cfg, err := info.ClientConfig()
-	if err != nil {
-		return nil, err
-	}
-
-	t := &Transport{
-		// timeouts taken from http.DefaultTransport
-		Dial: (&net.Dialer{
-			Timeout:   30 * time.Second,
-			KeepAlive: 30 * time.Second,
-		}).Dial,
-		TLSHandshakeTimeout: 10 * time.Second,
-		TLSClientConfig:     cfg,
-	}
-
-	return t, nil
-}
-
-func NewRemoteManager(listenAddr, cafile, certfile, keyfile string) (subnet.Manager, error) {
-	tls := transport.TLSInfo{
-		CAFile:   cafile,
-		CertFile: certfile,
-		KeyFile:  keyfile,
-	}
-
-	t, err := NewTransport(tls)
-	if err != nil {
-		return nil, err
-	}
-
-	var scheme string
-	if tls.Empty() && tls.CAFile == "" {
-		scheme = "http://"
-	} else {
-		scheme = "https://"
-	}
-
-	return &RemoteManager{
-		base:      scheme + listenAddr + "/v1",
-		transport: t,
-	}, nil
-}
-
-func (m *RemoteManager) mkurl(network string, parts ...string) string {
-	if network == "" {
-		network = "/_"
-	}
-	if network[0] != '/' {
-		network = "/" + network
-	}
-	return m.base + path.Join(append([]string{network}, parts...)...)
-}
-
-func (m *RemoteManager) GetNetworkConfig(ctx context.Context, network string) (*subnet.Config, error) {
-	url := m.mkurl(network, "config")
-
-	resp, err := m.httpVerb(ctx, "GET", url, "", nil)
-	if err != nil {
-		return nil, err
-	}
-	defer resp.Body.Close()
-
-	if resp.StatusCode != http.StatusOK {
-		return nil, httpError(resp)
-	}
-
-	body, err := ioutil.ReadAll(resp.Body)
-	if err != nil {
-		return nil, err
-	}
-
-	config, err := subnet.ParseConfig(string(body))
-	if err != nil {
-		return nil, err
-	}
-
-	return config, nil
-}
-
-func (m *RemoteManager) AcquireLease(ctx context.Context, network string, attrs *subnet.LeaseAttrs) (*subnet.Lease, error) {
-	url := m.mkurl(network, "leases/")
-
-	body, err := json.Marshal(attrs)
-	if err != nil {
-		return nil, err
-	}
-
-	resp, err := m.httpVerb(ctx, "POST", url, "application/json", body)
-	if err != nil {
-		return nil, err
-	}
-	defer resp.Body.Close()
-
-	if resp.StatusCode != http.StatusOK {
-		return nil, httpError(resp)
-	}
-
-	newLease := &subnet.Lease{}
-	if err := json.NewDecoder(resp.Body).Decode(newLease); err != nil {
-		return nil, err
-	}
-
-	return newLease, nil
-}
-
-func (m *RemoteManager) RenewLease(ctx context.Context, network string, lease *subnet.Lease) error {
-	url := m.mkurl(network, "leases", lease.Key())
-
-	body, err := json.Marshal(lease)
-	if err != nil {
-		return err
-	}
-
-	resp, err := m.httpVerb(ctx, "PUT", url, "application/json", body)
-	if err != nil {
-		return err
-	}
-	defer resp.Body.Close()
-
-	if resp.StatusCode != http.StatusOK {
-		return httpError(resp)
-	}
-
-	newLease := &subnet.Lease{}
-	if err := json.NewDecoder(resp.Body).Decode(newLease); err != nil {
-		return err
-	}
-
-	*lease = *newLease
-	return nil
-}
-
-func (m *RemoteManager) RevokeLease(ctx context.Context, network string, sn ip.IP4Net) error {
-	url := m.mkurl(network, "leases", subnet.MakeSubnetKey(sn))
-
-	resp, err := m.httpVerb(ctx, "DELETE", url, "", nil)
-	if err != nil {
-		return err
-	}
-	defer resp.Body.Close()
-
-	if resp.StatusCode != http.StatusOK {
-		return httpError(resp)
-	}
-
-	return nil
-}
-
-func (m *RemoteManager) watch(ctx context.Context, url string, cursor interface{}, wr interface{}) error {
-	if cursor != nil {
-		c, ok := cursor.(string)
-		if !ok {
-			return fmt.Errorf("internal error: RemoteManager.watch received non-string cursor")
-		}
-
-		url = fmt.Sprintf("%v?next=%v", url, c)
-	}
-
-	resp, err := m.httpVerb(ctx, "GET", url, "", nil)
-	if err != nil {
-		return err
-	}
-	defer resp.Body.Close()
-
-	if resp.StatusCode != http.StatusOK {
-		return httpError(resp)
-	}
-
-	if err := json.NewDecoder(resp.Body).Decode(wr); err != nil {
-		return err
-	}
-
-	return nil
-}
-
-func (m *RemoteManager) WatchLease(ctx context.Context, network string, sn ip.IP4Net, cursor interface{}) (subnet.LeaseWatchResult, error) {
-	url := m.mkurl(network, "leases", subnet.MakeSubnetKey(sn))
-
-	wr := subnet.LeaseWatchResult{}
-	err := m.watch(ctx, url, cursor, &wr)
-	if err != nil {
-		return subnet.LeaseWatchResult{}, err
-	}
-	if _, ok := wr.Cursor.(string); !ok {
-		return subnet.LeaseWatchResult{}, fmt.Errorf("watch returned non-string cursor")
-	}
-
-	return wr, nil
-}
-
-func (m *RemoteManager) WatchLeases(ctx context.Context, network string, cursor interface{}) (subnet.LeaseWatchResult, error) {
-	url := m.mkurl(network, "leases")
-
-	wr := subnet.LeaseWatchResult{}
-	err := m.watch(ctx, url, cursor, &wr)
-	if err != nil {
-		return subnet.LeaseWatchResult{}, err
-	}
-	if _, ok := wr.Cursor.(string); !ok {
-		return subnet.LeaseWatchResult{}, fmt.Errorf("watch returned non-string cursor")
-	}
-
-	return wr, nil
-}
-
-func (m *RemoteManager) WatchNetworks(ctx context.Context, cursor interface{}) (subnet.NetworkWatchResult, error) {
-	wr := subnet.NetworkWatchResult{}
-	err := m.watch(ctx, m.base+"/", cursor, &wr)
-	if err != nil {
-		return subnet.NetworkWatchResult{}, err
-	}
-
-	if _, ok := wr.Cursor.(string); !ok {
-		return subnet.NetworkWatchResult{}, fmt.Errorf("watch returned non-string cursor")
-	}
-
-	return wr, nil
-}
-
-func (m *RemoteManager) AddReservation(ctx context.Context, network string, r *subnet.Reservation) error {
-	url := m.mkurl(network, "reservations")
-
-	body, err := json.Marshal(r)
-	if err != nil {
-		return err
-	}
-
-	resp, err := m.httpVerb(ctx, "POST", url, "application/json", body)
-	if err != nil {
-		return err
-	}
-	defer resp.Body.Close()
-
-	if resp.StatusCode != http.StatusOK {
-		return httpError(resp)
-	}
-
-	return nil
-}
-
-func (m *RemoteManager) CreateBackendData(ctx context.Context, network, data string) error {
-	url := m.mkurl(network, "backend-data")
-
-	body, err := json.Marshal(data)
-	if err != nil {
-		return err
-	}
-
-	resp, err := m.httpVerb(ctx, "POST", url, "application/json", body)
-	if err != nil {
-		return err
-	}
-	defer resp.Body.Close()
-
-	if resp.StatusCode != http.StatusOK {
-		return httpError(resp)
-	}
-
-	return nil
-}
-
-func (m *RemoteManager) RemoveReservation(ctx context.Context, network string, sn ip.IP4Net) error {
-	url := m.mkurl(network, "reservations", subnet.MakeSubnetKey(sn))
-
-	resp, err := m.httpVerb(ctx, "DELETE", url, "", nil)
-	if err != nil {
-		return err
-	}
-	defer resp.Body.Close()
-
-	if resp.StatusCode != http.StatusOK {
-		return httpError(resp)
-	}
-
-	return nil
-}
-
-func (m *RemoteManager) ListReservations(ctx context.Context, network string) ([]subnet.Reservation, error) {
-	url := m.mkurl(network, "reservations")
-
-	resp, err := m.httpVerb(ctx, "GET", url, "", nil)
-	if err != nil {
-		return nil, err
-	}
-	defer resp.Body.Close()
-
-	if resp.StatusCode != http.StatusOK {
-		return nil, httpError(resp)
-	}
-	rs := []subnet.Reservation{}
-	if err := json.NewDecoder(resp.Body).Decode(&rs); err != nil {
-		return nil, err
-	}
-
-	return rs, nil
-}
-
-func (m *RemoteManager) GetBackendData(ctx context.Context, network string) (string, error) {
-	url := m.mkurl(network, "backend-data")
-
-	resp, err := m.httpVerb(ctx, "GET", url, "", nil)
-	if err != nil {
-		return "", err
-	}
-	defer resp.Body.Close()
-
-	if resp.StatusCode != http.StatusOK {
-		return "", httpError(resp)
-	}
-
-	data := ""
-	if err := json.NewDecoder(resp.Body).Decode(&data); err != nil {
-		return "", err
-	}
-
-	return data, nil
-}
-
-func httpError(resp *http.Response) error {
-	b, err := ioutil.ReadAll(resp.Body)
-	if err != nil {
-		return err
-	}
-	return fmt.Errorf("%v: %v", resp.Status, string(b))
-}
-
-type httpRespErr struct {
-	resp *http.Response
-	err  error
-}
-
-func (m *RemoteManager) httpDo(ctx context.Context, req *http.Request) (*http.Response, error) {
-	// Run the HTTP request in a goroutine (so it can be canceled) and pass
-	// the result via the channel c
-	client := &http.Client{Transport: m.transport}
-	c := make(chan httpRespErr, 1)
-	go func() {
-		resp, err := client.Do(req)
-		c <- httpRespErr{resp, err}
-	}()
-
-	select {
-	case <-ctx.Done():
-		m.transport.CancelRequest(req)
-		<-c // Wait for f to return.
-		return nil, ctx.Err()
-	case r := <-c:
-		return r.resp, r.err
-	}
-}
-
-func (m *RemoteManager) httpVerb(ctx context.Context, method, url, contentType string, body []byte) (*http.Response, error) {
-	var r io.Reader
-	if body != nil {
-		r = bytes.NewBuffer(body)
-	}
-
-	req, err := http.NewRequest(method, url, r)
-	if err != nil {
-		return nil, err
-	}
-
-	if contentType != "" {
-		req.Header.Set("Content-Type", contentType)
-	}
-	return m.httpDo(ctx, req)
-}

+ 0 - 447
remote/server.go

@@ -1,447 +0,0 @@
-// Copyright 2015 flannel authors
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//     http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package remote
-
-import (
-	"crypto/tls"
-	"encoding/json"
-	"fmt"
-	"net"
-	"net/http"
-	"net/url"
-	"regexp"
-	"strconv"
-
-	"github.com/coreos/etcd/pkg/transport"
-	"github.com/coreos/go-systemd/activation"
-	"github.com/coreos/go-systemd/daemon"
-	log "github.com/golang/glog"
-	"github.com/gorilla/mux"
-	"golang.org/x/net/context"
-
-	"github.com/coreos/flannel/subnet"
-)
-
-type handler func(context.Context, subnet.Manager, http.ResponseWriter, *http.Request)
-
-func jsonResponse(w http.ResponseWriter, code int, v interface{}) {
-	w.Header().Set("Content-Type", "application/json; charset=utf-8")
-	w.WriteHeader(code)
-	if err := json.NewEncoder(w).Encode(v); err != nil {
-		log.Error("Error JSON encoding response: %v", err)
-	}
-}
-
-// GET /{network}/config
-func handleGetNetworkConfig(ctx context.Context, sm subnet.Manager, w http.ResponseWriter, r *http.Request) {
-	network := mux.Vars(r)["network"]
-	if network == "_" {
-		network = ""
-	}
-
-	c, err := sm.GetNetworkConfig(ctx, network)
-	if err != nil {
-		w.WriteHeader(http.StatusInternalServerError)
-		fmt.Fprint(w, err)
-		return
-	}
-
-	jsonResponse(w, http.StatusOK, c)
-}
-
-func handleAcquireLease(ctx context.Context, sm subnet.Manager, w http.ResponseWriter, r *http.Request) {
-	network := mux.Vars(r)["network"]
-	if network == "_" {
-		network = ""
-	}
-
-	attrs := subnet.LeaseAttrs{}
-	if err := json.NewDecoder(r.Body).Decode(&attrs); err != nil {
-		w.WriteHeader(http.StatusBadRequest)
-		fmt.Fprint(w, "JSON decoding error: ", err)
-		return
-	}
-
-	lease, err := sm.AcquireLease(ctx, network, &attrs)
-	if err != nil {
-		w.WriteHeader(http.StatusInternalServerError)
-		fmt.Fprint(w, err)
-		return
-	}
-
-	jsonResponse(w, http.StatusOK, lease)
-}
-
-// PUT /{network}/{lease.network}
-func handleRenewLease(ctx context.Context, sm subnet.Manager, w http.ResponseWriter, r *http.Request) {
-	network := mux.Vars(r)["network"]
-	if network == "_" {
-		network = ""
-	}
-
-	lease := subnet.Lease{}
-	if err := json.NewDecoder(r.Body).Decode(&lease); err != nil {
-		w.WriteHeader(http.StatusBadRequest)
-		fmt.Fprint(w, "JSON decoding error: ", err)
-		return
-	}
-
-	if err := sm.RenewLease(ctx, network, &lease); err != nil {
-		w.WriteHeader(http.StatusInternalServerError)
-		fmt.Fprint(w, err)
-		return
-	}
-
-	jsonResponse(w, http.StatusOK, lease)
-}
-
-func handleRevokeLease(ctx context.Context, sm subnet.Manager, w http.ResponseWriter, r *http.Request) {
-	network := mux.Vars(r)["network"]
-	if network == "_" {
-		network = ""
-	}
-
-	sn := subnet.ParseSubnetKey(mux.Vars(r)["subnet"])
-	if sn == nil {
-		w.WriteHeader(http.StatusBadRequest)
-		fmt.Fprint(w, "failed to parse subnet")
-		return
-	}
-
-	if err := sm.RevokeLease(ctx, network, *sn); err != nil {
-		w.WriteHeader(http.StatusInternalServerError)
-		fmt.Fprint(w, err)
-		return
-	}
-}
-
-func handleGetBackendData(ctx context.Context, sm subnet.Manager, w http.ResponseWriter, r *http.Request) {
-	defer r.Body.Close()
-
-	network := mux.Vars(r)["network"]
-	if network == "_" {
-		network = ""
-	}
-
-	p, err := sm.GetBackendData(ctx, network)
-	if err != nil {
-		w.WriteHeader(http.StatusInternalServerError)
-		fmt.Fprint(w, err)
-		return
-	}
-
-	jsonResponse(w, http.StatusOK, p)
-}
-
-func handleCreateBackendData(ctx context.Context, sm subnet.Manager, w http.ResponseWriter, r *http.Request) {
-	defer r.Body.Close()
-
-	network := mux.Vars(r)["network"]
-	if network == "_" {
-		network = ""
-	}
-
-	data := ""
-	if err := json.NewDecoder(r.Body).Decode(&data); err != nil {
-		w.WriteHeader(http.StatusBadRequest)
-		fmt.Fprint(w, "JSON decoding error: ", err)
-		return
-	}
-
-	if err := sm.CreateBackendData(ctx, network, data); err != nil {
-		w.WriteHeader(http.StatusInternalServerError)
-		fmt.Fprint(w, err)
-		return
-	}
-
-	w.WriteHeader(http.StatusOK)
-}
-
-func getCursor(u *url.URL) interface{} {
-	vals, ok := u.Query()["next"]
-	if !ok {
-		return nil
-	}
-	return vals[0]
-}
-
-// GET /{network}/leases/subnet?next=cursor
-func handleWatchLease(ctx context.Context, sm subnet.Manager, w http.ResponseWriter, r *http.Request) {
-	network := mux.Vars(r)["network"]
-	if network == "_" {
-		network = ""
-	}
-
-	sn := subnet.ParseSubnetKey(mux.Vars(r)["subnet"])
-	if sn == nil {
-		w.WriteHeader(http.StatusBadRequest)
-		fmt.Fprint(w, "bad subnet")
-		return
-	}
-
-	cursor := getCursor(r.URL)
-
-	wr, err := sm.WatchLease(ctx, network, *sn, cursor)
-	if err != nil {
-		w.WriteHeader(http.StatusInternalServerError)
-		fmt.Fprint(w, err)
-		return
-	}
-
-	switch wr.Cursor.(type) {
-	case string:
-	case fmt.Stringer:
-		wr.Cursor = wr.Cursor.(fmt.Stringer).String()
-	default:
-		w.WriteHeader(http.StatusInternalServerError)
-		fmt.Fprint(w, fmt.Errorf("internal error: watch cursor is of unknown type"))
-		return
-	}
-
-	jsonResponse(w, http.StatusOK, wr)
-}
-
-// GET /{network}/leases?next=cursor
-func handleWatchLeases(ctx context.Context, sm subnet.Manager, w http.ResponseWriter, r *http.Request) {
-	network := mux.Vars(r)["network"]
-	if network == "_" {
-		network = ""
-	}
-
-	cursor := getCursor(r.URL)
-
-	wr, err := sm.WatchLeases(ctx, network, cursor)
-	if err != nil {
-		w.WriteHeader(http.StatusInternalServerError)
-		fmt.Fprint(w, err)
-		return
-	}
-
-	switch wr.Cursor.(type) {
-	case string:
-	case fmt.Stringer:
-		wr.Cursor = wr.Cursor.(fmt.Stringer).String()
-	default:
-		w.WriteHeader(http.StatusInternalServerError)
-		fmt.Fprint(w, fmt.Errorf("internal error: watch cursor is of unknown type"))
-		return
-	}
-
-	jsonResponse(w, http.StatusOK, wr)
-}
-
-// GET /?next=cursor watches
-// GET / retrieves all networks
-func handleNetworks(ctx context.Context, sm subnet.Manager, w http.ResponseWriter, r *http.Request) {
-	cursor := getCursor(r.URL)
-	wr, err := sm.WatchNetworks(ctx, cursor)
-	if err != nil {
-		w.WriteHeader(http.StatusInternalServerError)
-		fmt.Fprint(w, err)
-		return
-	}
-
-	switch wr.Cursor.(type) {
-	case string:
-	case fmt.Stringer:
-		wr.Cursor = wr.Cursor.(fmt.Stringer).String()
-	default:
-		w.WriteHeader(http.StatusInternalServerError)
-		fmt.Fprint(w, fmt.Errorf("internal error: watch cursor is of unknown type"))
-		return
-	}
-
-	jsonResponse(w, http.StatusOK, wr)
-}
-
-// POST /{network}/reservations
-func handleAddReservation(ctx context.Context, sm subnet.Manager, w http.ResponseWriter, r *http.Request) {
-	network := mux.Vars(r)["network"]
-	if network == "_" {
-		network = ""
-	}
-
-	rsv := &subnet.Reservation{}
-	if err := json.NewDecoder(r.Body).Decode(rsv); err != nil {
-		w.WriteHeader(http.StatusBadRequest)
-		fmt.Fprint(w, "JSON decoding error: ", err)
-		return
-	}
-
-	if err := sm.AddReservation(ctx, network, rsv); err != nil {
-		w.WriteHeader(http.StatusInternalServerError)
-		fmt.Fprint(w, fmt.Errorf("internal error: %v", err))
-		return
-	}
-}
-
-// DELETE /{network}/reservations/{subnet}
-func handleRemoveReservation(ctx context.Context, sm subnet.Manager, w http.ResponseWriter, r *http.Request) {
-	network := mux.Vars(r)["network"]
-	if network == "_" {
-		network = ""
-	}
-
-	sn := subnet.ParseSubnetKey(mux.Vars(r)["subnet"])
-	if sn == nil {
-		w.WriteHeader(http.StatusBadRequest)
-		fmt.Fprint(w, "bad subnet")
-		return
-	}
-
-	if err := sm.RemoveReservation(ctx, network, *sn); err != nil {
-		w.WriteHeader(http.StatusInternalServerError)
-		fmt.Fprint(w, err)
-		return
-	}
-
-	w.WriteHeader(http.StatusOK)
-}
-
-// GET /{network}/reservations
-func handleListReservations(ctx context.Context, sm subnet.Manager, w http.ResponseWriter, r *http.Request) {
-	network := mux.Vars(r)["network"]
-	if network == "_" {
-		network = ""
-	}
-
-	leases, err := sm.ListReservations(ctx, network)
-	if err != nil {
-		w.WriteHeader(http.StatusInternalServerError)
-		fmt.Fprint(w, err)
-		return
-	}
-
-	jsonResponse(w, http.StatusOK, leases)
-}
-
-func bindHandler(h handler, ctx context.Context, sm subnet.Manager) http.HandlerFunc {
-	return func(resp http.ResponseWriter, req *http.Request) {
-		h(ctx, sm, resp, req)
-	}
-}
-
-func fdListener(addr string) (net.Listener, error) {
-	fdOffset := 0
-	if addr != "" {
-		fd, err := strconv.Atoi(addr)
-		if err != nil {
-			return nil, fmt.Errorf("fd index is not a number")
-		}
-		fdOffset = fd - 3
-	}
-
-	listeners, err := activation.Listeners(false)
-	if err != nil {
-		return nil, err
-	}
-
-	if fdOffset >= len(listeners) {
-		return nil, fmt.Errorf("fd %v is out of range (%v)", addr, len(listeners)+3)
-	}
-
-	if listeners[fdOffset] == nil {
-		return nil, fmt.Errorf("fd %v was not socket activated", addr)
-	}
-
-	return listeners[fdOffset], nil
-}
-
-func listener(addr, cafile, certfile, keyfile string) (net.Listener, error) {
-	rex := regexp.MustCompile("(?:([a-z]+)://)?(.*)")
-	groups := rex.FindStringSubmatch(addr)
-
-	var l net.Listener
-	var err error
-
-	switch {
-	case groups == nil:
-		return nil, fmt.Errorf("bad listener address")
-
-	case groups[1] == "", groups[1] == "tcp":
-		if l, err = net.Listen("tcp", groups[2]); err != nil {
-			return nil, err
-		}
-
-	case groups[1] == "fd":
-		if l, err = fdListener(groups[2]); err != nil {
-			return nil, err
-		}
-
-	default:
-		return nil, fmt.Errorf("bad listener scheme")
-	}
-
-	tlsinfo := transport.TLSInfo{
-		CAFile:   cafile,
-		CertFile: certfile,
-		KeyFile:  keyfile,
-	}
-
-	if !tlsinfo.Empty() {
-		cfg, err := tlsinfo.ServerConfig()
-		if err != nil {
-			return nil, err
-		}
-
-		l = tls.NewListener(l, cfg)
-	}
-
-	return l, nil
-}
-
-func RunServer(ctx context.Context, sm subnet.Manager, listenAddr, cafile, certfile, keyfile string) {
-	// {network} is always required a the API level but to
-	// keep backward compat, special "_" network is allowed
-	// that means "no network"
-
-	r := mux.NewRouter()
-	r.HandleFunc("/v1/{network}/config", bindHandler(handleGetNetworkConfig, ctx, sm)).Methods("GET")
-
-	r.HandleFunc("/v1/{network}/leases", bindHandler(handleAcquireLease, ctx, sm)).Methods("POST")
-	r.HandleFunc("/v1/{network}/leases/{subnet}", bindHandler(handleWatchLease, ctx, sm)).Methods("GET")
-	r.HandleFunc("/v1/{network}/leases/{subnet}", bindHandler(handleRenewLease, ctx, sm)).Methods("PUT")
-	r.HandleFunc("/v1/{network}/leases/{subnet}", bindHandler(handleRevokeLease, ctx, sm)).Methods("DELETE")
-	r.HandleFunc("/v1/{network}/leases", bindHandler(handleWatchLeases, ctx, sm)).Methods("GET")
-	r.HandleFunc("/v1/", bindHandler(handleNetworks, ctx, sm)).Methods("GET")
-	r.HandleFunc("/v1/{network}/backend-data", bindHandler(handleGetBackendData, ctx, sm)).Methods("GET")
-	r.HandleFunc("/v1/{network}/backend-data", bindHandler(handleCreateBackendData, ctx, sm)).Methods("POST")
-
-	r.HandleFunc("/v1/{network}/reservations", bindHandler(handleListReservations, ctx, sm)).Methods("GET")
-	r.HandleFunc("/v1/{network}/reservations", bindHandler(handleAddReservation, ctx, sm)).Methods("POST")
-	r.HandleFunc("/v1/{network}/reservations/{subnet}", bindHandler(handleRemoveReservation, ctx, sm)).Methods("DELETE")
-
-	l, err := listener(listenAddr, cafile, certfile, keyfile)
-	if err != nil {
-		log.Errorf("Error listening on %v: %v", listenAddr, err)
-		return
-	}
-
-	c := make(chan error, 1)
-	go func() {
-		c <- http.Serve(l, httpLogger(r))
-	}()
-
-	daemon.SdNotify("READY=1")
-
-	select {
-	case <-ctx.Done():
-		l.Close()
-		<-c
-
-	case err := <-c:
-		log.Errorf("Error serving on %v: %v", listenAddr, err)
-	}
-}

+ 1 - 0
subnet/etcdv2/mock_registry.go

@@ -31,6 +31,7 @@ var clock clockwork.Clock = clockwork.NewRealClock()
 
 type netwk struct {
 	config        string
+	backendData   string
 	subnets       []Lease
 	subnetsEvents chan event
 

+ 21 - 0
subnet/etcdv2/registry.go

@@ -298,6 +298,27 @@ func parseSubnetWatchResponse(resp *etcd.Response) (Event, error) {
 	}
 }
 
+func (esr *etcdSubnetRegistry) createBackendData(ctx context.Context, network, data string) error {
+	key := path.Join(esr.etcdCfg.Prefix, network, "backend-data")
+	_, err := esr.client().Create(ctx, key, data)
+	if err != nil {
+		return err
+	}
+
+	return nil
+}
+
+func (esr *etcdSubnetRegistry) getBackendData(ctx context.Context, network string) (string, error) {
+	key := path.Join(esr.etcdCfg.Prefix, network, "backend-data")
+	etcdResponse, err := esr.client().Get(ctx, key, nil)
+
+	if err != nil {
+		return "", err
+	}
+
+	return etcdResponse.Node.Value, nil
+}
+
 func nodeToLease(node *etcd.Node) (*Lease, error) {
 	sn := ParseSubnetKey(node.Key)
 	if sn == nil {

+ 0 - 8
subnet/kube/kube.go

@@ -325,11 +325,3 @@ func (ksm *kubeSubnetManager) WatchLease(ctx context.Context, sn ip.IP4Net, curs
 func (ksm *kubeSubnetManager) Name() string {
 	return fmt.Sprintf("Kubernetes Subnet Manager - %s", ksm.nodeName)
 }
-
-func (ksm *kubeSubnetManager) GetBackendData(ctx context.Context, network string) (string, error) {
-	return "", ErrUnimplemented
-}
-
-func (ksm *kubeSubnetManager) CreateBackendData(ctx context.Context, network, data string) error {
-	return ErrUnimplemented
-}

+ 0 - 516
subnet/local_manager.go

@@ -1,516 +0,0 @@
-// Copyright 2015 flannel authors
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//     http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package subnet
-
-import (
-	"errors"
-	"fmt"
-	"strconv"
-	"time"
-
-	etcd "github.com/coreos/etcd/client"
-	"github.com/coreos/flannel/pkg/ip"
-	log "github.com/golang/glog"
-	"golang.org/x/net/context"
-)
-
-const (
-	raceRetries = 10
-	subnetTTL   = 24 * time.Hour
-)
-
-type LocalManager struct {
-	registry Registry
-}
-
-type watchCursor struct {
-	index uint64
-}
-
-func isErrEtcdTestFailed(e error) bool {
-	if e == nil {
-		return false
-	}
-	etcdErr, ok := e.(etcd.Error)
-	return ok && etcdErr.Code == etcd.ErrorCodeTestFailed
-}
-
-func isErrEtcdNodeExist(e error) bool {
-	if e == nil {
-		return false
-	}
-	etcdErr, ok := e.(etcd.Error)
-	return ok || etcdErr.Code == etcd.ErrorCodeNodeExist
-}
-
-func isErrEtcdKeyNotFound(e error) bool {
-	if e == nil {
-		return false
-	}
-	etcdErr, ok := e.(etcd.Error)
-	return ok || etcdErr.Code == etcd.ErrorCodeKeyNotFound
-}
-
-func (c watchCursor) String() string {
-	return strconv.FormatUint(c.index, 10)
-}
-
-func NewLocalManager(config *EtcdConfig) (Manager, error) {
-	r, err := newEtcdSubnetRegistry(config, nil)
-	if err != nil {
-		return nil, err
-	}
-	return newLocalManager(r), nil
-}
-
-func newLocalManager(r Registry) Manager {
-	return &LocalManager{
-		registry: r,
-	}
-}
-
-func (m *LocalManager) GetNetworkConfig(ctx context.Context, network string) (*Config, error) {
-	cfg, err := m.registry.getNetworkConfig(ctx, network)
-	if err != nil {
-		return nil, err
-	}
-
-	return ParseConfig(cfg)
-}
-
-func (m *LocalManager) AcquireLease(ctx context.Context, network string, attrs *LeaseAttrs) (*Lease, error) {
-	config, err := m.GetNetworkConfig(ctx, network)
-	if err != nil {
-		return nil, err
-	}
-
-	for i := 0; i < raceRetries; i++ {
-		l, err := m.tryAcquireLease(ctx, network, config, attrs.PublicIP, attrs)
-		switch err {
-		case nil:
-			return l, nil
-		case errTryAgain:
-			continue
-		default:
-			return nil, err
-		}
-	}
-
-	return nil, errors.New("Max retries reached trying to acquire a subnet")
-}
-
-func findLeaseByIP(leases []Lease, pubIP ip.IP4) *Lease {
-	for _, l := range leases {
-		if pubIP == l.Attrs.PublicIP {
-			return &l
-		}
-	}
-
-	return nil
-}
-
-func (m *LocalManager) tryAcquireLease(ctx context.Context, network string, config *Config, extIaddr ip.IP4, attrs *LeaseAttrs) (*Lease, error) {
-	leases, _, err := m.registry.getSubnets(ctx, network)
-	if err != nil {
-		return nil, err
-	}
-
-	// try to reuse a subnet if there's one that matches our IP
-	if l := findLeaseByIP(leases, extIaddr); l != nil {
-		// make sure the existing subnet is still within the configured network
-		if isSubnetConfigCompat(config, l.Subnet) {
-			log.Infof("Found lease (%v) for current IP (%v), reusing", l.Subnet, extIaddr)
-
-			ttl := time.Duration(0)
-			if !l.Expiration.IsZero() {
-				// Not a reservation
-				ttl = subnetTTL
-			}
-			exp, err := m.registry.updateSubnet(ctx, network, l.Subnet, attrs, ttl, 0)
-			if err != nil {
-				return nil, err
-			}
-
-			l.Attrs = *attrs
-			l.Expiration = exp
-			return l, nil
-		} else {
-			log.Infof("Found lease (%v) for current IP (%v) but not compatible with current config, deleting", l.Subnet, extIaddr)
-			if err := m.registry.deleteSubnet(ctx, network, l.Subnet); err != nil {
-				return nil, err
-			}
-		}
-	}
-
-	// no existing match, grab a new one
-	sn, err := m.allocateSubnet(config, leases)
-	if err != nil {
-		return nil, err
-	}
-
-	exp, err := m.registry.createSubnet(ctx, network, sn, attrs, subnetTTL)
-	switch {
-	case err == nil:
-		return &Lease{
-			Subnet:     sn,
-			Attrs:      *attrs,
-			Expiration: exp,
-		}, nil
-	case isErrEtcdNodeExist(err):
-		return nil, errTryAgain
-	default:
-		return nil, err
-	}
-}
-
-func (m *LocalManager) allocateSubnet(config *Config, leases []Lease) (ip.IP4Net, error) {
-	log.Infof("Picking subnet in range %s ... %s", config.SubnetMin, config.SubnetMax)
-
-	var bag []ip.IP4
-	sn := ip.IP4Net{IP: config.SubnetMin, PrefixLen: config.SubnetLen}
-
-OuterLoop:
-	for ; sn.IP <= config.SubnetMax && len(bag) < 100; sn = sn.Next() {
-		for _, l := range leases {
-			if sn.Overlaps(l.Subnet) {
-				continue OuterLoop
-			}
-		}
-		bag = append(bag, sn.IP)
-	}
-
-	if len(bag) == 0 {
-		return ip.IP4Net{}, errors.New("out of subnets")
-	} else {
-		i := randInt(0, len(bag))
-		return ip.IP4Net{IP: bag[i], PrefixLen: config.SubnetLen}, nil
-	}
-}
-
-func (m *LocalManager) RevokeLease(ctx context.Context, network string, sn ip.IP4Net) error {
-	return m.registry.deleteSubnet(ctx, network, sn)
-}
-
-func (m *LocalManager) RenewLease(ctx context.Context, network string, lease *Lease) error {
-	exp, err := m.registry.updateSubnet(ctx, network, lease.Subnet, &lease.Attrs, subnetTTL, 0)
-	if err != nil {
-		return err
-	}
-
-	lease.Expiration = exp
-	return nil
-}
-
-func getNextIndex(cursor interface{}) (uint64, error) {
-	nextIndex := uint64(0)
-
-	if wc, ok := cursor.(watchCursor); ok {
-		nextIndex = wc.index
-	} else if s, ok := cursor.(string); ok {
-		var err error
-		nextIndex, err = strconv.ParseUint(s, 10, 64)
-		if err != nil {
-			return 0, fmt.Errorf("failed to parse cursor: %v", err)
-		}
-	} else {
-		return 0, fmt.Errorf("internal error: watch cursor is of unknown type")
-	}
-
-	return nextIndex, nil
-}
-
-func (m *LocalManager) leaseWatchReset(ctx context.Context, network string, sn ip.IP4Net) (LeaseWatchResult, error) {
-	l, index, err := m.registry.getSubnet(ctx, network, sn)
-	if err != nil {
-		return LeaseWatchResult{}, err
-	}
-
-	return LeaseWatchResult{
-		Snapshot: []Lease{*l},
-		Cursor:   watchCursor{index},
-	}, nil
-}
-
-func (m *LocalManager) WatchLease(ctx context.Context, network string, sn ip.IP4Net, cursor interface{}) (LeaseWatchResult, error) {
-	if cursor == nil {
-		return m.leaseWatchReset(ctx, network, sn)
-	}
-
-	nextIndex, err := getNextIndex(cursor)
-	if err != nil {
-		return LeaseWatchResult{}, err
-	}
-
-	evt, index, err := m.registry.watchSubnet(ctx, network, nextIndex, sn)
-
-	switch {
-	case err == nil:
-		return LeaseWatchResult{
-			Events: []Event{evt},
-			Cursor: watchCursor{index},
-		}, nil
-
-	case isIndexTooSmall(err):
-		log.Warning("Watch of subnet leases failed because etcd index outside history window")
-		return m.leaseWatchReset(ctx, network, sn)
-
-	default:
-		return LeaseWatchResult{}, err
-	}
-}
-
-func (m *LocalManager) WatchLeases(ctx context.Context, network string, cursor interface{}) (LeaseWatchResult, error) {
-	if cursor == nil {
-		return m.leasesWatchReset(ctx, network)
-	}
-
-	nextIndex, err := getNextIndex(cursor)
-	if err != nil {
-		return LeaseWatchResult{}, err
-	}
-
-	evt, index, err := m.registry.watchSubnets(ctx, network, nextIndex)
-
-	switch {
-	case err == nil:
-		return LeaseWatchResult{
-			Events: []Event{evt},
-			Cursor: watchCursor{index},
-		}, nil
-
-	case isIndexTooSmall(err):
-		log.Warning("Watch of subnet leases failed because etcd index outside history window")
-		return m.leasesWatchReset(ctx, network)
-
-	default:
-		return LeaseWatchResult{}, err
-	}
-}
-
-func (m *LocalManager) WatchNetworks(ctx context.Context, cursor interface{}) (NetworkWatchResult, error) {
-	if cursor == nil {
-		return m.networkWatchReset(ctx)
-	}
-
-	nextIndex, err := getNextIndex(cursor)
-	if err != nil {
-		return NetworkWatchResult{}, err
-	}
-
-	for {
-		evt, index, err := m.registry.watchNetworks(ctx, nextIndex)
-
-		switch {
-		case err == nil:
-			return NetworkWatchResult{
-				Events: []Event{evt},
-				Cursor: watchCursor{index},
-			}, nil
-
-		case err == errTryAgain:
-			nextIndex = index
-
-		case isIndexTooSmall(err):
-			log.Warning("Watch of networks failed because etcd index outside history window")
-			return m.networkWatchReset(ctx)
-
-		default:
-			return NetworkWatchResult{}, err
-		}
-	}
-}
-
-func isIndexTooSmall(err error) bool {
-	etcdErr, ok := err.(etcd.Error)
-	return ok && etcdErr.Code == etcd.ErrorCodeEventIndexCleared
-}
-
-// leasesWatchReset is called when incremental lease watch failed and we need to grab a snapshot
-func (m *LocalManager) leasesWatchReset(ctx context.Context, network string) (LeaseWatchResult, error) {
-	wr := LeaseWatchResult{}
-
-	leases, index, err := m.registry.getSubnets(ctx, network)
-	if err != nil {
-		return wr, fmt.Errorf("failed to retrieve subnet leases: %v", err)
-	}
-
-	wr.Cursor = watchCursor{index}
-	wr.Snapshot = leases
-	return wr, nil
-}
-
-// networkWatchReset is called when incremental network watch failed and we need to grab a snapshot
-func (m *LocalManager) networkWatchReset(ctx context.Context) (NetworkWatchResult, error) {
-	wr := NetworkWatchResult{}
-
-	networks, index, err := m.registry.getNetworks(ctx)
-	if err != nil {
-		return wr, fmt.Errorf("failed to retrieve networks: %v", err)
-	}
-
-	wr.Cursor = watchCursor{index}
-	wr.Snapshot = networks
-	return wr, nil
-}
-
-func isSubnetConfigCompat(config *Config, sn ip.IP4Net) bool {
-	if sn.IP < config.SubnetMin || sn.IP > config.SubnetMax {
-		return false
-	}
-
-	return sn.PrefixLen == config.SubnetLen
-}
-
-func (m *LocalManager) tryAddReservation(ctx context.Context, network string, r *Reservation) error {
-	attrs := &LeaseAttrs{
-		PublicIP: r.PublicIP,
-	}
-
-	_, err := m.registry.createSubnet(ctx, network, r.Subnet, attrs, 0)
-	switch {
-	case err == nil:
-		return nil
-
-	case !isErrEtcdNodeExist(err):
-		return err
-	}
-
-	// This subnet or its reservation already exists.
-	// Get what's there and
-	// - if PublicIP matches, remove the TTL make it a reservation
-	// - otherwise, error out
-	sub, asof, err := m.registry.getSubnet(ctx, network, r.Subnet)
-	switch {
-	case err == nil:
-	case isErrEtcdKeyNotFound(err):
-		// Subnet just got expired or was deleted
-		return errTryAgain
-	default:
-		return err
-	}
-
-	if sub.Attrs.PublicIP != r.PublicIP {
-		// Subnet already taken
-		return ErrLeaseTaken
-	}
-
-	// remove TTL
-	_, err = m.registry.updateSubnet(ctx, network, r.Subnet, &sub.Attrs, 0, asof)
-	if isErrEtcdTestFailed(err) {
-		return errTryAgain
-	}
-	return err
-}
-
-func (m *LocalManager) AddReservation(ctx context.Context, network string, r *Reservation) error {
-	config, err := m.GetNetworkConfig(ctx, network)
-	if err != nil {
-		return err
-	}
-
-	if config.SubnetLen != r.Subnet.PrefixLen {
-		return fmt.Errorf("reservation subnet has mask incompatible with network config")
-	}
-
-	if !config.Network.Overlaps(r.Subnet) {
-		return fmt.Errorf("reservation subnet is outside of flannel network")
-	}
-
-	for i := 0; i < raceRetries; i++ {
-		err := m.tryAddReservation(ctx, network, r)
-		switch {
-		case err == nil:
-			return nil
-		case err == errTryAgain:
-			continue
-		default:
-			return err
-		}
-	}
-
-	return ErrNoMoreTries
-}
-
-func (m *LocalManager) tryRemoveReservation(ctx context.Context, network string, subnet ip.IP4Net) error {
-	sub, asof, err := m.registry.getSubnet(ctx, network, subnet)
-	if err != nil {
-		return err
-	}
-
-	// add back the TTL
-	_, err = m.registry.updateSubnet(ctx, network, subnet, &sub.Attrs, subnetTTL, asof)
-	if isErrEtcdTestFailed(err) {
-		return errTryAgain
-	}
-	return err
-}
-
-//RemoveReservation removes the subnet by setting TTL back to subnetTTL (24hours)
-func (m *LocalManager) RemoveReservation(ctx context.Context, network string, subnet ip.IP4Net) error {
-	for i := 0; i < raceRetries; i++ {
-		err := m.tryRemoveReservation(ctx, network, subnet)
-		switch {
-		case err == nil:
-			return nil
-		case err == errTryAgain:
-			continue
-		default:
-			return err
-		}
-	}
-
-	return ErrNoMoreTries
-}
-
-func (m *LocalManager) ListReservations(ctx context.Context, network string) ([]Reservation, error) {
-	subnets, _, err := m.registry.getSubnets(ctx, network)
-	if err != nil {
-		return nil, err
-	}
-
-	rsvs := []Reservation{}
-	for _, sub := range subnets {
-		// Reservations don't have TTL and so no expiration
-		if !sub.Expiration.IsZero() {
-			continue
-		}
-
-		r := Reservation{
-			Subnet:   sub.Subnet,
-			PublicIP: sub.Attrs.PublicIP,
-		}
-		rsvs = append(rsvs, r)
-	}
-
-	return rsvs, nil
-}
-
-func (m *LocalManager) CreateBackendData(ctx context.Context, network, data string) error {
-	err := m.registry.createBackendData(ctx, network, data)
-
-	if err == nil {
-		return nil
-	}
-
-	if etcdErr, ok := err.(etcd.Error); ok && etcdErr.Code == etcd.ErrorCodeNodeExist {
-		return nil
-	}
-
-	return err
-}
-
-func (m *LocalManager) GetBackendData(ctx context.Context, network string) (string, error) {
-	return m.registry.getBackendData(ctx, network)
-}

+ 0 - 488
subnet/mock_registry.go

@@ -1,488 +0,0 @@
-// Copyright 2015 flannel authors
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//     http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package subnet
-
-import (
-	"fmt"
-	"strings"
-	"sync"
-	"time"
-
-	etcd "github.com/coreos/etcd/client"
-	"golang.org/x/net/context"
-
-	"github.com/coreos/flannel/pkg/ip"
-)
-
-type netwk struct {
-	config        string
-	backendData   string
-	subnets       []Lease
-	subnetsEvents chan event
-	mux           sync.Mutex
-	subnetEvents  map[ip.IP4Net]chan event
-}
-
-func (n *netwk) sendSubnetEvent(sn ip.IP4Net, e event) {
-	n.subnetsEvents <- e
-
-	n.mux.Lock()
-	c, ok := n.subnetEvents[sn]
-	if !ok {
-		c = make(chan event, 10)
-		n.subnetEvents[sn] = c
-	}
-	n.mux.Unlock()
-	c <- e
-}
-
-func (n *netwk) subnetEventsChan(sn ip.IP4Net) chan event {
-	n.mux.Lock()
-	c, ok := n.subnetEvents[sn]
-	if !ok {
-		c = make(chan event, 10)
-		n.subnetEvents[sn] = c
-	}
-	n.mux.Unlock()
-	return c
-}
-
-type event struct {
-	evt   Event
-	index uint64
-}
-
-type MockSubnetRegistry struct {
-	mux           sync.Mutex
-	networks      map[string]*netwk
-	networkEvents chan event
-	index         uint64
-}
-
-func NewMockRegistry(network, config string, initialSubnets []Lease) *MockSubnetRegistry {
-	msr := &MockSubnetRegistry{
-		networkEvents: make(chan event, 1000),
-		index:         1000,
-		networks:      make(map[string]*netwk),
-	}
-
-	msr.networks[network] = &netwk{
-		config:        config,
-		subnets:       initialSubnets,
-		subnetsEvents: make(chan event, 1000),
-		subnetEvents:  make(map[ip.IP4Net]chan event),
-	}
-	return msr
-}
-
-func (msr *MockSubnetRegistry) getNetworkConfig(ctx context.Context, network string) (string, error) {
-	msr.mux.Lock()
-	defer msr.mux.Unlock()
-
-	n, ok := msr.networks[network]
-	if !ok {
-		return "", fmt.Errorf("Network %s not found", network)
-	}
-	return n.config, nil
-}
-
-func (msr *MockSubnetRegistry) setConfig(network, config string) error {
-	msr.mux.Lock()
-	defer msr.mux.Unlock()
-
-	n, ok := msr.networks[network]
-	if !ok {
-		return fmt.Errorf("Network %s not found", network)
-	}
-	n.config = config
-	return nil
-}
-
-func (msr *MockSubnetRegistry) getSubnets(ctx context.Context, network string) ([]Lease, uint64, error) {
-	msr.mux.Lock()
-	defer msr.mux.Unlock()
-
-	n, ok := msr.networks[network]
-	if !ok {
-		return nil, 0, fmt.Errorf("Network %s not found", network)
-	}
-
-	subs := make([]Lease, len(n.subnets))
-	copy(subs, n.subnets)
-	return subs, msr.index, nil
-}
-
-func (msr *MockSubnetRegistry) getSubnet(ctx context.Context, network string, sn ip.IP4Net) (*Lease, uint64, error) {
-	msr.mux.Lock()
-	defer msr.mux.Unlock()
-
-	n, ok := msr.networks[network]
-	if !ok {
-		return nil, 0, fmt.Errorf("Network %s not found", network)
-	}
-	for _, l := range n.subnets {
-		if l.Subnet.Equal(sn) {
-			return &l, msr.index, nil
-		}
-	}
-	return nil, msr.index, fmt.Errorf("subnet %s not found", sn)
-}
-
-func (msr *MockSubnetRegistry) createSubnet(ctx context.Context, network string, sn ip.IP4Net, attrs *LeaseAttrs, ttl time.Duration) (time.Time, error) {
-	msr.mux.Lock()
-	defer msr.mux.Unlock()
-
-	n, ok := msr.networks[network]
-	if !ok {
-		return time.Time{}, fmt.Errorf("Network %s not found", network)
-	}
-
-	// check for existing
-	if _, _, err := n.findSubnet(sn); err == nil {
-		return time.Time{}, etcd.Error{
-			Code:  etcd.ErrorCodeNodeExist,
-			Index: msr.index,
-		}
-	}
-
-	msr.index += 1
-
-	exp := time.Time{}
-	if ttl != 0 {
-		exp = clock.Now().Add(ttl)
-	}
-
-	l := Lease{
-		Subnet:     sn,
-		Attrs:      *attrs,
-		Expiration: exp,
-		asof:       msr.index,
-	}
-	n.subnets = append(n.subnets, l)
-
-	evt := Event{
-		Type:    EventAdded,
-		Lease:   l,
-		Network: network,
-	}
-
-	n.sendSubnetEvent(sn, event{evt, msr.index})
-
-	return exp, nil
-}
-
-func (msr *MockSubnetRegistry) updateSubnet(ctx context.Context, network string, sn ip.IP4Net, attrs *LeaseAttrs, ttl time.Duration, asof uint64) (time.Time, error) {
-	msr.mux.Lock()
-	defer msr.mux.Unlock()
-
-	n, ok := msr.networks[network]
-	if !ok {
-		return time.Time{}, fmt.Errorf("Network %s not found", network)
-	}
-
-	msr.index += 1
-
-	exp := time.Time{}
-	if ttl != 0 {
-		exp = clock.Now().Add(ttl)
-	}
-
-	sub, i, err := n.findSubnet(sn)
-	if err != nil {
-		return time.Time{}, err
-	}
-
-	sub.Attrs = *attrs
-	sub.asof = msr.index
-	sub.Expiration = exp
-	n.subnets[i] = sub
-	n.sendSubnetEvent(sn, event{
-		Event{
-			Type:    EventAdded,
-			Lease:   sub,
-			Network: network,
-		}, msr.index,
-	})
-
-	return sub.Expiration, nil
-}
-
-func (msr *MockSubnetRegistry) deleteSubnet(ctx context.Context, network string, sn ip.IP4Net) error {
-	msr.mux.Lock()
-	defer msr.mux.Unlock()
-
-	n, ok := msr.networks[network]
-	if !ok {
-		return fmt.Errorf("Network %s not found", network)
-	}
-
-	msr.index += 1
-
-	sub, i, err := n.findSubnet(sn)
-	if err != nil {
-		return err
-	}
-
-	n.subnets[i] = n.subnets[len(n.subnets)-1]
-	n.subnets = n.subnets[:len(n.subnets)-1]
-	sub.asof = msr.index
-	n.sendSubnetEvent(sn, event{
-		Event{
-			Type:    EventRemoved,
-			Lease:   sub,
-			Network: network,
-		}, msr.index,
-	})
-
-	return nil
-}
-
-func (msr *MockSubnetRegistry) watchSubnets(ctx context.Context, network string, since uint64) (Event, uint64, error) {
-	msr.mux.Lock()
-	n, ok := msr.networks[network]
-	msr.mux.Unlock()
-
-	if !ok {
-		return Event{}, 0, fmt.Errorf("Network %s not found", network)
-	}
-
-	for {
-		msr.mux.Lock()
-		index := msr.index
-		msr.mux.Unlock()
-
-		if since < index {
-			return Event{}, 0, etcd.Error{
-				Code:    etcd.ErrorCodeEventIndexCleared,
-				Cause:   "out of date",
-				Message: "cursor is out of date",
-				Index:   index,
-			}
-		}
-
-		select {
-		case <-ctx.Done():
-			return Event{}, 0, ctx.Err()
-
-		case e := <-n.subnetsEvents:
-			if e.index > since {
-				return e.evt, e.index, nil
-			}
-		}
-	}
-}
-
-func (msr *MockSubnetRegistry) watchSubnet(ctx context.Context, network string, since uint64, sn ip.IP4Net) (Event, uint64, error) {
-	msr.mux.Lock()
-	n, ok := msr.networks[network]
-	msr.mux.Unlock()
-
-	if !ok {
-		return Event{}, 0, fmt.Errorf("Network %s not found", network)
-	}
-
-	for {
-		msr.mux.Lock()
-		index := msr.index
-		msr.mux.Unlock()
-
-		if since < index {
-			return Event{}, msr.index, etcd.Error{
-				Code:    etcd.ErrorCodeEventIndexCleared,
-				Cause:   "out of date",
-				Message: "cursor is out of date",
-				Index:   index,
-			}
-		}
-
-		select {
-		case <-ctx.Done():
-			return Event{}, index, ctx.Err()
-
-		case e := <-n.subnetEventsChan(sn):
-			if e.index > since {
-				return e.evt, index, nil
-			}
-		}
-	}
-}
-
-func (msr *MockSubnetRegistry) expireSubnet(network string, sn ip.IP4Net) {
-	msr.mux.Lock()
-	defer msr.mux.Unlock()
-
-	n, ok := msr.networks[network]
-	if !ok {
-		return
-	}
-
-	if sub, i, err := n.findSubnet(sn); err == nil {
-		msr.index += 1
-		n.subnets[i] = n.subnets[len(n.subnets)-1]
-		n.subnets = n.subnets[:len(n.subnets)-1]
-		sub.asof = msr.index
-		n.sendSubnetEvent(sn, event{
-			Event{
-				Type:  EventRemoved,
-				Lease: sub,
-			}, msr.index,
-		})
-	}
-}
-
-func configKeyToNetworkKey(configKey string) string {
-	if !strings.HasSuffix(configKey, "/config") {
-		return ""
-	}
-	return strings.TrimSuffix(configKey, "/config")
-}
-
-func (msr *MockSubnetRegistry) getNetworks(ctx context.Context) ([]string, uint64, error) {
-	msr.mux.Lock()
-	defer msr.mux.Unlock()
-
-	ns := []string{}
-
-	for n, _ := range msr.networks {
-		ns = append(ns, n)
-	}
-
-	return ns, msr.index, nil
-}
-
-func (msr *MockSubnetRegistry) watchNetworks(ctx context.Context, since uint64) (Event, uint64, error) {
-	msr.mux.Lock()
-	index := msr.index
-	msr.mux.Unlock()
-
-	for {
-		if since < index {
-			return Event{}, 0, etcd.Error{
-				Code:    etcd.ErrorCodeEventIndexCleared,
-				Cause:   "out of date",
-				Message: "cursor is out of date",
-				Index:   index,
-			}
-		}
-
-		select {
-		case <-ctx.Done():
-			return Event{}, 0, ctx.Err()
-
-		case e := <-msr.networkEvents:
-			if e.index > since {
-				return e.evt, e.index, nil
-			}
-		}
-	}
-}
-
-func (msr *MockSubnetRegistry) getNetwork(ctx context.Context, network string) (*netwk, error) {
-	msr.mux.Lock()
-	defer msr.mux.Unlock()
-
-	n, ok := msr.networks[network]
-	if !ok {
-		return nil, fmt.Errorf("Network %s not found", network)
-	}
-
-	return n, nil
-}
-
-func (msr *MockSubnetRegistry) CreateNetwork(ctx context.Context, network, config string) error {
-	msr.mux.Lock()
-	defer msr.mux.Unlock()
-
-	_, ok := msr.networks[network]
-	if ok {
-		return fmt.Errorf("Network %s already exists", network)
-	}
-
-	msr.index += 1
-
-	n := &netwk{
-		config:        network,
-		subnetsEvents: make(chan event, 1000),
-		subnetEvents:  make(map[ip.IP4Net]chan event),
-	}
-
-	msr.networks[network] = n
-	msr.networkEvents <- event{
-		Event{
-			Type:    EventAdded,
-			Network: network,
-		}, msr.index,
-	}
-
-	return nil
-}
-
-func (msr *MockSubnetRegistry) DeleteNetwork(ctx context.Context, network string) error {
-	msr.mux.Lock()
-	defer msr.mux.Unlock()
-
-	_, ok := msr.networks[network]
-	if !ok {
-		return fmt.Errorf("Network %s not found", network)
-
-	}
-	delete(msr.networks, network)
-
-	msr.index += 1
-
-	msr.networkEvents <- event{
-		Event{
-			Type:    EventRemoved,
-			Network: network,
-		}, msr.index,
-	}
-
-	return nil
-}
-
-func (n *netwk) findSubnet(sn ip.IP4Net) (Lease, int, error) {
-	for i, sub := range n.subnets {
-		if sub.Subnet.Equal(sn) {
-			return sub, i, nil
-		}
-	}
-	return Lease{}, 0, fmt.Errorf("subnet not found")
-}
-
-func (msr *MockSubnetRegistry) createBackendData(ctx context.Context, network, data string) error {
-	n, ok := msr.networks[network]
-	if !ok {
-		return fmt.Errorf("network %s not found", network)
-	}
-
-	if n.backendData == "" {
-		n.backendData = data
-	}
-
-	return nil
-}
-
-func (msr *MockSubnetRegistry) getBackendData(ctx context.Context, network string) (string, error) {
-	n, ok := msr.networks[network]
-	if !ok {
-		return "", fmt.Errorf("network %s not found", network)
-	}
-
-	if n.backendData == "" {
-		return "", fmt.Errorf("backendData not set for %s network", network)
-	}
-
-	return n.backendData, nil
-}

+ 0 - 444
subnet/registry.go

@@ -1,444 +0,0 @@
-// Copyright 2015 flannel authors
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//     http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package subnet
-
-import (
-	"encoding/json"
-	"errors"
-	"fmt"
-	"path"
-	"regexp"
-	"sync"
-	"time"
-
-	etcd "github.com/coreos/etcd/client"
-	"github.com/coreos/etcd/pkg/transport"
-	log "github.com/golang/glog"
-	"golang.org/x/net/context"
-
-	"github.com/coreos/flannel/pkg/ip"
-)
-
-var (
-	subnetRegex *regexp.Regexp = regexp.MustCompile(`(\d+\.\d+.\d+.\d+)-(\d+)`)
-	errTryAgain                = errors.New("try again")
-)
-
-type Registry interface {
-	getNetworkConfig(ctx context.Context, network string) (string, error)
-	getSubnets(ctx context.Context, network string) ([]Lease, uint64, error)
-	getSubnet(ctx context.Context, network string, sn ip.IP4Net) (*Lease, uint64, error)
-	createSubnet(ctx context.Context, network string, sn ip.IP4Net, attrs *LeaseAttrs, ttl time.Duration) (time.Time, error)
-	updateSubnet(ctx context.Context, network string, sn ip.IP4Net, attrs *LeaseAttrs, ttl time.Duration, asof uint64) (time.Time, error)
-	deleteSubnet(ctx context.Context, network string, sn ip.IP4Net) error
-	watchSubnets(ctx context.Context, network string, since uint64) (Event, uint64, error)
-	watchSubnet(ctx context.Context, network string, since uint64, sn ip.IP4Net) (Event, uint64, error)
-	getNetworks(ctx context.Context) ([]string, uint64, error)
-	watchNetworks(ctx context.Context, since uint64) (Event, uint64, error)
-	createBackendData(ctx context.Context, network, data string) error
-	getBackendData(ctx context.Context, network string) (string, error)
-}
-
-type EtcdConfig struct {
-	Endpoints []string
-	Keyfile   string
-	Certfile  string
-	CAFile    string
-	Prefix    string
-	Username  string
-	Password  string
-}
-
-type etcdNewFunc func(c *EtcdConfig) (etcd.KeysAPI, error)
-
-type etcdSubnetRegistry struct {
-	cliNewFunc   etcdNewFunc
-	mux          sync.Mutex
-	cli          etcd.KeysAPI
-	etcdCfg      *EtcdConfig
-	networkRegex *regexp.Regexp
-}
-
-func newEtcdClient(c *EtcdConfig) (etcd.KeysAPI, error) {
-	tlsInfo := transport.TLSInfo{
-		CertFile: c.Certfile,
-		KeyFile:  c.Keyfile,
-		CAFile:   c.CAFile,
-	}
-
-	t, err := transport.NewTransport(tlsInfo, time.Second)
-	if err != nil {
-		return nil, err
-	}
-
-	cli, err := etcd.New(etcd.Config{
-		Endpoints: c.Endpoints,
-		Transport: t,
-		Username:  c.Username,
-		Password:  c.Password,
-	})
-	if err != nil {
-		return nil, err
-	}
-
-	return etcd.NewKeysAPI(cli), nil
-}
-
-func newEtcdSubnetRegistry(config *EtcdConfig, cliNewFunc etcdNewFunc) (Registry, error) {
-	r := &etcdSubnetRegistry{
-		etcdCfg:      config,
-		networkRegex: regexp.MustCompile(config.Prefix + `/([^/]*)(/|/config)?$`),
-	}
-	if cliNewFunc != nil {
-		r.cliNewFunc = cliNewFunc
-	} else {
-		r.cliNewFunc = newEtcdClient
-	}
-
-	var err error
-	r.cli, err = r.cliNewFunc(config)
-	if err != nil {
-		return nil, err
-	}
-
-	return r, nil
-}
-
-func (esr *etcdSubnetRegistry) getNetworkConfig(ctx context.Context, network string) (string, error) {
-	key := path.Join(esr.etcdCfg.Prefix, network, "config")
-	resp, err := esr.client().Get(ctx, key, &etcd.GetOptions{Quorum: true})
-	if err != nil {
-		return "", err
-	}
-	return resp.Node.Value, nil
-}
-
-// getSubnets queries etcd to get a list of currently allocated leases for a given network.
-// It returns the leases along with the "as-of" etcd-index that can be used as the starting
-// point for etcd watch.
-func (esr *etcdSubnetRegistry) getSubnets(ctx context.Context, network string) ([]Lease, uint64, error) {
-	key := path.Join(esr.etcdCfg.Prefix, network, "subnets")
-	resp, err := esr.client().Get(ctx, key, &etcd.GetOptions{Recursive: true, Quorum: true})
-	if err != nil {
-		if etcdErr, ok := err.(etcd.Error); ok && etcdErr.Code == etcd.ErrorCodeKeyNotFound {
-			// key not found: treat it as empty set
-			return []Lease{}, etcdErr.Index, nil
-		}
-		return nil, 0, err
-	}
-
-	leases := []Lease{}
-	for _, node := range resp.Node.Nodes {
-		l, err := nodeToLease(node)
-		if err != nil {
-			log.Warningf("Ignoring bad subnet node: %v", err)
-			continue
-		}
-
-		leases = append(leases, *l)
-	}
-
-	return leases, resp.Index, nil
-}
-
-func (esr *etcdSubnetRegistry) getSubnet(ctx context.Context, network string, sn ip.IP4Net) (*Lease, uint64, error) {
-	key := path.Join(esr.etcdCfg.Prefix, network, "subnets", MakeSubnetKey(sn))
-	resp, err := esr.client().Get(ctx, key, &etcd.GetOptions{Quorum: true})
-	if err != nil {
-		return nil, 0, err
-	}
-
-	l, err := nodeToLease(resp.Node)
-	return l, resp.Index, err
-}
-
-func (esr *etcdSubnetRegistry) createSubnet(ctx context.Context, network string, sn ip.IP4Net, attrs *LeaseAttrs, ttl time.Duration) (time.Time, error) {
-	key := path.Join(esr.etcdCfg.Prefix, network, "subnets", MakeSubnetKey(sn))
-	value, err := json.Marshal(attrs)
-	if err != nil {
-		return time.Time{}, err
-	}
-
-	opts := &etcd.SetOptions{
-		PrevExist: etcd.PrevNoExist,
-		TTL:       ttl,
-	}
-
-	resp, err := esr.client().Set(ctx, key, string(value), opts)
-	if err != nil {
-		return time.Time{}, err
-	}
-
-	exp := time.Time{}
-	if resp.Node.Expiration != nil {
-		exp = *resp.Node.Expiration
-	}
-
-	return exp, nil
-}
-
-func (esr *etcdSubnetRegistry) updateSubnet(ctx context.Context, network string, sn ip.IP4Net, attrs *LeaseAttrs, ttl time.Duration, asof uint64) (time.Time, error) {
-	key := path.Join(esr.etcdCfg.Prefix, network, "subnets", MakeSubnetKey(sn))
-	value, err := json.Marshal(attrs)
-	if err != nil {
-		return time.Time{}, err
-	}
-
-	resp, err := esr.client().Set(ctx, key, string(value), &etcd.SetOptions{
-		PrevIndex: asof,
-		TTL:       ttl,
-	})
-	if err != nil {
-		return time.Time{}, err
-	}
-
-	exp := time.Time{}
-	if resp.Node.Expiration != nil {
-		exp = *resp.Node.Expiration
-	}
-
-	return exp, nil
-}
-
-func (esr *etcdSubnetRegistry) deleteSubnet(ctx context.Context, network string, sn ip.IP4Net) error {
-	key := path.Join(esr.etcdCfg.Prefix, network, "subnets", MakeSubnetKey(sn))
-	_, err := esr.client().Delete(ctx, key, nil)
-	return err
-}
-
-func (esr *etcdSubnetRegistry) watchSubnets(ctx context.Context, network string, since uint64) (Event, uint64, error) {
-	key := path.Join(esr.etcdCfg.Prefix, network, "subnets")
-	opts := &etcd.WatcherOptions{
-		AfterIndex: since,
-		Recursive:  true,
-	}
-	e, err := esr.client().Watcher(key, opts).Next(ctx)
-	if err != nil {
-		return Event{}, 0, err
-	}
-
-	evt, err := parseSubnetWatchResponse(e)
-	return evt, e.Node.ModifiedIndex, err
-}
-
-func (esr *etcdSubnetRegistry) watchSubnet(ctx context.Context, network string, since uint64, sn ip.IP4Net) (Event, uint64, error) {
-	key := path.Join(esr.etcdCfg.Prefix, network, "subnets", MakeSubnetKey(sn))
-	opts := &etcd.WatcherOptions{
-		AfterIndex: since,
-	}
-
-	e, err := esr.client().Watcher(key, opts).Next(ctx)
-	if err != nil {
-		return Event{}, 0, err
-	}
-
-	evt, err := parseSubnetWatchResponse(e)
-	return evt, e.Node.ModifiedIndex, err
-}
-
-// getNetworks queries etcd to get a list of network names.  It returns the
-// networks along with the 'as-of' etcd-index that can be used as the starting
-// point for etcd watch.
-func (esr *etcdSubnetRegistry) getNetworks(ctx context.Context) ([]string, uint64, error) {
-	resp, err := esr.client().Get(ctx, esr.etcdCfg.Prefix, &etcd.GetOptions{Recursive: true, Quorum: true})
-
-	networks := []string{}
-
-	if err == nil {
-		for _, node := range resp.Node.Nodes {
-			// Look for '/config' on the child nodes
-			for _, child := range node.Nodes {
-				netname, isConfig := esr.parseNetworkKey(child.Key)
-				if isConfig {
-					networks = append(networks, netname)
-				}
-			}
-		}
-
-		return networks, resp.Index, nil
-	}
-
-	if etcdErr, ok := err.(etcd.Error); ok && etcdErr.Code == etcd.ErrorCodeKeyNotFound {
-		// key not found: treat it as empty set
-		return networks, etcdErr.Index, nil
-	}
-
-	return nil, 0, err
-}
-
-func (esr *etcdSubnetRegistry) watchNetworks(ctx context.Context, since uint64) (Event, uint64, error) {
-	key := esr.etcdCfg.Prefix
-	opts := &etcd.WatcherOptions{
-		AfterIndex: since,
-		Recursive:  true,
-	}
-	e, err := esr.client().Watcher(key, opts).Next(ctx)
-	if err != nil {
-		return Event{}, 0, err
-	}
-
-	return esr.parseNetworkWatchResponse(e)
-}
-
-func (esr *etcdSubnetRegistry) client() etcd.KeysAPI {
-	esr.mux.Lock()
-	defer esr.mux.Unlock()
-	return esr.cli
-}
-
-func (esr *etcdSubnetRegistry) resetClient() {
-	esr.mux.Lock()
-	defer esr.mux.Unlock()
-
-	var err error
-	esr.cli, err = newEtcdClient(esr.etcdCfg)
-	if err != nil {
-		panic(fmt.Errorf("resetClient: error recreating etcd client: %v", err))
-	}
-}
-
-func parseSubnetWatchResponse(resp *etcd.Response) (Event, error) {
-	sn := ParseSubnetKey(resp.Node.Key)
-	if sn == nil {
-		return Event{}, fmt.Errorf("%v %q: not a subnet, skipping", resp.Action, resp.Node.Key)
-	}
-
-	switch resp.Action {
-	case "delete", "expire":
-		return Event{
-			EventRemoved,
-			Lease{Subnet: *sn},
-			"",
-		}, nil
-
-	default:
-		attrs := &LeaseAttrs{}
-		err := json.Unmarshal([]byte(resp.Node.Value), attrs)
-		if err != nil {
-			return Event{}, err
-		}
-
-		exp := time.Time{}
-		if resp.Node.Expiration != nil {
-			exp = *resp.Node.Expiration
-		}
-
-		evt := Event{
-			EventAdded,
-			Lease{
-				Subnet:     *sn,
-				Attrs:      *attrs,
-				Expiration: exp,
-			},
-			"",
-		}
-		return evt, nil
-	}
-}
-
-func (esr *etcdSubnetRegistry) parseNetworkWatchResponse(resp *etcd.Response) (Event, uint64, error) {
-	index := resp.Node.ModifiedIndex
-	netname, isConfig := esr.parseNetworkKey(resp.Node.Key)
-	if netname == "" {
-		return Event{}, index, errTryAgain
-	}
-
-	evt := Event{}
-
-	switch resp.Action {
-	case "delete":
-		evt = Event{
-			EventRemoved,
-			Lease{},
-			netname,
-		}
-
-	default:
-		if !isConfig {
-			// Ignore non .../<netname>/config keys; tell caller to try again
-			return Event{}, index, errTryAgain
-		}
-
-		_, err := ParseConfig(resp.Node.Value)
-		if err != nil {
-			return Event{}, index, err
-		}
-
-		evt = Event{
-			EventAdded,
-			Lease{},
-			netname,
-		}
-	}
-
-	return evt, index, nil
-}
-
-// Returns network name from config key (eg, /coreos.com/network/foobar/config),
-// if the 'config' key isn't present we don't consider the network valid
-func (esr *etcdSubnetRegistry) parseNetworkKey(s string) (string, bool) {
-	if parts := esr.networkRegex.FindStringSubmatch(s); len(parts) == 3 {
-		return parts[1], parts[2] != ""
-	}
-
-	return "", false
-}
-
-func nodeToLease(node *etcd.Node) (*Lease, error) {
-	sn := ParseSubnetKey(node.Key)
-	if sn == nil {
-		return nil, fmt.Errorf("failed to parse subnet key %q", *sn)
-	}
-
-	attrs := &LeaseAttrs{}
-	if err := json.Unmarshal([]byte(node.Value), attrs); err != nil {
-		return nil, err
-	}
-
-	exp := time.Time{}
-	if node.Expiration != nil {
-		exp = *node.Expiration
-	}
-
-	lease := Lease{
-		Subnet:     *sn,
-		Attrs:      *attrs,
-		Expiration: exp,
-		asof:       node.ModifiedIndex,
-	}
-
-	return &lease, nil
-}
-
-func (esr *etcdSubnetRegistry) createBackendData(ctx context.Context, network, data string) error {
-	key := path.Join(esr.etcdCfg.Prefix, network, "backend-data")
-	_, err := esr.client().Create(ctx, key, data)
-	if err != nil {
-		return err
-	}
-
-	return nil
-}
-
-func (esr *etcdSubnetRegistry) getBackendData(ctx context.Context, network string) (string, error) {
-	key := path.Join(esr.etcdCfg.Prefix, network, "backend-data")
-	etcdResponse, err := esr.client().Get(ctx, key, nil)
-
-	if err != nil {
-		return "", err
-	}
-
-	return etcdResponse.Node.Value, nil
-}

+ 0 - 3
subnet/subnet.go

@@ -131,7 +131,4 @@ type Manager interface {
 	WatchLeases(ctx context.Context, cursor interface{}) (LeaseWatchResult, error)
 
 	Name() string
-
-	GetBackendData(ctx context.Context, network string) (string, error)
-	CreateBackendData(ctx context.Context, network, data string) error
 }

+ 20 - 0
vendor/github.com/bronze1man/goStrongswanVici/LICENSE

@@ -0,0 +1,20 @@
+The MIT License (MIT)
+
+Copyright (c) 2015 bronze1man
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of
+this software and associated documentation files (the "Software"), to deal in
+the Software without restriction, including without limitation the rights to
+use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
+the Software, and to permit persons to whom the Software is furnished to do so,
+subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

+ 79 - 0
vendor/github.com/bronze1man/goStrongswanVici/client.go

@@ -0,0 +1,79 @@
+package goStrongswanVici
+
+import (
+	"net"
+)
+
+type ClientOptions struct {
+	Network string
+	Addr    string
+	// Dialer creates new network connection and has priority over
+	// Network and Addr options.
+	Dialer func() (net.Conn, error)
+}
+
+type Client struct {
+	o ClientOptions
+}
+
+func NewClient(options ClientOptions) (client *Client) {
+	if options.Dialer == nil {
+		options.Dialer = func() (net.Conn, error) {
+			return net.Dial(options.Network, options.Addr)
+		}
+	}
+	return &Client{
+		o: options,
+	}
+}
+
+func NewClientFromDefaultSocket() (client *Client) {
+	return NewClient(ClientOptions{
+		Network: "unix",
+		Addr:    "/var/run/charon.vici",
+	})
+}
+
+func (c *Client) NewConn() (conn *ClientConn, err error) {
+	conn1, err := c.o.Dialer()
+	if err != nil {
+		return nil, err
+	}
+	return NewClientConn(conn1), nil
+}
+
+func (c *Client) ListSas(ike string, ike_id string) (sas []map[string]IkeSa, err error) {
+	conn, err := c.NewConn()
+	if err != nil {
+		return nil, err
+	}
+	defer conn.Close()
+	return conn.ListSas(ike, ike_id)
+}
+
+func (c *Client) ListAllVpnConnInfo() (list []VpnConnInfo, err error) {
+	conn, err := c.NewConn()
+	if err != nil {
+		return nil, err
+	}
+	defer conn.Close()
+	return conn.ListAllVpnConnInfo()
+}
+
+func (c *Client) Version() (out *Version, err error) {
+	conn, err := c.NewConn()
+	if err != nil {
+		return nil, err
+	}
+	defer conn.Close()
+	return conn.Version()
+}
+
+func (c *Client) Terminate(r *TerminateRequest) (err error) {
+	conn, err := c.NewConn()
+	if err != nil {
+		return err
+	}
+	defer conn.Close()
+	return conn.Terminate(r)
+}

+ 154 - 0
vendor/github.com/bronze1man/goStrongswanVici/clientConn.go

@@ -0,0 +1,154 @@
+package goStrongswanVici
+
+import (
+	"fmt"
+	"io"
+	"net"
+	"time"
+)
+
+const (
+	DefaultReadTimeout = 15 * time.Second
+)
+
+// This object is not thread safe.
+// if you want concurrent, you need create more clients.
+type ClientConn struct {
+	conn          net.Conn
+	responseChan  chan segment
+	eventHandlers map[string]func(response map[string]interface{})
+	lastError     error
+
+	// ReadTimeout specifies a time limit for requests made
+	// by this client.
+	ReadTimeout time.Duration
+}
+
+func (c *ClientConn) Close() error {
+	close(c.responseChan)
+	c.lastError = io.ErrClosedPipe
+	return c.conn.Close()
+}
+
+func NewClientConn(conn net.Conn) (client *ClientConn) {
+	client = &ClientConn{
+		conn:          conn,
+		responseChan:  make(chan segment, 2),
+		eventHandlers: map[string]func(response map[string]interface{}){},
+		ReadTimeout:   DefaultReadTimeout,
+	}
+	go client.readThread()
+	return client
+}
+
+// it dial from unix:///var/run/charon.vici
+func NewClientConnFromDefaultSocket() (client *ClientConn, err error) {
+	conn, err := net.Dial("unix", "/var/run/charon.vici")
+	if err != nil {
+		return
+	}
+	return NewClientConn(conn), nil
+}
+
+func (c *ClientConn) Request(apiname string, request map[string]interface{}) (response map[string]interface{}, err error) {
+	err = writeSegment(c.conn, segment{
+		typ:  stCMD_REQUEST,
+		name: apiname,
+		msg:  request,
+	})
+	if err != nil {
+		fmt.Printf("error writing segment \n")
+		return
+	}
+
+	outMsg := c.readResponse()
+	if c.lastError != nil {
+		return nil, c.lastError
+	}
+	if outMsg.typ != stCMD_RESPONSE {
+		return nil, fmt.Errorf("[%s] response error %d", apiname, outMsg.typ)
+	}
+	return outMsg.msg, nil
+}
+
+func (c *ClientConn) readResponse() segment {
+	select {
+	case outMsg := <-c.responseChan:
+		return outMsg
+	case <-time.After(c.ReadTimeout):
+		if c.lastError == nil {
+			c.lastError = fmt.Errorf("Timeout waiting for message response")
+		}
+		return segment{}
+	}
+}
+
+func (c *ClientConn) RegisterEvent(name string, handler func(response map[string]interface{})) (err error) {
+	if c.eventHandlers[name] != nil {
+		return fmt.Errorf("[event %s] register a event twice.", name)
+	}
+	c.eventHandlers[name] = handler
+	err = writeSegment(c.conn, segment{
+		typ:  stEVENT_REGISTER,
+		name: name,
+	})
+	if err != nil {
+		delete(c.eventHandlers, name)
+		return
+	}
+	outMsg := c.readResponse()
+	//fmt.Printf("registerEvent %#v\n", outMsg)
+	if c.lastError != nil {
+		delete(c.eventHandlers, name)
+		return c.lastError
+	}
+
+	if outMsg.typ != stEVENT_CONFIRM {
+		delete(c.eventHandlers, name)
+		return fmt.Errorf("[event %s] response error %d", name, outMsg.typ)
+	}
+	return nil
+}
+
+func (c *ClientConn) UnregisterEvent(name string) (err error) {
+	err = writeSegment(c.conn, segment{
+		typ:  stEVENT_UNREGISTER,
+		name: name,
+	})
+	if err != nil {
+		return
+	}
+	outMsg := c.readResponse()
+	//fmt.Printf("UnregisterEvent %#v\n", outMsg)
+	if c.lastError != nil {
+		return c.lastError
+	}
+
+	if outMsg.typ != stEVENT_CONFIRM {
+		return fmt.Errorf("[event %s] response error %d", name, outMsg.typ)
+	}
+	delete(c.eventHandlers, name)
+	return nil
+}
+
+func (c *ClientConn) readThread() {
+	for {
+		outMsg, err := readSegment(c.conn)
+		if err != nil {
+			c.lastError = err
+			return
+		}
+		switch outMsg.typ {
+		case stCMD_RESPONSE, stEVENT_CONFIRM:
+			c.responseChan <- outMsg
+		case stEVENT:
+			handler := c.eventHandlers[outMsg.name]
+			if handler != nil {
+				handler(outMsg.msg)
+			}
+		default:
+			c.lastError = fmt.Errorf("[Client.readThread] unknow msg type %d", outMsg.typ)
+			return
+		}
+	}
+}

+ 5 - 0
vendor/github.com/bronze1man/goStrongswanVici/doc.go

@@ -0,0 +1,5 @@
+/*
+a golang implement of strongswan vici plugin client.
+https://github.com/strongswan/strongswan/tree/master/src/libcharon/plugins/vici
+*/
+package goStrongswanVici

+ 24 - 0
vendor/github.com/bronze1man/goStrongswanVici/err.go

@@ -0,0 +1,24 @@
+package goStrongswanVici
+
+import (
+	"fmt"
+)
+
+func handlePanic(f func() error) (err error) {
+	defer func() {
+		r := recover()
+		//no panic
+		if r == nil {
+			return
+		}
+		//panic a error
+		if e, ok := r.(error); ok {
+			err = e
+			return
+		}
+		//panic another stuff
+		err = fmt.Errorf("%s", r)
+	}()
+	err = f()
+	return
+}

+ 47 - 0
vendor/github.com/bronze1man/goStrongswanVici/listConns.go

@@ -0,0 +1,47 @@
+package goStrongswanVici
+
+import (
+	"fmt"
+)
+
+func (c *ClientConn) ListConns(ike string) ([]map[string]IKEConf, error) {
+	conns := []map[string]IKEConf{}
+	var eventErr error
+	var err error
+
+	err = c.RegisterEvent("list-conn", func(response map[string]interface{}) {
+		conn := &map[string]IKEConf{}
+		err = ConvertFromGeneral(response, conn)
+		if err != nil {
+			eventErr = fmt.Errorf("list-conn event error: %v", err)
+			return
+		}
+		conns = append(conns, *conn)
+	})
+
+	if err != nil {
+		return nil, fmt.Errorf("error registering list-conn event: %v", err)
+	}
+
+	if eventErr != nil {
+		return nil, eventErr
+	}
+
+	reqMap := map[string]interface{}{}
+
+	if ike != "" {
+		reqMap["ike"] = ike
+	}
+
+	_, err = c.Request("list-conns", reqMap)
+	if err != nil {
+		return nil, fmt.Errorf("error requesting list-conns: %v", err)
+	}
+
+	err = c.UnregisterEvent("list-conn")
+	if err != nil {
+		return nil, fmt.Errorf("error unregistering list-conns event: %v", err)
+	}
+
+	return conns, nil
+}

+ 174 - 0
vendor/github.com/bronze1man/goStrongswanVici/listSas.go

@@ -0,0 +1,174 @@
+package goStrongswanVici
+
+import (
+	"fmt"
+	"strconv"
+)
+
+//from list-sa event
+type IkeSa struct {
+	Uniqueid        string               `json:"uniqueid"` //called ike_id in terminate() argument.
+	Version         string               `json:"version"`
+	State           string               `json:"state"` //had saw: ESTABLISHED
+	Local_host      string               `json:"local-host"`
+	Local_id        string               `json:"local-id"`
+	Remote_host     string               `json:"remote-host"`
+	Remote_id       string               `json:"remote-id"`
+	Remote_xauth_id string               `json:"remote-xauth-id"` //client username
+	Initiator       string               `json:"initiator"`
+	Initiator_spi   string               `json:"initiator-spi"`
+	Responder_spi   string               `json:"responder-spi"`
+	Encr_alg        string               `json:"encr-alg"`
+	Encr_keysize    string               `json:"encr-keysize"`
+	Integ_alg       string               `json:"integ-alg"`
+	Integ_keysize   string               `json:"integ-keysize"`
+	Prf_alg         string               `json:"prf-alg"`
+	Dh_group        string               `json:"dh-group"`
+	Established     string               `json:"established"`
+	Rekey_time      string               `json:"rekey-time"`
+	Reauth_time     string               `json:"reauth-time"`
+	Remote_vips     []string             `json:"remote-vips"`
+	Child_sas       map[string]Child_sas `json:"child-sas"` //key means child-sa-name(conn name in ipsec.conf)
+}
+
+type Child_sas struct {
+	Reqid         string   `json:"reqid"`
+	State         string   `json:"state"` //had saw: INSTALLED
+	Mode          string   `json:"mode"`  //had saw: TUNNEL
+	Protocol      string   `json:"protocol"`
+	Encap         string   `json:"encap"`
+	Spi_in        string   `json:"spi-in"`
+	Spi_out       string   `json:"spi-out"`
+	Cpi_in        string   `json:"cpi-in"`
+	Cpi_out       string   `json:"cpi-out"`
+	Encr_alg      string   `json:"encr-alg"`
+	Encr_keysize  string   `json:"encr-keysize"`
+	Integ_alg     string   `json:"integ-alg"`
+	Integ_keysize string   `json:"integ-keysize"`
+	Prf_alg       string   `json:"prf-alg"`
+	Dh_group      string   `json:"dh-group"`
+	Esn           string   `json:"esn"`
+	Bytes_in      string   `json:"bytes-in"` //bytes into this machine
+	Packets_in    string   `json:"packets-in"`
+	Use_in        string   `json:"use-in"`
+	Bytes_out     string   `json:"bytes-out"` // bytes out of this machine
+	Packets_out   string   `json:"packets-out"`
+	Use_out       string   `json:"use-out"`
+	Rekey_time    string   `json:"rekey-time"`
+	Life_time     string   `json:"life-time"`
+	Install_time  string   `json:"install-time"`
+	Local_ts      []string `json:"local-ts"`
+	Remote_ts     []string `json:"remote-ts"`
+}
+
+func (s *Child_sas) GetBytesIn() uint64 {
+	num, err := strconv.ParseUint(s.Bytes_in, 10, 64)
+	if err != nil {
+		return 0
+	}
+	return num
+}
+
+func (s *Child_sas) GetBytesOut() uint64 {
+	num, err := strconv.ParseUint(s.Bytes_out, 10, 64)
+	if err != nil {
+		return 0
+	}
+	return num
+}
+
+// To be simple, list all clients that are connecting to this server .
+// A client is a sa.
+// Lists currently active IKE_SAs
+func (c *ClientConn) ListSas(ike string, ike_id string) (sas []map[string]IkeSa, err error) {
+	sas = []map[string]IkeSa{}
+	var eventErr error
+	//register event
+	err = c.RegisterEvent("list-sa", func(response map[string]interface{}) {
+		sa := &map[string]IkeSa{}
+		err = ConvertFromGeneral(response, sa)
+		if err != nil {
+			fmt.Printf("list-sa event error: %s\n", err)
+			eventErr = err
+			return
+		}
+		sas = append(sas, *sa)
+		//fmt.Printf("event %#v\n", response)
+	})
+	if err != nil {
+		return
+	}
+	if eventErr != nil {
+		return
+	}
+
+	inMap := map[string]interface{}{}
+	if ike != "" {
+		inMap["ike"] = ike
+	}
+	if ike_id != "" {
+		inMap["ike_id"] = ike_id
+	}
+	_, err = c.Request("list-sas", inMap)
+	if err != nil {
+		return
+	}
+	//fmt.Printf("request finish %#v\n", sas)
+	err = c.UnregisterEvent("list-sa")
+	if err != nil {
+		return
+	}
+	return
+}
+
+//a vpn conn in the strongswan server
+type VpnConnInfo struct {
+	IkeSa
+	Child_sas
+	IkeSaName   string //looks like conn name in ipsec.conf, content is same as ChildSaName
+	ChildSaName string //looks like conn name in ipsec.conf
+}
+
+func (c *VpnConnInfo) GuessUserName() string {
+	if c.Remote_xauth_id != "" {
+		return c.Remote_xauth_id
+	}
+	if c.Remote_id != "" {
+		return c.Remote_id
+	}
+	return ""
+}
+
+// a helper method to avoid complex data struct in ListSas
+// if it only have one child_sas ,it will put it into info.Child_sas
+func (c *ClientConn) ListAllVpnConnInfo() (list []VpnConnInfo, err error) {
+	sasList, err := c.ListSas("", "")
+	if err != nil {
+		return
+	}
+	list = make([]VpnConnInfo, len(sasList))
+	for i, sa := range sasList {
+		info := VpnConnInfo{}
+		if len(sa) != 1 {
+			fmt.Printf("[vici.ListAllVpnConnInfo] warning: len(sa)[%d]!=1\n", len(sa))
+		}
+		for ikeSaName, ikeSa := range sa {
+			info.IkeSaName = ikeSaName
+			info.IkeSa = ikeSa
+			//if len(ikeSa.Child_sas) != 1 {
+			//	fmt.Println("[vici.ListAllVpnConnInfo] warning: len(ikeSa.Child_sas)[%d]!=1", len(ikeSa.Child_sas))
+			//}
+			for childSaName, childSa := range ikeSa.Child_sas {
+				info.ChildSaName = childSaName
+				info.Child_sas = childSa
+				break
+			}
+			break
+		}
+		if len(info.IkeSa.Child_sas) == 1 {
+			info.IkeSa.Child_sas = nil
+		}
+		list[i] = info
+	}
+	return
+}

+ 37 - 0
vendor/github.com/bronze1man/goStrongswanVici/loadCert.go

@@ -0,0 +1,37 @@
+package goStrongswanVici
+
+import (
+	"fmt"
+)
+
+type certPayload struct {
+	Typ  string `json:"type"` // (X509|X509_AC|X509_CRL)
+	Flag string `json:"flag"` // (CA|AA|OCSP|NONE)
+	Data string `json:"data"`
+}
+
+func (c *ClientConn) LoadCertificate(s string, typ string, flag string) (err error) {
+	requestMap := &map[string]interface{}{}
+
+	var k = certPayload{
+		Typ:  typ,
+		Flag: flag,
+		Data: s,
+	}
+
+	if err = ConvertToGeneral(k, requestMap); err != nil {
+		return fmt.Errorf("error creating request: %v", err)
+	}
+
+	msg, err := c.Request("load-cert", *requestMap)
+
+	if err != nil {
+		return fmt.Errorf("unsuccessful loadCert: %v", err.Error())
+	}
+
+	if msg["success"] != "yes" {
+		return fmt.Errorf("unsuccessful loadCert: %v", msg["success"])
+	}
+
+	return nil
+}

+ 66 - 0
vendor/github.com/bronze1man/goStrongswanVici/loadConn.go

@@ -0,0 +1,66 @@
+package goStrongswanVici
+
+import (
+	"fmt"
+)
+
+type Connection struct {
+	ConnConf map[string]IKEConf `json:"connections"`
+}
+
+type IKEConf struct {
+	LocalAddrs  []string               `json:"local_addrs"`
+	RemoteAddrs []string               `json:"remote_addrs,omitempty"`
+	Proposals   []string               `json:"proposals,omitempty"`
+	Version     string                 `json:"version"` //1 for ikev1, 0 for ikev1 & ikev2
+	Encap       string                 `json:"encap"`   //yes,no
+	KeyingTries string                 `json:"keyingtries"`
+	RekeyTime   string                 `json:"rekey_time"`
+	DPDDelay    string                 `json:"dpd_delay,omitempty"`
+	LocalAuth   AuthConf               `json:"local"`
+	RemoteAuth  AuthConf               `json:"remote"`
+	Pools       []string               `json:"pools,omitempty"`
+	Children    map[string]ChildSAConf `json:"children"`
+}
+
+type AuthConf struct {
+	ID         string `json:"id"`
+	Round      string `json:"round,omitempty"`
+	AuthMethod string `json:"auth"` // (psk|pubkey)
+	EAP_ID     string `json:"eap_id,omitempty"`
+}
+
+type ChildSAConf struct {
+	Local_ts      []string `json:"local_ts"`
+	Remote_ts     []string `json:"remote_ts"`
+	ESPProposals  []string `json:"esp_proposals,omitempty"` //aes128-sha1_modp1024
+	StartAction   string   `json:"start_action"`            //none,trap,start
+	CloseAction   string   `json:"close_action"`
+	ReqID         string   `json:"reqid"`
+	RekeyTime     string   `json:"rekey_time"`
+	ReplayWindow  string   `json:"replay_window,omitempty"`
+	Mode          string   `json:"mode"`
+	InstallPolicy string   `json:"policies"`
+	UpDown        string   `json:"updown,omitempty"`
+	Priority      string   `json:"priority,omitempty"`
+	MarkIn        string   `json:"mark_in,omitempty"`
+	MarkOut       string   `json:"mark_out,omitempty"`
+}
+
+func (c *ClientConn) LoadConn(conn *map[string]IKEConf) error {
+	requestMap := &map[string]interface{}{}
+
+	err := ConvertToGeneral(conn, requestMap)
+
+	if err != nil {
+		return fmt.Errorf("error creating request: %v", err)
+	}
+
+	msg, err := c.Request("load-conn", *requestMap)
+
+	if msg["success"] != "yes" {
+		return fmt.Errorf("unsuccessful LoadConn: %v", msg["errmsg"])
+	}
+
+	return nil
+}

+ 66 - 0
vendor/github.com/bronze1man/goStrongswanVici/loadPrivateKey.go

@@ -0,0 +1,66 @@
+package goStrongswanVici
+
+import (
+	"crypto/ecdsa"
+	"crypto/rsa"
+	"crypto/x509"
+	"encoding/pem"
+	"fmt"
+)
+
+type keyPayload struct {
+	Typ  string `json:"type"`
+	Data string `json:"data"`
+}
+
+// LoadECDSAPrivateKey encodes a *ecdsa.PrivateKey as a PEM block before sending
+// it to the Vici interface
+func (c *ClientConn) LoadECDSAPrivateKey(key *ecdsa.PrivateKey) error {
+	mk, err := x509.MarshalECPrivateKey(key)
+
+	if err != nil {
+		return err
+	}
+
+	var pemData = pem.EncodeToMemory(&pem.Block{
+		Type:  "ECDSA PRIVATE KEY",
+		Bytes: mk,
+	})
+
+	return c.loadPrivateKey("ECDSA", string(pemData))
+}
+
+// LoadRSAPrivateKey encodes a *rsa.PrivateKey as a PEM block before sending
+// it to the Vici interface
+func (c *ClientConn) LoadRSAPrivateKey(key *rsa.PrivateKey) error {
+	var mk = x509.MarshalPKCS1PrivateKey(key)
+
+	var pemData = pem.EncodeToMemory(&pem.Block{
+		Type:  "RSA PRIVATE KEY",
+		Bytes: mk,
+	})
+
+	return c.loadPrivateKey("RSA", string(pemData))
+}
+
+// loadPrivateKey expects typ to be (RSA|ECDSA) and a PEM encoded data as a
+// string
+func (c *ClientConn) loadPrivateKey(typ, data string) (err error) {
+	requestMap := &map[string]interface{}{}
+
+	var k = keyPayload{
+		Typ:  typ,
+		Data: data,
+	}
+
+	if err = ConvertToGeneral(k, requestMap); err != nil {
+		return fmt.Errorf("error creating request: %v", err)
+	}
+
+	msg, err := c.Request("load-key", *requestMap)
+	if msg["success"] != "yes" {
+		return fmt.Errorf("unsuccessful loadPrivateKey: %v", msg["success"])
+	}
+
+	return nil
+}

+ 29 - 0
vendor/github.com/bronze1man/goStrongswanVici/marshal.go

@@ -0,0 +1,29 @@
+package goStrongswanVici
+
+import (
+	"encoding/json"
+)
+
+//concrete data type to general data type
+// concrete data type like *Version
+// general data type include map[string]interface{} []string string
+// TODO make it faster
+func ConvertToGeneral(concrete interface{}, general interface{}) (err error) {
+	b, err := json.Marshal(concrete)
+	if err != nil {
+		return
+	}
+	return json.Unmarshal(b, general)
+}
+
+// general data type to concrete data type
+// concrete data type like *Version
+// general data type include map[string]interface{} []string string
+// TODO make it faster
+func ConvertFromGeneral(general interface{}, concrete interface{}) (err error) {
+	b, err := json.Marshal(general)
+	if err != nil {
+		return
+	}
+	return json.Unmarshal(b, concrete)
+}

+ 359 - 0
vendor/github.com/bronze1man/goStrongswanVici/msg.go

@@ -0,0 +1,359 @@
+package goStrongswanVici
+
+import (
+	"bufio"
+	"bytes"
+	"encoding/binary"
+	"fmt"
+	"io"
+	"strconv"
+)
+
+type segmentType byte
+
+const (
+	stCMD_REQUEST      segmentType = 0
+	stCMD_RESPONSE                 = 1
+	stCMD_UNKNOWN                  = 2
+	stEVENT_REGISTER               = 3
+	stEVENT_UNREGISTER             = 4
+	stEVENT_CONFIRM                = 5
+	stEVENT_UNKNOWN                = 6
+	stEVENT                        = 7
+)
+
+func (t segmentType) hasName() bool {
+	switch t {
+	case stCMD_REQUEST, stEVENT_REGISTER, stEVENT_UNREGISTER, stEVENT:
+		return true
+	}
+	return false
+}
+func (t segmentType) isValid() bool {
+	switch t {
+	case stCMD_REQUEST, stCMD_RESPONSE, stCMD_UNKNOWN, stEVENT_REGISTER,
+		stEVENT_UNREGISTER, stEVENT_CONFIRM, stEVENT_UNKNOWN, stEVENT:
+		return true
+	}
+	return false
+}
+
+func (t segmentType) hasMsg() bool {
+	switch t {
+	case stCMD_REQUEST, stCMD_RESPONSE, stEVENT:
+		return true
+	}
+	return false
+}
+
+type elementType byte
+
+const (
+	etSECTION_START elementType = 1
+	etSECTION_END               = 2
+	etKEY_VALUE                 = 3
+	etLIST_START                = 4
+	etLIST_ITEM                 = 5
+	etLIST_END                  = 6
+)
+
+type segment struct {
+	typ  segmentType
+	name string
+	msg  map[string]interface{}
+}
+
+//msg 在内部以下列3种类型表示(降低复杂度)
+// string
+// map[string]interface{}
+// []string
+func writeSegment(w io.Writer, msg segment) (err error) {
+	if !msg.typ.isValid() {
+		return fmt.Errorf("[writeSegment] msg.typ %d not defined", msg.typ)
+	}
+	buf := &bytes.Buffer{}
+	buf.WriteByte(byte(msg.typ))
+	//name
+	if msg.typ.hasName() {
+		err = writeString1(buf, msg.name)
+		if err != nil {
+			fmt.Printf("error returned from writeString1i \n")
+			return
+		}
+	}
+
+	if msg.typ.hasMsg() {
+		err = writeMap(buf, msg.msg)
+		if err != nil {
+			fmt.Printf("error retruned from writeMap \n")
+			return
+		}
+	}
+
+	//写长度
+	err = binary.Write(w, binary.BigEndian, uint32(buf.Len()))
+	if err != nil {
+		fmt.Printf("[writeSegment] error writing to binary \n")
+		return
+	}
+
+	_, err = buf.WriteTo(w)
+	if err != nil {
+		fmt.Printf("[writeSegment] error writing to buffer \n")
+		return
+	}
+
+	return nil
+}
+
+func readSegment(inR io.Reader) (msg segment, err error) {
+	//长度
+	var length uint32
+	err = binary.Read(inR, binary.BigEndian, &length)
+	if err != nil {
+		return
+	}
+	r := bufio.NewReader(&io.LimitedReader{
+		R: inR,
+		N: int64(length),
+	})
+	//类型
+	c, err := r.ReadByte()
+	if err != nil {
+		return
+	}
+	msg.typ = segmentType(c)
+	if !msg.typ.isValid() {
+		return msg, fmt.Errorf("[readSegment] msg.typ %d not defined", msg.typ)
+	}
+	if msg.typ.hasName() {
+		msg.name, err = readString1(r)
+		if err != nil {
+			return
+		}
+	}
+	if msg.typ.hasMsg() {
+		msg.msg, err = readMap(r, true)
+		if err != nil {
+			return
+		}
+	}
+	return
+}
+
+//一个字节长度的字符串
+func writeString1(w *bytes.Buffer, s string) (err error) {
+	length := len(s)
+	if length > 255 {
+		return fmt.Errorf("[writeString1] length>255")
+	}
+	w.WriteByte(byte(length))
+	w.WriteString(s)
+	return
+}
+
+func readString1(r *bufio.Reader) (s string, err error) {
+	length, err := r.ReadByte()
+	if err != nil {
+		return
+	}
+	buf := make([]byte, length)
+	_, err = io.ReadFull(r, buf)
+	if err != nil {
+		return
+	}
+	return string(buf), nil
+}
+
+//两个字节长度的字符串
+func writeString2(w *bytes.Buffer, s string) (err error) {
+	length := len(s)
+	if length > 65535 {
+		return fmt.Errorf("[writeString2] length>65535")
+	}
+	binary.Write(w, binary.BigEndian, uint16(length))
+	w.WriteString(s)
+	return
+}
+
+func readString2(r io.Reader) (s string, err error) {
+	var length uint16
+	err = binary.Read(r, binary.BigEndian, &length)
+	if err != nil {
+		return
+	}
+	buf := make([]byte, length)
+	_, err = io.ReadFull(r, buf)
+	if err != nil {
+		return
+	}
+	return string(buf), nil
+}
+
+func writeKeyMap(w *bytes.Buffer, name string, msg map[string]interface{}) (err error) {
+	w.WriteByte(byte(etSECTION_START))
+	err = writeString1(w, name)
+	if err != nil {
+		return
+	}
+	writeMap(w, msg)
+	w.WriteByte(byte(etSECTION_END))
+	return nil
+}
+
+func writeKeyList(w *bytes.Buffer, name string, msg []string) (err error) {
+	w.WriteByte(byte(etLIST_START))
+	err = writeString1(w, name)
+	if err != nil {
+		return
+	}
+	for _, s := range msg {
+		w.WriteByte(byte(etLIST_ITEM))
+		err = writeString2(w, s)
+		if err != nil {
+			return
+		}
+	}
+	w.WriteByte(byte(etLIST_END))
+	return nil
+}
+
+func writeKeyString(w *bytes.Buffer, name string, msg string) (err error) {
+	w.WriteByte(byte(etKEY_VALUE))
+	err = writeString1(w, name)
+	if err != nil {
+		return
+	}
+	err = writeString2(w, msg)
+	return
+}
+
+func writeMap(w *bytes.Buffer, msg map[string]interface{}) (err error) {
+	for k, v := range msg {
+		switch t := v.(type) {
+		case map[string]interface{}:
+			writeKeyMap(w, k, t)
+		case []string:
+			writeKeyList(w, k, t)
+		case string:
+			writeKeyString(w, k, t)
+		case []interface{}:
+			str := make([]string, len(t))
+			for i := range t {
+				str[i] = t[i].(string)
+			}
+			writeKeyList(w, k, str)
+		default:
+			return fmt.Errorf("[writeMap] can not write type %T right now", msg)
+		}
+	}
+	return nil
+}
+
+//SECTION_START has been read already.
+func readKeyMap(r *bufio.Reader) (key string, msg map[string]interface{}, err error) {
+	key, err = readString1(r)
+	if err != nil {
+		return
+	}
+	msg, err = readMap(r, false)
+	return
+}
+
+//LIST_START has been read already.
+func readKeyList(r *bufio.Reader) (key string, msg []string, err error) {
+	key, err = readString1(r)
+	if err != nil {
+		return
+	}
+	msg = []string{}
+	for {
+		var c byte
+		c, err = r.ReadByte()
+		if err != nil {
+			return
+		}
+		switch elementType(c) {
+		case etLIST_ITEM:
+			value, err := readString2(r)
+			if err != nil {
+				return "", nil, err
+			}
+			msg = append(msg, value)
+		case etLIST_END: //end of outer list
+			return key, msg, nil
+		default:
+			return "", nil, fmt.Errorf("[readKeyList] protocol error 2")
+		}
+	}
+	return
+}
+
+//KEY_VALUE has been read already.
+func readKeyString(r *bufio.Reader) (key string, msg string, err error) {
+	key, err = readString1(r)
+	if err != nil {
+		return
+	}
+	msg, err = readString2(r)
+	if err != nil {
+		return
+	}
+	return
+}
+
+// Since the original key chosen can have duplicates,
+// this function is used to map the original key to a new one
+// to make them unique.
+func getNewKeyToHandleDuplicates(key string, msg map[string]interface{}) string {
+	if _, ok := msg[key]; !ok {
+		return key
+	}
+
+	for i := 0; ; i++ {
+		newKey := key + "##" + strconv.Itoa(i)
+		if _, ok := msg[newKey]; !ok {
+			return newKey
+		}
+	}
+}
+
+//SECTION_START has been read already.
+func readMap(r *bufio.Reader, isRoot bool) (msg map[string]interface{}, err error) {
+	msg = map[string]interface{}{}
+	for {
+		c, err := r.ReadByte()
+		if err == io.EOF && isRoot { //may be root section
+			return msg, nil
+		}
+		if err != nil {
+			return nil, err
+		}
+		switch elementType(c) {
+		case etSECTION_START:
+			key, value, err := readKeyMap(r)
+			if err != nil {
+				return nil, err
+			}
+			msg[getNewKeyToHandleDuplicates(key, msg)] = value
+		case etLIST_START:
+			key, value, err := readKeyList(r)
+			if err != nil {
+				return nil, err
+			}
+			msg[getNewKeyToHandleDuplicates(key, msg)] = value
+		case etKEY_VALUE:
+			key, value, err := readKeyString(r)
+			if err != nil {
+				return nil, err
+			}
+			msg[getNewKeyToHandleDuplicates(key, msg)] = value
+		case etSECTION_END: //end of outer section
+			return msg, nil
+		default:
+			panic(fmt.Errorf("[readMap] protocol error 1, %d %#v", c, msg))
+			//return nil, fmt.Errorf("[readMap] protocol error 1, %d",c)
+		}
+	}
+	return
+}

+ 36 - 0
vendor/github.com/bronze1man/goStrongswanVici/pools.go

@@ -0,0 +1,36 @@
+package goStrongswanVici
+
+import (
+	"fmt"
+)
+
+type Pool struct {
+	PoolMapping map[string]interface{} `json:"pools"`
+}
+
+type PoolMapping struct {
+	Addrs              string   `json:"addrs"`
+	DNS                []string `json:"dns,omitempty"`
+	NBNS               []string `json:"nbns,omitempty"`
+	ApplicationVersion []string `json:"7,omitempty"`
+	InternalIPv6Prefix []string `json:"18,omitempty"`
+}
+
+func (c *ClientConn) LoadPool(ph Pool) error {
+	requestMap := map[string]interface{}{}
+
+	err := ConvertToGeneral(ph.PoolMapping, &requestMap)
+
+	if err != nil {
+		fmt.Println(err)
+		return fmt.Errorf("error creating request: %v", err)
+	}
+
+	msg, err := c.Request("load-pool", requestMap)
+
+	if msg["success"] != "yes" {
+		return fmt.Errorf("unsuccessful LoadPool: %v", msg["success"])
+	}
+
+	return nil
+}

+ 76 - 0
vendor/github.com/bronze1man/goStrongswanVici/shared.go

@@ -0,0 +1,76 @@
+// this file contains the functions for managing shared secrets
+
+package goStrongswanVici
+
+import (
+	"fmt"
+)
+
+type Key struct {
+	ID     string   `json:"id,omitempty"`
+	Typ    string   `json:"type"`
+	Data   string   `json:"data"`
+	Owners []string `json:"owners"`
+}
+
+type UnloadKeyRequest struct {
+	ID string `json:"id"`
+}
+
+type keyList struct {
+	Keys []string `json:"keys"`
+}
+
+// load a shared secret into the IKE daemon
+func (c *ClientConn) LoadShared(key *Key) error {
+	requestMap := &map[string]interface{}{}
+
+	err := ConvertToGeneral(key, requestMap)
+
+	if err != nil {
+		return fmt.Errorf("error creating request: %v", err)
+	}
+
+	msg, err := c.Request("load-shared", *requestMap)
+	if msg["success"] != "yes" {
+		return fmt.Errorf("unsuccessful loadSharedKey: %v", msg["errmsg"])
+	}
+
+	return nil
+}
+
+// unload (delete) a shared secret from the IKE daemon
+func (c *ClientConn) UnloadShared(key *UnloadKeyRequest) error {
+	requestMap := &map[string]interface{}{}
+
+	err := ConvertToGeneral(key, requestMap)
+
+	if err != nil {
+		return fmt.Errorf("error creating request: %v", err)
+	}
+
+	msg, err := c.Request("unload-shared", *requestMap)
+	if msg["success"] != "yes" {
+		return fmt.Errorf("unsuccessful loadSharedKey: %v", msg["errmsg"])
+	}
+
+	return nil
+}
+
+// get a the names of the shared secrets currently loaded
+func (c *ClientConn) GetShared() ([]string, error) {
+	msg, err := c.Request("get-shared", nil)
+	if err != nil {
+		fmt.Errorf("Error making request: %v", err)
+		return nil, err
+	}
+
+	keys := &keyList{}
+
+	err = ConvertFromGeneral(msg, keys)
+	if err != nil {
+		fmt.Errorf("Error converting data: %v", err)
+	}
+
+	return keys.Keys, err
+}

+ 7 - 0
vendor/github.com/bronze1man/goStrongswanVici/stats.go

@@ -0,0 +1,7 @@
+package goStrongswanVici
+
+// Stats returns IKE daemon statistics and load information.
+func (c *ClientConn) Stats() (msg map[string]interface{}, err error) {
+	msg, err = c.Request("stats", nil)
+	return
+}

+ 32 - 0
vendor/github.com/bronze1man/goStrongswanVici/terminate.go

@@ -0,0 +1,32 @@
+package goStrongswanVici
+
+import (
+	"fmt"
+)
+
+type TerminateRequest struct {
+	Child    string `json:"child,omitempty"`
+	Ike      string `json:"ike,omitempty"`
+	Child_id string `json:"child-id,omitempty"`
+	Ike_id   string `json:"ike-id,omitempty"`
+	Timeout  string `json:"timeout,omitempty"`
+	Loglevel string `json:"loglevel,omitempty"`
+}
+
+// To be simple, kill a client that is connecting to this server. A client is a sa.
+//Terminates an SA while streaming control-log events.
+func (c *ClientConn) Terminate(r *TerminateRequest) (err error) {
+	err = handlePanic(func() (err error) {
+		reqMap := &map[string]interface{}{}
+		ConvertToGeneral(r, reqMap)
+		msg, err := c.Request("terminate", *reqMap)
+		if err != nil {
+			return
+		}
+		if msg["success"] != "yes" {
+			return fmt.Errorf("[Terminate] %s", msg["errmsg"])
+		}
+		return
+	})
+	return
+}

+ 24 - 0
vendor/github.com/bronze1man/goStrongswanVici/unloadConn.go

@@ -0,0 +1,24 @@
+package goStrongswanVici
+
+import (
+	"fmt"
+)
+
+type UnloadConnRequest struct {
+	Name string `json:"name"`
+}
+
+func (c *ClientConn) UnloadConn(r *UnloadConnRequest) error {
+	reqMap := &map[string]interface{}{}
+	ConvertToGeneral(r, reqMap)
+	msg, err := c.Request("unload-conn", *reqMap)
+	if err != nil {
+		return err
+	}
+
+	if msg["success"] != "yes" {
+		return fmt.Errorf("[Unload-Connection] %s", msg["errmsg"])
+	}
+
+	return nil
+}

+ 19 - 0
vendor/github.com/bronze1man/goStrongswanVici/version.go

@@ -0,0 +1,19 @@
+package goStrongswanVici
+
+type Version struct {
+	Daemon  string `json:"daemon"`
+	Version string `json:"version"`
+	Sysname string `json:"sysname"`
+	Release string `json:"release"`
+	Machine string `json:"machine"`
+}
+
+func (c *ClientConn) Version() (out *Version, err error) {
+	msg, err := c.Request("version", nil)
+	if err != nil {
+		return
+	}
+	out = &Version{}
+	err = ConvertFromGeneral(msg, out)
+	return
+}