Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Inspect: fixes all, by name and topology file #1984

Merged
merged 8 commits into from
Apr 11, 2024
Merged
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
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -39,3 +39,5 @@ tests/out
# ignore backup clab topo files
**/.*clab.y*ml.bak
**/*.y*ml.bak

.python-version
8 changes: 5 additions & 3 deletions clab/clab.go
Original file line number Diff line number Diff line change
Expand Up @@ -546,6 +546,7 @@ func (c *CLab) createWaitForDependency() error {
return nil
}

// skipcq: GO-R1005
func (c *CLab) scheduleNodes(ctx context.Context, maxWorkers int, skipPostDeploy bool) (*sync.WaitGroup, *exec.ExecCollection) {
concurrentChan := make(chan *depMgr.DependencyNode)

Expand Down Expand Up @@ -828,7 +829,7 @@ func (c *CLab) ListContainers(ctx context.Context, filter []*types.GenericFilter
}

// ListNodesContainers lists all containers based on the nodes stored in clab instance.
func (c *CLab) listNodesContainers(ctx context.Context) ([]runtime.GenericContainer, error) {
func (c *CLab) ListNodesContainers(ctx context.Context) ([]runtime.GenericContainer, error) {
var containers []runtime.GenericContainer

for _, n := range c.Nodes {
Expand Down Expand Up @@ -882,7 +883,7 @@ func (c *CLab) getLinkNodes() map[string]links.Node {
// GetSpecialLinkNodes returns a map of special nodes that are used to resolve links.
// Special nodes are host and mgmt-bridge nodes that are not typically present in the topology file
// but are required to resolve links.
func (c *CLab) getSpecialLinkNodes() map[string]links.Node {
func (*CLab) getSpecialLinkNodes() map[string]links.Node {
// add the virtual host and mgmt-bridge nodes to the resolve nodes
specialNodes := map[string]links.Node{
"host": links.GetHostLinkNode(),
Expand Down Expand Up @@ -957,6 +958,7 @@ func (c *CLab) extractDNSServers(filesys fs.FS) error {
}

// Deploy the given topology.
// skipcq: GO-R1005
func (c *CLab) Deploy(ctx context.Context, options *DeployOptions) ([]runtime.GenericContainer, error) {
var err error

Expand Down Expand Up @@ -1088,7 +1090,7 @@ func (c *CLab) Deploy(ctx context.Context, options *DeployOptions) ([]runtime.Ge
}
}

containers, err := c.listNodesContainers(ctx)
containers, err := c.ListNodesContainers(ctx)
if err != nil {
return nil, err
}
Expand Down
11 changes: 8 additions & 3 deletions clab/hostsfile.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ func (c *CLab) appendHostsFileEntries(ctx context.Context) error {
return err
}

containers, err := c.listNodesContainers(ctx)
containers, err := c.ListNodesContainers(ctx)
if err != nil {
return err
}
Expand All @@ -53,11 +53,13 @@ func (c *CLab) appendHostsFileEntries(ctx context.Context) error {
return err
}

defer f.Close()
defer f.Close() // skipcq: GO-S2307

_, err = f.Write(data)
if err != nil {
return err
}

return nil
}

Expand All @@ -84,18 +86,21 @@ func generateHostsEntries(containers []runtime.GenericContainer, labname string)
entries.Write(v6entries.Bytes())
fmt.Fprintf(&entries, clabHostEntryPostfix, labname)
entries.WriteByte('\n')

return entries.Bytes()
}

func (c *CLab) DeleteEntriesFromHostsFile() error {
if c.Config.Name == "" {
return errors.New("missing containerlab name")
}

f, err := os.OpenFile(clabHostsFilename, os.O_RDWR, 0644) // skipcq: GSC-G302
if err != nil {
return err
}
defer f.Close()
defer f.Close() // skipcq: GO-S2307

reader := bufio.NewReader(f)
skiplines := false
output := bytes.Buffer{}
Expand Down
9 changes: 3 additions & 6 deletions cmd/inspect.go
Original file line number Diff line number Diff line change
Expand Up @@ -73,25 +73,21 @@ func inspectFn(_ *cobra.Command, _ []string) error {
)
}

if name != "" {
opts = append(opts, clab.WithLabName(name))
}

c, err := clab.NewContainerLab(opts...)
if err != nil {
return fmt.Errorf("could not parse the topology file: %v", err)
}

var containers []runtime.GenericContainer
var glabels []*types.GenericFilter

// if the topo file is available, use it
if topo != "" {
containers, err = c.ListContainers(ctx, nil)
containers, err = c.ListNodesContainers(ctx)
if err != nil {
return fmt.Errorf("failed to list containers: %s", err)
}
} else {
var glabels []*types.GenericFilter
// or when just the name is given
if name != "" {
// if name is set, filter for name
Expand All @@ -106,6 +102,7 @@ func inspectFn(_ *cobra.Command, _ []string) error {
Field: labels.Containerlab, Operator: "exists",
}}
}

containers, err = c.ListContainers(ctx, glabels)
if err != nil {
return fmt.Errorf("failed to list containers: %s", err)
Expand Down
3 changes: 3 additions & 0 deletions docs/manual/dev/index.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# Developers Guide

This is a start of the developers documentation. Stay tuned for more content!
71 changes: 71 additions & 0 deletions docs/manual/dev/test.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
# Testing Containerlab

Containerlab's test program largely consists of:

- Go-based unit tests
- RobotFramework-based integration tests

## Integration Tests

The integration tests are written in RobotFramework and are located in the [`tests`][tests-dir] directory. The tests are run using the [`rf-run`][rf-run] command that wraps `robot` command. The tests are run in a Docker container, so you don't need to install RobotFramework on your local machine.

### Local execution

To execute the integration tests locally you have to install the python environment with the required dependencies. If you're using `pyenv` you can use the following commands:

1. Create a venv and activate it

```bash
pyenv virtualenv 3.11 clab-rf
pyenv shell clab-rf
```

2. Install the dependencies

```bash
pip install -r tests/requirements.txt
```

Usually you would run the tests using the locally built containerlab binary that contains the unreleased changes. The typical workflow then starts with building the containerlab binary:

```bash
make build
```

The newly built binary is located in the `bin` directory. In order to let the test runner script know where to find the binary, you have to set the `CLAB_BIN` environment variable before calling the `rf-run` script:

```bash
CLAB_BIN=$(pwd)/bin/containerlab ./tests/rf-run.sh <runtime> <test suite>
```

/// note
The test runner script requires you to specify the runtime as its first argument. The runtime can be either `docker` or `podman`. Containerlab primarily uses Docker as the default runtime, hence the number of tests written for docker outnumber the podman tests.
///

#### Selecting the test suite

Containerlab's integration tests are grouped by a topic, and each topic is mapped to a directory under the [`tests`][tests-dir] directory and RobotFramework allows for a flexible selection of tests/test suites to run. For example, to run all the smoke test cases, you can use the following command:

```bash
CLAB_BIN=$(pwd)/bin/containerlab ./tests/rf-run.sh docker tests/01-smoke
```

since [`01-smoke`][01-smoke-dir] is a directory containing all the smoke test suites.

Consequently, in order to run a specific test suite you just need to provide a path to it. E.g. running the `01-basic-flow.robot` test suite from the `01-smoke` directory:

```bash
CLAB_BIN=$(pwd)/bin/containerlab ./tests/rf-run.sh docker tests/01-smoke/01-basic-flow.robot
```

/// note
Selecting a specific test case in a test suite is not supported, since test suites are written in a way that test cases depend on previous ones.
///

#### Inspecting the test results

RobotFramework generates a detailed report in HTML and XML formats that can be found in the `tests/out` directory. The exact paths to the reports are printed to the console after the test run.

[tests-dir]: https://github.com/srl-labs/containerlab/tree/main/tests
[rf-run]: https://github.com/srl-labs/containerlab/blob/main/tests/rf-run.sh
[01-smoke-dir]: https://github.com/srl-labs/containerlab/tree/main/tests/01-smoke
3 changes: 3 additions & 0 deletions mkdocs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,9 @@ nav:
- Certificate management: manual/cert.md
- Inventory: manual/inventory.md
- Image management: manual/images.md
- Developers guide:
- manual/dev/index.md
- Testing: manual/dev/test.md
- Command reference:
- deploy: cmd/deploy.md
- destroy: cmd/destroy.md
Expand Down
7 changes: 5 additions & 2 deletions tests/01-smoke/01-basic-flow.robot
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ Ensure CLAB_INTFS env var is set
# the result is printed today.
Should Contain ${output.stderr} stdout:\\n3

Inspect ${lab-name} lab
Inspect ${lab-name} lab using its name
${rc} ${output} = Run And Return Rc And Output
... sudo -E ${CLAB_BIN} --runtime ${runtime} inspect --name ${lab-name}
Log ${output}
Expand Down Expand Up @@ -271,7 +271,10 @@ Verify iptables allow rule is set
${ipt} = Run
... sudo iptables -vnL DOCKER-USER
Log ${ipt}
Should Contain ${ipt} ACCEPT all -- * ${MgmtBr}
# debian 12 uses `0` for protocol, while previous versions use `all`
Should Contain Any ${ipt}
... ACCEPT all -- * ${MgmtBr}
... ACCEPT 0 -- * ${MgmtBr}
... ignore_case=True
... collapse_spaces=True

Expand Down
43 changes: 41 additions & 2 deletions tests/01-smoke/02-destroy-all.robot
Original file line number Diff line number Diff line change
Expand Up @@ -15,28 +15,67 @@ Suite Teardown Run sudo -E ${CLAB_BIN} --runtime ${runtime} destroy --al

*** Variables ***
${runtime} docker
${lab1-file} 01-linux-nodes.clab.yml
${lab1-name} 2-linux-nodes
${lab2-file} 01-linux-single-node.clab.yml
${lab2-name} single-node
# ${orig_dir} ${EMPTY}


*** Test Cases ***
Deploy first lab
${result} = Run Process
... sudo -E ${CLAB_BIN} --runtime ${runtime} deploy -t ${CURDIR}/01-linux-nodes.clab.yml
... sudo -E ${CLAB_BIN} --runtime ${runtime} deploy -t ${CURDIR}/${lab1-file}
... shell=True
Log ${result.stdout}
Log ${result.stderr}
Should Be Equal As Integers ${result.rc} 0
Should Exist %{PWD}/clab-2-linux-nodes

Set Suite Variable ${orig_dir} ${CURDIR}

Deploy second lab
${result} = Run Process
... sudo -E ${CLAB_BIN} --runtime ${runtime} deploy -t ${CURDIR}/01-linux-single-node.clab.yml
... sudo -E ${CLAB_BIN} --runtime ${runtime} deploy -t ${CURDIR}/${lab2-file}
... cwd=/tmp # using a different cwd to check lab resolution via container labels
... shell=True
Log ${result.stdout}
Log ${result.stderr}
Should Be Equal As Integers ${result.rc} 0
Should Exist /tmp/clab-single-node

Inspect ${lab2-name} lab using its name
${rc} ${output} = Run And Return Rc And Output
... sudo -E ${CLAB_BIN} --runtime ${runtime} inspect --name ${lab2-name}
Log ${output}
Should Be Equal As Integers ${rc} 0

${num_lines} = Run bash -c "echo '${output}' | wc -l"
# lab2 only has 1 nodes and therefore inspect output should contain only 1 node (+4 lines for the table header and footer)
Should Be Equal As Integers ${num_lines} 5

Inspect ${lab2-name} lab using topology file reference
${result} = Run Process
... sudo -E ${CLAB_BIN} --runtime ${runtime} inspect -t ${orig_dir}/${lab2-file}
... shell=True
Log ${result.stdout}
Log ${result.stderr}
Should Be Equal As Integers ${result.rc} 0

${num_lines} = Run bash -c "echo '${result.stdout}' | wc -l"
# lab2 only has 1 nodes and therefore inspect output should contain only 1 node
Should Be Equal As Integers ${num_lines} 5

Inspect all
${rc} ${output} = Run And Return Rc And Output
... sudo -E ${CLAB_BIN} --runtime ${runtime} inspect --all
Log ${output}
Should Be Equal As Integers ${rc} 0

${num_lines} = Run bash -c "echo '${output}' | wc -l"
# 3 nodes in lab1 and 1 node in lab2 (+4 lines for the header and footer)
Should Be Equal As Integers ${num_lines} 8

Verify host mode networking for node l3
# l3 node is launched with host mode networking
# since it is the nginx container, by launching it in the host mode
Expand Down
12 changes: 12 additions & 0 deletions tests/06-ext-container/01-ext-container.robot
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,18 @@ Verify ip and thereby exec on ext1
Should Be Equal As Integers ${rc} 0
Should Contain ${output} 192.168.0.1/24

Inspect the lab using topology file reference
${result} = Run Process
... sudo -E ${CLAB_BIN} --runtime ${runtime} inspect -t ${CURDIR}/${lab-file-name}
... shell=True
Log ${result.stdout}
Log ${result.stderr}
Should Be Equal As Integers ${result.rc} 0

${num_nodes} = Run bash -c "echo '${result.stdout}' | wc -l"
# the inspect command should return only two external nodes (+4 lines for the header and footer)
Should Be Equal As Integers ${num_nodes} 6

Verify links in node ext2
${rc} ${output} = Run And Return Rc And Output
... sudo -E ${CLAB_BIN} --runtime ${runtime} exec --label clab-node-name\=ext2 --cmd "ip link show dev eth1"
Expand Down
Loading