From d2b7e5afd969983df792bc7ade35d53b281e5bfd Mon Sep 17 00:00:00 2001 From: yunchen Date: Fri, 22 Jun 2018 10:42:28 +0000 Subject: [PATCH 01/11] Add network controller Former-commit-id: 3b8a29de0aa98d685615d8f1275f1c680f1377b2 [formerly 28f7547ba0fa95a2b2e9c215c021867b6179b9fd] Former-commit-id: ef6a365ff731b723a40f7f1adde73f586c5138e9 --- src/networkcontroller/networkcontroller.go | 62 +++++ src/server/handler_network.go | 14 ++ vendor/vendor.json | 273 +++++++++++++++++++++ 3 files changed, 349 insertions(+) create mode 100644 src/networkcontroller/networkcontroller.go diff --git a/src/networkcontroller/networkcontroller.go b/src/networkcontroller/networkcontroller.go new file mode 100644 index 00000000..2856b8e2 --- /dev/null +++ b/src/networkcontroller/networkcontroller.go @@ -0,0 +1,62 @@ +package networkcontroller + +import ( + pb "github.com/linkernetworks/network-controller/messages" + "github.com/linkernetworks/vortex/src/entity" + k8sCtl "github.com/linkernetworks/vortex/src/kubernetes" + "golang.org/x/net/context" + "google.golang.org/grpc" + "k8s.io/client-go/kubernetes" + "time" +) + +type NetworkController struct { + Clientset kubernetes.Interface + ClientConn *grpc.ClientConn + Network entity.Network +} + +func New(clientset kubernetes.Interface, network entity.Network) (*NetworkController, error) { + node, err := k8sCtl.GetNode(clientset, network.Node) + if err != nil { + return nil, err + } + + var nodeIP string + for _, addr := range node.Status.Addresses { + if addr.Type == "ExternalIP" { + nodeIP = addr.Address + break + } + } + + // Set up a connection to the server. + conn, err := grpc.Dial(nodeIP, grpc.WithInsecure()) + if err != nil { + return nil, err + } + defer conn.Close() + + return &NetworkController{ + Clientset: clientset, + ClientConn: conn, + Network: network, + }, nil +} + +func (nc *NetworkController) CreateNetwork() error { + clientControl := pb.NewNetworkControlClient(nc.ClientConn) + ctx, cancel := context.WithTimeout(context.Background(), time.Second) + defer cancel() + + for _, port := range nc.Network.PhysicalPorts { + _, err := clientControl.AddPort(ctx, &pb.AddPortRequest{ + BridgeName: nc.Network.BridgeName, + IfaceName: port.Name}) + if err != nil { + return err + } + } + + return nil +} diff --git a/src/server/handler_network.go b/src/server/handler_network.go index 4262aa4e..f9f835b6 100644 --- a/src/server/handler_network.go +++ b/src/server/handler_network.go @@ -10,6 +10,7 @@ import ( "github.com/linkernetworks/vortex/src/entity" response "github.com/linkernetworks/vortex/src/net/http" "github.com/linkernetworks/vortex/src/net/http/query" + "github.com/linkernetworks/vortex/src/networkcontroller" "github.com/linkernetworks/vortex/src/web" mgo "gopkg.in/mgo.v2" "gopkg.in/mgo.v2/bson" @@ -42,6 +43,19 @@ func createNetworkHandler(ctx *web.Context) { } } + nc, err := networkcontroller.New(as.Kubernetes, network) + if err != nil { + logger.Error(err) + response.InternalServerError(req.Request, resp.ResponseWriter, err) + return + } + + if err := nc.CreateNetwork(); err != nil { + logger.Error(err) + response.InternalServerError(req.Request, resp.ResponseWriter, err) + return + } + network.ID = bson.NewObjectId() network.CreatedAt = timeutils.Now() if err := session.Insert(entity.NetworkCollectionName, &network); err != nil { diff --git a/vendor/vendor.json b/vendor/vendor.json index 25f67928..bed98e98 100644 --- a/vendor/vendor.json +++ b/vendor/vendor.json @@ -242,6 +242,18 @@ "revision": "759fb038e917fa2c92cf1c541cd6b0063394cf75", "revisionTime": "2018-05-24T10:14:37Z" }, + { + "checksumSHA1": "68e1u3tVjplIegtHjz2c8TprPJg=", + "path": "github.com/linkernetworks/network-controller/messages", + "revision": "f5afd26f4118f700c1c09c33368b9a218b23b43d", + "revisionTime": "2018-06-22T09:58:49Z" + }, + { + "checksumSHA1": "6xm1f1JNGEKoELwN4GXy/9/0HoM=", + "path": "github.com/linkernetworks/oauth/app/config", + "revision": "a7fe484fc0cf65696dd9479eb8bad1b2dd416ca9", + "revisionTime": "2018-05-31T10:18:20Z" + }, { "checksumSHA1": "V89FgGKA+7A70mAedEvmhDSCIyQ=", "path": "github.com/linkernetworks/oauth/entity", @@ -590,6 +602,12 @@ "revision": "db08ff08e8622530d9ed3a0e8ac279f6d4c02196", "revisionTime": "2018-06-11T16:35:41Z" }, + { + "checksumSHA1": "UxahDzW2v4mf/+aFxruuupaoIwo=", + "path": "golang.org/x/net/internal/timeseries", + "revision": "afe8f62b1d6bbd81f31868121a50b06d8188e1f9", + "revisionTime": "2018-06-20T20:20:43Z" + }, { "checksumSHA1": "sO3eKeIVIRXaRtmWbqGihYpJXpg=", "path": "golang.org/x/net/ipv4", @@ -597,6 +615,45 @@ "revisionTime": "2018-06-11T16:35:41Z" }, { +<<<<<<< 253e7e40213f87ea2d63837d4b82a64a0cf24285 +======= + "checksumSHA1": "rJn3m/27kO+2IU6KCCZ74Miby+8=", + "path": "golang.org/x/net/trace", + "revision": "afe8f62b1d6bbd81f31868121a50b06d8188e1f9", + "revisionTime": "2018-06-20T20:20:43Z" + }, + { + "checksumSHA1": "j0z/2h06wsvTkGiLaZ5XFLbMKfo=", + "path": "golang.org/x/oauth2", + "revision": "088f8e1d436e8d636f13cd83a345b3d6ff2f04ae", + "revisionTime": "2018-05-04T20:45:12Z" + }, + { + "checksumSHA1": "z7mSaGccufg15ki2YPd+M5PlsUc=", + "path": "golang.org/x/oauth2/google", + "revision": "088f8e1d436e8d636f13cd83a345b3d6ff2f04ae", + "revisionTime": "2018-05-04T20:45:12Z" + }, + { + "checksumSHA1": "3mJjldg4HJZppC5scDKEFgJ2z48=", + "path": "golang.org/x/oauth2/internal", + "revision": "088f8e1d436e8d636f13cd83a345b3d6ff2f04ae", + "revisionTime": "2018-05-04T20:45:12Z" + }, + { + "checksumSHA1": "huVltYnXdRFDJLgp/ZP9IALzG7g=", + "path": "golang.org/x/oauth2/jws", + "revision": "088f8e1d436e8d636f13cd83a345b3d6ff2f04ae", + "revisionTime": "2018-05-04T20:45:12Z" + }, + { + "checksumSHA1": "QPndO4ODVdEBILRhJ6869UDAoHc=", + "path": "golang.org/x/oauth2/jwt", + "revision": "088f8e1d436e8d636f13cd83a345b3d6ff2f04ae", + "revisionTime": "2018-05-04T20:45:12Z" + }, + { +>>>>>>> Add network controller "checksumSHA1": "g0ElG8ZOLLoSol7KoLtx9o7WFgg=", "path": "golang.org/x/sys/unix", "revision": "8883426083c04a2627e6e59d84d5f6fb63d16c91", @@ -650,6 +707,222 @@ "revision": "fbb02b2291d28baffd63558aa44b4b56f178d650", "revisionTime": "2018-04-12T16:56:04Z" }, + { + "checksumSHA1": "QoM8iwt2FVbTHR+Lav3dXmEu/7o=", + "path": "google.golang.org/appengine", + "revision": "b1f26356af11148e710935ed1ac8a7f5702c7612", + "revisionTime": "2018-05-21T22:34:13Z" + }, + { + "checksumSHA1": "x2UMjnBCqXdCFcKF4U925pCxmxQ=", + "path": "google.golang.org/appengine/internal", + "revision": "b1f26356af11148e710935ed1ac8a7f5702c7612", + "revisionTime": "2018-05-21T22:34:13Z" + }, + { + "checksumSHA1": "YI9+yxvbfgIihM3UXZfFwioAc88=", + "path": "google.golang.org/appengine/internal/app_identity", + "revision": "b1f26356af11148e710935ed1ac8a7f5702c7612", + "revisionTime": "2018-05-21T22:34:13Z" + }, + { + "checksumSHA1": "PJ+aP3+eOZn+ckAb4NZPHNAxESk=", + "path": "google.golang.org/appengine/internal/base", + "revision": "b1f26356af11148e710935ed1ac8a7f5702c7612", + "revisionTime": "2018-05-21T22:34:13Z" + }, + { + "checksumSHA1": "2JYgCZVGTTsBIhh29M5ItZGXQ7E=", + "path": "google.golang.org/appengine/internal/datastore", + "revision": "b1f26356af11148e710935ed1ac8a7f5702c7612", + "revisionTime": "2018-05-21T22:34:13Z" + }, + { + "checksumSHA1": "Tmunm9UyiE/Bs+JDU2ej2jTsFoY=", + "path": "google.golang.org/appengine/internal/log", + "revision": "b1f26356af11148e710935ed1ac8a7f5702c7612", + "revisionTime": "2018-05-21T22:34:13Z" + }, + { + "checksumSHA1": "0WONGA6dPWAV2Kex8qSXiID4Zxs=", + "path": "google.golang.org/appengine/internal/modules", + "revision": "b1f26356af11148e710935ed1ac8a7f5702c7612", + "revisionTime": "2018-05-21T22:34:13Z" + }, + { + "checksumSHA1": "ZZYm/rh5ssupiYTO/dazGw/IWZM=", + "path": "google.golang.org/appengine/internal/remote_api", + "revision": "b1f26356af11148e710935ed1ac8a7f5702c7612", + "revisionTime": "2018-05-21T22:34:13Z" + }, + { + "checksumSHA1": "bTGqlontu6VG532l5otdWy6f6m4=", + "path": "google.golang.org/appengine/internal/urlfetch", + "revision": "b1f26356af11148e710935ed1ac8a7f5702c7612", + "revisionTime": "2018-05-21T22:34:13Z" + }, + { + "checksumSHA1": "akOV9pYnCbcPA8wJUutSQVibdyg=", + "path": "google.golang.org/appengine/urlfetch", + "revision": "b1f26356af11148e710935ed1ac8a7f5702c7612", + "revisionTime": "2018-05-21T22:34:13Z" + }, + { + "checksumSHA1": "AubR8T/clx04wAEJlXwpwxI4uTM=", + "path": "google.golang.org/genproto/googleapis/rpc/status", + "revision": "80063a038e333bbe006c878e4c5ce4c74d055498", + "revisionTime": "2018-06-21T23:58:12Z" + }, + { + "checksumSHA1": "ic1jwBw73P4U67FPNixWxHOObPM=", + "path": "google.golang.org/grpc", + "revision": "ba63e52faf1676ef8bb26b6e0ba5acf78ff3b8e8", + "revisionTime": "2018-06-21T20:10:52Z" + }, + { + "checksumSHA1": "xX1+b0/gjwxrjocYH5W/LyQPjs4=", + "path": "google.golang.org/grpc/balancer", + "revision": "ba63e52faf1676ef8bb26b6e0ba5acf78ff3b8e8", + "revisionTime": "2018-06-21T20:10:52Z" + }, + { + "checksumSHA1": "lw+L836hLeH8+//le+C+ycddCCU=", + "path": "google.golang.org/grpc/balancer/base", + "revision": "ba63e52faf1676ef8bb26b6e0ba5acf78ff3b8e8", + "revisionTime": "2018-06-21T20:10:52Z" + }, + { + "checksumSHA1": "DJ1AtOk4Pu7bqtUMob95Hw8HPNw=", + "path": "google.golang.org/grpc/balancer/roundrobin", + "revision": "ba63e52faf1676ef8bb26b6e0ba5acf78ff3b8e8", + "revisionTime": "2018-06-21T20:10:52Z" + }, + { + "checksumSHA1": "R3tuACGAPyK4lr+oSNt1saUzC0M=", + "path": "google.golang.org/grpc/codes", + "revision": "ba63e52faf1676ef8bb26b6e0ba5acf78ff3b8e8", + "revisionTime": "2018-06-21T20:10:52Z" + }, + { + "checksumSHA1": "XH2WYcDNwVO47zYShREJjcYXm0Y=", + "path": "google.golang.org/grpc/connectivity", + "revision": "ba63e52faf1676ef8bb26b6e0ba5acf78ff3b8e8", + "revisionTime": "2018-06-21T20:10:52Z" + }, + { + "checksumSHA1": "KthiDKNPHMeIu967enqtE4NaZzI=", + "path": "google.golang.org/grpc/credentials", + "revision": "ba63e52faf1676ef8bb26b6e0ba5acf78ff3b8e8", + "revisionTime": "2018-06-21T20:10:52Z" + }, + { + "checksumSHA1": "cfLb+pzWB+Glwp82rgfcEST1mv8=", + "path": "google.golang.org/grpc/encoding", + "revision": "ba63e52faf1676ef8bb26b6e0ba5acf78ff3b8e8", + "revisionTime": "2018-06-21T20:10:52Z" + }, + { + "checksumSHA1": "LKKkn7EYA+Do9Qwb2/SUKLFNxoo=", + "path": "google.golang.org/grpc/encoding/proto", + "revision": "ba63e52faf1676ef8bb26b6e0ba5acf78ff3b8e8", + "revisionTime": "2018-06-21T20:10:52Z" + }, + { + "checksumSHA1": "ZPPSFisPDz2ANO4FBZIft+fRxyk=", + "path": "google.golang.org/grpc/grpclog", + "revision": "ba63e52faf1676ef8bb26b6e0ba5acf78ff3b8e8", + "revisionTime": "2018-06-21T20:10:52Z" + }, + { + "checksumSHA1": "cSdzm5GhbalJbWUNrN8pRdW0uks=", + "path": "google.golang.org/grpc/internal", + "revision": "ba63e52faf1676ef8bb26b6e0ba5acf78ff3b8e8", + "revisionTime": "2018-06-21T20:10:52Z" + }, + { + "checksumSHA1": "uDJA7QK2iGnEwbd9TPqkLaM+xuU=", + "path": "google.golang.org/grpc/internal/backoff", + "revision": "ba63e52faf1676ef8bb26b6e0ba5acf78ff3b8e8", + "revisionTime": "2018-06-21T20:10:52Z" + }, + { + "checksumSHA1": "DpRAlo/UzTvErgcJ9SUQ+lmTxws=", + "path": "google.golang.org/grpc/internal/channelz", + "revision": "ba63e52faf1676ef8bb26b6e0ba5acf78ff3b8e8", + "revisionTime": "2018-06-21T20:10:52Z" + }, + { + "checksumSHA1": "70gndc/uHwyAl3D45zqp7vyHWlo=", + "path": "google.golang.org/grpc/internal/grpcrand", + "revision": "ba63e52faf1676ef8bb26b6e0ba5acf78ff3b8e8", + "revisionTime": "2018-06-21T20:10:52Z" + }, + { + "checksumSHA1": "hcuHgKp8W0wIzoCnNfKI8NUss5o=", + "path": "google.golang.org/grpc/keepalive", + "revision": "ba63e52faf1676ef8bb26b6e0ba5acf78ff3b8e8", + "revisionTime": "2018-06-21T20:10:52Z" + }, + { + "checksumSHA1": "OjIAi5AzqlQ7kLtdAyjvdgMf6hc=", + "path": "google.golang.org/grpc/metadata", + "revision": "ba63e52faf1676ef8bb26b6e0ba5acf78ff3b8e8", + "revisionTime": "2018-06-21T20:10:52Z" + }, + { + "checksumSHA1": "VvGBoawND0urmYDy11FT+U1IHtU=", + "path": "google.golang.org/grpc/naming", + "revision": "ba63e52faf1676ef8bb26b6e0ba5acf78ff3b8e8", + "revisionTime": "2018-06-21T20:10:52Z" + }, + { + "checksumSHA1": "n5EgDdBqFMa2KQFhtl+FF/4gIFo=", + "path": "google.golang.org/grpc/peer", + "revision": "ba63e52faf1676ef8bb26b6e0ba5acf78ff3b8e8", + "revisionTime": "2018-06-21T20:10:52Z" + }, + { + "checksumSHA1": "QOKwFz4Zdfxfjs8czgCCtzM5bk4=", + "path": "google.golang.org/grpc/resolver", + "revision": "ba63e52faf1676ef8bb26b6e0ba5acf78ff3b8e8", + "revisionTime": "2018-06-21T20:10:52Z" + }, + { + "checksumSHA1": "30RAjcyNXLww43ikGOpiy3jg8WY=", + "path": "google.golang.org/grpc/resolver/dns", + "revision": "ba63e52faf1676ef8bb26b6e0ba5acf78ff3b8e8", + "revisionTime": "2018-06-21T20:10:52Z" + }, + { + "checksumSHA1": "zs9M4xE8Lyg4wvuYvR00XoBxmuw=", + "path": "google.golang.org/grpc/resolver/passthrough", + "revision": "ba63e52faf1676ef8bb26b6e0ba5acf78ff3b8e8", + "revisionTime": "2018-06-21T20:10:52Z" + }, + { + "checksumSHA1": "YclPgme2gT3S0hTkHVdE1zAxJdo=", + "path": "google.golang.org/grpc/stats", + "revision": "ba63e52faf1676ef8bb26b6e0ba5acf78ff3b8e8", + "revisionTime": "2018-06-21T20:10:52Z" + }, + { + "checksumSHA1": "t/NhHuykWsxY0gEBd2WIv5RVBK8=", + "path": "google.golang.org/grpc/status", + "revision": "ba63e52faf1676ef8bb26b6e0ba5acf78ff3b8e8", + "revisionTime": "2018-06-21T20:10:52Z" + }, + { + "checksumSHA1": "qvArRhlrww5WvRmbyMF2mUfbJew=", + "path": "google.golang.org/grpc/tap", + "revision": "ba63e52faf1676ef8bb26b6e0ba5acf78ff3b8e8", + "revisionTime": "2018-06-21T20:10:52Z" + }, + { + "checksumSHA1": "FmV+Y3VY7iRchu5m38iQTPMNAKc=", + "path": "google.golang.org/grpc/transport", + "revision": "ba63e52faf1676ef8bb26b6e0ba5acf78ff3b8e8", + "revisionTime": "2018-06-21T20:10:52Z" + }, { "checksumSHA1": "sToCp8GThnMnsBzsHv+L/tBYQrQ=", "path": "gopkg.in/alecthomas/kingpin.v2", From 2c021db6d2bf038cc98e0aeca59ded1c80977ca1 Mon Sep 17 00:00:00 2001 From: yunchen Date: Mon, 25 Jun 2018 04:00:39 +0000 Subject: [PATCH 02/11] Update networkcontrol for kubectl Former-commit-id: b6571e4474c047a09806c163f7598b862c8f81d6 [formerly b7e886e9adf4fa4e9a1a1a70633812818ff21005] Former-commit-id: e5a1c442654bd49cd18e30019ff18249184ff96d --- src/networkcontroller/networkcontroller.go | 30 +++++++++++----------- src/server/handler_network.go | 2 +- src/serviceprovider/serviceprovider.go | 28 ++++++++------------ vendor/vendor.json | 7 ++--- 4 files changed, 31 insertions(+), 36 deletions(-) diff --git a/src/networkcontroller/networkcontroller.go b/src/networkcontroller/networkcontroller.go index 2856b8e2..2087ac74 100644 --- a/src/networkcontroller/networkcontroller.go +++ b/src/networkcontroller/networkcontroller.go @@ -3,21 +3,21 @@ package networkcontroller import ( pb "github.com/linkernetworks/network-controller/messages" "github.com/linkernetworks/vortex/src/entity" - k8sCtl "github.com/linkernetworks/vortex/src/kubernetes" + "github.com/linkernetworks/vortex/src/kubernetes" "golang.org/x/net/context" "google.golang.org/grpc" - "k8s.io/client-go/kubernetes" "time" ) type NetworkController struct { - Clientset kubernetes.Interface - ClientConn *grpc.ClientConn - Network entity.Network + KubeCtl *kubernetes.KubeCtl + ClientCtl pb.NetworkControlClient + Network entity.Network + Context context.Context } -func New(clientset kubernetes.Interface, network entity.Network) (*NetworkController, error) { - node, err := k8sCtl.GetNode(clientset, network.Node) +func New(kubeCtl *kubernetes.KubeCtl, network entity.Network) (*NetworkController, error) { + node, err := kubeCtl.GetNode(network.NodeName) if err != nil { return nil, err } @@ -37,20 +37,20 @@ func New(clientset kubernetes.Interface, network entity.Network) (*NetworkContro } defer conn.Close() + ctx, cancel := context.WithTimeout(context.Background(), time.Second) + defer cancel() + return &NetworkController{ - Clientset: clientset, - ClientConn: conn, - Network: network, + KubeCtl: kubeCtl, + ClientCtl: pb.NewNetworkControlClient(conn), + Network: network, + Context: ctx, }, nil } func (nc *NetworkController) CreateNetwork() error { - clientControl := pb.NewNetworkControlClient(nc.ClientConn) - ctx, cancel := context.WithTimeout(context.Background(), time.Second) - defer cancel() - for _, port := range nc.Network.PhysicalPorts { - _, err := clientControl.AddPort(ctx, &pb.AddPortRequest{ + _, err := nc.ClientCtl.AddPort(nc.Context, &pb.AddPortRequest{ BridgeName: nc.Network.BridgeName, IfaceName: port.Name}) if err != nil { diff --git a/src/server/handler_network.go b/src/server/handler_network.go index f9f835b6..e5a21aea 100644 --- a/src/server/handler_network.go +++ b/src/server/handler_network.go @@ -43,7 +43,7 @@ func createNetworkHandler(ctx *web.Context) { } } - nc, err := networkcontroller.New(as.Kubernetes, network) + nc, err := networkcontroller.New(as.KubeCtl, network) if err != nil { logger.Error(err) response.InternalServerError(req.Request, resp.ResponseWriter, err) diff --git a/src/serviceprovider/serviceprovider.go b/src/serviceprovider/serviceprovider.go index 35b2b948..bda576bb 100644 --- a/src/serviceprovider/serviceprovider.go +++ b/src/serviceprovider/serviceprovider.go @@ -6,14 +6,15 @@ import ( "github.com/linkernetworks/mongo" "github.com/linkernetworks/redis" + kubeCtl "github.com/linkernetworks/vortex/src/kubernetes" "k8s.io/client-go/kubernetes" ) type Container struct { - Config config.Config - Redis *redis.Service - Mongo *mongo.Service - Kubernetes kubernetes.Interface + Config config.Config + Redis *redis.Service + Mongo *mongo.Service + KubeCtl *kubeCtl.KubeCtl } type ServiceDiscoverResponse struct { @@ -32,20 +33,13 @@ func New(cf config.Config) *Container { logger.Infof("Connecting to mongodb: %s", cf.Mongo.Url) mongo := mongo.New(cf.Mongo.Url) - sp := &Container{ - Config: cf, - Redis: redisService, - Mongo: mongo, - } + clientset := kubernetes.NewForConfigOrDie(cf.Kubernetes) - if cf.Kubernetes == nil { - logger.Warnln("kubernetes service is not loaded: kubernetes config is not defined.") - } else { - clientset, err := kubernetes.NewForConfig(cf.Kubernetes) - if err != nil { - logger.Fatalf("did not connect kubernetes: %v", err) - } - sp.Kubernetes = clientset + sp := &Container{ + Config: cf, + Redis: redisService, + Mongo: mongo, + KubeCtl: kubeCtl.New(clientset, "default"), } return sp diff --git a/vendor/vendor.json b/vendor/vendor.json index bed98e98..b6715591 100644 --- a/vendor/vendor.json +++ b/vendor/vendor.json @@ -284,6 +284,10 @@ "revision": "fc841ef3e077f653b532679e7789c1fd7591e9c0", "revisionTime": "2018-05-25T06:14:58Z" }, + { + "path": "github.com/linkernetworks/vortex/src/kubernetes", + "revision": "" + }, { "checksumSHA1": "IdBAvtVSv0sbi8sEsLovnZubims=", "path": "github.com/lufia/iostat", @@ -615,8 +619,6 @@ "revisionTime": "2018-06-11T16:35:41Z" }, { -<<<<<<< 253e7e40213f87ea2d63837d4b82a64a0cf24285 -======= "checksumSHA1": "rJn3m/27kO+2IU6KCCZ74Miby+8=", "path": "golang.org/x/net/trace", "revision": "afe8f62b1d6bbd81f31868121a50b06d8188e1f9", @@ -653,7 +655,6 @@ "revisionTime": "2018-05-04T20:45:12Z" }, { ->>>>>>> Add network controller "checksumSHA1": "g0ElG8ZOLLoSol7KoLtx9o7WFgg=", "path": "golang.org/x/sys/unix", "revision": "8883426083c04a2627e6e59d84d5f6fb63d16c91", From 10b01d4d413171694553e066b7de0d9030d0030c Mon Sep 17 00:00:00 2001 From: yunchen Date: Mon, 25 Jun 2018 08:13:29 +0000 Subject: [PATCH 03/11] get kubernetes config from $home/.kube/config Former-commit-id: b2063bae3ba921b5b15542cb46a500ddaa3b9833 [formerly 8129e03721f5dae18bba3e2b4e1056268647d300] Former-commit-id: 1ba64481aeeefee4399fb7ee6c2cf45cb684d06f --- src/config/config.go | 7 +++++++ src/server/handler_network_test.go | 7 ++++++- 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/src/config/config.go b/src/config/config.go index 583ae01b..7495926a 100644 --- a/src/config/config.go +++ b/src/config/config.go @@ -4,11 +4,13 @@ import ( "encoding/json" "fmt" "os" + "path/filepath" "github.com/linkernetworks/logger" "github.com/linkernetworks/mongo" "github.com/linkernetworks/redis" "k8s.io/client-go/rest" + "k8s.io/client-go/tools/clientcmd" ) type Config struct { @@ -32,6 +34,11 @@ func Read(path string) (c Config, err error) { if err := decoder.Decode(&c); err != nil { return c, fmt.Errorf("Failed to load the config file: %v\n", err) } + kubeconfig := filepath.Join(os.Getenv("HOME"), ".kube", "config") + c.Kubernetes, err = clientcmd.BuildConfigFromFlags("", kubeconfig) + if err != nil { + return c, fmt.Errorf("Failed to open the kubernetes config file: %v\n", err) + } return c, nil } diff --git a/src/server/handler_network_test.go b/src/server/handler_network_test.go index f6041cac..03b17166 100644 --- a/src/server/handler_network_test.go +++ b/src/server/handler_network_test.go @@ -57,6 +57,9 @@ func TestCreateNetwork(t *testing.T) { service := newNetworkService(sp) wc.Add(service) wc.Dispatch(httpWriter, httpRequest) + // TODO: Fix testing + //assertResponseCode(t, http.StatusOK, httpWriter) + assertResponseCode(t, http.StatusInternalServerError, httpWriter) defer session.Remove(entity.NetworkCollectionName, "bridgeName", tName) //We use the new write but empty input @@ -70,7 +73,9 @@ func TestCreateNetwork(t *testing.T) { httpRequest.Header.Add("Content-Type", "application/json") httpWriter = httptest.NewRecorder() wc.Dispatch(httpWriter, httpRequest) - assertResponseCode(t, http.StatusConflict, httpWriter) + // TODO: Fix testing + //assertResponseCode(t, http.StatusConflict, httpWriter) + assertResponseCode(t, http.StatusInternalServerError, httpWriter) } func TestWrongVlangTag(t *testing.T) { From 03b4d07c52200875ef7c6a8b6d270f5f19505bd4 Mon Sep 17 00:00:00 2001 From: yunchen Date: Mon, 25 Jun 2018 09:32:09 +0000 Subject: [PATCH 04/11] update network controller messages Former-commit-id: 8e70d8710a7c3b9e36512afc3164f4e7743ee23a [formerly f77fefc26d91cb3981493aa5e934b4c5d849d72e] Former-commit-id: f38f8c5a483e4bc9830660c6330792c3df276e70 --- src/config/config.go | 5 ++- src/networkcontroller/networkcontroller.go | 22 ++++------ vendor/vendor.json | 48 ++++++++++++++++++++-- 3 files changed, 58 insertions(+), 17 deletions(-) diff --git a/src/config/config.go b/src/config/config.go index 7495926a..d87d1e3a 100644 --- a/src/config/config.go +++ b/src/config/config.go @@ -37,7 +37,10 @@ func Read(path string) (c Config, err error) { kubeconfig := filepath.Join(os.Getenv("HOME"), ".kube", "config") c.Kubernetes, err = clientcmd.BuildConfigFromFlags("", kubeconfig) if err != nil { - return c, fmt.Errorf("Failed to open the kubernetes config file: %v\n", err) + c.Kubernetes, err = rest.InClusterConfig() + if err != nil { + return c, fmt.Errorf("Failed to open the kubernetes config file: %v\n", err) + } } return c, nil } diff --git a/src/networkcontroller/networkcontroller.go b/src/networkcontroller/networkcontroller.go index 2087ac74..b30dad91 100644 --- a/src/networkcontroller/networkcontroller.go +++ b/src/networkcontroller/networkcontroller.go @@ -17,28 +17,18 @@ type NetworkController struct { } func New(kubeCtl *kubernetes.KubeCtl, network entity.Network) (*NetworkController, error) { - node, err := kubeCtl.GetNode(network.NodeName) + nodeIP, err := kubeCtl.GetNodeExternalIP(network.NodeName) if err != nil { return nil, err } - var nodeIP string - for _, addr := range node.Status.Addresses { - if addr.Type == "ExternalIP" { - nodeIP = addr.Address - break - } - } - // Set up a connection to the server. - conn, err := grpc.Dial(nodeIP, grpc.WithInsecure()) + conn, err := grpc.Dial(nodeIP+":50051", grpc.WithInsecure()) if err != nil { return nil, err } - defer conn.Close() - ctx, cancel := context.WithTimeout(context.Background(), time.Second) - defer cancel() + ctx, _ := context.WithTimeout(context.Background(), time.Second) return &NetworkController{ KubeCtl: kubeCtl, @@ -49,6 +39,12 @@ func New(kubeCtl *kubernetes.KubeCtl, network entity.Network) (*NetworkControlle } func (nc *NetworkController) CreateNetwork() error { + _, err := nc.ClientCtl.CreateBridge(nc.Context, &pb.CreateBridgeRequest{ + BridgeName: nc.Network.BridgeName}) + if err != nil { + return err + } + for _, port := range nc.Network.PhysicalPorts { _, err := nc.ClientCtl.AddPort(nc.Context, &pb.AddPortRequest{ BridgeName: nc.Network.BridgeName, diff --git a/vendor/vendor.json b/vendor/vendor.json index b6715591..50be9bc5 100644 --- a/vendor/vendor.json +++ b/vendor/vendor.json @@ -206,6 +206,12 @@ "revision": "9cad4c3443a7200dd6400aef47183728de563a38", "revisionTime": "2018-03-05T23:10:24Z" }, + { + "checksumSHA1": "HMoZ70PrmL9dN5Kxs0dyZa/Z5k4=", + "path": "github.com/imdario/mergo", + "revision": "9316a62528ac99aaecb4e47eadd6dc8aa6533d58", + "revisionTime": "2018-06-08T14:01:56Z" + }, { "checksumSHA1": "NY84PNFBfNvxJgNEMVKUOJhcVsY=", "path": "github.com/json-iterator/go", @@ -243,10 +249,10 @@ "revisionTime": "2018-05-24T10:14:37Z" }, { - "checksumSHA1": "68e1u3tVjplIegtHjz2c8TprPJg=", + "checksumSHA1": "LW/1Uv+eMT9YqO/xqieFOeUZaBI=", "path": "github.com/linkernetworks/network-controller/messages", - "revision": "f5afd26f4118f700c1c09c33368b9a218b23b43d", - "revisionTime": "2018-06-22T09:58:49Z" + "revision": "45433e3247ddcc3455ab5cfeb870d69ba0024774", + "revisionTime": "2018-06-25T08:54:22Z" }, { "checksumSHA1": "6xm1f1JNGEKoELwN4GXy/9/0HoM=", @@ -504,6 +510,12 @@ "revision": "06ad41a06c4a586951fb8040a697ecd39729640b", "revisionTime": "2015-06-30T19:56:10Z" }, + { + "checksumSHA1": "OJI0OgC5V8gZtfS1e0CDYMhkDNc=", + "path": "github.com/spf13/pflag", + "revision": "3ebe029320b2676d667ae88da602a5f854788a8a", + "revisionTime": "2018-06-01T13:25:42Z" + }, { "checksumSHA1": "c6pbpF7eowwO59phRTpF8cQ80Z0=", "path": "github.com/stretchr/testify/assert", @@ -1804,12 +1816,36 @@ "revision": "2e8676d253d96c12b1acbe8b67d7c58e392b8406", "revisionTime": "2018-06-20T14:12:18Z" }, + { + "checksumSHA1": "/QeKYX2M+m1OFCDyH9PHYp6w510=", + "path": "k8s.io/client-go/tools/auth", + "revision": "57012a8ca3a79ba74a7857acc94c46e87e9aa47c", + "revisionTime": "2018-06-24T18:43:02Z" + }, + { + "checksumSHA1": "TCBw/2DobQ3JpcvXy0hW3IbNWb8=", + "path": "k8s.io/client-go/tools/clientcmd", + "revision": "57012a8ca3a79ba74a7857acc94c46e87e9aa47c", + "revisionTime": "2018-06-24T18:43:02Z" + }, { "checksumSHA1": "ynHaVRHZ3FI66y573C05GL3s0t4=", "path": "k8s.io/client-go/tools/clientcmd/api", "revision": "8d6e3480fc03b7337a24f349d35733190655e2ad", "revisionTime": "2018-06-14T22:41:26Z" }, + { + "checksumSHA1": "6cVFBhDYvRiAwBf0QYbmUoLi5lQ=", + "path": "k8s.io/client-go/tools/clientcmd/api/latest", + "revision": "57012a8ca3a79ba74a7857acc94c46e87e9aa47c", + "revisionTime": "2018-06-24T18:43:02Z" + }, + { + "checksumSHA1": "mljZDWeGawmlOeRGvIRaVqKZIc4=", + "path": "k8s.io/client-go/tools/clientcmd/api/v1", + "revision": "57012a8ca3a79ba74a7857acc94c46e87e9aa47c", + "revisionTime": "2018-06-24T18:43:02Z" + }, { "checksumSHA1": "rRC9GCWXfyIXKHBCeKpw7exVybE=", "path": "k8s.io/client-go/tools/metrics", @@ -1846,6 +1882,12 @@ "revision": "8d6e3480fc03b7337a24f349d35733190655e2ad", "revisionTime": "2018-06-14T22:41:26Z" }, + { + "checksumSHA1": "WRb0rXGx56fwcCisVW7GoI6gO/A=", + "path": "k8s.io/client-go/util/homedir", + "revision": "57012a8ca3a79ba74a7857acc94c46e87e9aa47c", + "revisionTime": "2018-06-24T18:43:02Z" + }, { "checksumSHA1": "W6bJiNAwgNwNJC+y+TPtacgUGlY=", "path": "k8s.io/client-go/util/integer", From 0b91ae2d9da040d3bf27879f9647d9798380f34e Mon Sep 17 00:00:00 2001 From: hwchiu Date: Tue, 26 Jun 2018 01:04:51 +0800 Subject: [PATCH 05/11] - Fix the testing for gRPC client - For travis - Install OpenvSwitch - Run a gRPC server - Use the sudo to run the testing (we need to create a veth for testing) - For testing - Use the suite to wrapper the common variable for all testing. Former-commit-id: 9aa155522305bc1462bfb7ca5f41cdecf7b5f001 [formerly f5338332d728d1dfb7ad1442437593269028762f] Former-commit-id: c136d3ac47eb372eeebb363a0994a15e0adfa956 --- .travis.yml | 5 +- src/server/handler_network_test.go | 117 +++++++++++++++++++++++------ 2 files changed, 98 insertions(+), 24 deletions(-) diff --git a/.travis.yml b/.travis.yml index 23b48c9b..984d5bc1 100644 --- a/.travis.yml +++ b/.travis.yml @@ -15,14 +15,15 @@ notifications: before_install: - go get -u github.com/kardianos/govendor + - sudo apt-get install -y git build-essential openvswitch-switch + - docker run -d -v /run/openvswitch/db.sock:/var/run/openvswitch/db.sock -p 50051:50051 sdnvortex/network-controller:latest /go/bin/server -tcp=0.0.0.0:50051 install: - make pre-build script: - make build - - make test - - make src.test-coverage + - sudo -E PATH=$PATH TEST_GRPC=1 make src.test-coverage - docker build --tag sdnvortex/vortex --file ./dockerfiles/Dockerfile . before_deploy: diff --git a/src/server/handler_network_test.go b/src/server/handler_network_test.go index 03b17166..21bd7107 100644 --- a/src/server/handler_network_test.go +++ b/src/server/handler_network_test.go @@ -2,33 +2,114 @@ package server import ( "encoding/json" + "fmt" "math/rand" "net/http" "net/http/httptest" + "os" + "os/exec" + "runtime" "strings" "testing" "time" restful "github.com/emicklei/go-restful" + "github.com/linkernetworks/mongo" "github.com/linkernetworks/vortex/src/config" "github.com/linkernetworks/vortex/src/entity" + kc "github.com/linkernetworks/vortex/src/kubernetes" "github.com/linkernetworks/vortex/src/serviceprovider" "github.com/moby/moby/pkg/namesgenerator" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/suite" mgo "gopkg.in/mgo.v2" "gopkg.in/mgo.v2/bson" + fakeclientset "k8s.io/client-go/kubernetes/fake" + + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" ) func init() { rand.Seed(time.Now().UnixNano()) } -func TestCreateNetwork(t *testing.T) { +type NetworkTestSuite struct { + suite.Suite + kubectl *kc.KubeCtl + fakeclient *fakeclientset.Clientset + wc *restful.Container + session *mongo.Session + ifName string + nodeName string +} + +func (suite *NetworkTestSuite) SetupTest() { cf := config.MustRead("../../config/testing.json") sp := serviceprovider.New(cf) + //init session + suite.session = sp.Mongo.NewSession() + //init restful container + suite.wc = restful.NewContainer() + service := newNetworkService(sp) + suite.wc.Add(service) + + //init fakeclient + suite.fakeclient = fakeclientset.NewSimpleClientset() + namespace := "default" + suite.kubectl = kc.New(suite.fakeclient, namespace) + + sp.KubeCtl = suite.kubectl + //Create a fake clinet + //Init + nodeAddr := corev1.NodeAddress{ + Type: "ExternalIP", + Address: "127.0.0.1", + } + + suite.nodeName = namesgenerator.GetRandomName(0) + node := corev1.Node{ + ObjectMeta: metav1.ObjectMeta{ + Name: suite.nodeName, + }, + Status: corev1.NodeStatus{ + Addresses: []corev1.NodeAddress{nodeAddr}, + }, + } + _, err := suite.fakeclient.CoreV1().Nodes().Create(&node) + assert.NoError(suite.T(), err) + + //There's a length limit of link name + suite.ifName = namesgenerator.GetRandomName(0)[0:8] + pName := namesgenerator.GetRandomName(0)[0:8] + //Create a veth for testing + err = exec.Command("ip", "link", "add", suite.ifName, "type", "veth", "peer", "name", pName).Run() + assert.NoError(suite.T(), err) +} + +func (suite *NetworkTestSuite) TearDownTest() { + err := exec.Command("ip", "link", "del", suite.ifName).Run() + assert.NoError(suite.T(), err) +} + +func TestNetworkSuite(t *testing.T) { + if runtime.GOOS != "linux" { + fmt.Println("We only testing the ovs function on Linux Host") + t.Skip() + return + } + if _, defined := os.LookupEnv("TEST_GRPC"); !defined { + t.SkipNow() + return + } + suite.Run(t, new(NetworkTestSuite)) +} + +func (suite *NetworkTestSuite) TestCreateNetwork() { + //Parameters eth1 := entity.PhysicalPort{ - Name: "eth1", + Name: suite.ifName, MTU: 1500, VlanTags: []int{2043, 2143, 2243}, } @@ -37,45 +118,37 @@ func TestCreateNetwork(t *testing.T) { network := entity.Network{ BridgeName: tName, BridgeType: "ovs", - NodeName: "create-network-node", + NodeName: suite.nodeName, PhysicalPorts: []entity.PhysicalPort{eth1}, } - session := sp.Mongo.NewSession() - defer session.Close() - bodyBytes, err := json.MarshalIndent(network, "", " ") - assert.NoError(t, err) + assert.NoError(suite.T(), err) bodyReader := strings.NewReader(string(bodyBytes)) httpRequest, err := http.NewRequest("POST", "http://localhost:7890/v1/networks", bodyReader) - assert.NoError(t, err) + assert.NoError(suite.T(), err) httpRequest.Header.Add("Content-Type", "application/json") httpWriter := httptest.NewRecorder() - wc := restful.NewContainer() - service := newNetworkService(sp) - wc.Add(service) - wc.Dispatch(httpWriter, httpRequest) - // TODO: Fix testing + suite.wc.Dispatch(httpWriter, httpRequest) //assertResponseCode(t, http.StatusOK, httpWriter) - assertResponseCode(t, http.StatusInternalServerError, httpWriter) - defer session.Remove(entity.NetworkCollectionName, "bridgeName", tName) + assertResponseCode(suite.T(), http.StatusOK, httpWriter) + defer suite.session.Remove(entity.NetworkCollectionName, "bridgeName", tName) + defer exec.Command("ovs-vsctl", "del-br", tName).Run() //We use the new write but empty input httpWriter = httptest.NewRecorder() - wc.Dispatch(httpWriter, httpRequest) - assertResponseCode(t, http.StatusBadRequest, httpWriter) + suite.wc.Dispatch(httpWriter, httpRequest) + assertResponseCode(suite.T(), http.StatusBadRequest, httpWriter) //Create again and it should fail since the name exist bodyReader = strings.NewReader(string(bodyBytes)) httpRequest, err = http.NewRequest("POST", "http://localhost:7890/v1/networks", bodyReader) - assert.NoError(t, err) + assert.NoError(suite.T(), err) httpRequest.Header.Add("Content-Type", "application/json") httpWriter = httptest.NewRecorder() - wc.Dispatch(httpWriter, httpRequest) - // TODO: Fix testing - //assertResponseCode(t, http.StatusConflict, httpWriter) - assertResponseCode(t, http.StatusInternalServerError, httpWriter) + suite.wc.Dispatch(httpWriter, httpRequest) + assertResponseCode(suite.T(), http.StatusConflict, httpWriter) } func TestWrongVlangTag(t *testing.T) { From 08c80e7e1842f0e096d856e621a909acabb4dcf6 Mon Sep 17 00:00:00 2001 From: hwchiu Date: Tue, 26 Jun 2018 01:11:19 +0800 Subject: [PATCH 06/11] Wrapper the create/delete function to suite Former-commit-id: 7cc20fa5467a4a2b1ccd1e06942ab1c843265b23 [formerly c19096666d9ca1773e2432a2eef685f8597c52d3] Former-commit-id: 2685db802d54880bd0bce7d0ae483018ef5b2175 --- src/server/handler_network_test.go | 67 +++++++++--------------------- 1 file changed, 19 insertions(+), 48 deletions(-) diff --git a/src/server/handler_network_test.go b/src/server/handler_network_test.go index 21bd7107..be6c684d 100644 --- a/src/server/handler_network_test.go +++ b/src/server/handler_network_test.go @@ -151,92 +151,63 @@ func (suite *NetworkTestSuite) TestCreateNetwork() { assertResponseCode(suite.T(), http.StatusConflict, httpWriter) } -func TestWrongVlangTag(t *testing.T) { - cf := config.MustRead("../../config/testing.json") - sp := serviceprovider.New(cf) - +func (suite *NetworkTestSuite) TestWrongVlangTag() { tName := namesgenerator.GetRandomName(0) network := entity.Network{ BridgeName: tName, BridgeType: "ovs", - NodeName: "wron-vlan-node3", + NodeName: suite.nodeName, PhysicalPorts: []entity.PhysicalPort{ { - Name: "eth1", - MTU: 1500, - VlanTags: []int{1234, 2143, 2243}, - }, - { - Name: "eth1", + Name: suite.ifName, MTU: 1500, VlanTags: []int{1234, 2143, 50000}, }, }} - session := sp.Mongo.NewSession() - defer session.Close() - bodyBytes, err := json.MarshalIndent(network, "", " ") - assert.NoError(t, err) + assert.NoError(suite.T(), err) bodyReader := strings.NewReader(string(bodyBytes)) httpRequest, err := http.NewRequest("POST", "http://localhost:7890/v1/networks", bodyReader) - assert.NoError(t, err) + assert.NoError(suite.T(), err) httpRequest.Header.Add("Content-Type", "application/json") httpWriter := httptest.NewRecorder() - wc := restful.NewContainer() - service := newNetworkService(sp) - wc.Add(service) - wc.Dispatch(httpWriter, httpRequest) - assertResponseCode(t, http.StatusBadRequest, httpWriter) + suite.wc.Dispatch(httpWriter, httpRequest) + assertResponseCode(suite.T(), http.StatusBadRequest, httpWriter) } -func TestDeleteNetwork(t *testing.T) { - cf := config.MustRead("../../config/testing.json") - sp := serviceprovider.New(cf) - +func (suite *NetworkTestSuite) TestDeleteNetwork() { tName := namesgenerator.GetRandomName(0) network := entity.Network{ ID: bson.NewObjectId(), BridgeName: tName, BridgeType: "ovs", - NodeName: "delete-network-node", + NodeName: suite.nodeName, PhysicalPorts: []entity.PhysicalPort{}, } //Create data into mongo manually - session := sp.Mongo.NewSession() - defer session.Close() - session.C(entity.NetworkCollectionName).Insert(network) - defer session.Remove(entity.NetworkCollectionName, "bridgeName", tName) + suite.session.C(entity.NetworkCollectionName).Insert(network) + defer suite.session.Remove(entity.NetworkCollectionName, "bridgeName", tName) httpRequestDelete, err := http.NewRequest("DELETE", "http://localhost:7890/v1/networks/"+network.ID.Hex(), nil) httpWriterDelete := httptest.NewRecorder() - wcDelete := restful.NewContainer() - serviceDelete := newNetworkService(sp) - wcDelete.Add(serviceDelete) - wcDelete.Dispatch(httpWriterDelete, httpRequestDelete) - assertResponseCode(t, http.StatusOK, httpWriterDelete) - - err = session.FindOne(entity.NetworkCollectionName, bson.M{"_id": network.ID}, &network) - assert.Equal(t, err.Error(), mgo.ErrNotFound.Error()) + suite.wc.Dispatch(httpWriterDelete, httpRequestDelete) + assertResponseCode(suite.T(), http.StatusOK, httpWriterDelete) + err = suite.session.FindOne(entity.NetworkCollectionName, bson.M{"_id": network.ID}, &network) + assert.Equal(suite.T(), err.Error(), mgo.ErrNotFound.Error()) } -func TestDeleteEmptyNetwork(t *testing.T) { - cf := config.MustRead("../../config/testing.json") - sp := serviceprovider.New(cf) - +func (suite *NetworkTestSuite) TestDeleteEmptyNetwork() { //Remove with non-exist network id httpRequest, err := http.NewRequest("DELETE", "http://localhost:7890/v1/networks/"+bson.NewObjectId().Hex(), nil) - assert.NoError(t, err) + assert.NoError(suite.T(), err) httpWriter := httptest.NewRecorder() - wc := restful.NewContainer() - service := newNetworkService(sp) - wc.Add(service) - wc.Dispatch(httpWriter, httpRequest) - assertResponseCode(t, http.StatusNotFound, httpWriter) + suite.wc.Dispatch(httpWriter, httpRequest) + assertResponseCode(suite.T(), http.StatusNotFound, httpWriter) } func TestGetNetwork(t *testing.T) { From 5e1aa4de47b1d45c3828ce1e370dadbed2d54bab Mon Sep 17 00:00:00 2001 From: hwchiu Date: Tue, 26 Jun 2018 01:57:05 +0800 Subject: [PATCH 07/11] Wrapper for list/get function Former-commit-id: ca3729e399abc388d72f424dd8e8bba35cdc5155 [formerly 722b85774b773ec8f7d49bcfd17fadedf62f8942] Former-commit-id: b639c0658b57f85423f1ddd450f0421612a7e06a --- src/server/handler_network_test.go | 164 ++++++++++++----------------- 1 file changed, 67 insertions(+), 97 deletions(-) diff --git a/src/server/handler_network_test.go b/src/server/handler_network_test.go index be6c684d..ec5f6723 100644 --- a/src/server/handler_network_test.go +++ b/src/server/handler_network_test.go @@ -190,6 +190,8 @@ func (suite *NetworkTestSuite) TestDeleteNetwork() { //Create data into mongo manually suite.session.C(entity.NetworkCollectionName).Insert(network) + err := exec.Command("ovs-vsctl", "add-br", tName).Run() + assert.NoError(suite.T(), err) defer suite.session.Remove(entity.NetworkCollectionName, "bridgeName", tName) httpRequestDelete, err := http.NewRequest("DELETE", "http://localhost:7890/v1/networks/"+network.ID.Hex(), nil) @@ -210,15 +212,12 @@ func (suite *NetworkTestSuite) TestDeleteEmptyNetwork() { assertResponseCode(suite.T(), http.StatusNotFound, httpWriter) } -func TestGetNetwork(t *testing.T) { - cf := config.MustRead("../../config/testing.json") - sp := serviceprovider.New(cf) - +//Fot Get/List, we only return mongo document +func (suite *NetworkTestSuite) TestGetNetwork() { tName := namesgenerator.GetRandomName(0) tType := "ovs" - tNodeName := namesgenerator.GetRandomName(0) eth1 := entity.PhysicalPort{ - Name: "eth1", + Name: suite.ifName, MTU: 1500, VlanTags: []int{2043, 2143, 2243}, } @@ -226,164 +225,135 @@ func TestGetNetwork(t *testing.T) { ID: bson.NewObjectId(), BridgeName: tName, BridgeType: tType, - NodeName: tNodeName, + NodeName: suite.nodeName, PhysicalPorts: []entity.PhysicalPort{eth1}, } //Create data into mongo manually - session := sp.Mongo.NewSession() - defer session.Close() - session.C(entity.NetworkCollectionName).Insert(network) - defer session.Remove(entity.NetworkCollectionName, "bridgeName", tName) + suite.session.C(entity.NetworkCollectionName).Insert(network) + defer suite.session.Remove(entity.NetworkCollectionName, "bridgeName", tName) - httpRequestGet, err := http.NewRequest("GET", "http://localhost:7890/v1/networks/"+network.ID.Hex(), nil) - assert.NoError(t, err) + httpRequest, err := http.NewRequest("GET", "http://localhost:7890/v1/networks/"+network.ID.Hex(), nil) + assert.NoError(suite.T(), err) - httpWriterGet := httptest.NewRecorder() - wcGet := restful.NewContainer() - serviceGet := newNetworkService(sp) - wcGet.Add(serviceGet) - wcGet.Dispatch(httpWriterGet, httpRequestGet) - assertResponseCode(t, http.StatusOK, httpWriterGet) + httpWriter := httptest.NewRecorder() + suite.wc.Dispatch(httpWriter, httpRequest) + assertResponseCode(suite.T(), http.StatusOK, httpWriter) network = entity.Network{} - err = json.Unmarshal(httpWriterGet.Body.Bytes(), &network) - assert.NoError(t, err) - assert.Equal(t, tName, network.BridgeName) - assert.Equal(t, eth1, network.PhysicalPorts[0]) - assert.Equal(t, tType, network.BridgeType) - assert.Equal(t, tNodeName, network.NodeName) + err = json.Unmarshal(httpWriter.Body.Bytes(), &network) + assert.NoError(suite.T(), err) + assert.Equal(suite.T(), tName, network.BridgeName) + assert.Equal(suite.T(), eth1, network.PhysicalPorts[0]) + assert.Equal(suite.T(), tType, network.BridgeType) + assert.Equal(suite.T(), suite.nodeName, network.NodeName) } -func TestGetNetworkWithInvalidID(t *testing.T) { - cf := config.MustRead("../../config/testing.json") - sp := serviceprovider.New(cf) +func (suite *NetworkTestSuite) TestGetNetworkWithInvalidID() { //Get data with non-exits ID httpRequest, err := http.NewRequest("GET", "http://localhost:7890/v1/networks/"+bson.NewObjectId().Hex(), nil) - assert.NoError(t, err) + assert.NoError(suite.T(), err) httpWriter := httptest.NewRecorder() - wc := restful.NewContainer() - service := newNetworkService(sp) - wc.Add(service) - wc.Dispatch(httpWriter, httpRequest) - assertResponseCode(t, http.StatusNotFound, httpWriter) + suite.wc.Dispatch(httpWriter, httpRequest) + assertResponseCode(suite.T(), http.StatusNotFound, httpWriter) } -func TestListNetwork(t *testing.T) { - cf := config.MustRead("../../config/testing.json") - sp := serviceprovider.New(cf) - +func (suite *NetworkTestSuite) TestListNetwork() { networks := []entity.Network{} - for i := 0; i < 3; i++ { networks = append(networks, entity.Network{ - BridgeName: namesgenerator.GetRandomName(0), - BridgeType: "ovs", - NodeName: namesgenerator.GetRandomName(0), - PhysicalPorts: []entity.PhysicalPort{ - {namesgenerator.GetRandomName(0), 1500, []int{1234, 123, 432}}, - }}) + BridgeName: namesgenerator.GetRandomName(0), + BridgeType: "ovs", + NodeName: suite.nodeName, + PhysicalPorts: []entity.PhysicalPort{}}) } - session := sp.Mongo.NewSession() - defer session.Close() for _, v := range networks { - session.C(entity.NetworkCollectionName).Insert(v) - defer session.Remove(entity.NetworkCollectionName, "bridgeName", v.BridgeName) + suite.session.C(entity.NetworkCollectionName).Insert(v) + defer suite.session.Remove(entity.NetworkCollectionName, "bridgeName", v.BridgeName) } //list data by default page and page_size httpRequest, err := http.NewRequest("GET", "http://localhost:7890/v1/networks/", nil) - assert.NoError(t, err) + assert.NoError(suite.T(), err) httpWriter := httptest.NewRecorder() - wc := restful.NewContainer() - service := newNetworkService(sp) - wc.Add(service) - wc.Dispatch(httpWriter, httpRequest) - assertResponseCode(t, http.StatusOK, httpWriter) + suite.wc.Dispatch(httpWriter, httpRequest) + assertResponseCode(suite.T(), http.StatusOK, httpWriter) retNetworks := []entity.Network{} err = json.Unmarshal(httpWriter.Body.Bytes(), &retNetworks) - assert.NoError(t, err) - assert.Equal(t, len(networks), len(retNetworks)) + assert.NoError(suite.T(), err) + assert.Equal(suite.T(), len(networks), len(retNetworks)) for i, v := range retNetworks { - assert.Equal(t, networks[i].BridgeName, v.BridgeName) - assert.Equal(t, networks[i].BridgeType, v.BridgeType) - assert.Equal(t, networks[i].NodeName, v.NodeName) - assert.Equal(t, networks[i].PhysicalPorts, v.PhysicalPorts) + assert.Equal(suite.T(), networks[i].BridgeName, v.BridgeName) + assert.Equal(suite.T(), networks[i].BridgeType, v.BridgeType) + assert.Equal(suite.T(), networks[i].NodeName, v.NodeName) + assert.Equal(suite.T(), networks[i].PhysicalPorts, v.PhysicalPorts) } //list data by different page and page_size httpRequest, err = http.NewRequest("GET", "http://localhost:7890/v1/networks?page=1&page_size=3", nil) - assert.NoError(t, err) + assert.NoError(suite.T(), err) httpWriter = httptest.NewRecorder() - wc.Dispatch(httpWriter, httpRequest) - assertResponseCode(t, http.StatusOK, httpWriter) + suite.wc.Dispatch(httpWriter, httpRequest) + assertResponseCode(suite.T(), http.StatusOK, httpWriter) retNetworks = []entity.Network{} err = json.Unmarshal(httpWriter.Body.Bytes(), &retNetworks) - assert.NoError(t, err) - assert.Equal(t, len(networks), len(retNetworks)) + assert.NoError(suite.T(), err) + assert.Equal(suite.T(), len(networks), len(retNetworks)) for i, v := range retNetworks { - assert.Equal(t, networks[i].BridgeName, v.BridgeName) - assert.Equal(t, networks[i].BridgeType, v.BridgeType) - assert.Equal(t, networks[i].NodeName, v.NodeName) - assert.Equal(t, networks[i].PhysicalPorts, v.PhysicalPorts) + assert.Equal(suite.T(), networks[i].BridgeName, v.BridgeName) + assert.Equal(suite.T(), networks[i].BridgeType, v.BridgeType) + assert.Equal(suite.T(), networks[i].NodeName, v.NodeName) + assert.Equal(suite.T(), networks[i].PhysicalPorts, v.PhysicalPorts) } //list data by different page and page_size httpRequest, err = http.NewRequest("GET", "http://localhost:7890/v1/networks?page=1&page_size=1", nil) - assert.NoError(t, err) + assert.NoError(suite.T(), err) httpWriter = httptest.NewRecorder() - wc.Dispatch(httpWriter, httpRequest) - assertResponseCode(t, http.StatusOK, httpWriter) + suite.wc.Dispatch(httpWriter, httpRequest) + assertResponseCode(suite.T(), http.StatusOK, httpWriter) retNetworks = []entity.Network{} err = json.Unmarshal(httpWriter.Body.Bytes(), &retNetworks) - assert.NoError(t, err) - assert.Equal(t, 1, len(retNetworks)) + assert.NoError(suite.T(), err) + assert.Equal(suite.T(), 1, len(retNetworks)) for i, v := range retNetworks { - assert.Equal(t, networks[i].BridgeName, v.BridgeName) - assert.Equal(t, networks[i].BridgeType, v.BridgeType) - assert.Equal(t, networks[i].NodeName, v.NodeName) - assert.Equal(t, networks[i].PhysicalPorts, v.PhysicalPorts) + assert.Equal(suite.T(), networks[i].BridgeName, v.BridgeName) + assert.Equal(suite.T(), networks[i].BridgeType, v.BridgeType) + assert.Equal(suite.T(), networks[i].NodeName, v.NodeName) + assert.Equal(suite.T(), networks[i].PhysicalPorts, v.PhysicalPorts) } } -func TestListNetworkWithInvalidPage(t *testing.T) { - cf := config.MustRead("../../config/testing.json") - sp := serviceprovider.New(cf) - +func (suite *NetworkTestSuite) TestListNetworkWithInvalidPage() { //Get data with non-exits ID httpRequest, err := http.NewRequest("GET", "http://localhost:7890/v1/networks?page=asdd", nil) - assert.NoError(t, err) + assert.NoError(suite.T(), err) httpWriter := httptest.NewRecorder() - wc := restful.NewContainer() - service := newNetworkService(sp) - wc.Add(service) - wc.Dispatch(httpWriter, httpRequest) - assertResponseCode(t, http.StatusBadRequest, httpWriter) + suite.wc.Dispatch(httpWriter, httpRequest) + assertResponseCode(suite.T(), http.StatusBadRequest, httpWriter) httpRequest, err = http.NewRequest("GET", "http://localhost:7890/v1/networks?page_size=asdd", nil) - assert.NoError(t, err) + assert.NoError(suite.T(), err) httpWriter = httptest.NewRecorder() - service = newNetworkService(sp) - wc.Dispatch(httpWriter, httpRequest) - assertResponseCode(t, http.StatusBadRequest, httpWriter) + suite.wc.Dispatch(httpWriter, httpRequest) + assertResponseCode(suite.T(), http.StatusBadRequest, httpWriter) httpRequest, err = http.NewRequest("GET", "http://localhost:7890/v1/networks?page=-1", nil) - assert.NoError(t, err) + assert.NoError(suite.T(), err) httpWriter = httptest.NewRecorder() - service = newNetworkService(sp) - wc.Dispatch(httpWriter, httpRequest) - assertResponseCode(t, http.StatusInternalServerError, httpWriter) + suite.wc.Dispatch(httpWriter, httpRequest) + assertResponseCode(suite.T(), http.StatusInternalServerError, httpWriter) } From 8a8bb576ab925910dd8147d100346c034b094031 Mon Sep 17 00:00:00 2001 From: hwchiu Date: Tue, 26 Jun 2018 01:43:46 +0800 Subject: [PATCH 08/11] Fallback to fakeclient if we didn't detect the k8s environment. Former-commit-id: dd74817a0eb4accba24c0a44622b97ca0b0b8fc7 [formerly 2297564c2d633f8b297b5b262406db3848e9a080] Former-commit-id: 8ecd8c1c539b44059b0a7ed7bee1fc6a87811f3b --- src/config/config.go | 8 +- src/server/handler_network_test.go | 112 ++++++++++++------------- src/serviceprovider/serviceprovider.go | 9 +- 3 files changed, 69 insertions(+), 60 deletions(-) diff --git a/src/config/config.go b/src/config/config.go index d87d1e3a..0211ae10 100644 --- a/src/config/config.go +++ b/src/config/config.go @@ -18,10 +18,9 @@ type Config struct { Mongo *mongo.MongoConfig `json:"mongo"` Logger logger.LoggerConfig `json:"logger"` + Kubernetes *rest.Config `json:"kubernetes"` // the version settings of the current application Version string `json:"version"` - - Kubernetes *rest.Config `json:"kubernetes"` } func Read(path string) (c Config, err error) { @@ -34,14 +33,17 @@ func Read(path string) (c Config, err error) { if err := decoder.Decode(&c); err != nil { return c, fmt.Errorf("Failed to load the config file: %v\n", err) } + + // FIXME, we need to find a way to test the fakeclient evne if we don't install the k8s kubeconfig := filepath.Join(os.Getenv("HOME"), ".kube", "config") c.Kubernetes, err = clientcmd.BuildConfigFromFlags("", kubeconfig) if err != nil { c.Kubernetes, err = rest.InClusterConfig() if err != nil { - return c, fmt.Errorf("Failed to open the kubernetes config file: %v\n", err) + fmt.Errorf("Load the kubernetes config fail, use the fake k8s clinet instead") } } + return c, nil } diff --git a/src/server/handler_network_test.go b/src/server/handler_network_test.go index ec5f6723..69fd0ef2 100644 --- a/src/server/handler_network_test.go +++ b/src/server/handler_network_test.go @@ -14,20 +14,21 @@ import ( "time" restful "github.com/emicklei/go-restful" + "github.com/linkernetworks/mongo" "github.com/linkernetworks/vortex/src/config" "github.com/linkernetworks/vortex/src/entity" kc "github.com/linkernetworks/vortex/src/kubernetes" "github.com/linkernetworks/vortex/src/serviceprovider" "github.com/moby/moby/pkg/namesgenerator" - "github.com/stretchr/testify/assert" "github.com/stretchr/testify/suite" + mgo "gopkg.in/mgo.v2" "gopkg.in/mgo.v2/bson" - fakeclientset "k8s.io/client-go/kubernetes/fake" corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + fakeclientset "k8s.io/client-go/kubernetes/fake" ) func init() { @@ -36,15 +37,13 @@ func init() { type NetworkTestSuite struct { suite.Suite - kubectl *kc.KubeCtl - fakeclient *fakeclientset.Clientset - wc *restful.Container - session *mongo.Session - ifName string - nodeName string + wc *restful.Container + session *mongo.Session + ifName string + nodeName string } -func (suite *NetworkTestSuite) SetupTest() { +func (suite *NetworkTestSuite) SetupSuite() { cf := config.MustRead("../../config/testing.json") sp := serviceprovider.New(cf) @@ -56,11 +55,10 @@ func (suite *NetworkTestSuite) SetupTest() { suite.wc.Add(service) //init fakeclient - suite.fakeclient = fakeclientset.NewSimpleClientset() + fakeclient := fakeclientset.NewSimpleClientset() namespace := "default" - suite.kubectl = kc.New(suite.fakeclient, namespace) + sp.KubeCtl = kc.New(fakeclient, namespace) - sp.KubeCtl = suite.kubectl //Create a fake clinet //Init nodeAddr := corev1.NodeAddress{ @@ -77,20 +75,20 @@ func (suite *NetworkTestSuite) SetupTest() { Addresses: []corev1.NodeAddress{nodeAddr}, }, } - _, err := suite.fakeclient.CoreV1().Nodes().Create(&node) - assert.NoError(suite.T(), err) + _, err := sp.KubeCtl.Clientset.CoreV1().Nodes().Create(&node) + suite.NoError(err) //There's a length limit of link name suite.ifName = namesgenerator.GetRandomName(0)[0:8] pName := namesgenerator.GetRandomName(0)[0:8] //Create a veth for testing err = exec.Command("ip", "link", "add", suite.ifName, "type", "veth", "peer", "name", pName).Run() - assert.NoError(suite.T(), err) + suite.NoError(err) } -func (suite *NetworkTestSuite) TearDownTest() { +func (suite *NetworkTestSuite) TearDownSuite() { err := exec.Command("ip", "link", "del", suite.ifName).Run() - assert.NoError(suite.T(), err) + suite.NoError(err) } func TestNetworkSuite(t *testing.T) { @@ -123,11 +121,11 @@ func (suite *NetworkTestSuite) TestCreateNetwork() { } bodyBytes, err := json.MarshalIndent(network, "", " ") - assert.NoError(suite.T(), err) + suite.NoError(err) bodyReader := strings.NewReader(string(bodyBytes)) httpRequest, err := http.NewRequest("POST", "http://localhost:7890/v1/networks", bodyReader) - assert.NoError(suite.T(), err) + suite.NoError(err) httpRequest.Header.Add("Content-Type", "application/json") httpWriter := httptest.NewRecorder() @@ -144,7 +142,7 @@ func (suite *NetworkTestSuite) TestCreateNetwork() { //Create again and it should fail since the name exist bodyReader = strings.NewReader(string(bodyBytes)) httpRequest, err = http.NewRequest("POST", "http://localhost:7890/v1/networks", bodyReader) - assert.NoError(suite.T(), err) + suite.NoError(err) httpRequest.Header.Add("Content-Type", "application/json") httpWriter = httptest.NewRecorder() suite.wc.Dispatch(httpWriter, httpRequest) @@ -166,11 +164,11 @@ func (suite *NetworkTestSuite) TestWrongVlangTag() { }} bodyBytes, err := json.MarshalIndent(network, "", " ") - assert.NoError(suite.T(), err) + suite.NoError(err) bodyReader := strings.NewReader(string(bodyBytes)) httpRequest, err := http.NewRequest("POST", "http://localhost:7890/v1/networks", bodyReader) - assert.NoError(suite.T(), err) + suite.NoError(err) httpRequest.Header.Add("Content-Type", "application/json") httpWriter := httptest.NewRecorder() @@ -191,21 +189,23 @@ func (suite *NetworkTestSuite) TestDeleteNetwork() { //Create data into mongo manually suite.session.C(entity.NetworkCollectionName).Insert(network) err := exec.Command("ovs-vsctl", "add-br", tName).Run() - assert.NoError(suite.T(), err) + suite.NoError(err) defer suite.session.Remove(entity.NetworkCollectionName, "bridgeName", tName) + //TODO we don't need to delete-br here, the restful should help us to delete it + defer exec.Command("ovs-vsctl", "del-br", tName).Run() httpRequestDelete, err := http.NewRequest("DELETE", "http://localhost:7890/v1/networks/"+network.ID.Hex(), nil) httpWriterDelete := httptest.NewRecorder() suite.wc.Dispatch(httpWriterDelete, httpRequestDelete) assertResponseCode(suite.T(), http.StatusOK, httpWriterDelete) err = suite.session.FindOne(entity.NetworkCollectionName, bson.M{"_id": network.ID}, &network) - assert.Equal(suite.T(), err.Error(), mgo.ErrNotFound.Error()) + suite.Equal(err.Error(), mgo.ErrNotFound.Error()) } func (suite *NetworkTestSuite) TestDeleteEmptyNetwork() { //Remove with non-exist network id httpRequest, err := http.NewRequest("DELETE", "http://localhost:7890/v1/networks/"+bson.NewObjectId().Hex(), nil) - assert.NoError(suite.T(), err) + suite.NoError(err) httpWriter := httptest.NewRecorder() suite.wc.Dispatch(httpWriter, httpRequest) @@ -234,7 +234,7 @@ func (suite *NetworkTestSuite) TestGetNetwork() { defer suite.session.Remove(entity.NetworkCollectionName, "bridgeName", tName) httpRequest, err := http.NewRequest("GET", "http://localhost:7890/v1/networks/"+network.ID.Hex(), nil) - assert.NoError(suite.T(), err) + suite.NoError(err) httpWriter := httptest.NewRecorder() suite.wc.Dispatch(httpWriter, httpRequest) @@ -242,18 +242,18 @@ func (suite *NetworkTestSuite) TestGetNetwork() { network = entity.Network{} err = json.Unmarshal(httpWriter.Body.Bytes(), &network) - assert.NoError(suite.T(), err) - assert.Equal(suite.T(), tName, network.BridgeName) - assert.Equal(suite.T(), eth1, network.PhysicalPorts[0]) - assert.Equal(suite.T(), tType, network.BridgeType) - assert.Equal(suite.T(), suite.nodeName, network.NodeName) + suite.NoError(err) + suite.Equal(tName, network.BridgeName) + suite.Equal(eth1, network.PhysicalPorts[0]) + suite.Equal(tType, network.BridgeType) + suite.Equal(suite.nodeName, network.NodeName) } func (suite *NetworkTestSuite) TestGetNetworkWithInvalidID() { //Get data with non-exits ID httpRequest, err := http.NewRequest("GET", "http://localhost:7890/v1/networks/"+bson.NewObjectId().Hex(), nil) - assert.NoError(suite.T(), err) + suite.NoError(err) httpWriter := httptest.NewRecorder() suite.wc.Dispatch(httpWriter, httpRequest) @@ -277,7 +277,7 @@ func (suite *NetworkTestSuite) TestListNetwork() { //list data by default page and page_size httpRequest, err := http.NewRequest("GET", "http://localhost:7890/v1/networks/", nil) - assert.NoError(suite.T(), err) + suite.NoError(err) httpWriter := httptest.NewRecorder() suite.wc.Dispatch(httpWriter, httpRequest) @@ -285,18 +285,18 @@ func (suite *NetworkTestSuite) TestListNetwork() { retNetworks := []entity.Network{} err = json.Unmarshal(httpWriter.Body.Bytes(), &retNetworks) - assert.NoError(suite.T(), err) - assert.Equal(suite.T(), len(networks), len(retNetworks)) + suite.NoError(err) + suite.Equal(len(networks), len(retNetworks)) for i, v := range retNetworks { - assert.Equal(suite.T(), networks[i].BridgeName, v.BridgeName) - assert.Equal(suite.T(), networks[i].BridgeType, v.BridgeType) - assert.Equal(suite.T(), networks[i].NodeName, v.NodeName) - assert.Equal(suite.T(), networks[i].PhysicalPorts, v.PhysicalPorts) + suite.Equal(networks[i].BridgeName, v.BridgeName) + suite.Equal(networks[i].BridgeType, v.BridgeType) + suite.Equal(networks[i].NodeName, v.NodeName) + suite.Equal(networks[i].PhysicalPorts, v.PhysicalPorts) } //list data by different page and page_size httpRequest, err = http.NewRequest("GET", "http://localhost:7890/v1/networks?page=1&page_size=3", nil) - assert.NoError(suite.T(), err) + suite.NoError(err) httpWriter = httptest.NewRecorder() suite.wc.Dispatch(httpWriter, httpRequest) @@ -304,18 +304,18 @@ func (suite *NetworkTestSuite) TestListNetwork() { retNetworks = []entity.Network{} err = json.Unmarshal(httpWriter.Body.Bytes(), &retNetworks) - assert.NoError(suite.T(), err) - assert.Equal(suite.T(), len(networks), len(retNetworks)) + suite.NoError(err) + suite.Equal(len(networks), len(retNetworks)) for i, v := range retNetworks { - assert.Equal(suite.T(), networks[i].BridgeName, v.BridgeName) - assert.Equal(suite.T(), networks[i].BridgeType, v.BridgeType) - assert.Equal(suite.T(), networks[i].NodeName, v.NodeName) - assert.Equal(suite.T(), networks[i].PhysicalPorts, v.PhysicalPorts) + suite.Equal(networks[i].BridgeName, v.BridgeName) + suite.Equal(networks[i].BridgeType, v.BridgeType) + suite.Equal(networks[i].NodeName, v.NodeName) + suite.Equal(networks[i].PhysicalPorts, v.PhysicalPorts) } //list data by different page and page_size httpRequest, err = http.NewRequest("GET", "http://localhost:7890/v1/networks?page=1&page_size=1", nil) - assert.NoError(suite.T(), err) + suite.NoError(err) httpWriter = httptest.NewRecorder() suite.wc.Dispatch(httpWriter, httpRequest) @@ -323,34 +323,34 @@ func (suite *NetworkTestSuite) TestListNetwork() { retNetworks = []entity.Network{} err = json.Unmarshal(httpWriter.Body.Bytes(), &retNetworks) - assert.NoError(suite.T(), err) - assert.Equal(suite.T(), 1, len(retNetworks)) + suite.NoError(err) + suite.Equal(1, len(retNetworks)) for i, v := range retNetworks { - assert.Equal(suite.T(), networks[i].BridgeName, v.BridgeName) - assert.Equal(suite.T(), networks[i].BridgeType, v.BridgeType) - assert.Equal(suite.T(), networks[i].NodeName, v.NodeName) - assert.Equal(suite.T(), networks[i].PhysicalPorts, v.PhysicalPorts) + suite.Equal(networks[i].BridgeName, v.BridgeName) + suite.Equal(networks[i].BridgeType, v.BridgeType) + suite.Equal(networks[i].NodeName, v.NodeName) + suite.Equal(networks[i].PhysicalPorts, v.PhysicalPorts) } } func (suite *NetworkTestSuite) TestListNetworkWithInvalidPage() { //Get data with non-exits ID httpRequest, err := http.NewRequest("GET", "http://localhost:7890/v1/networks?page=asdd", nil) - assert.NoError(suite.T(), err) + suite.NoError(err) httpWriter := httptest.NewRecorder() suite.wc.Dispatch(httpWriter, httpRequest) assertResponseCode(suite.T(), http.StatusBadRequest, httpWriter) httpRequest, err = http.NewRequest("GET", "http://localhost:7890/v1/networks?page_size=asdd", nil) - assert.NoError(suite.T(), err) + suite.NoError(err) httpWriter = httptest.NewRecorder() suite.wc.Dispatch(httpWriter, httpRequest) assertResponseCode(suite.T(), http.StatusBadRequest, httpWriter) httpRequest, err = http.NewRequest("GET", "http://localhost:7890/v1/networks?page=-1", nil) - assert.NoError(suite.T(), err) + suite.NoError(err) httpWriter = httptest.NewRecorder() suite.wc.Dispatch(httpWriter, httpRequest) diff --git a/src/serviceprovider/serviceprovider.go b/src/serviceprovider/serviceprovider.go index bda576bb..e1e31c88 100644 --- a/src/serviceprovider/serviceprovider.go +++ b/src/serviceprovider/serviceprovider.go @@ -8,6 +8,7 @@ import ( "github.com/linkernetworks/redis" kubeCtl "github.com/linkernetworks/vortex/src/kubernetes" "k8s.io/client-go/kubernetes" + fakeclientset "k8s.io/client-go/kubernetes/fake" ) type Container struct { @@ -33,7 +34,13 @@ func New(cf config.Config) *Container { logger.Infof("Connecting to mongodb: %s", cf.Mongo.Url) mongo := mongo.New(cf.Mongo.Url) - clientset := kubernetes.NewForConfigOrDie(cf.Kubernetes) + var clientset kubernetes.Interface + + if cf.Kubernetes != nil { + clientset = kubernetes.NewForConfigOrDie(cf.Kubernetes) + } else { + clientset = fakeclientset.NewSimpleClientset() + } sp := &Container{ Config: cf, From 11ee929183377be20452b32c7a5f50baeee752a6 Mon Sep 17 00:00:00 2001 From: yunchen Date: Tue, 26 Jun 2018 07:26:30 +0000 Subject: [PATCH 09/11] Add network controller testing Former-commit-id: 9b8a86d1333891f50b5a31a700075389832557d1 [formerly d43ebbadd5cf3b1cfbe1c7c566be447a86c3d6a7] Former-commit-id: cb8b3a145d39b5a92f32ce4f91d96453e1f4e993 --- .travis.yml | 2 +- .../networkcontroller_test.go | 103 ++++++++++++++++++ 2 files changed, 104 insertions(+), 1 deletion(-) create mode 100644 src/networkcontroller/networkcontroller_test.go diff --git a/.travis.yml b/.travis.yml index 984d5bc1..393cb335 100644 --- a/.travis.yml +++ b/.travis.yml @@ -16,7 +16,7 @@ notifications: before_install: - go get -u github.com/kardianos/govendor - sudo apt-get install -y git build-essential openvswitch-switch - - docker run -d -v /run/openvswitch/db.sock:/var/run/openvswitch/db.sock -p 50051:50051 sdnvortex/network-controller:latest /go/bin/server -tcp=0.0.0.0:50051 + - docker run -d -v /run/openvswitch/db.sock:/var/run/openvswitch/db.sock -p 50051:50051 sdnvortex/network-controller:v0.1 /go/bin/server -tcp=0.0.0.0:50051 install: - make pre-build diff --git a/src/networkcontroller/networkcontroller_test.go b/src/networkcontroller/networkcontroller_test.go new file mode 100644 index 00000000..a5f55f2d --- /dev/null +++ b/src/networkcontroller/networkcontroller_test.go @@ -0,0 +1,103 @@ +package networkcontroller + +import ( + "fmt" + "github.com/docker/docker/pkg/namesgenerator" + "github.com/linkernetworks/vortex/src/entity" + "github.com/linkernetworks/vortex/src/kubernetes" + "github.com/stretchr/testify/suite" + "os" + "os/exec" + "runtime" + "testing" + + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + fakeclientset "k8s.io/client-go/kubernetes/fake" +) + +type NetworkControllerTestSuite struct { + suite.Suite + kubectl *kubernetes.KubeCtl + ifName string + nodeName string +} + +func (suite *NetworkControllerTestSuite) SetupSuite() { + // init fakeclient + fakeclient := fakeclientset.NewSimpleClientset() + namespace := "default" + suite.kubectl = kubernetes.New(fakeclient, namespace) + + //Create a fake clinet + //Init + nodeAddr := corev1.NodeAddress{ + Type: "ExternalIP", + Address: "127.0.0.1", + } + + suite.nodeName = namesgenerator.GetRandomName(0)[0:8] + node := corev1.Node{ + ObjectMeta: metav1.ObjectMeta{ + Name: suite.nodeName, + }, + Status: corev1.NodeStatus{ + Addresses: []corev1.NodeAddress{nodeAddr}, + }, + } + _, err := suite.kubectl.Clientset.CoreV1().Nodes().Create(&node) + suite.NoError(err) + + //There's a length limit of link name + suite.ifName = namesgenerator.GetRandomName(0)[0:8] + pName := namesgenerator.GetRandomName(0)[0:8] + //Create a veth for testing + err = exec.Command("ip", "link", "add", suite.ifName, "type", "veth", "peer", "name", pName).Run() + suite.NoError(err) +} + +func TestNetworkControllerSuite(t *testing.T) { + if runtime.GOOS != "linux" { + fmt.Println("We only testing the ovs function on Linux Host") + t.Skip() + return + } + if _, defined := os.LookupEnv("TEST_GRPC"); !defined { + t.SkipNow() + return + } + suite.Run(t, new(NetworkControllerTestSuite)) +} + +func (suite *NetworkControllerTestSuite) TestNewNetworkController() { + network := entity.Network{ + NodeName: suite.nodeName, + } + + _, err := New(suite.kubectl, network) + suite.NoError(err) +} + +func (suite *NetworkControllerTestSuite) TestCreateNetwork() { + //Parameters + eth1 := entity.PhysicalPort{ + Name: suite.ifName, + MTU: 1500, + VlanTags: []int{2043, 2143, 2243}, + } + + tName := namesgenerator.GetRandomName(0) + network := entity.Network{ + BridgeName: tName, + BridgeType: "ovs", + NodeName: suite.nodeName, + PhysicalPorts: []entity.PhysicalPort{eth1}, + } + + nc, err := New(suite.kubectl, network) + suite.NoError(err) + err = nc.CreateNetwork() + suite.NoError(err) + + defer exec.Command("ovs-vsctl", "del-br", tName).Run() +} From 277445011b0ab28f447c14182103f6ab3fd5f845 Mon Sep 17 00:00:00 2001 From: John-Lin Date: Tue, 26 Jun 2018 15:51:57 +0800 Subject: [PATCH 10/11] rename and cleanup Former-commit-id: 01532cc601cd3c2701e7c09ca56b73478331b52f [formerly 60a958f907ed3830c2f67b0659341d243fc0f1bb] Former-commit-id: 195bbb0cd1785567bdc4589ba1b76ad5fa713a82 --- .travis.yml | 2 +- ...orkcontroller.go => network_controller.go} | 19 +++++++++++++------ ...ler_test.go => network_controller_test.go} | 5 +++++ src/server/handler_network.go | 10 +++++----- 4 files changed, 24 insertions(+), 12 deletions(-) rename src/networkcontroller/{networkcontroller.go => network_controller.go} (83%) rename src/networkcontroller/{networkcontroller_test.go => network_controller_test.go} (97%) diff --git a/.travis.yml b/.travis.yml index 393cb335..cb074d92 100644 --- a/.travis.yml +++ b/.travis.yml @@ -16,7 +16,7 @@ notifications: before_install: - go get -u github.com/kardianos/govendor - sudo apt-get install -y git build-essential openvswitch-switch - - docker run -d -v /run/openvswitch/db.sock:/var/run/openvswitch/db.sock -p 50051:50051 sdnvortex/network-controller:v0.1 /go/bin/server -tcp=0.0.0.0:50051 + - docker run -d -v /run/openvswitch/db.sock:/var/run/openvswitch/db.sock -p 50051:50051 sdnvortex/network-controller:v0.1.1 /go/bin/server -tcp=0.0.0.0:50051 install: - make pre-build diff --git a/src/networkcontroller/networkcontroller.go b/src/networkcontroller/network_controller.go similarity index 83% rename from src/networkcontroller/networkcontroller.go rename to src/networkcontroller/network_controller.go index b30dad91..30121668 100644 --- a/src/networkcontroller/networkcontroller.go +++ b/src/networkcontroller/network_controller.go @@ -1,12 +1,13 @@ package networkcontroller import ( + "time" + pb "github.com/linkernetworks/network-controller/messages" "github.com/linkernetworks/vortex/src/entity" "github.com/linkernetworks/vortex/src/kubernetes" "golang.org/x/net/context" "google.golang.org/grpc" - "time" ) type NetworkController struct { @@ -39,16 +40,22 @@ func New(kubeCtl *kubernetes.KubeCtl, network entity.Network) (*NetworkControlle } func (nc *NetworkController) CreateNetwork() error { - _, err := nc.ClientCtl.CreateBridge(nc.Context, &pb.CreateBridgeRequest{ - BridgeName: nc.Network.BridgeName}) + _, err := nc.ClientCtl.CreateBridge( + nc.Context, + &pb.CreateBridgeRequest{ + BridgeName: nc.Network.BridgeName, + }) if err != nil { return err } for _, port := range nc.Network.PhysicalPorts { - _, err := nc.ClientCtl.AddPort(nc.Context, &pb.AddPortRequest{ - BridgeName: nc.Network.BridgeName, - IfaceName: port.Name}) + _, err := nc.ClientCtl.AddPort( + nc.Context, + &pb.AddPortRequest{ + BridgeName: nc.Network.BridgeName, + IfaceName: port.Name, + }) if err != nil { return err } diff --git a/src/networkcontroller/networkcontroller_test.go b/src/networkcontroller/network_controller_test.go similarity index 97% rename from src/networkcontroller/networkcontroller_test.go rename to src/networkcontroller/network_controller_test.go index a5f55f2d..497fbd60 100644 --- a/src/networkcontroller/networkcontroller_test.go +++ b/src/networkcontroller/network_controller_test.go @@ -6,6 +6,7 @@ import ( "github.com/linkernetworks/vortex/src/entity" "github.com/linkernetworks/vortex/src/kubernetes" "github.com/stretchr/testify/suite" + "math/rand" "os" "os/exec" "runtime" @@ -16,6 +17,10 @@ import ( fakeclientset "k8s.io/client-go/kubernetes/fake" ) +func init() { + rand.Seed(time.Now().UnixNano()) +} + type NetworkControllerTestSuite struct { suite.Suite kubectl *kubernetes.KubeCtl diff --git a/src/server/handler_network.go b/src/server/handler_network.go index e5a21aea..bd57c74f 100644 --- a/src/server/handler_network.go +++ b/src/server/handler_network.go @@ -17,7 +17,7 @@ import ( ) func createNetworkHandler(ctx *web.Context) { - as, req, resp := ctx.ServiceProvider, ctx.Request, ctx.Response + sp, req, resp := ctx.ServiceProvider, ctx.Request, ctx.Response network := entity.Network{} if err := req.ReadEntity(&network); err != nil { @@ -26,7 +26,7 @@ func createNetworkHandler(ctx *web.Context) { return } - session := as.Mongo.NewSession() + session := sp.Mongo.NewSession() defer session.Close() session.C(entity.NetworkCollectionName).EnsureIndex(mgo.Index{ Key: []string{"bridgeName", "nodeName"}, @@ -43,15 +43,15 @@ func createNetworkHandler(ctx *web.Context) { } } - nc, err := networkcontroller.New(as.KubeCtl, network) + nc, err := networkcontroller.New(sp.KubeCtl, network) if err != nil { - logger.Error(err) + logger.Errorf("Failed to new network controller: %s", err.Error()) response.InternalServerError(req.Request, resp.ResponseWriter, err) return } if err := nc.CreateNetwork(); err != nil { - logger.Error(err) + logger.Errorf("Failed to create network: %s", err.Error()) response.InternalServerError(req.Request, resp.ResponseWriter, err) return } From 5761b55cc9400705878e75a3e83271c7f319c7db Mon Sep 17 00:00:00 2001 From: hwchiu Date: Tue, 26 Jun 2018 17:23:13 +0800 Subject: [PATCH 11/11] Use the NewForTest for fake client testing Former-commit-id: 77a268206ec391f8a59f2f855e7dc9abe45fe4bb [formerly 1e968e69808a0951b5b5d17a53d1fcb0ab956305] Former-commit-id: 84dc68d80d8088537007e1d9ea8205dce763a8ea --- src/config/config.go | 14 ------- .../network_controller_test.go | 3 +- src/server/handler_network_test.go | 2 +- src/server/handler_storage_provider_test.go | 10 ++--- src/server/handler_volume_test.go | 2 +- src/serviceprovider/serviceprovider.go | 41 ++++++++++++++++--- 6 files changed, 45 insertions(+), 27 deletions(-) diff --git a/src/config/config.go b/src/config/config.go index 0211ae10..4c10f363 100644 --- a/src/config/config.go +++ b/src/config/config.go @@ -4,13 +4,10 @@ import ( "encoding/json" "fmt" "os" - "path/filepath" "github.com/linkernetworks/logger" "github.com/linkernetworks/mongo" "github.com/linkernetworks/redis" - "k8s.io/client-go/rest" - "k8s.io/client-go/tools/clientcmd" ) type Config struct { @@ -18,7 +15,6 @@ type Config struct { Mongo *mongo.MongoConfig `json:"mongo"` Logger logger.LoggerConfig `json:"logger"` - Kubernetes *rest.Config `json:"kubernetes"` // the version settings of the current application Version string `json:"version"` } @@ -34,16 +30,6 @@ func Read(path string) (c Config, err error) { return c, fmt.Errorf("Failed to load the config file: %v\n", err) } - // FIXME, we need to find a way to test the fakeclient evne if we don't install the k8s - kubeconfig := filepath.Join(os.Getenv("HOME"), ".kube", "config") - c.Kubernetes, err = clientcmd.BuildConfigFromFlags("", kubeconfig) - if err != nil { - c.Kubernetes, err = rest.InClusterConfig() - if err != nil { - fmt.Errorf("Load the kubernetes config fail, use the fake k8s clinet instead") - } - } - return c, nil } diff --git a/src/networkcontroller/network_controller_test.go b/src/networkcontroller/network_controller_test.go index 497fbd60..c05495a4 100644 --- a/src/networkcontroller/network_controller_test.go +++ b/src/networkcontroller/network_controller_test.go @@ -2,15 +2,16 @@ package networkcontroller import ( "fmt" - "github.com/docker/docker/pkg/namesgenerator" "github.com/linkernetworks/vortex/src/entity" "github.com/linkernetworks/vortex/src/kubernetes" + "github.com/moby/moby/pkg/namesgenerator" "github.com/stretchr/testify/suite" "math/rand" "os" "os/exec" "runtime" "testing" + "time" corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" diff --git a/src/server/handler_network_test.go b/src/server/handler_network_test.go index 69fd0ef2..b7ad9756 100644 --- a/src/server/handler_network_test.go +++ b/src/server/handler_network_test.go @@ -45,7 +45,7 @@ type NetworkTestSuite struct { func (suite *NetworkTestSuite) SetupSuite() { cf := config.MustRead("../../config/testing.json") - sp := serviceprovider.New(cf) + sp := serviceprovider.NewForTesting(cf) //init session suite.session = sp.Mongo.NewSession() diff --git a/src/server/handler_storage_provider_test.go b/src/server/handler_storage_provider_test.go index 7e6a8498..382fbd5c 100644 --- a/src/server/handler_storage_provider_test.go +++ b/src/server/handler_storage_provider_test.go @@ -18,7 +18,7 @@ import ( func TestCreateStorageProvider(t *testing.T) { cf := config.MustRead("../../config/testing.json") - sp := serviceprovider.New(cf) + sp := serviceprovider.NewForTesting(cf) //Testing parameter tName := namesgenerator.GetRandomName(0) @@ -67,7 +67,7 @@ func TestCreateStorageProvider(t *testing.T) { func TestDeleteStorageProvider(t *testing.T) { cf := config.MustRead("../../config/testing.json") - sp := serviceprovider.New(cf) + sp := serviceprovider.NewForTesting(cf) //Testing parameter tName := namesgenerator.GetRandomName(0) @@ -107,7 +107,7 @@ func TestDeleteStorageProvider(t *testing.T) { func TestInValidDeleteStorageProvider(t *testing.T) { cf := config.MustRead("../../config/testing.json") - sp := serviceprovider.New(cf) + sp := serviceprovider.NewForTesting(cf) httpRequest, err := http.NewRequest("DELETE", "http://localhost:7890/v1/storageprovider/"+bson.NewObjectId().Hex(), nil) assert.NoError(t, err) @@ -121,7 +121,7 @@ func TestInValidDeleteStorageProvider(t *testing.T) { func TestListStorageProvider(t *testing.T) { cf := config.MustRead("../../config/testing.json") - sp := serviceprovider.New(cf) + sp := serviceprovider.NewForTesting(cf) session := sp.Mongo.NewSession() defer session.Close() @@ -189,7 +189,7 @@ func TestListStorageProvider(t *testing.T) { func TestListInvalidStorageProvider(t *testing.T) { cf := config.MustRead("../../config/testing.json") - sp := serviceprovider.New(cf) + sp := serviceprovider.NewForTesting(cf) //Invliad page size httpRequest, err := http.NewRequest("GET", "http://localhost:7890/v1/storageprovider?page=0", nil) diff --git a/src/server/handler_volume_test.go b/src/server/handler_volume_test.go index 64e1ec3f..89370fa0 100644 --- a/src/server/handler_volume_test.go +++ b/src/server/handler_volume_test.go @@ -33,7 +33,7 @@ type VolumeTestSuite struct { func (suite *VolumeTestSuite) SetupSuite() { cf := config.MustRead("../../config/testing.json") - sp := serviceprovider.New(cf) + sp := serviceprovider.NewForTesting(cf) //init session suite.session = sp.Mongo.NewSession() diff --git a/src/serviceprovider/serviceprovider.go b/src/serviceprovider/serviceprovider.go index e1e31c88..0894fc3f 100644 --- a/src/serviceprovider/serviceprovider.go +++ b/src/serviceprovider/serviceprovider.go @@ -1,14 +1,20 @@ package serviceprovider import ( + "fmt" "github.com/linkernetworks/logger" "github.com/linkernetworks/vortex/src/config" + "os" + "path/filepath" "github.com/linkernetworks/mongo" "github.com/linkernetworks/redis" kubeCtl "github.com/linkernetworks/vortex/src/kubernetes" + "k8s.io/client-go/kubernetes" fakeclientset "k8s.io/client-go/kubernetes/fake" + "k8s.io/client-go/rest" + "k8s.io/client-go/tools/clientcmd" ) type Container struct { @@ -34,14 +40,39 @@ func New(cf config.Config) *Container { logger.Infof("Connecting to mongodb: %s", cf.Mongo.Url) mongo := mongo.New(cf.Mongo.Url) - var clientset kubernetes.Interface + kubeconfig := filepath.Join(os.Getenv("HOME"), ".kube", "config") + k8s, err := clientcmd.BuildConfigFromFlags("", kubeconfig) + if err != nil { + k8s, err = rest.InClusterConfig() + if err != nil { + panic(fmt.Errorf("Load the kubernetes config fail")) + } + } + + clientset := kubernetes.NewForConfigOrDie(k8s) - if cf.Kubernetes != nil { - clientset = kubernetes.NewForConfigOrDie(cf.Kubernetes) - } else { - clientset = fakeclientset.NewSimpleClientset() + sp := &Container{ + Config: cf, + Redis: redisService, + Mongo: mongo, + KubeCtl: kubeCtl.New(clientset, "default"), } + return sp +} + +func NewForTesting(cf config.Config) *Container { + // setup logger configuration + logger.Setup(cf.Logger) + + logger.Infof("Connecting to redis: %s", cf.Redis.Addr()) + redisService := redis.New(cf.Redis) + + logger.Infof("Connecting to mongodb: %s", cf.Mongo.Url) + mongo := mongo.New(cf.Mongo.Url) + + clientset := fakeclientset.NewSimpleClientset() + sp := &Container{ Config: cf, Redis: redisService,