Browse Source

feat(api): add REST endpoints for the existing grpc services

Mustafa Arici 8 năm trước cách đây
mục cha
commit
7a1fbe6fc4
18 tập tin đã thay đổi với 1966 bổ sung111 xóa
  1. 1 1
      Makefile
  2. 38 0
      api/rest.go
  3. 11 0
      api/rpc.go
  4. 2 2
      bindata/bindata.go
  5. 39 8
      cmd/ovpmd/main.go
  6. 42 34
      pb/network.pb.go
  7. 388 0
      pb/network.pb.gw.go
  8. 51 7
      pb/network.proto
  9. 356 0
      pb/network.swagger.json
  10. 38 31
      pb/user.pb.go
  11. 342 0
      pb/user.pb.gw.go
  12. 42 6
      pb/user.proto
  13. 297 0
      pb/user.swagger.json
  14. 24 19
      pb/vpn.pb.go
  15. 158 0
      pb/vpn.pb.gw.go
  16. 12 2
      pb/vpn.proto
  17. 122 0
      pb/vpn.swagger.json
  18. 3 1
      vpn.go

+ 1 - 1
Makefile

@@ -1,4 +1,4 @@
-.PHONY: build
+.PHONY: deps build
 docker-build:
 	docker run --rm -i -t -e TRAVIS_GO_VERSION=$(TRAVIS_GO_VERSION) -e TRAVIS_BUILD_NUMBER=$(TRAVIS_BUILD_NUMBER) -e TRAVIS_TAG=$(TRAVIS_TAG) -v `pwd`:/fs/src/github.com/cad/ovpm -w /fs/src/github.com/cad/ovpm fedora ./build.sh
 	#docker run --rm -i -t -e TRAVIS_GO_VERSION=$(TRAVIS_GO_VERSION) -e TRAVIS_BUILD_NUMBER=$(TRAVIS_BUILD_NUMBER) -e TRAVIS_TAG=$(TRAVIS_TAG) -v `pwd`:/fs/src/github.com/cad/ovpm -w /fs/src/github.com/cad/ovpm fedora /bin/bash

+ 38 - 0
api/rest.go

@@ -0,0 +1,38 @@
+package api
+
+import (
+	"github.com/cad/ovpm/pb"
+	"github.com/grpc-ecosystem/grpc-gateway/runtime"
+	"golang.org/x/net/context"
+	"google.golang.org/grpc"
+)
+
+var (
+	vpnEndPoint     = "localhost:9891" // endpoint of VpnService
+	userEndPoint    = "localhost:9892" // endpoint of UserService
+	networkEndPoint = "localhost:9893" // endpoint of NetworkService
+)
+
+// NewRESTServer returns a new REST server.
+func NewRESTServer() (*runtime.ServeMux, context.CancelFunc, error) {
+	ctx := context.Background()
+	ctx, cancel := context.WithCancel(ctx)
+	mux := runtime.NewServeMux()
+	opts := []grpc.DialOption{grpc.WithInsecure()}
+	err := pb.RegisterVPNServiceHandlerFromEndpoint(ctx, mux, vpnEndPoint, opts)
+	if err != nil {
+		return nil, cancel, err
+	}
+
+	err = pb.RegisterUserServiceHandlerFromEndpoint(ctx, mux, userEndPoint, opts)
+	if err != nil {
+		return nil, cancel, err
+	}
+
+	err = pb.RegisterNetworkServiceHandlerFromEndpoint(ctx, mux, networkEndPoint, opts)
+	if err != nil {
+		return nil, cancel, err
+	}
+
+	return mux, cancel, nil
+}

+ 11 - 0
api/rpc.go

@@ -4,6 +4,8 @@ import (
 	"os"
 	"time"
 
+	"google.golang.org/grpc"
+
 	"github.com/Sirupsen/logrus"
 	"github.com/cad/ovpm"
 	"github.com/cad/ovpm/pb"
@@ -295,3 +297,12 @@ func (s *NetworkService) Dissociate(ctx context.Context, req *pb.NetworkDissocia
 
 	return &pb.NetworkDissociateResponse{}, nil
 }
+
+// NewRPCServer returns a new gRPC server.
+func NewRPCServer() *grpc.Server {
+	s := grpc.NewServer()
+	pb.RegisterUserServiceServer(s, &UserService{})
+	pb.RegisterVPNServiceServer(s, &VPNService{})
+	pb.RegisterNetworkServiceServer(s, &NetworkService{})
+	return s
+}

+ 2 - 2
bindata/bindata.go

@@ -87,7 +87,7 @@ func templateCcdFileTmpl() (*asset, error) {
 		return nil, err
 	}
 
-	info := bindataFileInfo{name: "template/ccd.file.tmpl", size: 229, mode: os.FileMode(420), modTime: time.Unix(1503827317, 0)}
+	info := bindataFileInfo{name: "template/ccd.file.tmpl", size: 229, mode: os.FileMode(420), modTime: time.Unix(1503828686, 0)}
 	a := &asset{bytes: bytes, info: info}
 	return a, nil
 }
@@ -167,7 +167,7 @@ func templateServerConfTmpl() (*asset, error) {
 		return nil, err
 	}
 
-	info := bindataFileInfo{name: "template/server.conf.tmpl", size: 9586, mode: os.FileMode(420), modTime: time.Unix(1503828509, 0)}
+	info := bindataFileInfo{name: "template/server.conf.tmpl", size: 9586, mode: os.FileMode(420), modTime: time.Unix(1503828686, 0)}
 	a := &asset{bytes: bytes, info: info}
 	return a, nil
 }

+ 39 - 8
cmd/ovpmd/main.go

@@ -3,11 +3,14 @@
 package main
 
 import (
+	"context"
 	"fmt"
 	"log"
 	"net"
+	"net/http"
 	"os"
 	"os/signal"
+	"strconv"
 	"syscall"
 	"time"
 
@@ -16,7 +19,7 @@ import (
 	"github.com/Sirupsen/logrus"
 	"github.com/cad/ovpm"
 	"github.com/cad/ovpm/api"
-	"github.com/cad/ovpm/pb"
+	"github.com/grpc-ecosystem/grpc-gateway/runtime"
 	"github.com/urfave/cli"
 )
 
@@ -64,9 +67,12 @@ func main() {
 }
 
 type server struct {
-	port       string
+	grpcPort   string
 	lis        net.Listener
 	grpcServer *grpc.Server
+	restServer *runtime.ServeMux
+	restCancel context.CancelFunc
+	restPort   string
 	signal     chan os.Signal
 	done       chan bool
 }
@@ -88,26 +94,41 @@ func newServer(port string) *server {
 		if err != nil {
 			logrus.Fatalf("could not listen to port %s: %v", port, err)
 		}
-		s := grpc.NewServer()
-		pb.RegisterUserServiceServer(s, &api.UserService{})
-		pb.RegisterVPNServiceServer(s, &api.VPNService{})
-		pb.RegisterNetworkServiceServer(s, &api.NetworkService{})
-		return &server{lis: lis, grpcServer: s, signal: sigs, done: done, port: port}
+
+		rpcServer := api.NewRPCServer()
+		restServer, restCancel, err := api.NewRESTServer()
+		if err != nil {
+			logrus.Fatalf("could not get new rest server :%v", err)
+		}
+
+		return &server{
+			lis:        lis,
+			grpcServer: rpcServer,
+			restServer: restServer,
+			restCancel: context.CancelFunc(restCancel),
+			restPort:   increasePort(port),
+			signal:     sigs,
+			done:       done,
+			grpcPort:   port,
+		}
 	}
 	return &server{}
 
 }
 
 func (s *server) start() {
-	logrus.Infof("OVPM is running :%s ...", s.port)
+	logrus.Infof("OVPM is running gRPC:%s, REST:%s ...", s.grpcPort, s.restPort)
 	go s.grpcServer.Serve(s.lis)
+	go http.ListenAndServe(":"+s.restPort, s.restServer)
 	ovpm.StartVPNProc()
 }
 
 func (s *server) stop() {
 	logrus.Info("OVPM is shutting down ...")
 	s.grpcServer.Stop()
+	s.restCancel()
 	ovpm.StopVPNProc()
+
 }
 
 func (s *server) waitForInterrupt() {
@@ -129,3 +150,13 @@ func stringInSlice(a string, list []string) bool {
 	}
 	return false
 }
+
+func increasePort(p string) string {
+	i, err := strconv.Atoi(p)
+	if err != nil {
+		logrus.Panicf(fmt.Sprintf("can't convert %s to int: %v", p, err))
+
+	}
+	i++
+	return fmt.Sprintf("%d", i)
+}

+ 42 - 34
pb/network.pb.go

@@ -6,6 +6,7 @@ package pb
 import proto "github.com/golang/protobuf/proto"
 import fmt "fmt"
 import math "math"
+import _ "google.golang.org/genproto/googleapis/api/annotations"
 
 import (
 	context "golang.org/x/net/context"
@@ -625,38 +626,45 @@ var _NetworkService_serviceDesc = grpc.ServiceDesc{
 func init() { proto.RegisterFile("network.proto", fileDescriptor2) }
 
 var fileDescriptor2 = []byte{
-	// 519 bytes of a gzipped FileDescriptorProto
-	0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xa4, 0x55, 0x5d, 0x6f, 0xd3, 0x30,
-	0x14, 0x5d, 0xd6, 0xae, 0x2c, 0x37, 0xe2, 0x43, 0x77, 0x83, 0x65, 0x5e, 0x87, 0x82, 0xc5, 0xc4,
-	0xc4, 0x43, 0x85, 0x86, 0x84, 0xc4, 0xcb, 0xa6, 0xaa, 0x95, 0x60, 0x80, 0xfa, 0x10, 0x3e, 0xde,
-	0xfb, 0xe1, 0x87, 0x88, 0xd2, 0x84, 0x38, 0x80, 0xf8, 0x29, 0xfc, 0x02, 0xfe, 0x26, 0x72, 0x7c,
-	0xed, 0x38, 0x4d, 0xd6, 0x09, 0xf5, 0xcd, 0x3d, 0xc7, 0x3e, 0xe7, 0x24, 0xe7, 0xc6, 0x85, 0xbb,
-	0x2b, 0x51, 0xfc, 0x4a, 0xf3, 0xaf, 0x83, 0x2c, 0x4f, 0x8b, 0x14, 0x77, 0xb3, 0x19, 0x5f, 0xc0,
-	0xe1, 0x44, 0x83, 0xa3, 0x5c, 0x4c, 0x0b, 0x11, 0x8b, 0xef, 0x3f, 0x84, 0x2c, 0x10, 0xa1, 0x3b,
-	0x99, 0x7e, 0x13, 0xa1, 0x17, 0x79, 0xe7, 0x7e, 0x5c, 0xae, 0x15, 0x36, 0xba, 0x1e, 0xc7, 0xe1,
-	0xae, 0xc6, 0xd4, 0x5a, 0x61, 0x9f, 0x7e, 0x67, 0x22, 0xec, 0x68, 0x4c, 0xad, 0xf1, 0x01, 0x74,
-	0xbe, 0x24, 0xd3, 0xb0, 0x5b, 0x42, 0x6a, 0xc9, 0x0f, 0x01, 0xc9, 0xe5, 0x43, 0x22, 0x0b, 0xf2,
-	0xe0, 0xcf, 0xad, 0xf7, 0x58, 0x2c, 0xc5, 0x46, 0x6f, 0x7e, 0x02, 0xc7, 0xb4, 0xf7, 0x8d, 0x28,
-	0x86, 0xcb, 0xa5, 0x32, 0x92, 0x46, 0xe8, 0x1a, 0x8e, 0x88, 0x1c, 0x4a, 0x99, 0xce, 0x93, 0x5b,
-	0x9e, 0x83, 0xc1, 0xfe, 0x67, 0x29, 0xf2, 0x95, 0xc2, 0xf5, 0xb3, 0xd8, 0xdf, 0xfc, 0x1d, 0x84,
-	0x26, 0x53, 0xb2, 0xad, 0xd6, 0x2b, 0x88, 0x9c, 0xcc, 0x46, 0x6d, 0xa1, 0x78, 0xb9, 0xe9, 0x59,
-	0xff, 0x7a, 0x70, 0x87, 0x0e, 0x6e, 0xd5, 0x43, 0x1f, 0x7c, 0x5d, 0xea, 0x62, 0x58, 0x50, 0x1b,
-	0x15, 0x80, 0x2f, 0xe0, 0xa0, 0x9e, 0x49, 0x65, 0x96, 0xe1, 0x5e, 0xd4, 0x39, 0xf7, 0xe3, 0x36,
-	0xca, 0xf4, 0xda, 0xab, 0x7a, 0x1d, 0x41, 0x40, 0x41, 0x4b, 0x43, 0x13, 0xc2, 0x73, 0x42, 0x44,
-	0x10, 0x8c, 0x85, 0x9c, 0xe7, 0x49, 0x56, 0x24, 0xe9, 0x8a, 0x32, 0xbb, 0x10, 0xbf, 0x84, 0x87,
-	0x6b, 0x23, 0x28, 0xb3, 0x74, 0x25, 0x05, 0x9e, 0xd9, 0xd7, 0x50, 0x2a, 0x06, 0x17, 0xc1, 0x20,
-	0x9b, 0x0d, 0x08, 0x8a, 0x0d, 0xc7, 0x2f, 0xe1, 0xa0, 0x36, 0x5c, 0x74, 0xfa, 0x19, 0xec, 0x13,
-	0x2c, 0x43, 0x2f, 0xea, 0xac, 0x1f, 0xb7, 0xa4, 0xe3, 0x6f, 0xc6, 0xf0, 0xff, 0xfc, 0x47, 0xc0,
-	0xda, 0x46, 0xd3, 0x8a, 0xec, 0x95, 0x00, 0x65, 0xb8, 0xef, 0x48, 0x28, 0x3c, 0xd6, 0x2c, 0x67,
-	0x76, 0xee, 0x9c, 0x11, 0xd6, 0x12, 0xce, 0xec, 0xbb, 0x33, 0x49, 0xe4, 0x10, 0x9e, 0x6c, 0x18,
-	0x32, 0x0a, 0xd1, 0x07, 0xbf, 0x6a, 0xd8, 0x2b, 0x1b, 0xae, 0x80, 0x8b, 0x3f, 0x5d, 0xb8, 0x47,
-	0x1a, 0x1f, 0x45, 0xfe, 0x33, 0x99, 0x0b, 0xbc, 0x82, 0x9e, 0x2e, 0x03, 0x43, 0x27, 0x70, 0xed,
-	0x8a, 0x60, 0xc7, 0x2d, 0x0c, 0x85, 0xda, 0xc1, 0xd7, 0xd0, 0x55, 0x6d, 0xe0, 0x23, 0x67, 0x93,
-	0xf3, 0xed, 0xb3, 0xa3, 0x06, 0x6e, 0x8f, 0x5e, 0x41, 0x4f, 0x17, 0x51, 0xf3, 0xae, 0x5d, 0x11,
-	0x35, 0xef, 0x7a, 0x6b, 0x7c, 0x07, 0x27, 0x10, 0x38, 0x4d, 0xe0, 0xa9, 0xb3, 0xb7, 0x79, 0x79,
-	0xb0, 0xc7, 0x37, 0xd1, 0x56, 0x6f, 0x0e, 0xd8, 0x7c, 0xb7, 0xf8, 0x74, 0xed, 0x5c, 0xeb, 0xf7,
-	0xcd, 0xce, 0x6e, 0xd9, 0x65, 0x4d, 0xde, 0x82, 0x6f, 0x49, 0x3c, 0x71, 0x4e, 0xad, 0x5f, 0x69,
-	0xac, 0xdf, 0x4e, 0x5a, 0xa5, 0xf7, 0x00, 0xd5, 0x9c, 0xa0, 0xbb, 0xbb, 0x71, 0xa5, 0xb1, 0xd3,
-	0x1b, 0x58, 0x23, 0x36, 0xeb, 0x95, 0x7f, 0x15, 0x2f, 0xff, 0x05, 0x00, 0x00, 0xff, 0xff, 0x97,
-	0x70, 0x5d, 0x7b, 0x3b, 0x06, 0x00, 0x00,
+	// 631 bytes of a gzipped FileDescriptorProto
+	0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xa4, 0x55, 0x4d, 0x6f, 0xd3, 0x40,
+	0x10, 0x95, 0x9b, 0x0f, 0x9a, 0x89, 0x80, 0x6a, 0xdb, 0x34, 0xee, 0x26, 0xa9, 0xdc, 0x85, 0x8a,
+	0xd2, 0x43, 0x02, 0x45, 0xe2, 0xc0, 0xa1, 0x52, 0x94, 0x48, 0xa8, 0x08, 0xf5, 0x60, 0x0a, 0xa7,
+	0x5e, 0x9c, 0x64, 0x15, 0x2c, 0x8c, 0x6d, 0xbc, 0xdb, 0x22, 0xae, 0x9c, 0xb9, 0xf1, 0x23, 0xf8,
+	0x41, 0xfc, 0x05, 0xfe, 0x05, 0x17, 0xb4, 0xeb, 0xb1, 0xb3, 0x4e, 0xdc, 0x54, 0xa8, 0xb7, 0xcd,
+	0x9b, 0xd9, 0xf7, 0xde, 0xfa, 0x8d, 0x26, 0x70, 0x3f, 0xe4, 0xf2, 0x6b, 0x94, 0x7c, 0xea, 0xc7,
+	0x49, 0x24, 0x23, 0xb2, 0x11, 0x4f, 0x68, 0x77, 0x1e, 0x45, 0xf3, 0x80, 0x0f, 0xbc, 0xd8, 0x1f,
+	0x78, 0x61, 0x18, 0x49, 0x4f, 0xfa, 0x51, 0x28, 0xd2, 0x0e, 0x36, 0x83, 0x9d, 0xf3, 0xf4, 0xca,
+	0x28, 0xe1, 0x9e, 0xe4, 0x2e, 0xff, 0x72, 0xc5, 0x85, 0x24, 0x04, 0xaa, 0xe7, 0xde, 0x67, 0x6e,
+	0x5b, 0x8e, 0x75, 0xd4, 0x70, 0xf5, 0x59, 0x61, 0xa3, 0xb3, 0xb1, 0x6b, 0x6f, 0xa4, 0x98, 0x3a,
+	0x2b, 0xec, 0xe2, 0x5b, 0xcc, 0xed, 0x4a, 0x8a, 0xa9, 0x33, 0xd9, 0x82, 0xca, 0x07, 0xdf, 0xb3,
+	0xab, 0x1a, 0x52, 0x47, 0xb6, 0x03, 0x04, 0x55, 0xde, 0xfa, 0x42, 0xa2, 0x06, 0x3b, 0xce, 0xb5,
+	0xc7, 0x3c, 0xe0, 0x6b, 0xb5, 0x59, 0x07, 0xf6, 0xb0, 0xf7, 0x35, 0x97, 0xc3, 0x20, 0x50, 0x42,
+	0x22, 0x23, 0x3a, 0x83, 0x36, 0x16, 0x87, 0x42, 0x44, 0x53, 0xff, 0x96, 0x77, 0x50, 0xd8, 0x7c,
+	0x2f, 0x78, 0x12, 0x2a, 0x3c, 0x7d, 0x4b, 0xfe, 0x9b, 0xbd, 0x01, 0x3b, 0xf3, 0xe4, 0xdf, 0x95,
+	0xeb, 0x25, 0x38, 0x86, 0xe7, 0x8c, 0x6d, 0xa6, 0xea, 0x62, 0xdd, 0x5b, 0x7f, 0x59, 0x70, 0x0f,
+	0x2f, 0xde, 0x29, 0x87, 0x2e, 0x34, 0xd2, 0x50, 0x67, 0x43, 0x89, 0x69, 0x2c, 0x00, 0xf2, 0x0c,
+	0xb6, 0x8b, 0x9e, 0x94, 0x67, 0x61, 0xd7, 0x9c, 0xca, 0x51, 0xc3, 0x2d, 0x2b, 0x65, 0xb9, 0xd6,
+	0x17, 0xb9, 0x8e, 0xa0, 0x89, 0x46, 0xb5, 0x60, 0x66, 0xc2, 0x32, 0x4c, 0x38, 0xd0, 0x1c, 0x73,
+	0x31, 0x4d, 0xfc, 0x58, 0x8d, 0x1d, 0x7a, 0x36, 0x21, 0x76, 0x0a, 0xad, 0xa5, 0x11, 0x14, 0x71,
+	0x14, 0x0a, 0x4e, 0x0e, 0xf3, 0xcf, 0xa0, 0x19, 0x9b, 0x27, 0xcd, 0x7e, 0x3c, 0xe9, 0x23, 0xe4,
+	0x66, 0x35, 0x76, 0x0a, 0xdb, 0x85, 0xe1, 0xc2, 0xdb, 0x4f, 0x60, 0x13, 0x61, 0x61, 0x5b, 0x4e,
+	0x65, 0xf9, 0x7a, 0x5e, 0x34, 0xf4, 0xb3, 0x31, 0xfc, 0x3f, 0xfd, 0x11, 0xd0, 0xb2, 0xd1, 0xcc,
+	0x49, 0x6a, 0x1a, 0x40, 0x0f, 0x0f, 0x0d, 0x0a, 0x85, 0xbb, 0x69, 0x95, 0xd1, 0x7c, 0xee, 0x8c,
+	0x11, 0x4e, 0x29, 0x8c, 0xd9, 0x37, 0x67, 0x12, 0x8b, 0x43, 0x38, 0x58, 0x33, 0x64, 0x68, 0xa2,
+	0x0b, 0x8d, 0x45, 0xc2, 0x96, 0x4e, 0x78, 0x01, 0x9c, 0xfc, 0xad, 0xc1, 0x03, 0xe4, 0x78, 0xc7,
+	0x93, 0x6b, 0x7f, 0xca, 0xc9, 0x25, 0xd4, 0xd3, 0x30, 0x88, 0x6d, 0x18, 0x2e, 0xac, 0x08, 0xba,
+	0x57, 0x52, 0x41, 0x53, 0xbd, 0xef, 0xbf, 0xff, 0xfc, 0xdc, 0x68, 0x33, 0x32, 0xb8, 0x7e, 0x3e,
+	0xc0, 0x95, 0x34, 0x98, 0xea, 0x9e, 0x57, 0xd6, 0x31, 0xb9, 0x80, 0xaa, 0x8a, 0x8a, 0xec, 0x1a,
+	0x0c, 0xc6, 0x62, 0xa0, 0xed, 0x15, 0x3c, 0xfb, 0x12, 0x9a, 0xb7, 0xc5, 0xb6, 0x4c, 0xde, 0xc0,
+	0x17, 0x52, 0xb1, 0x5e, 0x42, 0x3d, 0x0d, 0xb0, 0xe0, 0xb9, 0xb0, 0x5a, 0x0a, 0x9e, 0x8b, 0x69,
+	0x97, 0x7b, 0x9e, 0xe9, 0x1e, 0xc5, 0x1e, 0x43, 0xd3, 0x88, 0x97, 0xf4, 0x0c, 0xa2, 0xd5, 0x8d,
+	0x44, 0xf7, 0x6f, 0x2a, 0xa3, 0x18, 0xd3, 0x62, 0x5d, 0xd6, 0x36, 0xc5, 0xe6, 0x5c, 0x7a, 0x41,
+	0x20, 0x55, 0xa3, 0x52, 0xfc, 0x61, 0x01, 0x59, 0xcd, 0x94, 0x3c, 0x5e, 0xa2, 0x2e, 0xdd, 0x2b,
+	0xf4, 0xf0, 0x96, 0x2e, 0xf4, 0xf1, 0x54, 0xfb, 0x78, 0xc4, 0xf6, 0x97, 0x7d, 0xe4, 0xfd, 0x57,
+	0xaa, 0x5f, 0xd9, 0xf9, 0x08, 0x8d, 0x9c, 0x85, 0x74, 0x0c, 0xfa, 0xe5, 0x9d, 0x4b, 0xbb, 0xe5,
+	0x45, 0x94, 0x74, 0xb4, 0x24, 0x65, 0x2d, 0x53, 0x32, 0xd7, 0x53, 0x4a, 0x01, 0xc0, 0x62, 0xd0,
+	0x89, 0xc9, 0xb6, 0xb2, 0x93, 0x69, 0xef, 0x86, 0x2a, 0x8a, 0x1d, 0x68, 0xb1, 0x0e, 0xdb, 0x2d,
+	0x84, 0xea, 0x1b, 0x6a, 0x93, 0xba, 0xfe, 0x23, 0x7c, 0xf1, 0x2f, 0x00, 0x00, 0xff, 0xff, 0x58,
+	0xed, 0x37, 0x0c, 0x3b, 0x07, 0x00, 0x00,
 }

+ 388 - 0
pb/network.pb.gw.go

@@ -0,0 +1,388 @@
+// Code generated by protoc-gen-grpc-gateway. DO NOT EDIT.
+// source: network.proto
+
+/*
+Package pb is a reverse proxy.
+
+It translates gRPC into RESTful JSON APIs.
+*/
+package pb
+
+import (
+	"io"
+	"net/http"
+
+	"github.com/golang/protobuf/proto"
+	"github.com/grpc-ecosystem/grpc-gateway/runtime"
+	"github.com/grpc-ecosystem/grpc-gateway/utilities"
+	"golang.org/x/net/context"
+	"google.golang.org/grpc"
+	"google.golang.org/grpc/codes"
+	"google.golang.org/grpc/grpclog"
+	"google.golang.org/grpc/status"
+)
+
+var _ codes.Code
+var _ io.Reader
+var _ status.Status
+var _ = runtime.String
+var _ = utilities.NewDoubleArray
+
+func request_NetworkService_Create_0(ctx context.Context, marshaler runtime.Marshaler, client NetworkServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
+	var protoReq NetworkCreateRequest
+	var metadata runtime.ServerMetadata
+
+	if err := marshaler.NewDecoder(req.Body).Decode(&protoReq); err != nil {
+		return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
+	}
+
+	msg, err := client.Create(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
+	return msg, metadata, err
+
+}
+
+func request_NetworkService_List_0(ctx context.Context, marshaler runtime.Marshaler, client NetworkServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
+	var protoReq NetworkListRequest
+	var metadata runtime.ServerMetadata
+
+	if err := marshaler.NewDecoder(req.Body).Decode(&protoReq); err != nil {
+		return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
+	}
+
+	msg, err := client.List(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
+	return msg, metadata, err
+
+}
+
+func request_NetworkService_Delete_0(ctx context.Context, marshaler runtime.Marshaler, client NetworkServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
+	var protoReq NetworkDeleteRequest
+	var metadata runtime.ServerMetadata
+
+	if err := marshaler.NewDecoder(req.Body).Decode(&protoReq); err != nil {
+		return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
+	}
+
+	msg, err := client.Delete(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
+	return msg, metadata, err
+
+}
+
+func request_NetworkService_GetAllTypes_0(ctx context.Context, marshaler runtime.Marshaler, client NetworkServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
+	var protoReq NetworkGetAllTypesRequest
+	var metadata runtime.ServerMetadata
+
+	if err := marshaler.NewDecoder(req.Body).Decode(&protoReq); err != nil {
+		return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
+	}
+
+	msg, err := client.GetAllTypes(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
+	return msg, metadata, err
+
+}
+
+func request_NetworkService_GetAssociatedUsers_0(ctx context.Context, marshaler runtime.Marshaler, client NetworkServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
+	var protoReq NetworkGetAssociatedUsersRequest
+	var metadata runtime.ServerMetadata
+
+	if err := marshaler.NewDecoder(req.Body).Decode(&protoReq); err != nil {
+		return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
+	}
+
+	msg, err := client.GetAssociatedUsers(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
+	return msg, metadata, err
+
+}
+
+func request_NetworkService_Associate_0(ctx context.Context, marshaler runtime.Marshaler, client NetworkServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
+	var protoReq NetworkAssociateRequest
+	var metadata runtime.ServerMetadata
+
+	if err := marshaler.NewDecoder(req.Body).Decode(&protoReq); err != nil {
+		return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
+	}
+
+	msg, err := client.Associate(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
+	return msg, metadata, err
+
+}
+
+func request_NetworkService_Dissociate_0(ctx context.Context, marshaler runtime.Marshaler, client NetworkServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
+	var protoReq NetworkDissociateRequest
+	var metadata runtime.ServerMetadata
+
+	if err := marshaler.NewDecoder(req.Body).Decode(&protoReq); err != nil {
+		return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
+	}
+
+	msg, err := client.Dissociate(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
+	return msg, metadata, err
+
+}
+
+// RegisterNetworkServiceHandlerFromEndpoint is same as RegisterNetworkServiceHandler but
+// automatically dials to "endpoint" and closes the connection when "ctx" gets done.
+func RegisterNetworkServiceHandlerFromEndpoint(ctx context.Context, mux *runtime.ServeMux, endpoint string, opts []grpc.DialOption) (err error) {
+	conn, err := grpc.Dial(endpoint, opts...)
+	if err != nil {
+		return err
+	}
+	defer func() {
+		if err != nil {
+			if cerr := conn.Close(); cerr != nil {
+				grpclog.Printf("Failed to close conn to %s: %v", endpoint, cerr)
+			}
+			return
+		}
+		go func() {
+			<-ctx.Done()
+			if cerr := conn.Close(); cerr != nil {
+				grpclog.Printf("Failed to close conn to %s: %v", endpoint, cerr)
+			}
+		}()
+	}()
+
+	return RegisterNetworkServiceHandler(ctx, mux, conn)
+}
+
+// RegisterNetworkServiceHandler registers the http handlers for service NetworkService to "mux".
+// The handlers forward requests to the grpc endpoint over "conn".
+func RegisterNetworkServiceHandler(ctx context.Context, mux *runtime.ServeMux, conn *grpc.ClientConn) error {
+	client := NewNetworkServiceClient(conn)
+
+	mux.Handle("POST", pattern_NetworkService_Create_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
+		ctx, cancel := context.WithCancel(ctx)
+		defer cancel()
+		if cn, ok := w.(http.CloseNotifier); ok {
+			go func(done <-chan struct{}, closed <-chan bool) {
+				select {
+				case <-done:
+				case <-closed:
+					cancel()
+				}
+			}(ctx.Done(), cn.CloseNotify())
+		}
+		inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
+		rctx, err := runtime.AnnotateContext(ctx, mux, req)
+		if err != nil {
+			runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
+			return
+		}
+		resp, md, err := request_NetworkService_Create_0(rctx, inboundMarshaler, client, req, pathParams)
+		ctx = runtime.NewServerMetadataContext(ctx, md)
+		if err != nil {
+			runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
+			return
+		}
+
+		forward_NetworkService_Create_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
+
+	})
+
+	mux.Handle("POST", pattern_NetworkService_List_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
+		ctx, cancel := context.WithCancel(ctx)
+		defer cancel()
+		if cn, ok := w.(http.CloseNotifier); ok {
+			go func(done <-chan struct{}, closed <-chan bool) {
+				select {
+				case <-done:
+				case <-closed:
+					cancel()
+				}
+			}(ctx.Done(), cn.CloseNotify())
+		}
+		inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
+		rctx, err := runtime.AnnotateContext(ctx, mux, req)
+		if err != nil {
+			runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
+			return
+		}
+		resp, md, err := request_NetworkService_List_0(rctx, inboundMarshaler, client, req, pathParams)
+		ctx = runtime.NewServerMetadataContext(ctx, md)
+		if err != nil {
+			runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
+			return
+		}
+
+		forward_NetworkService_List_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
+
+	})
+
+	mux.Handle("POST", pattern_NetworkService_Delete_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
+		ctx, cancel := context.WithCancel(ctx)
+		defer cancel()
+		if cn, ok := w.(http.CloseNotifier); ok {
+			go func(done <-chan struct{}, closed <-chan bool) {
+				select {
+				case <-done:
+				case <-closed:
+					cancel()
+				}
+			}(ctx.Done(), cn.CloseNotify())
+		}
+		inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
+		rctx, err := runtime.AnnotateContext(ctx, mux, req)
+		if err != nil {
+			runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
+			return
+		}
+		resp, md, err := request_NetworkService_Delete_0(rctx, inboundMarshaler, client, req, pathParams)
+		ctx = runtime.NewServerMetadataContext(ctx, md)
+		if err != nil {
+			runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
+			return
+		}
+
+		forward_NetworkService_Delete_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
+
+	})
+
+	mux.Handle("POST", pattern_NetworkService_GetAllTypes_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
+		ctx, cancel := context.WithCancel(ctx)
+		defer cancel()
+		if cn, ok := w.(http.CloseNotifier); ok {
+			go func(done <-chan struct{}, closed <-chan bool) {
+				select {
+				case <-done:
+				case <-closed:
+					cancel()
+				}
+			}(ctx.Done(), cn.CloseNotify())
+		}
+		inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
+		rctx, err := runtime.AnnotateContext(ctx, mux, req)
+		if err != nil {
+			runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
+			return
+		}
+		resp, md, err := request_NetworkService_GetAllTypes_0(rctx, inboundMarshaler, client, req, pathParams)
+		ctx = runtime.NewServerMetadataContext(ctx, md)
+		if err != nil {
+			runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
+			return
+		}
+
+		forward_NetworkService_GetAllTypes_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
+
+	})
+
+	mux.Handle("POST", pattern_NetworkService_GetAssociatedUsers_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
+		ctx, cancel := context.WithCancel(ctx)
+		defer cancel()
+		if cn, ok := w.(http.CloseNotifier); ok {
+			go func(done <-chan struct{}, closed <-chan bool) {
+				select {
+				case <-done:
+				case <-closed:
+					cancel()
+				}
+			}(ctx.Done(), cn.CloseNotify())
+		}
+		inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
+		rctx, err := runtime.AnnotateContext(ctx, mux, req)
+		if err != nil {
+			runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
+			return
+		}
+		resp, md, err := request_NetworkService_GetAssociatedUsers_0(rctx, inboundMarshaler, client, req, pathParams)
+		ctx = runtime.NewServerMetadataContext(ctx, md)
+		if err != nil {
+			runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
+			return
+		}
+
+		forward_NetworkService_GetAssociatedUsers_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
+
+	})
+
+	mux.Handle("POST", pattern_NetworkService_Associate_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
+		ctx, cancel := context.WithCancel(ctx)
+		defer cancel()
+		if cn, ok := w.(http.CloseNotifier); ok {
+			go func(done <-chan struct{}, closed <-chan bool) {
+				select {
+				case <-done:
+				case <-closed:
+					cancel()
+				}
+			}(ctx.Done(), cn.CloseNotify())
+		}
+		inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
+		rctx, err := runtime.AnnotateContext(ctx, mux, req)
+		if err != nil {
+			runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
+			return
+		}
+		resp, md, err := request_NetworkService_Associate_0(rctx, inboundMarshaler, client, req, pathParams)
+		ctx = runtime.NewServerMetadataContext(ctx, md)
+		if err != nil {
+			runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
+			return
+		}
+
+		forward_NetworkService_Associate_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
+
+	})
+
+	mux.Handle("POST", pattern_NetworkService_Dissociate_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
+		ctx, cancel := context.WithCancel(ctx)
+		defer cancel()
+		if cn, ok := w.(http.CloseNotifier); ok {
+			go func(done <-chan struct{}, closed <-chan bool) {
+				select {
+				case <-done:
+				case <-closed:
+					cancel()
+				}
+			}(ctx.Done(), cn.CloseNotify())
+		}
+		inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
+		rctx, err := runtime.AnnotateContext(ctx, mux, req)
+		if err != nil {
+			runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
+			return
+		}
+		resp, md, err := request_NetworkService_Dissociate_0(rctx, inboundMarshaler, client, req, pathParams)
+		ctx = runtime.NewServerMetadataContext(ctx, md)
+		if err != nil {
+			runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
+			return
+		}
+
+		forward_NetworkService_Dissociate_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
+
+	})
+
+	return nil
+}
+
+var (
+	pattern_NetworkService_Create_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"v1", "network", "create"}, ""))
+
+	pattern_NetworkService_List_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"v1", "network", "list"}, ""))
+
+	pattern_NetworkService_Delete_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"v1", "network", "delete"}, ""))
+
+	pattern_NetworkService_GetAllTypes_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"v1", "network", "getalltypes"}, ""))
+
+	pattern_NetworkService_GetAssociatedUsers_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"v1", "network", "getassociatedusers"}, ""))
+
+	pattern_NetworkService_Associate_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"v1", "network", "associate"}, ""))
+
+	pattern_NetworkService_Dissociate_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"v1", "network", "dissociate"}, ""))
+)
+
+var (
+	forward_NetworkService_Create_0 = runtime.ForwardResponseMessage
+
+	forward_NetworkService_List_0 = runtime.ForwardResponseMessage
+
+	forward_NetworkService_Delete_0 = runtime.ForwardResponseMessage
+
+	forward_NetworkService_GetAllTypes_0 = runtime.ForwardResponseMessage
+
+	forward_NetworkService_GetAssociatedUsers_0 = runtime.ForwardResponseMessage
+
+	forward_NetworkService_Associate_0 = runtime.ForwardResponseMessage
+
+	forward_NetworkService_Dissociate_0 = runtime.ForwardResponseMessage
+)

+ 51 - 7
pb/network.proto

@@ -2,6 +2,8 @@ syntax = "proto3";
 
 package pb;
 
+import "google/api/annotations.proto";
+
 message NetworkCreateRequest {
   string Name = 1;
   string CIDR = 2;
@@ -26,13 +28,55 @@ message NetworkGetAssociatedUsersRequest {
   string Name = 1;
 }
 service NetworkService {
-  rpc Create (NetworkCreateRequest) returns (NetworkCreateResponse) {}
-  rpc List (NetworkListRequest) returns (NetworkListResponse) {}
-  rpc Delete (NetworkDeleteRequest) returns (NetworkDeleteResponse) {}
-  rpc GetAllTypes(NetworkGetAllTypesRequest) returns (NetworkGetAllTypesResponse) {}
-  rpc GetAssociatedUsers(NetworkGetAssociatedUsersRequest) returns (NetworkGetAssociatedUsersResponse) {}
-  rpc Associate (NetworkAssociateRequest) returns (NetworkAssociateResponse) {}
-  rpc Dissociate (NetworkDissociateRequest) returns (NetworkDissociateResponse) {}
+  rpc Create (NetworkCreateRequest) returns (NetworkCreateResponse) {
+    option (google.api.http) = {
+      post: "/v1/network/create"
+      body: "*"
+    };
+
+  }
+  rpc List (NetworkListRequest) returns (NetworkListResponse) {
+    option (google.api.http) = {
+      post: "/v1/network/list"
+      body: "*"
+    };
+
+  }
+  rpc Delete (NetworkDeleteRequest) returns (NetworkDeleteResponse) {
+    option (google.api.http) = {
+      post: "/v1/network/delete"
+      body: "*"
+    };
+
+  }
+  rpc GetAllTypes(NetworkGetAllTypesRequest) returns (NetworkGetAllTypesResponse) {
+    option (google.api.http) = {
+      post: "/v1/network/getalltypes"
+      body: "*"
+    };
+
+  }
+  rpc GetAssociatedUsers(NetworkGetAssociatedUsersRequest) returns (NetworkGetAssociatedUsersResponse) {
+    option (google.api.http) = {
+      post: "/v1/network/getassociatedusers"
+      body: "*"
+    };
+
+  }
+  rpc Associate (NetworkAssociateRequest) returns (NetworkAssociateResponse) {
+    option (google.api.http) = {
+      post: "/v1/network/associate"
+      body: "*"
+    };
+
+  }
+  rpc Dissociate (NetworkDissociateRequest) returns (NetworkDissociateResponse) {
+    option (google.api.http) = {
+      post: "/v1/network/dissociate"
+      body: "*"
+    };
+
+  }
 }
 message Network {
   string Name = 1;

+ 356 - 0
pb/network.swagger.json

@@ -0,0 +1,356 @@
+{
+  "swagger": "2.0",
+  "info": {
+    "title": "network.proto",
+    "version": "version not set"
+  },
+  "schemes": [
+    "http",
+    "https"
+  ],
+  "consumes": [
+    "application/json"
+  ],
+  "produces": [
+    "application/json"
+  ],
+  "paths": {
+    "/v1/network/associate": {
+      "post": {
+        "operationId": "Associate",
+        "responses": {
+          "200": {
+            "description": "",
+            "schema": {
+              "$ref": "#/definitions/pbNetworkAssociateResponse"
+            }
+          }
+        },
+        "parameters": [
+          {
+            "name": "body",
+            "in": "body",
+            "required": true,
+            "schema": {
+              "$ref": "#/definitions/pbNetworkAssociateRequest"
+            }
+          }
+        ],
+        "tags": [
+          "NetworkService"
+        ]
+      }
+    },
+    "/v1/network/create": {
+      "post": {
+        "operationId": "Create",
+        "responses": {
+          "200": {
+            "description": "",
+            "schema": {
+              "$ref": "#/definitions/pbNetworkCreateResponse"
+            }
+          }
+        },
+        "parameters": [
+          {
+            "name": "body",
+            "in": "body",
+            "required": true,
+            "schema": {
+              "$ref": "#/definitions/pbNetworkCreateRequest"
+            }
+          }
+        ],
+        "tags": [
+          "NetworkService"
+        ]
+      }
+    },
+    "/v1/network/delete": {
+      "post": {
+        "operationId": "Delete",
+        "responses": {
+          "200": {
+            "description": "",
+            "schema": {
+              "$ref": "#/definitions/pbNetworkDeleteResponse"
+            }
+          }
+        },
+        "parameters": [
+          {
+            "name": "body",
+            "in": "body",
+            "required": true,
+            "schema": {
+              "$ref": "#/definitions/pbNetworkDeleteRequest"
+            }
+          }
+        ],
+        "tags": [
+          "NetworkService"
+        ]
+      }
+    },
+    "/v1/network/dissociate": {
+      "post": {
+        "operationId": "Dissociate",
+        "responses": {
+          "200": {
+            "description": "",
+            "schema": {
+              "$ref": "#/definitions/pbNetworkDissociateResponse"
+            }
+          }
+        },
+        "parameters": [
+          {
+            "name": "body",
+            "in": "body",
+            "required": true,
+            "schema": {
+              "$ref": "#/definitions/pbNetworkDissociateRequest"
+            }
+          }
+        ],
+        "tags": [
+          "NetworkService"
+        ]
+      }
+    },
+    "/v1/network/getalltypes": {
+      "post": {
+        "operationId": "GetAllTypes",
+        "responses": {
+          "200": {
+            "description": "",
+            "schema": {
+              "$ref": "#/definitions/pbNetworkGetAllTypesResponse"
+            }
+          }
+        },
+        "parameters": [
+          {
+            "name": "body",
+            "in": "body",
+            "required": true,
+            "schema": {
+              "$ref": "#/definitions/pbNetworkGetAllTypesRequest"
+            }
+          }
+        ],
+        "tags": [
+          "NetworkService"
+        ]
+      }
+    },
+    "/v1/network/getassociatedusers": {
+      "post": {
+        "operationId": "GetAssociatedUsers",
+        "responses": {
+          "200": {
+            "description": "",
+            "schema": {
+              "$ref": "#/definitions/pbNetworkGetAssociatedUsersResponse"
+            }
+          }
+        },
+        "parameters": [
+          {
+            "name": "body",
+            "in": "body",
+            "required": true,
+            "schema": {
+              "$ref": "#/definitions/pbNetworkGetAssociatedUsersRequest"
+            }
+          }
+        ],
+        "tags": [
+          "NetworkService"
+        ]
+      }
+    },
+    "/v1/network/list": {
+      "post": {
+        "operationId": "List",
+        "responses": {
+          "200": {
+            "description": "",
+            "schema": {
+              "$ref": "#/definitions/pbNetworkListResponse"
+            }
+          }
+        },
+        "parameters": [
+          {
+            "name": "body",
+            "in": "body",
+            "required": true,
+            "schema": {
+              "$ref": "#/definitions/pbNetworkListRequest"
+            }
+          }
+        ],
+        "tags": [
+          "NetworkService"
+        ]
+      }
+    }
+  },
+  "definitions": {
+    "pbNetwork": {
+      "type": "object",
+      "properties": {
+        "Name": {
+          "type": "string"
+        },
+        "CIDR": {
+          "type": "string"
+        },
+        "Type": {
+          "type": "string"
+        },
+        "CreatedAt": {
+          "type": "string"
+        },
+        "AssociatedUsernames": {
+          "type": "array",
+          "items": {
+            "type": "string"
+          }
+        },
+        "Via": {
+          "type": "string"
+        }
+      }
+    },
+    "pbNetworkAssociateRequest": {
+      "type": "object",
+      "properties": {
+        "Name": {
+          "type": "string"
+        },
+        "Username": {
+          "type": "string"
+        }
+      }
+    },
+    "pbNetworkAssociateResponse": {
+      "type": "object"
+    },
+    "pbNetworkCreateRequest": {
+      "type": "object",
+      "properties": {
+        "Name": {
+          "type": "string"
+        },
+        "CIDR": {
+          "type": "string"
+        },
+        "Type": {
+          "type": "string"
+        },
+        "Via": {
+          "type": "string"
+        }
+      }
+    },
+    "pbNetworkCreateResponse": {
+      "type": "object",
+      "properties": {
+        "Network": {
+          "$ref": "#/definitions/pbNetwork"
+        }
+      }
+    },
+    "pbNetworkDeleteRequest": {
+      "type": "object",
+      "properties": {
+        "Name": {
+          "type": "string"
+        }
+      }
+    },
+    "pbNetworkDeleteResponse": {
+      "type": "object",
+      "properties": {
+        "Network": {
+          "$ref": "#/definitions/pbNetwork"
+        }
+      }
+    },
+    "pbNetworkDissociateRequest": {
+      "type": "object",
+      "properties": {
+        "Name": {
+          "type": "string"
+        },
+        "Username": {
+          "type": "string"
+        }
+      }
+    },
+    "pbNetworkDissociateResponse": {
+      "type": "object"
+    },
+    "pbNetworkGetAllTypesRequest": {
+      "type": "object"
+    },
+    "pbNetworkGetAllTypesResponse": {
+      "type": "object",
+      "properties": {
+        "Types": {
+          "type": "array",
+          "items": {
+            "$ref": "#/definitions/pbNetworkType"
+          }
+        }
+      }
+    },
+    "pbNetworkGetAssociatedUsersRequest": {
+      "type": "object",
+      "properties": {
+        "Name": {
+          "type": "string"
+        }
+      }
+    },
+    "pbNetworkGetAssociatedUsersResponse": {
+      "type": "object",
+      "properties": {
+        "Usernames": {
+          "type": "array",
+          "items": {
+            "type": "string"
+          }
+        }
+      }
+    },
+    "pbNetworkListRequest": {
+      "type": "object"
+    },
+    "pbNetworkListResponse": {
+      "type": "object",
+      "properties": {
+        "Networks": {
+          "type": "array",
+          "items": {
+            "$ref": "#/definitions/pbNetwork"
+          }
+        }
+      }
+    },
+    "pbNetworkType": {
+      "type": "object",
+      "properties": {
+        "Type": {
+          "type": "string"
+        },
+        "Description": {
+          "type": "string"
+        }
+      }
+    }
+  }
+}

+ 38 - 31
pb/user.pb.go

@@ -44,6 +44,7 @@ package pb
 import proto "github.com/golang/protobuf/proto"
 import fmt "fmt"
 import math "math"
+import _ "google.golang.org/genproto/googleapis/api/annotations"
 
 import (
 	context "golang.org/x/net/context"
@@ -570,35 +571,41 @@ var _UserService_serviceDesc = grpc.ServiceDesc{
 func init() { proto.RegisterFile("user.proto", fileDescriptor0) }
 
 var fileDescriptor0 = []byte{
-	// 480 bytes of a gzipped FileDescriptorProto
-	0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xac, 0x54, 0xcd, 0x6e, 0xd3, 0x40,
-	0x10, 0xae, 0x5d, 0xc7, 0xc4, 0xd3, 0x02, 0xee, 0x90, 0x22, 0x13, 0xf5, 0x10, 0xf9, 0x80, 0x22,
-	0x21, 0xb9, 0x22, 0xe5, 0xc6, 0x09, 0x52, 0x30, 0x95, 0x90, 0x1b, 0x6d, 0x55, 0xe5, 0x9c, 0x90,
-	0x49, 0x65, 0x29, 0xb1, 0xcd, 0xee, 0x86, 0xbc, 0x00, 0x2f, 0xc6, 0x85, 0x27, 0xe0, 0x81, 0xd0,
-	0x7a, 0xfd, 0x83, 0x83, 0x83, 0x72, 0xe0, 0x36, 0x7f, 0xdf, 0x8e, 0xe7, 0x9b, 0x6f, 0x0c, 0xb0,
-	0x11, 0xc4, 0x83, 0x8c, 0xa7, 0x32, 0x45, 0x33, 0x9b, 0xfb, 0x67, 0xf0, 0xf4, 0x5e, 0x10, 0xff,
-	0x1c, 0x0b, 0xc9, 0xe8, 0xeb, 0x86, 0x84, 0xf4, 0xb7, 0x70, 0xa6, 0x42, 0x63, 0x4e, 0x33, 0x49,
-	0x45, 0x10, 0xfb, 0xd0, 0x55, 0xc1, 0x64, 0xb6, 0x26, 0xcf, 0x18, 0x18, 0x43, 0x87, 0x55, 0xbe,
-	0xca, 0x4d, 0x66, 0x42, 0x6c, 0x53, 0xbe, 0xf0, 0x4c, 0x9d, 0x2b, 0x7d, 0x44, 0xb0, 0xa2, 0x34,
-	0x9c, 0x7a, 0xc7, 0x03, 0x63, 0xd8, 0x65, 0xb9, 0x8d, 0xcf, 0xc1, 0xfe, 0x94, 0x0a, 0x79, 0x73,
-	0xed, 0x59, 0x03, 0x63, 0xf8, 0x98, 0x15, 0x9e, 0xff, 0xc3, 0xd0, 0x9d, 0xef, 0xb3, 0xc5, 0x7f,
-	0xe8, 0xfc, 0x06, 0xec, 0x87, 0x6d, 0xc6, 0x69, 0x99, 0xf7, 0x7e, 0x32, 0xba, 0x08, 0xb2, 0x79,
-	0xf0, 0xd7, 0xf3, 0x41, 0x38, 0x9d, 0x70, 0x5a, 0xb2, 0xa2, 0x76, 0xef, 0xb7, 0xbd, 0x04, 0x5b,
-	0x57, 0x22, 0x80, 0x1d, 0xdd, 0x4e, 0xd8, 0x87, 0x8f, 0xee, 0x11, 0x76, 0xc1, 0x8a, 0x6e, 0xc3,
-	0xa9, 0x6b, 0xa0, 0x0d, 0x66, 0x38, 0x75, 0x4d, 0xff, 0x52, 0x8f, 0x70, 0x4d, 0x2b, 0x3a, 0x68,
-	0x04, 0x3f, 0x00, 0x57, 0xd9, 0x8c, 0x12, 0xda, 0x1e, 0x52, 0x3f, 0x82, 0x9e, 0xb2, 0x43, 0x4a,
-	0xc6, 0x69, 0xb2, 0x8c, 0x1f, 0x0e, 0xc1, 0x7c, 0x37, 0xe1, 0x54, 0x37, 0x11, 0x59, 0x9a, 0x08,
-	0xc2, 0x57, 0xd0, 0x51, 0x3a, 0x10, 0x9e, 0x31, 0x38, 0x1e, 0x9e, 0x8c, 0xce, 0x4b, 0x6a, 0xca,
-	0x02, 0xed, 0xe8, 0x9a, 0xfe, 0x4f, 0x03, 0x2c, 0xe5, 0xff, 0x73, 0x13, 0x01, 0xe0, 0x1d, 0xf1,
-	0x6f, 0xc4, 0xef, 0x88, 0xc7, 0xb3, 0x55, 0xb4, 0x59, 0xcf, 0x89, 0x17, 0x3b, 0x69, 0xc9, 0x28,
-	0x5d, 0x8c, 0x89, 0xcb, 0x7c, 0x37, 0x0e, 0xcb, 0x6d, 0xbc, 0x00, 0x47, 0x8b, 0x6e, 0xf1, 0x4e,
-	0xe6, 0xf4, 0x3b, 0xac, 0x0e, 0x60, 0x0f, 0x3a, 0x37, 0x93, 0x88, 0xa4, 0xd7, 0xc9, 0x33, 0xda,
-	0xa9, 0xf4, 0x65, 0xb7, 0xea, 0xeb, 0x51, 0x63, 0x87, 0x6f, 0xe1, 0x7c, 0x87, 0xba, 0x82, 0x0e,
-	0x1f, 0x4e, 0xc7, 0xab, 0x98, 0x12, 0xa9, 0xe3, 0xc5, 0x70, 0x8d, 0xd8, 0xe8, 0x97, 0x09, 0x27,
-	0x0a, 0xad, 0x66, 0x89, 0xbf, 0x10, 0x5e, 0x82, 0xa5, 0x8e, 0x06, 0x9f, 0x95, 0xdc, 0xfd, 0x71,
-	0x42, 0x7d, 0x77, 0x97, 0x50, 0xff, 0x08, 0xaf, 0xc0, 0xd6, 0xc3, 0x60, 0x45, 0x77, 0xe3, 0xc4,
-	0xf6, 0x81, 0xb4, 0x5c, 0x6b, 0x50, 0x43, 0xbe, 0xfb, 0x40, 0x5a, 0x7f, 0x35, 0xa8, 0xa1, 0xc7,
-	0x56, 0xd0, 0x6b, 0xe8, 0xe4, 0x1a, 0xc4, 0x5e, 0x9d, 0xac, 0x25, 0xd9, 0x0a, 0x79, 0x0f, 0x4e,
-	0xc5, 0x25, 0x7a, 0x65, 0xc1, 0xae, 0x32, 0xfb, 0x2f, 0x5a, 0x32, 0xe5, 0x1b, 0x73, 0x3b, 0xff,
-	0x15, 0x5d, 0xfd, 0x0e, 0x00, 0x00, 0xff, 0xff, 0x90, 0xef, 0x0f, 0xc4, 0x98, 0x04, 0x00, 0x00,
+	// 575 bytes of a gzipped FileDescriptorProto
+	0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xac, 0x94, 0x4d, 0x6e, 0xd3, 0x40,
+	0x14, 0xc7, 0xb1, 0x9b, 0x98, 0xe4, 0xf5, 0x2b, 0x9d, 0xa6, 0xe0, 0x5a, 0x41, 0x8a, 0x66, 0x81,
+	0xa2, 0x22, 0xd9, 0x22, 0xb0, 0x2a, 0x2b, 0x94, 0x82, 0x29, 0x82, 0x34, 0x72, 0x55, 0x65, 0x89,
+	0x9c, 0xe4, 0x25, 0xb2, 0x94, 0x7a, 0xcc, 0xcc, 0xa4, 0xd9, 0x23, 0x6e, 0xc0, 0x89, 0xd8, 0x70,
+	0x01, 0xae, 0xc0, 0x01, 0x38, 0x02, 0x9a, 0x19, 0xc7, 0x21, 0x21, 0xa0, 0x2c, 0xd8, 0xcd, 0xfb,
+	0xfa, 0x8d, 0xdf, 0x7b, 0xff, 0x31, 0xc0, 0x4c, 0x20, 0xf7, 0x33, 0xce, 0x24, 0x23, 0x76, 0x36,
+	0xf0, 0x1a, 0x13, 0xc6, 0x26, 0x53, 0x0c, 0xe2, 0x2c, 0x09, 0xe2, 0x34, 0x65, 0x32, 0x96, 0x09,
+	0x4b, 0x85, 0xc9, 0xa0, 0x47, 0x70, 0x78, 0x23, 0x90, 0xbf, 0x4b, 0x84, 0x8c, 0xf0, 0xe3, 0x0c,
+	0x85, 0xa4, 0x73, 0x38, 0x52, 0xae, 0x0e, 0xc7, 0x58, 0x62, 0xee, 0x24, 0x1e, 0x54, 0x94, 0x33,
+	0x8d, 0x6f, 0xd1, 0xb5, 0x9a, 0x56, 0xab, 0x1a, 0x15, 0xb6, 0x8a, 0xf5, 0x62, 0x21, 0xe6, 0x8c,
+	0x8f, 0x5c, 0xdb, 0xc4, 0x16, 0x36, 0x21, 0x50, 0xea, 0xb2, 0xb0, 0xef, 0xee, 0x34, 0xad, 0x56,
+	0x25, 0xd2, 0x67, 0xf2, 0x00, 0x9c, 0x37, 0x4c, 0xc8, 0xcb, 0x0b, 0xb7, 0xd4, 0xb4, 0x5a, 0xfb,
+	0x51, 0x6e, 0xd1, 0xaf, 0x96, 0xb9, 0xf9, 0x26, 0x1b, 0xfd, 0x87, 0x9b, 0x9f, 0x83, 0x33, 0x99,
+	0x67, 0x1c, 0xc7, 0xfa, 0xee, 0x83, 0x76, 0xc3, 0xcf, 0x06, 0xfe, 0x1f, 0x78, 0x3f, 0xec, 0xf7,
+	0x38, 0x8e, 0xa3, 0x3c, 0xf7, 0xaf, 0xdf, 0xf6, 0x18, 0x1c, 0x93, 0x49, 0x00, 0x9c, 0xee, 0x55,
+	0x2f, 0x7a, 0xf5, 0xba, 0x76, 0x8f, 0x54, 0xa0, 0xd4, 0xbd, 0x0a, 0xfb, 0x35, 0x8b, 0x38, 0x60,
+	0x87, 0xfd, 0x9a, 0x4d, 0x03, 0xd3, 0xc2, 0x05, 0x4e, 0x71, 0xab, 0x16, 0xa8, 0x0f, 0x35, 0x75,
+	0x8e, 0x30, 0xc5, 0xf9, 0x36, 0xf9, 0x6d, 0xa8, 0xab, 0x73, 0x88, 0x69, 0x87, 0xa5, 0xe3, 0x64,
+	0xb2, 0x4d, 0xcd, 0x67, 0x1b, 0xf6, 0xcc, 0x25, 0x22, 0x63, 0xa9, 0x40, 0xf2, 0x04, 0xca, 0x4a,
+	0x25, 0xc2, 0xb5, 0x9a, 0x3b, 0xad, 0xdd, 0xf6, 0xc9, 0x62, 0x34, 0x8b, 0x04, 0x63, 0x98, 0x1c,
+	0xef, 0x9b, 0x05, 0x25, 0x65, 0xff, 0x73, 0x13, 0x3e, 0x90, 0x6b, 0xe4, 0x77, 0xc8, 0xaf, 0x91,
+	0x27, 0xf1, 0xb4, 0x3b, 0xbb, 0x1d, 0x20, 0xcf, 0x77, 0xb2, 0x21, 0xa2, 0x74, 0xd1, 0x41, 0x2e,
+	0xf5, 0x6e, 0xaa, 0x91, 0x3e, 0x93, 0x06, 0x54, 0x8d, 0xe8, 0x46, 0x2f, 0xa5, 0x1e, 0x7f, 0x35,
+	0x5a, 0x3a, 0x48, 0x1d, 0xca, 0x97, 0xbd, 0x2e, 0x4a, 0xb7, 0xac, 0x23, 0xc6, 0x28, 0xf4, 0xe5,
+	0x6c, 0xd4, 0xd7, 0xfd, 0x95, 0x1d, 0xbe, 0x80, 0x93, 0xb5, 0xd1, 0xe5, 0xe3, 0xa0, 0xb0, 0xd7,
+	0x99, 0x26, 0x98, 0x4a, 0xe3, 0xcf, 0x9b, 0x5b, 0xf1, 0xb5, 0x7f, 0xee, 0xc0, 0xae, 0xaa, 0x56,
+	0xbd, 0x24, 0x43, 0x24, 0x21, 0x94, 0xd4, 0xa3, 0x21, 0xc7, 0x8b, 0xd9, 0xfd, 0xf6, 0x84, 0xbc,
+	0xda, 0xfa, 0x40, 0xa9, 0xfb, 0xe9, 0xfb, 0x8f, 0x2f, 0x36, 0xa1, 0xfb, 0xc1, 0xdd, 0xd3, 0x40,
+	0xcd, 0x35, 0x98, 0x26, 0x42, 0x9e, 0x5b, 0x67, 0xe4, 0x3d, 0x38, 0xa6, 0x49, 0x52, 0xac, 0x61,
+	0xe5, 0xe9, 0x6d, 0x80, 0x79, 0x1a, 0x56, 0xa7, 0x87, 0x05, 0x6c, 0xa8, 0x2b, 0x72, 0x9c, 0x11,
+	0xf8, 0x12, 0xb7, 0x22, 0xf8, 0xad, 0x70, 0x33, 0x5d, 0x91, 0xe3, 0x8c, 0x96, 0x97, 0xb8, 0x15,
+	0x6d, 0x6f, 0x85, 0x1b, 0xe9, 0x0a, 0x85, 0x7b, 0x0b, 0x65, 0xad, 0x74, 0x52, 0x5f, 0x96, 0x2d,
+	0x85, 0xbf, 0x01, 0x76, 0xaa, 0x61, 0xc7, 0xf4, 0xa0, 0x80, 0x71, 0x55, 0xa0, 0x58, 0x1f, 0xa0,
+	0x5a, 0xac, 0x92, 0xb8, 0x8b, 0xca, 0xf5, 0x87, 0xe1, 0x9d, 0x6e, 0x88, 0xe4, 0xf0, 0x47, 0x1a,
+	0xfe, 0x90, 0x92, 0x02, 0x3e, 0xc1, 0x74, 0xa8, 0x73, 0xce, 0xad, 0xb3, 0x81, 0xa3, 0x7f, 0x91,
+	0xcf, 0x7e, 0x05, 0x00, 0x00, 0xff, 0xff, 0xc8, 0x3d, 0xc7, 0xac, 0x52, 0x05, 0x00, 0x00,
 }

+ 342 - 0
pb/user.pb.gw.go

@@ -0,0 +1,342 @@
+// Code generated by protoc-gen-grpc-gateway. DO NOT EDIT.
+// source: user.proto
+
+/*
+Package pb is a reverse proxy.
+
+It translates gRPC into RESTful JSON APIs.
+*/
+package pb
+
+import (
+	"io"
+	"net/http"
+
+	"github.com/golang/protobuf/proto"
+	"github.com/grpc-ecosystem/grpc-gateway/runtime"
+	"github.com/grpc-ecosystem/grpc-gateway/utilities"
+	"golang.org/x/net/context"
+	"google.golang.org/grpc"
+	"google.golang.org/grpc/codes"
+	"google.golang.org/grpc/grpclog"
+	"google.golang.org/grpc/status"
+)
+
+var _ codes.Code
+var _ io.Reader
+var _ status.Status
+var _ = runtime.String
+var _ = utilities.NewDoubleArray
+
+func request_UserService_List_0(ctx context.Context, marshaler runtime.Marshaler, client UserServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
+	var protoReq UserListRequest
+	var metadata runtime.ServerMetadata
+
+	if err := marshaler.NewDecoder(req.Body).Decode(&protoReq); err != nil {
+		return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
+	}
+
+	msg, err := client.List(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
+	return msg, metadata, err
+
+}
+
+func request_UserService_Create_0(ctx context.Context, marshaler runtime.Marshaler, client UserServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
+	var protoReq UserCreateRequest
+	var metadata runtime.ServerMetadata
+
+	if err := marshaler.NewDecoder(req.Body).Decode(&protoReq); err != nil {
+		return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
+	}
+
+	msg, err := client.Create(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
+	return msg, metadata, err
+
+}
+
+func request_UserService_Update_0(ctx context.Context, marshaler runtime.Marshaler, client UserServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
+	var protoReq UserUpdateRequest
+	var metadata runtime.ServerMetadata
+
+	if err := marshaler.NewDecoder(req.Body).Decode(&protoReq); err != nil {
+		return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
+	}
+
+	msg, err := client.Update(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
+	return msg, metadata, err
+
+}
+
+func request_UserService_Delete_0(ctx context.Context, marshaler runtime.Marshaler, client UserServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
+	var protoReq UserDeleteRequest
+	var metadata runtime.ServerMetadata
+
+	if err := marshaler.NewDecoder(req.Body).Decode(&protoReq); err != nil {
+		return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
+	}
+
+	msg, err := client.Delete(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
+	return msg, metadata, err
+
+}
+
+func request_UserService_Renew_0(ctx context.Context, marshaler runtime.Marshaler, client UserServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
+	var protoReq UserRenewRequest
+	var metadata runtime.ServerMetadata
+
+	if err := marshaler.NewDecoder(req.Body).Decode(&protoReq); err != nil {
+		return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
+	}
+
+	msg, err := client.Renew(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
+	return msg, metadata, err
+
+}
+
+func request_UserService_GenConfig_0(ctx context.Context, marshaler runtime.Marshaler, client UserServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
+	var protoReq UserGenConfigRequest
+	var metadata runtime.ServerMetadata
+
+	if err := marshaler.NewDecoder(req.Body).Decode(&protoReq); err != nil {
+		return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
+	}
+
+	msg, err := client.GenConfig(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
+	return msg, metadata, err
+
+}
+
+// RegisterUserServiceHandlerFromEndpoint is same as RegisterUserServiceHandler but
+// automatically dials to "endpoint" and closes the connection when "ctx" gets done.
+func RegisterUserServiceHandlerFromEndpoint(ctx context.Context, mux *runtime.ServeMux, endpoint string, opts []grpc.DialOption) (err error) {
+	conn, err := grpc.Dial(endpoint, opts...)
+	if err != nil {
+		return err
+	}
+	defer func() {
+		if err != nil {
+			if cerr := conn.Close(); cerr != nil {
+				grpclog.Printf("Failed to close conn to %s: %v", endpoint, cerr)
+			}
+			return
+		}
+		go func() {
+			<-ctx.Done()
+			if cerr := conn.Close(); cerr != nil {
+				grpclog.Printf("Failed to close conn to %s: %v", endpoint, cerr)
+			}
+		}()
+	}()
+
+	return RegisterUserServiceHandler(ctx, mux, conn)
+}
+
+// RegisterUserServiceHandler registers the http handlers for service UserService to "mux".
+// The handlers forward requests to the grpc endpoint over "conn".
+func RegisterUserServiceHandler(ctx context.Context, mux *runtime.ServeMux, conn *grpc.ClientConn) error {
+	client := NewUserServiceClient(conn)
+
+	mux.Handle("POST", pattern_UserService_List_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
+		ctx, cancel := context.WithCancel(ctx)
+		defer cancel()
+		if cn, ok := w.(http.CloseNotifier); ok {
+			go func(done <-chan struct{}, closed <-chan bool) {
+				select {
+				case <-done:
+				case <-closed:
+					cancel()
+				}
+			}(ctx.Done(), cn.CloseNotify())
+		}
+		inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
+		rctx, err := runtime.AnnotateContext(ctx, mux, req)
+		if err != nil {
+			runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
+			return
+		}
+		resp, md, err := request_UserService_List_0(rctx, inboundMarshaler, client, req, pathParams)
+		ctx = runtime.NewServerMetadataContext(ctx, md)
+		if err != nil {
+			runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
+			return
+		}
+
+		forward_UserService_List_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
+
+	})
+
+	mux.Handle("POST", pattern_UserService_Create_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
+		ctx, cancel := context.WithCancel(ctx)
+		defer cancel()
+		if cn, ok := w.(http.CloseNotifier); ok {
+			go func(done <-chan struct{}, closed <-chan bool) {
+				select {
+				case <-done:
+				case <-closed:
+					cancel()
+				}
+			}(ctx.Done(), cn.CloseNotify())
+		}
+		inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
+		rctx, err := runtime.AnnotateContext(ctx, mux, req)
+		if err != nil {
+			runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
+			return
+		}
+		resp, md, err := request_UserService_Create_0(rctx, inboundMarshaler, client, req, pathParams)
+		ctx = runtime.NewServerMetadataContext(ctx, md)
+		if err != nil {
+			runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
+			return
+		}
+
+		forward_UserService_Create_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
+
+	})
+
+	mux.Handle("POST", pattern_UserService_Update_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
+		ctx, cancel := context.WithCancel(ctx)
+		defer cancel()
+		if cn, ok := w.(http.CloseNotifier); ok {
+			go func(done <-chan struct{}, closed <-chan bool) {
+				select {
+				case <-done:
+				case <-closed:
+					cancel()
+				}
+			}(ctx.Done(), cn.CloseNotify())
+		}
+		inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
+		rctx, err := runtime.AnnotateContext(ctx, mux, req)
+		if err != nil {
+			runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
+			return
+		}
+		resp, md, err := request_UserService_Update_0(rctx, inboundMarshaler, client, req, pathParams)
+		ctx = runtime.NewServerMetadataContext(ctx, md)
+		if err != nil {
+			runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
+			return
+		}
+
+		forward_UserService_Update_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
+
+	})
+
+	mux.Handle("POST", pattern_UserService_Delete_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
+		ctx, cancel := context.WithCancel(ctx)
+		defer cancel()
+		if cn, ok := w.(http.CloseNotifier); ok {
+			go func(done <-chan struct{}, closed <-chan bool) {
+				select {
+				case <-done:
+				case <-closed:
+					cancel()
+				}
+			}(ctx.Done(), cn.CloseNotify())
+		}
+		inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
+		rctx, err := runtime.AnnotateContext(ctx, mux, req)
+		if err != nil {
+			runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
+			return
+		}
+		resp, md, err := request_UserService_Delete_0(rctx, inboundMarshaler, client, req, pathParams)
+		ctx = runtime.NewServerMetadataContext(ctx, md)
+		if err != nil {
+			runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
+			return
+		}
+
+		forward_UserService_Delete_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
+
+	})
+
+	mux.Handle("POST", pattern_UserService_Renew_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
+		ctx, cancel := context.WithCancel(ctx)
+		defer cancel()
+		if cn, ok := w.(http.CloseNotifier); ok {
+			go func(done <-chan struct{}, closed <-chan bool) {
+				select {
+				case <-done:
+				case <-closed:
+					cancel()
+				}
+			}(ctx.Done(), cn.CloseNotify())
+		}
+		inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
+		rctx, err := runtime.AnnotateContext(ctx, mux, req)
+		if err != nil {
+			runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
+			return
+		}
+		resp, md, err := request_UserService_Renew_0(rctx, inboundMarshaler, client, req, pathParams)
+		ctx = runtime.NewServerMetadataContext(ctx, md)
+		if err != nil {
+			runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
+			return
+		}
+
+		forward_UserService_Renew_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
+
+	})
+
+	mux.Handle("POST", pattern_UserService_GenConfig_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
+		ctx, cancel := context.WithCancel(ctx)
+		defer cancel()
+		if cn, ok := w.(http.CloseNotifier); ok {
+			go func(done <-chan struct{}, closed <-chan bool) {
+				select {
+				case <-done:
+				case <-closed:
+					cancel()
+				}
+			}(ctx.Done(), cn.CloseNotify())
+		}
+		inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
+		rctx, err := runtime.AnnotateContext(ctx, mux, req)
+		if err != nil {
+			runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
+			return
+		}
+		resp, md, err := request_UserService_GenConfig_0(rctx, inboundMarshaler, client, req, pathParams)
+		ctx = runtime.NewServerMetadataContext(ctx, md)
+		if err != nil {
+			runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
+			return
+		}
+
+		forward_UserService_GenConfig_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
+
+	})
+
+	return nil
+}
+
+var (
+	pattern_UserService_List_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"v1", "user", "list"}, ""))
+
+	pattern_UserService_Create_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"v1", "user", "create"}, ""))
+
+	pattern_UserService_Update_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"v1", "user", "update"}, ""))
+
+	pattern_UserService_Delete_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"v1", "user", "delete"}, ""))
+
+	pattern_UserService_Renew_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"v1", "user", "renew"}, ""))
+
+	pattern_UserService_GenConfig_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"v1", "user", "genconfig"}, ""))
+)
+
+var (
+	forward_UserService_List_0 = runtime.ForwardResponseMessage
+
+	forward_UserService_Create_0 = runtime.ForwardResponseMessage
+
+	forward_UserService_Update_0 = runtime.ForwardResponseMessage
+
+	forward_UserService_Delete_0 = runtime.ForwardResponseMessage
+
+	forward_UserService_Renew_0 = runtime.ForwardResponseMessage
+
+	forward_UserService_GenConfig_0 = runtime.ForwardResponseMessage
+)

+ 42 - 6
pb/user.proto

@@ -2,6 +2,8 @@ syntax = "proto3";
 
 package pb;
 
+import "google/api/annotations.proto";
+
 message UserListRequest {
 
 }
@@ -39,12 +41,46 @@ message UserGenConfigRequest {
 }
 
 service UserService {
-  rpc List (UserListRequest) returns (UserResponse) {}
-  rpc Create (UserCreateRequest) returns (UserResponse) {}
-  rpc Update (UserUpdateRequest) returns (UserResponse) {}
-  rpc Delete (UserDeleteRequest) returns (UserResponse) {}
-  rpc Renew (UserRenewRequest) returns (UserResponse) {}
-  rpc GenConfig (UserGenConfigRequest) returns (UserGenConfigResponse) {}
+  rpc List (UserListRequest) returns (UserResponse) {
+    option (google.api.http) = {
+      post: "/v1/user/list"
+      body: "*"
+    };
+
+  }
+  rpc Create (UserCreateRequest) returns (UserResponse) {
+        option (google.api.http) = {
+          post: "/v1/user/create"
+          body: "*"
+        };
+  }
+  rpc Update (UserUpdateRequest) returns (UserResponse) {
+        option (google.api.http) = {
+      post: "/v1/user/update"
+      body: "*"
+    };
+
+  }
+  rpc Delete (UserDeleteRequest) returns (UserResponse) {
+        option (google.api.http) = {
+      post: "/v1/user/delete"
+      body: "*"
+    };
+
+  }
+  rpc Renew (UserRenewRequest) returns (UserResponse) {
+        option (google.api.http) = {
+      post: "/v1/user/renew"
+      body: "*"
+    };
+
+  }
+  rpc GenConfig (UserGenConfigRequest) returns (UserGenConfigResponse) {
+        option (google.api.http) = {
+      post: "/v1/user/genconfig"
+      body: "*"
+    };
+  }
 }
 
 message UserResponse {

+ 297 - 0
pb/user.swagger.json

@@ -0,0 +1,297 @@
+{
+  "swagger": "2.0",
+  "info": {
+    "title": "user.proto",
+    "version": "version not set"
+  },
+  "schemes": [
+    "http",
+    "https"
+  ],
+  "consumes": [
+    "application/json"
+  ],
+  "produces": [
+    "application/json"
+  ],
+  "paths": {
+    "/v1/user/create": {
+      "post": {
+        "operationId": "Create",
+        "responses": {
+          "200": {
+            "description": "",
+            "schema": {
+              "$ref": "#/definitions/pbUserResponse"
+            }
+          }
+        },
+        "parameters": [
+          {
+            "name": "body",
+            "in": "body",
+            "required": true,
+            "schema": {
+              "$ref": "#/definitions/pbUserCreateRequest"
+            }
+          }
+        ],
+        "tags": [
+          "UserService"
+        ]
+      }
+    },
+    "/v1/user/delete": {
+      "post": {
+        "operationId": "Delete",
+        "responses": {
+          "200": {
+            "description": "",
+            "schema": {
+              "$ref": "#/definitions/pbUserResponse"
+            }
+          }
+        },
+        "parameters": [
+          {
+            "name": "body",
+            "in": "body",
+            "required": true,
+            "schema": {
+              "$ref": "#/definitions/pbUserDeleteRequest"
+            }
+          }
+        ],
+        "tags": [
+          "UserService"
+        ]
+      }
+    },
+    "/v1/user/genconfig": {
+      "post": {
+        "operationId": "GenConfig",
+        "responses": {
+          "200": {
+            "description": "",
+            "schema": {
+              "$ref": "#/definitions/pbUserGenConfigResponse"
+            }
+          }
+        },
+        "parameters": [
+          {
+            "name": "body",
+            "in": "body",
+            "required": true,
+            "schema": {
+              "$ref": "#/definitions/pbUserGenConfigRequest"
+            }
+          }
+        ],
+        "tags": [
+          "UserService"
+        ]
+      }
+    },
+    "/v1/user/list": {
+      "post": {
+        "operationId": "List",
+        "responses": {
+          "200": {
+            "description": "",
+            "schema": {
+              "$ref": "#/definitions/pbUserResponse"
+            }
+          }
+        },
+        "parameters": [
+          {
+            "name": "body",
+            "in": "body",
+            "required": true,
+            "schema": {
+              "$ref": "#/definitions/pbUserListRequest"
+            }
+          }
+        ],
+        "tags": [
+          "UserService"
+        ]
+      }
+    },
+    "/v1/user/renew": {
+      "post": {
+        "operationId": "Renew",
+        "responses": {
+          "200": {
+            "description": "",
+            "schema": {
+              "$ref": "#/definitions/pbUserResponse"
+            }
+          }
+        },
+        "parameters": [
+          {
+            "name": "body",
+            "in": "body",
+            "required": true,
+            "schema": {
+              "$ref": "#/definitions/pbUserRenewRequest"
+            }
+          }
+        ],
+        "tags": [
+          "UserService"
+        ]
+      }
+    },
+    "/v1/user/update": {
+      "post": {
+        "operationId": "Update",
+        "responses": {
+          "200": {
+            "description": "",
+            "schema": {
+              "$ref": "#/definitions/pbUserResponse"
+            }
+          }
+        },
+        "parameters": [
+          {
+            "name": "body",
+            "in": "body",
+            "required": true,
+            "schema": {
+              "$ref": "#/definitions/pbUserUpdateRequest"
+            }
+          }
+        ],
+        "tags": [
+          "UserService"
+        ]
+      }
+    }
+  },
+  "definitions": {
+    "UserResponseUser": {
+      "type": "object",
+      "properties": {
+        "Username": {
+          "type": "string"
+        },
+        "ServerSerialNumber": {
+          "type": "string"
+        },
+        "Cert": {
+          "type": "string"
+        },
+        "CreatedAt": {
+          "type": "string"
+        },
+        "IPNet": {
+          "type": "string"
+        },
+        "NoGW": {
+          "type": "boolean",
+          "format": "boolean"
+        },
+        "HostID": {
+          "type": "integer",
+          "format": "int64"
+        }
+      }
+    },
+    "UserUpdateRequestGWPref": {
+      "type": "string",
+      "enum": [
+        "NOPREF",
+        "NOGW",
+        "GW"
+      ],
+      "default": "NOPREF"
+    },
+    "pbUserCreateRequest": {
+      "type": "object",
+      "properties": {
+        "Username": {
+          "type": "string"
+        },
+        "Password": {
+          "type": "string"
+        },
+        "NoGW": {
+          "type": "boolean",
+          "format": "boolean"
+        },
+        "HostID": {
+          "type": "integer",
+          "format": "int64"
+        }
+      }
+    },
+    "pbUserDeleteRequest": {
+      "type": "object",
+      "properties": {
+        "Username": {
+          "type": "string"
+        }
+      }
+    },
+    "pbUserGenConfigRequest": {
+      "type": "object",
+      "properties": {
+        "Username": {
+          "type": "string"
+        }
+      }
+    },
+    "pbUserGenConfigResponse": {
+      "type": "object",
+      "properties": {
+        "ClientConfig": {
+          "type": "string"
+        }
+      }
+    },
+    "pbUserListRequest": {
+      "type": "object"
+    },
+    "pbUserRenewRequest": {
+      "type": "object",
+      "properties": {
+        "Username": {
+          "type": "string"
+        }
+      }
+    },
+    "pbUserResponse": {
+      "type": "object",
+      "properties": {
+        "users": {
+          "type": "array",
+          "items": {
+            "$ref": "#/definitions/UserResponseUser"
+          }
+        }
+      }
+    },
+    "pbUserUpdateRequest": {
+      "type": "object",
+      "properties": {
+        "Username": {
+          "type": "string"
+        },
+        "Password": {
+          "type": "string"
+        },
+        "gwpref": {
+          "$ref": "#/definitions/UserUpdateRequestGWPref"
+        },
+        "HostID": {
+          "type": "integer",
+          "format": "int64"
+        }
+      }
+    }
+  }
+}

+ 24 - 19
pb/vpn.pb.go

@@ -6,6 +6,7 @@ package pb
 import proto "github.com/golang/protobuf/proto"
 import fmt "fmt"
 import math "math"
+import _ "google.golang.org/genproto/googleapis/api/annotations"
 
 import (
 	context "golang.org/x/net/context"
@@ -252,23 +253,27 @@ var _VPNService_serviceDesc = grpc.ServiceDesc{
 func init() { proto.RegisterFile("vpn.proto", fileDescriptor1) }
 
 var fileDescriptor1 = []byte{
-	// 278 bytes of a gzipped FileDescriptorProto
-	0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x74, 0x91, 0x4f, 0x4f, 0x83, 0x40,
-	0x10, 0xc5, 0xa5, 0x45, 0x2c, 0x13, 0xa3, 0xed, 0xf8, 0x27, 0x1b, 0xe2, 0xc1, 0xec, 0xc9, 0x13,
-	0x89, 0x7a, 0xf0, 0x6a, 0xc3, 0x45, 0x0f, 0x12, 0xd2, 0x26, 0xbd, 0x83, 0xce, 0x81, 0x68, 0x01,
-	0x77, 0x87, 0xc6, 0xef, 0xec, 0x97, 0x30, 0xbb, 0x8b, 0xa5, 0x34, 0xe9, 0xed, 0xed, 0x6f, 0x67,
-	0xde, 0x64, 0xde, 0x40, 0xb8, 0x69, 0xaa, 0xb8, 0x51, 0x35, 0xd7, 0x38, 0x6a, 0x0a, 0x89, 0x30,
-	0x5d, 0x65, 0xe9, 0x92, 0x73, 0x6e, 0xf5, 0x82, 0xbe, 0x5b, 0xd2, 0x2c, 0x9f, 0xe1, 0x6c, 0x95,
-	0xa5, 0xaf, 0x55, 0xc9, 0x1d, 0xc1, 0x08, 0x26, 0x2f, 0xb5, 0xe6, 0x2a, 0x5f, 0x93, 0xf0, 0x6e,
-	0xbd, 0xbb, 0x70, 0xb1, 0x7d, 0x23, 0x82, 0x9f, 0xd5, 0x8a, 0xc5, 0xc8, 0x72, 0xab, 0xe5, 0xaf,
-	0x07, 0xb3, 0x1d, 0x5b, 0xdd, 0xd4, 0x95, 0xb6, 0x95, 0x69, 0xef, 0x60, 0x35, 0x4a, 0x38, 0x5d,
-	0x92, 0x2a, 0xf3, 0xaf, 0xb4, 0x5d, 0x17, 0xa4, 0x3a, 0x97, 0x01, 0x1b, 0x4c, 0x1f, 0x1f, 0x98,
-	0xee, 0xf7, 0xd3, 0x0d, 0x4b, 0x48, 0xb1, 0x38, 0x76, 0xcc, 0x68, 0xbc, 0x86, 0x20, 0x99, 0x5b,
-	0x1a, 0x58, 0xda, 0xbd, 0x70, 0x0a, 0xe3, 0x94, 0x58, 0x9c, 0x58, 0x68, 0xa4, 0xe9, 0x7e, 0xcb,
-	0xf5, 0xa7, 0x98, 0xb8, 0x6e, 0xa3, 0xf1, 0x06, 0xc2, 0x44, 0x51, 0xce, 0xf4, 0x31, 0x67, 0x11,
-	0xda, 0x8f, 0x1e, 0xc8, 0x19, 0x9c, 0x6f, 0xf3, 0x72, 0xab, 0x3e, 0xfc, 0x00, 0x98, 0xfd, 0x49,
-	0x6d, 0xca, 0x77, 0xc2, 0x27, 0x08, 0x5c, 0x14, 0x78, 0x19, 0x37, 0x45, 0xbc, 0x1f, 0x78, 0x74,
-	0xb5, 0x47, 0x9d, 0x89, 0x3c, 0xc2, 0x7b, 0xf0, 0x8d, 0x2d, 0x62, 0x57, 0xb0, 0x73, 0x93, 0xe8,
-	0x62, 0xc0, 0xfe, 0x5b, 0x8a, 0xc0, 0xde, 0xf6, 0xf1, 0x2f, 0x00, 0x00, 0xff, 0xff, 0xc0, 0x1d,
-	0xb6, 0x7e, 0xe8, 0x01, 0x00, 0x00,
+	// 341 bytes of a gzipped FileDescriptorProto
+	0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x74, 0x92, 0xcd, 0x4e, 0xfa, 0x40,
+	0x14, 0xc5, 0x53, 0xe0, 0xdf, 0x3f, 0xbd, 0x21, 0x08, 0x17, 0x3f, 0x6a, 0xc3, 0xc2, 0xcc, 0xca,
+	0xb0, 0xa0, 0x51, 0x77, 0xac, 0x24, 0x6c, 0x70, 0x61, 0xd3, 0x40, 0xc2, 0x7e, 0xaa, 0x13, 0xd2,
+	0x08, 0x33, 0xb5, 0x73, 0xe9, 0x03, 0xf8, 0x0a, 0xbe, 0x84, 0xef, 0xe3, 0x2b, 0xb8, 0xf3, 0x25,
+	0xcc, 0x4c, 0x2b, 0x5f, 0x89, 0xbb, 0x33, 0xbf, 0xb9, 0xf7, 0x9c, 0xf4, 0x74, 0xc0, 0x2b, 0x32,
+	0x39, 0xcc, 0x72, 0x45, 0x0a, 0x6b, 0x59, 0x12, 0xf4, 0x97, 0x4a, 0x2d, 0x57, 0x22, 0xe4, 0x59,
+	0x1a, 0x72, 0x29, 0x15, 0x71, 0x4a, 0x95, 0xd4, 0xe5, 0x04, 0x43, 0xe8, 0x2c, 0xe2, 0x68, 0x4e,
+	0x9c, 0x36, 0x7a, 0x26, 0x5e, 0x37, 0x42, 0x13, 0xbb, 0x87, 0xf6, 0x22, 0x8e, 0x1e, 0x64, 0x4a,
+	0x15, 0xc1, 0x00, 0x9a, 0x53, 0xa5, 0x49, 0xf2, 0xb5, 0xf0, 0x9d, 0x2b, 0xe7, 0xda, 0x9b, 0x6d,
+	0xcf, 0x88, 0xd0, 0x88, 0x55, 0x4e, 0x7e, 0xcd, 0x72, 0xab, 0xd9, 0xb7, 0x03, 0xdd, 0x3d, 0x5b,
+	0x9d, 0x29, 0xa9, 0xed, 0x64, 0xb4, 0x73, 0xb0, 0x1a, 0x19, 0xb4, 0xe6, 0x22, 0x4f, 0xf9, 0x2a,
+	0xda, 0xac, 0x13, 0x91, 0x57, 0x2e, 0x07, 0xec, 0x20, 0xbd, 0xfe, 0x47, 0x7a, 0x63, 0x97, 0x6e,
+	0xd8, 0x44, 0xe4, 0xe4, 0xff, 0x2b, 0x99, 0xd1, 0x78, 0x0e, 0xee, 0x64, 0x6c, 0xa9, 0x6b, 0x69,
+	0x75, 0xc2, 0x0e, 0xd4, 0x23, 0x41, 0xfe, 0x7f, 0x0b, 0x8d, 0x34, 0xdb, 0x8f, 0x5c, 0xbf, 0xf8,
+	0xcd, 0x72, 0xdb, 0x68, 0xec, 0x83, 0x37, 0xc9, 0x05, 0x27, 0xf1, 0x3c, 0x26, 0xdf, 0xb3, 0x17,
+	0x3b, 0xc0, 0xba, 0x70, 0xb2, 0xed, 0xab, 0xfc, 0xd4, 0xdb, 0x0f, 0x07, 0xc0, 0x14, 0x20, 0xf2,
+	0x22, 0x7d, 0x12, 0x18, 0x83, 0x5b, 0x76, 0x81, 0xa7, 0xc3, 0x2c, 0x19, 0x1e, 0x37, 0x1e, 0x9c,
+	0x1d, 0xd1, 0xd2, 0x85, 0x5d, 0xbe, 0x7d, 0x7e, 0xbd, 0xd7, 0x7a, 0xac, 0x1d, 0x16, 0x37, 0x61,
+	0x91, 0xc9, 0x50, 0xdb, 0xfb, 0x91, 0x33, 0xc0, 0x29, 0x34, 0x4c, 0x20, 0x62, 0xb5, 0xb9, 0xf7,
+	0xb7, 0x82, 0xde, 0x01, 0xab, 0xbc, 0x2e, 0xac, 0x57, 0x97, 0xb5, 0x7e, 0xbd, 0x52, 0x99, 0xd2,
+	0xc8, 0x19, 0x24, 0xae, 0x7d, 0x08, 0x77, 0x3f, 0x01, 0x00, 0x00, 0xff, 0xff, 0x17, 0xd3, 0x4c,
+	0xab, 0x37, 0x02, 0x00, 0x00,
 }

+ 158 - 0
pb/vpn.pb.gw.go

@@ -0,0 +1,158 @@
+// Code generated by protoc-gen-grpc-gateway. DO NOT EDIT.
+// source: vpn.proto
+
+/*
+Package pb is a reverse proxy.
+
+It translates gRPC into RESTful JSON APIs.
+*/
+package pb
+
+import (
+	"io"
+	"net/http"
+
+	"github.com/golang/protobuf/proto"
+	"github.com/grpc-ecosystem/grpc-gateway/runtime"
+	"github.com/grpc-ecosystem/grpc-gateway/utilities"
+	"golang.org/x/net/context"
+	"google.golang.org/grpc"
+	"google.golang.org/grpc/codes"
+	"google.golang.org/grpc/grpclog"
+	"google.golang.org/grpc/status"
+)
+
+var _ codes.Code
+var _ io.Reader
+var _ status.Status
+var _ = runtime.String
+var _ = utilities.NewDoubleArray
+
+func request_VPNService_Status_0(ctx context.Context, marshaler runtime.Marshaler, client VPNServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
+	var protoReq VPNStatusRequest
+	var metadata runtime.ServerMetadata
+
+	if err := marshaler.NewDecoder(req.Body).Decode(&protoReq); err != nil {
+		return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
+	}
+
+	msg, err := client.Status(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
+	return msg, metadata, err
+
+}
+
+func request_VPNService_Init_0(ctx context.Context, marshaler runtime.Marshaler, client VPNServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
+	var protoReq VPNInitRequest
+	var metadata runtime.ServerMetadata
+
+	if err := marshaler.NewDecoder(req.Body).Decode(&protoReq); err != nil {
+		return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
+	}
+
+	msg, err := client.Init(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
+	return msg, metadata, err
+
+}
+
+// RegisterVPNServiceHandlerFromEndpoint is same as RegisterVPNServiceHandler but
+// automatically dials to "endpoint" and closes the connection when "ctx" gets done.
+func RegisterVPNServiceHandlerFromEndpoint(ctx context.Context, mux *runtime.ServeMux, endpoint string, opts []grpc.DialOption) (err error) {
+	conn, err := grpc.Dial(endpoint, opts...)
+	if err != nil {
+		return err
+	}
+	defer func() {
+		if err != nil {
+			if cerr := conn.Close(); cerr != nil {
+				grpclog.Printf("Failed to close conn to %s: %v", endpoint, cerr)
+			}
+			return
+		}
+		go func() {
+			<-ctx.Done()
+			if cerr := conn.Close(); cerr != nil {
+				grpclog.Printf("Failed to close conn to %s: %v", endpoint, cerr)
+			}
+		}()
+	}()
+
+	return RegisterVPNServiceHandler(ctx, mux, conn)
+}
+
+// RegisterVPNServiceHandler registers the http handlers for service VPNService to "mux".
+// The handlers forward requests to the grpc endpoint over "conn".
+func RegisterVPNServiceHandler(ctx context.Context, mux *runtime.ServeMux, conn *grpc.ClientConn) error {
+	client := NewVPNServiceClient(conn)
+
+	mux.Handle("POST", pattern_VPNService_Status_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
+		ctx, cancel := context.WithCancel(ctx)
+		defer cancel()
+		if cn, ok := w.(http.CloseNotifier); ok {
+			go func(done <-chan struct{}, closed <-chan bool) {
+				select {
+				case <-done:
+				case <-closed:
+					cancel()
+				}
+			}(ctx.Done(), cn.CloseNotify())
+		}
+		inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
+		rctx, err := runtime.AnnotateContext(ctx, mux, req)
+		if err != nil {
+			runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
+			return
+		}
+		resp, md, err := request_VPNService_Status_0(rctx, inboundMarshaler, client, req, pathParams)
+		ctx = runtime.NewServerMetadataContext(ctx, md)
+		if err != nil {
+			runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
+			return
+		}
+
+		forward_VPNService_Status_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
+
+	})
+
+	mux.Handle("POST", pattern_VPNService_Init_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
+		ctx, cancel := context.WithCancel(ctx)
+		defer cancel()
+		if cn, ok := w.(http.CloseNotifier); ok {
+			go func(done <-chan struct{}, closed <-chan bool) {
+				select {
+				case <-done:
+				case <-closed:
+					cancel()
+				}
+			}(ctx.Done(), cn.CloseNotify())
+		}
+		inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
+		rctx, err := runtime.AnnotateContext(ctx, mux, req)
+		if err != nil {
+			runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
+			return
+		}
+		resp, md, err := request_VPNService_Init_0(rctx, inboundMarshaler, client, req, pathParams)
+		ctx = runtime.NewServerMetadataContext(ctx, md)
+		if err != nil {
+			runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
+			return
+		}
+
+		forward_VPNService_Init_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
+
+	})
+
+	return nil
+}
+
+var (
+	pattern_VPNService_Status_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"v1", "vpn", "status"}, ""))
+
+	pattern_VPNService_Init_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"v1", "vpn", "init"}, ""))
+)
+
+var (
+	forward_VPNService_Status_0 = runtime.ForwardResponseMessage
+
+	forward_VPNService_Init_0 = runtime.ForwardResponseMessage
+)

+ 12 - 2
pb/vpn.proto

@@ -2,6 +2,8 @@ syntax = "proto3";
 
 package pb;
 
+import "google/api/annotations.proto";
+
 message VPNStatusRequest {}
 message VPNInitRequest {
   string Hostname = 1;
@@ -9,8 +11,16 @@ message VPNInitRequest {
 }
 
 service VPNService {
-  rpc Status (VPNStatusRequest) returns (VPNStatusResponse) {}
-  rpc Init (VPNInitRequest) returns (VPNInitResponse) {}
+  rpc Status (VPNStatusRequest) returns (VPNStatusResponse) {
+    option (google.api.http) = {
+      post: "/v1/vpn/status"
+      body: "*"
+    };}
+  rpc Init (VPNInitRequest) returns (VPNInitResponse) {
+    option (google.api.http) = {
+      post: "/v1/vpn/init"
+      body: "*"
+    };}
 }
 
 message VPNStatusResponse {

+ 122 - 0
pb/vpn.swagger.json

@@ -0,0 +1,122 @@
+{
+  "swagger": "2.0",
+  "info": {
+    "title": "vpn.proto",
+    "version": "version not set"
+  },
+  "schemes": [
+    "http",
+    "https"
+  ],
+  "consumes": [
+    "application/json"
+  ],
+  "produces": [
+    "application/json"
+  ],
+  "paths": {
+    "/v1/vpn/init": {
+      "post": {
+        "operationId": "Init",
+        "responses": {
+          "200": {
+            "description": "",
+            "schema": {
+              "$ref": "#/definitions/pbVPNInitResponse"
+            }
+          }
+        },
+        "parameters": [
+          {
+            "name": "body",
+            "in": "body",
+            "required": true,
+            "schema": {
+              "$ref": "#/definitions/pbVPNInitRequest"
+            }
+          }
+        ],
+        "tags": [
+          "VPNService"
+        ]
+      }
+    },
+    "/v1/vpn/status": {
+      "post": {
+        "operationId": "Status",
+        "responses": {
+          "200": {
+            "description": "",
+            "schema": {
+              "$ref": "#/definitions/pbVPNStatusResponse"
+            }
+          }
+        },
+        "parameters": [
+          {
+            "name": "body",
+            "in": "body",
+            "required": true,
+            "schema": {
+              "$ref": "#/definitions/pbVPNStatusRequest"
+            }
+          }
+        ],
+        "tags": [
+          "VPNService"
+        ]
+      }
+    }
+  },
+  "definitions": {
+    "pbVPNInitRequest": {
+      "type": "object",
+      "properties": {
+        "Hostname": {
+          "type": "string"
+        },
+        "Port": {
+          "type": "string"
+        }
+      }
+    },
+    "pbVPNInitResponse": {
+      "type": "object"
+    },
+    "pbVPNStatusRequest": {
+      "type": "object"
+    },
+    "pbVPNStatusResponse": {
+      "type": "object",
+      "properties": {
+        "Name": {
+          "type": "string"
+        },
+        "SerialNumber": {
+          "type": "string"
+        },
+        "Hostname": {
+          "type": "string"
+        },
+        "Port": {
+          "type": "string"
+        },
+        "Cert": {
+          "type": "string"
+        },
+        "CACert": {
+          "type": "string"
+        },
+        "Net": {
+          "type": "string"
+        },
+        "Mask": {
+          "type": "string"
+        },
+        "CreatedAt": {
+          "type": "string"
+        }
+      }
+    }
+  }
+}

+ 3 - 1
vpn.go

@@ -1,5 +1,7 @@
 //go:generate go-bindata -pkg bindata -o bindata/bindata.go template/
-//go:generate protoc -I pb/ pb/user.proto pb/vpn.proto pb/network.proto --go_out=plugins=grpc:pb
+//go:generate protoc -I pb/ -I$GOPATH/src/github.com/grpc-ecosystem/grpc-gateway/third_party/googleapis pb/user.proto pb/vpn.proto pb/network.proto --go_out=plugins=grpc:pb
+//go:generate protoc -I pb/ -I$GOPATH/src/github.com/grpc-ecosystem/grpc-gateway/third_party/googleapis pb/user.proto pb/vpn.proto pb/network.proto --grpc-gateway_out=logtostderr=true:pb
+//go:generate protoc -I pb/ -I$GOPATH/src/github.com/grpc-ecosystem/grpc-gateway/third_party/googleapis pb/user.proto pb/vpn.proto pb/network.proto --swagger_out=logtostderr=true:pb
 
 package ovpm