convert server to cnitool server
authorMichael Cambria <mcambria@redhat.com>
Thu, 18 Apr 2019 19:58:32 +0000 (15:58 -0400)
committerMichael Cambria <mcambria@redhat.com>
Thu, 18 Apr 2019 19:58:32 +0000 (15:58 -0400)
add-cmd.json
api/handler.go
check-cmd.json
client/main.go
del-cmd.json
server/main.go

index 999ea2c..4d36b4c 100644 (file)
@@ -1,7 +1,8 @@
 
 {"cmd":"ADD", 
-"ifName": "ensY",
-"containerID": "ContainerTwo",
-"netNS": "mcc-test-2",
-"stdIn": "stdInStrTwo"
+"ifName": "ens1",
+"containerID": "NotUsed",
+"netNS": "/var/run/netns/mcc-cni-test0",
+"conf": "bridge-mcc1-range-chain",
+"stdIn": "stdInStrNotUsed"
 } 
index 882459d..a71e5cf 100644 (file)
@@ -2,8 +2,29 @@ package api
 
 import (
        "log"
+       "context"
+       "crypto/sha512"
+       //"encoding/json"
+       "fmt"
+       "os"
+       "path/filepath"
+       "strings"
 
-       "golang.org/x/net/context"
+       "github.com/containernetworking/cni/libcni"
+)
+
+const (
+       EnvCNIPath        = "CNI_PATH"
+       EnvNetDir         = "NETCONFPATH"
+       //EnvCapabilityArgs = "CAP_ARGS"
+       //EnvCNIArgs        = "CNI_ARGS"
+       //EnvCNIIfname      = "CNI_IFNAME"
+
+       DefaultNetDir = "/etc/cni/net.d"
+
+       CmdAdd   = "add"
+       CmdCheck = "check"
+       CmdDel   = "del"
 )
 
 // Server represents the gRPC server
@@ -60,14 +81,25 @@ func (s *CNIServer) CNIop(ctx context.Context, in *CNImsg) (*CNIresult, error) {
 func (s *CNIServer) CNIadd(ctx context.Context, in *CNIaddMsg) (*ADDresult, error) {
 
        log.Printf("Receive message Conf file: %s", in.Conf)
-
        log.Printf("Receive message ContainerID: %s", in.ContainerID)
        log.Printf("Receive message NetNS: %s", in.NetNS)
        log.Printf("Receive message IfName: %s", in.IfName)
        log.Printf("Receive message CniArgs: %s", in.CniArgs)
+       log.Printf("Receive message CniCapArgs: %s", in.CapArgs)
 
-       cniResult := ADDresult{
-              StdOut: "stdOutStringHere",
+       netconf, rt, cninet, err := cniCommon(in.Conf, in.NetNS, in.IfName, in.CniArgs, in.CapArgs)
+       if err != nil {
+          return nil, err
+       }
+
+       result, err := cninet.AddNetworkList(context.TODO(), netconf, rt)
+       if err != nil {
+          return nil, err
+       }
+
+       cniResult := ADDresult{}
+       if result != nil {
+          cniResult.StdOut = result.String()
        }
 
        log.Printf("Response from server: %s", cniResult.StdOut)
@@ -78,11 +110,21 @@ func (s *CNIServer) CNIadd(ctx context.Context, in *CNIaddMsg) (*ADDresult, erro
 func (s *CNIServer) CNIcheck(ctx context.Context, in *CNIcheckMsg) (*CHECKresult, error) {
 
        log.Printf("Receive message Conf file: %s", in.Conf)
-
        log.Printf("Receive message ContainerID: %s", in.ContainerID)
        log.Printf("Receive message NetNS: %s", in.NetNS)
        log.Printf("Receive message IfName: %s", in.IfName)
        log.Printf("Receive message CniArgs: %s", in.CniArgs)
+       log.Printf("Receive message CniCapArgs: %s", in.CapArgs)
+
+       netconf, rt, cninet, err := cniCommon(in.Conf, in.NetNS, in.IfName, in.CniArgs, in.CapArgs)
+       if err != nil {
+          return nil, err
+       }
+
+       err = cninet.CheckNetworkList(context.TODO(), netconf, rt)
+       if err != nil {
+          return nil, err
+       }
 
        cniResult := CHECKresult{
               Error: "",
@@ -95,17 +137,146 @@ func (s *CNIServer) CNIcheck(ctx context.Context, in *CNIcheckMsg) (*CHECKresult
 // CNIdel generates result to a CNIdelMsg
 func (s *CNIServer) CNIdel(ctx context.Context, in *CNIdelMsg) (*DELresult, error) {
 
-       log.Printf("Receive message Conf file: %s", in.Conf)
 
+       log.Printf("Receive message Conf file: %s", in.Conf)
        log.Printf("Receive message ContainerID: %s", in.ContainerID)
        log.Printf("Receive message NetNS: %s", in.NetNS)
        log.Printf("Receive message IfName: %s", in.IfName)
        log.Printf("Receive message CniArgs: %s", in.CniArgs)
+       log.Printf("Receive message CniCapArgs: %s", in.CapArgs)
+
+       netconf, rt, cninet, err := cniCommon(in.Conf, in.NetNS, in.IfName, in.CniArgs, in.CapArgs)
+       if err != nil {
+          return nil, err
+       }
+
+       err = cninet.DelNetworkList(context.TODO(), netconf, rt)
+       if err != nil {
+          return nil, err
+       }
 
        cniResult := DELresult{
-              StdOut: "stdOutStringHere",
+              Error: "",
        }
 
        log.Printf("Response from server: %s", cniResult.StdOut)
        return &cniResult, nil
 }
+
+func parseArgs(args string) ([][2]string, error) {
+       var result [][2]string
+
+       pairs := strings.Split(args, ";")
+       for _, pair := range pairs {
+               kv := strings.Split(pair, "=")
+               if len(kv) != 2 || kv[0] == "" || kv[1] == "" {
+                       return nil, fmt.Errorf("invalid CNI_ARGS pair %q", pair)
+               }
+
+               result = append(result, [2]string{kv[0], kv[1]})
+       }
+
+       return result, nil
+}
+
+func cniCommon(conf string, netns string, ifName string, args string, capabilityArgsValue []*CNIcapArgs) (*libcni.NetworkConfigList, *libcni.RuntimeConf, *libcni.CNIConfig, error) {
+
+       log.Printf("cniCommon Called")
+
+       // TODO
+       //netdir := os.Getenv(EnvNetDir)
+       netdir := "/home/mcambria/go/src/github.com/containernetworking"
+       if netdir == "" {
+               netdir = DefaultNetDir
+       }
+       netconf, err := libcni.LoadConfList(netdir, conf)
+       if err != nil {
+               return nil, nil, nil, err
+       }
+
+       // TODO deal with capabilityArgs
+       //
+       //var capabilityArgs map[string]interface{}
+       //  //capabilityArgsValue := os.Getenv(EnvCapabilityArgs)
+       //if len(capabilityArgsValue) > 0 {
+       //      if err = json.Unmarshal([]byte(capabilityArgsValue), &capabilityArgs); err != nil {
+       //              return nil, nil, nil, err
+       //      }
+       //}
+
+       var cniArgs [][2]string
+       if args != "" {
+         if len(args) > 0 {
+               cniArgs, err = parseArgs(args)
+               if err != nil {
+                       return nil, nil, nil, err
+               }
+         }
+       }
+
+       if ifName == "" {
+               ifName = "eth0"
+       }
+
+       if netns != "" {
+         netns, err = filepath.Abs(netns)
+         if err != nil {
+               return nil, nil, nil, err
+         }
+       } else {
+         return nil, nil, nil, fmt.Errorf("network namespace is required")
+       }
+
+       // Generate the containerid by hashing the netns path
+       s := sha512.Sum512([]byte(netns))
+       containerID := fmt.Sprintf("cnitool-%x", s[:10])
+
+       // TODO
+       //cninet := libcni.NewCNIConfig(filepath.SplitList(os.Getenv(EnvCNIPath)), nil)
+       cniBinPath := "/home/mcambria/go/src/github.com/mccv1r0/plugins/bin"
+       cninet := libcni.NewCNIConfig(filepath.SplitList(cniBinPath), nil)
+
+       rt := &libcni.RuntimeConf{
+               ContainerID:    containerID,
+               NetNS:          netns,
+               IfName:         ifName,
+               Args:           cniArgs,
+               //CapabilityArgs: capabilityArgs,
+       }
+
+var f *os.File
+var sout string
+f, _ = os.OpenFile("/tmp/check.log", os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
+
+sout = fmt.Sprintf("mcc: cninet: %v of type %T \n", cninet, cninet)
+_, _ = f.Write([]byte(sout))
+sout = fmt.Sprintf("mcc: netconf: %v of type %T \n", netconf, netconf)
+_, _ = f.Write([]byte(sout))
+sout = fmt.Sprintf("mcc: rt: %v of type %T \n", rt, rt)
+_, _ = f.Write([]byte(sout))
+
+       return netconf, rt, cninet, nil
+}
+
+/*
+{
+
+       switch os.Args[1] {
+       case CmdAdd:
+               result, err := cninet.AddNetworkList(context.TODO(), netconf, rt)
+               if result != nil {
+                       _ = result.Print()
+               }
+               return err
+       case CmdCheck:
+               err := cninet.CheckNetworkList(context.TODO(), netconf, rt)
+               return err
+       case CmdDel:
+               err := cninet.DelNetworkList(context.TODO(), netconf, rt)
+               return err
+       }
+
+       return nil
+}
+*/
index 1472257..0c1f5e5 100644 (file)
@@ -1,7 +1,8 @@
 
 {"cmd":"CHECK", 
-"ifName": "ensY",
-"containerID": "ContainerTwo",
-"netNS": "mcc-test-2",
-"stdIn": "stdInStrTwo"
+"ifName": "ens1",
+"containerID": "NotUsed",
+"netNS": "/var/run/netns/mcc-cni-test0",
+"conf": "bridge-mcc1-range-chain",
+"stdIn": "stdInStrNotUsed"
 } 
index 2466ea4..ab5360f 100644 (file)
@@ -1,14 +1,38 @@
+
 package main
 
 import (
        "log"
+       "context"
+       "crypto/sha512"
+       "encoding/json"
+       "fmt"
+       "os"
+       "path/filepath"
+       "strings"
+
+       "github.com/containernetworking/cni/libcni"
 
        "github.com/mccv1r0/demo-grpc/api"
-       "golang.org/x/net/context"
        "google.golang.org/grpc"
        "google.golang.org/grpc/credentials"
 )
 
+const (
+       EnvCNIPath        = "CNI_PATH"
+       EnvNetDir         = "NETCONFPATH"
+       EnvCapabilityArgs = "CAP_ARGS"
+       EnvCNIArgs        = "CNI_ARGS"
+       EnvCNIIfname      = "CNI_IFNAME"
+
+       DefaultNetDir = "/etc/cni/net.d"
+
+       CmdAdd   = "add"
+       CmdCheck = "check"
+       CmdDel   = "del"
+)
+
+
 // Authentication holds the login/password
 type Authentication struct {
        Login    string
@@ -70,7 +94,7 @@ func sendgRPCusingUnix() error {
               ConfigPath: &cniPath,
               Cmd: api.CmdType_ADD,
               ContainerID: "containerOne",
-              NetNS: "mcc-test-0",
+              NetNS: "/var/run/netns/mcc-test-0",
               IfName: "ensX",
               StdIn: "stdInStringHere",
               CniArgs: "IgnoreUnknown=1;IP=10.1.0.20",
@@ -129,7 +153,7 @@ func sendgRPCusingTcp() error {
               ConfigPath: &cniPath,
               Cmd: api.CmdType_ADD,
               ContainerID: "containerOne",
-              NetNS: "mcc-test-0",
+              NetNS: "/var/run/netns/mcc-test-0",
               IfName: "ensX",
               StdIn: "stdInStringHere",
               CniArgs: "IgnoreUnknown=1;IP=10.1.0.20",
@@ -146,7 +170,7 @@ func sendgRPCusingTcp() error {
        cniAddMsg := api.CNIaddMsg{
               Conf: cniPath.NetConf,
               ContainerID: "containerOne",
-              NetNS: "mcc-test-0",
+              NetNS: "/var/run/netns/mcc-test-0",
               IfName: "ensX",
               CniArgs: "IgnoreUnknown=1;IP=10.1.0.20",
 
@@ -162,7 +186,7 @@ func sendgRPCusingTcp() error {
        return nil
 }
 
-func main() {
+func oldmain() {
      err := sendgRPCusingTcp()
      if err != nil {
                log.Fatalf("error when calling sendRPCusingTcp: %s", err)
@@ -173,3 +197,120 @@ func main() {
                log.Fatalf("error when calling sendRPCusingUnix: %s", err2)
      }
 }
+
+func parseArgs(args string) ([][2]string, error) {
+       var result [][2]string
+
+       pairs := strings.Split(args, ";")
+       for _, pair := range pairs {
+               kv := strings.Split(pair, "=")
+               if len(kv) != 2 || kv[0] == "" || kv[1] == "" {
+                       return nil, fmt.Errorf("invalid CNI_ARGS pair %q", pair)
+               }
+
+               result = append(result, [2]string{kv[0], kv[1]})
+       }
+
+       return result, nil
+}
+
+func main() {
+       if len(os.Args) < 4 {
+               usage()
+               return
+       }
+
+       netdir := os.Getenv(EnvNetDir)
+       if netdir == "" {
+               netdir = DefaultNetDir
+       }
+       netconf, err := libcni.LoadConfList(netdir, os.Args[2])
+       if err != nil {
+               exit(err)
+       }
+
+       var capabilityArgs map[string]interface{}
+       capabilityArgsValue := os.Getenv(EnvCapabilityArgs)
+       if len(capabilityArgsValue) > 0 {
+               if err = json.Unmarshal([]byte(capabilityArgsValue), &capabilityArgs); err != nil {
+                       exit(err)
+               }
+       }
+
+       var cniArgs [][2]string
+       args := os.Getenv(EnvCNIArgs)
+       if len(args) > 0 {
+               cniArgs, err = parseArgs(args)
+               if err != nil {
+                       exit(err)
+               }
+       }
+
+       ifName, ok := os.LookupEnv(EnvCNIIfname)
+       if !ok {
+               ifName = "eth0"
+       }
+
+       netns := os.Args[3]
+       netns, err = filepath.Abs(netns)
+       if err != nil {
+               exit(err)
+       }
+
+       // Generate the containerid by hashing the netns path
+       s := sha512.Sum512([]byte(netns))
+       containerID := fmt.Sprintf("cnitool-%x", s[:10])
+
+       cninet := libcni.NewCNIConfig(filepath.SplitList(os.Getenv(EnvCNIPath)), nil)
+
+       rt := &libcni.RuntimeConf{
+               ContainerID:    containerID,
+               NetNS:          netns,
+               IfName:         ifName,
+               Args:           cniArgs,
+               CapabilityArgs: capabilityArgs,
+       }
+
+var f *os.File
+var sout string
+f, _ = os.OpenFile("/tmp/check.log", os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
+
+sout = fmt.Sprintf("mcc: cninet: %v of type %T \n", cninet, cninet)
+_, _ = f.Write([]byte(sout))
+sout = fmt.Sprintf("mcc: netconf: %v of type %T \n", netconf, netconf)
+_, _ = f.Write([]byte(sout))
+sout = fmt.Sprintf("mcc: rt: %v of type %T \n", rt, rt)
+_, _ = f.Write([]byte(sout))
+
+       switch os.Args[1] {
+       case CmdAdd:
+               result, err := cninet.AddNetworkList(context.TODO(), netconf, rt)
+               if result != nil {
+                       _ = result.Print()
+               }
+               exit(err)
+       case CmdCheck:
+               err := cninet.CheckNetworkList(context.TODO(), netconf, rt)
+               exit(err)
+       case CmdDel:
+               exit(cninet.DelNetworkList(context.TODO(), netconf, rt))
+       }
+}
+
+func usage() {
+       exe := filepath.Base(os.Args[0])
+
+       fmt.Fprintf(os.Stderr, "%s: Add, check, or remove network interfaces from a network namespace\n", exe)
+       fmt.Fprintf(os.Stderr, "  %s add   <net> <netns>\n", exe)
+       fmt.Fprintf(os.Stderr, "  %s check <net> <netns>\n", exe)
+       fmt.Fprintf(os.Stderr, "  %s del   <net> <netns>\n", exe)
+       os.Exit(1)
+}
+
+func exit(err error) {
+       if err != nil {
+               fmt.Fprintf(os.Stderr, "%s\n", err)
+               os.Exit(1)
+       }
+       os.Exit(0)
+}
index 65cbd7d..ed29f68 100644 (file)
@@ -1,7 +1,8 @@
 
 {"cmd":"DEL", 
-"ifName": "ensY",
-"containerID": "ContainerTwo",
-"netNS": "mcc-test-2",
-"stdIn": "stdInStrTwo"
+"ifName": "ens1",
+"containerID": "NotUsed",
+"netNS": "/var/run/netns/mcc-cni-test0",
+"conf": "bridge-mcc1-range-chain",
+"stdIn": "stdInStrNotUsed"
 } 
index bc71aac..feb89fe 100644 (file)
@@ -7,11 +7,10 @@ import (
        "net/http"
        "strings"
        "syscall"
+       "context"
 
        "github.com/grpc-ecosystem/grpc-gateway/runtime"
 
-       "golang.org/x/net/context"
-
        "github.com/mccv1r0/demo-grpc/api"
        "google.golang.org/grpc"
        "google.golang.org/grpc/credentials"