Skip to content

Commit

Permalink
--keep-mgmt-net
Browse files Browse the repository at this point in the history
  • Loading branch information
steiler committed Jun 18, 2021
1 parent 66ab3d8 commit cab4781
Show file tree
Hide file tree
Showing 7 changed files with 85 additions and 14 deletions.
6 changes: 6 additions & 0 deletions clab/clab.go
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,12 @@ func WithRuntime(name string, d bool, dur time.Duration, gracefulShutdown bool)
}
}

func WithKeepMgmtNet() ClabOption {
return func(c *CLab) {
c.Runtime.WithKeepMgmtNet()
}
}

func WithTopoFile(file string) ClabOption {
return func(c *CLab) {
if file == "" {
Expand Down
14 changes: 11 additions & 3 deletions cmd/destroy.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,11 @@ import (
"github.com/srl-labs/containerlab/types"
)

var cleanup bool
var graceful bool
var (
cleanup bool
graceful bool
keepmgmtnet bool
)

// destroyCmd represents the destroy command
var destroyCmd = &cobra.Command{
Expand All @@ -41,6 +44,10 @@ var destroyCmd = &cobra.Command{
clab.WithRuntime(rt, debug, timeout, graceful),
}

if keepmgmtnet {
opts = append(opts, clab.WithKeepMgmtNet())
}

topos := map[string]struct{}{}

switch {
Expand Down Expand Up @@ -112,6 +119,7 @@ func init() {
destroyCmd.Flags().BoolVarP(&graceful, "graceful", "", false, "attempt to stop containers before removing")
destroyCmd.Flags().BoolVarP(&all, "all", "a", false, "destroy all containerlab labs")
destroyCmd.Flags().UintVarP(&maxWorkers, "max-workers", "", 0, "limit the maximum number of workers deleteing nodes")
destroyCmd.Flags().BoolVarP(&keepmgmtnet, "keep-mgmt-net", "", false, "do not remove the mgmt network")
}

func deleteEntriesFromHostsFile(containers []types.GenericContainer, bridgeName string) error {
Expand Down Expand Up @@ -202,7 +210,7 @@ func destroyLab(ctx context.Context, c *clab.CLab) (err error) {
}

// delete lab management network
log.Infof("Deleting network '%s'...", c.Config.Mgmt.Network)
log.Infof("Cleanup networking")
if err = c.Runtime.DeleteNet(ctx); err != nil {
// do not log error message if deletion error simply says that such network doesn't exist
if err.Error() != fmt.Sprintf("Error: No such network: %s", c.Config.Mgmt.Network) {
Expand Down
1 change: 0 additions & 1 deletion cmd/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,6 @@ var rootCmd = &cobra.Command{
if debug {
log.SetLevel(log.DebugLevel)
}

},
}

Expand Down
22 changes: 18 additions & 4 deletions runtime/containerd/containerd.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,14 +39,14 @@ const (
func init() {
runtime.Register(dockerRuntimeName, func() runtime.ContainerRuntime {
return &ContainerdRuntime{
Mgmt: new(types.MgmtNet),
}
Mgmt: new(types.MgmtNet)}
})
}

func (c *ContainerdRuntime) Init(opts ...runtime.RuntimeOption) error {
var err error
log.Info("Runtime: containerd")
c.keepMgmtNet = false
c.client, err = containerd.New("/run/containerd/containerd.sock")
if err != nil {
return err
Expand All @@ -71,6 +71,7 @@ type ContainerdRuntime struct {
Mgmt *types.MgmtNet
debug bool
gracefulShutdown bool
keepMgmtNet bool
}

func (c *ContainerdRuntime) WithConfig(cfg *runtime.RuntimeConfig) {
Expand All @@ -93,14 +94,27 @@ func (c *ContainerdRuntime) WithMgmtNet(n *types.MgmtNet) {
c.Mgmt = n
}

func (c *ContainerdRuntime) WithKeepMgmtNet() {
c.keepMgmtNet = true
}

func (c *ContainerdRuntime) CreateNet(ctx context.Context) error {
log.Debug("CreateNet() - Not needed with containerd")
return nil
}
func (c *ContainerdRuntime) DeleteNet(context.Context) error {
log.Debug("DeleteNet() - Not yet required with containerd")
return nil
bridgename := c.Mgmt.Bridge
brInUse, err := utils.CheckBrInUse(bridgename)
if c.keepMgmtNet || brInUse {
log.Infof("Skipping deletion of bridge '%s'", bridgename)
return nil
}
if err != nil {
return err
}
return utils.DeleteNetworkInterface(bridgename)
}

func (c *ContainerdRuntime) ContainerInspect(context.Context, string) (*types.GenericContainer, error) {
return nil, errors.New("not implemented")
}
Expand Down
19 changes: 13 additions & 6 deletions runtime/docker/docker.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,11 +48,13 @@ type DockerRuntime struct {
Mgmt *types.MgmtNet
debug bool
gracefulShutdown bool
keepMgmtNet bool
}

func (c *DockerRuntime) Init(opts ...runtime.RuntimeOption) error {
var err error
log.Info("Runtime: Docker")
c.keepMgmtNet = false
c.Client, err = dockerC.NewClientWithOpts(dockerC.FromEnv, dockerC.WithAPIVersionNegotiation())
if err != nil {
return err
Expand All @@ -63,6 +65,10 @@ func (c *DockerRuntime) Init(opts ...runtime.RuntimeOption) error {
return nil
}

func (c *DockerRuntime) WithKeepMgmtNet() {
c.keepMgmtNet = true
}

func (c *DockerRuntime) WithConfig(cfg *runtime.RuntimeConfig) {
c.timeout = cfg.Timeout
c.debug = cfg.Debug
Expand Down Expand Up @@ -183,28 +189,29 @@ func (c *DockerRuntime) CreateNet(ctx context.Context) (err error) {

// DeleteNet deletes a docker bridge
func (c *DockerRuntime) DeleteNet(ctx context.Context) (err error) {
if c.Mgmt.Network == "bridge" {
log.Debug("Skipping potential deletion of docker default bridge 'bridge'.")
network := c.Mgmt.Network
if network == "bridge" || c.keepMgmtNet {
log.Infof("Skipping potential deletion of docker default bridge '%s'", network)
return nil
}
nctx, cancel := context.WithTimeout(ctx, c.timeout)
defer cancel()

nres, err := c.Client.NetworkInspect(ctx, c.Mgmt.Network, dockerTypes.NetworkInspectOptions{})
nres, err := c.Client.NetworkInspect(ctx, network, dockerTypes.NetworkInspectOptions{})
if err != nil {
return err
}
numEndpoints := len(nres.Containers)
if numEndpoints > 0 {
if c.debug {
log.Debugf("network '%s' has %d active endpoints, deletion skipped", c.Mgmt.Network, numEndpoints)
log.Debugf("network '%s' has %d active endpoints, deletion skipped", network, numEndpoints)
for _, endp := range nres.Containers {
log.Debugf("'%s' is connected to %s", endp.Name, c.Mgmt.Network)
log.Debugf("'%s' is connected to %s", endp.Name, network)
}
}
return nil
}
err = c.Client.NetworkRemove(nctx, c.Mgmt.Network)
err = c.Client.NetworkRemove(nctx, network)
if err != nil {
return err
}
Expand Down
9 changes: 9 additions & 0 deletions runtime/runtime.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ type ContainerRuntime interface {
WithConfig(*RuntimeConfig)
// Set the network management details (generated by the config.go)
WithMgmtNet(*types.MgmtNet)
// Instructs the runtime not to delete the mgmt network on destroy
WithKeepMgmtNet()
// Create container (bridge) network
CreateNet(context.Context) error
// Delete container (bridge) network
Expand Down Expand Up @@ -57,6 +59,7 @@ type RuntimeConfig struct {
Timeout time.Duration
GracefulShutdown bool
Debug bool
KeepMgmtNet bool
}

var ContainerRuntimes = map[string]Initializer{}
Expand All @@ -76,3 +79,9 @@ func WithMgmtNet(mgmt *types.MgmtNet) RuntimeOption {
r.WithMgmtNet(mgmt)
}
}

func WithKeepMgmtNet() RuntimeOption {
return func(r ContainerRuntime) {
r.WithKeepMgmtNet()
}
}
28 changes: 28 additions & 0 deletions utils/netlink.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,3 +47,31 @@ func DefaultNetMTU() (string, error) {
}
return fmt.Sprint(b.MTU), nil
}

func CheckBrInUse(brname string) (bool, error) {
InUse := false
l, err := netlink.LinkList()
if err != nil {
return InUse, err
}
mgmtbr, err := netlink.LinkByName(brname)
if err != nil {
return InUse, err
}
mgmtbridx := mgmtbr.Attrs().Index
for _, link := range l {
if link.Attrs().MasterIndex == mgmtbridx {
InUse = true
break
}
}
return InUse, nil
}

func DeleteNetworkInterface(name string) error {
l, err := netlink.LinkByName(name)
if err != nil {
return err
}
return netlink.LinkDel(l)
}

0 comments on commit cab4781

Please sign in to comment.