Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 27 additions & 1 deletion docs/manual/kinds/ceos.md
Original file line number Diff line number Diff line change
Expand Up @@ -280,7 +280,18 @@ topology:

#### User defined config

It is possible to make ceos nodes to boot up with a user-defined config instead of a built-in one. With a [`startup-config`](../nodes.md#startup-config) property a user sets the path to the config file that will be mounted to a container and used as a startup config:
cEOS supports user defined startup configurations in two forms:

- Full startup configuration.
- Partial startup configuration.

Both types of startup configurations are only applied during initial lab deployment. When you save configuration in cEOS to the startup-config using `wr` or `copy running-config startup-config`, the saved configuration will override the startup configuration on subsequent reboots.

##### Full startup configuration

The full startup configuration is used to fully replace the default startup configuration that is applied. This means you must define the necessary configuration for management interface IP addressing and services in your configuration to access cEOS.

You can use the template variables that are defined in the [default startup configuration](https://github.com/srl-labs/containerlab/blob/main/nodes/ceos/ceos.cfg). On lab deployment the template variables will be replaced/substituted.

```yaml
name: ceos_lab
Expand Down Expand Up @@ -321,6 +332,21 @@ It is possible to change the default config which every ceos node will start wit
- endpoints: ["ceos1:eth1", "ceos2:eth1"]
```

##### Partial startup configuration

The partial startup configuration is appended to the default startup configuration. This is useful to preconfigure certain things like additional interfaces, while also taking advantage of the startup configuration that containerlab applies by default for management interface IP addressing and services.

The partial startup configuration must contain `.partial` in the filename. For example: `config.partial.txt` or `config.partial`

```yaml
name: ceos_partial_startup_cfg
topology:
nodes:
ceos:
kind: -{{ kind_code_name }}-
startup-config: configuration.txt.partial
```

#### Saving configuration

In addition to cli commands such as `write memory` user can take advantage of the [`containerlab save`](../../cmd/save.md) command. It saves running cEOS configuration into a startup config file effectively calling the `write` CLI command.
Expand Down
1 change: 1 addition & 0 deletions nodes/ceos/ceos.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -34,5 +34,6 @@ management api http-commands
vrf {{ .Env.CLAB_MGMT_VRF }}
no shutdown
{{end}}
{{ .PartialCfg }}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

AI remark, not tested in the lab:
Full configs still get Go template rendering, but no longer pass through SubstituteEnvsAndTemplate, so ${VAR} expansion regresses. Partial configs are inserted as .PartialCfg, so a partial file containing {{ .ShortName }} would be emitted literally instead of rendered.

Please add a test case for env expansion.

!
end
35 changes: 34 additions & 1 deletion nodes/ceos/ceos.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
package ceos

import (
"bytes"
"context"
_ "embed"
"encoding/json"
Expand All @@ -16,6 +17,7 @@ import (
"path/filepath"
"regexp"
"strings"
"text/template"

"github.com/charmbracelet/log"
clabconstants "github.com/srl-labs/containerlab/constants"
Expand Down Expand Up @@ -81,6 +83,7 @@ func Register(r *clabnodes.NodeRegistry) {

type ceos struct {
clabnodes.DefaultNode
partialStartupCfg string
}

// intfMap represents interface mapping config file.
Expand Down Expand Up @@ -217,7 +220,12 @@ func (n *ceos) createCEOSFiles(ctx context.Context) error {
if err != nil {
return err
}
currentCfgTemplate = string(c)

if clabutils.IsPartialConfigFile(nodeCfg.StartupConfig) {
n.partialStartupCfg = string(c)
} else {
currentCfgTemplate = string(c)
}
}

err = n.GenerateConfig(nodeCfg.ResStartupConfig, currentCfgTemplate)
Expand Down Expand Up @@ -402,3 +410,28 @@ func (n *ceos) CheckInterfaceName() error {

return nil
}

type ceosTemplateData struct {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

According to a quick AI review for this PR new nodes/ceos/ceos.go logic no longer honors suppress-startup-config and enforce-startup-config. I was not checking the code in detail, but installed the Containerlab from you branch and tested following:

  1. enforce-startup-config: false for cEOS kind
  2. define startup-config for every cEOS node
  3. Start the lab and change the hostname on one of the nodes (or do any other change)
  4. Stop the lab WITHOUT --cleanup
  5. Start the lab again and check the hostname: hostname is set from the startup config

This is breaking and must be fixed.

*clabtypes.NodeConfig
PartialCfg string
}

func (n *ceos) GenerateConfig(dst, t string) error {
data := ceosTemplateData{
NodeConfig: n.Cfg,
PartialCfg: n.partialStartupCfg,
}

ceosCfgTpl, err := template.New("ceos-config").Funcs(clabutils.CreateFuncs()).Parse(t)
if err != nil {
return fmt.Errorf("failed to parse ceos cfg template for node %q: %w", n.Cfg.ShortName, err)
}

buf := new(bytes.Buffer)
err = ceosCfgTpl.Execute(buf, data)
if err != nil {
return fmt.Errorf("failed to execute ceos cfg template for node %q: %w", n.Cfg.ShortName, err)
}

return clabutils.CreateFile(dst, buf.String())
}
56 changes: 56 additions & 0 deletions tests/03-basic-ceos/02-partial-config.robot
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
*** Settings ***

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for adding the test.
As it looks like this PR can break more than I anticipated originally, please also add tests for:

  • startup config preservaion
  • suppress-startup-config
  • env expansion and template rendering inside partial config

Thank you!

Library OperatingSystem
Resource ../common.robot
Resource ../ssh.robot

Suite Teardown Run Keyword Cleanup


*** Variables ***
${lab-name} ceos-partial-test
${lab-file-name} partial-clab.yml
${runtime} docker


*** Test Cases ***
Deploy ${lab-name} lab
Log ${CURDIR}
${rc} ${output} = Run And Return Rc And Output
... ${CLAB_BIN} deploy -t ${CURDIR}/${lab-file-name}
Log ${output}
Should Be Equal As Integers ${rc} 0

Verify default configuration on ceos1
${f} = OperatingSystem.Get File ${CURDIR}/clab-${lab-name}/ceos1/flash/startup-config
Log ${f}
Should Contain ${f} hostname ceos1
Should Contain ${f} username admin
Should Contain ${f} management api gnmi

Verify partial startup configuration on ceos2
${f} = OperatingSystem.Get File ${CURDIR}/clab-${lab-name}/ceos2/flash/startup-config
Log ${f}
Should Contain ${f} hostname ceos2
Should Contain ${f} username admin
Should Contain ${f} management api gnmi
Should Contain ${f} description PARTIAL_CONFIG_TEST
Should Contain ${f} interface Ethernet1

Verify full startup configuration on ceos3
${f} = OperatingSystem.Get File ${CURDIR}/clab-${lab-name}/ceos3/flash/startup-config
Log ${f}
Should Contain ${f} hostname ceos3-full
Should Not Contain ${f} management api gnmi

Destroy ${lab-name} lab
Log ${CURDIR}
${rc} ${output} = Run And Return Rc And Output
... ${CLAB_BIN} --runtime ${runtime} destroy -t ${CURDIR}/${lab-file-name}
Log ${output}
Should Be Equal As Integers ${rc} 0


*** Keywords ***
Cleanup
Run ${CLAB_BIN} destroy -t ${CURDIR}/${lab-file-name} --cleanup
Run rm -rf ${CURDIR}/clab-${lab-name}
2 changes: 2 additions & 0 deletions tests/03-basic-ceos/full_config.cfg
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
hostname {{ .ShortName }}-full
!
4 changes: 4 additions & 0 deletions tests/03-basic-ceos/interface.partial.cfg
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
interface Ethernet1
description PARTIAL_CONFIG_TEST
no shutdown
!
19 changes: 19 additions & 0 deletions tests/03-basic-ceos/partial-clab.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
name: ceos-partial-test

topology:
kinds:
arista_ceos:
image: ceos:4.32.0F
nodes:
ceos1:
kind: arista_ceos
ceos2:
kind: arista_ceos
startup-config: ./interface.partial.cfg
ceos3:
kind: arista_ceos
startup-config: ./full_config.cfg

links:
- endpoints: ["ceos1:eth1", "ceos2:eth1"]
- endpoints: ["ceos2:eth1", "ceos3:eth1"]