Skip to content

Commit

Permalink
Merge pull request #261 from srl-wim/mysocket
Browse files Browse the repository at this point in the history
added mysocketio integration
  • Loading branch information
hellt authored Feb 16, 2021
2 parents 38339e0 + aa8d969 commit 6ca453b
Show file tree
Hide file tree
Showing 13 changed files with 328 additions and 21 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 err
}
22 changes: 19 additions & 3 deletions clab/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,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 @@ -68,6 +68,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
Publish []string `yaml:"publish,omitempty"` // list of ports to publish 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 @@ -128,7 +129,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
Publish []string //list of ports to publish with mysocketctl
}

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

func (c *CLab) publishInit(nodeCfg *NodeConfig, kind string) []string {
switch {
case len(nodeCfg.Publish) != 0:
return nodeCfg.Publish
case len(c.Config.Topology.Kinds[kind].Publish) != 0:
return c.Config.Topology.Kinds[kind].Publish
case len(c.Config.Topology.Defaults.Publish) != 0:
return c.Config.Topology.Defaults.Publish
}
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 @@ -410,6 +424,8 @@ func (c *CLab) NewNode(nodeName string, nodeCfg NodeConfig, idx int) error {

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

node.Publish = c.publishInit(&nodeCfg, node.Kind)

switch node.Kind {
case "ceos":
// initialize the global parameters with defaults, can be overwritten later
Expand Down Expand Up @@ -647,7 +663,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, err = c.configInit(&nodeCfg, node.Kind)
if err != nil {
return err
Expand Down
14 changes: 14 additions & 0 deletions clab/docker.go
Original file line number Diff line number Diff line change
Expand Up @@ -345,6 +345,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.Publish) == 0 {
continue
}
for _, socket := range n.Publish {
split := strings.Split(socket, "/")
if len(split) > 2 {
log.Warnf("wrong mysocketio publish section %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 @@ -238,7 +238,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 published ports 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 {
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("Published ports:")
fmt.Println(string(stdout))
}

func getContainerIPv4(container types.Container, bridgeName string) string {
Expand Down
2 changes: 1 addition & 1 deletion docs/index.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<p align=center><img src=https://gitlab.com/rdodin/pics/-/wikis/uploads/18b84497134ee39510d9daa6bc6712ad/containerlab_export.svg?sanitize=true/></p>
<p align=center><img src=https://gitlab.com/rdodin/pics/-/wikis/uploads/9f2e581a8d207a21ff024a312679a239/containerlab_export_white_ink_3.svg?sanitize=true/></p>

[![github release](https://img.shields.io/github/release/srl-wim/container-lab.svg?style=flat-square&color=00c9ff&labelColor=bec8d2)](https://github.com/srl-wim/container-lab/releases/)
[![Github all releases](https://img.shields.io/github/downloads/srl-wim/container-lab/total.svg?style=flat-square&color=00c9ff&labelColor=bec8d2)](https://github.com/srl-wim/container-lab/releases/)
Expand Down
16 changes: 16 additions & 0 deletions docs/manual/nodes.md
Original file line number Diff line number Diff line change
Expand Up @@ -141,4 +141,20 @@ topology:
nodes:
node1:
cmd: bash cmd3.sh
```

### share
Container lab integrates with [mysocket.io](https://mysocket.io) service to allow for private, Internet-reachable tunnels created for sockets of containerlab nodes. This enables effortless access sharing with cusomters/partners/colleagues.

This integration is extensively described on [Share lab access](published-ports.md) page.

```yaml
name: demo
topology:
nodes:
r1:
kind: srl
share:
- tcp/22 # tcp port 22 will be exposed
- tcp/57400 # tcp port 57400 will be exposed
```
Loading

0 comments on commit 6ca453b

Please sign in to comment.