From: Michael Cambria Date: Thu, 18 Apr 2019 19:58:32 +0000 (-0400) Subject: convert server to cnitool server X-Git-Url: https://git.halfball.org/?a=commitdiff_plain;h=7bdfd2db61e068d5bcce1104dd654c9fd22ec929;p=demo-grpc.git convert server to cnitool server --- diff --git a/add-cmd.json b/add-cmd.json index 999ea2c..4d36b4c 100644 --- a/add-cmd.json +++ b/add-cmd.json @@ -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" } diff --git a/api/handler.go b/api/handler.go index 882459d..a71e5cf 100644 --- a/api/handler.go +++ b/api/handler.go @@ -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 +} +*/ diff --git a/check-cmd.json b/check-cmd.json index 1472257..0c1f5e5 100644 --- a/check-cmd.json +++ b/check-cmd.json @@ -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" } diff --git a/client/main.go b/client/main.go index 2466ea4..ab5360f 100644 --- a/client/main.go +++ b/client/main.go @@ -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 \n", exe) + fmt.Fprintf(os.Stderr, " %s check \n", exe) + fmt.Fprintf(os.Stderr, " %s del \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) +} diff --git a/del-cmd.json b/del-cmd.json index 65cbd7d..ed29f68 100644 --- a/del-cmd.json +++ b/del-cmd.json @@ -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" } diff --git a/server/main.go b/server/main.go index bc71aac..feb89fe 100644 --- a/server/main.go +++ b/server/main.go @@ -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"