cli: add network commands

Add update and list commands for notwork hotplug

Signed-off-by: Ruidong Cao <caoruidong@huawei.com>
This commit is contained in:
Ruidong Cao 2018-07-30 22:42:10 +08:00
parent 1a17200cc8
commit 72df219306
2 changed files with 204 additions and 0 deletions

View File

@ -129,6 +129,7 @@ var runtimeCommands = []cli.Command{
// Kata Containers specific extensions
kataCheckCLICommand,
kataEnvCLICommand,
kataNetworkCLICommand,
factoryCLICommand,
}

203
cli/network.go Normal file
View File

@ -0,0 +1,203 @@
// Copyright (c) 2018 Huawei Corporation.
//
// SPDX-License-Identifier: Apache-2.0
//
package main
import (
"encoding/json"
"fmt"
"os"
"github.com/kata-containers/agent/protocols/grpc"
vc "github.com/kata-containers/runtime/virtcontainers"
"github.com/sirupsen/logrus"
"github.com/urfave/cli"
)
type networkType int
const (
// interfaceType for interface operation
interfaceType networkType = iota
routeType
)
var kataNetworkCLICommand = cli.Command{
Name: "kata-network",
Usage: "manage interfaces and routes for container",
Subcommands: []cli.Command{
addIfaceCommand,
delIfaceCommand,
listIfacesCommand,
updateRoutesCommand,
listRoutesCommand,
},
Action: func(context *cli.Context) error {
return cli.ShowSubcommandHelp(context)
},
}
var addIfaceCommand = cli.Command{
Name: "add-iface",
Usage: "add an interface to a container",
ArgsUsage: `add-iface <container-id> file or - for stdin`,
Flags: []cli.Flag{},
Action: func(context *cli.Context) error {
return networkModifyCommand(context.Args().First(), context.Args().Get(1), interfaceType, true)
},
}
var delIfaceCommand = cli.Command{
Name: "del-iface",
Usage: "delete an interface from a container",
ArgsUsage: `del-iface <container-id> file or - for stdin`,
Flags: []cli.Flag{},
Action: func(context *cli.Context) error {
return networkModifyCommand(context.Args().First(), context.Args().Get(1), interfaceType, false)
},
}
var listIfacesCommand = cli.Command{
Name: "list-ifaces",
Usage: "list network interfaces in a container",
ArgsUsage: `list-ifaces <container-id>`,
Flags: []cli.Flag{},
Action: func(context *cli.Context) error {
return networkListCommand(context.Args().First(), interfaceType)
},
}
var updateRoutesCommand = cli.Command{
Name: "update-routes",
Usage: "update routes of a container",
ArgsUsage: `update-routes <container-id> file or - for stdin`,
Flags: []cli.Flag{},
Action: func(context *cli.Context) error {
return networkModifyCommand(context.Args().First(), context.Args().Get(1), routeType, true)
},
}
var listRoutesCommand = cli.Command{
Name: "list-routes",
Usage: "list network routes in a container",
ArgsUsage: `list-routes <container-id>`,
Flags: []cli.Flag{},
Action: func(context *cli.Context) error {
return networkListCommand(context.Args().First(), routeType)
},
}
func networkModifyCommand(containerID, input string, opType networkType, add bool) (err error) {
status, sandboxID, err := getExistingContainerInfo(containerID)
if err != nil {
return err
}
containerID = status.ID
kataLog = kataLog.WithFields(logrus.Fields{
"container": containerID,
"sandbox": sandboxID,
})
setExternalLoggers(kataLog)
// container MUST be running
if status.State.State != vc.StateRunning {
return fmt.Errorf("container %s is not running", containerID)
}
var (
f *os.File
output = defaultOutputFile
)
if input == "-" {
f = os.Stdin
} else {
f, err = os.Open(input)
if err != nil {
return err
}
defer f.Close()
}
switch opType {
case interfaceType:
var inf, resultingInf *grpc.Interface
if err = json.NewDecoder(f).Decode(&inf); err != nil {
return err
}
if add {
resultingInf, err = vci.AddInterface(sandboxID, inf)
if err != nil {
kataLog.WithField("resulting-interface", fmt.Sprintf("%+v", resultingInf)).
WithError(err).Error("add interface failed")
}
} else {
resultingInf, err = vci.RemoveInterface(sandboxID, inf)
if err != nil {
kataLog.WithField("resulting-interface", fmt.Sprintf("%+v", resultingInf)).
WithError(err).Error("delete interface failed")
}
}
json.NewEncoder(output).Encode(resultingInf)
case routeType:
var routes, resultingRoutes []*grpc.Route
if err = json.NewDecoder(f).Decode(&routes); err != nil {
return err
}
resultingRoutes, err = vci.UpdateRoutes(sandboxID, routes)
json.NewEncoder(output).Encode(resultingRoutes)
if err != nil {
kataLog.WithField("resulting-routes", fmt.Sprintf("%+v", resultingRoutes)).
WithError(err).Error("update routes failed")
}
}
return err
}
func networkListCommand(containerID string, opType networkType) (err error) {
status, sandboxID, err := getExistingContainerInfo(containerID)
if err != nil {
return err
}
containerID = status.ID
kataLog = kataLog.WithFields(logrus.Fields{
"container": containerID,
"sandbox": sandboxID,
})
setExternalLoggers(kataLog)
// container MUST be running
if status.State.State != vc.StateRunning {
return fmt.Errorf("container %s is not running", containerID)
}
var file = defaultOutputFile
switch opType {
case interfaceType:
var interfaces []*grpc.Interface
interfaces, err = vci.ListInterfaces(sandboxID)
if err != nil {
kataLog.WithField("existing-interfaces", fmt.Sprintf("%+v", interfaces)).
WithError(err).Error("list interfaces failed")
}
json.NewEncoder(file).Encode(interfaces)
case routeType:
var routes []*grpc.Route
routes, err = vci.ListRoutes(sandboxID)
if err != nil {
kataLog.WithField("resulting-routes", fmt.Sprintf("%+v", routes)).
WithError(err).Error("update routes failed")
}
json.NewEncoder(file).Encode(routes)
}
return err
}