Skip to content

Commit

Permalink
Merge branch 'master' into srl-cfg-w-scrapligo
Browse files Browse the repository at this point in the history
  • Loading branch information
hellt committed Sep 11, 2021
2 parents 2e6ae5e + 0b8ec47 commit aa679ec
Show file tree
Hide file tree
Showing 7 changed files with 81 additions and 11 deletions.
3 changes: 3 additions & 0 deletions clab/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -243,6 +243,9 @@ func (c *CLab) createNodeCfg(nodeName string, nodeDef *types.NodeDefinition, idx
CPU: c.Config.Topology.GetNodeCPU(nodeName),
RAM: c.Config.Topology.GetNodeRAM(nodeName),
StartupDelay: c.Config.Topology.GetNodeStartupDelay(nodeName),

// Extras
Extras: c.Config.Topology.GetNodeExtras(nodeName),
}

log.Debugf("node config: %+v", nodeCfg)
Expand Down
18 changes: 17 additions & 1 deletion docs/manual/kinds/srl.md
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,22 @@ INFO[0001] saved SR Linux configuration from leaf2 node. Output:
Saved current running configuration as initial (startup) configuration '/etc/opt/srlinux/config.json'
```

#### User defined custom agents for SR Linux nodes
SR Linux supports custom "agents", i.e. small independent pieces of software that extend the functionality of the core platform and integrate with the CLI and the rest of the system. To deploy an agent, a YAML configuration file must be placed under `/etc/opt/srlinux/appmgr/`. This feature adds the ability to copy agent YAML file(s) to the config directory of a specific SRL node, or all such nodes.

```yaml
name: srl_lab_with_custom_agents
topology:
nodes:
srl1:
kind: srl
...
extras:
srl-agents:
- path1/my_custom_agent.yml
- path2/my_other_agent.yml
```

### TLS
By default containerlab will generate TLS certificates and keys for each SR Linux node of a lab. The TLS related files that containerlab creates are located in the so-called CA directory which can be located by the `<lab-directory>/ca/` path. Here is a list of files that containerlab creates relative to the CA directory

Expand Down Expand Up @@ -149,4 +165,4 @@ The `config` directory is mounted to container's `/etc/opt/srlinux/` path in `rw
banner cli config.json devices tls ztp
```
The topology file that defines the emulated hardware type is driven by the value of the kinds `type` parameter. Depending on a specified `type` the appropriate content will be populated into the `topology.yml` file that will get mounted to `/tmp/topology.yml` directory inside the container in `ro` mode.
The topology file that defines the emulated hardware type is driven by the value of the kinds `type` parameter. Depending on a specified `type` the appropriate content will be populated into the `topology.yml` file that will get mounted to `/tmp/topology.yml` directory inside the container in `ro` mode.
15 changes: 15 additions & 0 deletions nodes/srl/srl.go
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,21 @@ func (s *srl) PreDeploy(configName, labCADir, labCARoot string) error {
s.cfg.TLSCert = string(nodeCerts.Cert)
s.cfg.TLSKey = string(nodeCerts.Key)

// Create appmgr subdir for agent specs and copy files, if needed
if s.cfg.Extras != nil && len(s.cfg.Extras.SRLAgents) != 0 {
agents := s.cfg.Extras.SRLAgents
appmgr := filepath.Join(s.cfg.LabDir, "config/appmgr/")
utils.CreateDirectory(appmgr, 0777)

for _, fullpath := range agents {
basename := filepath.Base(fullpath)
dst := filepath.Join(appmgr, basename)
if err := utils.CopyFile(fullpath, dst); err != nil {
return fmt.Errorf("agent copy src %s -> dst %s failed %v", fullpath, dst, err)
}
}
}

return createSRLFiles(s.cfg)
}

Expand Down
20 changes: 10 additions & 10 deletions runtime/ignite/iginite.go
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ func init() {
})
}

func (c *IgniteRuntime) GetName() string { return runtimeName }
func (*IgniteRuntime) GetName() string { return runtimeName }
func (c *IgniteRuntime) Config() runtime.RuntimeConfig { return c.config }

func (c *IgniteRuntime) Init(opts ...runtime.RuntimeOption) error {
Expand Down Expand Up @@ -137,7 +137,7 @@ func (c *IgniteRuntime) DeleteNet(ctx context.Context) error {
return c.ctrRuntime.DeleteNet(ctx)
}

func (c *IgniteRuntime) PullImageIfRequired(ctx context.Context, imageName string) error {
func (*IgniteRuntime) PullImageIfRequired(_ context.Context, imageName string) error {
ociRef, err := meta.NewOCIImageRef(imageName)
if err != nil {
return fmt.Errorf("failed to parse OCI image ref %q: %s", imageName, err)
Expand Down Expand Up @@ -217,7 +217,7 @@ func (c *IgniteRuntime) CreateContainer(ctx context.Context, node *types.NodeCon
}
defer os.Remove(udevFile.Name())

if _, err := udevFile.Write([]byte(strings.Join(udevRules, "\n"))); err != nil {
if _, err := udevFile.Write([]byte(strings.Join(udevRules, "\n") + "\n")); err != nil {
return nil, err
}
if err := udevFile.Close(); err != nil {
Expand Down Expand Up @@ -262,16 +262,16 @@ func (c *IgniteRuntime) CreateContainer(ctx context.Context, node *types.NodeCon
return vmChans, utils.LinkContainerNS(node.NSPath, node.LongName)
}

func (c *IgniteRuntime) StartContainer(ctx context.Context, _ string) error {
func (*IgniteRuntime) StartContainer(_ context.Context, _ string) error {
// this is a no-op
return nil
}
func (c *IgniteRuntime) StopContainer(ctx context.Context, name string) error {
func (*IgniteRuntime) StopContainer(_ context.Context, _ string) error {
// this is a no-op, only used by ceos at this stage
return nil
}

func (c *IgniteRuntime) ListContainers(ctx context.Context, gfilters []*types.GenericFilter) ([]types.GenericContainer, error) {
func (c *IgniteRuntime) ListContainers(_ context.Context, gfilters []*types.GenericFilter) ([]types.GenericContainer, error) {

var result []types.GenericContainer

Expand Down Expand Up @@ -311,7 +311,7 @@ func (c *IgniteRuntime) ListContainers(ctx context.Context, gfilters []*types.Ge
return c.produceGenericContainerList(filteredVMs)
}

func (c *IgniteRuntime) GetContainer(ctx context.Context, containerID string) (*types.GenericContainer, error) {
func (c *IgniteRuntime) GetContainer(_ context.Context, containerID string) (*types.GenericContainer, error) {
var result *types.GenericContainer
vm, err := providers.Client.VMs().Find(filter.NewVMFilter(containerID))
if err != nil {
Expand All @@ -330,7 +330,7 @@ func (c *IgniteRuntime) GetContainer(ctx context.Context, containerID string) (*
}

// Transform docker-specific to generic container format
func (c *IgniteRuntime) produceGenericContainerList(input []*api.VM) ([]types.GenericContainer, error) {
func (*IgniteRuntime) produceGenericContainerList(input []*api.VM) ([]types.GenericContainer, error) {
var result []types.GenericContainer

for _, i := range input {
Expand Down Expand Up @@ -376,11 +376,11 @@ func (c *IgniteRuntime) GetNSPath(ctx context.Context, ctrId string) (string, er
return result, nil
}

func (c *IgniteRuntime) Exec(context.Context, string, []string) ([]byte, []byte, error) {
func (*IgniteRuntime) Exec(context.Context, string, []string) ([]byte, []byte, error) {
log.Infof("Exec is not yet implemented for Ignite runtime")
return []byte{}, []byte{}, nil
}
func (c *IgniteRuntime) ExecNotWait(context.Context, string, []string) error {
func (*IgniteRuntime) ExecNotWait(context.Context, string, []string) error {
log.Infof("ExecNotWait is not yet implemented for Ignite runtime")
return nil
}
Expand Down
10 changes: 10 additions & 0 deletions types/node_definition.go
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,9 @@ type NodeDefinition struct {
CPU string `yaml:"cpu,omitempty"`
// Set node RAM (cgroup or hypervisor)
RAM string `yaml:"ram,omitempty"`

// Extra options, may be kind specific
Extras *Extras `yaml:"extras,omitempty"`
}

func (n *NodeDefinition) GetKind() string {
Expand Down Expand Up @@ -244,6 +247,13 @@ func (n *NodeDefinition) GetExec() []string {
return n.Exec
}

func (n *NodeDefinition) GetExtras() *Extras {
if n == nil {
return nil
}
return n.Extras
}

// ImportEnvs imports all environment variales defined in the shell
// if __IMPORT_ENVS is set to true
func (n *NodeDefinition) ImportEnvs() {
Expand Down
18 changes: 18 additions & 0 deletions types/topology.go
Original file line number Diff line number Diff line change
Expand Up @@ -400,6 +400,24 @@ func (t *Topology) GetNodeRAM(name string) string {
return ""
}

// Returns the 'extras' section for the given node
func (t *Topology) GetNodeExtras(name string) *Extras {
if ndef, ok := t.Nodes[name]; ok {
node_extras := ndef.GetExtras()
if node_extras != nil {
return node_extras
}

kind_extras := t.GetKind(t.GetNodeKind(name)).GetExtras()
if kind_extras != nil {
return kind_extras
}

return t.GetDefaults().GetExtras()
}
return nil
}

func (t *Topology) ImportEnvs() {
t.Defaults.ImportEnvs()

Expand Down
8 changes: 8 additions & 0 deletions types/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,9 @@ type NodeConfig struct {
// Resource requirements
CPU, RAM string
DeploymentStatus string // status that is set by containerlab to indicate deployment stage

// Extras
Extras *Extras // Extra node parameters
}

// GenerateConfig generates configuration for the nodes
Expand Down Expand Up @@ -228,3 +231,8 @@ func (cd *ConfigDispatcher) GetVars() map[string]interface{} {
}
return cd.Vars
}

// Extras contains extra node parameters which are not entitled to be part of a generic node config
type Extras struct {
SRLAgents []string `yaml:"srl-agents,omitempty"` // Nokia SR Linux agents. As of now just the agents spec files can be provided here
}

0 comments on commit aa679ec

Please sign in to comment.