From 7d5c21acc1dab9b7ca53bc89a5ee2ff2ee6cd64f Mon Sep 17 00:00:00 2001
From: Akiel Aries <56521583+akielaries@users.noreply.github.com>
Date: Wed, 13 Dec 2023 03:14:47 -0700
Subject: [PATCH] Add support for vJunosEvolved (#1775)
* adding support for vJunosEvolved
* removing vim files
* Update vr-vjunosevolved.md
* update link README.md
* adding vJunosEvolved lab example doc, mkdocs.yml, and link in README
* removing vr- prefixed instances of vJunos-switch and Evo. updating lab-example to reference upcoming release of clab
* removing vr- prefix in `vr-vjunosswitch.go`
---
README.md | 2 +
clab/register.go | 2 +
docs/lab-examples/srl-vjunosevolved.md | 25 +++++
docs/manual/kinds/vr-vjunosevolved.md | 83 ++++++++++++++
docs/manual/vrnetlab.md | 1 +
lab-examples/srlvjunos02/srl.cli | 39 +++++++
lab-examples/srlvjunos02/srlvjunos02.clab.yml | 18 +++
lab-examples/srlvjunos02/vjunos.cfg | 23 ++++
mkdocs.yml | 2 +
nodes/vr_vjunosevolved/vr-vjunosevolved.go | 103 ++++++++++++++++++
nodes/vr_vjunosswitch/vr-vjunosswitch.go | 2 +-
schemas/clab.schema.json | 7 +-
12 files changed, 303 insertions(+), 4 deletions(-)
create mode 100644 docs/lab-examples/srl-vjunosevolved.md
create mode 100644 docs/manual/kinds/vr-vjunosevolved.md
create mode 100644 lab-examples/srlvjunos02/srl.cli
create mode 100644 lab-examples/srlvjunos02/srlvjunos02.clab.yml
create mode 100644 lab-examples/srlvjunos02/vjunos.cfg
create mode 100644 nodes/vr_vjunosevolved/vr-vjunosevolved.go
diff --git a/README.md b/README.md
index 9603b96ca..ffec6d245 100644
--- a/README.md
+++ b/README.md
@@ -34,6 +34,8 @@ In addition to native containerized NOSes, containerlab can launch traditional v
* [Juniper vMX](https://containerlab.dev/manual/kinds/vr-vmx/)
* [Juniper vQFX](https://containerlab.dev/manual/kinds/vr-vqfx/)
* [Juniper vSRX](https://containerlab.dev/manual/kinds/vr-vsrx/)
+* [Juniper vJunos-switch](https://containerlab.dev/manual/kinds/vr-vjunosswitch/)
+* [Juniper vJunosEvolved](https://containerlab.dev/manual/kinds/vr-vjunosevolved/)
* [Cisco IOS XRv9k](https://containerlab.dev/manual/kinds/vr-xrv9k/)
* [Cisco Nexus 9000v](https://containerlab.dev/manual/kinds/vr-n9kv)
* [Cisco CSR 1000v](https://containerlab.dev/manual/kinds/vr-csr)
diff --git a/clab/register.go b/clab/register.go
index 13be1157a..4ed8b5bed 100644
--- a/clab/register.go
+++ b/clab/register.go
@@ -31,6 +31,7 @@ import (
vr_sros "github.com/srl-labs/containerlab/nodes/vr_sros"
vr_veos "github.com/srl-labs/containerlab/nodes/vr_veos"
vr_vjunosswitch "github.com/srl-labs/containerlab/nodes/vr_vjunosswitch"
+ vr_vjunosevolved "github.com/srl-labs/containerlab/nodes/vr_vjunosevolved"
vr_vmx "github.com/srl-labs/containerlab/nodes/vr_vmx"
vr_vqfx "github.com/srl-labs/containerlab/nodes/vr_vqfx"
vr_vsrx "github.com/srl-labs/containerlab/nodes/vr_vsrx"
@@ -67,6 +68,7 @@ func (c *CLab) RegisterNodes() {
vr_vsrx.Register(c.Reg)
vr_vqfx.Register(c.Reg)
vr_vjunosswitch.Register(c.Reg)
+ vr_vjunosevolved.Register(c.Reg)
vr_xrv.Register(c.Reg)
vr_xrv9k.Register(c.Reg)
xrd.Register(c.Reg)
diff --git a/docs/lab-examples/srl-vjunosevolved.md b/docs/lab-examples/srl-vjunosevolved.md
new file mode 100644
index 000000000..25132ebfb
--- /dev/null
+++ b/docs/lab-examples/srl-vjunosevolved.md
@@ -0,0 +1,25 @@
+| | |
+| ----------------------------- | ---------------------------------------------------------------------------------------- |
+| **Description** | A Nokia SR Linux connected back-to-back with Juniper vJunosEvolved |
+| **Components** | [Nokia SR Linux][srl], [Juniper vJunosEvolved][vjunos] |
+| **Resource requirements**[^1] | :fontawesome-solid-microchip: 6
:fontawesome-solid-memory: 12 GB |
+| **Topology file** | [srlvjunos02.clab.yml][topofile] |
+| **Name** | srlvjunos02 |
+| **Version information**[^2] | `containerlab:0.49.0`, `srlinux:23.7.1`, `vJunosEvolved-23.2R1-S1.8`, `docker-ce:24.0.7,` |
+
+## Description
+
+A lab consists of an SR Linux node connected with Juniper vJunosEvolved via three point-to-point ethernet links. Both nodes are also connected with their management interfaces to the `clab` docker network.
+
+## Use cases
+
+The nodes are provisioned with a basic interface configuration for three interfaces they are connected with. Pings between the nodes should work out of the box using all three interfaces.
+
+[srl]: ../manual/kinds/srl.md
+[vjunos]: ../manual/kinds/vr-vjunosevolved.md
+[topofile]: https://github.com/srl-labs/containerlab/tree/main/lab-examples/srlvjunos02/srlvjunos02.clab.yml
+
+[^1]: Resource requirements are provisional. Consult with the installation guides for additional information.
+[^2]: The lab has been validated using these versions of the required tools/components. Using versions other than stated might lead to a non-operational setup process.
+
+
diff --git a/docs/manual/kinds/vr-vjunosevolved.md b/docs/manual/kinds/vr-vjunosevolved.md
new file mode 100644
index 000000000..63e38b078
--- /dev/null
+++ b/docs/manual/kinds/vr-vjunosevolved.md
@@ -0,0 +1,83 @@
+---
+search:
+ boost: 4
+---
+# Juniper vJunosEvolved
+
+[Juniper vJunosEvolved](https://support.juniper.net/support/downloads/?p=vjunos-evolved) is a virtualized PTX10001 router identified with `juniper_vjunosevolved` kind in the [topology file](../topo-def-file.md). It is built using [vrnetlab](../vrnetlab.md) project and essentially is a Qemu VM packaged in a docker container format.
+
+Juniper vJunosEvolved nodes launched with containerlab come up pre-provisioned with SSH, SNMP, NETCONF and gNMI services enabled.
+
+## How to obtain the image
+
+The qcow2 image can be downloaded from [Juniper website](https://support.juniper.net/support/downloads/?p=vjunos-evolved) and built with [vrnetlab](../vrnetlab.md).
+
+## Managing Juniper vJunosEvolved nodes
+
+!!!note
+ Containers with vJunosEvolved inside will take ~15min to fully boot.
+ You can monitor the progress with `docker logs -f `.
+
+Juniper vJunosEvolved node launched with containerlab can be managed via the following interfaces:
+
+=== "bash"
+ to connect to a `bash` shell of a running Juniper vJunosEvolved container:
+ ```bash
+ docker exec -it bash
+ ```
+=== "CLI via SSH"
+ to connect to the vJunosEvolved CLI
+ ```bash
+ ssh admin@
+ ```
+=== "NETCONF"
+ NETCONF server is running over port 830
+ ```bash
+ ssh admin@ -p 830 -s netconf
+ ```
+
+!!!info
+ Default user credentials: `admin:admin@123`
+
+## Interfaces mapping
+
+Juniper vJunosEvolved container can have up to 17 interfaces and uses the following mapping rules:
+
+* `eth0` - management interface connected to the containerlab management network
+* `eth1` - first data interface, mapped to a first data port of vJunosEvolved VM
+* `eth2+` - second and subsequent data interface
+
+When containerlab launches Juniper vJunosEvolved node, it will assign IPv4/6 address to the `eth0` interface. These addresses can be used to reach the management plane of the router.
+
+Data interfaces `eth1+` need to be configured with IP addressing manually using CLI/management protocols or via a startup-config text file.
+
+## Features and options
+
+### Node configuration
+
+Juniper vJunosEvolved nodes come up with a basic configuration supplied by a mountable configuration disk to the main VM image. Users, management interfaces, and protocols such as SSH and NETCONF are configured.
+
+#### Startup configuration
+
+It is possible to make vJunosEvolved nodes boot up with a user-defined startup-config instead of a built-in one. With a [`startup-config`](../nodes.md#startup-config) property of the node/kind user sets the path to the config file that will be mounted to a container and used as a startup-config:
+
+```yaml
+topology:
+ nodes:
+ node:
+ kind: juniper_vjunosevolved
+ startup-config: myconfig.txt
+```
+
+With this knob containerlab is instructed to take a file `myconfig.txt` from the directory that hosts the topology file, and copy it to the lab directory for that specific node under the `/config/startup-config.cfg` name. Then the directory that hosts the startup-config dir is mounted to the container. This will result in this config being applied at startup by the node.
+
+Configuration is applied after the node is started, thus it can contain partial configuration snippets that you desire to add on top of the default config that a node boots up with.
+
+## Lab examples
+
+The following labs feature the Juniper vJunosEvolved node:
+
+* [SR Linux and Juniper vJunosEvolved](../../../lab-examples/srlvjunos02/srlvjunos02.yml
+
+## Known issues and limitations
+* To check the boot log, use `docker logs -f `.
diff --git a/docs/manual/vrnetlab.md b/docs/manual/vrnetlab.md
index a9d9c0655..244d9bdba 100644
--- a/docs/manual/vrnetlab.md
+++ b/docs/manual/vrnetlab.md
@@ -90,6 +90,7 @@ The images that work with containerlab will appear in the supported list as we i
| Juniper vQFX | [juniper_vqfx](kinds/vr-vqfx.md) | | |
| Juniper vSRX | [juniper_vsrx](kinds/vr-vsrx.md) | | |
| Juniper vJunos-Switch | [juniper_vjunosswitch](kinds/vr-vjunosswitch.md) | | |
+| Juniper vJunosEvolved | [juniper_vjunosevolved](kinds/vr-vjunosevolved.md) | | |
| Cisco XRv | [cisco_xrv](kinds/vr-xrv.md) | [SRL & XRv](../lab-examples/vr-xrv.md) | |
| Cisco XRv9k | [cisco_xrv9k](kinds/vr-xrv9k.md) | [SRL & XRv9k](../lab-examples/vr-xrv9k.md) | |
| Cisco CSR1000v | [cisco_csr](kinds/vr-csr.md) | | |
diff --git a/lab-examples/srlvjunos02/srl.cli b/lab-examples/srlvjunos02/srl.cli
new file mode 100644
index 000000000..9d820f24f
--- /dev/null
+++ b/lab-examples/srlvjunos02/srl.cli
@@ -0,0 +1,39 @@
+interface ethernet-1/1 {
+ admin-state enable
+ subinterface 0 {
+ ipv4 {
+ admin-state enable
+ address 192.168.0.2/24 {
+ }
+ }
+ }
+}
+interface ethernet-1/2 {
+ admin-state enable
+ subinterface 0 {
+ ipv4 {
+ admin-state enable
+ address 192.168.1.2/24 {
+ }
+ }
+ }
+}
+interface ethernet-1/3 {
+ admin-state enable
+ subinterface 0 {
+ ipv4 {
+ admin-state enable
+ address 192.168.2.2/24 {
+ }
+ }
+ }
+}
+
+network-instance default {
+ interface ethernet-1/1.0 {
+ }
+ interface ethernet-1/2.0 {
+ }
+ interface ethernet-1/3.0 {
+ }
+}
\ No newline at end of file
diff --git a/lab-examples/srlvjunos02/srlvjunos02.clab.yml b/lab-examples/srlvjunos02/srlvjunos02.clab.yml
new file mode 100644
index 000000000..953dd83db
--- /dev/null
+++ b/lab-examples/srlvjunos02/srlvjunos02.clab.yml
@@ -0,0 +1,18 @@
+name: srlvjunos02
+
+topology:
+ nodes:
+ srl:
+ kind: nokia_srlinux
+ image: ghcr.io/nokia/srlinux:23.7.1
+ startup-config: srl.cli
+
+ vevo:
+ kind: juniper_vjunosevolved
+ image: vrnetlab/vr-vjunosevolved:23.2R1-S1.8-EVO
+ startup-config: vjunos.cfg
+
+ links:
+ - endpoints: ["srl:e1-1", "vevo:eth1"]
+ - endpoints: ["srl:e1-2", "vevo:eth2"]
+ - endpoints: ["srl:e1-3", "vevo:eth3"]
diff --git a/lab-examples/srlvjunos02/vjunos.cfg b/lab-examples/srlvjunos02/vjunos.cfg
new file mode 100644
index 000000000..f6de73d7e
--- /dev/null
+++ b/lab-examples/srlvjunos02/vjunos.cfg
@@ -0,0 +1,23 @@
+interfaces {
+ et-0/0/0 {
+ unit 0 {
+ family inet {
+ address 192.168.0.1/24;
+ }
+ }
+ }
+ et-0/0/1 {
+ unit 0 {
+ family inet {
+ address 192.168.1.1/24;
+ }
+ }
+ }
+ et-0/0/2 {
+ unit 0 {
+ family inet {
+ address 192.168.2.1/24;
+ }
+ }
+ }
+}
diff --git a/mkdocs.yml b/mkdocs.yml
index b465522f9..535b68336 100644
--- a/mkdocs.yml
+++ b/mkdocs.yml
@@ -18,6 +18,7 @@ nav:
- Juniper vQFX: manual/kinds/vr-vqfx.md
- Juniper vSRX: manual/kinds/vr-vsrx.md
- Juniper vJunos-switch: manual/kinds/vr-vjunosswitch.md
+ - Juniper vJunosEvolved: manual/kinds/vr-vjunosevolved.md
- Cisco XRd: manual/kinds/xrd.md
- Cisco XRv9k: manual/kinds/vr-xrv9k.md
- Cisco XRv: manual/kinds/vr-xrv.md
@@ -97,6 +98,7 @@ nav:
- Nokia SR Linux and Cisco XRv: lab-examples/vr-xrv.md
- Nokia SR Linux and FRR: lab-examples/srl-frr.md
- Nokia SR Linux and Juniper vJunos-switch: lab-examples/srl-vjunos-switch.md
+ - Nokia SR Linux and Juniper vJunosEvolved: lab-examples/srl-vjunosevolved.md
- FRR: lab-examples/frr01.md
- Cumulus Linux and FRR: lab-examples/cvx01.md
- Cumulus Linux (docker runtime) and Host: lab-examples/cvx02.md
diff --git a/nodes/vr_vjunosevolved/vr-vjunosevolved.go b/nodes/vr_vjunosevolved/vr-vjunosevolved.go
new file mode 100644
index 000000000..4e17e2fe4
--- /dev/null
+++ b/nodes/vr_vjunosevolved/vr-vjunosevolved.go
@@ -0,0 +1,103 @@
+// Copyright 2020 Nokia
+// Licensed under the BSD 3-Clause License.
+// SPDX-License-Identifier: BSD-3-Clause
+
+package vr_vjunosevolved
+
+import (
+ "context"
+ "fmt"
+ "path"
+
+ log "github.com/sirupsen/logrus"
+ "github.com/srl-labs/containerlab/netconf"
+ "github.com/srl-labs/containerlab/nodes"
+ "github.com/srl-labs/containerlab/types"
+ "github.com/srl-labs/containerlab/utils"
+)
+
+var (
+ kindnames = []string{"juniper_vjunosevolved"}
+ defaultCredentials = nodes.NewCredentials("admin", "admin@123")
+)
+
+const (
+ scrapliPlatformName = "juniper_junos"
+
+ configDirName = "config"
+ startupCfgFName = "startup-config.cfg"
+)
+
+// Register registers the node in the NodeRegistry.
+func Register(r *nodes.NodeRegistry) {
+ r.Register(kindnames, func() nodes.Node {
+ return new(vrVJUNOSEVOLVED)
+ }, defaultCredentials)
+}
+
+type vrVJUNOSEVOLVED struct {
+ nodes.DefaultNode
+}
+
+func (n *vrVJUNOSEVOLVED) Init(cfg *types.NodeConfig, opts ...nodes.NodeOption) error {
+ // Init DefaultNode
+ n.DefaultNode = *nodes.NewDefaultNode(n)
+ // set virtualization requirement
+ n.HostRequirements.VirtRequired = true
+
+ n.Cfg = cfg
+ for _, o := range opts {
+ o(n)
+ }
+ // env vars are used to set launch.py arguments in vrnetlab container
+ defEnv := map[string]string{
+ "USERNAME": defaultCredentials.GetUsername(),
+ "PASSWORD": defaultCredentials.GetPassword(),
+ "CONNECTION_MODE": nodes.VrDefConnMode,
+ "DOCKER_NET_V4_ADDR": n.Mgmt.IPv4Subnet,
+ "DOCKER_NET_V6_ADDR": n.Mgmt.IPv6Subnet,
+ }
+ n.Cfg.Env = utils.MergeStringMaps(defEnv, n.Cfg.Env)
+
+ // mount config dir to support startup-config functionality
+ n.Cfg.Binds = append(n.Cfg.Binds, fmt.Sprint(path.Join(n.Cfg.LabDir, configDirName), ":/config"))
+
+ if n.Cfg.Env["CONNECTION_MODE"] == "macvtap" {
+ // mount dev dir to enable macvtap
+ n.Cfg.Binds = append(n.Cfg.Binds, "/dev:/dev")
+ }
+
+ n.Cfg.Cmd = fmt.Sprintf("--username %s --password %s --hostname %s --connection-mode %s --trace",
+ defaultCredentials.GetUsername(), defaultCredentials.GetPassword(), n.Cfg.ShortName, n.Cfg.Env["CONNECTION_MODE"])
+
+ return nil
+}
+
+func (n *vrVJUNOSEVOLVED) PreDeploy(_ context.Context, params *nodes.PreDeployParams) error {
+ utils.CreateDirectory(n.Cfg.LabDir, 0777)
+ _, err := n.LoadOrGenerateCertificate(params.Cert, params.TopologyName)
+ if err != nil {
+ return nil
+ }
+ return nodes.LoadStartupConfigFileVr(n, configDirName, startupCfgFName)
+}
+
+func (n *vrVJUNOSEVOLVED) SaveConfig(_ context.Context) error {
+ err := netconf.SaveConfig(n.Cfg.LongName,
+ defaultCredentials.GetUsername(),
+ defaultCredentials.GetPassword(),
+ scrapliPlatformName,
+ )
+ if err != nil {
+ return err
+ }
+
+ log.Infof("saved %s running configuration to startup configuration file\n", n.Cfg.ShortName)
+ return nil
+}
+
+// CheckInterfaceName checks if a name of the interface referenced in the topology file correct.
+func (n *vrVJUNOSEVOLVED) CheckInterfaceName() error {
+ return nodes.GenericVMInterfaceCheck(n.Cfg.ShortName, n.Endpoints)
+}
+
diff --git a/nodes/vr_vjunosswitch/vr-vjunosswitch.go b/nodes/vr_vjunosswitch/vr-vjunosswitch.go
index 2b3934ad3..4c9435182 100644
--- a/nodes/vr_vjunosswitch/vr-vjunosswitch.go
+++ b/nodes/vr_vjunosswitch/vr-vjunosswitch.go
@@ -17,7 +17,7 @@ import (
)
var (
- kindnames = []string{"juniper_vjunosswitch", "vr-vjunosswitch", "vr-juniper_vjunosswitch"}
+ kindnames = []string{"juniper_vjunosswitch"}
defaultCredentials = nodes.NewCredentials("admin", "admin@123")
)
diff --git a/schemas/clab.schema.json b/schemas/clab.schema.json
index 91f4e9ce4..97bc4c7d8 100644
--- a/schemas/clab.schema.json
+++ b/schemas/clab.schema.json
@@ -62,6 +62,7 @@
"vr-vjunosswitch",
"vr-juniper_vjunosswitch",
"juniper_vjunosswitch",
+ "juniper_vjunosevolved",
"vr-xrv",
"vr-cisco_xrv",
"cisco_xrv",
@@ -728,10 +729,10 @@
"vr-vsrx": {
"$ref": "#/definitions/node-config"
},
- "vr-juniper_vjunosswitch": {
+ "juniper_vjunosswitch": {
"$ref": "#/definitions/node-config"
},
- "vr-vjunosswitch": {
+ "juniper_vjunosevolved": {
"$ref": "#/definitions/node-config"
},
"vr-aruba_aoscx": {
@@ -844,4 +845,4 @@
"name",
"topology"
]
-}
\ No newline at end of file
+}