diff options
Diffstat (limited to 'doc/book-enea-edge-automation-user-guide/doc/automation_framework_test_harness.xml')
-rw-r--r-- | doc/book-enea-edge-automation-user-guide/doc/automation_framework_test_harness.xml | 1602 |
1 files changed, 1602 insertions, 0 deletions
diff --git a/doc/book-enea-edge-automation-user-guide/doc/automation_framework_test_harness.xml b/doc/book-enea-edge-automation-user-guide/doc/automation_framework_test_harness.xml new file mode 100644 index 0000000..cec8dcf --- /dev/null +++ b/doc/book-enea-edge-automation-user-guide/doc/automation_framework_test_harness.xml | |||
@@ -0,0 +1,1602 @@ | |||
1 | <?xml version="1.0" encoding="UTF-8"?> | ||
2 | <chapter id="auto_fw_test_harness"> | ||
3 | <title>Enea Edge Automation</title> | ||
4 | |||
5 | <section id="AFTH_structure"> | ||
6 | <title>File Structure</title> | ||
7 | |||
8 | <para>Enea Edge Automation is an open-source product, with the following | ||
9 | directory structure:</para> | ||
10 | |||
11 | <itemizedlist spacing="compact"> | ||
12 | <listitem> | ||
13 | <para>ansible.cfg</para> | ||
14 | </listitem> | ||
15 | |||
16 | <listitem> | ||
17 | <para>automation_framework</para> | ||
18 | </listitem> | ||
19 | |||
20 | <listitem> | ||
21 | <para>CHANGELOG</para> | ||
22 | </listitem> | ||
23 | |||
24 | <listitem> | ||
25 | <para>environment_variables.sh</para> | ||
26 | </listitem> | ||
27 | |||
28 | <listitem> | ||
29 | <para>modules</para> | ||
30 | </listitem> | ||
31 | |||
32 | <listitem> | ||
33 | <para>setup_env_requirements.txt</para> | ||
34 | </listitem> | ||
35 | |||
36 | <listitem> | ||
37 | <para>setup_env.sh</para> | ||
38 | </listitem> | ||
39 | |||
40 | <listitem> | ||
41 | <para>test_harness</para> | ||
42 | </listitem> | ||
43 | |||
44 | <listitem> | ||
45 | <para>unit_tests</para> | ||
46 | </listitem> | ||
47 | |||
48 | <listitem> | ||
49 | <para>VERSION</para> | ||
50 | </listitem> | ||
51 | </itemizedlist> | ||
52 | |||
53 | <para>Each file/directory is described in more details in the following | ||
54 | sections.</para> | ||
55 | |||
56 | <section id="create_virt_test_env"> | ||
57 | <title>Creating the Virtual Environment for Testing</title> | ||
58 | |||
59 | <para>The <filename>setup_env.sh</filename>, | ||
60 | <filename>setup_env_requirements.txt</filename> and | ||
61 | <filename>environment_variables.sh</filename> files are used to create | ||
62 | the testing virtual environment, using the following | ||
63 | prerequisites:</para> | ||
64 | |||
65 | <itemizedlist spacing="compact"> | ||
66 | <listitem> | ||
67 | <para>The environment variable</para> | ||
68 | </listitem> | ||
69 | |||
70 | <listitem> | ||
71 | <para>Python packages</para> | ||
72 | </listitem> | ||
73 | |||
74 | <listitem> | ||
75 | <para>Ansible package(s)</para> | ||
76 | </listitem> | ||
77 | </itemizedlist> | ||
78 | |||
79 | <para>The <filename>environment_variables.sh</filename> script sets the | ||
80 | environment variables, the | ||
81 | <filename>setup_env_requirements.txt</filename> file contains the | ||
82 | mapping between the package name and its version, and the | ||
83 | <filename>setup_env.sh</filename> script creates a testing virtual | ||
84 | environment.</para> | ||
85 | |||
86 | <para>The <filename>setup_env.sh</filename> does the following:</para> | ||
87 | |||
88 | <itemizedlist spacing="compact"> | ||
89 | <listitem> | ||
90 | <para>Checks if the <literal>Python 3</literal> and | ||
91 | <literal>pip</literal> packages are installed on the host. If at | ||
92 | least one package is not installed on the host, then an error is | ||
93 | displayed and the script stops.</para> | ||
94 | </listitem> | ||
95 | |||
96 | <listitem> | ||
97 | <para>Creates and activates the <literal>testHarness-venv</literal> | ||
98 | virtual environment.</para> | ||
99 | </listitem> | ||
100 | |||
101 | <listitem> | ||
102 | <para>Upgrades the <literal>pip</literal> package to the newest | ||
103 | version.</para> | ||
104 | </listitem> | ||
105 | |||
106 | <listitem> | ||
107 | <para>Installs the packages defined in | ||
108 | <filename>setup_env_requirements.txt</filename> on the virtual | ||
109 | environment.</para> | ||
110 | </listitem> | ||
111 | |||
112 | <listitem> | ||
113 | <para>Sets the environment variables defined in | ||
114 | <filename>environment_variables.sh</filename> on the virtual | ||
115 | environment.</para> | ||
116 | </listitem> | ||
117 | </itemizedlist> | ||
118 | </section> | ||
119 | |||
120 | <section id="version_changelog"> | ||
121 | <title>VERSION and CHANGELOG</title> | ||
122 | |||
123 | <para>The <filename>VERSION</filename> and | ||
124 | <filename>CHANGELOG</filename> files contain information about the | ||
125 | version, build number, and all the notable changes added in the Enea | ||
126 | Edge Automation.</para> | ||
127 | </section> | ||
128 | |||
129 | <section id="module_enea_dir"> | ||
130 | <title>The modules/enea directory</title> | ||
131 | |||
132 | <para>The <literal>modules/enea</literal> directory contains the | ||
133 | following:</para> | ||
134 | |||
135 | <itemizedlist spacing="compact"> | ||
136 | <listitem> | ||
137 | <para><literal>config</literal> - contains the configuration files | ||
138 | that need to be updated in order to successfully run the Enea Edge | ||
139 | Automation. For more details, see <xref | ||
140 | linkend="AFTH_cofig" />.</para> | ||
141 | </listitem> | ||
142 | |||
143 | <listitem> | ||
144 | <para><literal>scenario</literal> - contains the test scenarios. The | ||
145 | test scenarios include custom script examples, service chaining VNF | ||
146 | examples and so on.</para> | ||
147 | </listitem> | ||
148 | |||
149 | <listitem> | ||
150 | <para><literal>VNF_images</literal> - contains the VNF images that | ||
151 | are used in test scenarios.</para> | ||
152 | </listitem> | ||
153 | </itemizedlist> | ||
154 | </section> | ||
155 | |||
156 | <section id="automation_framework_dir"> | ||
157 | <title>The automation_framework directory</title> | ||
158 | |||
159 | <para>The <literal>automation_framework</literal> directory includes all | ||
160 | the Python scripts used by the Automation Framework. Each Python script | ||
161 | implements a class that defines a functionality of the Enea Edge | ||
162 | Management application.</para> | ||
163 | |||
164 | <para>The Python scripts can be split into the following:</para> | ||
165 | |||
166 | <itemizedlist> | ||
167 | <listitem> | ||
168 | <para>The <filename>ManagementHTTPClientRestAPIv2.py</filename> | ||
169 | script, where the <literal>ManagementClient</literal> class is | ||
170 | defined. This class communicates with the Enea Edge Management | ||
171 | application via REST API.</para> | ||
172 | |||
173 | <note> | ||
174 | <para>The <filename>uCPEMgrHTTPClientRestAPIv2.py</filename> | ||
175 | script is where the <literal>uCPEMgrHTTPClient</literal> class is | ||
176 | defined. The <literal>uCPEMgrHTTPClient</literal> class is a | ||
177 | wrapper of the <literal>ManagementClient</literal> class. This | ||
178 | script is deprecated and will be removed starting with the next | ||
179 | major release.</para> | ||
180 | </note> | ||
181 | </listitem> | ||
182 | |||
183 | <listitem> | ||
184 | <para>Other Python scripts, where the classes for the Enea Edge | ||
185 | Management module are defined. Each class inherits the | ||
186 | <literal>ManagementClient</literal> class and uses its methods to | ||
187 | communicate with the Enea Edge Management application via the REST | ||
188 | API. Each class corresponds to an Enea Edge Management | ||
189 | module.</para> | ||
190 | |||
191 | <para><emphasis role="bold">Example</emphasis>: the | ||
192 | <filename>OfflineConfigHandler.py</filename> script, where the | ||
193 | <literal>OfflineConfigHandler</literal> class is defined. Inside | ||
194 | this class, the methods for offline configuration functionality are | ||
195 | implemented: <literal>addOfflineConfigStore</literal>, | ||
196 | <literal>deleteOfflineConfigStore</literal>, | ||
197 | <literal>uploadConfigToDevice</literal> and so on.</para> | ||
198 | </listitem> | ||
199 | </itemizedlist> | ||
200 | </section> | ||
201 | |||
202 | <section id="unit_test_dir"> | ||
203 | <title>The unit_test directory</title> | ||
204 | |||
205 | <para>The <literal>unit_test</literal> directory contains:</para> | ||
206 | |||
207 | <itemizedlist spacing="compact"> | ||
208 | <listitem> | ||
209 | <para>JSON files for complex scenarios with multiple | ||
210 | operations.</para> | ||
211 | </listitem> | ||
212 | |||
213 | <listitem> | ||
214 | <para>The Python <literal>unit-test</literal> class.</para> | ||
215 | </listitem> | ||
216 | |||
217 | <listitem> | ||
218 | <para>Loader scripts for generating specific test cases for the | ||
219 | available Python script.</para> | ||
220 | </listitem> | ||
221 | </itemizedlist> | ||
222 | |||
223 | <para>The generated test cases are injected into the Python | ||
224 | <literal>unit-test</literal> suite class to run using the Python | ||
225 | <literal>unit-test</literal> framework.</para> | ||
226 | </section> | ||
227 | |||
228 | <section id="test_harn_ansible"> | ||
229 | <title>The test_harness directory and ansible.cfg</title> | ||
230 | |||
231 | <para>The <filename>ansible.cfg</filename> file represents the | ||
232 | configuration file for Test Harness. The Ansible configurations have | ||
233 | default values delivered in the archive, but they can be changed. | ||
234 | <emphasis role="bold">Example</emphasis>: for a more extended output, | ||
235 | change the output from selective to debug.</para> | ||
236 | |||
237 | <para>The <literal>test_harness</literal> directory contains all the | ||
238 | implemented playbooks. This directory is structured in multiple | ||
239 | subdirectories, each subdirectory represents a functionality of the Enea | ||
240 | Edge Management application. Each implemented playbook from this | ||
241 | directory runs a method from a Python class from the | ||
242 | <literal>automation_framework</literal> directory. Each playbook is an | ||
243 | atomic operation, a basic operation that need to be tested. These | ||
244 | playbooks are used in complex test scenarios.</para> | ||
245 | </section> | ||
246 | |||
247 | <section id="log_dir"> | ||
248 | <title>The log directory</title> | ||
249 | |||
250 | <para>The <literal>log</literal> directory is added in the directory | ||
251 | structure by the <filename>setup_env.sh</filename> script. The | ||
252 | <filename>setup_env.sh</filename> script stores the output logs in the | ||
253 | <filename>setup_env.log</filename> file. The Ansible playbooks store the | ||
254 | logs in the <filename>ansible.log</filename> file. The Python scripts | ||
255 | store the logs in the <filename>debug.log</filename> file.</para> | ||
256 | </section> | ||
257 | </section> | ||
258 | |||
259 | <section id="AFTH_cofig"> | ||
260 | <title>Configuring the System</title> | ||
261 | |||
262 | <para>The configuration files must be updated before using Enea Edge | ||
263 | Automation. They are stored in the <literal>modules/enea/config</literal> | ||
264 | directory.</para> | ||
265 | |||
266 | <para>The configuration files are split according to the component that is | ||
267 | used in the testing process:</para> | ||
268 | |||
269 | <itemizedlist spacing="compact"> | ||
270 | <listitem> | ||
271 | <para>The Enea Edge Management application</para> | ||
272 | </listitem> | ||
273 | |||
274 | <listitem> | ||
275 | <para>uCPE Devices</para> | ||
276 | </listitem> | ||
277 | |||
278 | <listitem> | ||
279 | <para>VNFs</para> | ||
280 | </listitem> | ||
281 | </itemizedlist> | ||
282 | |||
283 | <section id="config_files_mg"> | ||
284 | <title>Configuration Files for the Enea Edge Management | ||
285 | application</title> | ||
286 | |||
287 | <para>In order to create a connection with the Enea Edge Management | ||
288 | application, the following parameters have to be specified:</para> | ||
289 | |||
290 | <itemizedlist spacing="compact"> | ||
291 | <listitem> | ||
292 | <para>Enea Edge Management username</para> | ||
293 | </listitem> | ||
294 | |||
295 | <listitem> | ||
296 | <para>Enea Edge Management password</para> | ||
297 | </listitem> | ||
298 | |||
299 | <listitem> | ||
300 | <para>Enea Edge Management IP address or FQDN</para> | ||
301 | </listitem> | ||
302 | </itemizedlist> | ||
303 | |||
304 | <para><emphasis role="bold">Updating the configuration | ||
305 | file</emphasis></para> | ||
306 | |||
307 | <orderedlist> | ||
308 | <listitem> | ||
309 | <para>Open | ||
310 | <filename>modules/enea/config/Management/management01.json</filename></para> | ||
311 | |||
312 | <programlisting>{ | ||
313 | "ucpe_usr":"admin", | ||
314 | "ucpe_pass":"admin", | ||
315 | "ucpe_host":"172.24.3.92" | ||
316 | }</programlisting> | ||
317 | </listitem> | ||
318 | |||
319 | <listitem> | ||
320 | <para>Update the username, password and IP address or FQDN.</para> | ||
321 | |||
322 | <note> | ||
323 | <para>The | ||
324 | <filename>modules/enea/config/uCPEManager/ucpem01.json</filename> | ||
325 | file is a symbolic link to the | ||
326 | <filename>modules/enea/config/Management/management01.json</filename> | ||
327 | file. It is deprecated, and it will be removed starting with the | ||
328 | next major release.</para> | ||
329 | </note> | ||
330 | </listitem> | ||
331 | </orderedlist> | ||
332 | |||
333 | <para>It is possible to use another JSON file for the connection with | ||
334 | the Enea Edge Management application.</para> | ||
335 | |||
336 | <para><emphasis role="bold">Changing the path for the Enea Edge | ||
337 | Management JSON file</emphasis></para> | ||
338 | |||
339 | <orderedlist> | ||
340 | <listitem> | ||
341 | <para>Open the | ||
342 | <filename>automation_framework/ManagementHTTPClientRestAPIv2.py</filename> | ||
343 | file.</para> | ||
344 | </listitem> | ||
345 | |||
346 | <listitem> | ||
347 | <para>Go to the <literal>create_json_file</literal> method from the | ||
348 | <literal>ManagementConfig</literal> class.</para> | ||
349 | </listitem> | ||
350 | |||
351 | <listitem> | ||
352 | <para>Change the path of the Enea Edge Management JSON file in the | ||
353 | <literal>self.ucpe_json_file</literal> variable.</para> | ||
354 | </listitem> | ||
355 | </orderedlist> | ||
356 | </section> | ||
357 | |||
358 | <section id="config_files_ucpe_devices"> | ||
359 | <title>Configuration Files for uCPE Devices</title> | ||
360 | |||
361 | <para>The <literal>modules/enea/config/uCPEDevices</literal> directory | ||
362 | contains the following:</para> | ||
363 | |||
364 | <itemizedlist spacing="compact"> | ||
365 | <listitem> | ||
366 | <para>Examples of the configuration files for different uCPE | ||
367 | Devices: | ||
368 | <literal>inteld1521-16</literal>,<literal>inteld1521-17</literal>, | ||
369 | and so on.</para> | ||
370 | </listitem> | ||
371 | |||
372 | <listitem> | ||
373 | <para>The scripts for generating all configuration files in | ||
374 | <literal>scripts</literal> folder.</para> | ||
375 | </listitem> | ||
376 | </itemizedlist> | ||
377 | |||
378 | <para>The following scripts are implemented to generate the | ||
379 | configuration files:</para> | ||
380 | |||
381 | <itemizedlist spacing="compact"> | ||
382 | <listitem> | ||
383 | <para><filename>generate_device_config.py</filename> - generates the | ||
384 | JSON configuration file for the uCPE Device.</para> | ||
385 | </listitem> | ||
386 | |||
387 | <listitem> | ||
388 | <para><filename>generate_bridges_config_files.py</filename> - | ||
389 | generates configuration files for all possible OVS bridges created | ||
390 | on the uCPE Device.</para> | ||
391 | </listitem> | ||
392 | |||
393 | <listitem> | ||
394 | <para><filename>generate_nics_config_files.py</filename> - generates | ||
395 | the configuration files for all possible NICs created on the uCPE | ||
396 | Device.</para> | ||
397 | </listitem> | ||
398 | </itemizedlist> | ||
399 | |||
400 | <section id="generate_config"> | ||
401 | <title>Generating Device config</title> | ||
402 | |||
403 | <para>Before running the script, check the following:</para> | ||
404 | |||
405 | <itemizedlist spacing="compact"> | ||
406 | <listitem> | ||
407 | <para>The available NICs on the target.</para> | ||
408 | </listitem> | ||
409 | |||
410 | <listitem> | ||
411 | <para>The device ID.</para> | ||
412 | </listitem> | ||
413 | |||
414 | <listitem> | ||
415 | <para>The IP address of the uCPE Device.</para> | ||
416 | </listitem> | ||
417 | </itemizedlist> | ||
418 | |||
419 | <para><emphasis role="bold">Generating the device | ||
420 | config</emphasis></para> | ||
421 | |||
422 | <note> | ||
423 | <para>Make sure the management interface, the one that ensures the | ||
424 | connection between the uCPE Device and the Enea Edge Management | ||
425 | application, is not used when generating the JSON configuration | ||
426 | files.</para> | ||
427 | </note> | ||
428 | |||
429 | <orderedlist> | ||
430 | <listitem> | ||
431 | <para>Run <filename>generate_device_config.py</filename>:</para> | ||
432 | |||
433 | <programlisting>python generate_device_config.py | ||
434 | Device name: test | ||
435 | Device ID: test_id | ||
436 | Device groupings tags [ ]: test_id | ||
437 | uCPE Device version [2.5.0]: 2.5.0 | ||
438 | Device IP address [No]: 10.0.0.1 | ||
439 | Call home [false]: | ||
440 | Mgmt network interface - it must not be the management interface [No]: eth0 | ||
441 | WAN network interface - it must not be the management interface [No]: eth1 | ||
442 | LAN network interface - it must not be the management interface [No]: eth2 | ||
443 | WAP network interface - it must not be the management interface [No]: wlan0 | ||
444 | |||
445 | The following JSON config file was successfully created (uCPE Device config file): | ||
446 | test.json | ||
447 | |||
448 | The following JSON config file was successfully created (config store file): | ||
449 | store.json</programlisting> | ||
450 | </listitem> | ||
451 | |||
452 | <listitem> | ||
453 | <para>Check the configuration files in the | ||
454 | <literal>modules/enea/config/uCPEDevices/test</literal> | ||
455 | directory:</para> | ||
456 | |||
457 | <itemizedlist> | ||
458 | <listitem> | ||
459 | <para><filename>test.json</filename> file - contains all the | ||
460 | input parameters for the <literal>test</literal> | ||
461 | device:</para> | ||
462 | |||
463 | <programlisting>{ | ||
464 | "deviceId": "test_id", | ||
465 | "deviceGroupingTags": "test_id", | ||
466 | "name": "test", | ||
467 | "version": "2.5.0", | ||
468 | "callHome": "false", | ||
469 | "address": "10.0.0.1", | ||
470 | "certificate": null, | ||
471 | "description": "test", | ||
472 | "maintMode": "false", | ||
473 | "passphrase": null, | ||
474 | "password": "", | ||
475 | "port": "830", | ||
476 | "username": "root", | ||
477 | "interfaces": { | ||
478 | "mgmt": "eth0", | ||
479 | "wan": "eth1", | ||
480 | "lan": "eth2", | ||
481 | "wap": "wlan0" | ||
482 | } | ||
483 | }</programlisting> | ||
484 | </listitem> | ||
485 | |||
486 | <listitem> | ||
487 | <para><filename>store.json</filename> file - contains the | ||
488 | input parameters used for creating an offline config for the | ||
489 | uCPE Device:</para> | ||
490 | |||
491 | <programlisting>{ | ||
492 | "version": "2.5.0", | ||
493 | "deviceId": "test_id", | ||
494 | "deviceGroupingTags": "test_id", | ||
495 | "description": "Config file for test" | ||
496 | }</programlisting> | ||
497 | </listitem> | ||
498 | </itemizedlist> | ||
499 | </listitem> | ||
500 | </orderedlist> | ||
501 | |||
502 | <para>The <filename>generate_device_config.py</filename> script can be | ||
503 | executed in a non-interactive way using the | ||
504 | <command>--non-interactive</command> option, as follows:</para> | ||
505 | |||
506 | <programlisting>python generate_device_config.py --non-interactive --device_name=test | ||
507 | --device_id=test_id --device_grouping_tags=test_id --version 2.5.0 | ||
508 | --device_ip_addr=10.0.0.1 --call_home=false --mgmt_nic=eth0 --wan_nic=eth1 | ||
509 | --lan_nic=eth2 --wap_nic=wlan0</programlisting> | ||
510 | |||
511 | <para>The names of the interfaces (<literal>mgmt_*, wan_*, | ||
512 | lan_*</literal> and <literal>wap_*</literal>) are used to generate the | ||
513 | config file for NIC and OVS bridges. Their values depend on the input | ||
514 | scenario.</para> | ||
515 | |||
516 | <para>When the script is interactively run, the parameter's value | ||
517 | between the square brackets is the default one. It can be omitted when | ||
518 | the script is non-interactively run.</para> | ||
519 | </section> | ||
520 | |||
521 | <section id="nic_config_files"> | ||
522 | <title>Generating NIC config files</title> | ||
523 | |||
524 | <para><emphasis role="bold">Generating NIC config | ||
525 | files</emphasis></para> | ||
526 | |||
527 | <orderedlist> | ||
528 | <listitem> | ||
529 | <para>Run | ||
530 | <filename>generate_nics_config_files.py</filename>:</para> | ||
531 | |||
532 | <programlisting>python generate_nics_config_files.py | ||
533 | Device name: test | ||
534 | Check 'test' directory for JSON configuration files</programlisting> | ||
535 | </listitem> | ||
536 | |||
537 | <listitem> | ||
538 | <para>Check the configuration files for all interface types in the | ||
539 | <literal>modules/enea/config/uCPEDevices/test</literal> directory. | ||
540 | The interface name is defined in the | ||
541 | <filename>test.json</filename> file. The NIC config files have the | ||
542 | following structure: | ||
543 | <literal><interface_name>_<interface_type>_nic.json</literal>. | ||
544 | For the <literal>eth2</literal> lan interface, the following JSON | ||
545 | files are created:</para> | ||
546 | |||
547 | <itemizedlist> | ||
548 | <listitem> | ||
549 | <para><filename>lan_dpdk_nic.json</filename> - contains: | ||
550 | Interface type: <literal>DPDK</literal>; Sub-type: | ||
551 | <literal>vfio-pci</literal>.</para> | ||
552 | |||
553 | <programlisting> { | ||
554 | "name": "eth2", | ||
555 | "dpdk_type": "vfio-pci" | ||
556 | }</programlisting> | ||
557 | </listitem> | ||
558 | |||
559 | <listitem> | ||
560 | <para><filename>lan_sriov_nic.json</filename> - contains | ||
561 | Interface type: <literal>SR-IOV, SR-IOV</literal>; Mode: | ||
562 | <literal>adapter-pool</literal>; Num VFS: | ||
563 | <literal>2</literal>.</para> | ||
564 | |||
565 | <programlisting>{ | ||
566 | "name": "eth2", | ||
567 | "sriov_mode": "adapter-pool", | ||
568 | "sriov_num_vfs": "2" | ||
569 | }</programlisting> | ||
570 | </listitem> | ||
571 | |||
572 | <listitem> | ||
573 | <para><filename>lan_wan_nic.json</filename> - contains | ||
574 | Interface type: <literal>WAN</literal>; Address assignment: | ||
575 | <literal>DHCP</literal>.</para> | ||
576 | |||
577 | <programlisting>{ | ||
578 | "name": "eth2", | ||
579 | "address_assignment": "dhcp", | ||
580 | "ip_address": "null", | ||
581 | "gateway": "null", | ||
582 | "netmask": "null" | ||
583 | }</programlisting> | ||
584 | </listitem> | ||
585 | |||
586 | <listitem> | ||
587 | <para><filename>wap_wap_nic.json</filename> - contains | ||
588 | Interface type: <literal>WAP</literal>; Country Code: | ||
589 | <literal>SE</literal>; Wireless band: | ||
590 | <literal>band5GHz</literal>; Wireless Mode: <literal>802.11 | ||
591 | g/n</literal>; Radio Channel: <literal>42 (80 MHz | ||
592 | wide)</literal>.</para> | ||
593 | |||
594 | <programlisting>{ | ||
595 | "name": "wlan0", | ||
596 | "country_code": "SE", | ||
597 | "wireless_band": "band5GHz", | ||
598 | "wireless_mode": "802.11 ac/n", | ||
599 | "radio_channel": "42 (80 MHz wide)" | ||
600 | }</programlisting> | ||
601 | </listitem> | ||
602 | </itemizedlist> | ||
603 | </listitem> | ||
604 | </orderedlist> | ||
605 | |||
606 | <para>The <filename>generate_nics_config_files.py</filename> script | ||
607 | can be executed in a non-interactive way, as follows:</para> | ||
608 | |||
609 | <programlisting>python generate_nics_config_files.py --device_name=test | ||
610 | Check 'test' directory for JSON configuration files</programlisting> | ||
611 | |||
612 | <para>The values from the JSON files depend on the input | ||
613 | scenario.</para> | ||
614 | </section> | ||
615 | |||
616 | <section id="generate_ovs_config"> | ||
617 | <title>Generating OVS config files</title> | ||
618 | |||
619 | <para><emphasis role="bold">Generating OVS config | ||
620 | files</emphasis></para> | ||
621 | |||
622 | <orderedlist> | ||
623 | <listitem> | ||
624 | <para>Run | ||
625 | <filename>generate_bridges_config_files.py</filename>:</para> | ||
626 | |||
627 | <programlisting>python generate_bridges_config_files.py | ||
628 | Device name: test | ||
629 | Check 'test' directory for JSON configuration files</programlisting> | ||
630 | </listitem> | ||
631 | |||
632 | <listitem> | ||
633 | <para>Check the configuration files in the | ||
634 | <literal>modules/enea/config/uCPEDevices/test</literal> directory. | ||
635 | The name of OVS bridges type has the following structure: | ||
636 | <literal><bridge_type>_br.json</literal>. The following JSON | ||
637 | files are created:</para> | ||
638 | |||
639 | <itemizedlist> | ||
640 | <listitem> | ||
641 | <para><filename>ibm_br.json</filename> - contains information | ||
642 | about the <literal>In-band management OVS | ||
643 | bridge</literal>:</para> | ||
644 | |||
645 | <programlisting>{ | ||
646 | "name": "ibm_br", | ||
647 | "type": "inband_mgmt" | ||
648 | }</programlisting> | ||
649 | </listitem> | ||
650 | |||
651 | <listitem> | ||
652 | <para><filename>sfc_br.json</filename> - contains: | ||
653 | <literal>Dataplane OVS bridge</literal>; Type: | ||
654 | <literal>integration</literal>:</para> | ||
655 | |||
656 | <programlisting>{ | ||
657 | "name": "sfc_br", | ||
658 | "type": "dataplane", | ||
659 | "subType": "integration", | ||
660 | "interfaces": [] | ||
661 | }</programlisting> | ||
662 | </listitem> | ||
663 | |||
664 | <listitem> | ||
665 | <para><filename>vnfmgmt_ipv4_br.json</filename> - contains | ||
666 | <literal>VNF Management OVS bridge, IPv4</literal>:</para> | ||
667 | |||
668 | <programlisting>{ | ||
669 | "name": "vnfmgmt_ipv4_br", | ||
670 | "type": "vnfMgmt", | ||
671 | "vnfMgmtAddress": "10.0.0.1" | ||
672 | }</programlisting> | ||
673 | </listitem> | ||
674 | |||
675 | <listitem> | ||
676 | <para><filename>vnfmgmt_ipv6_br.json</filename> - contains | ||
677 | <literal>VNF Management OVS bridge, IPv6</literal>:</para> | ||
678 | |||
679 | <programlisting> | ||
680 | { | ||
681 | "name": "vnfmgmt_ipv6_br", | ||
682 | "type": "vnfMgmt", | ||
683 | "vnfMgmtAddress": "2001:db8:0:0:0:0:0:0" | ||
684 | }</programlisting> | ||
685 | </listitem> | ||
686 | |||
687 | <listitem> | ||
688 | <para><filename>lan_br.json</filename> - contains | ||
689 | <literal>Dataplane OVS bridge</literal>; Type: | ||
690 | <literal>communication</literal>; Interface: | ||
691 | <literal>eth2</literal>:</para> | ||
692 | |||
693 | <programlisting>lan_br.json | ||
694 | { | ||
695 | "name": "lan_br", | ||
696 | "type": "dataplane", | ||
697 | "subType": "communication", | ||
698 | "interfaces": [ | ||
699 | "eth2" | ||
700 | ] | ||
701 | }</programlisting> | ||
702 | </listitem> | ||
703 | |||
704 | <listitem> | ||
705 | <para><filename>wap_br.json</filename> - contains | ||
706 | <literal>Dataplane OVS bridge</literal>; Type: | ||
707 | <literal>communication</literal>:</para> | ||
708 | |||
709 | <programlisting>{ | ||
710 | "name": "wap_br", | ||
711 | "type": "dataplane", | ||
712 | "subType": "communication", | ||
713 | "interfaces": [] | ||
714 | }</programlisting> | ||
715 | </listitem> | ||
716 | </itemizedlist> | ||
717 | </listitem> | ||
718 | </orderedlist> | ||
719 | |||
720 | <para>The <filename>generate_bridges_config_files.py</filename> script | ||
721 | can be executed in a non-interactive way, as follows:</para> | ||
722 | |||
723 | <programlisting>python generate_bridges_config_files.py --device_name=test | ||
724 | Check 'test' directory for JSON configuration files</programlisting> | ||
725 | |||
726 | <para>The values from the JSON files depend on the input | ||
727 | scenario.</para> | ||
728 | </section> | ||
729 | </section> | ||
730 | |||
731 | <section id="config_file_vnf"> | ||
732 | <title>Configuration Files for the VNF</title> | ||
733 | |||
734 | <para>The VNF directory <literal>modules/enea/config/VNF</literal>, | ||
735 | contains subdirectories for each defined VNF: | ||
736 | <literal>fortigateFWImage</literal>, <literal>junipervSRXImae</literal> | ||
737 | and so on.</para> | ||
738 | |||
739 | <para>Each VNF subdirectory contains configuration files for: | ||
740 | cloud-init, VNF Descriptors, VNF instances. These configuration files | ||
741 | are examples used in test scenarios from Enea Edge Automation.</para> | ||
742 | |||
743 | <para>For more details about the test scenarios from | ||
744 | <literal>modules/enea/scenario/</literal>, see <xref | ||
745 | linkend="AFTH_test" />.</para> | ||
746 | </section> | ||
747 | </section> | ||
748 | |||
749 | <section id="AFTH_automation"> | ||
750 | <title>The Automation Framework</title> | ||
751 | |||
752 | <para>The Automation Framework scripts described in the following section | ||
753 | are located in the | ||
754 | <literal><Automation-installerdir>/automation_framework</literal> | ||
755 | directory.</para> | ||
756 | |||
757 | <section id="httpclient_class"> | ||
758 | <title>The ManagementClient class</title> | ||
759 | |||
760 | <para>The <literal>ManagementClient</literal> class is implemented in | ||
761 | the <filename>ManagementHTTPClientRestAPIv2.py</filename> script.</para> | ||
762 | |||
763 | <para>The scope of this class is to send REST API requests to the Enea | ||
764 | Edge Management application. The methods of the | ||
765 | <literal>ManagementClient</literal> class represent REST API calls to | ||
766 | the Enea Edge Management application or ways for creating the objects | ||
767 | that are used as input for sending the request.</para> | ||
768 | |||
769 | <para>The dictionaries used as the payload in the REST API requests are | ||
770 | created in methods from this class. The output of these methods is used | ||
771 | as input for the REST API request payload.</para> | ||
772 | |||
773 | <para>Each method has a short description in the header, as | ||
774 | follows:</para> | ||
775 | |||
776 | <itemizedlist spacing="compact"> | ||
777 | <listitem> | ||
778 | <para>The scope of the method</para> | ||
779 | </listitem> | ||
780 | |||
781 | <listitem> | ||
782 | <para>The input parameters</para> | ||
783 | </listitem> | ||
784 | |||
785 | <listitem> | ||
786 | <para>The return value from the source code</para> | ||
787 | </listitem> | ||
788 | |||
789 | <listitem> | ||
790 | <para>The URL for the REST API call</para> | ||
791 | </listitem> | ||
792 | |||
793 | <listitem> | ||
794 | <para>The payload dictionary for the REST API call</para> | ||
795 | </listitem> | ||
796 | </itemizedlist> | ||
797 | |||
798 | <para>Other classes from the <literal>automation_framework</literal> | ||
799 | directory inherit this class, and call its methods.</para> | ||
800 | |||
801 | <note> | ||
802 | <para>The <literal>uCPEMgrHTTPClientRestAPIv2</literal> class is a | ||
803 | wrapper of the <literal>ManagementClient</literal> class. All the | ||
804 | methods defined in the <literal>ManagementClient</literal> class can | ||
805 | be used when the <literal>uCPEMgrHTTPClientRestAPIv2</literal> object | ||
806 | is instantiated. The <literal>uCPEMgrHTTPClientRestAPIv2</literal> | ||
807 | object is deprecated and will be removed starting with the next major | ||
808 | release. It is recommended to use the | ||
809 | <literal>ManagementClient</literal> class instead.</para> | ||
810 | </note> | ||
811 | |||
812 | <para><emphasis role="bold">Examples</emphasis>:</para> | ||
813 | |||
814 | <orderedlist spacing="compact"> | ||
815 | <listitem> | ||
816 | <para>uCPE Device functionalities are defined in the | ||
817 | <literal>uCPEDeviceHandler</literal> class.</para> | ||
818 | </listitem> | ||
819 | |||
820 | <listitem> | ||
821 | <para>The <literal>uCPEDeviceHandler</literal> class inherits the | ||
822 | <literal>ManagementClient</literal> class.</para> | ||
823 | </listitem> | ||
824 | |||
825 | <listitem> | ||
826 | <para>The <literal>uCPEDeviceHandler</literal> method calls methods | ||
827 | from <literal>ManagementClient</literal> to send requests to the | ||
828 | Enea Edge Management application.</para> | ||
829 | </listitem> | ||
830 | |||
831 | <listitem> | ||
832 | <para>Methods from <literal>ManagementClient</literal> create the | ||
833 | payload dictionary starting from the input parameters and send the | ||
834 | REST API request.</para> | ||
835 | </listitem> | ||
836 | |||
837 | <listitem> | ||
838 | <para>The output of the methods are parsed and analyzed by methods | ||
839 | from the <literal>uCPEDeviceHandler</literal> class.</para> | ||
840 | </listitem> | ||
841 | </orderedlist> | ||
842 | </section> | ||
843 | |||
844 | <section id="mg_functionalities"> | ||
845 | <title>Handlers for Enea Edge Management Functionalities</title> | ||
846 | |||
847 | <para>In Enea Edge Automation the modules of the Enea Edge Management | ||
848 | application are represented by Python classes called | ||
849 | <literal>Handlers</literal>. Each Python class represents a | ||
850 | functionality of the Enea Edge Management application.</para> | ||
851 | |||
852 | <para>These classes are implemented in the Python scripts that have a | ||
853 | <literal>Handler</literal> string included in the name. The name of the | ||
854 | classes is the same as the name of Python script.</para> | ||
855 | |||
856 | <para>For the usage of any class, run the Python script with the | ||
857 | <emphasis role="bold">--help</emphasis> option:</para> | ||
858 | |||
859 | <programlisting>python automation_framework/uCPEDeviceHandler.py --help | ||
860 | Usage: uCPEDeviceHandler.py [OPTIONS] [PARAMETERS]... | ||
861 | |||
862 | Options: | ||
863 | -v, --verbose Get info about the methods and parameters | ||
864 | -d, --device_name TEXT The uCPE Device name | ||
865 | -m, --method TEXT The atomic operation you want to run | ||
866 | -f, --config_file TEXT The config file for NIC or bridges (optional | ||
867 | argument) | ||
868 | |||
869 | -o, --display_output Display output of the method | ||
870 | --help Show this message and exit.</programlisting> | ||
871 | |||
872 | <para>For displaying all the available Python APIs and their parameters, | ||
873 | run the Python script with the <literal>-v/--verbose</literal> option. A | ||
874 | few examples will be displayed in the following sections.</para> | ||
875 | |||
876 | <para>If the parameters of the Python APIs contain <literal>=</literal> | ||
877 | in their description that means they have a default value that is | ||
878 | already defined in the Python script. The default value of the parameter | ||
879 | is displayed after this symbol.</para> | ||
880 | |||
881 | <para>To use or change the default value of one or more parameters, | ||
882 | perform one of the following methods:</para> | ||
883 | |||
884 | <itemizedlist> | ||
885 | <listitem> | ||
886 | <para>Run the Python API using only the values of the parameters | ||
887 | without specifying the parameters' names. All parameters will be | ||
888 | given and the value will be the position of each parameter.</para> | ||
889 | </listitem> | ||
890 | |||
891 | <listitem> | ||
892 | <para>Run the Python API using the | ||
893 | <literal><parameter_name>=</literal> syntax. Only specific | ||
894 | parameters will be given and they will be specified as | ||
895 | <literal><parameter_name>=<parameter_value></literal>.</para> | ||
896 | </listitem> | ||
897 | |||
898 | <listitem> | ||
899 | <para>Run the Python API with a mix of parameters. Mandatory | ||
900 | parameters will be given without specifying their name (their | ||
901 | position will be used in this situation) and the optional parameters | ||
902 | will be given, using the syntax:<literal> | ||
903 | <parameter_name>=<parameter_value></literal>.</para> | ||
904 | </listitem> | ||
905 | </itemizedlist> | ||
906 | |||
907 | <para>In the <literal>test_harness/<module name></literal> | ||
908 | directory, the Ansible Playbooks are implemented for running the Python | ||
909 | scripts from Enea Edge Automation. The name of the Ansible Playbooks is | ||
910 | the same as the name of the Python method. The Python command is between | ||
911 | the <literal><command> ... </command></literal> tags from | ||
912 | the <literal>*.yml</literal> files.</para> | ||
913 | |||
914 | <section id="mg_functionalities_ucpe"> | ||
915 | <title>uCPE Device</title> | ||
916 | |||
917 | <para>The Enea Edge Management functionalities for the uCPE Device are | ||
918 | implemented, as follows:</para> | ||
919 | |||
920 | <itemizedlist spacing="compact"> | ||
921 | <listitem> | ||
922 | <para><filename>automation_framework/uCPEDeviceHandler.py</filename> | ||
923 | - <literal>uCPEDeviceHandler</literal> class with methods for | ||
924 | adding a device, removing a device, waiting a device to be up, | ||
925 | getting the uCPE Device status, and so on.</para> | ||
926 | </listitem> | ||
927 | |||
928 | <listitem> | ||
929 | <para><filename>automation_framework/Configuration.py</filename> - | ||
930 | <literal>Configuration</literal> class with methods for | ||
931 | configuring the uCPE Device: DPDK, external interface, and OVS | ||
932 | bridges. The methods of the <literal>Configuration</literal> class | ||
933 | are used in the <literal>uCPEDeviceHandler</literal> and | ||
934 | <literal>OfflineConfigHandler</literal> classes.</para> | ||
935 | </listitem> | ||
936 | </itemizedlist> | ||
937 | |||
938 | <para>The <literal>uCPEDeviceHandler</literal> class inherits the | ||
939 | <literal>Configuration</literal> class and all its methods.</para> | ||
940 | |||
941 | <para>The functionalities for <literal>configure external | ||
942 | interfaces</literal>, <literal>configure OVS bridges</literal> can be | ||
943 | run using the:</para> | ||
944 | |||
945 | <itemizedlist spacing="compact"> | ||
946 | <listitem> | ||
947 | <para>Configuration file located in | ||
948 | <literal>modules/enea/config/uCPEDevices</literal>, with the | ||
949 | <emphasis role="bold">-f</emphasis> option.</para> | ||
950 | </listitem> | ||
951 | |||
952 | <listitem> | ||
953 | <para>Input parameters.</para> | ||
954 | </listitem> | ||
955 | </itemizedlist> | ||
956 | |||
957 | <para>The <literal>addDevice</literal> and | ||
958 | <literal>removeDevice</literal> functionalities use the | ||
959 | <filename>modules/enea/config/uCPEDevice/<device_name>/<device_name>.json</filename> | ||
960 | config file, as the default.</para> | ||
961 | |||
962 | <para>The other functionalities can be run using only input | ||
963 | parameters.</para> | ||
964 | |||
965 | <para>To list the implemented methods (functionalities), run the | ||
966 | script with the <emphasis role="bold">-v/--verbose</emphasis> | ||
967 | option:</para> | ||
968 | |||
969 | <programlisting>python automation_framework/uCPEDeviceHandler.py -v | ||
970 | Info about uCPEDeviceHandler methods | ||
971 | ... | ||
972 | Method: addDpdkExternalInterface | ||
973 | Parameters: name, dpdkType | ||
974 | ...</programlisting> | ||
975 | |||
976 | <para>The syntax for running | ||
977 | <literal>addDpdkExternalInterface</literal>, using the configuration | ||
978 | file:</para> | ||
979 | |||
980 | <programlisting>python automation_framework/uCPEDeviceHandler.py -d <device_name> -m | ||
981 | addDpdkExternalInterface -f | ||
982 | modules/enea/config/uCPEDevices/<device_name>/<interface_name>_dpdk_nic.json </programlisting> | ||
983 | |||
984 | <para><emphasis role="bold">Example:</emphasis></para> | ||
985 | |||
986 | <programlisting>python automation_framework/uCPEDeviceHandler.py -d vep1445-8 -m | ||
987 | addDpdkExternalInterface -f modules/enea/config/uCPEDevices/vep1445-8/lan_dpdk_nic.json</programlisting> | ||
988 | |||
989 | <para>The syntax for running the | ||
990 | <literal>addDpdkExternalInterface</literal> functionality:</para> | ||
991 | |||
992 | <programlisting>python automation_framework/uCPEDeviceHandler.py -d <device_name> -m | ||
993 | addDpdkExternalInterface <interface_name> <dpdk_type></programlisting> | ||
994 | |||
995 | <para><emphasis role="bold">Example:</emphasis></para> | ||
996 | |||
997 | <programlisting>python automation_framework/uCPEDeviceHandler.py -d vep1445-8 -m | ||
998 | addDpdkExternalInterface eno4 vfio-pci</programlisting> | ||
999 | </section> | ||
1000 | |||
1001 | <section id="offline_config_mg_func"> | ||
1002 | <title>Offline config</title> | ||
1003 | |||
1004 | <para>The Enea Edge Management functionalities regarding the offline | ||
1005 | configuration are implemented as follows:</para> | ||
1006 | |||
1007 | <itemizedlist> | ||
1008 | <listitem> | ||
1009 | <para><filename>automation_framework/OfflineConfigHandler.py</filename> | ||
1010 | - <literal>OfflineConfigHandler</literal> class has methods for | ||
1011 | adding an offline config, removing an offline config, uploading an | ||
1012 | offline config on a uCPE Device, and so on.</para> | ||
1013 | </listitem> | ||
1014 | |||
1015 | <listitem> | ||
1016 | <para><filename>automation_framework/Configuration.py</filename> - | ||
1017 | <literal>Configuration</literal> class has methods for configuring | ||
1018 | the uCPE Device: DPDK, external interface, and OVS bridges. The | ||
1019 | methods of the <literal>Configuration</literal> class are used in | ||
1020 | the <literal>uCPEDeviceHandler</literal> and | ||
1021 | <literal>OfflineConfigHandler</literal> classes.</para> | ||
1022 | </listitem> | ||
1023 | </itemizedlist> | ||
1024 | |||
1025 | <para>The <literal>OfflineConfigHandler</literal> class inherits the | ||
1026 | <literal>Configuration</literal> class with all its methods.</para> | ||
1027 | |||
1028 | <para>The functionalities for the <literal>adding offline config | ||
1029 | store</literal>, <literal>removing offline config store</literal>, | ||
1030 | <literal>configuring external interfaces</literal>, | ||
1031 | <literal>configuring OVS bridges</literal> can be run using | ||
1032 | the:</para> | ||
1033 | |||
1034 | <itemizedlist spacing="compact"> | ||
1035 | <listitem> | ||
1036 | <para>Configuration file located in | ||
1037 | <literal>modules/enea/config/uCPEDevices</literal>.</para> | ||
1038 | </listitem> | ||
1039 | |||
1040 | <listitem> | ||
1041 | <para>Input parameters.</para> | ||
1042 | </listitem> | ||
1043 | </itemizedlist> | ||
1044 | |||
1045 | <para>The other functionalities can be run using only input | ||
1046 | parameters.</para> | ||
1047 | |||
1048 | <para>To list the implemented methods (functionalities), run the | ||
1049 | script with the <emphasis role="bold">-v/--verbose</emphasis> | ||
1050 | option:</para> | ||
1051 | |||
1052 | <programlisting>python automation_framework/OfflineConfigHandler.py -v | ||
1053 | Info about OfflineConfigHandler methods | ||
1054 | ... | ||
1055 | Method: addOfflineConfigStore | ||
1056 | Parameters: version, deviceId, deviceGroupingTags, descr='' | ||
1057 | ...</programlisting> | ||
1058 | |||
1059 | <para>The syntax for running the | ||
1060 | <literal>addOfflineConfigStore</literal> using the configuration | ||
1061 | file:</para> | ||
1062 | |||
1063 | <programlisting>python automation_framework/OfflineConfigHandler.py -s <store_name> -m | ||
1064 | addOfflineConfigStore -f <path_to_store_configuration_file></programlisting> | ||
1065 | |||
1066 | <para><emphasis role="bold">Example:</emphasis></para> | ||
1067 | |||
1068 | <programlisting>python automation_framework/OfflineConfigHandler.py -s testOfflineConfig -m | ||
1069 | addOfflineConfigStore -f modules/enea/config/uCPEDevices/test/store.json</programlisting> | ||
1070 | |||
1071 | <para>The syntax for running the | ||
1072 | <literal>addOfflineConfigStore</literal> functionality using input | ||
1073 | parameters: <literal>version</literal>, <literal>deviceId</literal>, | ||
1074 | <literal>deviceGroupingTags</literal>, <literal>desc</literal>:</para> | ||
1075 | |||
1076 | <programlisting>python automation_framework/OfflineConfigHandler.py -s <store_name> -m | ||
1077 | addOfflineConfigStore <version> <deviceId> <deviceGroupingTags></programlisting> | ||
1078 | |||
1079 | <para><emphasis role="bold">Example:</emphasis></para> | ||
1080 | |||
1081 | <programlisting>python automation_framework/OfflineConfigHandler.py -s testStoreName -m | ||
1082 | addOfflineConfigStore 2.5.0 deviceId customerTag</programlisting> | ||
1083 | </section> | ||
1084 | |||
1085 | <section id="custom_scripts_mg_func"> | ||
1086 | <title>Custom scripts</title> | ||
1087 | |||
1088 | <para>All the Enea Edge Management functionalities regarding the | ||
1089 | custom scripts are implemented in the | ||
1090 | <filename>CustomScriptsHandler.py</filename> script.</para> | ||
1091 | |||
1092 | <para>The <literal>CustomScriptsHandler</literal> class is implemented | ||
1093 | in <filename>CustomScriptsHandler.py</filename> script.</para> | ||
1094 | |||
1095 | <para>Examples of custom scripts are in the | ||
1096 | <literal>modules/enea/config/customScripts/</literal> directory. They | ||
1097 | can be used when running a Python method from the | ||
1098 | <literal>CustomScriptsHandler</literal> class.</para> | ||
1099 | |||
1100 | <para>To list the implemented methods (functionalities), run the | ||
1101 | script with the <emphasis role="bold">-v/--verbose</emphasis> | ||
1102 | option:</para> | ||
1103 | |||
1104 | <programlisting>python automation_framework/CustomScriptsHandler.py -v | ||
1105 | Info about CustomScriptHandler methods | ||
1106 | ... | ||
1107 | Method: uploadCustomScript | ||
1108 | Parameters: customScript, phase | ||
1109 | ...</programlisting> | ||
1110 | |||
1111 | <para>The syntax for running the <literal>uploadCustomScript</literal> | ||
1112 | functionality starting from the input parameters:</para> | ||
1113 | |||
1114 | <programlisting>python automation_framework/CustomScriptsHandler.py -m | ||
1115 | uploadCustomScript <customScript> <phase></programlisting> | ||
1116 | |||
1117 | <para><emphasis role="bold">Example</emphasis>:</para> | ||
1118 | |||
1119 | <programlisting>python automation_framework/CustomScriptsHandler.py -m uploadCustomScript | ||
1120 | modules/enea/config/customScripts/test_fail_after_once once-after-startup</programlisting> | ||
1121 | |||
1122 | <para>All the other methods run in a similar way.</para> | ||
1123 | </section> | ||
1124 | |||
1125 | <section id="device_upgrade_mg_func"> | ||
1126 | <title>Device upgrade</title> | ||
1127 | |||
1128 | <para>The Enea Edge Management functionalities regarding the uCPE | ||
1129 | Device upgrade are implemented in the | ||
1130 | <filename>DeviceUpgradeHandler.py</filename> script.</para> | ||
1131 | |||
1132 | <para>The <literal>DeviceUpgradeHandler</literal> class is implemented | ||
1133 | in the <filename>DeviceUpgradeHandler.py</filename> script.</para> | ||
1134 | |||
1135 | <para>To list the implemented methods (functionalities), run the | ||
1136 | script with the <emphasis role="bold">-v/--verbose</emphasis> | ||
1137 | option:</para> | ||
1138 | |||
1139 | <programlisting>python automation_framework/DeviceUpgradeHandler.py -v | ||
1140 | Info about DeviceUpgradeHandler methods | ||
1141 | ... | ||
1142 | Method: uploadImage | ||
1143 | Parameters: imagePath, type, module='VcpeAgent' | ||
1144 | ...</programlisting> | ||
1145 | |||
1146 | <para>The syntax for running the <literal>uploadImage</literal> | ||
1147 | functionality starting from the input parameters:</para> | ||
1148 | |||
1149 | <programlisting>python automation_framework/DeviceUpgradeHandler.py -m | ||
1150 | uploadImage <imagePath> <type></programlisting> | ||
1151 | |||
1152 | <para>The default value for the <literal>module</literal> is | ||
1153 | <literal>VcepAgent</literal>, cannot be changed and it is | ||
1154 | omitted.</para> | ||
1155 | |||
1156 | <para><emphasis role="bold">Example:</emphasis></para> | ||
1157 | |||
1158 | <programlisting>python automation_framework/DeviceUpgradeHandler.py -m uploadImage | ||
1159 | /tmp/enea-edge-runtime-xeon-d.tar.gz xeon-d</programlisting> | ||
1160 | |||
1161 | <para>All the other methods run in a similar way.</para> | ||
1162 | </section> | ||
1163 | |||
1164 | <section id="vnf_mg_func"> | ||
1165 | <title>VNF</title> | ||
1166 | |||
1167 | <para>The Enea Edge Management functionalities regarding the VNF are | ||
1168 | implemented in the <filename>VNFHandler.py</filename> script.</para> | ||
1169 | |||
1170 | <para>The <literal>VNFHandler</literal> class is implemented in the | ||
1171 | <filename>VNFHandler.py</filename> script.</para> | ||
1172 | |||
1173 | <para>To list the implemented methods (functionalities), run the | ||
1174 | script with the <emphasis role="bold">-v/--verbose</emphasis> | ||
1175 | option:</para> | ||
1176 | |||
1177 | <programlisting>python automation_framework/VNFHandler.py -v | ||
1178 | Info about VNFHandler methods | ||
1179 | ... | ||
1180 | Method: getVNFDescriptorByName | ||
1181 | Parameters: vnfDescriptorName | ||
1182 | ...</programlisting> | ||
1183 | |||
1184 | <para>The syntax for running the | ||
1185 | <literal>getVNFDescriptorByName</literal> functionality starting from | ||
1186 | the input parameters:</para> | ||
1187 | |||
1188 | <programlisting>python automation_framework/VNFHandler.py -m getVNFDescriptorByName <vnfDescriptorName> -o</programlisting> | ||
1189 | |||
1190 | <para><emphasis role="bold">Example:</emphasis></para> | ||
1191 | |||
1192 | <programlisting>python automation_framework/VNFHandler.py -m getVNFDescriptorByName fortigateImage -o</programlisting> | ||
1193 | |||
1194 | <para>All the other methods run in a similar way.</para> | ||
1195 | </section> | ||
1196 | |||
1197 | <section id="mg_funcs"> | ||
1198 | <title>Enea Edge Management</title> | ||
1199 | |||
1200 | <para>The functionalities regarding the Enea Edge Management | ||
1201 | configuration are implemented in the | ||
1202 | <filename>ManagementHandler.py</filename> script.</para> | ||
1203 | |||
1204 | <para>The <literal>ManagementHandler</literal> class is implemented in | ||
1205 | the <filename>ManagementHandler.py</filename> script.</para> | ||
1206 | |||
1207 | <para>To list the implemented methods (functionalities), run the | ||
1208 | script with the <emphasis role="bold">-v/--verbose</emphasis> | ||
1209 | option:</para> | ||
1210 | |||
1211 | <programlisting>python automation_framework/ManagementHandler.py -v | ||
1212 | Info about ManagementHandler methods | ||
1213 | ... | ||
1214 | Method: getManagementVersion | ||
1215 | Parameters(not needed): -- | ||
1216 | ...</programlisting> | ||
1217 | |||
1218 | <para>The syntax for running the | ||
1219 | <literal>getManagementVersion</literal> functionality is:</para> | ||
1220 | |||
1221 | <programlisting>python automation_framework/ManagementHandler.py -m getManagementVersion -o</programlisting> | ||
1222 | |||
1223 | <para>All the other methods run in a similar way.</para> | ||
1224 | |||
1225 | <note> | ||
1226 | <para>The functionalities relating to the Enea Edge Management | ||
1227 | application configuration are also implemented in the | ||
1228 | <filename>uCPEManagerHandler.py</filename> script where the | ||
1229 | <literal>uCPEManagerHandler</literal> class is defined. The | ||
1230 | <literal>uCPEManagerHandler</literal> class is a wrapper of the | ||
1231 | <literal>ManagementHandler</literal> class. The | ||
1232 | <filename>uCPEManagerHandler.py</filename> file is deprecated and | ||
1233 | will be removed starting with the next major release. It is | ||
1234 | recommended to use the <filename>ManagementHandler.py</filename> | ||
1235 | script instead.</para> | ||
1236 | </note> | ||
1237 | </section> | ||
1238 | </section> | ||
1239 | |||
1240 | <section id="auxiliar_classes"> | ||
1241 | <title>Auxiliar classes</title> | ||
1242 | |||
1243 | <section id="config_class"> | ||
1244 | <title>The Configuration class</title> | ||
1245 | |||
1246 | <para>The <literal>Configuration</literal> class is implemented in the | ||
1247 | <filename>Configuration.py</filename> script. The | ||
1248 | <literal>Configuration</literal> class cannot be independently | ||
1249 | used.</para> | ||
1250 | |||
1251 | <para>The <literal>uCPEDeviceHandler</literal> and | ||
1252 | <literal>OfflineConfigHandler</literal> classes inherit the | ||
1253 | <literal>Configuration</literal> class. The methods should be | ||
1254 | implemented for both functionalities: uCPE Device and Offline | ||
1255 | config.</para> | ||
1256 | </section> | ||
1257 | |||
1258 | <section id="logger_class"> | ||
1259 | <title>The Logger Class</title> | ||
1260 | |||
1261 | <para>The <literal>Logger</literal> class is implemented in the | ||
1262 | <filename>Logger.py</filename> script. It is inherited in all the | ||
1263 | classes defined in <literal>automation_framework</literal>.</para> | ||
1264 | |||
1265 | <para>This class defines a logger for displaying the logs from Python | ||
1266 | scripts, in console log and file log.</para> | ||
1267 | |||
1268 | <para>For console log, the logger has:</para> | ||
1269 | |||
1270 | <itemizedlist spacing="compact"> | ||
1271 | <listitem> | ||
1272 | <para>Default severity: <literal>INFO</literal></para> | ||
1273 | </listitem> | ||
1274 | |||
1275 | <listitem> | ||
1276 | <para>Format of the logs: <literal>[datetime] [severity] | ||
1277 | message</literal></para> | ||
1278 | </listitem> | ||
1279 | </itemizedlist> | ||
1280 | |||
1281 | <para>For file log, the logger has:</para> | ||
1282 | |||
1283 | <itemizedlist spacing="compact"> | ||
1284 | <listitem> | ||
1285 | <para>Logs path: <literal>log/debug.log</literal></para> | ||
1286 | </listitem> | ||
1287 | |||
1288 | <listitem> | ||
1289 | <para>Default severity: <literal>DEBUG</literal></para> | ||
1290 | </listitem> | ||
1291 | |||
1292 | <listitem> | ||
1293 | <para>Format of the logs: <literal>[severity] | ||
1294 | [name_of_Python_script] message</literal></para> | ||
1295 | </listitem> | ||
1296 | </itemizedlist> | ||
1297 | </section> | ||
1298 | </section> | ||
1299 | </section> | ||
1300 | |||
1301 | <section id="AFTH_test"> | ||
1302 | <title>Test Harness</title> | ||
1303 | |||
1304 | <para>The Test Harness sources are in the | ||
1305 | <literal><Automation-installerdir>/test_harness</literal> | ||
1306 | directory.</para> | ||
1307 | |||
1308 | <section id="indiv_ansible_playbooks"> | ||
1309 | <title>Individual Ansible Playbooks</title> | ||
1310 | |||
1311 | <para>The Ansible based Test Harness represents an example of | ||
1312 | structuring the files needed for creating automated test cases using the | ||
1313 | Enea Edge Automation, and provides a way to implement them.</para> | ||
1314 | |||
1315 | <para>The <filename>ansible.cfg</filename> file contains an example of | ||
1316 | the Ansible default configuration. The default value for | ||
1317 | <literal>stdout_callback</literal> is set to | ||
1318 | <literal>selective</literal>, to print only certain tasks. It is | ||
1319 | recommended to switch to <literal>debug</literal> when a test fails. By | ||
1320 | setting the parameter <literal>any_errors_fatal</literal> to | ||
1321 | <literal>True</literal>, task failures are considered fatal errors and | ||
1322 | the play execution stops.</para> | ||
1323 | |||
1324 | <para>All the Playbooks that execute Automation Framework Python modules | ||
1325 | run on <literal>localhost</literal>. New entries have to be created for | ||
1326 | direct communication over SSH with the boards.</para> | ||
1327 | |||
1328 | <para>The <filename>setup_env.sh</filename> script sets up the | ||
1329 | <literal>testHarness</literal> test environment by creating the | ||
1330 | <literal>testHarness-venv</literal> Python virtual environment, | ||
1331 | executing requests needed by Automation Framework Python modules, and | ||
1332 | installing Ansible. The Ansible package version is 2.9.6.</para> | ||
1333 | |||
1334 | <para>The <literal>test_harness</literal> directory contains all the | ||
1335 | implemented Ansible Playbooks. This directory contains the | ||
1336 | <filename>check_error.yml</filename> Playbook and many subdirectories, | ||
1337 | each subdirectory representing an Enea Edge Management module.</para> | ||
1338 | |||
1339 | <para>The <filename>check_errors.yml</filename> Playbook checks the | ||
1340 | Python output and returns success or fail results. This file is imported | ||
1341 | in all playbooks from the <literal>test_harness</literal> directory and | ||
1342 | it cannot be run standalone.</para> | ||
1343 | |||
1344 | <para>According to their functionality, the Ansible Playbooks that refer | ||
1345 | to offline configuration are in the <literal>OfflineConfig</literal> | ||
1346 | directory, the ones that refers to <literal>CustomScript</literal> are | ||
1347 | in the <literal>CustomScripts</literal>, and so on.</para> | ||
1348 | |||
1349 | <para>Each Ansible Playbook has a help menu for:</para> | ||
1350 | |||
1351 | <itemizedlist spacing="compact"> | ||
1352 | <listitem> | ||
1353 | <para>Returning the syntax, and examples for running the | ||
1354 | Playbook.</para> | ||
1355 | </listitem> | ||
1356 | |||
1357 | <listitem> | ||
1358 | <para>Warning if the input parameters are wrong or not enough. The | ||
1359 | input parameters are called <literal>extra-vars</literal> in Ansible | ||
1360 | playbooks.</para> | ||
1361 | </listitem> | ||
1362 | </itemizedlist> | ||
1363 | |||
1364 | <para>The help menu is activated when the Playbook is run without any | ||
1365 | parameters.</para> | ||
1366 | |||
1367 | <para><emphasis role="bold">Example</emphasis>:</para> | ||
1368 | |||
1369 | <orderedlist> | ||
1370 | <listitem> | ||
1371 | <para>Display the help menu for | ||
1372 | <filename>addDataPlaneOvsBridge.yml</filename>:</para> | ||
1373 | |||
1374 | <programlisting>ansible-playbook test_harness/uCPEDevice/addDataPlaneOvsBridge.yml | ||
1375 | |||
1376 | This playbook runs 'addDataPlaneOvsBridge' method from uCPEDeviceHandler module | ||
1377 | |||
1378 | The Python module will be run as: | ||
1379 | |||
1380 | Usage: uCPEDeviceHandler.py [OPTIONS] [PARAMETERS]... | ||
1381 | |||
1382 | Options: | ||
1383 | -v, --verbose Get info about the methods and parameters | ||
1384 | -d, --device_name TEXT The uCPE Device name | ||
1385 | -m, --method TEXT The atomic operation you want to run | ||
1386 | -f, --config_file TEXT The config file for NIC or bridges (optional | ||
1387 | argument) | ||
1388 | |||
1389 | -o, --display_output Display output of the method | ||
1390 | --help Show this message and exit. | ||
1391 | |||
1392 | Usage: | ||
1393 | ansible-playbook test_harness/uCPEDevice/addDataPlaneOvsBridge.yml -e | ||
1394 | "device=<device_name> bridge_config_file=<bridge_config_file>" | ||
1395 | ansible-playbook test_harness/uCPEDevice/addDataPlaneOvsBridge.yml -e | ||
1396 | "device=<device_name> bridge_name=<bridge_name> bridge_type=integration" | ||
1397 | ansible-playbook test_harness/uCPEDevice/addDataPlaneOvsBridge.yml -e | ||
1398 | "device=<device_name> bridge_name=<bridge_name> bridge_type=communication" | ||
1399 | ansible-playbook test_harness/uCPEDevice/addDataPlaneOvsBridge.yml -e | ||
1400 | "device=<device_name> bridge_name=<bridge_name> bridge_type=communication | ||
1401 | interfaces=<interfaces>"</programlisting> | ||
1402 | </listitem> | ||
1403 | |||
1404 | <listitem> | ||
1405 | <para>Run the <filename>addDataPlaneOvsBridge.yml</filename> | ||
1406 | playbook:</para> | ||
1407 | |||
1408 | <programlisting>ansible-playbook test_harness/uCPEDevice/addDataPlaneOvsBridge.yml -e | ||
1409 | "device=inteld1521-17 bridge_config_file=sfc_br.json" | ||
1410 | ansible-playbook test_harness/uCPEDevice/addDataPlaneOvsBridge.yml -e | ||
1411 | "device=inteld1521-17 bridge_config_file=lan_br.json" | ||
1412 | ansible-playbook test_harness/uCPEDevice/addDataPlaneOvsBridge.yml -e | ||
1413 | "device=inteld1521-17 bridge_name=sfc_br bridge_type=integration" | ||
1414 | ansible-playbook test_harness/uCPEDevice/addDataPlaneOvsBridge.yml -e | ||
1415 | "device=inteld1521-17 bridge_name=wap_br bridge_type=communication" | ||
1416 | ansible-playbook test_harness/uCPEDevice/addDataPlaneOvsBridge.yml -e | ||
1417 | "device=inteld1521-17 bridge_name=lan_br bridge_type=communication | ||
1418 | interfaces=eno4" | ||
1419 | ansible-playbook test_harness/uCPEDevice/addDataPlaneOvsBridge.yml -e | ||
1420 | "device=inteld1521-17 bridge_name=lan_br bridge_type=communication | ||
1421 | interfaces=eno4,eno5"</programlisting> | ||
1422 | </listitem> | ||
1423 | </orderedlist> | ||
1424 | |||
1425 | <para>Each Ansible Playbook from the <literal>test_harness</literal> | ||
1426 | directory represents an atomic operation, a basic functionality that is | ||
1427 | performed on the Enea Edge Management application at a specific period | ||
1428 | of the time. They can be sequentially run or they can be imported into | ||
1429 | other playbooks for creating complex scenarios.</para> | ||
1430 | |||
1431 | <para><emphasis role="bold">Example:</emphasis></para> | ||
1432 | |||
1433 | <para>To instantiate a VNF, the following operations have to be | ||
1434 | performed: connect to the uCPE Device, bind NICs, create an OVS bridge, | ||
1435 | create a VNF descriptor, and instantiate the VNF on the device. All | ||
1436 | these operations can be run Playbook after Playbook using the | ||
1437 | <literal>*.yml</literal> files from the <literal>test_harness</literal> | ||
1438 | directory.</para> | ||
1439 | </section> | ||
1440 | |||
1441 | <section id="test_scenario"> | ||
1442 | <title>Test Scenario</title> | ||
1443 | |||
1444 | <para>All the individual Playbooks can be used as imported Playbooks in | ||
1445 | complex test scenarios.</para> | ||
1446 | |||
1447 | <para>The complex scenarios are defined in: | ||
1448 | <literal>modules/enea/scenario</literal>.</para> | ||
1449 | |||
1450 | <para>The test scenarios are split into the following:</para> | ||
1451 | |||
1452 | <itemizedlist spacing="compact"> | ||
1453 | <listitem> | ||
1454 | <para>Functionalities to be tested and used: the | ||
1455 | <literal>CustomScripts, OfflineConfig, ovsTests</literal> | ||
1456 | directories.</para> | ||
1457 | </listitem> | ||
1458 | |||
1459 | <listitem> | ||
1460 | <para>Service Creation and Lifecycle: the | ||
1461 | <literal>chainedVNFsService</literal> directory.</para> | ||
1462 | </listitem> | ||
1463 | |||
1464 | <listitem> | ||
1465 | <para>VNF Deployment and Lifecycle: the | ||
1466 | <literal>fortigateFWService</literal> directory.</para> | ||
1467 | </listitem> | ||
1468 | </itemizedlist> | ||
1469 | |||
1470 | <para>For each test scenario, the <literal>README</literal> file | ||
1471 | contains:</para> | ||
1472 | |||
1473 | <itemizedlist> | ||
1474 | <listitem> | ||
1475 | <para>Preconditions:</para> | ||
1476 | |||
1477 | <itemizedlist spacing="compact"> | ||
1478 | <listitem> | ||
1479 | <para>The configuration files to be updated</para> | ||
1480 | </listitem> | ||
1481 | |||
1482 | <listitem> | ||
1483 | <para>The VNF images to be copied</para> | ||
1484 | </listitem> | ||
1485 | |||
1486 | <listitem> | ||
1487 | <para>The license file needed from the provider and added to a | ||
1488 | specific path, etc.</para> | ||
1489 | </listitem> | ||
1490 | </itemizedlist> | ||
1491 | </listitem> | ||
1492 | |||
1493 | <listitem> | ||
1494 | <para>Running procedures:</para> | ||
1495 | |||
1496 | <itemizedlist spacing="compact"> | ||
1497 | <listitem> | ||
1498 | <para>The <literal>ansible-playbook</literal> commands for setup | ||
1499 | the configuration</para> | ||
1500 | </listitem> | ||
1501 | |||
1502 | <listitem> | ||
1503 | <para>Testing the configuration</para> | ||
1504 | </listitem> | ||
1505 | |||
1506 | <listitem> | ||
1507 | <para>Cleaning up the configuration</para> | ||
1508 | </listitem> | ||
1509 | </itemizedlist> | ||
1510 | </listitem> | ||
1511 | </itemizedlist> | ||
1512 | |||
1513 | <para>The test scenarios have the <filename>variable.yml</filename> file | ||
1514 | that contains the input parameters for the Playbooks. These variables | ||
1515 | can be reused when the same setup is run on another device.</para> | ||
1516 | |||
1517 | <para><emphasis role="bold">Example:</emphasis></para> | ||
1518 | |||
1519 | <para>For the <literal>fortigateFWService</literal> scenario, the | ||
1520 | <filename>variable.yml</filename> file has the following content:</para> | ||
1521 | |||
1522 | <programlisting>vnf_image_path: "modules/enea/VNF_images/fortios.qcow2" | ||
1523 | vnfd_config_file: "modules/enea/config/VNF/fortigateImage/fortigateImage.json" | ||
1524 | vnfd_name: "fortigateImage" | ||
1525 | vnfi_config_file: "modules/enea/config/VNF/fortigateImage/fortigateFWInstance.json" | ||
1526 | vnfi_name: "fortigateFWInstance"</programlisting> | ||
1527 | </section> | ||
1528 | </section> | ||
1529 | |||
1530 | <section id="AFTH_pyton"> | ||
1531 | <title>Python Unit-Test Suite</title> | ||
1532 | |||
1533 | <para>The <literal>unit-test</literal> suite is implemented in the | ||
1534 | <literal>unit_tests</literal> directory.</para> | ||
1535 | |||
1536 | <para>The <literal>unit-test</literal> suite contains the | ||
1537 | <literal>unit-test</literal> class defined in | ||
1538 | <filename>unittestSuite.py</filename>, and examples of JSON configuration | ||
1539 | files that can be used for the execution of AF Python classes from the | ||
1540 | <literal>automation_framework</literal> directory.</para> | ||
1541 | |||
1542 | <para>The Python <literal>unit-test</literal> class defined in the | ||
1543 | <filename>unittestSuite.py</filename> script provides a way to automate | ||
1544 | the execution of specific test cases for each supported Python | ||
1545 | script.</para> | ||
1546 | |||
1547 | <para>This class requires a test suite configuration JSON file that | ||
1548 | contains a dictionary list of the Python scripts to be processed. Each | ||
1549 | dictionary contains the path of the Python script to be loaded and the | ||
1550 | path to the file describing the test cases to be performed against the | ||
1551 | designated script.</para> | ||
1552 | |||
1553 | <para>Python <literal>unit-test</literal> suite examples are in the | ||
1554 | <literal>unit_tests/scenario</literal> directory.</para> | ||
1555 | |||
1556 | <para>Each scenario has 3 parts:</para> | ||
1557 | |||
1558 | <itemizedlist spacing="compact"> | ||
1559 | <listitem> | ||
1560 | <para><literal>README</literal> - explains the prerequisites needed | ||
1561 | before running the Python <literal>unit-test</literal> suite.</para> | ||
1562 | </listitem> | ||
1563 | |||
1564 | <listitem> | ||
1565 | <para><literal>config</literal> - contains a JSON file for each | ||
1566 | functionality that is used in the specified scenario. The JSON files | ||
1567 | have two keys:</para> | ||
1568 | |||
1569 | <itemizedlist spacing="compact"> | ||
1570 | <listitem> | ||
1571 | <para>name: The description of the functionality.</para> | ||
1572 | </listitem> | ||
1573 | |||
1574 | <listitem> | ||
1575 | <para>args: The arguments of the Python module.</para> | ||
1576 | </listitem> | ||
1577 | </itemizedlist> | ||
1578 | </listitem> | ||
1579 | |||
1580 | <listitem> | ||
1581 | <para><literal>JSON</literal> - used for running the scenario. Each | ||
1582 | JSON file contains the calls to the JSON files from the | ||
1583 | <literal>config</literal> directory, and has two keys:</para> | ||
1584 | |||
1585 | <itemizedlist spacing="compact"> | ||
1586 | <listitem> | ||
1587 | <para>config: The JSON file from the <literal>config</literal> | ||
1588 | directory that is used.</para> | ||
1589 | </listitem> | ||
1590 | |||
1591 | <listitem> | ||
1592 | <para>module: The Python module that is run.</para> | ||
1593 | </listitem> | ||
1594 | </itemizedlist> | ||
1595 | </listitem> | ||
1596 | </itemizedlist> | ||
1597 | |||
1598 | <para>Steps for running the Python unit-test suite on the Enea Edge | ||
1599 | Management application are provided in the <literal>README</literal> file | ||
1600 | from scenario in use.</para> | ||
1601 | </section> | ||
1602 | </chapter> \ No newline at end of file | ||