Skip to content

Commit

Permalink
added mysocketsio integration
Browse files Browse the repository at this point in the history
  • Loading branch information
hellt committed Feb 4, 2021
1 parent e4fe285 commit d862df1
Show file tree
Hide file tree
Showing 11 changed files with 310 additions and 20 deletions.
2 changes: 2 additions & 0 deletions .goreleaser.yml
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,8 @@ nfpms:
dst: /etc/containerlab/lab-examples
- src: ./templates/**/*
dst: /etc/containerlab/templates
- src: ./tools/**/*
dst: /etc/containerlab/tools
- src: /usr/bin/containerlab
dst: /usr/bin/clab
type: symlink
44 changes: 30 additions & 14 deletions clab/clab.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package clab

import (
"context"
"fmt"
"strconv"
"strings"
"sync"
Expand Down Expand Up @@ -169,23 +170,11 @@ func (c *CLab) ExecPostDeployTasks(ctx context.Context, node *Node, lworkers uin

case "linux":
log.Debugf("Running postdeploy actions for Linux '%s' node", node.ShortName)
// disable tx checksum offload for linux containers on lo and eth0 interfaces
nodeNS, err := ns.GetNS(node.NSPath)
if err != nil {
return err
}
err = nodeNS.Do(func(_ ns.NetNS) error {
// disabling offload on lo0 interface
err = EthtoolTXOff("eth0")
if err != nil {
log.Infof("Failed to disable TX checksum offload for 'eth0' interface for Linux '%s' node: %v", node.ShortName, err)
}
return nil
})
return err
return disableTxOffload(node)

case "sonic-vs":
log.Debugf("Running postdeploy actions for sonic-vs '%s' node", node.ShortName)
// TODO: change this calls to c.ExecNotWait
// exec `supervisord` to start sonic services
execConfig := types.ExecConfig{Tty: false, AttachStdout: false, AttachStderr: false, Cmd: strings.Fields("supervisord")}
respID, err := c.DockerClient.ContainerExecCreate(context.Background(), node.ContainerID, execConfig)
Expand All @@ -206,6 +195,16 @@ func (c *CLab) ExecPostDeployTasks(ctx context.Context, node *Node, lworkers uin
if err != nil {
return err
}
case "mysocketio":
log.Debugf("Running postdeploy actions for mysocketio '%s' node", node.ShortName)
err := disableTxOffload(node)
if err != nil {
return fmt.Errorf("failed to disable tx checksum offload for mysocketio kind: %v", err)
}

log.Infof("Creating mysocketio tunnels...")
err = createMysocketTunnels(ctx, c, node)
return err
}
return nil
}
Expand Down Expand Up @@ -235,3 +234,20 @@ func (c *CLab) CreateLinks(ctx context.Context, workers uint, linksChan chan *Li
}(i)
}
}

func disableTxOffload(n *Node) error {
// disable tx checksum offload for linux containers on eth0 interfaces
nodeNS, err := ns.GetNS(n.NSPath)
if err != nil {
return err
}
err = nodeNS.Do(func(_ ns.NetNS) error {
// disabling offload on lo0 interface
err := EthtoolTXOff("eth0")
if err != nil {
log.Infof("Failed to disable TX checksum offload for 'eth0' interface for Linux '%s' node: %v", n.ShortName, err)
}
return err
})
return nil
}
22 changes: 19 additions & 3 deletions clab/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ const (
)

// supported kinds
var kinds = []string{"srl", "ceos", "crpd", "sonic-vs", "vr-sros", "vr-vmx", "vr-xrv", "vr-xrv9k", "linux", "bridge"}
var kinds = []string{"srl", "ceos", "crpd", "sonic-vs", "vr-sros", "vr-vmx", "vr-xrv", "vr-xrv9k", "linux", "bridge", "mysocketio"}

var defaultConfigTemplates = map[string]string{
"srl": "/etc/containerlab/templates/srl/srlconfig.tpl",
Expand Down Expand Up @@ -67,6 +67,7 @@ type NodeConfig struct {
Ports []string `yaml:"ports,omitempty"` // list of port bindings
MgmtIPv4 string `yaml:"mgmt_ipv4,omitempty"` // user-defined IPv4 address in the management network
MgmtIPv6 string `yaml:"mgmt_ipv6,omitempty"` // user-defined IPv6 address in the management network
Share []string `yaml:"share,omitempty"` // list of ports to share with mysocketctl

Env map[string]string `yaml:"env,omitempty"` // environment variables
User string `yaml:"user,omitempty"` // linux user used in a container
Expand Down Expand Up @@ -126,7 +127,8 @@ type Node struct {
TLSCert string
TLSKey string
TLSAnchor string
NSPath string // network namespace path for this node
NSPath string // network namespace path for this node
Share []string //list of ports to share with mysocketctl
}

// Link is a struct that contains the information of a link between 2 containers
Expand Down Expand Up @@ -349,6 +351,18 @@ func (c *CLab) userInit(nodeCfg *NodeConfig, kind string) string {
return ""
}

func (c *CLab) shareInit(nodeCfg *NodeConfig, kind string) []string {
switch {
case len(nodeCfg.Share) != 0:
return nodeCfg.Share
case len(c.Config.Topology.Kinds[kind].Share) != 0:
return c.Config.Topology.Kinds[kind].Share
case len(c.Config.Topology.Defaults.Share) != 0:
return c.Config.Topology.Defaults.Share
}
return nil
}

// NewNode initializes a new node object
func (c *CLab) NewNode(nodeName string, nodeCfg NodeConfig, idx int) error {
// initialize a new node
Expand Down Expand Up @@ -387,6 +401,8 @@ func (c *CLab) NewNode(nodeName string, nodeCfg NodeConfig, idx int) error {

user := c.userInit(&nodeCfg, node.Kind)

node.Share = c.shareInit(&nodeCfg, node.Kind)

switch node.Kind {
case "ceos":
// initialize the global parameters with defaults, can be overwritten later
Expand Down Expand Up @@ -598,7 +614,7 @@ func (c *CLab) NewNode(nodeName string, nodeCfg NodeConfig, idx int) error {

node.Cmd = fmt.Sprintf("--username %s --password %s --hostname %s --connection-mode %s --vcpu %s --ram %s --trace", node.Env["USERNAME"], node.Env["PASSWORD"], node.ShortName, node.Env["CONNECTION_MODE"], node.Env["VCPU"], node.Env["RAM"])

case "alpine", "linux":
case "alpine", "linux", "mysocketio":
node.Config = c.configInit(&nodeCfg, node.Kind)
node.Image = c.imageInitialization(&nodeCfg, node.Kind)
node.Group = c.groupInitialization(&nodeCfg, node.Kind)
Expand Down
14 changes: 14 additions & 0 deletions clab/docker.go
Original file line number Diff line number Diff line change
Expand Up @@ -344,6 +344,20 @@ func (c *CLab) Exec(ctx context.Context, id string, cmd []string) ([]byte, []byt
return outBuf.Bytes(), errBuf.Bytes(), nil
}

// ExecNotWait executes cmd on container identified with id but doesn't wait for output nor attaches stodout/err
func (c *CLab) ExecNotWait(ctx context.Context, id string, cmd []string) error {
execConfig := types.ExecConfig{Tty: false, AttachStdout: false, AttachStderr: false, Cmd: cmd}
respID, err := c.DockerClient.ContainerExecCreate(context.Background(), id, execConfig)
if err != nil {
return err
}
_, err = c.DockerClient.ContainerExecAttach(context.Background(), respID.ID, execConfig)
if err != nil {
return err
}
return nil
}

// DeleteContainer tries to stop a container then remove it
func (c *CLab) DeleteContainer(ctx context.Context, name string) error {
var err error
Expand Down
58 changes: 58 additions & 0 deletions clab/mysocketio.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
package clab

import (
"context"
"fmt"
"strings"

log "github.com/sirupsen/logrus"
)

// createMysocketTunnels creates internet reachable personal tunnels using mysocket.io
func createMysocketTunnels(ctx context.Context, c *CLab, node *Node) error {
// remove the existing sockets
cmd := []string{"/bin/sh", "-c", "mysocketctl socket ls | awk '/clab/ {print $2}' | xargs -n1 mysocketctl socket delete -s"}
log.Debugf("Running postdeploy mysocketio command %q", cmd)
_, _, err := c.Exec(ctx, node.ContainerID, cmd)
if err != nil {
return fmt.Errorf("failed to remove existing sockets: %v", err)
}

for _, n := range c.Nodes {
if len(n.Share) == 0 {
continue
}
for _, socket := range n.Share {
split := strings.Split(socket, "/")
if len(split) > 2 {
log.Warnf("wrong mysocketio share definition %s. should be type/port-number, i.e. tcp/22", socket)
}
t := split[0] // type
p := split[1] // port

// create socket and get its ID
cmd := []string{"/bin/sh", "-c", fmt.Sprintf("mysocketctl socket create -t %s -n clab-%s-%s-%s | awk 'NR==4 {print $2}'", t, t, p, n.ShortName)}
log.Debugf("Running mysocketio command %q", cmd)
stdout, _, err := c.Exec(ctx, node.ContainerID, cmd)
if err != nil {
return fmt.Errorf("failed to create mysocketio socket: %v", err)
}
sockID := strings.TrimSpace(string(stdout))

// create tunnel and get its ID
cmd = []string{"/bin/sh", "-c", fmt.Sprintf("mysocketctl tunnel create -s %s | awk 'NR==4 {print $4}'", sockID)}
log.Debugf("Running mysocketio command %q", cmd)
stdout, _, err = c.Exec(ctx, node.ContainerID, cmd)
if err != nil {
return fmt.Errorf("failed to create mysocketio socket: %v", err)
}
tunID := strings.TrimSpace(string(stdout))

// connect tunnel
cmd = []string{"/bin/sh", "-c", fmt.Sprintf("mysocketctl tunnel connect --host %s -p %s -s %s -t %s > socket-%s-%s-%s.log", n.LongName, p, sockID, tunID, n.ShortName, t, p)}
log.Debugf("Running mysocketio command %q", cmd)
c.ExecNotWait(ctx, node.ContainerID, cmd)
}
}
return nil
}
2 changes: 1 addition & 1 deletion cmd/deploy.go
Original file line number Diff line number Diff line change
Expand Up @@ -232,7 +232,7 @@ var deployCmd = &cobra.Command{
log.Errorf("failed to create hosts file: %v", err)
}
// print table summary
printContainerInspect(containers, c.Config.Mgmt.Network, format)
printContainerInspect(c, containers, c.Config.Mgmt.Network, format)
return nil
},
}
Expand Down
26 changes: 24 additions & 2 deletions cmd/inspect.go
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ var inspectCmd = &cobra.Command{
fmt.Println(string(b))
return
}
printContainerInspect(containers, c.Config.Mgmt.Network, format)
printContainerInspect(c, containers, c.Config.Mgmt.Network, format)
},
}

Expand All @@ -103,8 +103,12 @@ func toTableData(det []containerDetails) [][]string {
return tabData
}

func printContainerInspect(containers []types.Container, bridgeName string, format string) {
func printContainerInspect(c *clab.CLab, containers []types.Container, bridgeName string, format string) {
contDetails := make([]containerDetails, 0, len(containers))
// do not print shared sockets unless mysocketio kind is found
printMysocket := false
var mysocketCID string

for _, cont := range containers {
// get topo file path relative of the cwd
cwd, _ := os.Getwd()
Expand All @@ -126,6 +130,10 @@ func printContainerInspect(containers []types.Container, bridgeName string, form
}
if kind, ok := cont.Labels["kind"]; ok {
cdet.Kind = kind
if kind == "mysocketio" {
printMysocket = true
mysocketCID = cont.ID
}
}
if group, ok := cont.Labels["group"]; ok {
cdet.Group = group
Expand Down Expand Up @@ -170,6 +178,20 @@ func printContainerInspect(containers []types.Container, bridgeName string, form
table.SetAutoMergeCellsByColumnIndex([]int{1, 2})
table.AppendBulk(tabData)
table.Render()

if printMysocket == false {
return
}
stdout, stderr, err := c.Exec(context.Background(), mysocketCID, []string{"mysocketctl", "socket", "ls"})
if err != nil {
log.Errorf("failed to execute cmd: %v", err)

}
if len(stderr) > 0 {
log.Infof("errors during listing mysocketio sockets: %s", string(stderr))
}
fmt.Println("Shared sockets:")
fmt.Println(string(stdout))
}

func getContainerIPv4(container types.Container, bridgeName string) string {
Expand Down
Loading

0 comments on commit d862df1

Please sign in to comment.