Skip to content

Commit af96b59

Browse files
authored
Create daemon config files in 'netlab initial' Python code (ipspace#2867)
The daemon config files and other container configuration templates are no longer rendered in an Ansible playbook, ensuring the created configurations match the actual daemon configurations mapped into containers. Also: * Add '--clean' parameter to cleanup the output directory * Handle the output directory cleanup/creation in Python code * Add tags to 'create-config' playbook to correctly handle the '-m', '-i' and '-c' parameters * Define '-l' parameter as a valid 'netlab initial' parameter (previously it was just passed to Ansible) and use it to limit the nodes for which the container config templates are rendered.
1 parent 1261b72 commit af96b59

File tree

5 files changed

+261
-120
lines changed

5 files changed

+261
-120
lines changed

docs/netlab/initial.md

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -34,8 +34,8 @@ Jinja2 templates are used together with **_device_\_config** Ansible modules to
3434

3535
```text
3636
$ netlab initial -h
37-
usage: netlab initial [-h] [--log] [-v] [-q] [-i] [-m [MODULE]] [-c] [--ready] [--fast]
38-
[-o [OUTPUT]] [--instance INSTANCE]
37+
usage: netlab initial [-h] [--log] [-v] [-q] [-i] [-m [MODULE]] [-l LIMIT] [-c]
38+
[--ready] [--fast] [-o [OUTPUT]] [--clean] [--instance INSTANCE]
3939
4040
Initial device configurations
4141
@@ -45,17 +45,20 @@ options:
4545
-v, --verbose Verbose logging (add multiple flags for increased verbosity)
4646
-q, --quiet Report only major errors
4747
-i, --initial Deploy just the initial configuration
48-
-m [MODULE], --module [MODULE]
48+
-m, --module [MODULE]
4949
Deploy module-specific configuration (optionally including a
5050
list of modules separated by commas)
51+
-l, --limit LIMIT Limit the operation to a subset of nodes
5152
-c, --custom Deploy custom configuration templates (specified in "config"
5253
group or node attribute)
5354
--ready Wait for devices to become ready
5455
--fast Use "free" strategy in Ansible playbook for faster configuration
5556
deployment
56-
-o [OUTPUT], --output [OUTPUT]
57+
-o, --output [OUTPUT]
5758
Create a directory with initial configurations instead of
5859
deploying them (default output directory: config)
60+
--clean Clean up the output directory before creating the initial
61+
configuration
5962
--instance INSTANCE Specify lab instance to configure
6063
6164
All other arguments are passed directly to ansible-playbook
@@ -119,10 +122,10 @@ You'll find more details in _[](custom-config)_ and _[](dev-find-custom)_ docume
119122

120123
The **netlab initial** command deploys all initial device configurations when started without additional parameters. To control the deployment of initial configurations:
121124

122-
* use the `-i` flag to deploy initial device configurations.
123-
* use the `-m` flag to deploy module-specific configurations.
124-
* use the `-m` flag followed by a module name (example: `-m ospf -m bgp`) to deploy device configuration for specific modules. You can use the `-m` flag multiple times.
125-
* use the `-c` flag to deploy custom configuration templates.
125+
* Use the `-i` flag to deploy initial device configurations.
126+
* Use the `-m` flag to deploy all module-specific configurations.
127+
* Use the `-m` flag followed by a module name (example: `-m ospf`) or a comma-separated list of module names (example: `-m ospf,bgp`) to deploy device configuration for specific module(s).
128+
* Use the `-c` flag to deploy custom configuration templates.
126129

127130
All unrecognized parameters are passed to the internal `initial-config.ansible` Ansible playbook. You can use **ansible-playbook** CLI parameters to modify the configuration deployment, for example:
128131

netsim/ansible/create-config.ansible

Lines changed: 11 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -7,19 +7,11 @@
77
config_dir: "{{ lookup('env','PWD') }}/config"
88
node_provider: "{{ provider|default(netlab_provider) }}"
99
tasks:
10-
- block:
11-
- name: Set variables that cannot be set with vars
12-
set_fact:
13-
netlab_device_type: "{{ netlab_device_type|default(ansible_network_os) }}"
14-
netlab_interfaces: "{{ ([ loopback ] if loopback is defined else []) + interfaces|default([]) }}"
15-
16-
- name: Create config directory in {{ config_dir }}
17-
file:
18-
path: "{{ config_dir }}"
19-
state: directory
20-
run_once: true
21-
22-
delegate_to: localhost
10+
- name: Set variables that cannot be set with vars
11+
set_fact:
12+
netlab_device_type: "{{ netlab_device_type|default(ansible_network_os) }}"
13+
netlab_interfaces: "{{ ([ loopback ] if loopback is defined else []) + interfaces|default([]) }}"
14+
tags: [ always ]
2315

2416
- name: Create initial device configuration
2517
include_tasks: "tasks/create-config.yml"
@@ -28,6 +20,8 @@
2820
vars:
2921
config_item: initial
3022
paths: "{{ paths_templates.dirs }}"
23+
tags: [ always ]
24+
tags: [ initial ]
3125

3226
- name: Create module-specific configurations
3327
hosts: modules
@@ -50,9 +44,11 @@
5044
loop_var: config_item
5145
args:
5246
apply:
47+
tags: [ always ]
5348
vars:
5449
paths: "{{ paths_templates.dirs }}"
5550

51+
tags: [ module ]
5652
delegate_to: localhost
5753

5854
- name: Create custom deployment templates
@@ -68,27 +64,7 @@
6864
loop_var: custom_config
6965
args:
7066
apply:
67+
tags: [ always ]
7168
vars:
7269
paths: "{{ paths_custom.dirs }}"
73-
74-
- name: Create daemon configuration files
75-
hosts: daemons
76-
serial: 1
77-
vars:
78-
node_provider: "{{ provider|default(netlab_provider) }}"
79-
extra_config: >
80-
{{ _daemon_config|default({})
81-
|list
82-
|difference(modules|default([]))
83-
|difference(config|default([])) }}
84-
tasks:
85-
- name: Create daemon configurations
86-
include_tasks: "tasks/create-config.yml"
87-
loop: "{{ extra_config }}"
88-
when: "'@' not in config_item"
89-
loop_control:
90-
loop_var: config_item
91-
args:
92-
apply:
93-
vars:
94-
paths: "{{ paths_templates.dirs }}"
70+
tags: [ custom ]

netsim/cli/initial.py

Lines changed: 5 additions & 77 deletions
Original file line numberDiff line numberDiff line change
@@ -3,106 +3,34 @@
33
#
44
# Deploys initial device configurations
55
#
6-
import argparse
7-
import os
86
import typing
97

108
from .. import devices
119
from ..utils import log
1210
from ..utils import status as _status
1311
from . import (
1412
ansible,
15-
common_parse_args,
1613
external_commands,
1714
get_message,
15+
initial_actions,
1816
lab_status_change,
1917
load_snapshot,
20-
parser_lab_location,
2118
)
2219

2320

24-
#
25-
# CLI parser for 'netlab initial' command
26-
#
27-
def initial_config_parse(args: typing.List[str]) -> typing.Tuple[argparse.Namespace, typing.List[str]]:
28-
parser = argparse.ArgumentParser(
29-
parents=[ common_parse_args() ],
30-
prog="netlab initial",
31-
description='Initial device configurations',
32-
epilog='All other arguments are passed directly to ansible-playbook')
33-
34-
parser.add_argument(
35-
'-i','--initial',
36-
dest='initial', action='store_true',
37-
help='Deploy just the initial configuration')
38-
parser.add_argument(
39-
'-m','--module',
40-
dest='module', action='store',nargs='?',const='*',
41-
help='Deploy module-specific configuration (optionally including a list of modules separated by commas)')
42-
parser.add_argument(
43-
'-c','--custom',
44-
dest='custom', action='store_true',
45-
help='Deploy custom configuration templates (specified in "config" group or node attribute)')
46-
parser.add_argument(
47-
'--ready',
48-
dest='ready', action='store_true',
49-
help='Wait for devices to become ready')
50-
parser.add_argument(
51-
'--fast',
52-
dest='fast', action='store_true',
53-
help='Use "free" strategy in Ansible playbook for faster configuration deployment')
54-
parser.add_argument(
55-
'-o','--output',
56-
dest='output', action='store',nargs='?',const='config',
57-
help='Create a directory with initial configurations instead of deploying them (default output directory: config)')
58-
parser.add_argument(
59-
'--no-message',
60-
dest='no_message', action='store_true',
61-
help=argparse.SUPPRESS)
62-
parser_lab_location(parser,instance=True,i_used=True,action='configure')
63-
64-
return parser.parse_known_args(args)
65-
6621
def run_initial(cli_args: typing.List[str]) -> None:
67-
(args,rest) = initial_config_parse(cli_args)
68-
if args.output:
69-
rest = ['-e',f'config_dir="{os.path.abspath(args.output)}"' ] + rest
70-
22+
(args,rest) = initial_actions.initial_config_parse(cli_args)
7123
topology = load_snapshot(args)
7224

73-
deploy_parts = []
74-
if args.verbose:
75-
rest = ['-' + 'v' * args.verbose] + rest
76-
77-
if args.initial:
78-
rest = ['-t','initial'] + rest
79-
deploy_parts.append("initial configuration")
80-
81-
if args.quiet:
82-
os.environ["ANSIBLE_STDOUT_CALLBACK"] = "selective"
83-
84-
if args.module:
85-
if args.module != "*":
86-
deploy_parts.append("module(s): " + args.module)
87-
rest = ['-e','modlist='+args.module] + rest
88-
else:
89-
deploy_parts.append("modules")
90-
rest = ['-t','module'] + rest
91-
92-
if args.custom:
93-
deploy_parts.append("custom")
94-
rest = ['-t','custom'] + rest
95-
96-
if args.fast or os.environ.get('NETLAB_FAST_CONFIG',None):
97-
rest = ['-e','netlab_strategy=free'] + rest
25+
rest = rest + initial_actions.ansible_args(args)
26+
deploy_parts = initial_actions.get_deploy_parts(args)
9827

9928
if args.logging or args.verbose:
10029
print("Ansible playbook args: %s" % rest)
10130

10231
ansible.check_version()
10332
if args.output:
104-
ansible.playbook('create-config.ansible',rest)
105-
print("\nInitial configurations have been created in the %s directory" % args.output)
33+
initial_actions.configs.run(topology,args,rest)
10634
return
10735
elif args.ready:
10836
ansible.playbook('device-ready.ansible',rest)
Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
"""
2+
Common functions for the "netlab initial" actions
3+
"""
4+
5+
import argparse
6+
import os
7+
import typing
8+
9+
from .. import common_parse_args, parser_lab_location
10+
from . import configs
11+
12+
13+
#
14+
# CLI parser for 'netlab initial' command
15+
#
16+
def initial_config_parse(args: typing.List[str]) -> typing.Tuple[argparse.Namespace, typing.List[str]]:
17+
parser = argparse.ArgumentParser(
18+
parents=[ common_parse_args() ],
19+
prog="netlab initial",
20+
description='Initial device configurations',
21+
epilog='All other arguments are passed directly to ansible-playbook')
22+
23+
parser.add_argument(
24+
'-i','--initial',
25+
dest='initial', action='store_true',
26+
help='Deploy just the initial configuration')
27+
parser.add_argument(
28+
'-m','--module',
29+
dest='module', action='store',nargs='?',const='*',
30+
help='Deploy module-specific configuration (optionally including a list of modules separated by commas)')
31+
parser.add_argument(
32+
'-l','--limit',
33+
dest='limit', action='store',
34+
help='Limit the operation to a subset of nodes')
35+
parser.add_argument(
36+
'-c','--custom',
37+
dest='custom', action='store_true',
38+
help='Deploy custom configuration templates (specified in "config" group or node attribute)')
39+
parser.add_argument(
40+
'--ready',
41+
dest='ready', action='store_true',
42+
help='Wait for devices to become ready')
43+
parser.add_argument(
44+
'--fast',
45+
dest='fast', action='store_true',
46+
help='Use "free" strategy in Ansible playbook for faster configuration deployment')
47+
parser.add_argument(
48+
'-o','--output',
49+
dest='output', action='store',nargs='?',const='config',
50+
help='Create a directory with initial configurations instead of deploying them (default output directory: config)')
51+
parser.add_argument(
52+
'--clean',
53+
dest='clean', action='store_true',
54+
help='Clean up the output directory before creating the initial configuration')
55+
parser.add_argument(
56+
'--no-message',
57+
dest='no_message', action='store_true',
58+
help=argparse.SUPPRESS)
59+
parser_lab_location(parser,instance=True,i_used=True,action='configure')
60+
61+
return parser.parse_known_args(args)
62+
63+
"""
64+
Build Ansible arguments based on 'netlab initial' parameters
65+
"""
66+
def ansible_args(args: argparse.Namespace) -> list:
67+
rest: typing.List[str] = []
68+
if args.verbose:
69+
rest = ['-' + 'v' * args.verbose] + rest
70+
71+
if args.limit:
72+
rest = ['--limit',args.limit] + rest
73+
74+
if args.initial:
75+
rest = ['-t','initial'] + rest
76+
77+
if args.quiet:
78+
os.environ["ANSIBLE_STDOUT_CALLBACK"] = "selective"
79+
80+
if args.module:
81+
if args.module != "*":
82+
rest = ['-e','modlist='+args.module] + rest
83+
rest = ['-t','module'] + rest
84+
85+
if args.custom:
86+
rest = ['-t','custom'] + rest
87+
88+
if args.fast or os.environ.get('NETLAB_FAST_CONFIG',None):
89+
rest = ['-e','netlab_strategy=free'] + rest
90+
91+
return rest
92+
93+
def get_deploy_parts(args: argparse.Namespace) -> list:
94+
deploy_parts = []
95+
if args.initial:
96+
deploy_parts.append("initial configuration")
97+
98+
if args.module:
99+
if args.module != "*":
100+
deploy_parts.append("module(s): " + args.module)
101+
else:
102+
deploy_parts.append("modules")
103+
104+
if args.custom:
105+
deploy_parts.append("custom")
106+
107+
return deploy_parts

0 commit comments

Comments
 (0)