diff --git a/.gitignore b/.gitignore index c38ccac..00d2735 100644 --- a/.gitignore +++ b/.gitignore @@ -134,4 +134,8 @@ dmypy.json # Tests /test_cases/integration_tests/alcatel/output.txt -/test_cases/integration_tests/huawei/output.txt \ No newline at end of file +/test_cases/integration_tests/huawei/output.txt +/test_cases/integration_tests/keymile/output.txt +/test_cases/integration_tests/edgecore/output.txt +/test_cases/integration_tests/pbn/output.txt +/test_cases/integration_tests/zhone/output.txt \ No newline at end of file diff --git a/README.md b/README.md index 9edd2fc..f470dbe 100644 --- a/README.md +++ b/README.md @@ -38,10 +38,10 @@ Click [here](https://thola.io/posts/thola-fosdem/) for more information ### Supported Vendors - Alcatel (nearly feature complete) - Huawei (nearly feature complete) - - Edgecore (not implemented yet) - - Keymile (work in progress) + - Edgecore (nearly feature complete) + - Keymile (nearly feature complete) - Pbn (not implemented yet) - - Zhone (not implemented yet) + - Zhone (work in progress) ### Supported network components @@ -51,6 +51,7 @@ Click [here](https://thola.io/posts/thola-fosdem/) for more information - ONTs - CPEs - Vlans +- Interfaces ## Download diff --git a/bootup/conf/bootstraps/create-alcatel-7360.sh b/bootup/conf/bootstraps/create-alcatel-7360.sh index a1b2009..fbad234 100755 --- a/bootup/conf/bootstraps/create-alcatel-7360.sh +++ b/bootup/conf/bootstraps/create-alcatel-7360.sh @@ -101,21 +101,21 @@ req='{ box_id=$(create_resource "$req" $ENDPOINT/boxen) || exit 1 -# Create login credentials at the switch (admin operation) +# Admin user req='{ - "username": "admin", - "password": "secret" + "name": "Admin" }' -admin_credential_id=$(create_resource "$req" $ENDPOINT/boxen/$box_id/credentials) +admin_id=$(create_resource "$req" $ENDPOINT/boxen/$box_id/users) -# Admin user +# Create login credentials at the switch (admin operation) req='{ - "name": "admin", - "credentials_id": '$admin_credential_id' + "username": "admin", + "password": "secret", + "user_id": '$admin_id' }' -admin_id=$(create_resource "$req" $ENDPOINT/boxen/$box_id/users) +admin_credential_id=$(create_resource "$req" $ENDPOINT/boxen/$box_id/credentials) # PortProfile 1 req='{ diff --git a/bootup/conf/bootstraps/create-edgecore-xxxx.sh b/bootup/conf/bootstraps/create-edgecore-xxxx.sh new file mode 100644 index 0000000..5d5699e --- /dev/null +++ b/bootup/conf/bootstraps/create-edgecore-xxxx.sh @@ -0,0 +1,154 @@ +#!/bin/bash +# This file is part of the NESi software. +# +# Copyright (c) 2020 +# Original Software Design by Ilya Etingof . +# +# Software adapted by inexio . +# - Janis Groß +# - Philip Konrath +# - Alexander Dincher +# +# License: https://github.com/inexio/NESi/LICENSE.rst +# +# Example NESi REST API server bootstrapping +# +ENDPOINT=http://localhost:5000/nesi/v1 + +path="`dirname \"$0\"`" + +. $path/functions.sh + +#--------------------------------------------------------# +# # +# Subrack 0 # +# |---> Card 1 # +# | |-> Port 1/1 # +# | | |-> Interface 1/1 # +# # +#--------------------------------------------------------# +# # +# default Vlan 1 # +# Enable Credentials # +# Backup Credentials # +# # +#--------------------------------------------------------# + +# Create a network device (admin operation) +req='{ + "vendor": "EdgeCore", + "model": "ECS4120-28Fv2-I", + "version": "A", + "description": "EdgeCore ECS4120-28Fv2-I box", + "hostname": "ed-ge-co-re-1", + "mgmt_address": "10.0.0.12", + "software_version": "MA5623V800R016C00", + "network_protocol": "ssh", + "network_address": "127.0.0.1", + "network_port": 9023, + "dsl_mode": "tr165", + "uuid": "1111" +}' + +box_id=$(create_resource "$req" $ENDPOINT/boxen) || exit 1 + +# Admin user +req='{ + "name": "Admin", + "profile": "root" +}' + +admin_id=$(create_resource "$req" $ENDPOINT/boxen/$box_id/users) + +# Admin credentials +req='{ + "username": "admin", + "password": "secret", + "user_id": '$admin_id' +}' + +admin_credential_id=$(create_resource "$req" $ENDPOINT/boxen/$box_id/credentials) + +# enable user +req='{ + "name": "Enable", + "profile": "enable" +}' + +enable_id=$(create_resource "$req" $ENDPOINT/boxen/$box_id/users) + +# Super enable credentials +req='{ + "username": "enable", + "password": "enable", + "user_id": '$enable_id' +}' + +enable_credential_id=$(create_resource "$req" $ENDPOINT/boxen/$box_id/credentials) + +# backup user +req='{ + "name": "Backup", + "profile": "backup" +}' + +backup_id=$(create_resource "$req" $ENDPOINT/boxen/$box_id/users) + +# Super backup credentials +req='{ + "username": "backup", + "password": "backup", + "user_id": '$backup_id' +}' + +backup_credential_id=$(create_resource "$req" $ENDPOINT/boxen/$box_id/credentials) + +### Subrack 0 ### + +# Create a physical subrack at the network device (admin operation) +req='{ + "name": "", + "description": "Pseudo Subrack" +}' + +subrack_id=$(create_resource "$req" $ENDPOINT/boxen/$box_id/subracks) + +### Unit-1 ### + +# Create a physical card at the network device (admin operation) +req='{ + "subrack_id": '$subrack_id', + "name": "1", + "product": "adsl" +}' + +unit_1=$(create_resource "$req" $ENDPOINT/boxen/$box_id/cards) + +### Port-1 ### + +# Create a physical port at the network device (admin operation) +req='{ + "card_id": '$unit_1', + "admin_state": "1", + "operational_state": "1" +}' + +port_1_1=$(create_resource "$req" $ENDPOINT/boxen/$box_id/ports) + +### Interface-1 ### + +# Create a physical interface at the network device (admin operation) +req='{ + "port_id": '$port_1_1' +}' + +interface_3_1_1=$(create_resource "$req" $ENDPOINT/boxen/$box_id/interfaces) + +# default Vlan +req='{ + "number": 1, + "name": "default", + "description": "The standard Vlan" +}' + +vlan_pppoe=$(create_resource "$req" $ENDPOINT/boxen/$box_id/vlans) diff --git a/bootup/conf/bootstraps/create-huawei-5623.sh b/bootup/conf/bootstraps/create-huawei-5623.sh index fe9b521..a95a429 100644 --- a/bootup/conf/bootstraps/create-huawei-5623.sh +++ b/bootup/conf/bootstraps/create-huawei-5623.sh @@ -123,28 +123,28 @@ req='{ box_id=$(create_resource "$req" $ENDPOINT/boxen) || exit 1 -# Super Admin credentials -req='{ - "username": "root", - "password": "secret" -}' - -root_credential_id=$(create_resource "$req" $ENDPOINT/boxen/$box_id/credentials) - # Super Admin user req='{ - "name": "root", - "credentials_id": '$root_credential_id', + "name": "Root", "level": "Super", "profile": "root", "append_info": "Super Admin", "reenter_num": 3, "reenter_num_temp": 3, - "lock_status": "Unlocked" + "lock_status": "unlocked" }' root_id=$(create_resource "$req" $ENDPOINT/boxen/$box_id/users) +# Super Admin credentials +req='{ + "username": "root", + "password": "secret", + "user_id": '$root_id' +}' + +root_credential_id=$(create_resource "$req" $ENDPOINT/boxen/$box_id/credentials) + # Service Profile req='{ "name": "line_spectrum_1", diff --git a/bootup/conf/bootstraps/create-keymile-MG2500.sh b/bootup/conf/bootstraps/create-keymile-MG2500.sh new file mode 100644 index 0000000..f87a252 --- /dev/null +++ b/bootup/conf/bootstraps/create-keymile-MG2500.sh @@ -0,0 +1,756 @@ +#!/bin/bash +# This file is part of the NESi software. +# +# Copyright (c) 2020 +# Original Software Design by Ilya Etingof . +# +# Software adapted by inexio . +# - Janis Groß +# - Philip Konrath +# - Alexander Dincher +# - Philipp-Noah Groß +# +# License: https://github.com/inexio/NESi/LICENSE.rst +# +# Example NESi REST API server bootstrapping +# +ENDPOINT=http://localhost:5000/nesi/v1 + +path="`dirname \"$0\"`" + +. $path/functions.sh + + +#--------------------------------------------------------# +# # +# Subrack 0 # +# |---> Unit-1 (adsl) (SUAD2) # +# | |-> Port-1 # +# | | |-> Chan-1 # +# | | |-> VCC-1 # +# | # +# |---> Unit-2 (sdsl) (SUSE1) # +# | |-> Port-1 # +# | |-> Port-2 # +# | |-> LogPorts # +# | | |-> LogPort-2 # +# | | | |-> Interface-1 # +# | # +# |---> Unit-3 (sdsl) (SUSE1) # +# | |-> Port-1 # +# | | |-> Interface-1 # +# | # +# |---> Unit-4 (adsl) (SUAD2) # +# | |-> Port-1 # +# | | |-> Chan-1 # +# | | |-> VCC-1 # +# | # +# |---> Unit-5 (vdsl) (SUVM4) # +# | |-> Port-1 # +# | | |-> Chan-1 # +# | | |-> Interface-1 # +# | # +# |---> Unit-6 (vdsl) (SUVM6) # +# | |-> Port-1 # +# | # +# |---> Unit-7 (ftth) (SUEN3) # +# | |-> Port-1 # +# | | |-> Interface-1 # +# | # +# |---> Unit-8 (vdsl) (SUVM6) # +# | # +# |---> Unit-11 (mgmt) (COGE1) # +# | |-> Port-1 (mgmt) # +# | # +# |---> Unit-19 (isdn) (isdn) # +# | |-> Port-1 # +# | |-> PortGroup-1 (PSTN) # +# | | |-> Port-1 # +# | |-> PortGroup-2 (ISDN) # +# | | |-> Port-1 # +#--------------------------------------------------------# + +# Create a network device (admin operation) +req='{ + "vendor": "KeyMile", + "model": "MileGate", + "version": "2500", + "description": "Example Switch", + "hostname": "KeyMileMG2500", + "mgmt_address": "10.0.0.12", + "software_version": "MG2500V800R016C00", + "network_protocol": "telnet", + "network_address": "127.0.0.1", + "network_port": 9023, + "uuid": "2500", + "currTemperature": 15 +}' + +box_id=$(create_resource "$req" $ENDPOINT/boxen) || exit 1 + +# Sessionmanager user +req='{ + "name": "Session Manager", + "level": "Super", + "profile": "root", + "append_info": "Sessionmanager", + "lock_status": "unlocked" +}' + +sessionmanager_id=$(create_resource "$req" $ENDPOINT/boxen/$box_id/users) + +# Sessionmanager credentials +req='{ + "username": "sessionmanager", + "password": "secret", + "user_id": '$sessionmanager_id' +}' + +sessionmanager_credential_id=$(create_resource "$req" $ENDPOINT/boxen/$box_id/credentials) + +# Manager user +req='{ + "name": "Manager", + "level": "Admin", + "profile": "admin", + "append_info": "Manager", + "lock_status": "unlocked" +}' + +manager_id=$(create_resource "$req" $ENDPOINT/boxen/$box_id/users) + +# Manager credentials +req='{ + "username": "manager", + "password": "secret", + "user_id": '$manager_id' +}' + +manager_credential_id=$(create_resource "$req" $ENDPOINT/boxen/$box_id/credentials) + +# Manager user +req='{ + "name": "Maintenance", + "level": "Operator", + "profile": "operator", + "append_info": "Maintenance", + "lock_status": "unlocked" +}' + +maintenance_id=$(create_resource "$req" $ENDPOINT/boxen/$box_id/users) + +# Maintenance credentials +req='{ + "username": "maintenance", + "password": "secret", + "user_id": '$maintenance_id' +}' + +maintenance_credential_id=$(create_resource "$req" $ENDPOINT/boxen/$box_id/credentials) + +# Manager user +req='{ + "name": "Information", + "level": "User", + "profile": "commonuser", + "append_info": "Information", + "lock_status": "unlocked" +}' + +information_id=$(create_resource "$req" $ENDPOINT/boxen/$box_id/users) + +# Information credentials +req='{ + "username": "information", + "password": "secret", + "user_id": '$information_id' +}' + +information_credential_id=$(create_resource "$req" $ENDPOINT/boxen/$box_id/credentials) + +### Nto1-Service-1 ### + +# Create a physical port at the network device (admin operation) +req='{ + "service_type": "nto1", + "svid": 123, + "address": "/unit-1/port-1/chan-1/interface-1" +}' + +srvc_nto1_1=$(create_resource "$req" $ENDPOINT/boxen/$box_id/srvcs) + +### 1to1singletag-Service-1 ### + +# Create a physical port at the network device (admin operation) +req='{ + "service_type": "1to1singletag", + "svid": 1213, + "address": "/unit-19/control" +}' + +srvc_1to1singletag_1=$(create_resource "$req" $ENDPOINT/boxen/$box_id/srvcs) + +### 1to1singletag-Service-2 ### + +# Create a physical port at the network device (admin operation) +req='{ + "service_type": "1to1singletag", + "svid": 187, + "address": "/unit-19/media" +}' + +srvc_1to1singletag_2=$(create_resource "$req" $ENDPOINT/boxen/$box_id/srvcs) + +#################################################################################################################### + +### Subrack 0 ### + +# Create a physical subrack at the network device (admin operation) +req='{ + "name": "", + "description": "Pseudo Subrack" +}' + +subrack_id=$(create_resource "$req" $ENDPOINT/boxen/$box_id/subracks) + +### Unit-1 ### + +# Create a physical card at the network device (admin operation) +req='{ + "subrack_id": '$subrack_id', + "product": "adsl", + "board_name": "SUAD2", + "supplier_build_state": "R3D", + "board_id": "305", + "hardware_key": 102, + "software": "suad2_r5c01.esw", + "software_name": "SUAD2", + "software_revision": "R5C01", + "state": "Ok", + "serial_number": "4363507882", + "manufacturer_name": "KEYMILE", + "model_name": "37900030", + "short_text": "MG SUSE1 SHDSL EFM 32-port", + "manufacturer_id": "100989", + "manufacturer_part_number": "09862706", + "manufacturer_build_state": "02", + "boot_loader": "BLSU1_R1G01/CT23337", + "processor": "CPU MPC852T/853T 50MHz, RAM 64MB, FLASH 32MB" +}' + +unit_1=$(create_resource "$req" $ENDPOINT/boxen/$box_id/cards) + +### Port-1 ### + +# Create a physical port at the network device (admin operation) +req='{ + "card_id": '$unit_1', + "admin_state": "1", + "operational_state": "1" +}' + +port_1_1=$(create_resource "$req" $ENDPOINT/boxen/$box_id/ports) + +### Chan-1 ### + +# Create a logical channel at the network device (admin operation) +req='{ + "port_id": '$port_1_1', + "description": "Channel #1" +}' + +chan_1_1_1=$(create_resource "$req" $ENDPOINT/boxen/$box_id/channels) + +### Interface-1 ### + +# Create a physical port at the network device (admin operation) +req='{ + "chan_id": '$chan_1_1_1' +}' + +interface_1_1_1_1=$(create_resource "$req" $ENDPOINT/boxen/$box_id/interfaces) + +### Unit-2 ### + +# Create a physical card at the network device (admin operation) +req='{ + "subrack_id": '$subrack_id', + "product": "sdsl", + "board_name": "SUSE1", + "supplier_build_state": "R1A", + "board_id": "330", + "hardware_key": 1, + "software": "suse1_r4d02_t01.esw", + "software_name": "SUSE1", + "software_revision": "R4D02_T01", + "state": "Ok", + "serial_number": "6973180458", + "manufacturer_name": "KEYMILE", + "model_name": "37900196", + "short_text": "MG SUAD2 ADSL2+ AnnexB 32-port", + "manufacturer_id": "100989", + "manufacturer_part_number": "09860762", + "manufacturer_build_state": "05", + "boot_loader": "BLSU1_R1F01/CT18388", + "processor": "CPU MPC852T/853T 50MHz, RAM 64MB, FLASH 32MB" +}' + +unit_2=$(create_resource "$req" $ENDPOINT/boxen/$box_id/cards) + +### Port-1 ### + +# Create a physical port at the network device (admin operation) +req='{ + "card_id": '$unit_2', + "admin_state": "1", + "operational_state": "1" +}' + +port_2_1=$(create_resource "$req" $ENDPOINT/boxen/$box_id/ports) + +### Port-2 ### + +# Create a physical port at the network device (admin operation) +req='{ + "card_id": '$unit_2', + "admin_state": "1", + "operational_state": "1" +}' + +port_2_2=$(create_resource "$req" $ENDPOINT/boxen/$box_id/ports) + +### LogPort-2 ### + +# Create a logical logport object at the network device (admin operation) +req='{ + "card_id": '$unit_2', + "name": "2/L/2", + "ports": "ports:2" +}' + +logport_2_l_2=$(create_resource "$req" $ENDPOINT/boxen/$box_id/logports) + +### Interface-1 ### + +# Create a physical port at the network device (admin operation) +req='{ + "logport_id": '$logport_2_l_2' +}' + +interface_2_l_2_1=$(create_resource "$req" $ENDPOINT/boxen/$box_id/interfaces) + +### Unit-3 ### + +# Create a physical card at the network device (admin operation) +req='{ + "subrack_id": '$subrack_id', + "product": "sdsl", + "board_name": "SUSE1", + "supplier_build_state": "R1A", + "board_id": "330", + "hardware_key": 3, + "software": "suse1_r4d02_t01.esw", + "software_name": "SUSE1", + "software_revision": "R4D02_T01", + "state": "Ok", + "serial_number": "3383369557", + "manufacturer_name": "KEYMILE", + "model_name": "37900196", + "short_text": "MG SUSE1 SHDSL EFM 32-port", + "manufacturer_id": "100989", + "manufacturer_part_number": "09862706", + "manufacturer_build_state": "02", + "boot_loader": "BLSU1_R1G01/CT23337", + "processor": "CPU MPC852T/853T 50MHz, RAM 64MB, FLASH 32MB" +}' + +unit_3=$(create_resource "$req" $ENDPOINT/boxen/$box_id/cards) + +### Port-1 ### + +# Create a physical port at the network device (admin operation) +req='{ + "card_id": '$unit_3', + "admin_state": "1", + "operational_state": "1" +}' + +port_3_1=$(create_resource "$req" $ENDPOINT/boxen/$box_id/ports) + +### Interface-1 ### + +# Create a physical port at the network device (admin operation) +req='{ + "port_id": '$port_3_1' +}' + +interface_3_1_1=$(create_resource "$req" $ENDPOINT/boxen/$box_id/interfaces) + +### Unit-4 ### + +# Create a physical card at the network device (admin operation) +req='{ + "subrack_id": '$subrack_id', + "product": "adsl", + "board_name": "SUAD2", + "supplier_build_state": "R3D", + "board_id": "305", + "hardware_key": 104, + "software": "suad2_r5c01.esw", + "software_name": "SUAD2", + "software_revision": "R5C01", + "state": "Ok", + "serial_number": "4810312946", + "manufacturer_name": "KEYMILE", + "model_name": "37900030", + "short_text": "MG SUAD2 ADSL2+ AnnexB 32-port", + "manufacturer_id": "100989", + "manufacturer_part_number": "09860762", + "manufacturer_build_state": "05", + "boot_loader": "BLSU1_R1F01/CT18388", + "processor": "CPU MPC852T/853T 50MHz, RAM 64MB, FLASH 32MB" +}' + +unit_4=$(create_resource "$req" $ENDPOINT/boxen/$box_id/cards) + +### Port-1 ### + +# Create a physical port at the network device (admin operation) +req='{ + "card_id": '$unit_4', + "admin_state": "1", + "operational_state": "1" +}' + +port_4_1=$(create_resource "$req" $ENDPOINT/boxen/$box_id/ports) + +### Chan-1 ### + +# Create a logical channel at the network device (admin operation) +req='{ + "port_id": '$port_4_1', + "description": "Channel #1" +}' + +chan_4_1_1=$(create_resource "$req" $ENDPOINT/boxen/$box_id/channels) + +### VCC-1 ### + +# Create a physical port at the network device (admin operation) +req='{ + "chan_id": '$chan_4_1_1' +}' + +interface_4_1_1_1=$(create_resource "$req" $ENDPOINT/boxen/$box_id/interfaces) + +### Unit-5 ### + +# Create a physical card at the network device (admin operation) +req='{ + "subrack_id": '$subrack_id', + "product": "vdsl", + "board_name": "SUVM4", + "supplier_build_state": "R1G", + "board_id": "345", + "hardware_key": 1, + "software": "suvm4_r3c02_01.esw", + "software_name": "SUVM4", + "software_revision": "R3C02_01", + "state": "Ok", + "serial_number": "6702369850", + "manufacturer_name": "KEYMILE", + "model_name": "37900293", + "short_text": "MG SUVM4 VDSL2 ISDN 32-port", + "manufacturer_id": "100989", + "manufacturer_part_number": "09866094", + "manufacturer_build_state": "01", + "boot_loader": "BPSUVM4_R1B03/CT0", + "processor": "CPU MPC852T/853T 50MHz, RAM 64MB, FLASH 32MB" +}' + +unit_5=$(create_resource "$req" $ENDPOINT/boxen/$box_id/cards) + +### Port-1 ### + +# Create a physical port at the network device (admin operation) +req='{ + "card_id": '$unit_5', + "admin_state": "1", + "operational_state": "1" +}' + +port_5_1=$(create_resource "$req" $ENDPOINT/boxen/$box_id/ports) + +### Chan-1 ### + +# Create a logical channel at the network device (admin operation) +req='{ + "port_id": '$port_5_1', + "description": "Channel #1" +}' + +chan_5_1_1=$(create_resource "$req" $ENDPOINT/boxen/$box_id/channels) + +### Interface-1 ### + +# Create a physical interface at the network device (admin operation) +req='{ + "chan_id": '$chan_5_1_1' +}' + +interface_5_1_1_1=$(create_resource "$req" $ENDPOINT/boxen/$box_id/interfaces) + +### Unit-6 ### + +# Create a physical card at the network device (admin operation) +req='{ + "subrack_id": '$subrack_id', + "product": "vdsl", + "board_name": "SUVM6", + "supplier_build_state": "R1K", + "board_id": "377", + "hardware_key": 25, + "software": "suvm6_r3e10_01.esw", + "software_name": "SUVM6", + "software_revision": "R3E10_01", + "state": "Ok", + "serial_number": "1283288279", + "manufacturer_name": "KEYMILE", + "model_name": "37900528", + "short_text": "MG SUVM6 VDSL2/17MHz ISDN 48pt", + "manufacturer_id": "100989", + "manufacturer_part_number": "09869778", + "manufacturer_build_state": "20", + "boot_loader": "BPSUVM6_R1B02/CT0", + "processor": "CPU MPC852T/853T 50MHz, RAM 64MB, FLASH 32MB" +}' + +unit_6=$(create_resource "$req" $ENDPOINT/boxen/$box_id/cards) + +### Port-1 ### + +# Create a physical port at the network device (admin operation) +req='{ + "card_id": '$unit_6', + "admin_state": "1", + "operational_state": "1" +}' + +port_6_1=$(create_resource "$req" $ENDPOINT/boxen/$box_id/ports) + +### Unit-7 ### + +# Create a physical card at the network device (admin operation) +req='{ + "subrack_id": '$subrack_id', + "product": "ftth", + "board_name": "SUEN3", + "supplier_build_state": "R1K", + "board_id": "377", + "hardware_key": 14, + "software": "suvm6_r3e10_01.esw", + "software_name": "SUEN3", + "software_revision": "R3E10_01", + "state": "Ok", + "serial_number": "6135149854", + "manufacturer_name": "KEYMILE", + "model_name": "37900528", + "short_text": "MG SUEN3 VDSL2/17MHz ISDN 48pt", + "manufacturer_id": "100989", + "manufacturer_part_number": "09869778", + "manufacturer_build_state": "20", + "boot_loader": "BPSUVM6_R1B02/CT0", + "processor": "CPU MPC852T/853T 50MHz, RAM 64MB, FLASH 32MB" +}' + +unit_7=$(create_resource "$req" $ENDPOINT/boxen/$box_id/cards) + +### Port-1 ### + +# Create a physical port at the network device (admin operation) +req='{ + "card_id": '$unit_7', + "admin_state": "1", + "operational_state": "1" +}' + +port_7_1=$(create_resource "$req" $ENDPOINT/boxen/$box_id/ports) + +### Interface-1 ### + +# Create a physical port at the network device (admin operation) +req='{ + "port_id": '$port_7_1' +}' + +interface_7_1_1=$(create_resource "$req" $ENDPOINT/boxen/$box_id/interfaces) + +### Unit-8 ### + +# Create a physical card at the network device (admin operation) +req='{ + "subrack_id": '$subrack_id', + "product": "vdsl", + "board_name": "SUVM6", + "supplier_build_state": "R1K", + "board_id": "377", + "hardware_key": 104, + "software": "suvm6_r3e10_01.esw", + "software_name": "SUVM6", + "software_revision": "R3E10_01", + "state": "Ok", + "serial_number": "8781619728", + "manufacturer_name": "KEYMILE", + "model_name": "37900528", + "short_text": "MG SUVM6 VDSL2/17MHz ISDN 48pt", + "manufacturer_id": "100989", + "manufacturer_part_number": "09869778", + "manufacturer_build_state": "20", + "boot_loader": "BPSUVM6_R1B02/CT0", + "processor": "CPU MPC852T/853T 50MHz, RAM 64MB, FLASH 32MB" +}' + +unit_8=$(create_resource "$req" $ENDPOINT/boxen/$box_id/cards) + +### Mgmt-Unit-11 ### + +# Create a physical card at the network device (admin operation) +req='{ + "subrack_id": '$subrack_id', + "board_name": "COGE1", + "supplier_build_state": "R3D", + "board_id": "305", + "hardware_key": 104, + "software": "COGE1_r5c01.esw", + "software_name": "COGE1", + "software_revision": "R5C01", + "state": "Ok", + "serial_number": "4810312946", + "manufacturer_name": "KEYMILE", + "model_name": "37900030", + "short_text": "MG COGE1 COGE1+ AnnexB 32-port", + "manufacturer_id": "100989", + "manufacturer_part_number": "09860762", + "manufacturer_build_state": "05", + "boot_loader": "BLSU1_R1F01/CT18388", + "processor": "CPU MPC852T/853T 50MHz, RAM 64MB, FLASH 32MB" +}' + +unit_11=$(create_resource "$req" $ENDPOINT/boxen/$box_id/mgmt_cards) + +### Mgmt-Port-1 ### + +# Create a physical port at the network device (admin operation) +req='{ + "mgmt_card_id": '$unit_11', + "admin_state": "1", + "operational_state": "1" +}' + +port_11_1=$(create_resource "$req" $ENDPOINT/boxen/$box_id/mgmt_ports) + +### Unit-19 ### + +# Create a physical card at the network device (admin operation) +req='{ + "subrack_id": '$subrack_id', + "product": "isdn", + "name": "19", + "board_name": "IPSX3", + "supplier_build_state": "R2B", + "board_id": "308", + "hardware_key": 105, + "software": "ipss2_r4e05_02.esw", + "software_name": "IPSS2", + "software_revision": "R4E05_02", + "state": "Ok", + "serial_number": "4936551973", + "manufacturer_name": "KEYMILE", + "model_name": "37900315", + "short_text": "MG IPSX3 VoIP SMG 912ch", + "manufacturer_id": "100989", + "manufacturer_part_number": "37900315", + "manufacturer_build_state": "09", + "boot_loader": "BLSU2_R1J01/CT40500", + "processor": "CPU MPC852T/853T 50MHz, RAM 64MB, FLASH 32MB", + "gateway_ipaddress": "10.0.0.20", + "subnet_mask": "255.255.255.0", + "default_gateway": "10.0.0.1", + "country_code": "+672" +}' + +unit_19=$(create_resource "$req" $ENDPOINT/boxen/$box_id/cards) + +### Port-1 ### + +# Create a physical port at the network device (admin operation) +req='{ + "card_id": '$unit_19', + "admin_state": "1", + "operational_state": "1" +}' + +port_19_1=$(create_resource "$req" $ENDPOINT/boxen/$box_id/ports) + +### PortGroupPort-1 ### + +# Create a physical port at the network device (admin operation) +req='{ + "card_id": '$unit_19', + "admin_state": "1", + "operational_state": "1", + "name": "19/G1/1", + "type": "PSTN" +}' + +port_19_G1_1=$(create_resource "$req" $ENDPOINT/boxen/$box_id/portgroupports) + +# test subscriber 1 +req='{ + "name": "tester", + "number": 9023, + "portgroupport_id": '$port_19_G1_1', + "autorisation_user_name": "Test User", + "autorisation_password": "topsecret", + "display_name": "Mr. Testuser" +}' + +subscriber_id=$(create_resource "$req" $ENDPOINT/boxen/$box_id/subscribers) + +### PortGroupPort-2 ### + +# Create a physical port at the network device (admin operation) +req='{ + "card_id": '$unit_19', + "admin_state": "1", + "operational_state": "1", + "name": "19/G2/1", + "type": "ISDN" +}' + +port_19_G2_1=$(create_resource "$req" $ENDPOINT/boxen/$box_id/portgroupports) + +# test subscriber 3 +req='{ + "name": "tester2", + "number": 7653312, + "portgroupport_id": '$port_19_G2_1', + "autorisation_user_name": "Test User 2", + "autorisation_password": "topsecret", + "display_name": "Mrs. Testuser" +}' + +subscriber_id=$(create_resource "$req" $ENDPOINT/boxen/$box_id/subscribers) + +# test subscriber 3 +req='{ + "name": "tester3", + "number": 1234567, + "portgroupport_id": '$port_19_G2_1', + "autorisation_user_name": "Test User 3", + "autorisation_password": "topsecret", + "display_name": "Mr. & Mrs. Testuser", + "registration_state": "Unregistered" +}' + +subscriber_id=$(create_resource "$req" $ENDPOINT/boxen/$box_id/subscribers) diff --git a/bootup/conf/ssh/id_rsa b/bootup/conf/ssh/id_rsa new file mode 100644 index 0000000..5c272a8 --- /dev/null +++ b/bootup/conf/ssh/id_rsa @@ -0,0 +1,28 @@ +-----BEGIN OPENSSH PRIVATE KEY----- +b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAABFwAAAAdzc2gtcn +NhAAAAAwEAAQAAAQEA2m6f+W9xnt0mHvvJqzasFmIP1/z8gaDTYcgzwYhE4UItZeUXLUzx +3PGSiFd8GkRIjEhaPL9omFbL5E5q/SLNzu6AAg9eNOMKthy+EwyUYAC/Z36XSsjt89hXkv +SwzqIT7APl5hE4ZZIub3mA9q9YmLlo9bAi90UF11z7U3/jg0vlV45iDUj02Ont/QsvaxWr +EQG3XF4DWs5iid7RFqoHYdwEAMafi3nTZZKB8RGvsx9vpZkjLy5h+9Svgx1mFJZz2G4yJ0 +sEGOL/6QGCc6fp0L58+2rkVLGUZ0VT1o3WCp9ij8PKh24h1nuYXr1xHkG+ojVv1sXCnMxY +ww7g9BX3HwAAA+Ai4SmvIuEprwAAAAdzc2gtcnNhAAABAQDabp/5b3Ge3SYe+8mrNqwWYg +/X/PyBoNNhyDPBiEThQi1l5RctTPHc8ZKIV3waREiMSFo8v2iYVsvkTmr9Is3O7oACD140 +4wq2HL4TDJRgAL9nfpdKyO3z2FeS9LDOohPsA+XmEThlki5veYD2r1iYuWj1sCL3RQXXXP +tTf+ODS+VXjmINSPTY6e39Cy9rFasRAbdcXgNazmKJ3tEWqgdh3AQAxp+LedNlkoHxEa+z +H2+lmSMvLmH71K+DHWYUlnPYbjInSwQY4v/pAYJzp+nQvnz7auRUsZRnRVPWjdYKn2KPw8 +qHbiHWe5hevXEeQb6iNW/WxcKczFjDDuD0FfcfAAAAAwEAAQAAAQEA0i7ctJIuDKXURsAV +oDBtiuQ1Rqpi9wEgJdkVJEbRsMeTE5dLpAWEPgwd6h/0hPnrrUD5w7aTGPN8ImXqwUW6ME +KC3niXN+C4r+AcbgwOwgo2I4pGXmnVvmwQaJIXh92hudtOXwF2+RWepRmPpM+5Osw+WRtx +qem64y7Pj9thuzWGyKGuFmQ8ujb7zh6ovWwNlyTB64rM9zq+YFPh8QWiXocRwN7egOChtZ +fF+amgn/wkMi1Ja11PTIzVON/ajg0vnpPYOZ56boerPU3YhRHnzHXkSa34qvzd7XofiNee +2ybfFO7QxaEhDfcIXqztItPp6t1RvIUb89lUyCT4WkG3cQAAAIEAtiMJt2nkKL8UWbY6PT +wgEZ9D4RRuZzEk4SMnonXxGaFAXtnL2+sKlQiyJhGJEKQrWAyEBIXQtZNo2rZwLIvOOq7T +uXk9OjwCGPXT50jLrhD09yBNeWAR4fZsCqAYEq1cjLZgaXJxBGiBWfvk0vHADnz6PKPxfi +q7PJKn7WAIT/4AAACBAPrlmB0HOvFL0QAN4HnvLe3QMy7HuDVoYaQ9jz9uB9T7VTE+N7R9 +CxwDD8AUufU8gc88tw1FBUaWN1l6K8gSC0KIIKgIVtT+lttblKY1qJIakox2V/+qbtPU0T +DTSaC85znNkUJ4eqavRCitjPVnKke6v5JSePQO6Rag5/8Ww9KjAAAAgQDe3/0ca5btlE7n +iDEWQxfpzBYyED19VVb0HVM82BMYDb9rbgdmAu5vEWmIhtOyNTjkvOR5ZvZ5alsFY+FbcV +QVDWu5AqHGp+iUm1pfxCNB7UbJN664O+raL6UyHDQLZfjPT/rUCL2PX4ePsLaV4Cc8lQ5D +thL7QOgFiQ2Sx9JNVQAAACRqYW5pc19ncm9zc0BKYW5pc3MtTWFjQm9vay1Qcm8ubG9jYW +wBAgMEBQ== +-----END OPENSSH PRIVATE KEY----- diff --git a/bootup/conf/ssh/id_rsa.pub b/bootup/conf/ssh/id_rsa.pub new file mode 100644 index 0000000..3eb0b1b --- /dev/null +++ b/bootup/conf/ssh/id_rsa.pub @@ -0,0 +1 @@ +ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDabp/5b3Ge3SYe+8mrNqwWYg/X/PyBoNNhyDPBiEThQi1l5RctTPHc8ZKIV3waREiMSFo8v2iYVsvkTmr9Is3O7oACD1404wq2HL4TDJRgAL9nfpdKyO3z2FeS9LDOohPsA+XmEThlki5veYD2r1iYuWj1sCL3RQXXXPtTf+ODS+VXjmINSPTY6e39Cy9rFasRAbdcXgNazmKJ3tEWqgdh3AQAxp+LedNlkoHxEa+zH2+lmSMvLmH71K+DHWYUlnPYbjInSwQY4v/pAYJzp+nQvnz7auRUsZRnRVPWjdYKn2KPw8qHbiHWe5hevXEeQb6iNW/WxcKczFjDDuD0Ffcf janis_gross@Janiss-MacBook-Pro.local diff --git a/bootup/restapi.sh b/bootup/restapi.sh index 6c7d600..aea0175 100755 --- a/bootup/restapi.sh +++ b/bootup/restapi.sh @@ -179,8 +179,10 @@ bash bootup/conf/bootstraps/create-vendors-and-models.sh if [ $recreate_db = "yes" ]; then #bash bootup/conf/bootstraps/create-box-port-vlan.sh - bash bootup/conf/bootstraps/create-alcatel-7360.sh - bash bootup/conf/bootstraps/create-huawei-5623.sh + #bash bootup/conf/bootstraps/create-alcatel-7360.sh + #bash bootup/conf/bootstraps/create-huawei-5623.sh + #bash bootup/conf/bootstraps/create-keymile-MG2500.sh + bash bootup/conf/bootstraps/create-edgecore-xxxx.sh fi if [ $alcatel_api = "yes" ]; then @@ -190,10 +192,10 @@ if [ $huawei_api = "yes" ]; then bash bootup/conf/bootstraps/create-huawei-5623.sh fi if [ $keymile_api = "yes" ]; then - bash bootup/conf/bootstraps/create-alcatel-7360.sh #work_in_progress + bash bootup/conf/bootstraps/create-keymile-MG2500.sh fi if [ $edgecore_api = "yes" ]; then - bash bootup/conf/bootstraps/create-alcatel-7360.sh #work_in_progress + bash bootup/conf/bootstraps/create-edgecore-xxxx.sh fi if [ $pbn_api = "yes" ]; then bash bootup/conf/bootstraps/create-alcatel-7360.sh #work_in_progress diff --git a/bootup/sockets/ssh.py b/bootup/sockets/ssh.py new file mode 100644 index 0000000..55ba080 --- /dev/null +++ b/bootup/sockets/ssh.py @@ -0,0 +1,137 @@ +from twisted.cred.portal import Portal +from twisted.cred import portal +from twisted.conch.ssh import factory, userauth, connection, keys, session +from twisted.conch.ssh.transport import SSHServerTransport +from twisted.conch import avatar +from twisted.cred.checkers import InMemoryUsernamePasswordDatabaseDontUse +from twisted.internet import reactor, protocol +from twisted.python import components +from zope.interface import implementer +import threading +import os +from pathlib import Path + +full_path = os.path.dirname(os.path.abspath(__file__)) +path = str(Path(full_path).parents[0]) + +SERVER_RSA_PUBLIC = path + '/conf/ssh/id_rsa.pub' +SERVER_RSA_PRIVATE = path + '/conf/ssh/id_rsa' + +PRIMES = { + 2048: [(2, 24265446577633846575813468889658944748236936003103970778683933705240497295505367703330163384138799145013634794444597785054574812547990300691956176233759905976222978197624337271745471021764463536913188381724789737057413943758936963945487690939921001501857793275011598975080236860899147312097967655185795176036941141834185923290769258512343298744828216530595090471970401506268976911907264143910697166165795972459622410274890288999065530463691697692913935201628660686422182978481412651196163930383232742547281180277809475129220288755541335335798837173315854931040199943445285443708240639743407396610839820418936574217939)], + 4096: [(2, 889633836007296066695655481732069270550615298858522362356462966213994239650370532015908457586090329628589149803446849742862797136176274424808060302038380613106889959709419621954145635974564549892775660764058259799708313210328185716628794220535928019146593583870799700485371067763221569331286080322409646297706526831155237865417316423347898948704639476720848300063714856669054591377356454148165856508207919637875509861384449885655015865507939009502778968273879766962650318328175030623861285062331536562421699321671967257712201155508206384317725827233614202768771922547552398179887571989441353862786163421248709273143039795776049771538894478454203924099450796009937772259125621285287516787494652132525370682385152735699722849980820612370907638783461523042813880757771177423192559299945620284730833939896871200164312605489165789501830061187517738930123242873304901483476323853308396428713114053429620808491032573674192385488925866607192870249619437027459456991431298313382204980988971292641217854130156830941801474940667736066881036980286520892090232096545650051755799297658390763820738295370567143697617670291263734710392873823956589171067167839738896249891955689437111486748587887718882564384870583135509339695096218451174112035938859)], +} + + +class Avatar(avatar.ConchUser): + def __init__(self, username, cli, model, template_root): + avatar.ConchUser.__init__(self) + self.username = username + self.cli = cli + self.model = model + self.template_root = template_root + self.channelLookup.update({b'session': session.SSHSession}) + + +@implementer(portal.IRealm) +class Realm(object): + def __init__(self, cli, model, template_root): + self.cli = cli + self.model = model + self.template_root = template_root + + def requestAvatar(self, avatarId, mind, *interfaces): + return interfaces[0], Avatar(avatarId, self.cli, self.model, self.template_root), lambda: None + + +class SSHProtocol(protocol.Protocol): + char = b'' + + def connectionMade(self): + connection = self.transport.getPeer().address + print('%s:%s connected.' % (connection.host, connection.port)) + + def connectionLost(self, reason=None): + connection = self.transport.getPeer().address + print('%s:%s disconnected.' % (connection.host, connection.port)) + + def receiveData(self): + while self.char == b'': + pass + + return_val = self.char + self.char = b'' + return return_val + + def dataReceived(self, data): + self.char = data + + +class ExampleSession(object): + def __init__(self, avatar): + self.avatar = avatar + + def getPty(self, term, windowSize, attrs): + pass + + def execCommand(self, proto, cmd): + raise Exception("not executing commands") + + def openShell(self, transport): + protocol = SSHProtocol() + protocol.makeConnection(transport) + transport.makeConnection(session.wrapProtocol(protocol)) + + command_processor = self.avatar.cli( + self.avatar.model, protocol, transport, (), template_root=self.avatar.template_root, daemon=True) + command_processor.skipLogin = True + thread = threading.Thread(target=command_processor.loop, args=()) + thread.start() + + def eofReceived(self): + pass + + def closed(self): + pass + + +class Factory(factory.SSHFactory): + protocol = SSHServerTransport + publicKeys = { + b'ssh-rsa': keys.Key.fromFile(SERVER_RSA_PUBLIC) + } + privateKeys = { + b'ssh-rsa': keys.Key.fromFile(SERVER_RSA_PRIVATE) + } + services = { + b'ssh-userauth': userauth.SSHUserAuthServer, + b'ssh-connection': connection.SSHConnection + } + + def getPrimes(self): + return PRIMES + + +class SshSocket: + def __init__(self, cli, model, template_root, hostaddress, port): + self.hostaddress = hostaddress + self.port = port + self.cli = cli + self.model = model + self.template_root = template_root + + def start(self): + components.registerAdapter(ExampleSession, Avatar, session.ISession) + + portal = Portal(Realm(self.cli, self.model, self.template_root)) + passwdDB = InMemoryUsernamePasswordDatabaseDontUse() + + for credential in self.model.credentials: + passwdDB.addUser(credential.username.encode('utf-8'), credential.password.encode('utf-8')) + + portal.registerChecker(passwdDB) + Factory.portal = portal + + print("Starting ssh socket on " + self.hostaddress + ":" + str(self.port)) + reactor.listenTCP(self.port, Factory()) + reactor.run() diff --git a/cli.py b/cli.py index a64a13a..13526d2 100644 --- a/cli.py +++ b/cli.py @@ -23,6 +23,7 @@ from nesi.softbox.cli import rest_client from nesi.softbox.base_resources import root, base from bootup.sockets.telnet import TelnetSocket +from bootup.sockets.ssh import SshSocket import pytest import subprocess @@ -184,8 +185,9 @@ def main(): telnet = TelnetSocket(cli, model, template_root, ip_address, int(port)) telnet.start() elif model.network_protocol == 'ssh': - ssh = None - # TODO: add ssh-socket daemon + cli = main.PostLoginCommandProcessor + ssh = SshSocket(cli, model, template_root, ip_address, int(port)) + ssh.start() else: stdin = os.fdopen(sys.stdin.fileno(), 'rb', 0) diff --git a/nesi/edgecore/api/__init__.py b/nesi/edgecore/api/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/nesi/edgecore/api/schemas/__init__.py b/nesi/edgecore/api/schemas/__init__.py new file mode 100644 index 0000000..04e408d --- /dev/null +++ b/nesi/edgecore/api/schemas/__init__.py @@ -0,0 +1,17 @@ +from inspect import isclass +from pkgutil import iter_modules +from pathlib import Path +from importlib import import_module + +# iterate through the modules in the current package +package_dir = Path(__file__).resolve().parent +for (_, module_name, _) in iter_modules([package_dir]): + + # import the module and iterate through its attributes + module = import_module(f"{__name__}.{module_name}") + for attribute_name in dir(module): + attribute = getattr(module, attribute_name) + + if isclass(attribute): + # Add the class to this package's variables + globals()[attribute_name] = attribute \ No newline at end of file diff --git a/nesi/edgecore/api/schemas/edgecore_box_schemas.py b/nesi/edgecore/api/schemas/edgecore_box_schemas.py new file mode 100644 index 0000000..85d2896 --- /dev/null +++ b/nesi/edgecore/api/schemas/edgecore_box_schemas.py @@ -0,0 +1,24 @@ +# This file is part of the NESi software. +# +# Copyright (c) 2020 +# Original Software Design by Ilya Etingof . +# +# Software adapted by inexio . +# - Janis Groß +# - Philip Konrath +# - Alexander Dincher +# +# License: https://github.com/inexio/NESi/LICENSE.rst + +from nesi.softbox.api.schemas.box_schemas import * + + +class EdgeCoreBoxSchema(BoxSchema): + class Meta: + model = Box + fields = BoxSchema.Meta.fields + ('management_start_address', 'management_end_address', 'logging_host', + 'loopback_detection_action', 'logging_port', 'logging_level', + 'sntp_server_ip', 'sntp_client', 'timezone_name', 'timezone_time', + 'summer_time_name', 'summer_time_region') + + diff --git a/nesi/edgecore/api/schemas/edgecore_card_schemas.py b/nesi/edgecore/api/schemas/edgecore_card_schemas.py new file mode 100644 index 0000000..5f3b4bf --- /dev/null +++ b/nesi/edgecore/api/schemas/edgecore_card_schemas.py @@ -0,0 +1,19 @@ +# This file is part of the NESi software. +# +# Copyright (c) 2020 +# Original Software Design by Ilya Etingof . +# +# Software adapted by inexio . +# - Janis Groß +# - Philip Konrath +# - Alexander Dincher +# +# License: https://github.com/inexio/NESi/LICENSE.rst + +from nesi.softbox.api.schemas.card_schemas import * + + +class EdgeCoreCardSchema(CardSchema): + class Meta: + model = Card + fields = CardSchema.Meta.fields + ('mac_address', 'admin_state', 'operational_state') diff --git a/nesi/edgecore/api/schemas/edgecore_interface_schemas.py b/nesi/edgecore/api/schemas/edgecore_interface_schemas.py new file mode 100644 index 0000000..da8e696 --- /dev/null +++ b/nesi/edgecore/api/schemas/edgecore_interface_schemas.py @@ -0,0 +1,21 @@ +# This file is part of the NESi software. +# +# Copyright (c) 2020 +# Original Software Design by Ilya Etingof . +# +# Software adapted by inexio . +# - Janis Groß +# - Philip Konrath +# - Alexander Dincher +# +# License: https://github.com/inexio/NESi/LICENSE.rst + +from nesi.softbox.api.schemas.interface_schemas import * + + +class EdgeCoreInterfaceSchema(InterfaceSchema): + class Meta: + model = Interface + fields = InterfaceSchema.Meta.fields + ('port_id', 'ingress_state', 'ingress_rate', 'egress_state', + 'egress_rate', 'vlan_membership_mode', 'native_vlan', 'allowed_vlan', + 'mac_address') diff --git a/nesi/edgecore/api/schemas/edgecore_port_schemas.py b/nesi/edgecore/api/schemas/edgecore_port_schemas.py new file mode 100644 index 0000000..b5cfe93 --- /dev/null +++ b/nesi/edgecore/api/schemas/edgecore_port_schemas.py @@ -0,0 +1,19 @@ +# This file is part of the NESi software. +# +# Copyright (c) 2020 +# Original Software Design by Ilya Etingof . +# +# Software adapted by inexio . +# - Janis Groß +# - Philip Konrath +# - Alexander Dincher +# +# License: https://github.com/inexio/NESi/LICENSE.rst + +from nesi.softbox.api.schemas.port_schemas import * + + +class EdgeCorePortSchema(PortSchema): + class Meta: + model = Port + fields = PortSchema.Meta.fields + ('mac_address', ) diff --git a/nesi/edgecore/api/schemas/edgecore_user_schemas.py b/nesi/edgecore/api/schemas/edgecore_user_schemas.py new file mode 100644 index 0000000..30f905c --- /dev/null +++ b/nesi/edgecore/api/schemas/edgecore_user_schemas.py @@ -0,0 +1,7 @@ +from nesi.softbox.api.schemas.user_schemas import * + + +class EdgecoreUserSchema(UserSchema): + class Meta: + model = User + fields = UserSchema.Meta.fields + ('profile',) diff --git a/nesi/edgecore/api/schemas/edgecore_vlan_schemas.py b/nesi/edgecore/api/schemas/edgecore_vlan_schemas.py new file mode 100644 index 0000000..fcba3da --- /dev/null +++ b/nesi/edgecore/api/schemas/edgecore_vlan_schemas.py @@ -0,0 +1,19 @@ +# This file is part of the NESi software. +# +# Copyright (c) 2020 +# Original Software Design by Ilya Etingof . +# +# Software adapted by inexio . +# - Janis Groß +# - Philip Konrath +# - Alexander Dincher +# +# License: https://github.com/inexio/NESi/LICENSE.rst + +from nesi.softbox.api.schemas.vlan_schemas import * + + +class EdgeCoreVlanSchema(VlanSchema): + class Meta: + model = Vlan + fields = VlanSchema.Meta.fields diff --git a/nesi/edgecore/edgecore_resources/__init__.py b/nesi/edgecore/edgecore_resources/__init__.py index a9a2c5b..2cc22c0 100644 --- a/nesi/edgecore/edgecore_resources/__init__.py +++ b/nesi/edgecore/edgecore_resources/__init__.py @@ -1 +1 @@ -__all__ = [] +__all__ = ["edgecore_card", "edgecore_interface", "edgecore_port", "edgecore_vlan", "edgecore_user"] diff --git a/nesi/edgecore/edgecore_resources/edgecore_box.py b/nesi/edgecore/edgecore_resources/edgecore_box.py index 47b29b7..ea2c8ce 100644 --- a/nesi/edgecore/edgecore_resources/edgecore_box.py +++ b/nesi/edgecore/edgecore_resources/edgecore_box.py @@ -9,10 +9,9 @@ # - Alexander Dincher # # License: https://github.com/inexio/NESi/LICENSE.rst -from nesi.huawei.huawei_resources import * +from nesi.edgecore.edgecore_resources import * from nesi.softbox.base_resources import credentials -from nesi.softbox.base_resources import route from nesi.softbox.base_resources.box import * LOG = logging.getLogger(__name__) @@ -25,6 +24,122 @@ class EdgeCoreBox(Box): :param identity: The identity of the System resource """ # Define Edgecore Properties + management_start_address = base.Field('management_start_address') + management_end_address = base.Field('management_end_address') + logging_host = base.Field('logging_host') + logging_port = base.Field('logging_port') + logging_level = base.Field('logging_level') + loopback_detection_action = base.Field('loopback_detection_action') + sntp_server_ip = base.Field('sntp_server_ip') + sntp_client = base.Field('sntp_client') + timezone_name = base.Field('timezone_name') + timezone_time = base.Field('timezone_time') + summer_time_name = base.Field('summer_time_name') + summer_time_region = base.Field('summer_time_region') + + @property + def credentials(self): + """Return `CredentialsCollection` object.""" + return credentials.CredentialsCollection( + self._conn, base.get_sub_resource_path_by( + self, 'credentials')) + + @property + def users(self): + """Return `UserCollection` object.""" + return edgecore_user.UserCollection( + self._conn, base.get_sub_resource_path_by( + self, 'users')) + + def get_user(self, field, value): + """Get specific user object.""" + return edgecore_user.EdgecoreUserCollection( + self._conn, base.get_sub_resource_path_by(self, 'users'), + params={field: value}).find_by_field_value(field, value) + + @property + def cards(self): + """Return `CardCollection` object.""" + return edgecore_card.EdgeCoreCardCollection( + self._conn, base.get_sub_resource_path_by(self, 'cards')) + + def get_card(self, field, value): + """Get specific card object.""" + return edgecore_card.EdgeCoreCardCollection( + self._conn, base.get_sub_resource_path_by(self, 'cards'), + params={field: value}).find_by_field_value(field, value) + + def get_cards(self, field, value): + """Get all cards.""" + return edgecore_card.EdgeCoreCardCollection( + self._conn, base.get_sub_resource_path_by(self, 'cards'), + params={field: value}) + + @property + def ports(self): + """Return `PortCollection` object.""" + return edgecore_port.EdgeCorePortCollection( + self._conn, base.get_sub_resource_path_by(self, 'ports')) + + def get_port(self, field, value): + """Get specific port object.""" + return edgecore_port.EdgeCorePortCollection( + self._conn, base.get_sub_resource_path_by(self, 'ports'), + params={field: value}).find_by_field_value(field, value) + + def get_ports(self, field, value): + """Get specific port object.""" + return edgecore_port.EdgeCorePortCollection( + self._conn, base.get_sub_resource_path_by(self, 'ports'), + params={field: value}) + + @property + def interfaces(self): + """Return `InterfaceCollection` object.""" + return edgecore_interface.EdgeCoreInterfaceCollection( + self._conn, base.get_sub_resource_path_by(self, 'interfaces')) + + def get_interface(self, field, value): + """Get specific interface object.""" + return edgecore_interface.EdgeCoreInterfaceCollection( + self._conn, base.get_sub_resource_path_by(self, 'interfaces'), + params={field: value}).find_by_field_value(field, value) + + def get_interfaces(self, field, value): + """Get specific interface object.""" + return edgecore_interface.EdgeCoreInterfaceCollection( + self._conn, base.get_sub_resource_path_by(self, 'interfaces'), + params={field: value}) + + @property + def vlans(self): + """Return `VlanCollection` object.""" + return edgecore_vlan.EdgeCoreVlanCollection( + self._conn, base.get_sub_resource_path_by(self, 'vlans')) + + def get_vlan(self, field, value): + """Get specific vlan object.""" + return edgecore_vlan.EdgeCoreVlanCollection( + self._conn, base.get_sub_resource_path_by(self, 'vlans'), + params={field: value}).find_by_field_value(field, value) + + def get_vlans(self, field, value): + """Get specific vlan object.""" + return edgecore_vlan.EdgeCoreVlanCollection( + self._conn, base.get_sub_resource_path_by(self, 'vlans'), + params={field: value}) + + def add_vlan(self, **fields): + """Add new vlan.""" + edgecore_vlan.EdgeCoreVlan.create( + self._conn, + os.path.join(self.path, 'vlans'), + **fields + ) + + def set(self, field, value): + mapping = {field: value} + self.update(**mapping) class EdgeCoreBoxCollection(BoxCollection): diff --git a/nesi/edgecore/edgecore_resources/edgecore_card.py b/nesi/edgecore/edgecore_resources/edgecore_card.py new file mode 100644 index 0000000..e431f77 --- /dev/null +++ b/nesi/edgecore/edgecore_resources/edgecore_card.py @@ -0,0 +1,36 @@ +# This file is part of the NESi software. +# +# Copyright (c) 2020 +# Original Software Design by Ilya Etingof . +# +# Software adapted by inexio . +# - Janis Groß +# - Philip Konrath +# - Alexander Dincher +# +# License: https://github.com/inexio/NESi/LICENSE.rst + +from nesi.softbox.base_resources.card import Card, CardCollection, logging +from nesi.softbox.base_resources import base + +LOG = logging.getLogger(__name__) + + +class EdgeCoreCard(Card): + """Represent physical shelf resource.""" + + mac_address = base.Field('mac_address') + admin_state = base.Field('admin_state') + operational_state = base.Field('operational_state') + + def set(self, field, value): + mapping = {field: value} + self.update(**mapping) + + +class EdgeCoreCardCollection(CardCollection): + """Represent a collection of cards.""" + + @property + def _resource_type(self): + return EdgeCoreCard diff --git a/nesi/edgecore/edgecore_resources/edgecore_interface.py b/nesi/edgecore/edgecore_resources/edgecore_interface.py new file mode 100644 index 0000000..9571240 --- /dev/null +++ b/nesi/edgecore/edgecore_resources/edgecore_interface.py @@ -0,0 +1,42 @@ +# This file is part of the NESi software. +# +# Copyright (c) 2020 +# Original Software Design by Ilya Etingof . +# +# Software adapted by inexio . +# - Janis Groß +# - Philip Konrath +# - Alexander Dincher +# +# License: https://github.com/inexio/NESi/LICENSE.rst + +from nesi.softbox.base_resources.interface import Interface, InterfaceCollection, logging +from nesi.softbox.base_resources import base + +LOG = logging.getLogger(__name__) + + +class EdgeCoreInterface(Interface): + """Represent a VlanInterface resource.""" + + port_id = base.Field('port_id') + ingress_state = base.Field('ingress_state') + ingress_rate = base.Field('ingress_rate') + egress_state = base.Field('egress_state') + egress_rate = base.Field('egress_rate') + vlan_membership_mode = base.Field('vlan_membership_mode') + native_vlan = base.Field('native_vlan') + allowed_vlan = base.Field('allowed_vlan') + mac_address = base.Field('mac_address') + + def set(self, field, value): + mapping = {field: value} + self.update(**mapping) + + +class EdgeCoreInterfaceCollection(InterfaceCollection): + """Represent the collection of VlanInterfaces.""" + + @property + def _resource_type(self): + return EdgeCoreInterface diff --git a/nesi/edgecore/edgecore_resources/edgecore_port.py b/nesi/edgecore/edgecore_resources/edgecore_port.py new file mode 100644 index 0000000..f49f4b2 --- /dev/null +++ b/nesi/edgecore/edgecore_resources/edgecore_port.py @@ -0,0 +1,34 @@ +# This file is part of the NESi software. +# +# Copyright (c) 2020 +# Original Software Design by Ilya Etingof . +# +# Software adapted by inexio . +# - Janis Groß +# - Philip Konrath +# - Alexander Dincher +# +# License: https://github.com/inexio/NESi/LICENSE.rst + +from nesi.softbox.base_resources.port import Port, PortCollection, logging +from nesi.softbox.base_resources import base + +LOG = logging.getLogger(__name__) + + +class EdgeCorePort(Port): + """Represent physical port resource.""" + + mac_address = base.Field('mac_address') + + def set(self, field, value): + mapping = {field: value} + self.update(**mapping) + + +class EdgeCorePortCollection(PortCollection): + """Represent a collection of ports.""" + + @property + def _resource_type(self): + return EdgeCorePort diff --git a/nesi/edgecore/edgecore_resources/edgecore_user.py b/nesi/edgecore/edgecore_resources/edgecore_user.py new file mode 100644 index 0000000..fb56e38 --- /dev/null +++ b/nesi/edgecore/edgecore_resources/edgecore_user.py @@ -0,0 +1,30 @@ +# This file is part of the NESi software. +# +# Copyright (c) 2020 +# Original Software Design by Ilya Etingof . +# +# Software adapted by inexio . +# - Janis Groß +# - Philip Konrath +# - Alexander Dincher +# +# License: https://github.com/inexio/NESi/LICENSE.rst + +from nesi.softbox.base_resources.user import User, UserCollection, logging +from nesi.softbox.base_resources import base + +LOG = logging.getLogger(__name__) + + +class EdgecoreUser(User): + """Represents a logical User resource""" + + profile = base.Field('profile') + + +class EdgecoreUserCollection(UserCollection): + """Represent the collection of Users.""" + + @property + def _resource_type(self): + return EdgecoreUser diff --git a/nesi/edgecore/edgecore_resources/edgecore_vlan.py b/nesi/edgecore/edgecore_resources/edgecore_vlan.py new file mode 100644 index 0000000..16b90ab --- /dev/null +++ b/nesi/edgecore/edgecore_resources/edgecore_vlan.py @@ -0,0 +1,32 @@ +# This file is part of the NESi software. +# +# Copyright (c) 2020 +# Original Software Design by Ilya Etingof . +# +# Software adapted by inexio . +# - Janis Groß +# - Philip Konrath +# - Alexander Dincher +# +# License: https://github.com/inexio/NESi/LICENSE.rst + +from nesi.softbox.base_resources.vlan import Vlan, VlanCollection, logging +from nesi.softbox.base_resources import base + +LOG = logging.getLogger(__name__) + + +class EdgeCoreVlan(Vlan): + """Represent a VLAN resource.""" + + def set(self, field, value): + mapping = {field: value} + self.update(**mapping) + + +class EdgeCoreVlanCollection(VlanCollection): + """Represent the collection of VLANs.""" + + @property + def _resource_type(self): + return EdgeCoreVlan diff --git a/nesi/exceptions.py b/nesi/exceptions.py index 4607f66..fd9c50c 100644 --- a/nesi/exceptions.py +++ b/nesi/exceptions.py @@ -76,15 +76,24 @@ class TerminalExitError(SoftboxenError): def __init__(self, **kwargs): super(TerminalExitError, self).__init__(**kwargs) self._return_to = None + self._command = None @property def return_to(self): return self._return_to + @property + def command(self): + return self._command + @return_to.setter def return_to(self, return_to): self._return_to = return_to + @command.setter + def command(self, command): + self._command = command + class TemplateError(SoftboxenError): """Raise on template rendering error.""" @@ -102,6 +111,20 @@ class CommandSyntaxError(SoftboxenError): def __init__(self, **kwargs): super(CommandSyntaxError, self).__init__(**kwargs) self.command = kwargs.get('command') + self.template = None + self.template_scopes = () + + +class CommandExecutionError(SoftboxenError): + """Raise on CLI command execution error.""" + + message = 'Command execution error: %(command)s' + + def __init__(self, **kwargs): + super(CommandExecutionError, self).__init__(**kwargs) + self.command = kwargs.get('command') + self.template = kwargs.get('template') + self.template_scopes = kwargs.get('template_scopes') class RestApiError(SoftboxenError): diff --git a/nesi/huawei/api/schemas/huawei_user_schemas.py b/nesi/huawei/api/schemas/huawei_user_schemas.py index 2ab3e86..4264e1a 100644 --- a/nesi/huawei/api/schemas/huawei_user_schemas.py +++ b/nesi/huawei/api/schemas/huawei_user_schemas.py @@ -4,5 +4,5 @@ class HuaweiUserSchema(UserSchema): class Meta: model = User - fields = UserSchema.Meta.fields + ('level', 'status', 'profile', 'append_info', 'reenter_num', - 'reenter_num_temp', 'lock_status') + fields = UserSchema.Meta.fields + ('level', 'profile', 'append_info', 'reenter_num', + 'reenter_num_temp') diff --git a/nesi/huawei/huawei_resources/huawei_card.py b/nesi/huawei/huawei_resources/huawei_card.py index 30c1ffa..6670ea2 100644 --- a/nesi/huawei/huawei_resources/huawei_card.py +++ b/nesi/huawei/huawei_resources/huawei_card.py @@ -35,4 +35,3 @@ class HuaweiCardCollection(CardCollection): @property def _resource_type(self): return HuaweiCard - diff --git a/nesi/huawei/huawei_resources/huawei_user.py b/nesi/huawei/huawei_resources/huawei_user.py index 090f2cf..d3acc6b 100644 --- a/nesi/huawei/huawei_resources/huawei_user.py +++ b/nesi/huawei/huawei_resources/huawei_user.py @@ -20,24 +20,22 @@ class HuaweiUser(User): """Represents a logical User resource""" level = base.Field('level') - status = base.Field('status') profile = base.Field('profile') append_info = base.Field('append_info') reenter_num = base.Field('reenter_num') reenter_num_temp = base.Field('reenter_num_temp') - lock_status = base.Field('lock_status') def set_online(self): - self.update(status='Online') + self.update(status='online') def set_offline(self): - self.update(status='Offline') + self.update(status='offline') def lock(self): - self.update(lock_status='Locked') + self.update(lock_status='locked') def unlock(self): - self.update(lock_status='Unlocked') + self.update(lock_status='unlocked') def set_reenter_num_temp(self, num): self.update(reenter_num_temp=num) diff --git a/nesi/keymile/api/__init__.py b/nesi/keymile/api/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/nesi/keymile/api/schemas/__init__.py b/nesi/keymile/api/schemas/__init__.py new file mode 100644 index 0000000..4bcd514 --- /dev/null +++ b/nesi/keymile/api/schemas/__init__.py @@ -0,0 +1,17 @@ +from inspect import isclass +from pkgutil import iter_modules +from pathlib import Path +from importlib import import_module + +# iterate through the modules in the current package +package_dir = Path(__file__).resolve().parent +for (_, module_name, _) in iter_modules([package_dir]): + + # import the module and iterate through its attributes + module = import_module(f"{__name__}.{module_name}") + for attribute_name in dir(module): + attribute = getattr(module, attribute_name) + + if isclass(attribute): + # Add the class to this package's variables + globals()[attribute_name] = attribute diff --git a/nesi/keymile/api/schemas/keymile_box_schemas.py b/nesi/keymile/api/schemas/keymile_box_schemas.py new file mode 100644 index 0000000..55234d1 --- /dev/null +++ b/nesi/keymile/api/schemas/keymile_box_schemas.py @@ -0,0 +1,33 @@ +# This file is part of the NESi software. +# +# Copyright (c) 2020 +# Original Software Design by Ilya Etingof . +# +# Software adapted by inexio . +# - Janis Groß +# - Philip Konrath +# - Alexander Dincher +# - Philipp-Noah Groß +# +# License: https://github.com/inexio/NESi/LICENSE.rst + +from nesi.softbox.api.schemas.box_schemas import * + + +class KeyMileBoxSchema(BoxSchema): + class Meta: + model = Box + fields = BoxSchema.Meta.fields + ('channels', 'interfaces', 'currTemperature', 'logports', 'ftp_server_ip', 'ftp_login', + 'ftp_password', 'network_element_management_vlan_id') + + interfaces = ma.Hyperlinks( + {'_links': { + 'self': ma.URLFor('show_interfaces', box_id='')}}) + + channels = ma.Hyperlinks( + {'_links': { + 'self': ma.URLFor('show_channels', box_id='')}}) + + logports = ma.Hyperlinks( + {'_links': { + 'self': ma.URLFor('show_logports', box_id='')}}) diff --git a/nesi/keymile/api/schemas/keymile_card_schemas.py b/nesi/keymile/api/schemas/keymile_card_schemas.py new file mode 100644 index 0000000..7f62849 --- /dev/null +++ b/nesi/keymile/api/schemas/keymile_card_schemas.py @@ -0,0 +1,31 @@ +# This file is part of the NESi software. +# +# Copyright (c) 2020 +# Original Software Design by Ilya Etingof . +# +# Software adapted by inexio . +# - Janis Groß +# - Philip Konrath +# - Alexander Dincher +# +# License: https://github.com/inexio/NESi/LICENSE.rst + +from nesi.softbox.api.schemas.card_schemas import * + + +class KeyMileCardSchema(CardSchema): + class Meta: + model = Card + fields = CardSchema.Meta.fields + ('board_name', 'supplier_build_state', 'board_id', 'hardware_key', 'software', + 'software_name', 'software_revision', 'state', 'serial_number', + 'manufacturer_name', 'model_name', 'short_text', 'manufacturer_id', + 'manufacturer_part_number', 'manufacturer_build_state', 'customer_id', + 'customer_product_id', 'boot_loader', 'processor', 'label1', 'label2', + 'gateway_name', 'home_domain', 'sip_port_number', 'country_code', 'area_code', + 'retransmission_timer', 'max_retransmission_interval', 'sip_extension', + 'asserted_id_mode', 'overlap_signalling', 'overlap_timer', + 'uac_request_timer', 'uas_request_timer', 'session_expiration', 'proxy_mode', + 'proxy_address', 'proxy_port', 'proxy_address_sec', 'proxy_port_sec', + 'proxy_enable', 'proxy_method', 'proxy_interval', 'registrar_adress', + 'registrar_port', 'registration_mode', 'registration_expiration_time', + 'gateway_ipaddress', 'subnet_mask', 'default_gateway') diff --git a/nesi/keymile/api/schemas/keymile_channel_schemas.py b/nesi/keymile/api/schemas/keymile_channel_schemas.py new file mode 100644 index 0000000..010810c --- /dev/null +++ b/nesi/keymile/api/schemas/keymile_channel_schemas.py @@ -0,0 +1,20 @@ +# This file is part of the NESi software. +# +# Copyright (c) 2020 +# Original Software Design by Ilya Etingof . +# +# Software adapted by inexio . +# - Janis Groß +# - Philip Konrath +# - Alexander Dincher +# +# License: https://github.com/inexio/NESi/LICENSE.rst + +from nesi.softbox.api.schemas.channel_schemas import * + + +class KeyMileChannelSchema(ChannelSchema): + class Meta: + model = Channel + fields = ChannelSchema.Meta.fields + ('interfaces', 'chan_profile_name', 'curr_rate_u', 'curr_rate_d', + 'prev_rate_u', 'prev_rate_d', 'curr_delay_u') diff --git a/nesi/keymile/api/schemas/keymile_interface_schemas.py b/nesi/keymile/api/schemas/keymile_interface_schemas.py new file mode 100644 index 0000000..960a086 --- /dev/null +++ b/nesi/keymile/api/schemas/keymile_interface_schemas.py @@ -0,0 +1,21 @@ +# This file is part of the NESi software. +# +# Copyright (c) 2020 +# Original Software Design by Ilya Etingof . +# +# Software adapted by inexio . +# - Janis Groß +# - Philip Konrath +# - Alexander Dincher +# +# License: https://github.com/inexio/NESi/LICENSE.rst + +from nesi.softbox.api.schemas.interface_schemas import * + + +class KeyMileInterfaceSchema(InterfaceSchema): + class Meta: + model = Interface + fields = InterfaceSchema.Meta.fields + ('chan_id', 'port_id', 'logport_id', 'number_of_conn_services', + 'reconfiguration_allowed', 'vcc_profile', 'vlan_profile', + 'services_connected') diff --git a/nesi/keymile/api/schemas/keymile_logport_schemas.py b/nesi/keymile/api/schemas/keymile_logport_schemas.py new file mode 100644 index 0000000..8a8ae3c --- /dev/null +++ b/nesi/keymile/api/schemas/keymile_logport_schemas.py @@ -0,0 +1,19 @@ +# This file is part of the NESi software. +# +# Copyright (c) 2020 +# Original Software Design by Ilya Etingof . +# +# Software adapted by inexio . +# - Janis Groß +# - Philip Konrath +# - Alexander Dincher +# +# License: https://github.com/inexio/NESi/LICENSE.rst + +from nesi.softbox.api.schemas.logport_schemas import * + + +class KeyMileLogPortSchema(LogPortSchema): + class Meta: + model = LogPort + fields = LogPortSchema.Meta.fields + ('interfaces',) diff --git a/nesi/keymile/api/schemas/keymile_mgmt_card_schemas.py b/nesi/keymile/api/schemas/keymile_mgmt_card_schemas.py new file mode 100644 index 0000000..d4be416 --- /dev/null +++ b/nesi/keymile/api/schemas/keymile_mgmt_card_schemas.py @@ -0,0 +1,24 @@ +# This file is part of the NESi software. +# +# Copyright (c) 2020 +# Original Software Design by Ilya Etingof . +# +# Software adapted by inexio . +# - Janis Groß +# - Philip Konrath +# - Alexander Dincher +# +# License: https://github.com/inexio/NESi/LICENSE.rst + +from nesi.softbox.api.schemas.mgmt_card_schemas import * + + +class KeyMileMgmtCardSchema(MgmtCardSchema): + class Meta: + model = MgmtCard + fields = MgmtCardSchema.Meta.fields + ('board_name', 'supplier_build_state', 'board_id', 'hardware_key', + 'software','software_name', 'software_revision', 'state', 'serial_number', + 'manufacturer_name', 'model_name', 'short_text', 'manufacturer_id', + 'manufacturer_part_number', 'manufacturer_build_state', 'customer_id', + 'customer_product_id', 'boot_loader', 'processor', 'label1', 'label2', + 'product') diff --git a/nesi/keymile/api/schemas/keymile_mgmt_port_schemas.py b/nesi/keymile/api/schemas/keymile_mgmt_port_schemas.py new file mode 100644 index 0000000..9b0a12f --- /dev/null +++ b/nesi/keymile/api/schemas/keymile_mgmt_port_schemas.py @@ -0,0 +1,20 @@ +# This file is part of the NESi software. +# +# Copyright (c) 2020 +# Original Software Design by Ilya Etingof . +# +# Software adapted by inexio . +# - Janis Groß +# - Philip Konrath +# - Alexander Dincher +# +# License: https://github.com/inexio/NESi/LICENSE.rst + +from nesi.softbox.api.schemas.mgmt_port_schemas import * + + +class KeyMilePortSchema(MgmtPortSchema): + class Meta: + model = MgmtPort + fields = MgmtPortSchema.Meta.fields + ('label1', 'label2') + diff --git a/nesi/keymile/api/schemas/keymile_port_schemas.py b/nesi/keymile/api/schemas/keymile_port_schemas.py new file mode 100644 index 0000000..cd8dd4b --- /dev/null +++ b/nesi/keymile/api/schemas/keymile_port_schemas.py @@ -0,0 +1,25 @@ +# This file is part of the NESi software. +# +# Copyright (c) 2020 +# Original Software Design by Ilya Etingof . +# +# Software adapted by inexio . +# - Janis Groß +# - Philip Konrath +# - Alexander Dincher +# +# License: https://github.com/inexio/NESi/LICENSE.rst + +from nesi.softbox.api.schemas.port_schemas import * + + +class KeyMilePortSchema(PortSchema): + class Meta: + model = Port + fields = PortSchema.Meta.fields + ('channels', 'label1', 'label2', 'loopbacktest_state', 'melttest_state', + 'linetest_state', 'profile1_enable', 'profile1_name', 'profile1_elength', + 'profile2_enable', 'profile2_name', 'profile2_elength', 'profile3_enable', + 'profile3_name', 'profile3_elength', 'profile4_enable', 'profile4_name', + 'profile_mode', 'mode', 'flow_control', 'upstream', 'downstream') + + channels = ma.Nested(CpesSchema.CpeSchema, many=True) diff --git a/nesi/keymile/keymile_resources/__init__.py b/nesi/keymile/keymile_resources/__init__.py index a9a2c5b..4d2603c 100644 --- a/nesi/keymile/keymile_resources/__init__.py +++ b/nesi/keymile/keymile_resources/__init__.py @@ -1 +1,3 @@ -__all__ = [] +__all__ = ["keymile_card", "keymile_port", "keymile_subrack", "keymile_channel", "keymile_interface", + "keymile_subscriber", "keymile_logport", "keymile_portgroupport", "keymile_srvc", "keymile_mgmt_card", + "keymile_mgmt_port"] diff --git a/nesi/keymile/keymile_resources/keymile_box.py b/nesi/keymile/keymile_resources/keymile_box.py index 710f68c..18bccea 100644 --- a/nesi/keymile/keymile_resources/keymile_box.py +++ b/nesi/keymile/keymile_resources/keymile_box.py @@ -7,13 +7,15 @@ # - Janis Groß # - Philip Konrath # - Alexander Dincher +# - Philipp-Noah Groß # # License: https://github.com/inexio/NESi/LICENSE.rst +import os + from nesi.keymile.keymile_resources import * -from nesi.softbox.base_resources import credentials -from nesi.softbox.base_resources import route -from nesi.softbox.base_resources.box import * +from nesi.softbox.base_resources import credentials, base +from nesi.softbox.base_resources.box import BoxCollection, Box, logging LOG = logging.getLogger(__name__) @@ -24,7 +26,226 @@ class KeyMileBox(Box): :param connection: A RestClient instance :param identity: The identity of the System resource """ - # Define Keymile Properties + + currTemperature = base.Field("currTemperature") + ftp_server_ip = base.Field("backup_ip") + ftp_login = base.Field("login") + ftp_password = base.Field("password") + network_element_management_vlan_id = base.Field('network_element_management_vlan_id') + + def set_ftp_data(self, ftp_server_ip, login, password): + self.update(ftp_server_ip=ftp_server_ip) + self.update(ftp_login=login) + self.update(ftp_password=password) + + @property + def channels(self): + """Return `ChannelCollection` object.""" + return keymile_channel.KeyMileChannelCollection( + self._conn, base.get_sub_resource_path_by(self, 'channels')) + + @property + def interfaces(self): + """Return `InterfaceCollection` object.""" + return keymile_interface.KeyMileInterfaceCollection( + self._conn, base.get_sub_resource_path_by(self, 'interfaces')) + + @property + def credentials(self): + """Return `CredentialsCollection` object.""" + return credentials.CredentialsCollection( + self._conn, base.get_sub_resource_path_by( + self, 'credentials')) + + @property + def cards(self): + """Return `cardCollection` object.""" + return keymile_card.KeyMileCardCollection( + self._conn, base.get_sub_resource_path_by( + self, 'cards')) + + @property + def mgmt_cards(self): + """Return `mgmtcardCollection` object.""" + return keymile_mgmt_card.KeyMileMgntCardCollection( + self._conn, base.get_sub_resource_path_by( + self, 'mgmt_cards')) + + @property + def mgmt_ports(self): + """Return `mgmtportCollection` object.""" + return keymile_mgmt_port.KeyMileMgmtPortCollection( + self._conn, base.get_sub_resource_path_by( + self, 'mgmt_ports')) + + @property + def subscribers(self): + """Return `SubscriberCollection` object.""" + return keymile_subscriber.KeyMileSubscriberCollection( + self._conn, base.get_sub_resource_path_by(self, 'subscribers')) + + @property + def portgroupsports(self): + """Return `PortgrouportCollection` object.""" + return keymile_portgroupport.KeyMilePortGroupPortCollection( + self._conn, base.get_sub_resource_path_by(self, 'portgrouports')) + + @property + def logports(self): + """Return `LogPortCollection` object.""" + return keymile_logport.KeyMileLogPortCollection( + self._conn, base.get_sub_resource_path_by(self, 'logports')) + + @property + def srvcs(self): + """Return `SrvcCollection` object.""" + return keymile_srvc.KeyMileSrvcCollection( + self._conn, base.get_sub_resource_path_by(self, 'srvcs')) + + def get_card(self, field, value): + """Get specific card object.""" + return keymile_card.KeyMileCardCollection( + self._conn, base.get_sub_resource_path_by(self, 'cards'), + params={field: value}).find_by_field_value(field, value) + + def get_cards(self, field, value): + """Get all cards.""" + return keymile_card.KeyMileCardCollection( + self._conn, base.get_sub_resource_path_by(self, 'cards'), + params={field: value}) + + def get_mgmt_card(self, field, value): + """Get specific mgnt card object.""" + return keymile_mgmt_card.KeyMileMgntCardCollection( + self._conn, base.get_sub_resource_path_by(self, 'mgmt_cards'), + params={field: value}).find_by_field_value(field, value) + + def get_mgmt_port(self, field, value): + """Get specific mgmtport object.""" + return keymile_mgmt_port.KeyMileMgmtPortCollection( + self._conn, base.get_sub_resource_path_by(self, 'mgmt_ports'), + params={field: value}).find_by_field_value(field, value) + + def get_mgmt_ports(self, field, value): + """Get specific mgmtport object.""" + return keymile_mgmt_port.KeyMileMgmtPortCollection( + self._conn, base.get_sub_resource_path_by(self, 'mgmt_ports'), + params={field: value}) + + def get_port(self, field, value): + """Get specific port object.""" + return keymile_port.KeyMilePortCollection( + self._conn, base.get_sub_resource_path_by(self, 'ports'), + params={field: value}).find_by_field_value(field, value) + + def get_ports(self, field, value): + """Get specific port object.""" + return keymile_port.KeyMilePortCollection( + self._conn, base.get_sub_resource_path_by(self, 'ports'), + params={field: value}) + + def get_logport(self, field, value): + """Get specific logport object.""" + return keymile_logport.KeyMileLogPortCollection( + self._conn, base.get_sub_resource_path_by(self, 'logports'), + params={field: value}).find_by_field_value(field, value) + + def get_logports(self, field, value): + """Get al logport objects with a specific trait.""" + return keymile_logport.KeyMileLogPortCollection( + self._conn, base.get_sub_resource_path_by(self, 'logports'), + params={field: value}) + + def add_logport(self, **fields): + """Add new logport.""" + return keymile_logport.KeyMileLogPort.create( + self._conn, + os.path.join(self.path, 'logports'), + **fields) + + def get_chan(self, field, value): + """Get specific channel object.""" + return keymile_channel.KeyMileChannelCollection( + self._conn, base.get_sub_resource_path_by(self, 'channels'), + params={field: value}).find_by_field_value(field, value) + + def get_chans(self, field, value): + return keymile_channel.KeyMileChannelCollection( + self._conn, base.get_sub_resource_path_by(self, 'channels'), + params={field: value}) + + def get_interface(self, field, value): + """Get specific interface object.""" + return keymile_interface.KeyMileInterfaceCollection( + self._conn, base.get_sub_resource_path_by(self, 'interfaces'), + params={field: value}).find_by_field_value(field, value) + + def get_interfaces(self, field, value): + """Get specific interface object.""" + return keymile_interface.KeyMileInterfaceCollection( + self._conn, base.get_sub_resource_path_by(self, 'interfaces'), + params={field: value}) + + def add_interface(self, **fields): + """Add new interface/vcc.""" + return keymile_interface.KeyMileInterface.create( + self._conn, + os.path.join(self.path, 'interfaces'), + **fields) + + def get_subscriber(self, field, value): + """Get specific subscriber object.""" + return keymile_subscriber.KeyMileSubscriberCollection( + self._conn, base.get_sub_resource_path_by(self, 'subscribers'), + params={field: value}).find_by_field_value(field, value) + + def get_subscribers(self, field, value): + """Get specific subscribers object.""" + return keymile_subscriber.KeyMileSubscriberCollection( + self._conn, base.get_sub_resource_path_by(self, 'subscribers'), + params={field: value}) + + def add_subscriber(self, **fields): + """Add new subscriber.""" + return keymile_subscriber.KeyMileSubscriber.create( + self._conn, + os.path.join(self.path, 'subscribers'), + **fields) + + def get_portgroupport(self, field, value): + """Get specific portgroupport object.""" + return keymile_portgroupport.KeyMilePortGroupPortCollection( + self._conn, base.get_sub_resource_path_by(self, 'portgroupports'), + params={field: value}).find_by_field_value(field, value) + + def get_portgroupports(self, field, value): + """Get specific portgroupports object.""" + return keymile_portgroupport.KeyMilePortGroupPortCollection( + self._conn, base.get_sub_resource_path_by(self, 'portgroupports'), + params={field: value}) + + def get_srvc(self, field, value): + """Get specific srvc object.""" + return keymile_srvc.KeyMileSrvcCollection( + self._conn, base.get_sub_resource_path_by(self, 'srvcs'), + params={field: value}).find_by_field_value(field, value) + + def get_srvcs(self, field, value): + """Get specific srvcs object.""" + return keymile_srvc.KeyMileSrvcCollection( + self._conn, base.get_sub_resource_path_by(self, 'srvcs'), + params={field: value}) + + def add_srvc(self, **fields): + """Add new srvc.""" + return keymile_srvc.KeyMileSrvc.create( + self._conn, + os.path.join(self.path, 'srvcs'), + **fields) + + def set_vlan_id(self, vlan_id): + """Change the network element management vlan.""" + self.update(network_element_management_vlan_id=vlan_id) class KeyMileBoxCollection(BoxCollection): diff --git a/nesi/keymile/keymile_resources/keymile_card.py b/nesi/keymile/keymile_resources/keymile_card.py new file mode 100644 index 0000000..4e65f98 --- /dev/null +++ b/nesi/keymile/keymile_resources/keymile_card.py @@ -0,0 +1,129 @@ +# This file is part of the NESi software. +# +# Copyright (c) 2020 +# Original Software Design by Ilya Etingof . +# +# Software adapted by inexio . +# - Janis Groß +# - Philip Konrath +# - Alexander Dincher +# +# License: https://github.com/inexio/NESi/LICENSE.rst + +from nesi.softbox.base_resources.card import CardCollection, Card, logging +from nesi.softbox.base_resources import base + +LOG = logging.getLogger(__name__) + + +class KeyMileCard(Card): + """Represent physical shelf resource.""" + + board_name = base.Field('board_name') + supplier_build_state = base.Field('supplier_build_state') + board_id = base.Field('board_id') + hardware_key = base.Field('hardware_key') + software = base.Field('software') + software_name = base.Field('software_name') + software_revision = base.Field('software_revision') + state = base.Field('state') + serial_number = base.Field('serial_number') + manufacturer_name = base.Field('manufacturer_name') + model_name = base.Field('model_name') + short_text = base.Field('short_text') + manufacturer_id = base.Field('manufacturer_id') + manufacturer_part_number = base.Field('manufacturer_part_number') + manufacturer_build_state = base.Field('manufacturer_build_state') + customer_id = base.Field('customer_id') + customer_product_id = base.Field('customer_product_id') + boot_loader = base.Field('boot_loader') + processor = base.Field('processor') + label1 = base.Field('label1') + label2 = base.Field('label2') + + gateway_ipaddress = base.Field('gateway_ipaddress') + subnet_mask = base.Field('subnet_mask') + default_gateway = base.Field('default_gateway') + + # Keymile ipsx2/3 card SIP specifications + gateway_name = base.Field('gateway_name') + home_domain = base.Field('home_domain') + sip_port_number = base.Field('sip_port_number') + country_code = base.Field('country_code') + area_code = base.Field('area_code') + retransmission_timer = base.Field('retransmission_timer') + max_retransmission_interval = base.Field('max_retransmission_interval') + sip_extension = base.Field('sip_extension') + asserted_id_mode = base.Field('asserted_id_mode') + overlap_signalling = base.Field('overlap_signalling') + overlap_timer = base.Field('overlap_timer') + uac_request_timer = base.Field('uac_request_timer') + uas_request_timer = base.Field('uas_request_timer') + session_expiration = base.Field('session_expiration') + # Keymile ipsx2/3 card Proxy specification + proxy_mode = base.Field('proxy_mode') + proxy_address = base.Field('proxy_address') + proxy_port = base.Field('proxy_port') + proxy_address_sec = base.Field('proxy_address_sec') + proxy_port_sec = base.Field('proxy_port_sec') + proxy_enable = base.Field('proxy_enable') + proxy_method = base.Field('proxy_method') + proxy_interval = base.Field('proxy_interval') + # Keymile ipsx2/3 card Registrar specification + registrar_adress = base.Field('registrar_adress') + registrar_port = base.Field('registrar_port') + registration_mode = base.Field('registration_mode') + registration_expiration_time = base.Field('registration_expiration_time') + + def set_sip(self, gateway_name, home_domain, sip_port_number, country_code, area_code, retransmission_timer, + max_retransmission_interval, sip_extension, asserted_id_mode, overlap_signalling, overlap_timer, + uac_request_timer, uas_request_timer, session_expiration): + self.update(gateway_name=gateway_name) + self.update(home_domain=home_domain) + self.update(sip_port_number=sip_port_number) + self.update(country_code=country_code) + self.update(area_code=area_code) + self.update(retransmission_timer=retransmission_timer) + self.update(max_retransmission_interval=max_retransmission_interval) + self.update(sip_extension=sip_extension) + self.update(asserted_id_mode=asserted_id_mode) + self.update(overlap_signalling=overlap_signalling) + self.update(overlap_timer=overlap_timer) + self.update(uac_request_timer=uac_request_timer) + self.update(uas_request_timer=uas_request_timer) + self.update(session_expiration=session_expiration) + + def set_ip(self, gateway_ipaddress, subnet_mask, default_gateway): + self.update(gateway_ipaddress=gateway_ipaddress) + self.update(subnet_mask=subnet_mask) + self.update(default_gateway=default_gateway) + + def set_label(self, l1, l2, desc): + self.update(label1=l1) + self.update(label2=l2) + self.update(description=desc) + + def set_proxy(self, proxy_mode, proxy_address, proxy_port, proxy_address_sec, proxy_port_sec, proxy_enable, + proxy_method, proxy_interval): + self.update(proxy_mode=proxy_mode) + self.update(proxy_address=proxy_address) + self.update(proxy_port=proxy_port) + self.update(proxy_address_sec=proxy_address_sec) + self.update(proxy_port_sec=proxy_port_sec) + self.update(proxy_enable=proxy_enable) + self.update(proxy_method=proxy_method) + self.update(proxy_interval=proxy_interval) + + def set_registrar(self, registrar_adress, registrar_port, registration_mode, registration_expiration_time): + self.update(registrar_adress=registrar_adress) + self.update(registrar_port=registrar_port) + self.update(registration_mode=registration_mode) + self.update(registration_expiration_time=registration_expiration_time) + + +class KeyMileCardCollection(CardCollection): + """Represent a collection of cards.""" + + @property + def _resource_type(self): + return KeyMileCard diff --git a/nesi/keymile/keymile_resources/keymile_channel.py b/nesi/keymile/keymile_resources/keymile_channel.py new file mode 100644 index 0000000..62acb04 --- /dev/null +++ b/nesi/keymile/keymile_resources/keymile_channel.py @@ -0,0 +1,44 @@ +# This file is part of the NESi software. +# +# Copyright (c) 2020 +# Original Software Design by Ilya Etingof . +# +# Software adapted by inexio . +# - Janis Groß +# - Philip Konrath +# - Alexander Dincher +# +# License: https://github.com/inexio/NESi/LICENSE.rst + +import logging + +from nesi.softbox.base_resources import base + +LOG = logging.getLogger(__name__) + + +class KeyMileChannel(base.Resource): + """Represent logical channel resource.""" + + id = base.Field('id') + port_id = base.Field('port_id') + name = base.Field('name') + description = base.Field('description') + chan_profile_name = base.Field('chan_profile_name') + curr_rate_u = base.Field('curr_rate_u') + curr_rate_d = base.Field('curr_rate_d') + prev_rate_u = base.Field('prev_rate_u') + prev_rate_d = base.Field('prev_rate_d') + curr_delay_u = base.Field('curr_delay_u') + curr_delay_d = base.Field('curr_delay_d') + + def set_profile_name(self, name): + self.update(chan_profile_name=name) + + +class KeyMileChannelCollection(base.ResourceCollection): + """Represent a collection of channels.""" + + @property + def _resource_type(self): + return KeyMileChannel diff --git a/nesi/keymile/keymile_resources/keymile_interface.py b/nesi/keymile/keymile_resources/keymile_interface.py new file mode 100644 index 0000000..e5c62a3 --- /dev/null +++ b/nesi/keymile/keymile_resources/keymile_interface.py @@ -0,0 +1,39 @@ +# This file is part of the NESi software. +# +# Copyright (c) 2020 +# Original Software Design by Ilya Etingof . +# +# Software adapted by inexio . +# - Janis Groß +# - Philip Konrath +# - Alexander Dincher +# +# License: https://github.com/inexio/NESi/LICENSE.rst + + +from nesi.softbox.base_resources.interface import Interface, InterfaceCollection, logging, base + +LOG = logging.getLogger(__name__) + + +class KeyMileInterface(Interface): + """Represent logical interface resource.""" + + port_id = base.Field('port_id') + chan_id = base.Field('chan_id') + logport_id = base.Field('logport_id') + + # vcc + vcc_profile = base.Field('vcc_profile') + vlan_profile = base.Field('vlan_profile') + number_of_conn_services = base.Field('number_of_conn_services') + reconfiguration_allowed = base.Field('reconfiguration_allowed') + services_connected = base.Field('services_connected') + + +class KeyMileInterfaceCollection(InterfaceCollection): + """Represent a collection of interfaces.""" + + @property + def _resource_type(self): + return KeyMileInterface diff --git a/nesi/keymile/keymile_resources/keymile_logport.py b/nesi/keymile/keymile_resources/keymile_logport.py new file mode 100644 index 0000000..c9d424b --- /dev/null +++ b/nesi/keymile/keymile_resources/keymile_logport.py @@ -0,0 +1,63 @@ +# This file is part of the NESi software. +# +# Copyright (c) 2020 +# Original Software Design by Ilya Etingof . +# +# Software adapted by inexio . +# - Janis Groß +# - Philip Konrath +# - Alexander Dincher +# +# License: https://github.com/inexio/NESi/LICENSE.rst + +from nesi.softbox.base_resources.service_port import logging +from nesi.softbox.base_resources import base + +LOG = logging.getLogger(__name__) + + +class KeyMileLogPort(base.Resource): + """Represent logical log_port resource.""" + + id = base.Field('id') + name = base.Field('name') + card_id = base.Field('card_id') + ports = base.Field('ports') + label1 = base.Field('label1') + label2 = base.Field('label2') + description = base.Field('description') + admin_state = base.Field('admin_state') + operational_state = base.Field('operational_state') + profile = base.Field('profile') + + def admin_up(self): + """Set the admin port state to up""" + self.update(admin_state='1') + + def admin_down(self): + """Set the admin port state to down""" + self.update(admin_state='0') + + def down(self): + """Set the port state to down""" + self.update(operational_state='0') + + def up(self): + """Set the port state to down""" + self.update(operational_state='1') + + def set_profile(self, profile): + self.update(profile=profile) + + def set_label(self, l1, l2, desc): + self.update(label1=l1) + self.update(label2=l2) + self.update(description=desc) + + +class KeyMileLogPortCollection(base.ResourceCollection): + """Represent a collection of logical log_ports.""" + + @property + def _resource_type(self): + return KeyMileLogPort diff --git a/nesi/keymile/keymile_resources/keymile_mgmt_card.py b/nesi/keymile/keymile_resources/keymile_mgmt_card.py new file mode 100644 index 0000000..acfa59f --- /dev/null +++ b/nesi/keymile/keymile_resources/keymile_mgmt_card.py @@ -0,0 +1,56 @@ +# This file is part of the NESi software. +# +# Copyright (c) 2020 +# Original Software Design by Ilya Etingof . +# +# Software adapted by inexio . +# - Janis Groß +# - Philip Konrath +# - Alexander Dincher +# +# License: https://github.com/inexio/NESi/LICENSE.rst + +from nesi.softbox.base_resources.mgmt_card import MgmtCard, MgmtCardCollection, logging +from nesi.softbox.base_resources import base + +LOG = logging.getLogger(__name__) + + +class KeyMileMgmtCard(MgmtCard): + """Represent physical shelf resource.""" + + board_name = base.Field('board_name') + supplier_build_state = base.Field('supplier_build_state') + board_id = base.Field('board_id') + hardware_key = base.Field('hardware_key') + software = base.Field('software') + software_name = base.Field('software_name') + software_revision = base.Field('software_revision') + state = base.Field('state') + serial_number = base.Field('serial_number') + manufacturer_name = base.Field('manufacturer_name') + model_name = base.Field('model_name') + short_text = base.Field('short_text') + manufacturer_id = base.Field('manufacturer_id') + manufacturer_part_number = base.Field('manufacturer_part_number') + manufacturer_build_state = base.Field('manufacturer_build_state') + customer_id = base.Field('customer_id') + customer_product_id = base.Field('customer_product_id') + boot_loader = base.Field('boot_loader') + processor = base.Field('processor') + label1 = base.Field('label1') + label2 = base.Field('label2') + product = base.Field('product') + + def set_label(self, l1, l2, desc): + self.update(label1=l1) + self.update(label2=l2) + self.update(description=desc) + + +class KeyMileMgntCardCollection(MgmtCardCollection): + """Represent a collection of cards.""" + + @property + def _resource_type(self): + return KeyMileMgmtCard diff --git a/nesi/keymile/keymile_resources/keymile_mgmt_port.py b/nesi/keymile/keymile_resources/keymile_mgmt_port.py new file mode 100644 index 0000000..fa92b38 --- /dev/null +++ b/nesi/keymile/keymile_resources/keymile_mgmt_port.py @@ -0,0 +1,34 @@ +# This file is part of the NESi software. +# +# Copyright (c) 2020 +# Original Software Design by Ilya Etingof . +# +# Software adapted by inexio . +# - Janis Groß +# - Philip Konrath +# - Alexander Dincher +# +# License: https://github.com/inexio/NESi/LICENSE.rst + +from nesi.softbox.base_resources.mgmt_port import MgmtPortCollection, MgmtPort, logging, base + +LOG = logging.getLogger(__name__) + + +class KeyMileMgmtPort(MgmtPort): + """Represent physical port resource.""" + label1 = base.Field('label1') + label2 = base.Field('label2') + + def set_label(self, l1, l2, desc): + self.update(label1=l1) + self.update(label2=l2) + self.update(description=desc) + + +class KeyMileMgmtPortCollection(MgmtPortCollection): + """Represent a collection of ports.""" + + @property + def _resource_type(self): + return KeyMileMgmtPort diff --git a/nesi/keymile/keymile_resources/keymile_port.py b/nesi/keymile/keymile_resources/keymile_port.py new file mode 100644 index 0000000..c976869 --- /dev/null +++ b/nesi/keymile/keymile_resources/keymile_port.py @@ -0,0 +1,94 @@ +# This file is part of the NESi software. +# +# Copyright (c) 2020 +# Original Software Design by Ilya Etingof . +# +# Software adapted by inexio . +# - Janis Groß +# - Philip Konrath +# - Alexander Dincher +# +# License: https://github.com/inexio/NESi/LICENSE.rst + +from nesi.softbox.base_resources.port import PortCollection, Port, logging, base + +LOG = logging.getLogger(__name__) + + +class KeyMilePort(Port): + """Represent physical port resource.""" + label1 = base.Field('label1') + label2 = base.Field('label2') + loopbacktest_state = base.Field('loopbacktest_state') + melttest_state = base.Field('melttest_state') + linetest_state = base.Field('linetest_state') + mode = base.Field('mode') + flow_control = base.Field('flow_control') + profile1_enable = base.Field('profile1_enable') + profile1_name = base.Field('profile1_name') + profile1_elength = base.Field('profile1_elength') + profile2_enable = base.Field('profile2_enable') + profile2_name = base.Field('profile2_name') + profile2_elength = base.Field('profile2_elength') + profile3_enable = base.Field('profile3_enable') + profile3_name = base.Field('profile3_name') + profile3_elength = base.Field('profile3_elength') + profile4_enable = base.Field('profile4_enable') + profile4_name = base.Field('profile4_name') + profile_mode = base.Field('profile_mode') + upstream = base.Field('upstream') + downstream = base.Field('downstream') + + def set_profile(self, name): + self.update(profile1_name=name) + + + def set_profiles(self, e1, n1, el1, e2, n2, el2, e3, n3, el3, e4, n4, mode): + self.update(profile1_enable=e1) + self.update(profile1_name=n1) + self.update(profile1_elength=el1) + self.update(profile2_enable=e2) + self.update(profile2_name=n2) + self.update(profile2_elength=el2) + self.update(profile3_enable=e3) + self.update(profile3_name=n3) + self.update(profile3_elength=el3) + self.update(profile4_enable=e4) + self.update(profile4_name=n4) + self.update(profile_mode=mode) + + def set_label(self, l1, l2, desc): + self.update(label1=l1) + self.update(label2=l2) + self.update(description=desc) + + def set_test_state(self, state): + self.update(loopbacktest_state=state) + + def lock_admin(self): + """Set the admin port state to up""" + self.update(admin_state='2') + + def unlock_admin(self): + """Set the admin port state to down""" + self.update(admin_state='3') + + def set_melttest_state(self, state): + self.update(melttest_state=state) + + def set_linetest_state(self, state): + self.update(linetest_state=state) + + def set_mode(self, mode): + self.update(mode=mode) + + def set_flow_control(self, ctrl): + self.update(flow_control=ctrl) + + +class KeyMilePortCollection(PortCollection): + """Represent a collection of ports.""" + + @property + def _resource_type(self): + return KeyMilePort diff --git a/nesi/keymile/keymile_resources/keymile_portgroupport.py b/nesi/keymile/keymile_resources/keymile_portgroupport.py new file mode 100644 index 0000000..7cbf510 --- /dev/null +++ b/nesi/keymile/keymile_resources/keymile_portgroupport.py @@ -0,0 +1,92 @@ +# This file is part of the NESi software. +# +# Copyright (c) 2020 +# Original Software Design by Ilya Etingof . +# +# Software adapted by inexio . +# - Janis Groß +# - Philip Konrath +# - Alexander Dincher +# +# License: https://github.com/inexio/NESi/LICENSE.rst + +from nesi.softbox.base_resources.service_port import logging +from nesi.softbox.base_resources import base + +LOG = logging.getLogger(__name__) + + +class KeyMilePortGroupPort(base.Resource): + """Represent logical subscriber resource.""" + + # fields + id = base.Field('id') + name = base.Field('name') + operational_state = base.Field('operational_state') + admin_state = base.Field('admin_state') + description = base.Field('description') + label1 = base.Field('label1') + label2 = base.Field('label2') + type = base.Field('type') + enable = base.Field('enable') + register_as_global = base.Field('register_as_global') + register_default_number_only = base.Field('register_default_number_only') + layer_1_permanently_activated = base.Field('layer_1_permanently_activated') + sip_profile = base.Field('sip_profile') + proxy_registrar_profile = base.Field('proxy_registrar_profile') + codec_sdp_profile = base.Field('codec_sdp_profile') + isdnba_profile = base.Field('isdnba_profile') + pay_phone = base.Field('pay_phone') + pstn_profile = base.Field('pstn_profile') + enterprise_profile = base.Field('enterprise_profile') + + def set_label(self, l1, l2, desc): + self.update(label1=l1) + self.update(label2=l2) + self.update(description=desc) + + def admin_up(self): + """Set the admin port state to up""" + self.update(admin_state='1') + + def admin_down(self): + """Set the admin port state to down""" + self.update(admin_state='0') + + def down(self): + """Set the port state to down""" + self.update(operational_state='0') + + def up(self): + """Set the port state to down""" + self.update(operational_state='1') + + def set_pstnport(self, enable, registerglobal, phone, sip, proxy, codec, pstn, enterprise): + """Set the pstnport""" + self.update(enable=enable) + self.update(register_as_global=registerglobal) + self.update(pay_phone=phone) + self.update(sip_profile=sip) + self.update(proxy_registrar_profile=proxy) + self.update(codec_sdp_profile=codec) + self.update(pstn_profile=pstn) + self.update(enterprise_profile=enterprise) + + def set_isdnport(self, enable, registerglobal, regdefault, layer1, sip, proxy, codec, isdn): + """Set the isdnport""" + self.update(enable=enable) + self.update(register_as_global=registerglobal) + self.update(register_default_number_only=regdefault) + self.update(sip_profile=sip) + self.update(proxy_registrar_profile=proxy) + self.update(codec_sdp_profile=codec) + self.update(layer_1_permanently_activated=layer1) + self.update(isdnba_profile=isdn) + + +class KeyMilePortGroupPortCollection(base.ResourceCollection): + """Represent a collection of logical subscribers.""" + + @property + def _resource_type(self): + return KeyMilePortGroupPort diff --git a/nesi/keymile/keymile_resources/keymile_srvc.py b/nesi/keymile/keymile_resources/keymile_srvc.py new file mode 100644 index 0000000..d1b7a16 --- /dev/null +++ b/nesi/keymile/keymile_resources/keymile_srvc.py @@ -0,0 +1,43 @@ +# This file is part of the NESi software. +# +# Copyright (c) 2020 +# Original Software Design by Ilya Etingof . +# +# Software adapted by inexio . +# - Janis Groß +# - Philip Konrath +# - Alexander Dincher +# - Philipp-Noah Groß +# +# License: https://github.com/inexio/NESi/LICENSE.rst + +from nesi.softbox.base_resources.service_port import logging +from nesi.softbox.base_resources import base + +LOG = logging.getLogger(__name__) + + +class KeyMileSrvc(base.Resource): + """Represent logical srvc resource.""" + + id = base.Field('id') + name = base.Field('name') + service_type = base.Field('service_type') + address = base.Field('address') + svid = base.Field('svid') + stag_priority = base.Field('stag_priority') + vlan_handling = base.Field('vlan_handling') + + def set_service(self, address, svid, stag_prio, vlan): + self.update(address=address) + self.update(svid=svid) + self.update(stag_priority=stag_prio) + self.update(vlan_handling=vlan) + + +class KeyMileSrvcCollection(base.ResourceCollection): + """Represent a collection of logical srvcs.""" + + @property + def _resource_type(self): + return KeyMileSrvc diff --git a/nesi/keymile/keymile_resources/keymile_subrack.py b/nesi/keymile/keymile_resources/keymile_subrack.py new file mode 100644 index 0000000..b228dc6 --- /dev/null +++ b/nesi/keymile/keymile_resources/keymile_subrack.py @@ -0,0 +1,27 @@ +# This file is part of the NESi software. +# +# Copyright (c) 2020 +# Original Software Design by Ilya Etingof . +# +# Software adapted by inexio . +# - Janis Groß +# - Philip Konrath +# - Alexander Dincher +# +# License: https://github.com/inexio/NESi/LICENSE.rst + +from nesi.softbox.base_resources.subrack import Subrack, SubrackCollection, logging, base + +LOG = logging.getLogger(__name__) + + +class KeyMileSubrack(Subrack): + """Represent physical shelf resource.""" + + +class KeyMileSubrackCollection(SubrackCollection): + """Represent a collection of subracks.""" + + @property + def _resource_type(self): + return KeyMileSubrack \ No newline at end of file diff --git a/nesi/keymile/keymile_resources/keymile_subscriber.py b/nesi/keymile/keymile_resources/keymile_subscriber.py new file mode 100644 index 0000000..82c7231 --- /dev/null +++ b/nesi/keymile/keymile_resources/keymile_subscriber.py @@ -0,0 +1,45 @@ +# This file is part of the NESi software. +# +# Copyright (c) 2020 +# Original Software Design by Ilya Etingof . +# +# Software adapted by inexio . +# - Janis Groß +# - Philip Konrath +# - Alexander Dincher +# +# License: https://github.com/inexio/NESi/LICENSE.rst + +from nesi.softbox.base_resources.service_port import logging +from nesi.softbox.base_resources import base + +LOG = logging.getLogger(__name__) + + +class KeyMileSubscriber(base.Resource): + """Represent logical subscriber resource.""" + + # fields + id = base.Field('id') + number = base.Field('number') + name = base.Field('name') + type = base.Field('type') + address = base.Field('address') + registration_state = base.Field('registration_state') + autorisation_user_name = base.Field('autorisation_user_name') + autorisation_password = base.Field('autorisation_password') + display_name = base.Field('display_name') + privacy = base.Field('privacy') + portgroupport_id = base.Field('portgroupport_id') + + def set(self, field, value): + mapping = {field: value} + self.update(**mapping) + + +class KeyMileSubscriberCollection(base.ResourceCollection): + """Represent a collection of logical subscribers.""" + + @property + def _resource_type(self): + return KeyMileSubscriber diff --git a/nesi/softbox/api/models/box_models.py b/nesi/softbox/api/models/box_models.py index dcb31d3..223b94e 100644 --- a/nesi/softbox/api/models/box_models.py +++ b/nesi/softbox/api/models/box_models.py @@ -7,6 +7,7 @@ # - Janis Groß # - Philip Konrath # - Alexander Dincher +# - Philipp-Noah Groß # # License: https://github.com/inexio/NESi/LICENSE.rst import uuid @@ -27,6 +28,16 @@ from .route_models import Route from .emu_models import Emu from .user_models import User +from .channel_models import Channel +from .subscriber_models import Subscriber +from .portgroupport_models import PortGroupPort +from .logport_models import LogPort +from .interface_models import Interface +from .srvc_models import Srvc +from .service_vlan_models import ServiceVlan +from .service_port_models import ServicePort +from .mgmt_card_models import MgmtCard +from .mgmt_port_models import MgmtPort class Box(db.Model): @@ -44,6 +55,8 @@ class Box(db.Model): description = db.Column(db.String()) hostname = db.Column(db.String(64)) mgmt_address = db.Column(db.String(32)) + default_gateway = db.Column(db.String(32), default='0.0.0.0') + net_mask = db.Column(db.String(32), default='255.255.255.0') contact_person = db.Column(db.String(), default=None, nullable=True) isam_id = db.Column(db.String(), default=None, nullable=True) isam_location = db.Column(db.String(), default=None, nullable=True) @@ -52,10 +65,15 @@ class Box(db.Model): credentials = db.relationship('Credential', backref='Box', lazy='dynamic') credential_details = db.relationship('Credential', backref='credentials', lazy='dynamic') users = db.relationship('User', backref='Box', lazy='dynamic') + user_details = db.relationship('User', backref='users', lazy='dynamic') subracks = db.relationship('Subrack', backref='Box', lazy='dynamic') subrack_details = db.relationship('Subrack', backref='subracks', lazy='dynamic') cards = db.relationship('Card', backref='Box', lazy='dynamic') + mgmt_cards = db.relationship('MgmtCard', backref='Box', lazy='dynamic') ports = db.relationship('Port', backref='Box', lazy='dynamic') + mgmt_ports = db.relationship('MgmtPort', backref='Box', lazy='dynamic') + channels = db.relationship('Channel', backref='Box', lazy='dynamic') + interfaces = db.relationship('Interface', backref='Box', lazy='dynamic') cpes = db.relationship('Cpe', backref='Box', lazy='dynamic') cpe_ports = db.relationship('CpePort', backref='Box', lazy='dynamic') onts = db.relationship('Ont', backref='Box', lazy='dynamic') @@ -67,6 +85,12 @@ class Box(db.Model): vlan_interfaces = db.relationship('VlanInterface', backref='Box', lazy='dynamic') routes = db.relationship('Route', backref='Box', lazy='dynamic') emus = db.relationship('Emu', backref='Box', lazy='dynamic') + subscribers = db.relationship('Subscriber', backref='Box', lazy='dynamic') + portgroupports = db.relationship('PortGroupPort', backref='Box', lazy='dynamic') + logports = db.relationship('LogPort', backref='Box', lazy='dynamic') + srvcs = db.relationship('Srvc', backref='Box', lazy='dynamic') + service_vlans = db.relationship('ServiceVlan', backref='Box', lazy='dynamic') + service_ports = db.relationship('ServicePort', backref='Box', lazy='dynamic') board_missing_reporting_logging = db.Column(db.Boolean(), default=False) board_instl_missing_reporting_logging = db.Column(db.Boolean(), default=False) board_init_reporting_logging = db.Column(db.Boolean(), default=False) @@ -109,3 +133,22 @@ class Box(db.Model): pitp_mode = db.Column(db.String(), default='') dsl_mode = db.Column(db.Enum('tr165', 'tr129'), default='tr165') + currTemperature = db.Column(db.Integer(), default=15) + ftp_server_ip = db.Column(db.String(), default='') + ftp_login = db.Column(db.String(), default='') + ftp_password = db.Column(db.String(), default='') + network_element_management_vlan_id = db.Column(db.Integer(), default=None) + + #EdgeCore + management_start_address = db.Column(db.String(), default='') + management_end_address = db.Column(db.String(), default='') + logging_host = db.Column(db.String(), default='') + logging_port = db.Column(db.String(), default='') + logging_level = db.Column(db.Integer(), default=7) + loopback_detection_action = db.Column(db.String(), default='shutdown') + sntp_server_ip = db.Column(db.String(), default='None') + sntp_client = db.Column(db.Enum('Disabled', 'Enabled'), default='Disabled') + timezone_name = db.Column(db.String(), default='None') + timezone_time = db.Column(db.String(), default='None') + summer_time_name = db.Column(db.String(), default='') + summer_time_region = db.Column(db.String(), default='') diff --git a/nesi/softbox/api/models/card_models.py b/nesi/softbox/api/models/card_models.py index c132fb4..4d26ffb 100644 --- a/nesi/softbox/api/models/card_models.py +++ b/nesi/softbox/api/models/card_models.py @@ -7,6 +7,7 @@ # - Janis Groß # - Philip Konrath # - Alexander Dincher +# - Philipp-Noah Groß # # License: https://github.com/inexio/NESi/LICENSE.rst import uuid @@ -22,11 +23,11 @@ class Card(db.Model): subrack_id = db.Column(db.Integer, db.ForeignKey('subrack.id')) ports = db.relationship('Port', backref='Card', lazy='dynamic') ppc = db.Column(db.Enum('8', '16', '32', '48', '64'), default='32') - product = db.Column(db.Enum('xdsl', 'vdsl', 'adsl', 'sdsl', 'ftth-pon', 'ftth', 'mgnt'), + product = db.Column(db.Enum('xdsl', 'vdsl', 'adsl', 'sdsl', 'ftth-pon', 'ftth', 'mgnt', 'analog', 'isdn'), nullable=False, default='vdsl') # Alcatel specific data - description = db.Column(db.String(), default='None') + description = db.Column(db.String(), default='""') position = db.Column(db.String()) entry_vlan_number = db.Column(db.Integer()) planned_type = db.Column(db.Enum('rdlt-c', 'rant-a', 'nant-a', 'nrnt-a', 'fant-f', 'relt-a', 'nelt-b', 'fglt-b', @@ -79,3 +80,70 @@ class Card(db.Model): power_off_cause = db.Column(db.String(), default='-') power_off_time = db.Column(db.String(), default='-') temperature = db.Column(db.String(), default='68C') + + # Keymile specific data + supplier_build_state = db.Column(db.Enum('R1G', 'R1D', 'R2B', 'R2A', 'R1K', 'R1H', 'R2B', 'R1E', 'R3D', 'R1C', + 'R1A', ''), default='') + board_id = db.Column(db.Enum('345', '332', '303', '308', '377', '356', '305', '307', '330', '0'), default='0') + hardware_key = db.Column(db.Integer(), default=0) + software = db.Column(db.String(), default='') + software_name = db.Column(db.String(), default='') + software_revision = db.Column(db.String(), default='') + state = db.Column(db.Enum('Ok', 'Empty'), default='Empty') + serial_number = db.Column(db.String(), default='') + manufacturer_name = db.Column(db.String(), default='') + model_name = db.Column(db.String(), default='') + short_text = db.Column(db.String(), default='') + manufacturer_id = db.Column(db.String(), default='') + manufacturer_part_number = db.Column(db.String(), default='') + manufacturer_build_state = db.Column(db.String(), default='') + customer_id = db.Column(db.String(), default='') + customer_product_id = db.Column(db.String(), default='') + boot_loader = db.Column(db.String(), default='') + processor = db.Column(db.String(), default='') + label1 = db.Column(db.String(), default='""') + label2 = db.Column(db.String(), default='""') + gateway_ipaddress = db.Column(db.String(), default='""') + subnet_mask = db.Column(db.String(), default='""') + default_gateway = db.Column(db.String(), default='""') + + # Keymile ipsx2/3 card SIP specifications + gateway_name = db.Column(db.String(), default='""') + home_domain = db.Column(db.String(), default='""') + sip_port_number = db.Column(db.Integer(), default=0) + country_code = db.Column(db.String(), default='') + area_code = db.Column(db.String(), default='') + retransmission_timer = db.Column(db.Integer(), default=0) + max_retransmission_interval = db.Column(db.Integer(), default=0) + sip_extension = db.Column(db.Boolean, default=False) + asserted_id_mode = db.Column(db.Enum('Asserted', 'Preferred'), default=None) + overlap_signalling = db.Column(db.Boolean, default=False) + overlap_timer = db.Column(db.Integer(), default=0) + uac_request_timer = db.Column(db.Boolean, default=False) + uas_request_timer = db.Column(db.Boolean, default=False) + session_expiration = db.Column(db.Integer(), default=0) + # Keymile ipsx2/3 card Proxy specification + proxy_mode = db.Column(db.Enum('PrimaryOnly', 'Revertive', 'NonRevertive', 'DnsRfc3263'), default='PrimaryOnly') + proxy_address = db.Column(db.String(), default='""') + proxy_port = db.Column(db.Integer(), default=5060) + proxy_address_sec = db.Column(db.String(), default='""') + proxy_port_sec = db.Column(db.Integer(), default=0) + proxy_enable = db.Column(db.Boolean, default=True) + proxy_method = db.Column(db.Enum('Options', 'Register'), default='Options') + proxy_interval = db.Column(db.Integer(), default=10) + # Keymile ipsx2/3 card Registrar specification + registrar_adress = db.Column(db.String(), default='') + registrar_port = db.Column(db.Integer(), default=5060) + registration_mode = db.Column(db.Enum('NoRegistration', 'OneByOneRegistration'), default='OneByOneRegistration') + registration_expiration_time = db.Column(db.Integer(), default=100) + + + # Keymile ipsx2/3 card digimap specification + #digimap_uri_schema = db.Column(db.Enum('sip', 'tel'), default='sip') + #digit_map = db.Column(db.String(), default='') + #digimap_domain_phone_context = db.Column(db.String(), default='') + #digimap_prestrip = db.Column(db.Integer(), default=0) + #digimap_prepend = db.Column(db.String(), default='') + + #Edgecore + mac_address = db.Column(db.String(), default='A8-2B-B5-7F-E3-C0') diff --git a/nesi/softbox/api/models/channel_models.py b/nesi/softbox/api/models/channel_models.py new file mode 100644 index 0000000..bbbed86 --- /dev/null +++ b/nesi/softbox/api/models/channel_models.py @@ -0,0 +1,30 @@ +# This file is part of the NESi software. +# +# Copyright (c) 2020 +# Original Software Design by Ilya Etingof . +# +# Software adapted by inexio . +# - Janis Groß +# - Philip Konrath +# - Alexander Dincher +# +# License: https://github.com/inexio/NESi/LICENSE.rst + +from nesi.softbox.api import db +from ..models.interface_models import Interface + + +class Channel(db.Model): + id = db.Column(db.Integer(), primary_key=True) + name = db.Column(db.String(64)) + description = db.Column(db.String()) + chan_profile_name = db.Column(db.String(), default='') + curr_rate_u = db.Column(db.String(), default=0) + curr_rate_d = db.Column(db.String(), default=0) + prev_rate_u = db.Column(db.String(), default=0) + prev_rate_d = db.Column(db.String(), default=0) + curr_delay_u = db.Column(db.String(), default=0) + curr_delay_d = db.Column(db.String(), default=0) + box_id = db.Column(db.Integer, db.ForeignKey('box.id')) + port_id = db.Column(db.Integer, db.ForeignKey('port.id')) + interfaces = db.relationship('Interface', backref='Channel', lazy='dynamic') diff --git a/nesi/softbox/api/models/credential_models.py b/nesi/softbox/api/models/credential_models.py index 7271d64..242d925 100644 --- a/nesi/softbox/api/models/credential_models.py +++ b/nesi/softbox/api/models/credential_models.py @@ -17,6 +17,7 @@ class Credential(db.Model): id = db.Column(db.Integer(), primary_key=True) protocol = db.Column( db.Enum('password'), nullable=False, default='password') + user_id = db.Column(db.Integer, db.ForeignKey('user.id')) username = db.Column(db.String(64), nullable=True) password = db.Column(db.String(32), nullable=True) box_id = db.Column(db.Integer, db.ForeignKey('box.id')) diff --git a/nesi/softbox/api/models/interface_models.py b/nesi/softbox/api/models/interface_models.py new file mode 100644 index 0000000..e73d2f7 --- /dev/null +++ b/nesi/softbox/api/models/interface_models.py @@ -0,0 +1,41 @@ +# This file is part of the NESi software. +# +# Copyright (c) 2020 +# Original Software Design by Ilya Etingof . +# +# Software adapted by inexio . +# - Janis Groß +# - Philip Konrath +# - Alexander Dincher +# +# License: https://github.com/inexio/NESi/LICENSE.rst + +from nesi.softbox.api import db + + +class Interface(db.Model): + id = db.Column(db.Integer(), primary_key=True) + name = db.Column(db.String(64)) + description = db.Column(db.String()) + box_id = db.Column(db.Integer, db.ForeignKey('box.id')) + + # KeyMile + chan_id = db.Column(db.Integer, db.ForeignKey('channel.id')) + port_id = db.Column(db.Integer, db.ForeignKey('port.id')) + logport_id = db.Column(db.Integer, db.ForeignKey('log_port.id')) + # vcc + vcc_profile = db.Column(db.String(), default='') # default or profile_name, default:= vpi=0 and vci=33 + vlan_profile = db.Column(db.String(), default='') # default or profile_name, must be untagged + number_of_conn_services = db.Column(db.Integer(), default=0) + reconfiguration_allowed = db.Column(db.Enum('true', 'false'), default='true') + services_connected = db.Column(db.String(), default='') + + #EdgeCore + ingress_state = db.Column(db.Enum('Disabled', 'Enabled'), default='Disabled') + ingress_rate = db.Column(db.Integer(), default=1000000) + egress_state = db.Column(db.Enum('Disabled', 'Enabled'), default='Disabled') + egress_rate = db.Column(db.Integer(), default=1000000) + vlan_membership_mode = db.Column(db.Enum('Hybrid', 'Access', 'Trunk'), default='Hybrid') + native_vlan = db.Column(db.Integer(), default=1) + allowed_vlan = db.Column(db.String(), default='1(u)') + mac_address = db.Column(db.String(), default='A8-2B-B5-7F-E3-C0') diff --git a/nesi/softbox/api/models/logport_models.py b/nesi/softbox/api/models/logport_models.py new file mode 100644 index 0000000..7b9b6f8 --- /dev/null +++ b/nesi/softbox/api/models/logport_models.py @@ -0,0 +1,29 @@ +# This file is part of the NESi software. +# +# Copyright (c) 2020 +# Original Software Design by Ilya Etingof . +# +# Software adapted by inexio . +# - Janis Groß +# - Philip Konrath +# - Alexander Dincher +# +# License: https://github.com/inexio/NESi/LICENSE.rst + +from ..models.interface_models import Interface +from nesi.softbox.api import db + + +class LogPort(db.Model): + id = db.Column(db.Integer(), primary_key=True) + name = db.Column(db.String(64)) + ports = db.Column(db.String(), default='') + box_id = db.Column(db.Integer, db.ForeignKey('box.id')) + card_id = db.Column(db.Integer, db.ForeignKey('card.id')) + interfaces = db.relationship('Interface', backref='LogPort', lazy='dynamic') + label1 = db.Column(db.String(), default='""') + label2 = db.Column(db.String(), default='""') + description = db.Column(db.String(), default='""') + operational_state = db.Column(db.Enum('0', '1'), default='0') + admin_state = db.Column(db.Enum('0', '1'), default='0') + profile = db.Column(db.String(), default='default') diff --git a/nesi/softbox/api/models/mgmt_card_models.py b/nesi/softbox/api/models/mgmt_card_models.py new file mode 100644 index 0000000..2c24945 --- /dev/null +++ b/nesi/softbox/api/models/mgmt_card_models.py @@ -0,0 +1,49 @@ +# This file is part of the NESi software. +# +# Copyright (c) 2020 +# Original Software Design by Ilya Etingof . +# +# Software adapted by inexio . +# - Janis Groß +# - Philip Konrath +# - Alexander Dincher +# - Philipp-Noah Groß +# +# License: https://github.com/inexio/NESi/LICENSE.rst +import uuid + +from nesi.softbox.api import db +from .mgmt_port_models import MgmtPort + + +class MgmtCard(db.Model): + id = db.Column(db.Integer(), primary_key=True) + name = db.Column(db.String(64)) + box_id = db.Column(db.Integer, db.ForeignKey('box.id')) + subrack_id = db.Column(db.Integer, db.ForeignKey('subrack.id')) + mgmt_ports = db.relationship('MgmtPort', backref='MgmtCard', lazy='dynamic') + + description = db.Column(db.String(), default='') + admin_state = db.Column(db.Enum('0', '1'), default='0') + operational_state = db.Column(db.Enum('0', '1'), default='0') + board_name = db.Column(db.String(), default='') + supplier_build_state = db.Column(db.Enum('R1G', 'R1D', 'R2B', 'R2A', 'R1K', 'R1H', 'R2B', 'R1E', 'R3D', 'R1C', + 'R1A', ''), default='') + board_id = db.Column(db.Enum('345', '332', '303', '308', '377', '356', '305', '307', '330', '0'), default='0') + hardware_key = db.Column(db.Integer(), default=0) + software = db.Column(db.String(), default='') + software_name = db.Column(db.String(), default='') + software_revision = db.Column(db.String(), default='') + state = db.Column(db.Enum('Ok', 'Empty'), default='Empty') + serial_number = db.Column(db.String(), default='') + manufacturer_name = db.Column(db.String(), default='') + model_name = db.Column(db.String(), default='') + short_text = db.Column(db.String(), default='') + manufacturer_id = db.Column(db.String(), default='') + manufacturer_part_number = db.Column(db.String(), default='') + manufacturer_build_state = db.Column(db.String(), default='') + customer_id = db.Column(db.String(), default='') + customer_product_id = db.Column(db.String(), default='') + boot_loader = db.Column(db.String(), default='') + processor = db.Column(db.String(), default='') + product = db.Column(db.Enum('mgmt'), nullable=False, default='mgmt') diff --git a/nesi/softbox/api/models/mgmt_port_models.py b/nesi/softbox/api/models/mgmt_port_models.py new file mode 100644 index 0000000..85ca3ca --- /dev/null +++ b/nesi/softbox/api/models/mgmt_port_models.py @@ -0,0 +1,24 @@ +# This file is part of the NESi software. +# +# Copyright (c) 2020 +# Original Software Design by Ilya Etingof . +# +# Software adapted by inexio . +# - Janis Groß +# - Philip Konrath +# - Alexander Dincher +# - Philipp-Noah Groß +# +# License: https://github.com/inexio/NESi/LICENSE.rst +from nesi.softbox.api import db + + +class MgmtPort(db.Model): + id = db.Column(db.Integer(), primary_key=True) + name = db.Column(db.String(64)) + box_id = db.Column(db.Integer, db.ForeignKey('box.id')) + mgmt_card_id = db.Column(db.Integer, db.ForeignKey('mgmt_card.id')) + + admin_state = db.Column(db.Enum('0', '1'), default='0') + operational_state = db.Column(db.Enum('0', '1'), default='0') + description = db.Column(db.String(64)) diff --git a/nesi/softbox/api/models/port_models.py b/nesi/softbox/api/models/port_models.py index f6d5ab1..3136913 100644 --- a/nesi/softbox/api/models/port_models.py +++ b/nesi/softbox/api/models/port_models.py @@ -14,6 +14,8 @@ from nesi.softbox.api import db from .ont_models import Ont from .cpe_models import Cpe +from .channel_models import Channel +from .interface_models import Interface class Port(db.Model): @@ -25,12 +27,12 @@ class Port(db.Model): cpes = db.relationship('Cpe', backref='Port', lazy='dynamic') # Alcatel data - description = db.Column(db.String()) + description = db.Column(db.String(), default='') type = db.Column(db.Enum('pon', 'ethernet-line'), default='pon') shutdown = db.Column(db.Boolean(), default=False) speed = db.Column(db.Enum('10M', '1G', '10G'), default='1G') operational_state = db.Column(db.Enum('0', '1', '2'), default='0') # Alcatel: 0 => down, 1 => up, 2 => not-appl; Huawei: 0 => deactivated, 1 => activated, 2 => activating - admin_state = db.Column(db.Enum('0', '1', '2'), default='0') # Alcatel: 0 => down, 1 => up, 2 => not-appl; Huawei: 0 => deactivated, 1 => activated, 2 => activating + admin_state = db.Column(db.Enum('0', '1', '2', '3'), default='0') # Alcatel: 0 => down, 1 => up, 2 => not-appl; Huawei: 0 => deactivated, 1 => activated, 2 => activating; KeyMile: 0 => down, 1 => up, 2 => locked, 3 => unlocked upstream = db.Column(db.Integer(), default=0) downstream = db.Column(db.Integer(), default=0) upstream_max = db.Column(db.String(), default="100000") @@ -305,3 +307,30 @@ class Port(db.Model): vectoring_group = db.Column(db.Integer(), default=None) vectoring_profile_id = db.Column(db.Integer(), default=None) template_name = db.Column(db.String(), default=None) + + # KeyMile + channels = db.relationship('Channel', backref='Port', lazy='dynamic') + interfaces = db.relationship('Interface', backref='Port', lazy='dynamic') + label1 = db.Column(db.String(), default='""') + label2 = db.Column(db.String(), default='""') + loopbacktest_state = db.Column(db.Enum('Failed', 'Passed', 'Running', 'NoTestResult', 'Stopped', 'Interrupted'), default='NoTestResult') + melttest_state = db.Column(db.Enum('Failed', 'Passed', 'Running', 'NotTested'), default='NotTested') + linetest_state = db.Column(db.Enum('Failed', 'Passed', 'Running', 'NotTested'), default='NotTested') + mode = db.Column(db.String(), default='') + flow_control = db.Column(db.String(), default='') + # profiles + profile1_enable = db.Column(db.Boolean(), default=False) + profile1_name = db.Column(db.String(), default='') + profile1_elength = db.Column(db.Integer, default=0) + profile2_enable = db.Column(db.Boolean(), default=False) + profile2_name = db.Column(db.String(), default='') + profile2_elength = db.Column(db.Integer, default=0) + profile3_enable = db.Column(db.Boolean(), default=False) + profile3_name = db.Column(db.String(), default='') + profile3_elength = db.Column(db.Integer, default=0) + profile4_enable = db.Column(db.Boolean(), default=False) + profile4_name = db.Column(db.String(), default='') + profile_mode = db.Column(db.Enum('Priority', 'ElectricalLoopLength'), default=None) + + #Edgecore + mac_address = db.Column(db.String(), default='A8-2B-B5-7F-E3-C0') \ No newline at end of file diff --git a/nesi/softbox/api/models/portgroupport_models.py b/nesi/softbox/api/models/portgroupport_models.py new file mode 100644 index 0000000..fdb9554 --- /dev/null +++ b/nesi/softbox/api/models/portgroupport_models.py @@ -0,0 +1,43 @@ +# This file is part of the NESi software. +# +# Copyright (c) 2020 +# Original Software Design by Ilya Etingof . +# +# Software adapted by inexio . +# - Janis Groß +# - Philip Konrath +# - Alexander Dincher +# - Philipp-Noah Groß +# +# License: https://github.com/inexio/NESi/LICENSE.rst +from nesi.softbox.api import db +from .subscriber_models import Subscriber + + +class PortGroupPort(db.Model): + id = db.Column(db.Integer(), primary_key=True) + name = db.Column(db.String(64)) + box_id = db.Column(db.Integer, db.ForeignKey('box.id')) + operational_state = db.Column(db.Enum('1', '0'), default='0') # 0 => down, 1 => up + admin_state = db.Column(db.Enum('1', '0'), default='0') + description = db.Column(db.String(), default='') + label1 = db.Column(db.String(), default='""') + label2 = db.Column(db.String(), default='""') + card_id = db.Column(db.Integer, db.ForeignKey('card.id')) + type = db.Column(db.Enum('ISDN', 'PSTN'), default='ISDN') + subscribers = db.relationship('Subscriber', backref='PortGroupPort', lazy='dynamic') + + #isdn + enable = db.Column(db.Boolean(), default=False) + register_as_global = db.Column(db.Boolean, default=True) + register_default_number_only = db.Column(db.Boolean, default=False) + layer_1_permanently_activated = db.Column(db.Boolean, default=False) + sip_profile = db.Column(db.String(), default='none') + proxy_registrar_profile = db.Column(db.String(), default='none') + codec_sdp_profile = db.Column(db.String(), default='none') + isdnba_profile = db.Column(db.String(), default='none') + + #pstn + pay_phone = db.Column(db.Boolean(), default=False) + pstn_profile = db.Column(db.String(), default='none') + enterprise_profile = db.Column(db.String(), default='none') diff --git a/nesi/softbox/api/models/srvc_models.py b/nesi/softbox/api/models/srvc_models.py new file mode 100644 index 0000000..c0074a9 --- /dev/null +++ b/nesi/softbox/api/models/srvc_models.py @@ -0,0 +1,25 @@ +# This file is part of the NESi software. +# +# Copyright (c) 2020 +# Original Software Design by Ilya Etingof . +# +# Software adapted by inexio . +# - Janis Groß +# - Philip Konrath +# - Alexander Dincher +# - Philipp-Noah Groß +# +# License: https://github.com/inexio/NESi/LICENSE.rst +import uuid +from nesi.softbox.api import db + + +class Srvc(db.Model): + id = db.Column(db.Integer(), primary_key=True) + name = db.Column(db.String(64)) + box_id = db.Column(db.Integer, db.ForeignKey('box.id')) + service_type = db.Column(db.Enum('1to1doubletag', '1to1singletag', 'mcast', 'nto1', 'pls', 'tls')) + address = db.Column(db.String(), default='') + svid = db.Column(db.Integer(), default=None) + stag_priority = db.Column(db.Enum('CoS0', 'CoS1', 'CoS2', 'CoS3', 'CoS4', 'CoS5', 'CoS6', 'CoS7'), default=None) + vlan_handling = db.Column(db.Enum('Add', 'Transparent', 'Swap'), default=None) diff --git a/nesi/softbox/api/models/subrack_models.py b/nesi/softbox/api/models/subrack_models.py index a4cfa6e..46f207b 100644 --- a/nesi/softbox/api/models/subrack_models.py +++ b/nesi/softbox/api/models/subrack_models.py @@ -13,6 +13,7 @@ from nesi.softbox.api import db from .card_models import Card +from .mgmt_card_models import MgmtCard class Subrack(db.Model): @@ -20,6 +21,7 @@ class Subrack(db.Model): name = db.Column(db.String(64), default='test') box_id = db.Column(db.Integer, db.ForeignKey('box.id')) cards = db.relationship('Card', backref='Subrack', lazy='dynamic') + mgmt_cards = db.relationship('MgmtCard', backref='Subrack', lazy='dynamic') # data description = db.Column(db.String(), default='') planned_type = db.Column(db.Enum('rvxs-a', 'not-planned', 'planned', 'nfxs-f'), default='not-planned') diff --git a/nesi/softbox/api/models/subscriber_models.py b/nesi/softbox/api/models/subscriber_models.py new file mode 100644 index 0000000..9e1f8dd --- /dev/null +++ b/nesi/softbox/api/models/subscriber_models.py @@ -0,0 +1,33 @@ +# This file is part of the NESi software. +# +# Copyright (c) 2020 +# Original Software Design by Ilya Etingof . +# +# Software adapted by inexio . +# - Janis Groß +# - Philip Konrath +# - Alexander Dincher +# - Philipp-Noah Groß +# +# License: https://github.com/inexio/NESi/LICENSE.rst< + +from nesi.softbox.api import db + + +class Subscriber(db.Model): + id = db.Column(db.Integer(), primary_key=True) + name = db.Column(db.String(64)) + box_id = db.Column(db.Integer, db.ForeignKey('box.id')) + portgroupport_id = db.Column(db.Integer(), db.ForeignKey('port_group_port.id')) + + number = db.Column(db.Integer(), nullable=False, unique=True) + address = db.Column(db.String(), default='') + registration_state = db.Column( + db.Enum('Registered', 'Registering', 'RegisteringWith-Cred', + 'DeRegInRegistering', 'DeRegistering', 'Reregistering', + 'Unregistered'), default='Registered') + autorisation_user_name = db.Column(db.String(), default='') + autorisation_password = db.Column(db.String(), default='') + display_name = db.Column(db.String(), default='') + privacy = db.Column(db.String(), default='None') + diff --git a/nesi/softbox/api/models/user_models.py b/nesi/softbox/api/models/user_models.py index 2add0be..74805e5 100644 --- a/nesi/softbox/api/models/user_models.py +++ b/nesi/softbox/api/models/user_models.py @@ -9,6 +9,7 @@ # - Alexander Dincher # # License: https://github.com/inexio/NESi/LICENSE.rst +from .credential_models import Credential from nesi.softbox.api import db @@ -17,12 +18,12 @@ class User(db.Model): id = db.Column(db.Integer(), primary_key=True) box_id = db.Column(db.Integer(), db.ForeignKey('box.id')) - credentials_id = db.Column(db.Integer(), db.ForeignKey('credential.id')) + credential_details = db.relationship('Credential', backref='User', lazy='dynamic') name = db.Column(db.String(), default='user') level = db.Column(db.Enum('Super', 'Admin', 'Operator', 'User'), default='User') - status = db.Column(db.Enum('Online', 'Offline'), default='Offline') - profile = db.Column(db.Enum('root', 'admin', 'operator', 'commonuser'), default='commonuser') + status = db.Column(db.Enum('online', 'offline'), default='offline') + profile = db.Column(db.Enum('root', 'admin', 'operator', 'commonuser', 'enable', 'backup'), default='commonuser') append_info = db.Column(db.String(), default='-----') reenter_num = db.Column(db.Integer(), default=3) reenter_num_temp = db.Column(db.Integer(), default=3) - lock_status = db.Column(db.Enum('Locked', 'Unlocked'), default='Unlocked') + lock_status = db.Column(db.Enum('locked', 'unlocked'), default='unlocked') diff --git a/nesi/softbox/api/models/vlan_models.py b/nesi/softbox/api/models/vlan_models.py index 13a4bc9..e9f5fd6 100644 --- a/nesi/softbox/api/models/vlan_models.py +++ b/nesi/softbox/api/models/vlan_models.py @@ -19,6 +19,7 @@ class Vlan(db.Model): name = db.Column(db.String(64), nullable=False) number = db.Column(db.Integer(), nullable=False) description = db.Column(db.String()) + mtu = db.Column(db.Integer(), default=1500) role = db.Column( db.Enum('access', 'trunk', 'native'), nullable=False, default='access') @@ -29,7 +30,6 @@ class Vlan(db.Model): egress_port = db.Column(db.String(), default='') fdb_id = db.Column(db.Integer, default=2620) shutdown = db.Column(db.Boolean(), default=False) - mtu = db.Column(db.Integer(), default=1500) access_group_in = db.Column(db.String(64), default='') access_group_out = db.Column(db.String(64), default='') ip_redirect = db.Column(db.Boolean(), default=False) diff --git a/nesi/softbox/api/schemas/box_schemas.py b/nesi/softbox/api/schemas/box_schemas.py index af4a27b..eb5b802 100644 --- a/nesi/softbox/api/schemas/box_schemas.py +++ b/nesi/softbox/api/schemas/box_schemas.py @@ -7,6 +7,7 @@ # - Janis Groß # - Philip Konrath # - Alexander Dincher +# - Philipp-Noah Groß # # License: https://github.com/inexio/NESi/LICENSE.rst @@ -16,6 +17,7 @@ from ..schemas.credential_schemas import CredentialsSchema from ..schemas.vlan_schemas import VlansSchema from ..schemas.portprofile_schemas import PortProfilesSchema +from ..schemas.user_schemas import UsersSchema class RootSchema(ma.ModelSchema): @@ -30,12 +32,13 @@ class BoxSchema(ma.ModelSchema): class Meta: model = Box fields = ('id', 'vendor', 'model', 'version', 'software_version', 'network_protocol', 'network_address', - 'network_port', 'uuid', 'description', - 'hostname', 'mgmt_address', 'credentials', 'credential_details', 'port_profiles', - 'port_profile_details', 'vlans', 'service_vlans', 'vlan_details', - 'subracks', 'subrack_details', 'cards', 'ports', 'service_ports', 'emus', 'onts', 'ont_ports', 'cpes', - 'cpe_ports', 'routes', 'login_banner', 'vlan_interfaces', 'users', - 'welcome_banner', 'last_login', 'last_logout', 'sntp_server_ip_address', 'timezone_offset', '_links') + 'network_port', 'uuid', 'description', 'interfaces', 'logports', 'ont_ports', 'cpes', 'srvcs', + 'hostname', 'mgmt_address', 'credentials', 'credential_details', 'port_profiles', 'mgmt_ports', + 'port_profile_details', 'vlans', 'service_vlans', 'vlan_details', 'subscribers', 'currTemperature', + 'subracks', 'subrack_details', 'cards', 'ports', 'channels', 'service_ports', 'emus', 'onts', + 'cpe_ports', 'routes', 'login_banner', 'vlan_interfaces', 'users', 'user_details', 'portgroupports', 'mgmt_cards', + 'welcome_banner', 'last_login', 'last_logout', 'sntp_server_ip_address', 'timezone_offset', + 'net_mask', 'default_gateway', '_links') credentials = ma.Hyperlinks( {'_links': { @@ -47,6 +50,8 @@ class Meta: {'_links': { 'self': ma.URLFor('show_users', box_id='')}}) + user_details = ma.Nested(UsersSchema.UserSchema, many=True) + subracks = ma.Hyperlinks( {'_links': { 'self': ma.URLFor('show_subracks', box_id='')}}) @@ -57,10 +62,26 @@ class Meta: {'_links': { 'self': ma.URLFor('show_cards', box_id='')}}) + mgmt_cards = ma.Hyperlinks( + {'_links': { + 'self': ma.URLFor('show_mgmt_cards', box_id='')}}) + ports = ma.Hyperlinks( {'_links': { 'self': ma.URLFor('show_ports', box_id='')}}) + mgmt_ports = ma.Hyperlinks( + {'_links': { + 'self': ma.URLFor('show_mgmt_ports', box_id='')}}) + + channels = ma.Hyperlinks( + {'_links': { + 'self': ma.URLFor('show_channels', box_id='')}}) + + interfaces = ma.Hyperlinks( + {'_links': { + 'self': ma.URLFor('show_interfaces', box_id='')}}) + service_ports = ma.Hyperlinks( {'_links': { 'self': ma.URLFor('show_service_ports', box_id='')}}) @@ -69,6 +90,22 @@ class Meta: {'_links': { 'self': ma.URLFor('show_emus', box_id='')}}) + subscribers = ma.Hyperlinks( + {'_links': { + 'self': ma.URLFor('show_subscribers', box_id='')}}) + + portgroupports = ma.Hyperlinks( + {'_links': { + 'self': ma.URLFor('show_portgroupports', box_id='')}}) + + logports = ma.Hyperlinks( + {'_links': { + 'self': ma.URLFor('show_logports', box_id='')}}) + + srvcs = ma.Hyperlinks( + {'_links': { + 'self': ma.URLFor('show_srvcs', box_id='')}}) + onts = ma.Hyperlinks({'_links': { 'self': ma.URLFor('show_onts', box_id='')}}) diff --git a/nesi/softbox/api/schemas/channel_schemas.py b/nesi/softbox/api/schemas/channel_schemas.py new file mode 100644 index 0000000..a9842ee --- /dev/null +++ b/nesi/softbox/api/schemas/channel_schemas.py @@ -0,0 +1,52 @@ +# This file is part of the NESi software. +# +# Copyright (c) 2020 +# Original Software Design by Ilya Etingof . +# +# Software adapted by inexio . +# - Janis Groß +# - Philip Konrath +# - Alexander Dincher +# +# License: https://github.com/inexio/NESi/LICENSE.rst + +from nesi.softbox.api import ma +from ..models.channel_models import Channel +from ..schemas.interface_schemas import InterfacesSchema + + +class ChannelSchema(ma.ModelSchema): + class Meta: + model = Channel + fields = ('id', 'box_id', 'box', 'port_id', 'interfaces', 'curr_rate_u', 'curr_rate_d', 'prev_rate_u', + 'name', 'description', 'prev_rate_d', 'curr_delay_u', 'curr_delay_d', '_links') + + interfaces = ma.Nested(InterfacesSchema.InterfaceSchema, many=True) + + box = ma.Hyperlinks( + {'_links': { + 'self': ma.URLFor('show_box', id='')}}) + + _links = ma.Hyperlinks( + {'self': ma.URLFor('show_channel', box_id='', id='')}) + + +class ChannelsSchema(ma.ModelSchema): + class Meta: + fields = ('members', 'count', '_links') + + class ChannelSchema(ma.ModelSchema): + class Meta: + model = Channel + fields = ('id', 'name', '_links') + + _links = ma.Hyperlinks( + {'self': ma.URLFor( + 'show_channel', box_id='', id='')}) + + members = ma.Nested(ChannelSchema, many=True) + + _links = ma.Hyperlinks( + {'self': ma.URLFor('show_channels', box_id='')}) + + diff --git a/nesi/softbox/api/schemas/credential_schemas.py b/nesi/softbox/api/schemas/credential_schemas.py index c60f477..c81a5a7 100644 --- a/nesi/softbox/api/schemas/credential_schemas.py +++ b/nesi/softbox/api/schemas/credential_schemas.py @@ -18,7 +18,7 @@ class CredentialSchema(ma.ModelSchema): class Meta: model = Credential fields = ('id', 'protocol', 'credential', 'username', 'password', - 'box', '_links') + 'box', 'box_id', 'user_id', '_links') box = ma.Hyperlinks( {'_links': { diff --git a/nesi/softbox/api/schemas/emu_schemas.py b/nesi/softbox/api/schemas/emu_schemas.py index aad1347..7d4fb13 100644 --- a/nesi/softbox/api/schemas/emu_schemas.py +++ b/nesi/softbox/api/schemas/emu_schemas.py @@ -17,7 +17,7 @@ class EmuSchema(ma.ModelSchema): class Meta: model = Emu - fields = ('id', 'name', 'box', '_links') + fields = ('id', 'name', 'box', 'box_id', '_links') box = ma.Hyperlinks( {'_links': { diff --git a/nesi/softbox/api/schemas/interface_schemas.py b/nesi/softbox/api/schemas/interface_schemas.py new file mode 100644 index 0000000..1c68aec --- /dev/null +++ b/nesi/softbox/api/schemas/interface_schemas.py @@ -0,0 +1,48 @@ +# This file is part of the NESi software. +# +# Copyright (c) 2020 +# Original Software Design by Ilya Etingof . +# +# Software adapted by inexio . +# - Janis Groß +# - Philip Konrath +# - Alexander Dincher +# +# License: https://github.com/inexio/NESi/LICENSE.rst + +from nesi.softbox.api import ma +from ..models.interface_models import Interface + + +class InterfaceSchema(ma.ModelSchema): + class Meta: + model = Interface + fields = ('id', 'box_id', 'box', 'name', 'description', '_links') + + box = ma.Hyperlinks( + {'_links': { + 'self': ma.URLFor('show_box', id='')}}) + + _links = ma.Hyperlinks( + {'self': ma.URLFor('show_interface', box_id='', id='')}) + + +class InterfacesSchema(ma.ModelSchema): + class Meta: + fields = ('members', 'count', '_links') + + class InterfaceSchema(ma.ModelSchema): + class Meta: + model = Interface + fields = ('id', 'name', '_links') + + _links = ma.Hyperlinks( + {'self': ma.URLFor( + 'show_interface', box_id='', id='')}) + + members = ma.Nested(InterfaceSchema, many=True) + + _links = ma.Hyperlinks( + {'self': ma.URLFor('show_interfaces', box_id='')}) + + diff --git a/nesi/softbox/api/schemas/logport_schemas.py b/nesi/softbox/api/schemas/logport_schemas.py new file mode 100644 index 0000000..7c09372 --- /dev/null +++ b/nesi/softbox/api/schemas/logport_schemas.py @@ -0,0 +1,52 @@ +# This file is part of the NESi software. +# +# Copyright (c) 2020 +# Original Software Design by Ilya Etingof . +# +# Software adapted by inexio . +# - Janis Groß +# - Philip Konrath +# - Alexander Dincher +# +# License: https://github.com/inexio/NESi/LICENSE.rst + +from nesi.softbox.api import ma +from .interface_schemas import InterfacesSchema +from ..models.logport_models import LogPort + + +class LogPortSchema(ma.ModelSchema): + class Meta: + model = LogPort + fields = ('id', 'box_id', 'box', 'card_id', 'name', 'ports', 'interfaces', 'description', 'admin_state', + 'operational_state', 'label1', 'label2', 'profile', + '_links') + + interfaces = ma.Nested(InterfacesSchema.InterfaceSchema, many=True) + + box = ma.Hyperlinks( + {'_links': { + 'self': ma.URLFor('show_box', id='')}}) + + _links = ma.Hyperlinks( + {'self': ma.URLFor('show_logport', box_id='', id=''), + 'collection': ma.URLFor('show_logports', box_id='')}) + + +class LogPortsSchema(ma.ModelSchema): + class Meta: + fields = ('members', 'count', '_links') + + class LogPortSchema(ma.ModelSchema): + class Meta: + model = LogPort + fields = ('id', 'name', '_links') + + _links = ma.Hyperlinks( + {'self': ma.URLFor( + 'show_logport', box_id='', id='')}) + + members = ma.Nested(LogPortSchema, many=True) + + _links = ma.Hyperlinks( + {'self': ma.URLFor('show_logports', box_id='')}) diff --git a/nesi/softbox/api/schemas/mgmt_card_schemas.py b/nesi/softbox/api/schemas/mgmt_card_schemas.py new file mode 100644 index 0000000..e455a6f --- /dev/null +++ b/nesi/softbox/api/schemas/mgmt_card_schemas.py @@ -0,0 +1,54 @@ +# This file is part of the NESi software. +# +# Copyright (c) 2020 +# Original Software Design by Ilya Etingof . +# +# Software adapted by inexio . +# - Janis Groß +# - Philip Konrath +# - Alexander Dincher +# - Philipp-Noah Groß +# +# License: https://github.com/inexio/NESi/LICENSE.rst + +from nesi.softbox.api import ma +from ..models.mgmt_card_models import MgmtCard +from ..schemas.mgmt_port_schemas import MgmtPortsSchema + + +class MgmtCardSchema(ma.ModelSchema): + class Meta: + model = MgmtCard + fields = ('id', 'box_id', 'box', 'name', 'subrack_id', 'admin_state', 'operational_state', 'description', + 'mgmt_ports') + + mgmt_ports = ma.Nested(MgmtPortsSchema.MgmtPortSchema, many=True) + + box = ma.Hyperlinks( + {'_links': { + 'self': ma.URLFor('show_box', id='')}}) + + _links = ma.Hyperlinks( + {'self': ma.URLFor('show_mgmt_card', box_id='', id=''), + 'collection': ma.URLFor('show_mgmt_cards', box_id='')}) + + +class MgmtCardsSchema(ma.ModelSchema): + class Meta: + fields = ('members', 'count', '_links') + + class MgmtCardSchema(ma.ModelSchema): + class Meta: + model = MgmtCard + fields = ('id', 'name', 'operational_state', 'mgmt_ports', '_links') + + mgmt_ports = ma.Nested(MgmtPortsSchema.MgmtPortSchema, many=True) + + _links = ma.Hyperlinks( + {'self': ma.URLFor( + 'show_mgmt_card', box_id='', id='')}) + + members = ma.Nested(MgmtCardSchema, many=True) + + _links = ma.Hyperlinks( + {'self': ma.URLFor('show_mgmt_cards', box_id='')}) diff --git a/nesi/softbox/api/schemas/mgmt_port_schemas.py b/nesi/softbox/api/schemas/mgmt_port_schemas.py new file mode 100644 index 0000000..0cdbae4 --- /dev/null +++ b/nesi/softbox/api/schemas/mgmt_port_schemas.py @@ -0,0 +1,49 @@ +# This file is part of the NESi software. +# +# Copyright (c) 2020 +# Original Software Design by Ilya Etingof . +# +# Software adapted by inexio . +# - Janis Groß +# - Philip Konrath +# - Alexander Dincher +# - Philipp-Noah Groß +# +# License: https://github.com/inexio/NESi/LICENSE.rst + +from nesi.softbox.api import ma +from ..models.mgmt_port_models import MgmtPort + + +class MgmtPortSchema(ma.ModelSchema): + class Meta: + model = MgmtPort + fields = ('id', 'box_id', 'box', 'mgmt_card_id', 'name', + 'description', 'admin_state', 'operational_state', '_links') + + box = ma.Hyperlinks( + {'_links': { + 'self': ma.URLFor('show_box', id='')}}) + + _links = ma.Hyperlinks( + {'self': ma.URLFor('show_mgmt_port', box_id='', id=''), + 'collection': ma.URLFor('show_mgmt_ports', box_id='')}) + + +class MgmtPortsSchema(ma.ModelSchema): + class Meta: + fields = ('members', 'count', '_links') + + class MgmtPortSchema(ma.ModelSchema): + class Meta: + model = MgmtPort + fields = ('id', 'name', 'operational_state', '_links') + + _links = ma.Hyperlinks( + {'self': ma.URLFor( + 'show_mgmt_port', box_id='', id='')}) + + members = ma.Nested(MgmtPortSchema, many=True) + + _links = ma.Hyperlinks( + {'self': ma.URLFor('show_mgmt_ports', box_id='')}) diff --git a/nesi/softbox/api/schemas/port_schemas.py b/nesi/softbox/api/schemas/port_schemas.py index b2cced5..83679f3 100644 --- a/nesi/softbox/api/schemas/port_schemas.py +++ b/nesi/softbox/api/schemas/port_schemas.py @@ -14,18 +14,24 @@ from ..models.port_models import Port from ..schemas.cpe_schemas import CpesSchema from ..schemas.ont_schemas import OntsSchema +from ..schemas.channel_schemas import ChannelsSchema +from ..schemas.interface_schemas import InterfacesSchema class PortSchema(ma.ModelSchema): class Meta: model = Port - fields = ('id', 'box_id', 'box', 'card_id', 'cpes', 'onts', 'loopback', 'name', + fields = ('id', 'box_id', 'box', 'card_id', 'cpes', 'onts', 'channels', 'loopback', 'name', 'interfaces', 'description', 'admin_state', 'operational_state', '_links') cpes = ma.Nested(CpesSchema.CpeSchema, many=True) onts = ma.Nested(OntsSchema.OntSchema, many=True) + channels = ma.Nested(ChannelsSchema.ChannelSchema, many=True) + + interfaces = ma.Nested(InterfacesSchema.InterfaceSchema, many=True) + box = ma.Hyperlinks( {'_links': { 'self': ma.URLFor('show_box', id='')}}) diff --git a/nesi/softbox/api/schemas/portgroupport_schemas.py b/nesi/softbox/api/schemas/portgroupport_schemas.py new file mode 100644 index 0000000..39cd17e --- /dev/null +++ b/nesi/softbox/api/schemas/portgroupport_schemas.py @@ -0,0 +1,54 @@ +# This file is part of the NESi software. +# +# Copyright (c) 2020 +# Original Software Design by Ilya Etingof . +# +# Software adapted by inexio . +# - Janis Groß +# - Philip Konrath +# - Alexander Dincher +# +# License: https://github.com/inexio/NESi/LICENSE.rst + +from nesi.softbox.api import ma +from ..models.portgroupport_models import PortGroupPort +from .subscriber_schemas import SubscribersSchema + + +class PortGroupPortSchema(ma.ModelSchema): + class Meta: + model = PortGroupPort + fields = ('id', 'name', 'box_id', 'card_id', 'operational_state', 'admin_state', 'description', 'label1', + 'label2', 'type', 'enable', 'register_as_global', 'subscribers', + 'register_default_number_only', 'layer_1_permanently_activated', 'sip_profile', 'isdnba_profile', + 'proxy_registrar_profile', 'codec_sdp_profile', 'pay_phone', 'pstn_profile', 'enterprise_profile', + '_links') + + subscribers = ma.Nested(SubscribersSchema.SubscriberSchema, many=True) + + box = ma.Hyperlinks( + {'_links': { + 'self': ma.URLFor('show_box', id='')}}) + + _links = ma.Hyperlinks( + {'self': ma.URLFor('show_portgroupport', box_id='', id=''), + 'collection': ma.URLFor('show_portgroupports', box_id='')}) + + +class PortGroupPortsSchema(ma.ModelSchema): + class Meta: + fields = ('members', 'count', '_links') + + class PortGroupPortSchema(ma.ModelSchema): + class Meta: + model = PortGroupPort + fields = ('id', '_links') + + _links = ma.Hyperlinks( + {'self': ma.URLFor( + 'show_portgroupport', box_id='', id='')}) + + members = ma.Nested(PortGroupPortSchema, many=True) + + _links = ma.Hyperlinks( + {'self': ma.URLFor('show_portgroupports', box_id='')}) diff --git a/nesi/softbox/api/schemas/qos_interface_schemas.py b/nesi/softbox/api/schemas/qos_interface_schemas.py index 0743d85..02dd33f 100644 --- a/nesi/softbox/api/schemas/qos_interface_schemas.py +++ b/nesi/softbox/api/schemas/qos_interface_schemas.py @@ -17,7 +17,7 @@ class QosInterfaceSchema(ma.ModelSchema): class Meta: model = QosInterface - fields = ('id', 'name', 'description', 'box', + fields = ('id', 'name', 'description', 'box', 'box_id', '_links') _links = ma.Hyperlinks({ diff --git a/nesi/softbox/api/schemas/route_schemas.py b/nesi/softbox/api/schemas/route_schemas.py index da0b85e..41db76f 100644 --- a/nesi/softbox/api/schemas/route_schemas.py +++ b/nesi/softbox/api/schemas/route_schemas.py @@ -17,7 +17,7 @@ class RouteSchema(ma.ModelSchema): class Meta: model = Route - fields = ('id', 'dst', 'gw', 'metric', 'box', '_links') + fields = ('id', 'dst', 'gw', 'metric', 'box', 'box_id', '_links') box = ma.Hyperlinks( {'_links': { diff --git a/nesi/softbox/api/schemas/service_port_schemas.py b/nesi/softbox/api/schemas/service_port_schemas.py index ae33609..251d7ef 100644 --- a/nesi/softbox/api/schemas/service_port_schemas.py +++ b/nesi/softbox/api/schemas/service_port_schemas.py @@ -17,7 +17,7 @@ class ServicePortSchema(ma.ModelSchema): class Meta: model = ServicePort - fields = ('id', 'name', 'box', 'connected_id', 'connected_type', 'admin_state', 'operational_state', + fields = ('id', 'name', 'box', 'box_id', 'connected_id', 'connected_type', 'admin_state', 'operational_state', '_links') box = ma.Hyperlinks( diff --git a/nesi/softbox/api/schemas/service_vlan_schemas.py b/nesi/softbox/api/schemas/service_vlan_schemas.py index d9c0e2a..1354f95 100644 --- a/nesi/softbox/api/schemas/service_vlan_schemas.py +++ b/nesi/softbox/api/schemas/service_vlan_schemas.py @@ -17,7 +17,7 @@ class ServiceVlanSchema(ma.ModelSchema): class Meta: model = ServiceVlan - fields = ('id', 'name', 'service_port_id', 'vlan_id', 'box', 'card_id', '_links') + fields = ('id', 'name', 'service_port_id', 'vlan_id', 'box', 'box_id', 'card_id', '_links') box = ma.Hyperlinks( {'_links': { diff --git a/nesi/softbox/api/schemas/srvc_schemas.py b/nesi/softbox/api/schemas/srvc_schemas.py new file mode 100644 index 0000000..034283f --- /dev/null +++ b/nesi/softbox/api/schemas/srvc_schemas.py @@ -0,0 +1,49 @@ +# This file is part of the NESi software. +# +# Copyright (c) 2020 +# Original Software Design by Ilya Etingof . +# +# Software adapted by inexio . +# - Janis Groß +# - Philip Konrath +# - Alexander Dincher +# - Philipp-Noah Groß +# +# License: https://github.com/inexio/NESi/LICENSE.rst + +from nesi.softbox.api import ma +from ..models.srvc_models import Srvc + + +class SrvcSchema(ma.ModelSchema): + class Meta: + model = Srvc + fields = ('id', 'box', 'box_id', 'name', 'service_type', 'address', 'svid', 'stag_priority', 'vlan_handling', + '_links') + + box = ma.Hyperlinks( + {'_links': { + 'self': ma.URLFor('show_box', id='')}}) + + _links = ma.Hyperlinks( + {'self': ma.URLFor('show_srvc', box_id='', id=''), + 'collection': ma.URLFor('show_srvcs', box_id='')}) + + +class SrvcsSchema(ma.ModelSchema): + class Meta: + fields = ('members', 'count', '_links') + + class SrvcSchema(ma.ModelSchema): + class Meta: + model = Srvc + fields = ('id', 'name', '_links') + + _links = ma.Hyperlinks( + {'self': ma.URLFor( + 'show_srvc', box_id='', id='')}) + + members = ma.Nested(SrvcSchema, many=True) + + _links = ma.Hyperlinks( + {'self': ma.URLFor('show_srvcs', box_id='')}) diff --git a/nesi/softbox/api/schemas/subrack_schemas.py b/nesi/softbox/api/schemas/subrack_schemas.py index dc42f7d..7a6c773 100644 --- a/nesi/softbox/api/schemas/subrack_schemas.py +++ b/nesi/softbox/api/schemas/subrack_schemas.py @@ -13,15 +13,17 @@ from nesi.softbox.api import ma from ..models.subrack_models import Subrack from ..schemas.card_schemas import CardsSchema +from ..schemas.mgmt_card_schemas import MgmtCardsSchema class SubrackSchema(ma.ModelSchema): class Meta: model = Subrack - fields = ('id', 'box_id', 'box', 'cards', + fields = ('id', 'box_id', 'box', 'cards', 'mgmt_cards', 'name', 'description', '_links') cards = ma.Nested(CardsSchema.CardSchema, many=True) + mgmt_cards = ma.Nested(MgmtCardsSchema.MgmtCardSchema, many=True) box = ma.Hyperlinks( {'_links': { diff --git a/nesi/softbox/api/schemas/subscriber_schemas.py b/nesi/softbox/api/schemas/subscriber_schemas.py new file mode 100644 index 0000000..581acfc --- /dev/null +++ b/nesi/softbox/api/schemas/subscriber_schemas.py @@ -0,0 +1,49 @@ +# This file is part of the NESi software. +# +# Copyright (c) 2020 +# Original Software Design by Ilya Etingof . +# +# Software adapted by inexio . +# - Janis Groß +# - Philip Konrath +# - Alexander Dincher +# +# License: https://github.com/inexio/NESi/LICENSE.rst + +from nesi.softbox.api import ma +from ..models.subscriber_models import Subscriber + + +class SubscriberSchema(ma.ModelSchema): + class Meta: + model = Subscriber + fields = ('id', 'name', 'box', 'box_id', 'number', 'address', 'registration_state', 'display_name', + 'autorisation_user_name', 'autorisation_password', 'privacy', 'portgroupport_id', + '_links') + + box = ma.Hyperlinks( + {'_links': { + 'self': ma.URLFor('show_box', id='')}}) + + _links = ma.Hyperlinks( + {'self': ma.URLFor('show_subscriber', box_id='', id=''), + 'collection': ma.URLFor('show_subscribers', box_id='')}) + + +class SubscribersSchema(ma.ModelSchema): + class Meta: + fields = ('members', 'count', '_links') + + class SubscriberSchema(ma.ModelSchema): + class Meta: + model = Subscriber + fields = ('id', '_links') + + _links = ma.Hyperlinks( + {'self': ma.URLFor( + 'show_subscriber', box_id='', id='')}) + + members = ma.Nested(SubscriberSchema, many=True) + + _links = ma.Hyperlinks( + {'self': ma.URLFor('show_subscribers', box_id='')}) diff --git a/nesi/softbox/api/schemas/user_schemas.py b/nesi/softbox/api/schemas/user_schemas.py index f2f93e5..fadd4e8 100644 --- a/nesi/softbox/api/schemas/user_schemas.py +++ b/nesi/softbox/api/schemas/user_schemas.py @@ -12,12 +12,15 @@ from nesi.softbox.api import ma from ..models.user_models import User +from ..schemas.credential_schemas import CredentialsSchema class UserSchema(ma.ModelSchema): class Meta: model = User - fields = ('id', 'box', 'credentials_id', 'name', '_links') + fields = ('id', 'box', 'box_id', 'credential_details', 'name', 'status', 'lock_status', 'profile', '_links') + + credential_details = ma.Nested(CredentialsSchema.CredentialSchema, many=True) box = ma.Hyperlinks( {'_links': { @@ -35,7 +38,7 @@ class Meta: class UserSchema(ma.ModelSchema): class Meta: model = User - fields = ('id', 'name', '_links') + fields = ('id', 'name', 'status', '_links') _links = ma.Hyperlinks( {'self': ma.URLFor( diff --git a/nesi/softbox/api/schemas/vlan_interface_schemas.py b/nesi/softbox/api/schemas/vlan_interface_schemas.py index ff335dc..aa67183 100644 --- a/nesi/softbox/api/schemas/vlan_interface_schemas.py +++ b/nesi/softbox/api/schemas/vlan_interface_schemas.py @@ -17,7 +17,7 @@ class VlanInterfaceSchema(ma.ModelSchema): class Meta: model = VlanInterface - fields = ('id', 'name', 'box', 'vlan_id', '_links') + fields = ('id', 'name', 'box', 'box_id', 'vlan_id', '_links') _links = ma.Hyperlinks({ 'self': ma.URLFor( diff --git a/nesi/softbox/api/schemas/vlan_schemas.py b/nesi/softbox/api/schemas/vlan_schemas.py index 96d608a..1620b34 100644 --- a/nesi/softbox/api/schemas/vlan_schemas.py +++ b/nesi/softbox/api/schemas/vlan_schemas.py @@ -17,7 +17,7 @@ class VlanSchema(ma.ModelSchema): class Meta: model = Vlan - fields = ('id', 'box_id', 'number', 'mtu', + fields = ('id', 'box_id', 'number', 'mtu', 'box', 'description', 'name', '_links') box = ma.Hyperlinks( diff --git a/nesi/softbox/api/views/__init__.py b/nesi/softbox/api/views/__init__.py index c37245d..e87d03d 100644 --- a/nesi/softbox/api/views/__init__.py +++ b/nesi/softbox/api/views/__init__.py @@ -1,4 +1,5 @@ __all__ = ["box_views", "credential_views", "route_views", "subrack_views", "card_views", "port_views", "ont_views", "ontport_views", "cpe_views", "cpeport_views", "vlan_views", "portprofile_views", "emu_views", - "model_views", "vendor_views", "version_views", "service_port_views", "service_vlan_views", - "qos_interface_views", "vlan_interface_views", "user_views"] + "model_views", "vendor_views", "version_views", "service_port_views", "service_vlan_views", "srvc_views", + "qos_interface_views", "vlan_interface_views", "user_views", "channel_views", "interface_views", + "mgmt_card_views", "mgmt_port_views", "subscriber_views", "portgroupport_views", "logport_views"] diff --git a/nesi/softbox/api/views/base_views.py b/nesi/softbox/api/views/base_views.py index aef71de..cd8d2b2 100644 --- a/nesi/softbox/api/views/base_views.py +++ b/nesi/softbox/api/views/base_views.py @@ -7,6 +7,7 @@ # - Janis Groß # - Philip Konrath # - Alexander Dincher +# - Philipp-Noah Groß # # License: https://github.com/inexio/NESi/LICENSE.rst @@ -19,6 +20,8 @@ from nesi.softbox.api.schemas import * from nesi.alcatel.api.schemas import * from nesi.huawei.api.schemas import * +from nesi.keymile.api.schemas import * +from nesi.edgecore.api.schemas import * # important for other view classes from nesi.softbox.api import db diff --git a/nesi/softbox/api/views/box_views.py b/nesi/softbox/api/views/box_views.py index a08b6b9..2c3a01b 100644 --- a/nesi/softbox/api/views/box_views.py +++ b/nesi/softbox/api/views/box_views.py @@ -10,6 +10,7 @@ # # License: https://github.com/inexio/NESi/LICENSE.rst +# TODO: When no more new components are being created, update new_box, clone_box, and del_box from .base_views import * from ..models.box_models import Box @@ -24,6 +25,7 @@ from ..models.vlan_models import Vlan from ..models.portprofile_models import PortProfile from ..models.route_models import Route +from ..models.user_models import User from ..schemas.box_schemas import * # KNAUP @@ -184,7 +186,7 @@ def clone_components(components, component_model, reference_field=None, referenc component_mapping[component.id] = component_new.id return component_mapping - _ = clone_components(box.credentials, Credential) + clone_components(box.credentials, Credential) subrack_mapping = clone_components(box.subracks, Subrack) card_mapping = clone_components(box.cards, Card, 'subrack_id', subrack_mapping) port_mapping = clone_components(box.ports, Port, 'card_id', card_mapping) @@ -193,6 +195,8 @@ def clone_components(components, component_model, reference_field=None, referenc cpe_mapping = clone_components(box.cpes, Cpe, 'port_id', port_mapping, 'ont_port_id', ont_port_mapping) clone_components(box.cpe_ports, CpePort, 'cpe_id', cpe_mapping) clone_components(box.vlans, Vlan) + user_mapping = clone_components(box.users, User) + clone_components(box.credentials, Credential, 'user_id', user_mapping) clone_components(box.port_profiles, PortProfile) clone_components(box.routes, Route) @@ -236,21 +240,12 @@ def del_sub_components(component_collection): for component in component_collection: db.session.delete(component) - del_sub_components(box.credentials) - del_sub_components(box.subracks) - del_sub_components(box.cards) - del_sub_components(box.ports) - del_sub_components(box.cpes) - del_sub_components(box.cpe_ports) - del_sub_components(box.onts) - del_sub_components(box.ont_ports) - del_sub_components(box.vlans) - del_sub_components(box.port_profiles) - del_sub_components(box.routes) - del_sub_components(box.vlan_interfaces) - del_sub_components(box.emus) - del_sub_components(box.qos_interfaces) - del_sub_components(box.users) + for element in (box.credentials, box.subracks, box.cards, box.ports, box.cpes, box.cpe_ports, + box.onts, box.ont_ports, box.vlans, box.port_profiles, box.routes, box.vlan_interfaces, + box.emus, box.users, box.channels, box.interfaces, box.logports, box.mgmt_cards, + box.mgmt_ports, box.portgroupports, box.srvcs, box.service_ports, box.service_vlans + ): + del_sub_components(element) db.session.delete(box) db.session.commit() diff --git a/nesi/softbox/api/views/card_views.py b/nesi/softbox/api/views/card_views.py index 5ebe026..1d96791 100644 --- a/nesi/softbox/api/views/card_views.py +++ b/nesi/softbox/api/views/card_views.py @@ -7,6 +7,7 @@ # - Janis Groß # - Philip Konrath # - Alexander Dincher +# - Philipp-Noah Groß # # License: https://github.com/inexio/NESi/LICENSE.rst @@ -42,49 +43,52 @@ def show_card(box_id, id): def new_card(box_id): req = flask.request.json + vendor = '' if 'name' not in req or req['name'] == "": subrack = json.loads(show_component(Subrack, box_id, req['subrack_id']).data.decode('utf-8')) box = json.loads(show_box(box_id)[0].data.decode('utf-8')) + vendor = box['vendor'] if len(subrack['cards']) > 0: last_card = subrack['cards'][len(subrack['cards']) - 1] - if last_card['name'].startswith('nt-'): + if last_card['name'].startswith('nt-') and vendor == 'Alcatel': if subrack['name'] != "": - if box['vendor'] == 'Huawei': - req['name'] = subrack['name'] + "/0" - else: - req['name'] = subrack['name'] + "/1" + req['name'] = subrack['name'] + "/1" else: - if box['vendor'] == 'Huawei': - req['name'] = "0" - else: - req['name'] = "1" + req['name'] = "1" else: - p = re.compile('[0-9]+/([0-9]+(/)?([0-9]+)?)') - last_card_index = '' - check = p.match(last_card['name']).groups(1) - if len(check[0]) <= 2 and not check[0].endswith('/'): - last_card_index = check[0] - elif len(check[0]) > 2: - _, last_card_index = check[0].split('/', maxsplit=1) - else: - return flask.Response(status=400) + p = re.compile('^([0-9]+)?/?([0-9]+)?/?([0-9]+)?$') + match_groups = p.match(last_card['name']).groups() + filtered_match_groups = [x for x in match_groups if x is not None] # filter out None values + last_card_index = filtered_match_groups[len(filtered_match_groups) - 1] if subrack['name'] != "": req['name'] = subrack['name'] + "/" + str(int(last_card_index) + 1) else: + if vendor == 'KeyMile': + if int(last_card_index) + 1 in (11, 13): + return flask.Response(status=500) # MgmtCard slots are reserved + if (box['version'] == '2500' and int(last_card_index) + 1 > 21) or (box['version'] == '2300' and int(last_card_index) + 1 > 14) or (box['version'] == '2200' and int(last_card_index) + 1 > 12): + return flask.Response(status=500) req['name'] = str(int(last_card_index) + 1) else: if subrack['name'] != "": - if box['vendor'] == 'Huawei': + if vendor == 'Huawei': req['name'] = subrack['name'] + "/0" else: req['name'] = subrack['name'] + "/1" else: - if box['vendor'] == 'Huawei': + if vendor == 'Huawei': req['name'] = "0" + elif vendor == 'KeyMile': + if box['version'] == '2500': + req['name'] = "1" + elif box['version'] == '2300': + req['name'] = "7" + elif box['version'] == '2200': + req['name'] = "9" else: req['name'] = "1" - if 'position' not in req or req['position'] == "": + if 'position' not in req or req['position'] == "" and vendor == 'Alcatel': req['position'] = 'lt:' + req['name'] response = new_component(CardSchema(), Card, req, box_id) diff --git a/nesi/softbox/api/views/channel_views.py b/nesi/softbox/api/views/channel_views.py new file mode 100644 index 0000000..ca37c4d --- /dev/null +++ b/nesi/softbox/api/views/channel_views.py @@ -0,0 +1,59 @@ +# This file is part of the NESi software. +# +# Copyright (c) 2020 +# Original Software Design by Ilya Etingof . +# +# Software adapted by inexio . +# - Janis Groß +# - Philip Konrath +# - Alexander Dincher +# +# License: https://github.com/inexio/NESi/LICENSE.rst + +from .base_views import * +from ..models.port_models import Port +from ..schemas.channel_schemas import * + +PREFIX = '/nesi/v1' + + +@app.route(PREFIX + '/boxen//channels', methods=['GET']) +def show_channels(box_id): + if flask.request.args is None: + req = {} + else: + req = flask.request.args + + response = show_components(ChannelsSchema(), Channel, req, box_id) + return response, 200 + + +@app.route(PREFIX + '/boxen//channels/', methods=['GET']) +def show_channel(box_id, id): + response = show_component(Channel, box_id, id) + return response, 200 + + +@app.route(PREFIX + '/boxen//channels', methods=['POST']) +def new_channel(box_id): + req = flask.request.json + + if 'name' not in req or req['name'] == "": + if 'port_id' in req: + port = json.loads(show_component(Port, box_id, req['port_id']).data.decode('utf-8')) + req['name'] = port['name'] + "/" + str(len(port['channels']) + 1) + response = new_component(ChannelSchema(), Channel, req, box_id) + return response, 201 + + +@app.route(PREFIX + '/boxen//channels/', methods=['PUT']) +def update_channel(box_id, id): + req = flask.request.json + update_component(Channel, req, box_id, id) + return flask.Response(status=200) + + +@app.route(PREFIX + '/boxen//channels/', methods=['DELETE']) +def del_channel(box_id, id): + del_component(Channel, box_id, id) + return flask.Response(status=204) diff --git a/nesi/softbox/api/views/credential_views.py b/nesi/softbox/api/views/credential_views.py index 9021636..7491df6 100644 --- a/nesi/softbox/api/views/credential_views.py +++ b/nesi/softbox/api/views/credential_views.py @@ -36,6 +36,10 @@ def show_credential(box_id, id): @app.route(PREFIX + '/boxen//credentials', methods=['POST']) def new_credential(box_id): req = flask.request.json + credentials = json.loads(show_components(CredentialsSchema(), Credential, {'user_id': req['user_id']}, box_id).data.decode('utf-8'))['members'] + if len(credentials) >= 1: + return flask.Response(status=500) + response = new_component(CredentialSchema(), Credential, req, box_id) return response, 201 diff --git a/nesi/softbox/api/views/interface_views.py b/nesi/softbox/api/views/interface_views.py new file mode 100644 index 0000000..8d140c3 --- /dev/null +++ b/nesi/softbox/api/views/interface_views.py @@ -0,0 +1,75 @@ +# This file is part of the NESi software. +# +# Copyright (c) 2020 +# Original Software Design by Ilya Etingof . +# +# Software adapted by inexio . +# - Janis Groß +# - Philip Konrath +# - Alexander Dincher +# +# License: https://github.com/inexio/NESi/LICENSE.rst + +from .base_views import * +from .box_views import show_box +from ..models.port_models import Port +from ..models.channel_models import Channel +from ..models.logport_models import LogPort +from ..schemas.interface_schemas import * + +PREFIX = '/nesi/v1' + + +@app.route(PREFIX + '/boxen//interfaces', methods=['GET']) +def show_interfaces(box_id): + if flask.request.args is None: + req = {} + else: + req = flask.request.args + + response = show_components(InterfacesSchema(), Interface, req, box_id) + return response, 200 + + +@app.route(PREFIX + '/boxen//interfaces/', methods=['GET']) +def show_interface(box_id, id): + response = show_component(Interface, box_id, id) + return response, 200 + + +@app.route(PREFIX + '/boxen//interfaces', methods=['POST']) +def new_interface(box_id): + req = flask.request.json + box = json.loads(show_box(box_id)[0].data.decode('utf-8')) + + if 'name' not in req or req['name'] == "": + if box['vendor'] == 'KeyMile': + if 'port_id' in req: + port = json.loads(show_component(Port, box_id, req['port_id']).data.decode('utf-8')) + req['name'] = port['name'] + "/" + str(len(port['interfaces']) + 1) + elif 'chan_id' in req: + channel = json.loads(show_component(Channel, box_id, req['chan_id']).data.decode('utf-8')) + req['name'] = channel['name'] + "/" + str(len(channel['interfaces']) + 1) + elif 'logport_id' in req: + logport = json.loads(show_component(LogPort, box_id, req['logport_id']).data.decode('utf-8')) + req['name'] = logport['name'] + "/" + str(len(logport['interfaces']) + 1) + else: + raise exceptions.Forbidden('can not have port and channel as parent') + elif box['vendor'] == 'EdgeCore': + port = json.loads(show_component(Port, box_id, req['port_id']).data.decode('utf-8')) + req['name'] = port['name'] + response = new_component(InterfaceSchema(), Interface, req, box_id) + return response, 201 + + +@app.route(PREFIX + '/boxen//interfaces/', methods=['PUT']) +def update_interface(box_id, id): + req = flask.request.json + update_component(Interface, req, box_id, id) + return flask.Response(status=200) + + +@app.route(PREFIX + '/boxen//interfaces/', methods=['DELETE']) +def del_interface(box_id, id): + del_component(Interface, box_id, id) + return flask.Response(status=204) diff --git a/nesi/softbox/api/views/logport_views.py b/nesi/softbox/api/views/logport_views.py new file mode 100644 index 0000000..81b49c8 --- /dev/null +++ b/nesi/softbox/api/views/logport_views.py @@ -0,0 +1,53 @@ +# This file is part of the NESi software. +# +# Copyright (c) 2020 +# Original Software Design by Ilya Etingof . +# +# Software adapted by inexio . +# - Janis Groß +# - Philip Konrath +# - Alexander Dincher +# +# License: https://github.com/inexio/NESi/LICENSE.rst + +from .base_views import * +from ..schemas.logport_schemas import * + +PREFIX = '/nesi/v1' + + +@app.route(PREFIX + '/boxen//logports', methods=['GET']) +def show_logports(box_id): + if flask.request.args is None: + req = {} + else: + req = flask.request.args + + response = show_components(LogPortsSchema(), LogPort, req, box_id) + return response, 200 + + +@app.route(PREFIX + '/boxen//logports/', methods=['GET']) +def show_logport(box_id, id): + response = show_component(LogPort, box_id, id) + return response, 200 + + +@app.route(PREFIX + '/boxen//logports', methods=['POST']) +def new_logport(box_id): + req = flask.request.json + response = new_component(LogPortSchema(), LogPort, req, box_id) + return response, 201 + + +@app.route(PREFIX + '/boxen//logports/', methods=['PUT']) +def update_logport(box_id, id): + req = flask.request.json + update_component(LogPort, req, box_id, id) + return flask.Response(status=200) + + +@app.route(PREFIX + '/boxen//logports/', methods=['DELETE']) +def del_logport(box_id, id): + del_component(LogPort, box_id, id) + return flask.Response(status=204) diff --git a/nesi/softbox/api/views/mgmt_card_views.py b/nesi/softbox/api/views/mgmt_card_views.py new file mode 100644 index 0000000..9167f9a --- /dev/null +++ b/nesi/softbox/api/views/mgmt_card_views.py @@ -0,0 +1,78 @@ +# This file is part of the NESi software. +# +# Copyright (c) 2020 +# Original Software Design by Ilya Etingof . +# +# Software adapted by inexio . +# - Janis Groß +# - Philip Konrath +# - Alexander Dincher +# - Philipp-Noah Groß +# +# License: https://github.com/inexio/NESi/LICENSE.rst + +import re + +from .base_views import * +from .box_views import show_box +from ..models.mgmt_card_models import MgmtCard +from ..models.subrack_models import Subrack +from ..schemas.mgmt_card_schemas import * + +PREFIX = '/nesi/v1' + + +@app.route(PREFIX + '/boxen//mgmt_cards', methods=['GET']) +def show_mgmt_cards(box_id): + if flask.request.args is None: + req = {} + else: + req = flask.request.args + + response = show_components(MgmtCardsSchema(), MgmtCard, req, box_id) + return response, 200 + + +@app.route(PREFIX + '/boxen//mgmt_cards/', methods=['GET']) +def show_mgmt_card(box_id, id): + response = show_component(MgmtCard, box_id, id) + return response, 200 + + +@app.route(PREFIX + '/boxen//mgmt_cards', methods=['POST']) +def new_mgmt_card(box_id): + req = flask.request.json + + box = json.loads(show_box(box_id)[0].data.decode('utf-8')) + subrack = json.loads(show_component(Subrack, box_id, req['subrack_id']).data.decode('utf-8')) + if 'name' not in req or req['name'] == '' or req['name'] not in ('11', '13'): + if box['vendor'] == 'KeyMile': + card11_exists = False + card13_exists = False + for card in subrack['mgmt_cards']: + if card['name'] == '11': + card11_exists = True + elif card['name'] == '13': + card13_exists = True + if not card11_exists: + req['name'] = '11' + elif not card13_exists: + req['name'] = '13' + else: + return flask.Response(status=500) + + response = new_component(MgmtCardSchema(), MgmtCard, req, box_id) + return response, 201 + + +@app.route(PREFIX + '/boxen//mgmt_cards/', methods=['PUT']) +def update_mgmt_card(box_id, id): + req = flask.request.json + update_component(MgmtCard, req, box_id, id) + return flask.Response(status=200) + + +@app.route(PREFIX + '/boxen//mgmt_cards/', methods=['DELETE']) +def del_mgmt_card(box_id, id): + del_component(MgmtCard, box_id, id) + return flask.Response(status=204) diff --git a/nesi/softbox/api/views/mgmt_port_views.py b/nesi/softbox/api/views/mgmt_port_views.py new file mode 100644 index 0000000..b7ec236 --- /dev/null +++ b/nesi/softbox/api/views/mgmt_port_views.py @@ -0,0 +1,66 @@ +# This file is part of the NESi software. +# +# Copyright (c) 2020 +# Original Software Design by Ilya Etingof . +# +# Software adapted by inexio . +# - Janis Groß +# - Philip Konrath +# - Alexander Dincher +# - Philipp-Noah Groß +# +# License: https://github.com/inexio/NESi/LICENSE.rst + +from .base_views import * +from .box_views import show_box +from ..models.mgmt_card_models import MgmtCard +from ..schemas.mgmt_port_schemas import * + +PREFIX = '/nesi/v1' + + +@app.route(PREFIX + '/boxen//mgmt_ports', methods=['GET']) +def show_mgmt_ports(box_id): + if flask.request.args is None: + req = {} + else: + req = flask.request.args + + response = show_components(MgmtPortsSchema(), MgmtPort, req, box_id) + return response, 200 + + +@app.route(PREFIX + '/boxen//mgmt_ports/', methods=['GET']) +def show_mgmt_port(box_id, id): + response = show_component(MgmtPort, box_id, id) + return response, 200 + + +@app.route(PREFIX + '/boxen//mgmt_ports', methods=['POST']) +def new_mgmt_port(box_id): + req = flask.request.json + + mgmt_card = json.loads(show_component(MgmtCard, box_id, req['mgmt_card_id']).data.decode('utf-8')) + box = json.loads(show_box(box_id)[0].data.decode('utf-8')) + + if 'name' not in req or req['name'] == "": #TODO evtl. noch zu bearbeiten + if box['vendor'] == 'Huawei': + req['name'] = mgmt_card['name'] + "/" + str(len(mgmt_card['mgmt_ports'])) + else: + req['name'] = mgmt_card['name'] + "/" + str(len(mgmt_card['mgmt_ports']) + 1) + + response = new_component(MgmtPortSchema(), MgmtPort, req, box_id) + return response, 201 + + +@app.route(PREFIX + '/boxen//mgmt_ports/', methods=['PUT']) +def update_mgmt_port(box_id, id): + req = flask.request.json + update_component(MgmtPort, req, box_id, id) + return flask.Response(status=200) + + +@app.route(PREFIX + '/boxen//mgmt_ports/', methods=['DELETE']) +def del_mgmt_port(box_id, id): + del_component(MgmtPort, box_id, id) + return flask.Response(status=204) diff --git a/nesi/softbox/api/views/portgroupport_views.py b/nesi/softbox/api/views/portgroupport_views.py new file mode 100644 index 0000000..3f452a3 --- /dev/null +++ b/nesi/softbox/api/views/portgroupport_views.py @@ -0,0 +1,53 @@ +# This file is part of the NESi software. +# +# Copyright (c) 2020 +# Original Software Design by Ilya Etingof . +# +# Software adapted by inexio . +# - Janis Groß +# - Philip Konrath +# - Alexander Dincher +# +# License: https://github.com/inexio/NESi/LICENSE.rst + +from .base_views import * +from ..schemas.portgroupport_schemas import * + +PREFIX = '/nesi/v1' + + +@app.route(PREFIX + '/boxen//portgroupports', methods=['GET']) +def show_portgroupports(box_id): + if flask.request.args is None: + req = {} + else: + req = flask.request.args + + response = show_components(PortGroupPortsSchema(), PortGroupPort, req, box_id) + return response, 200 + + +@app.route(PREFIX + '/boxen//portgroupports/', methods=['GET']) +def show_portgroupport(box_id, id): + response = show_component(PortGroupPort, box_id, id) + return response, 200 + + +@app.route(PREFIX + '/boxen//portgroupports/', methods=['PUT']) +def update_portgroupport(box_id, id): + req = flask.request.json + update_component(PortGroupPort, req, box_id, id) + return flask.Response(status=200) + + +@app.route(PREFIX + '/boxen//portgroupports', methods=['POST']) +def new_portgroupport(box_id): + req = flask.request.json + response = new_component(PortGroupPortSchema(), PortGroupPort, req, box_id) + return response, 201 + + +@app.route(PREFIX + '/boxen//portgroupports/', methods=['DELETE']) +def del_portgroupport(box_id, id): + del_component(PortGroupPort, box_id, id) + return flask.Response(status=204) diff --git a/nesi/softbox/api/views/srvc_views.py b/nesi/softbox/api/views/srvc_views.py new file mode 100644 index 0000000..3315341 --- /dev/null +++ b/nesi/softbox/api/views/srvc_views.py @@ -0,0 +1,67 @@ +# This file is part of the NESi software. +# +# Copyright (c) 2020 +# Original Software Design by Ilya Etingof . +# +# Software adapted by inexio . +# - Janis Groß +# - Philip Konrath +# - Alexander Dincher +# - Philipp-Noah Groß +# +# License: https://github.com/inexio/NESi/LICENSE.rst + +from .base_views import * +from ..schemas.srvc_schemas import * + +PREFIX = '/nesi/v1' + + +@app.route(PREFIX + '/boxen//srvcs', methods=['GET']) +def show_srvcs(box_id): + if flask.request.args is None: + req = {} + else: + req = flask.request.args + + response = show_components(SrvcsSchema(), Srvc, req, box_id) + return response, 200 + + +@app.route(PREFIX + '/boxen//srvcs/', methods=['GET']) +def show_srvc(box_id, id): + response = show_component(Srvc, box_id, id) + return response, 200 + + +@app.route(PREFIX + '/boxen//srvcs/', methods=['PUT']) +def update_srvc(box_id, id): + req = flask.request.json + update_component(Srvc, req, box_id, id) + return flask.Response(status=200) + + +@app.route(PREFIX + '/boxen//srvcs', methods=['POST']) +def new_srvc(box_id): + req = flask.request.json + + if 'name' not in req or req['name'] == "": + srvcs = json.loads(show_components(SrvcsSchema(), Srvc, req={'service_type': req['service_type']}, box_id=box_id).data.decode('utf-8')) + last_srvc = None + for s in srvcs['members']: + last_srvc = s + + if last_srvc is not None: + _, num = last_srvc['name'].split('-') + req['name'] = 'srvc-' + str(int(num)+1) + else: + req['name'] = 'srvc-1' + + response = new_component(SrvcSchema(), Srvc, req, box_id) + return response, 201 + + +@app.route(PREFIX + '/boxen//srvcs/', methods=['DELETE']) +def del_srvc(box_id, id): + del_component(Srvc, box_id, id) + return flask.Response(status=204) diff --git a/nesi/softbox/api/views/subscriber_views.py b/nesi/softbox/api/views/subscriber_views.py new file mode 100644 index 0000000..545d218 --- /dev/null +++ b/nesi/softbox/api/views/subscriber_views.py @@ -0,0 +1,56 @@ +# This file is part of the NESi software. +# +# Copyright (c) 2020 +# Original Software Design by Ilya Etingof . +# +# Software adapted by inexio . +# - Janis Groß +# - Philip Konrath +# - Alexander Dincher +# +# License: https://github.com/inexio/NESi/LICENSE.rst + +from .base_views import * +from ..schemas.subscriber_schemas import * +from ..models.portgroupport_models import PortGroupPort + +PREFIX = '/nesi/v1' + + +@app.route(PREFIX + '/boxen//subscribers', methods=['GET']) +def show_subscribers(box_id): + if flask.request.args is None: + req = {} + else: + req = flask.request.args + + response = show_components(SubscribersSchema(), Subscriber, req, box_id) + return response, 200 + + +@app.route(PREFIX + '/boxen//subscribers/', methods=['GET']) +def show_subscriber(box_id, id): + response = show_component(Subscriber, box_id, id) + return response, 200 + + +@app.route(PREFIX + '/boxen//subscribers/', methods=['PUT']) +def update_subscriber(box_id, id): + req = flask.request.json + update_component(Subscriber, req, box_id, id) + return flask.Response(status=200) + + +@app.route(PREFIX + '/boxen//subscribers', methods=['POST']) +def new_subscriber(box_id): + req = flask.request.json + portgroupport = json.loads(show_component(PortGroupPort, box_id, req['portgroupport_id']).data.decode('utf-8')) + req['address'] = '/portgroup-' + portgroupport['name'].split('/')[1][1:] + '/port-' + portgroupport['name'].split('/')[2] + response = new_component(SubscriberSchema(), Subscriber, req, box_id) + return response, 201 + + +@app.route(PREFIX + '/boxen//subscribers/', methods=['DELETE']) +def del_subscriber(box_id, id): + del_component(Subscriber, box_id, id) + return flask.Response(status=204) diff --git a/nesi/softbox/base_resources/box.py b/nesi/softbox/base_resources/box.py index df93d87..006e1a5 100644 --- a/nesi/softbox/base_resources/box.py +++ b/nesi/softbox/base_resources/box.py @@ -56,6 +56,12 @@ class Box(base.Resource): mgmt_address = base.Field('mgmt_address') """Management IP address""" + net_mask = base.Field('net_mask') + """Network Mask of the device""" + + default_gateway = base.Field('default_gateway') + """Default network gateway of the device""" + software_version = base.Field('software_version') """Software Version""" @@ -75,6 +81,18 @@ def set_hostname(self, name): """Change the hostname value.""" self.update(hostname=name) + def set_mgmt_address(self, ip): + """Change the mgmt_address value.""" + self.update(mgmt_address=ip) + + def set_net_mask(self, mask): + """Change the net_mask value.""" + self.update(net_mask=mask) + + def set_default_gateway(self, gateway): + """Change the default_gateway value.""" + self.update(default_gateway=gateway) + def set_last_login(self, time): """Change last_login value.""" self.update(last_login=time) @@ -113,10 +131,6 @@ def vlans(self): def service_vlans(self): raise PropertyNotFoundError("abstract service_vlans properties") - @property - def vlans_connections(self): - raise PropertyNotFoundError("abstract vlans properties") - @property def port_profiles(self): raise PropertyNotFoundError("abstract port_profiles properties") diff --git a/nesi/softbox/base_resources/card.py b/nesi/softbox/base_resources/card.py index 2de330b..93df665 100644 --- a/nesi/softbox/base_resources/card.py +++ b/nesi/softbox/base_resources/card.py @@ -7,6 +7,7 @@ # - Janis Groß # - Philip Konrath # - Alexander Dincher +# - Philipp-Noah Groß # # License: https://github.com/inexio/NESi/LICENSE.rst diff --git a/nesi/softbox/base_resources/credentials.py b/nesi/softbox/base_resources/credentials.py index dc48bd6..271f97d 100644 --- a/nesi/softbox/base_resources/credentials.py +++ b/nesi/softbox/base_resources/credentials.py @@ -21,6 +21,7 @@ class Credentials(base.Resource): """Represent user credentials.""" id = base.Field('id') + user_id = base.Field('user_id') protocol = base.Field('protocol') username = base.Field('username') password = base.Field('password') diff --git a/nesi/softbox/base_resources/interface.py b/nesi/softbox/base_resources/interface.py new file mode 100644 index 0000000..a95d664 --- /dev/null +++ b/nesi/softbox/base_resources/interface.py @@ -0,0 +1,33 @@ +# This file is part of the NESi software. +# +# Copyright (c) 2020 +# Original Software Design by Ilya Etingof . +# +# Software adapted by inexio . +# - Janis Groß +# - Philip Konrath +# - Alexander Dincher +# +# License: https://github.com/inexio/NESi/LICENSE.rst + +import logging + +from nesi.softbox.base_resources import base + +LOG = logging.getLogger(__name__) + + +class Interface(base.Resource): + """Represent logical interface resource.""" + + id = base.Field('id') + name = base.Field('name') + description = base.Field('description') + + +class InterfaceCollection(base.ResourceCollection): + """Represent a collection of interfaces.""" + + @property + def _resource_type(self): + return Interface diff --git a/nesi/softbox/base_resources/mgmt_card.py b/nesi/softbox/base_resources/mgmt_card.py new file mode 100644 index 0000000..09c9273 --- /dev/null +++ b/nesi/softbox/base_resources/mgmt_card.py @@ -0,0 +1,51 @@ +# This file is part of the NESi software. +# +# Copyright (c) 2020 +# Original Software Design by Ilya Etingof . +# +# Software adapted by inexio . +# - Janis Groß +# - Philip Konrath +# - Alexander Dincher +# - Philipp-Noah Groß +# +# License: https://github.com/inexio/NESi/LICENSE.rst + +import logging + +from nesi.softbox.base_resources import base + +LOG = logging.getLogger(__name__) + + +class MgmtCard(base.Resource): + """Represent physical shelf resource.""" + id = base.Field('id') + name = base.Field('name') + description = base.Field('description') + admin_state = base.Field('admin_state') + operational_state = base.Field('operational_state') + + def admin_up(self): + """Set the admin port state to up""" + self.update(admin_state='1') + + def admin_down(self): + """Set the admin port state to down""" + self.update(admin_state='0') + + def down(self): + """Set the port state to down""" + self.update(operational_state='0') + + def up(self): + """Set the port state to down""" + self.update(operational_state='1') + + +class MgmtCardCollection(base.ResourceCollection): + """Represent a collection of cards.""" + + @property + def _resource_type(self): + return MgmtCard diff --git a/nesi/softbox/base_resources/mgmt_port.py b/nesi/softbox/base_resources/mgmt_port.py new file mode 100644 index 0000000..176e161 --- /dev/null +++ b/nesi/softbox/base_resources/mgmt_port.py @@ -0,0 +1,55 @@ + +# This file is part of the NESi software. +# +# Copyright (c) 2020 +# Original Software Design by Ilya Etingof . +# +# Software adapted by inexio . +# - Janis Groß +# - Philip Konrath +# - Alexander Dincher +# - Philipp-Noah Groß +# +# License: https://github.com/inexio/NESi/LICENSE.rst + +import logging + +from nesi.softbox.base_resources import base + +LOG = logging.getLogger(__name__) + + +class MgmtPort(base.Resource): + """Represent physical port resource.""" + + id = base.Field('id') + name = base.Field('name') + box_id = base.Field('box_id') + card_id = base.Field('card_id') + description = base.Field('description') + admin_state = base.Field('admin_state') + operational_state = base.Field('operational_state') + + def admin_up(self): + """Set the admin port state to up""" + self.update(admin_state='1') + + def admin_down(self): + """Set the admin port state to down""" + self.update(admin_state='0') + + def down(self): + """Set the port state to down""" + self.update(operational_state='0') + + def up(self): + """Set the port state to up""" + self.update(operational_state='1') + + +class MgmtPortCollection(base.ResourceCollection): + """Represent a collection of management ports.""" + + @property + def _resource_type(self): + return MgmtPort diff --git a/nesi/softbox/base_resources/user.py b/nesi/softbox/base_resources/user.py index a82a0eb..9e13703 100644 --- a/nesi/softbox/base_resources/user.py +++ b/nesi/softbox/base_resources/user.py @@ -20,8 +20,9 @@ class User(base.Resource): """Represents a logical User resource""" id = base.Field('id') - credentials_id = base.Field('credentials_id') name = base.Field('name') + status = base.Field('status') + lock_status = base.Field('lock_status') class UserCollection(base.ResourceCollection): diff --git a/nesi/softbox/cli/base.py b/nesi/softbox/cli/base.py index c69e2d6..f39c52e 100644 --- a/nesi/softbox/cli/base.py +++ b/nesi/softbox/cli/base.py @@ -18,6 +18,7 @@ import jinja2 from nesi import exceptions +from twisted.internet import reactor LOG = logging.getLogger(__name__) @@ -45,11 +46,12 @@ class CommandProcessor: """ def __init__(self, model, input_stream, output_stream, history, - template_root=None, scopes=(), daemon=False): + template_root=None, scopes=(), daemon=False, parent=None, case_sensitive=True): self._model = model self._input = input_stream self._output = output_stream self._scopes = scopes + self._parent = parent self._template_root = template_root self._template_dir = os.path.join( template_root, *scopes) @@ -61,9 +63,12 @@ def __init__(self, model, input_stream, output_stream, history, self.daemon = daemon # CLI specific attributes + self.skipLogin = False + self.case_sensitive = case_sensitive self.line_buffer = [] self.history_enabled = True self.hide_input = False + self.star_input = False self.history_pos = 0 self.history = history self.prompt_end_pos = self.get_prompt_len() - 1 @@ -113,10 +118,22 @@ def move_right(self): self.cursor_pos += 1 def get(self): - inkey = self._Getch() + inkey = None + if not self.daemon: + inkey = self._Getch() while (1): - k = inkey(self._input).decode('utf-8') - if k != '': break + if self.daemon: + k = self._input.receiveData().decode('utf-8') + if k == '\r\n' or k == '\n\r': + k = '\r' + if '\r\n' in k or '\n\r' in k: + k = k.replace('\n', '') + elif '\n' in k: + k = k.replace('\n', '\r') + else: + k = inkey(self._input).decode('utf-8') + if k != '': + break if k == '\x1b[A': # up-arrow if self.history_enabled: return 'history', self.history_up() @@ -138,7 +155,7 @@ def get(self): return 'backspace', '' else: return None, None - elif k == '[3': # del-key + elif k == '[3' or k == '[3~': # del-key return 'del', '' elif k == '': # ctrl-v return 'paste', pyperclip.paste() @@ -164,15 +181,16 @@ def updateline(self, line): self._write('\033[' + str(self.cursor_pos) + 'C') # move cursor to correct position def getline(self, tmp_boundary=None): - char = None + char = '' line = '' self.history_pos = len(self.history) self.cursor_pos = self.prompt_end_pos + 1 self.cursor_boundary = self.prompt_end_pos + 1 - while char != '\r': + while '\r' not in char: option, char = self.get() if char is None: + char = '' continue elif char == '\r': continue @@ -209,7 +227,10 @@ def getline(self, tmp_boundary=None): break if not self.hide_input: - self.updateline(line) + out = line + if self.star_input: + out = len(line) * '*' + self.updateline(out) if line != '\r' and line != '' and self.history_enabled: self.history += (line.replace('\r', '').rstrip(),) @@ -257,15 +278,17 @@ def _default_command_handler(self, command, *args, context=None): self._write(text) def _read(self, tmp_boundary=None): - if self.daemon: + if self.daemon and self._model.network_protocol == 'telnet': line = self._input.readline().decode('utf-8') else: line = self.getline(tmp_boundary) - return line def _write(self, text): + text = text.replace('\n', '\r\n') self._output.write(text.encode('utf-8')) + #if self.daemon and self._model.network_protocol == 'ssh': + # reactor.iterate() def _get_command_func(self, line): if line.startswith(self.comment): @@ -275,8 +298,11 @@ def _get_command_func(self, line): command = args[0] args = args[1:] - if command == self.negation: - command += "_" + args.pop(0) + if self.case_sensitive is False: + command = command.lower() + + #if command == self.negation: + #command += "_" + args.pop(0) command = command.replace('-', '_') @@ -314,7 +340,7 @@ def _create_subprocessor(self, subprocessor, *scopes): return subprocessor( self._model, self._input, self._output, self.history, template_root=self._template_root, - scopes=scopes, daemon=self.daemon) + scopes=scopes, daemon=self.daemon, parent=self, case_sensitive=self.case_sensitive) def process_command(self, line, context): self._parse_and_execute_command(line, context) @@ -339,6 +365,9 @@ def loop(self, context=None, return_to=None, command=None): self.line_buffer = line.split('\r\n') continue context['raw_line'] = line + + #if self.daemon: + # self._write(line) # write line to stdout if box is in daemon mode else: line = command command = None @@ -346,9 +375,9 @@ def loop(self, context=None, return_to=None, command=None): try: self.process_command(line, context) - except exceptions.CommandSyntaxError as exc: - self.line_buffer = [] # manually clear buffer in case of exception - self.on_error(dict(context, command=exc.command)) + except (exceptions.CommandExecutionError, exceptions.CommandSyntaxError) as exc: + self.line_buffer = [] + self.write_error_message(context, exc.template, *exc.template_scopes) except exceptions.TerminalExitError as exc: self.line_buffer = [] # manually clear buffer in case of exception @@ -356,16 +385,27 @@ def loop(self, context=None, return_to=None, command=None): exc.return_to = return_to if not exc.return_to or exc.return_to == 'sysexit' or exc.return_to == 'sysreboot' or not isinstance(self, exc.return_to): + if self.daemon and self._model.network_protocol == 'ssh' and exc.return_to in ('sysexit', 'sysreboot'): + self._output.loseConnection() + reactor.iterate() + return raise exc # set prompt_len anew in case of prompt_len change in command-processor beneath self.set_prompt_end_pos(context) + if exc.command is not None: + command = exc.command + continue + # This is the first instance of the desired # CommandProcessor to unwind to, continuing self.on_cycle(context) self.on_exit(context) + def _terminate(self, command=None): + del self + def get_prompt_len(self): text = self._render('on_cycle', context=dict(), ignore_errors=True) @@ -382,7 +422,7 @@ def get_prompt_len(self): def set_prompt_end_pos(self, context): text = self._render('on_cycle', context=context, ignore_errors=True) - if len(text) == 0: + if text is None or len(text) == 0: text = self._render('on_enter', context=context, ignore_errors=True) self.prompt_end_pos = len(text.replace('\n', '')) - 1 @@ -407,6 +447,13 @@ def on_error(self, context): if text is not None: self._write(text) + def write_error_message(self, context, template, *scopes): + if template is None: + template = 'on_error' + text = self._render(template, context=context, *scopes, ignore_errors=True) + if text is not None: + self._write(text) + @property def comment(self): return '!' @@ -425,6 +472,11 @@ def _dissect(self, args, *tokens): except IndexError: raise exceptions.CommandSyntaxError(command=' '.join(args)) + if self.case_sensitive is False: + if not isinstance(token, type): + arg = arg.lower() + token = token.lower() + if type(token) == type: values.append(arg) @@ -443,6 +495,11 @@ def _validate(self, args, *tokens): except IndexError: return False + if self.case_sensitive is False: + if not isinstance(token, type): + arg = arg.lower() + token = token.lower() + if arg != token and type(token) != type: return False diff --git a/requirements.txt b/requirements.txt index 5038a59..ba89e83 100644 --- a/requirements.txt +++ b/requirements.txt @@ -9,3 +9,7 @@ pydevd-pycharm~=201.7846.77 psutil pytest pyperclip +twisted +cryptography +bcrypt +pyasn1 diff --git a/templates/EdgeCore/login/mainloop/?.j2 b/templates/EdgeCore/login/mainloop/?.j2 new file mode 100644 index 0000000..a184270 --- /dev/null +++ b/templates/EdgeCore/login/mainloop/?.j2 @@ -0,0 +1,14 @@ +EXEC commands: + disable Returns to normal mode from privileged mode + disconnect Terminates an SSH, Telnet, or a console connection + enable Turns on privileged commands + exit Exits from privileged EXEC mode + help Description of the interactive help system + ping Sends ICMP echo request packets to another host + ping6 Sends ICMPv6 echo request packets to another host + quit Exits a CLI session + show Shows information + terminal Terminal setting + traceroute Traces routing path + traceroute6 Traces routing path + diff --git a/templates/EdgeCore/login/mainloop/enable/?.j2 b/templates/EdgeCore/login/mainloop/enable/?.j2 new file mode 100644 index 0000000..4b455cf --- /dev/null +++ b/templates/EdgeCore/login/mainloop/enable/?.j2 @@ -0,0 +1,43 @@ +EXEC commands: + auto-traffic-control Auto traffic control configuration + calendar Date and time information + clear Resets functions + configure Enters configuration mode + copy Copies from one file to another + debug Debugging functions + delete Deletes a file + dir Lists files on the file system + disable Returns to normal mode from privileged mode + disconnect Terminates an SSH, Telnet, or a console connection + dot1x Configures 802.1X port-based access control + efm Ethernet First Mile feature + enable Turns on privileged commands + erps Ethernet Ring Protection Switching + ethernet Metro Ethernet + exit Exits from privileged EXEC mode + hardware Hardware ralated functions + help Description of the interactive help system + ip Internet protocol + ipv6 IPv6 configuration commands + loopback-detection Performs loopback detection privileged operations + no Negates a command or sets its defaults + ping Sends ICMP echo request packets to another host + ping6 Sends ICMPv6 echo request packets to another host + port Configures the characteristics of the port + quit Exits a CLI session + rcommand telnet to member + reload Halts and performs a warm restart + sflow Configures sFlow + show Shows information + smart-pair Specifies a smart pair + spanning-tree Specifies spanning-tree configuration + telnet Telnet to a specified host + terminal Terminal setting + test Tests subsystem + traceroute Traces routing path + traceroute6 Traces routing path + transceiver-eeprom Access transceiver EEPROM data + watchdog Configures watchdog setting + web-auth Configures web authentication parameters + whichboot Shows which files booted on system power up + diff --git a/templates/EdgeCore/login/mainloop/enable/config/interface/on_cycle.j2 b/templates/EdgeCore/login/mainloop/enable/config/interface/on_cycle.j2 new file mode 100644 index 0000000..7496ed2 --- /dev/null +++ b/templates/EdgeCore/login/mainloop/enable/config/interface/on_cycle.j2 @@ -0,0 +1 @@ +{{ model.hostname }}(config-if)# diff --git a/templates/EdgeCore/login/mainloop/enable/config/interface/on_error.j2 b/templates/EdgeCore/login/mainloop/enable/config/interface/on_error.j2 new file mode 100644 index 0000000..d965dc6 --- /dev/null +++ b/templates/EdgeCore/login/mainloop/enable/config/interface/on_error.j2 @@ -0,0 +1,3 @@ + ^ +% Invalid input detected at '^' marker. + diff --git a/templates/EdgeCore/login/mainloop/enable/config/on_cycle.j2 b/templates/EdgeCore/login/mainloop/enable/config/on_cycle.j2 new file mode 100644 index 0000000..ece1f7f --- /dev/null +++ b/templates/EdgeCore/login/mainloop/enable/config/on_cycle.j2 @@ -0,0 +1 @@ +{{ model.hostname }}(config)# diff --git a/templates/EdgeCore/login/mainloop/enable/config/on_error.j2 b/templates/EdgeCore/login/mainloop/enable/config/on_error.j2 new file mode 100644 index 0000000..d965dc6 --- /dev/null +++ b/templates/EdgeCore/login/mainloop/enable/config/on_error.j2 @@ -0,0 +1,3 @@ + ^ +% Invalid input detected at '^' marker. + diff --git a/templates/EdgeCore/login/mainloop/enable/config/vlan/on_cycle.j2 b/templates/EdgeCore/login/mainloop/enable/config/vlan/on_cycle.j2 new file mode 100644 index 0000000..7c17cd7 --- /dev/null +++ b/templates/EdgeCore/login/mainloop/enable/config/vlan/on_cycle.j2 @@ -0,0 +1 @@ +{{ model.hostname }}(config-vlan)# diff --git a/templates/EdgeCore/login/mainloop/enable/config/vlan/on_error.j2 b/templates/EdgeCore/login/mainloop/enable/config/vlan/on_error.j2 new file mode 100644 index 0000000..e13e225 --- /dev/null +++ b/templates/EdgeCore/login/mainloop/enable/config/vlan/on_error.j2 @@ -0,0 +1,3 @@ + ^ +% Invalid input detected at '^' marker. + diff --git a/templates/EdgeCore/login/mainloop/enable/copy_startup_config_ftp_failure.j2 b/templates/EdgeCore/login/mainloop/enable/copy_startup_config_ftp_failure.j2 new file mode 100644 index 0000000..639e9d9 --- /dev/null +++ b/templates/EdgeCore/login/mainloop/enable/copy_startup_config_ftp_failure.j2 @@ -0,0 +1,3 @@ +Failed to connect to server. +Error. + diff --git a/templates/EdgeCore/login/mainloop/enable/copy_startup_config_ftp_success.j2 b/templates/EdgeCore/login/mainloop/enable/copy_startup_config_ftp_success.j2 new file mode 100644 index 0000000..ff46f1d --- /dev/null +++ b/templates/EdgeCore/login/mainloop/enable/copy_startup_config_ftp_success.j2 @@ -0,0 +1,4 @@ +Flash Programming started. +Flash Programming completed. +Success. + diff --git a/templates/EdgeCore/login/mainloop/enable/help.j2 b/templates/EdgeCore/login/mainloop/enable/help.j2 new file mode 100644 index 0000000..800b1a8 --- /dev/null +++ b/templates/EdgeCore/login/mainloop/enable/help.j2 @@ -0,0 +1,12 @@ +Help may be requested at any point in a command by entering +a question mark '?'. If nothing matches, the help list will +be empty and you must backup until entering a '?' shows the +available options. +Two styles of help are provided: +1. Full help is available when you are ready to enter a + command argument (e.g. 'show ?') and describes each possible + argument. +2. Partial help is provided when an abbreviated argument is entered + and you want to know what arguments match the input + (e.g. 'show br?'.) + diff --git a/templates/EdgeCore/login/mainloop/enable/on_cycle.j2 b/templates/EdgeCore/login/mainloop/enable/on_cycle.j2 new file mode 100644 index 0000000..d8fe528 --- /dev/null +++ b/templates/EdgeCore/login/mainloop/enable/on_cycle.j2 @@ -0,0 +1 @@ +{{ model.hostname }}# \ No newline at end of file diff --git a/templates/EdgeCore/login/mainloop/enable/on_error.j2 b/templates/EdgeCore/login/mainloop/enable/on_error.j2 new file mode 100644 index 0000000..d965dc6 --- /dev/null +++ b/templates/EdgeCore/login/mainloop/enable/on_error.j2 @@ -0,0 +1,3 @@ + ^ +% Invalid input detected at '^' marker. + diff --git a/templates/EdgeCore/login/mainloop/enable/show_?.j2 b/templates/EdgeCore/login/mainloop/enable/show_?.j2 new file mode 100644 index 0000000..036b300 --- /dev/null +++ b/templates/EdgeCore/login/mainloop/enable/show_?.j2 @@ -0,0 +1,92 @@ + access-group Access groups + access-list Access lists + accounting Uses the specified accounting list + arp Information of ARP cache + authorization Authorization configurations + auto-traffic-control Auto traffic control information + banner Banner info + bridge-ext Bridge extension information + cable-diagnostics Shows the information of cable diagnostics + calendar Date and time information + class-map Displays class maps + cluster Display cluster + debug State of each debugging option + discard Discard packet + dns DNS information + dos-protection Shows the system dos-protection summary information + dot1q-tunnel 802.1Q tunnel + dot1x 802.1X content + dying-gasp Dying gasp information + efm Ethernet First Mile feature + erps Displays ERPS configuration + ethernet Shows Metro Ethernet information + garp GARP properties + gvrp GVRP interface information + hardware Hardware ralated functions + history Shows history information + hosts Host information + interfaces Shows interface information + ip IP information + ipv6 IPv6 information + l2protocol-tunnel Layer 2 protocol tunneling configuration + lacp LACP statistics + line TTY line information + lldp LLDP + log Log records + logging Logging setting + loop Shows the information of loopback + loopback-detection Shows loopback detection information + mac MAC access list + mac-address-table Configuration of the address table + mac-vlan MAC-based VLAN information + management Shows management information + memory Memory utilization + mvr multicast VLAN registration + mvr6 IPv6 Multicast VLAN registration + network-access Shows the entries of the secure port + nlm Show notification log + ntp Network Time Protocol configuration + policy-map Displays policy maps + port Port characteristics + port-channel Port channel information + power Shows power + power-save Shows the power saving information + pppoe Displays PPPoE configuration + privilege Shows current privilege level + process Device process + protocol-vlan Protocol-VLAN information + public-key Public key information + qos Quality of Service + queue Priority queue information + radius-server RADIUS server information + reload Shows the reload settings + rmon Remote monitoring information + rspan Display status of the current RSPAN configuration + running-config Information on the running configuration + sflow Shows the sflow information + smart-pair Displays backup port information + snmp Simple Network Management Protocol configuration and + statistics + snmp-server Displays SNMP server configuration + sntp Simple Network Time Protocol configuration + spanning-tree Spanning-tree configuration + ssh Secure shell server connections + startup-config Startup system configuration + subnet-vlan IP subnet-based VLAN information + system System information + tacacs-server TACACS server information + tech-support Technical information + time-range Time range + traffic-segmentation Traffic segmentation information + transceiver-eeprom Access transceiver EEPROM data configuration + twamp TWAMP configuration, statistics and session information + udld Displays UDLD information + upgrade Shows upgrade information + users Information about users logged in + version System hardware and software versions + vlan Shows virtual LAN settings + vlan-translation VLAN translation information + voice Shows the voice VLAN information + watchdog Displays watchdog status + web-auth Shows web authentication configuration + diff --git a/templates/EdgeCore/login/mainloop/enable/show_interface_status.j2 b/templates/EdgeCore/login/mainloop/enable/show_interface_status.j2 new file mode 100644 index 0000000..456249d --- /dev/null +++ b/templates/EdgeCore/login/mainloop/enable/show_interface_status.j2 @@ -0,0 +1,29 @@ +Information of Eth {{ context.port.name }} + Basic Information: + Port Type : 1000BASE SFP + MAC Address : {{ context.port.mac_address }} +Configuration: + Name : {{ context.port.description }} + Port Admin : {{ context.port.admin_state }} + Speed-duplex : Auto + Capabilities : 1000full + Broadcast Storm : Disabled + Broadcast Storm Limit : 500 packets/second + Multicast Storm : Disabled + Multicast Storm Limit : 262143 packets/second + Unknown Unicast Storm : Disabled + Unknown Unicast Storm Limit : 262143 packets/second + Flow Control : Disabled + VLAN Trunking : Disabled + LACP : Disabled + MAC Learning : Enabled + Link-up-down Trap : Enabled + Media Type : None + MTU : 1518 +Current Status: + Link Status : {{ context.port.operational_state }} + Operation Speed-duplex : 1000full + Flow Control Type : None + Max Frame Size : 1518 bytes (1522 bytes for tagged frames) + MAC Learning Status : Enabled + diff --git a/templates/EdgeCore/login/mainloop/enable/show_interface_switchport.j2 b/templates/EdgeCore/login/mainloop/enable/show_interface_switchport.j2 new file mode 100644 index 0000000..ccf7204 --- /dev/null +++ b/templates/EdgeCore/login/mainloop/enable/show_interface_switchport.j2 @@ -0,0 +1,22 @@ +Information of Eth {{ context.interface.name }} + Broadcast Threshold : Enabled, 500 packets/second + Multicast Threshold : Disabled + Unknown Unicast Threshold : Disabled + LACP Status : Disabled + Ingress Rate Limit : {{ context.interface.ingress_state }}, {{ context.interface.ingress_rate }} kbits/second + Egress Rate Limit : {{ context.interface.egress_state }}, {{ context.interface.egress_rate }} kbits/second + VLAN Membership Mode : {{ context.interface.vlan_membership_mode }} + Ingress Rule : Disabled + Acceptable Frame Type : All frames + Native VLAN : {{ context.interface.native_vlan }} + Priority for Untagged Traffic : 0 + GVRP Status : Disabled + Allowed VLAN : {{ context.interface.allowed_vlan }} + Forbidden VLAN : + 802.1Q Tunnel Status : Disabled + 802.1Q Tunnel Mode : Normal + 802.1Q Tunnel TPID : 8100 (Hex) + Broadcast Block : Disabled + Unknown Multicast Block : Disabled + Unknown Unicast Block : Disabled + diff --git a/templates/EdgeCore/login/mainloop/enable/show_interface_transceiver.j2 b/templates/EdgeCore/login/mainloop/enable/show_interface_transceiver.j2 new file mode 100644 index 0000000..271b17d --- /dev/null +++ b/templates/EdgeCore/login/mainloop/enable/show_interface_transceiver.j2 @@ -0,0 +1,26 @@ +Information of Eth {{ context.port.name }} + Connector Type : LC + Fiber Type : Multimode 50um (M5), Multimode 62.5um (M6) + Eth Compliance Codes : 1000BASE-SX + Baud Rate : 2100 MBd + Vendor OUI : 00-90-65 + Vendor Name : FINISAR CORP. + Vendor PN : FTLF8519P2BNL + Vendor Rev : A + Vendor SN : PFS4U5F + Date Code : 09-07-02 +DDM Information + Temperature : 31.36 degree C + Vcc : 3.32 V + Bias Current : 25.61 mA + TX Power : -3.11 dBm + RX Power : -40.00 dBm +DDM Thresholds + Low Alarm Low Warning High Warning High Alarm + ----------- ------------ ------------ ------------ ------------ + Temperature(Celsius) -25.00 -20.00 90.00 95.00 + Voltage(Volts) 2.80 2.90 3.70 3.80 + Current(mA) 2.00 3.00 80.00 90.00 + TxPower(dBm) -7.96 -6.99 1.00 2.01 + RxPower(dBm) -20.00 -19.00 0.00 1.00 + diff --git a/templates/EdgeCore/login/mainloop/enable/show_mac_address_table.j2 b/templates/EdgeCore/login/mainloop/enable/show_mac_address_table.j2 new file mode 100644 index 0000000..82e2ff6 --- /dev/null +++ b/templates/EdgeCore/login/mainloop/enable/show_mac_address_table.j2 @@ -0,0 +1,3 @@ + Interface MAC Address VLAN Type Life Time + --------- ----------------- ---- -------- ----------------- + diff --git a/templates/EdgeCore/login/mainloop/enable/show_mac_address_table_entry.j2 b/templates/EdgeCore/login/mainloop/enable/show_mac_address_table_entry.j2 new file mode 100644 index 0000000..413ac00 --- /dev/null +++ b/templates/EdgeCore/login/mainloop/enable/show_mac_address_table_entry.j2 @@ -0,0 +1,2 @@ + Eth {{ context.interface.name }} {{ context.interface.mac_address }} {{ context.interface.native_vlan }} Learn Delete on Timeout + diff --git a/templates/EdgeCore/login/mainloop/enable/show_mac_address_table_unit.j2 b/templates/EdgeCore/login/mainloop/enable/show_mac_address_table_unit.j2 new file mode 100644 index 0000000..769a7e1 --- /dev/null +++ b/templates/EdgeCore/login/mainloop/enable/show_mac_address_table_unit.j2 @@ -0,0 +1,3 @@ + CPU {{ context.card.mac_address }} 1 CPU Delete on Reset + + diff --git a/templates/EdgeCore/login/mainloop/enable/show_memory.j2 b/templates/EdgeCore/login/mainloop/enable/show_memory.j2 new file mode 100644 index 0000000..a082ecb --- /dev/null +++ b/templates/EdgeCore/login/mainloop/enable/show_memory.j2 @@ -0,0 +1,10 @@ + Status Bytes % + ------ ---------- --- + Free 236236800 44 + Used 300634112 56 + Total 536870912 + +Alarm Configuration + Rising Threshold : 90% + Falling Threshold : 70% + diff --git a/templates/EdgeCore/login/mainloop/enable/show_process_cpu.j2 b/templates/EdgeCore/login/mainloop/enable/show_process_cpu.j2 new file mode 100644 index 0000000..fe6c2bb --- /dev/null +++ b/templates/EdgeCore/login/mainloop/enable/show_process_cpu.j2 @@ -0,0 +1,16 @@ + CPU Utilization in the past 5 seconds : 7% + + CPU Utilization in the past 60 seconds + Average Utilization : 8% + Maximum Utilization : 9% + + Alarm Status + Current Alarm Status : Off + Last Alarm Start Time : Jun 9 15:10:09 2011 + Last Alarm Duration Time : 10 seconds + + Alarm Configuration + Rising Threshold : 90% + Falling Threshold : 70% + + diff --git a/templates/EdgeCore/login/mainloop/enable/show_system.j2 b/templates/EdgeCore/login/mainloop/enable/show_system.j2 new file mode 100644 index 0000000..e9c9f14 --- /dev/null +++ b/templates/EdgeCore/login/mainloop/enable/show_system.j2 @@ -0,0 +1,28 @@ +System Description : {{ context.box.model }} +System OID String : 1.3.6.1.4.1.259.10.1.45.108 +System Information + System Up Time : 0 days, 5 hours, 44 minutes, and 42.28 seconds + System Name : + System Location : + System Contact : + MAC Address (Unit 1) : {{ context.card.mac_address }} + Web Server : Enabled + Web Server Port : 80 + Web Secure Server : Enabled + Web Secure Server Port : 443 + Telnet Server : Enabled + Telnet Server Port : 23 + Jumbo Frame : Disabled + +System Fan: + Force Fan Speed Full : Disabled +Unit 1 + Fan 1: Ok Fan 2: Ok + +System Temperature: +Unit 1 + Temperature 1: 35 degrees + +Unit 1 + Main Power Status : {{ context.card.admin_state }} + diff --git a/templates/EdgeCore/login/mainloop/enable_password.j2 b/templates/EdgeCore/login/mainloop/enable_password.j2 new file mode 100644 index 0000000..417a449 --- /dev/null +++ b/templates/EdgeCore/login/mainloop/enable_password.j2 @@ -0,0 +1,2 @@ +% Bad passwords + diff --git a/templates/EdgeCore/login/mainloop/help.j2 b/templates/EdgeCore/login/mainloop/help.j2 new file mode 100644 index 0000000..800b1a8 --- /dev/null +++ b/templates/EdgeCore/login/mainloop/help.j2 @@ -0,0 +1,12 @@ +Help may be requested at any point in a command by entering +a question mark '?'. If nothing matches, the help list will +be empty and you must backup until entering a '?' shows the +available options. +Two styles of help are provided: +1. Full help is available when you are ready to enter a + command argument (e.g. 'show ?') and describes each possible + argument. +2. Partial help is provided when an abbreviated argument is entered + and you want to know what arguments match the input + (e.g. 'show br?'.) + diff --git a/templates/EdgeCore/login/mainloop/on_cycle.j2 b/templates/EdgeCore/login/mainloop/on_cycle.j2 new file mode 100644 index 0000000..d9f093f --- /dev/null +++ b/templates/EdgeCore/login/mainloop/on_cycle.j2 @@ -0,0 +1 @@ +{{ model.hostname }}> \ No newline at end of file diff --git a/templates/EdgeCore/login/mainloop/on_enter.j2 b/templates/EdgeCore/login/mainloop/on_enter.j2 new file mode 100644 index 0000000..c148098 --- /dev/null +++ b/templates/EdgeCore/login/mainloop/on_enter.j2 @@ -0,0 +1,24 @@ +*************************************************************** +WARNING - MONITORED ACTIONS AND ACCESSES +FNT + + +Station's information: + + +Floor / Row / Rack / Sub-Rack + / / / +DC power supply: +Power Source A: Floor / Row / Rack / Electrical circuit + / / / + +Number of LP: +Position MUX: +IP LAN: {{ context.ip }} +Note: {{ context.name }} +MOTD: +*************************************************************** + + CLI session with the ECS4120-28Fv2-I is opened. + To end the CLI session, enter [Exit]. + diff --git a/templates/EdgeCore/login/mainloop/on_error.j2 b/templates/EdgeCore/login/mainloop/on_error.j2 new file mode 100644 index 0000000..d965dc6 --- /dev/null +++ b/templates/EdgeCore/login/mainloop/on_error.j2 @@ -0,0 +1,3 @@ + ^ +% Invalid input detected at '^' marker. + diff --git a/templates/EdgeCore/login/mainloop/show_?.j2 b/templates/EdgeCore/login/mainloop/show_?.j2 new file mode 100644 index 0000000..73ca696 --- /dev/null +++ b/templates/EdgeCore/login/mainloop/show_?.j2 @@ -0,0 +1,17 @@ + banner Banner info + calendar Date and time information + history Shows history information + interfaces Shows interface information + ip IP information + lacp LACP statistics + line TTY line information + memory Memory utilization + privilege Shows current privilege level + process Device process + public-key Public key information + snmp Simple Network Management Protocol configuration and statistics + system System information + users Information about users logged in + version System hardware and software versions + vlan Shows virtual LAN settings + diff --git a/templates/EdgeCore/login/on_cycle.j2 b/templates/EdgeCore/login/on_cycle.j2 new file mode 100644 index 0000000..e69de29 diff --git a/templates/EdgeCore/login/on_enter.j2 b/templates/EdgeCore/login/on_enter.j2 new file mode 100644 index 0000000..3adfb18 --- /dev/null +++ b/templates/EdgeCore/login/on_enter.j2 @@ -0,0 +1 @@ +>>User password: \ No newline at end of file diff --git a/templates/EdgeCore/login/password.j2 b/templates/EdgeCore/login/password.j2 new file mode 100644 index 0000000..a64789f --- /dev/null +++ b/templates/EdgeCore/login/password.j2 @@ -0,0 +1,2 @@ +Bad username or password + diff --git a/templates/EdgeCore/on_cycle.j2 b/templates/EdgeCore/on_cycle.j2 new file mode 100644 index 0000000..b24a03e --- /dev/null +++ b/templates/EdgeCore/on_cycle.j2 @@ -0,0 +1 @@ +>>User name: \ No newline at end of file diff --git a/templates/EdgeCore/on_enter.j2 b/templates/EdgeCore/on_enter.j2 new file mode 100644 index 0000000..e69de29 diff --git a/templates/EdgeCore/on_exit.j2 b/templates/EdgeCore/on_exit.j2 new file mode 100644 index 0000000..b900707 --- /dev/null +++ b/templates/EdgeCore/on_exit.j2 @@ -0,0 +1,4 @@ +% CLI exit session +Connection to {{ context.ip }} closed by remote host. +Connection to {{ context.ip }} closed. + diff --git a/templates/KeyMile/login/base/execution_errors/invalid_address_error.j2 b/templates/KeyMile/login/base/execution_errors/invalid_address_error.j2 new file mode 100644 index 0000000..e9423d2 --- /dev/null +++ b/templates/KeyMile/login/base/execution_errors/invalid_address_error.j2 @@ -0,0 +1,2 @@ +error: invalid address + diff --git a/templates/KeyMile/login/base/execution_errors/invalid_management_function_error.j2 b/templates/KeyMile/login/base/execution_errors/invalid_management_function_error.j2 new file mode 100644 index 0000000..c36472c --- /dev/null +++ b/templates/KeyMile/login/base/execution_errors/invalid_management_function_error.j2 @@ -0,0 +1,2 @@ +error: invalid management function + diff --git a/templates/KeyMile/login/base/execution_errors/invalid_property.j2 b/templates/KeyMile/login/base/execution_errors/invalid_property.j2 new file mode 100644 index 0000000..af8470b --- /dev/null +++ b/templates/KeyMile/login/base/execution_errors/invalid_property.j2 @@ -0,0 +1,2 @@ +error: invalid property + diff --git a/templates/KeyMile/login/base/execution_errors/unknown_service_fragment.j2 b/templates/KeyMile/login/base/execution_errors/unknown_service_fragment.j2 new file mode 100644 index 0000000..46fd889 --- /dev/null +++ b/templates/KeyMile/login/base/execution_errors/unknown_service_fragment.j2 @@ -0,0 +1,2 @@ +error: Unknown service fragment + diff --git a/templates/KeyMile/login/base/get/actual_status.j2 b/templates/KeyMile/login/base/get/actual_status.j2 new file mode 100644 index 0000000..97fd17a --- /dev/null +++ b/templates/KeyMile/login/base/get/actual_status.j2 @@ -0,0 +1,5 @@ + \ # OverallLinePayloadRate + \ # PayloadRate +0 \ # CurrentOverallPayloadRate +0 \ # AttainableOverallPayloadRate + diff --git a/templates/KeyMile/login/base/get/administrative_status.j2 b/templates/KeyMile/login/base/get/administrative_status.j2 new file mode 100644 index 0000000..62715fa --- /dev/null +++ b/templates/KeyMile/login/base/get/administrative_status.j2 @@ -0,0 +1,3 @@ + \ # AdministrativeStatus +{{ context.port.admin_state }}{{ context.spacer }}\ # State + diff --git a/templates/KeyMile/login/base/get/attainable_rate.j2 b/templates/KeyMile/login/base/get/attainable_rate.j2 new file mode 100644 index 0000000..e5eb709 --- /dev/null +++ b/templates/KeyMile/login/base/get/attainable_rate.j2 @@ -0,0 +1,4 @@ + \ # AttainableRate +{{ context.port.downstream }}{{ context.spacer1 }}\ # Downstream +{{ context.port.upstream }}{{ context.spacer2 }}\ # Upstream + diff --git a/templates/KeyMile/login/base/get/chan_profile.j2 b/templates/KeyMile/login/base/get/chan_profile.j2 new file mode 100644 index 0000000..c60d36c --- /dev/null +++ b/templates/KeyMile/login/base/get/chan_profile.j2 @@ -0,0 +1,3 @@ + \ # ChannelProfile +{{ context.profile_name }}{{ context.spacer1 }}\ # Name + diff --git a/templates/KeyMile/login/base/get/configured_profiles.j2 b/templates/KeyMile/login/base/get/configured_profiles.j2 new file mode 100644 index 0000000..ae4c784 --- /dev/null +++ b/templates/KeyMile/login/base/get/configured_profiles.j2 @@ -0,0 +1,6 @@ + \ # configuredProfiles + \ # vccProfile +{{ context.vcc.vcc_profile }}{{ context.spacer1 }}\ # name + \ # vlanProfile +{{ context.vcc.vlan_profile }}{{ context.spacer2 }}\ # Name + diff --git a/templates/KeyMile/login/base/get/currTemperature.j2 b/templates/KeyMile/login/base/get/currTemperature.j2 new file mode 100644 index 0000000..95d1608 --- /dev/null +++ b/templates/KeyMile/login/base/get/currTemperature.j2 @@ -0,0 +1,3 @@ + \ # Current +{{ context.currTemperature }}{{ context.spacer }}\ # Temperature + diff --git a/templates/KeyMile/login/base/get/current_status.j2 b/templates/KeyMile/login/base/get/current_status.j2 new file mode 100644 index 0000000..2ea3cef --- /dev/null +++ b/templates/KeyMile/login/base/get/current_status.j2 @@ -0,0 +1,8 @@ + \ # EquipmentStatus +{{ context.unit_state }}{{ context.spacer_1 }}\ # State +{{ context.unit_hardware | safe }}{{ context.spacer_2 }}\ # Hardware +{{ context.unit_software | safe }}{{ context.spacer_3 }}\ # Software +{{ context.unit_serial_number | safe }}{{ context.spacer_4 }}\ # SerialNumber +{{ context.unit_manufacturer_name | safe }}{{ context.spacer_5 }}\ # ManufacturerName +{{ context.unit_model_name | safe }}{{ context.spacer_6 }}\ # ModelName + diff --git a/templates/KeyMile/login/base/get/current_status_empty.j2 b/templates/KeyMile/login/base/get/current_status_empty.j2 new file mode 100644 index 0000000..73a5a02 --- /dev/null +++ b/templates/KeyMile/login/base/get/current_status_empty.j2 @@ -0,0 +1,8 @@ + \ # EquipmentStatus +Empty \ # State +"" \ # Hardware +"" \ # Software +"" \ # SerialNumber +"" \ # ManufacturerName +"" \ # ModelName + diff --git a/templates/KeyMile/login/base/get/ddm_status.j2 b/templates/KeyMile/login/base/get/ddm_status.j2 new file mode 100644 index 0000000..6cf2a61 --- /dev/null +++ b/templates/KeyMile/login/base/get/ddm_status.j2 @@ -0,0 +1,8 @@ + \ # DdmStatus +Supported \ # DdmInterfaceSupport +35 \ # ModuleTemperature +3.34E0 \ # SupplyVoltage +0.0E0 \ # TxBiasCurrent +-9 \ # TxOutputPower +-40 \ # RxInputPower + diff --git a/templates/KeyMile/login/base/get/equipment_inventory.j2 b/templates/KeyMile/login/base/get/equipment_inventory.j2 new file mode 100644 index 0000000..6780cd1 --- /dev/null +++ b/templates/KeyMile/login/base/get/equipment_inventory.j2 @@ -0,0 +1,16 @@ + \ # EquipmentInventory +{{ context.unit_symbol | safe }}{{ context.spacer_1 }}\ # Symbol +{{ context.unit_short_text | safe }}{{ context.spacer_2 }}\ # ShortText +{{ context.unit_board_id }}{{ context.spacer_3 }}\ # BoardId +{{ context.unit_hardware_key }}{{ context.spacer_4 }}\ # HardwareKey +{{ context.unit_manufacturer_id | safe }}{{ context.spacer_5 }}\ # ManufacturerId +{{ context.unit_serial_number | safe }}{{ context.spacer_6 }}\ # ManufacturerSerialNumber +{{ context.unit_manufacturer_part_number | safe }}{{ context.spacer_7 }}\ # ManufacturerPartNumber +{{ context.unit_manufacturer_build_state | safe }}{{ context.spacer_8 }}\ # ManufacturerBuildState +{{ context.unit_supplier_part_number | safe }}{{ context.spacer_9 }}\ # SupplierPartNumber +{{ context.unit_supplier_build_state | safe }}{{ context.spacer_10 }}\ # SupplierBuildState +{{ context.unit_customer_id | safe }}{{ context.spacer_11 }}\ # CustomerId +{{ context.unit_customer_product_id | safe }}{{ context.spacer_12 }}\ # CustomerProductId +{{ context.unit_boot_loader | safe }}{{ context.spacer_13 }}\ # Bootloader +{{ context.unit_processor | safe }}{{ context.spacer_14 }}\ # Processor + diff --git a/templates/KeyMile/login/base/get/equipment_inventory_empty.j2 b/templates/KeyMile/login/base/get/equipment_inventory_empty.j2 new file mode 100644 index 0000000..d28b60d --- /dev/null +++ b/templates/KeyMile/login/base/get/equipment_inventory_empty.j2 @@ -0,0 +1,16 @@ + \ # EquipmentInventory +"" \ # Symbol +"" \ # ShortText +0 \ # BoardId +0 \ # HardwareKey +"" \ # ManufacturerId +"" \ # ManufacturerSerialNumber +"" \ # ManufacturerPartNumber +"" \ # ManufacturerBuildState +"" \ # SupplierPartNumber +"" \ # SupplierBuildState +"" \ # CustomerId +"" \ # CustomerProductId +"" \ # Bootloader +"" \ # Processor + diff --git a/templates/KeyMile/login/base/get/hardware_and_software.j2 b/templates/KeyMile/login/base/get/hardware_and_software.j2 new file mode 100644 index 0000000..0ac56c1 --- /dev/null +++ b/templates/KeyMile/login/base/get/hardware_and_software.j2 @@ -0,0 +1,9 @@ + \ # HardwareAndSoftware +{{ context.unit_hardware | safe }}{{ context.spacer_1 }}\ # Hardware +{{ context.unit_supplier_build_state | safe }}{{ context.spacer_2 }}\ # SupplierBuildState +{{ context.unit_board_id | safe }}{{ context.spacer_3 }}\ # BoardId +{{ context.unit_hardware_key | safe }}{{ context.spacer_4 }}\ # HardwareKey +{{ context.unit_software | safe }}{{ context.spacer_5 }}\ # Software +{{ context.unit_software_name | safe }}{{ context.spacer_6 }}\ # SoftwareName +{{ context.unit_software_revision | safe }}{{ context.spacer_7 }}\ # SoftwareRevision + diff --git a/templates/KeyMile/login/base/get/if_rate_limiting.j2 b/templates/KeyMile/login/base/get/if_rate_limiting.j2 new file mode 100644 index 0000000..0cac93a --- /dev/null +++ b/templates/KeyMile/login/base/get/if_rate_limiting.j2 @@ -0,0 +1,8 @@ + \ # IfRateLimiter + \ # UpstreamProfile +false \ # Enabled +default \ # Name + \ # DownstreamProfile +false \ # Enabled +default \ # Name + diff --git a/templates/KeyMile/login/base/get/ip.j2 b/templates/KeyMile/login/base/get/ip.j2 new file mode 100644 index 0000000..b6082d3 --- /dev/null +++ b/templates/KeyMile/login/base/get/ip.j2 @@ -0,0 +1,5 @@ + \ # Ip +{{ context.card.gateway_ipaddress | safe }}{{ context.spacer1 }}\ # GatewayIpAddress +{{ context.card.subnet_mask | safe }}{{ context.spacer2 }}\ # SubnetMask +{{ context.card.default_gateway | safe }}{{ context.spacer3 }}\ # DefaultGateway + diff --git a/templates/KeyMile/login/base/get/ip_address.j2 b/templates/KeyMile/login/base/get/ip_address.j2 new file mode 100644 index 0000000..4baceff --- /dev/null +++ b/templates/KeyMile/login/base/get/ip_address.j2 @@ -0,0 +1,5 @@ + \ # ManagementInterface +{{ context.ip_address }}{{ context.spacer1 }}\ # IpAddress +{{ context.net_mask }}{{ context.spacer2 }}\ # NetworkMask +{{ context.default_gateway }}{{ context.spacer3 }}\ # DefaultGateway + diff --git a/templates/KeyMile/login/base/get/isdnport_bottom.j2 b/templates/KeyMile/login/base/get/isdnport_bottom.j2 new file mode 100644 index 0000000..a6ca59f --- /dev/null +++ b/templates/KeyMile/login/base/get/isdnport_bottom.j2 @@ -0,0 +1,9 @@ +} \ +{{ context.port.register_as_global | lower }}{{ context.spacer2 }}\ # RegisterAsGlobal +{{ context.port.register_default_number_only | lower }}{{ context.spacer3 }}\ # RegisterDefaultNumberOnly +{{ context.port.layer_1_permanently_activated | lower }}{{ context.spacer8 }}\ # Layer1PermanentlyActivated +{{ context.port.sip_profile }}{{ context.spacer4 }}\ # SipProfile +{{ context.port.proxy_registrar_profile }}{{ context.spacer5 }}\ # ProxyRegistrarProfile +{{ context.port.codec_sdp_profile }}{{ context.spacer6 }}\ # CodecSdpProfile +{{ context.port.isdnba_profile }}{{ context.spacer7 }}\ # IsdnBaProfile + diff --git a/templates/KeyMile/login/base/get/isdnport_middle.j2 b/templates/KeyMile/login/base/get/isdnport_middle.j2 new file mode 100644 index 0000000..2336e11 --- /dev/null +++ b/templates/KeyMile/login/base/get/isdnport_middle.j2 @@ -0,0 +1,9 @@ + \ # [{{ context.i }}] # + \ # SubscriberId + "{{ context.subscriber.number }}"{{ context.spacer10 }}\ # SubscriberNumber + "{{ context.subscriber.autorisation_user_name }}"{{ context.spacer11 }}\ # AuthorisationUserName + "{{ context.subscriber.autorisation_password }}"{{ context.spacer12 }}\ # AuthorisationPassword + "{{ context.subscriber.display_name | safe }}"{{ context.spacer13 }}\ # DisplayName + {{ context.subscriber.privacy }}{{ context.spacer14 }}\ # privacy +; \ + diff --git a/templates/KeyMile/login/base/get/isdnport_top.j2 b/templates/KeyMile/login/base/get/isdnport_top.j2 new file mode 100644 index 0000000..96dd3bf --- /dev/null +++ b/templates/KeyMile/login/base/get/isdnport_top.j2 @@ -0,0 +1,4 @@ + \ # IsdnPort +{{ context.port.enable | lower }}{{ context.spacer1 }}\ # Enable +{ \ # SubscriberIdentifications + diff --git a/templates/KeyMile/login/base/get/labels.j2 b/templates/KeyMile/login/base/get/labels.j2 new file mode 100644 index 0000000..d8b257f --- /dev/null +++ b/templates/KeyMile/login/base/get/labels.j2 @@ -0,0 +1,5 @@ + \ # Labels +{{ context.port.label1 | safe }}{{ context.spacer1 }}\ # Label1 +{{ context.port.label2 | safe }}{{ context.spacer2 }}\ # Label2 +{{ context.port.description | safe }}{{ context.spacer3 }}\ # Description + diff --git a/templates/KeyMile/login/base/get/line_actual_state.j2 b/templates/KeyMile/login/base/get/line_actual_state.j2 new file mode 100644 index 0000000..00a44f6 --- /dev/null +++ b/templates/KeyMile/login/base/get/line_actual_state.j2 @@ -0,0 +1,6 @@ + \ # LinePayloadRate + \ # PayloadRate +0 \ # ActualPayloadRate +0 \ # MaxAttainablePayloadRate +Auto \ # Tcpam + diff --git a/templates/KeyMile/login/base/get/line_operation_state.j2 b/templates/KeyMile/login/base/get/line_operation_state.j2 new file mode 100644 index 0000000..2ffbc06 --- /dev/null +++ b/templates/KeyMile/login/base/get/line_operation_state.j2 @@ -0,0 +1,3 @@ + \ # LineOperationalStatus +WaitForG.Handshaking \ # State + diff --git a/templates/KeyMile/login/base/get/line_results_device.j2 b/templates/KeyMile/login/base/get/line_results_device.j2 new file mode 100644 index 0000000..86eceee --- /dev/null +++ b/templates/KeyMile/login/base/get/line_results_device.j2 @@ -0,0 +1,63 @@ + \ # LineTestStatus +1970-01-01T00:00:00 \ # TimeStamp +{{ context.test_state }}{{ context.spacer }}\ # State +{ \ # Results + \ # [0] # + "Foreign DC Voltage a-GND" \ # TestDescription + NotTested \ # Status + "" \ # MeasuredValue +; \ # [1] # + "Foreign DC Voltage b-GND" \ # TestDescription + NotTested \ # Status + "" \ # MeasuredValue +; \ # [2] # + "Foreign DC Voltage a-b" \ # TestDescription + NotTested \ # Status + "" \ # MeasuredValue +; \ # [3] # + "Foreign AC Voltage a-GND" \ # TestDescription + NotTested \ # Status + "" \ # MeasuredValue +; \ # [4] # + "Foreign AC Voltage b-GND" \ # TestDescription + NotTested \ # Status + "" \ # MeasuredValue +; \ # [5] # + "Foreign AC Voltage a-b" \ # TestDescription + NotTested \ # Status + "" \ # MeasuredValue +; \ # [6] # + "Isolation a-GND" \ # TestDescription + NotTested \ # Status + "" \ # MeasuredValue +; \ # [7] # + "Isolation b-GND" \ # TestDescription + NotTested \ # Status + "" \ # MeasuredValue +; \ # [8] # + "Resistance b-a" \ # TestDescription + NotTested \ # Status + "" \ # MeasuredValue +; \ # [9] # + "Resistance a-b" \ # TestDescription + NotTested \ # Status + "" \ # MeasuredValue +; \ # [10] # + "Capacitance a-GND" \ # TestDescription + NotTested \ # Status + "" \ # MeasuredValue +; \ # [11] # + "Capacitance b-GND" \ # TestDescription + NotTested \ # Status + "" \ # MeasuredValue +; \ # [12] # + "Capacitance a-b" \ # TestDescription + NotTested \ # Status + "" \ # MeasuredValue +; \ # [13] # + "Noise" \ # TestDescription + NotTested \ # Status + "" \ # MeasuredValue +; \ +} \ + diff --git a/templates/KeyMile/login/base/get/line_results_docu.j2 b/templates/KeyMile/login/base/get/line_results_docu.j2 new file mode 100644 index 0000000..a8b7151 --- /dev/null +++ b/templates/KeyMile/login/base/get/line_results_docu.j2 @@ -0,0 +1,13 @@ +TimeStamp 2010-09-21T10:36:11 +State {{ context.test_state }} +Results + | TestDescription | Status | MeasuredValue +---+--------------------------+-----------+--------------- + 0 | Foreign DC Voltage a-b | Ok | -30 mV + 1 | Foreign DC Voltage a-GND | Ok | -162 mV + 2 | Foreign DC Voltage b-GND | Ok | -133 mV + 3 | Foreign AC Voltage a-b | Ok | 11 mV + 4 | Foreign AC Voltage a-GND | Ok | 12 mV + 5 | Foreign AC Voltage b-GND | Ok | 11 mV + 6 | Resistance a-b | Ok | 10000.000 kOhm + diff --git a/templates/KeyMile/login/base/get/melt_results_device.j2 b/templates/KeyMile/login/base/get/melt_results_device.j2 new file mode 100644 index 0000000..6eeceff --- /dev/null +++ b/templates/KeyMile/login/base/get/melt_results_device.j2 @@ -0,0 +1,71 @@ + \ # MeasurementStatus +1970-01-01T00:00:27 \ # TimeStamp +{{ context.test_state }}{{ context.spacer }}\ # State +{ \ # Results + \ # [0] # + "Foreign DC Voltage a-b" \ # TestDescription + NotTested \ # Status + "" \ # MeasuredValue +; \ # [1] # + "Foreign DC Voltage a-GND" \ # TestDescription + NotTested \ # Status + "" \ # MeasuredValue +; \ # [2] # + "Foreign DC Voltage b-GND" \ # TestDescription + NotTested \ # Status + "" \ # MeasuredValue +; \ # [3] # + "Foreign AC Voltage a-b" \ # TestDescription + NotTested \ # Status + "" \ # MeasuredValue +; \ # [4] # + "Foreign AC Voltage a-GND" \ # TestDescription + NotTested \ # Status + "" \ # MeasuredValue +; \ # [5] # + "Foreign AC Voltage b-GND" \ # TestDescription + NotTested \ # Status + "" \ # MeasuredValue +; \ # [6] # + "Resistance a-b" \ # TestDescription + NotTested \ # Status + "" \ # MeasuredValue +; \ # [7] # + "Resistance a-b (pos)" \ # TestDescription + NotTested \ # Status + "" \ # MeasuredValue +; \ # [8] # + "Resistance a-b (neg)" \ # TestDescription + NotTested \ # Status + "" \ # MeasuredValue +; \ # [9] # + "Isolation a-GND" \ # TestDescription + NotTested \ # Status + "" \ # MeasuredValue +; \ # [10] # + "Isolation b-GND" \ # TestDescription + NotTested \ # Status + "" \ # MeasuredValue +; \ # [11] # + "Capacitance a-b" \ # TestDescription + NotTested \ # Status + "" \ # MeasuredValue +; \ # [12] # + "Capacitance a-GND" \ # TestDescription + NotTested \ # Status + "" \ # MeasuredValue +; \ # [13] # + "Capacitance b-GND" \ # TestDescription + NotTested \ # Status + "" \ # MeasuredValue +; \ # [14] # + "PPA detected" \ # TestDescription + NotTested \ # Status + "" \ # MeasuredValue +; \ # [15] # + "PPA Resistance" \ # TestDescription + NotTested \ # Status + "" \ # MeasuredValue +; \ +} \ + diff --git a/templates/KeyMile/login/base/get/melt_results_docu.j2 b/templates/KeyMile/login/base/get/melt_results_docu.j2 new file mode 100644 index 0000000..a8b7151 --- /dev/null +++ b/templates/KeyMile/login/base/get/melt_results_docu.j2 @@ -0,0 +1,13 @@ +TimeStamp 2010-09-21T10:36:11 +State {{ context.test_state }} +Results + | TestDescription | Status | MeasuredValue +---+--------------------------+-----------+--------------- + 0 | Foreign DC Voltage a-b | Ok | -30 mV + 1 | Foreign DC Voltage a-GND | Ok | -162 mV + 2 | Foreign DC Voltage b-GND | Ok | -133 mV + 3 | Foreign AC Voltage a-b | Ok | 11 mV + 4 | Foreign AC Voltage a-GND | Ok | 12 mV + 5 | Foreign AC Voltage b-GND | Ok | 11 mV + 6 | Resistance a-b | Ok | 10000.000 kOhm + diff --git a/templates/KeyMile/login/base/get/operational_status.j2 b/templates/KeyMile/login/base/get/operational_status.j2 new file mode 100644 index 0000000..167d462 --- /dev/null +++ b/templates/KeyMile/login/base/get/operational_status.j2 @@ -0,0 +1,3 @@ + \ # OperationalStatus +{{ context.port_operational_state }}{{ context.spacer }}\ # State + diff --git a/templates/KeyMile/login/base/get/operational_wire_state.j2 b/templates/KeyMile/login/base/get/operational_wire_state.j2 new file mode 100644 index 0000000..7d825a6 --- /dev/null +++ b/templates/KeyMile/login/base/get/operational_wire_state.j2 @@ -0,0 +1,4 @@ + \ # OperationalWireState +NO-WIRE \ # CurrentState +2wire \ # Attainable + diff --git a/templates/KeyMile/login/base/get/port_general_status.j2 b/templates/KeyMile/login/base/get/port_general_status.j2 new file mode 100644 index 0000000..cb6881a --- /dev/null +++ b/templates/KeyMile/login/base/get/port_general_status.j2 @@ -0,0 +1,5 @@ + \ # PHYState +LinkDown \ # Speed +LinkDown \ # Duplex +false \ # IEEE802_3FlowControl + diff --git a/templates/KeyMile/login/base/get/port_mac_status.j2 b/templates/KeyMile/login/base/get/port_mac_status.j2 new file mode 100644 index 0000000..9778239 --- /dev/null +++ b/templates/KeyMile/login/base/get/port_mac_status.j2 @@ -0,0 +1,4 @@ + \ # PortMacStatus +2000 \ # MaxPacketLength +00W0DACF4D79 \ # MACAddress + diff --git a/templates/KeyMile/login/base/get/port_profile.j2 b/templates/KeyMile/login/base/get/port_profile.j2 new file mode 100644 index 0000000..cd044d5 --- /dev/null +++ b/templates/KeyMile/login/base/get/port_profile.j2 @@ -0,0 +1,3 @@ + \ # PortProfile +{{ context.profile_name }}{{ context.spacer1 }}\ # Name + diff --git a/templates/KeyMile/login/base/get/port_profiles.j2 b/templates/KeyMile/login/base/get/port_profiles.j2 new file mode 100644 index 0000000..89af093 --- /dev/null +++ b/templates/KeyMile/login/base/get/port_profiles.j2 @@ -0,0 +1,19 @@ + \ # Profiles + \ # VDSLxPrio1 +{{ context.port.profile1_enable }}{{ context.spacer1 }}\ # Enabled +{{ context.port.profile1_name }}{{ context.spacer2 }}\ # Name +{{ context.port.profile1_elength }}{{ context.spacer3 }}\ # MaxElectricalLoopLength + \ # VDSLxPrio2 +{{ context.port.profile2_enable }}{{ context.spacer4 }}\ # Enabled +{{ context.port.profile2_name }}{{ context.spacer5 }}\ # Name +{{ context.port.profile2_elength }}{{ context.spacer6 }}\ # MaxElectricalLoopLength + \ # VDSLxPrio3 +{{ context.port.profile3_enable }}{{ context.spacer7 }}\ # Enabled +{{ context.port.profile3_name }}{{ context.spacer8 }}\ # Name +{{ context.port.profile3_elength }}{{ context.spacer9 }}\ # MaxElectricalLoopLength + \ # ADSLxPrio4 +{{ context.port.profile4_enable }}{{ context.spacer10 }}\ # Enabled +{{ context.port.profile4_name }}{{ context.spacer11 }}\ # Name + \ # AutomaticProfileSwitching +{{ context.port.profile_mode }}{{ context.spacer12 }}\ # Mode + diff --git a/templates/KeyMile/login/base/get/proxy.j2 b/templates/KeyMile/login/base/get/proxy.j2 new file mode 100644 index 0000000..c20a356 --- /dev/null +++ b/templates/KeyMile/login/base/get/proxy.j2 @@ -0,0 +1,13 @@ + \ # Proxy +{{ context.card.proxy_mode }}{{ context.spacer1 }}\ # ProxyMode + \ # PrimaryProxy +{{ context.card.proxy_address | safe }}{{ context.spacer2 }}\ # ProxyAddress +{{ context.card.proxy_port }}{{ context.spacer3 }}\ # ProxyPort + \ # SecondaryProxy +{{ context.card.proxy_address_sec | safe }}{{ context.spacer4 }}\ # ProxyAddress +{{ context.card.proxy_port_sec }}{{ context.spacer5 }}\ # ProxyPort + \ # ProxyAvailabilityCheck +{{ context.card.proxy_enable }}{{ context.spacer6 }}\ # Enabled +{{ context.card.proxy_method }}{{ context.spacer7 }}\ # Method +{{ context.card.proxy_interval }}{{ context.spacer8 }}\ # Interval + diff --git a/templates/KeyMile/login/base/get/pstnport_bottom.j2 b/templates/KeyMile/login/base/get/pstnport_bottom.j2 new file mode 100644 index 0000000..adb8176 --- /dev/null +++ b/templates/KeyMile/login/base/get/pstnport_bottom.j2 @@ -0,0 +1,9 @@ +} \ +{{ context.port.register_as_global | lower }}{{ context.spacer2 }}\ # RegisterAsGlobal +{{ context.port.pay_phone | lower }}{{ context.spacer3 }}\ # PayPhone +{{ context.port.sip_profile }}{{ context.spacer4 }}\ # SipProfile +{{ context.port.proxy_registrar_profile }}{{ context.spacer5 }}\ # ProxyRegistrarProfile +{{ context.port.codec_sdp_profile }}{{ context.spacer6 }}\ # CodecSdpProfile +{{ context.port.pstn_profile }}{{ context.spacer7 }}\ # PstnProfile +{{ context.port.enterprise_profile }}{{ context.spacer8 }}\ # EnterpriseProfile + diff --git a/templates/KeyMile/login/base/get/pstnport_middle.j2 b/templates/KeyMile/login/base/get/pstnport_middle.j2 new file mode 100644 index 0000000..2336e11 --- /dev/null +++ b/templates/KeyMile/login/base/get/pstnport_middle.j2 @@ -0,0 +1,9 @@ + \ # [{{ context.i }}] # + \ # SubscriberId + "{{ context.subscriber.number }}"{{ context.spacer10 }}\ # SubscriberNumber + "{{ context.subscriber.autorisation_user_name }}"{{ context.spacer11 }}\ # AuthorisationUserName + "{{ context.subscriber.autorisation_password }}"{{ context.spacer12 }}\ # AuthorisationPassword + "{{ context.subscriber.display_name | safe }}"{{ context.spacer13 }}\ # DisplayName + {{ context.subscriber.privacy }}{{ context.spacer14 }}\ # privacy +; \ + diff --git a/templates/KeyMile/login/base/get/pstnport_top.j2 b/templates/KeyMile/login/base/get/pstnport_top.j2 new file mode 100644 index 0000000..f470f1b --- /dev/null +++ b/templates/KeyMile/login/base/get/pstnport_top.j2 @@ -0,0 +1,4 @@ + \ # PstnPort +{{ context.port.enable | lower }}{{ context.spacer1 }}\ # Enable +{ \ # SubscriberIdentifications + diff --git a/templates/KeyMile/login/base/get/quickloopbacktest.j2 b/templates/KeyMile/login/base/get/quickloopbacktest.j2 new file mode 100644 index 0000000..126938e --- /dev/null +++ b/templates/KeyMile/login/base/get/quickloopbacktest.j2 @@ -0,0 +1,3 @@ + \ # QuickLoopbackTest +{{ context.loopbacktest_state }}{{ context.spacer }}\ # State + diff --git a/templates/KeyMile/login/base/get/registrar.j2 b/templates/KeyMile/login/base/get/registrar.j2 new file mode 100644 index 0000000..e4da7e2 --- /dev/null +++ b/templates/KeyMile/login/base/get/registrar.j2 @@ -0,0 +1,6 @@ + \ # Registrar +{{ context.card.registrar_adress | safe }}{{ context.spacer1 }}\ # RegistrarAddress +{{ context.card.registrar_port }}{{ context.spacer2 }}\ # RegistrarPort +{{ context.card.registration_mode }}{{ context.spacer3 }}\ # RegistrationMode +{{ context.card.registration_expiration_time }}{{ context.spacer4 }}\ # RegistrationExpirationTime + diff --git a/templates/KeyMile/login/base/get/service_mcast.j2 b/templates/KeyMile/login/base/get/service_mcast.j2 new file mode 100644 index 0000000..bcbaf3b --- /dev/null +++ b/templates/KeyMile/login/base/get/service_mcast.j2 @@ -0,0 +1,6 @@ + \ # MCastAccessService + \ # Interface +{{ context.service.address }}{{ context.spacer1 }}\ # Address + \ # Specific +{{ context.service.svid }}{{ context.spacer2 }}\ # Svid + diff --git a/templates/KeyMile/login/base/get/service_nto1.j2 b/templates/KeyMile/login/base/get/service_nto1.j2 new file mode 100644 index 0000000..2a30929 --- /dev/null +++ b/templates/KeyMile/login/base/get/service_nto1.j2 @@ -0,0 +1,16 @@ + \ # Nto1AccessService + \ # Interface +{{ context.service.address }}{{ context.spacer1 }}\ # Address + \ # Specific +{{ context.service.svid }}{{ context.spacer2 }}\ # Svid +{{ context.service.stag_priority }}{{ context.spacer3 }}\ # STagPriority +PPPoE \ # LogonMethod +{{ context.service.vlan_handling }}{{ context.spacer4 }}\ # VLANHandling +false \ # SourceFilter +false \ # DestinationFilter +false \ # SourceIPFilter +false \ # DynamicARPInspection +false \ # MacForcedForwarding +Assigned \ # PriorityHandling +default \ # CoSProfile + diff --git a/templates/KeyMile/login/base/get/service_onetoonedoubletag.j2 b/templates/KeyMile/login/base/get/service_onetoonedoubletag.j2 new file mode 100644 index 0000000..60476ca --- /dev/null +++ b/templates/KeyMile/login/base/get/service_onetoonedoubletag.j2 @@ -0,0 +1,6 @@ + \ # OnetoOneDoubleTagAccessService + \ # Interface +{{ context.service.address }}{{ context.spacer1 }}\ # Address + \ # Specific +{{ context.service.svid }}{{ context.spacer2 }}\ # Svid + diff --git a/templates/KeyMile/login/base/get/service_onetoonesingletag.j2 b/templates/KeyMile/login/base/get/service_onetoonesingletag.j2 new file mode 100644 index 0000000..1a31a6c --- /dev/null +++ b/templates/KeyMile/login/base/get/service_onetoonesingletag.j2 @@ -0,0 +1,8 @@ + \ # OnetoOneSingleTagAccessService + \ # Interface +{{ context.service.address }}{{ context.spacer1 }}\ # Address + \ # Specific +{{ context.service.svid }}{{ context.spacer2 }}\ # Svid +{{ context.service.stag_priority }}{{ context.spacer3 }}\ # STagPriority +{{ context.service.vlan_handling }}{{ context.spacer4 }}\ # VLANHandling + diff --git a/templates/KeyMile/login/base/get/service_pls.j2 b/templates/KeyMile/login/base/get/service_pls.j2 new file mode 100644 index 0000000..d0f3789 --- /dev/null +++ b/templates/KeyMile/login/base/get/service_pls.j2 @@ -0,0 +1,6 @@ + \ # PLSAccessService + \ # Interface +{{ context.service.address }}{{ context.spacer1 }}\ # Address + \ # Specific +{{ context.service.svid }}{{ context.spacer2 }}\ # Svid + diff --git a/templates/KeyMile/login/base/get/service_status.j2 b/templates/KeyMile/login/base/get/service_status.j2 new file mode 100644 index 0000000..a5ce7f6 --- /dev/null +++ b/templates/KeyMile/login/base/get/service_status.j2 @@ -0,0 +1,5 @@ + \ # serviceStatus +{{ context.vcc.number_of_conn_services }}{{ context.spacer1 }}\ # NumberOfConnectedServices +{{ context.vcc.reconfiguration_allowed }}{{ context.spacer2 }}\ # ReconfigurationAllowed +{{ context.vcc_services_connected | safe }}{{ context.spacer3 }}\ # ServicesCurrentConnected + diff --git a/templates/KeyMile/login/base/get/service_tls.j2 b/templates/KeyMile/login/base/get/service_tls.j2 new file mode 100644 index 0000000..9c22053 --- /dev/null +++ b/templates/KeyMile/login/base/get/service_tls.j2 @@ -0,0 +1,6 @@ + \ # TLSAccessService + \ # Interface +{{ context.service.address }}{{ context.spacer1 }}\ # Address + \ # Specific +{{ context.service.svid }}{{ context.spacer2 }}\ # Svid + diff --git a/templates/KeyMile/login/base/get/sip.j2 b/templates/KeyMile/login/base/get/sip.j2 new file mode 100644 index 0000000..6bfb4e9 --- /dev/null +++ b/templates/KeyMile/login/base/get/sip.j2 @@ -0,0 +1,17 @@ + \ # sip +{{ context.card.gateway_name | safe }}{{ context.spacer1 }}\ # GatewayName +{{ context.card.home_domain | safe }}{{ context.spacer2 }}\ # HomeDomain +{{ context.card.sip_port_number }}{{ context.spacer3 }}\ # SipPortNumber +"{{ context.card.country_code | safe }}"{{ context.spacer4 }}\ # CountryCode +"{{ context.card.area_code | safe }}"{{ context.spacer5 }}\ # AreaCode +{{ context.card.retransmission_timer }}{{ context.spacer6 }}\ # RetransmissionTimerT1 +{{ context.card.max_retransmission_interval }}{{ context.spacer7 }}\ # MaxRetransmissionIntervalT2 +{{ context.card.sip_extension }}{{ context.spacer8 }}\ # SipExtension100relRequired +{{ context.card.asserted_id_mode }}{{ context.spacer9 }}\ # assertedIdentityMode +{{ context.card.overlap_signalling }}{{ context.spacer10 }}\ # OverlapSignalling +{{ context.card.overlap_timer }}{{ context.spacer11 }}\ # OverlapT10timer + \ # SessionTimer +{{ context.card.uac_request_timer }}{{ context.spacer12 }}\ # UacRequestSessionTimer +{{ context.card.uas_request_timer }}{{ context.spacer13 }}\ # UasRequestSessionTimer +{{ context.card.session_expiration }}{{ context.spacer14 }}\ # SessionExpiration + diff --git a/templates/KeyMile/login/base/get/span_profiles.j2 b/templates/KeyMile/login/base/get/span_profiles.j2 new file mode 100644 index 0000000..75e6eab --- /dev/null +++ b/templates/KeyMile/login/base/get/span_profiles.j2 @@ -0,0 +1,3 @@ + \ # LogicalPort +{{ context.port.profile }}{{ context.spacer1 }}\ # Name + diff --git a/templates/KeyMile/login/base/get/status.j2 b/templates/KeyMile/login/base/get/status.j2 new file mode 100644 index 0000000..aa19e07 --- /dev/null +++ b/templates/KeyMile/login/base/get/status.j2 @@ -0,0 +1,10 @@ + \ # Status + \ # Downstream +{{ context.channel.curr_rate_d }}{{ context.spacer1 }}\ # CurrentRate +{{ context.channel.prev_rate_d }}{{ context.spacer2 }}\ # PreviousRate +{{ context.channel.curr_delay_d }}{{ context.spacer3 }}\ # CurrentDelay + \ # Upstream +{{ context.channel.curr_rate_u }}{{ context.spacer4 }}\ # CurrentRate +{{ context.channel.prev_rate_u }}{{ context.spacer5 }}\ # PreviousRate +{{ context.channel.curr_delay_u }}{{ context.spacer6 }}\ # CurrentDelay + diff --git a/templates/KeyMile/login/base/get/subscriberList_bottom.j2 b/templates/KeyMile/login/base/get/subscriberList_bottom.j2 new file mode 100644 index 0000000..7d2b463 --- /dev/null +++ b/templates/KeyMile/login/base/get/subscriberList_bottom.j2 @@ -0,0 +1,2 @@ +} \ + diff --git a/templates/KeyMile/login/base/get/subscriberList_item.j2 b/templates/KeyMile/login/base/get/subscriberList_item.j2 new file mode 100644 index 0000000..189f50a --- /dev/null +++ b/templates/KeyMile/login/base/get/subscriberList_item.j2 @@ -0,0 +1,7 @@ + \ # [{{ context.i }}] # + \ # Subscriber + "{{ context.subscriber.number }}"{{ context.spacer1 }}\ # SubscriberNumber + "{{ context.subscriber.registration_state }}"{{ context.spacer2 }}\ # RegistrationStatus + "{{ context.subscriber.address }}"{{ context.spacer3 }}\ # Address +; \ + diff --git a/templates/KeyMile/login/base/get/subscriberList_item2.j2 b/templates/KeyMile/login/base/get/subscriberList_item2.j2 new file mode 100644 index 0000000..733e082 --- /dev/null +++ b/templates/KeyMile/login/base/get/subscriberList_item2.j2 @@ -0,0 +1,6 @@ + \ # [{{ context.i }}] # + \ # Subscriber + "{{ context.subscriber.number }}"{{ context.spacer1 }}\ # SubscriberNumber + "{{ context.subscriber.registration_state }}"{{ context.spacer2 }}\ # RegistrationStatus +; \ + diff --git a/templates/KeyMile/login/base/get/subscriberList_top.j2 b/templates/KeyMile/login/base/get/subscriberList_top.j2 new file mode 100644 index 0000000..2e483ea --- /dev/null +++ b/templates/KeyMile/login/base/get/subscriberList_top.j2 @@ -0,0 +1,3 @@ + \ # Registration +{ \ # UnregisteredSubscriberList + diff --git a/templates/KeyMile/login/base/get/unicast_list.j2 b/templates/KeyMile/login/base/get/unicast_list.j2 new file mode 100644 index 0000000..3a6dfad --- /dev/null +++ b/templates/KeyMile/login/base/get/unicast_list.j2 @@ -0,0 +1,10 @@ +{ \ # UnicastList + \ # [0] # + \ # PortDynamicListEntry + 1 \ # Index + 00A38EA34DD0 \ # MacAddress + 2620 \ # VlanId + 0.0.0.0 \ # IpAddress +; \ +} \ + diff --git a/templates/KeyMile/login/base/get/unicast_list_empty.j2 b/templates/KeyMile/login/base/get/unicast_list_empty.j2 new file mode 100644 index 0000000..a8d7a8e --- /dev/null +++ b/templates/KeyMile/login/base/get/unicast_list_empty.j2 @@ -0,0 +1,3 @@ +{ \ # UnicastList +} \ + diff --git a/templates/KeyMile/login/base/get/vendor_id.j2 b/templates/KeyMile/login/base/get/vendor_id.j2 new file mode 100644 index 0000000..57149cb --- /dev/null +++ b/templates/KeyMile/login/base/get/vendor_id.j2 @@ -0,0 +1,12 @@ + \ # DSLvendor + \ # CO +"B400/ITTN/0001" \ # VendorId +"14.3.3.60.0.22" \ # VersionNumber +"5610864561" \ # SerialNumber +"0x07 40 00 00 00 18 00 11" \ # DslLineTransCap + \ # CPE +"B400/ITTN/2F0A" \ # VendorId +"1.283.5.17 AB" \ # VersionNumber +"3CDH5F478B7B F!Box7550 165.70.10" \ # SerialNumber +"0x00 11 40 11 50 10 03 00" \ # DslLineTransCap + diff --git a/templates/KeyMile/login/base/get/vlan_id.j2 b/templates/KeyMile/login/base/get/vlan_id.j2 new file mode 100644 index 0000000..0d643c3 --- /dev/null +++ b/templates/KeyMile/login/base/get/vlan_id.j2 @@ -0,0 +1,3 @@ + \ # ManagementVlan +{{ context.vlan_id }}{{ context.spacer }}\ # VlanId + diff --git a/templates/KeyMile/login/base/get/vlan_profile.j2 b/templates/KeyMile/login/base/get/vlan_profile.j2 new file mode 100644 index 0000000..0c5d04b --- /dev/null +++ b/templates/KeyMile/login/base/get/vlan_profile.j2 @@ -0,0 +1,3 @@ + \ # vlanProfile +{{ context.vcc.vlan_profile }}{{ context.spacer1 }}\ # Name + diff --git a/templates/KeyMile/login/base/help/help.j2 b/templates/KeyMile/login/base/help/help.j2 new file mode 100644 index 0000000..7e32ef8 --- /dev/null +++ b/templates/KeyMile/login/base/help/help.j2 @@ -0,0 +1,19 @@ + +commands +-------- + +cd -- Change to specified node address and/or MF +pwd -- Show current address +ls -- Show infos for current address +show -- Show settings +mode -- Configure operation modes +ftpserver -- Configure the (s)ftp-server settings +upload -- Upload a file (filename) from the NE into the (s)ftp server (serverpath) +download -- Download a file (serverpath/filename) from the (s)ftp server into the NE +get -- Get property values from the node +set -- Define property values and send them to the node +profile -- profile utility +help -- Show CLI operation help +exit -- Exit CLI session + + diff --git a/templates/KeyMile/login/base/help/help_cd.j2 b/templates/KeyMile/login/base/help/help_cd.j2 new file mode 100644 index 0000000..fd008c8 --- /dev/null +++ b/templates/KeyMile/login/base/help/help_cd.j2 @@ -0,0 +1,9 @@ + +Syntax: + cd
+ +Change to specified node address and/or MF + + address -- node address and/or MF (i.e. /unit-11/main) + + diff --git a/templates/KeyMile/login/base/help/help_download.j2 b/templates/KeyMile/login/base/help/help_download.j2 new file mode 100644 index 0000000..d649a27 --- /dev/null +++ b/templates/KeyMile/login/base/help/help_download.j2 @@ -0,0 +1,10 @@ + +Syntax: + download
+ +Download a file (serverpath/filename) from the (s)ftp server into the NE + + address MO address -- MO address of a file node + remoteFile characters -- Filepath and -name on file server + + diff --git a/templates/KeyMile/login/base/help/help_exit.j2 b/templates/KeyMile/login/base/help/help_exit.j2 new file mode 100644 index 0000000..719f4cc --- /dev/null +++ b/templates/KeyMile/login/base/help/help_exit.j2 @@ -0,0 +1,9 @@ + +Syntax: + exit [-s] + +Exit CLI session + + -s -- Save configuration on exit + + diff --git a/templates/KeyMile/login/base/help/help_ftpserver.j2 b/templates/KeyMile/login/base/help/help_ftpserver.j2 new file mode 100644 index 0000000..e24ebb7 --- /dev/null +++ b/templates/KeyMile/login/base/help/help_ftpserver.j2 @@ -0,0 +1,11 @@ + +Syntax: + ftpserver + +Configure the (s)ftp-server settings + + ipAddress IP address -- IP address of the server + user characters -- User to logon the server + password characters -- Password to logon the server + + diff --git a/templates/KeyMile/login/base/help/help_get.j2 b/templates/KeyMile/login/base/help/help_get.j2 new file mode 100644 index 0000000..629d1ad --- /dev/null +++ b/templates/KeyMile/login/base/help/help_get.j2 @@ -0,0 +1,9 @@ + +Syntax: + get + +Get property values from the node + + property -- MO Address of a property + + diff --git a/templates/KeyMile/login/base/help/help_help.j2 b/templates/KeyMile/login/base/help/help_help.j2 new file mode 100644 index 0000000..0219d12 --- /dev/null +++ b/templates/KeyMile/login/base/help/help_help.j2 @@ -0,0 +1,28 @@ + +Syntax: + help [] + +Display a description for global commands or for the optionally specified operation + + operation -- any valid command or property operation + +Notation syntax: + - Parameters enclosed in square brackets [ ] are optional + - Parameter values enclosed in angle brackets < > must be specified by the user + - Predefined selections are enclosed in parantheses ( ) and separated by a vertical bar | + - Elements in tables are enclosed in curly brackets { } and separated by a semicolon ; + +MO address syntax: + - An absolute address notation always begins with the slash '/' + - The addition of a MF after the MO address is optional + + [(. | ..)]/[/(main | cfgm | fm | pm | status)] + + / forward-slash -- substitute for the AP root and separator for multiple address elements + MO-address -- The MO address consists of one or several node IDs, separated with a slash + (main | cfgm | fm | pm | status) keywords for MFs -- The management function may be appended to the MO-address + ./ dot forward-slash -- substitute for the current location in the AP tree + ../ dot dot forward-slash -- one step upwards in the AP tree + + + diff --git a/templates/KeyMile/login/base/help/help_ls.j2 b/templates/KeyMile/login/base/help/help_ls.j2 new file mode 100644 index 0000000..6f452c1 --- /dev/null +++ b/templates/KeyMile/login/base/help/help_ls.j2 @@ -0,0 +1,10 @@ + +Syntax: + ls [
] [-e] + +Show infos for current address + + address -- node address and/or MF (i.e. /unit-11/main) + -e -- Extends infos about children + + diff --git a/templates/KeyMile/login/base/help/help_mode.j2 b/templates/KeyMile/login/base/help/help_mode.j2 new file mode 100644 index 0000000..245edc4 --- /dev/null +++ b/templates/KeyMile/login/base/help/help_mode.j2 @@ -0,0 +1,14 @@ + +mode commands +------------- + +display -- Configure display operation mode +etx -- Configure ETX mode (cli output termination) +prompt -- Configure prompt mode +syntaxversion -- Configure CLI syntax version for script compatibility +warnings -- Configure warnings mode (warnings on/off in plain display mode) + +Syntax: + mode + + diff --git a/templates/KeyMile/login/base/help/help_profile.j2 b/templates/KeyMile/login/base/help/help_profile.j2 new file mode 100644 index 0000000..b72b7f9 --- /dev/null +++ b/templates/KeyMile/login/base/help/help_profile.j2 @@ -0,0 +1,14 @@ + +profile commands +---------------- + +create -- create a profile +list -- list profiles +showDefaults -- show default values of a profile type +showTypes -- show available profile types +showValues -- show values of a profile + +Syntax: + profile + + diff --git a/templates/KeyMile/login/base/help/help_pwd.j2 b/templates/KeyMile/login/base/help/help_pwd.j2 new file mode 100644 index 0000000..4073496 --- /dev/null +++ b/templates/KeyMile/login/base/help/help_pwd.j2 @@ -0,0 +1,4 @@ + +Show current address + + diff --git a/templates/KeyMile/login/base/help/help_set.j2 b/templates/KeyMile/login/base/help/help_set.j2 new file mode 100644 index 0000000..bf73063 --- /dev/null +++ b/templates/KeyMile/login/base/help/help_set.j2 @@ -0,0 +1,12 @@ + +Syntax: + set ... + +Define property values and send them to the node + + property characters + attr1 characters + attr2 characters + ... + + diff --git a/templates/KeyMile/login/base/help/help_show.j2 b/templates/KeyMile/login/base/help/help_show.j2 new file mode 100644 index 0000000..d22768f --- /dev/null +++ b/templates/KeyMile/login/base/help/help_show.j2 @@ -0,0 +1,13 @@ + +show commands +------------- + +mode -- Show current modes +version -- Show CLI version +ftpserver -- Show (S)FTP server settings +sessionIf -- Show CLI sessionIf + +Syntax: + show + + diff --git a/templates/KeyMile/login/base/help/help_upload.j2 b/templates/KeyMile/login/base/help/help_upload.j2 new file mode 100644 index 0000000..2f04846 --- /dev/null +++ b/templates/KeyMile/login/base/help/help_upload.j2 @@ -0,0 +1,10 @@ + +Syntax: + upload
+ +Upload a file (filename) from the NE into the (s)ftp server (serverpath) + + address MO address -- MO address of a file node + remoteFile characters -- Filepath and -name on file server + + diff --git a/templates/KeyMile/login/base/login_message.j2 b/templates/KeyMile/login/base/login_message.j2 new file mode 100644 index 0000000..84f6b7f --- /dev/null +++ b/templates/KeyMile/login/base/login_message.j2 @@ -0,0 +1,2 @@ +---===### CLI Release R2A20, Build 2014-01-31 ###===--- + diff --git a/templates/KeyMile/login/base/ls/ls_ap_list.j2 b/templates/KeyMile/login/base/ls/ls_ap_list.j2 new file mode 100644 index 0000000..c514d30 --- /dev/null +++ b/templates/KeyMile/login/base/ls/ls_ap_list.j2 @@ -0,0 +1,3 @@ + +AP List: + diff --git a/templates/KeyMile/login/base/ls/ls_header.j2 b/templates/KeyMile/login/base/ls/ls_header.j2 new file mode 100644 index 0000000..ab51e15 --- /dev/null +++ b/templates/KeyMile/login/base/ls/ls_header.j2 @@ -0,0 +1,10 @@ +Infos of AP: {{ context.path }} + Name : {{ context.ls_Name }} + Main Mode : {{ context.ls_MainMode }} + Equipment State : {{ context.ls_EquipmentState }} + Alarm Severity : Cleared + Propagated Alarm Severity : Major + User Label : + Service Label : + Description : + diff --git a/templates/KeyMile/login/base/ls/ls_list_body.j2 b/templates/KeyMile/login/base/ls/ls_list_body.j2 new file mode 100644 index 0000000..325772f --- /dev/null +++ b/templates/KeyMile/login/base/ls/ls_list_body.j2 @@ -0,0 +1,2 @@ + {{ context.list_entry }} + diff --git a/templates/KeyMile/login/base/ls/ls_mf_body.j2 b/templates/KeyMile/login/base/ls/ls_mf_body.j2 new file mode 100644 index 0000000..4cbc7f7 --- /dev/null +++ b/templates/KeyMile/login/base/ls/ls_mf_body.j2 @@ -0,0 +1,2 @@ +{{ context.prop_type }}: {{ context.prop_name }} {{ context.prop_rw_rights }} + diff --git a/templates/KeyMile/login/base/ls/ls_mf_header.j2 b/templates/KeyMile/login/base/ls/ls_mf_header.j2 new file mode 100644 index 0000000..f245922 --- /dev/null +++ b/templates/KeyMile/login/base/ls/ls_mf_header.j2 @@ -0,0 +1,2 @@ +{{ context.mf_layer }} + diff --git a/templates/KeyMile/login/base/ls/ls_mf_list.j2 b/templates/KeyMile/login/base/ls/ls_mf_list.j2 new file mode 100644 index 0000000..e7c6651 --- /dev/null +++ b/templates/KeyMile/login/base/ls/ls_mf_list.j2 @@ -0,0 +1,3 @@ + +MF List: + diff --git a/templates/KeyMile/login/base/on_cycle.j2 b/templates/KeyMile/login/base/on_cycle.j2 new file mode 100644 index 0000000..aa3921f --- /dev/null +++ b/templates/KeyMile/login/base/on_cycle.j2 @@ -0,0 +1 @@ +{{ context.path }}> diff --git a/templates/KeyMile/login/base/on_error.j2 b/templates/KeyMile/login/base/on_error.j2 new file mode 100644 index 0000000..c36472c --- /dev/null +++ b/templates/KeyMile/login/base/on_error.j2 @@ -0,0 +1,2 @@ +error: invalid management function + diff --git a/templates/KeyMile/login/base/pwd.j2 b/templates/KeyMile/login/base/pwd.j2 new file mode 100644 index 0000000..b598ab2 --- /dev/null +++ b/templates/KeyMile/login/base/pwd.j2 @@ -0,0 +1,2 @@ +{{ context.path }}{{ context.spacer }}\ # current directory + diff --git a/templates/KeyMile/login/base/set/interface_success.j2 b/templates/KeyMile/login/base/set/interface_success.j2 new file mode 100644 index 0000000..96bd08d --- /dev/null +++ b/templates/KeyMile/login/base/set/interface_success.j2 @@ -0,0 +1,3 @@ + \ # CreateInterface +interface-{{ context.id }}{{ context.spacer1 }}\ # Interface ID + diff --git a/templates/KeyMile/login/base/set/vcc_success.j2 b/templates/KeyMile/login/base/set/vcc_success.j2 new file mode 100644 index 0000000..b5a9cf3 --- /dev/null +++ b/templates/KeyMile/login/base/set/vcc_success.j2 @@ -0,0 +1,3 @@ + \ # CreateVcc +vcc-{{ context.id }}{{ context.spacer1 }}\ # VCC ID + diff --git a/templates/KeyMile/login/base/syntax_errors/syntax_error.j2 b/templates/KeyMile/login/base/syntax_errors/syntax_error.j2 new file mode 100644 index 0000000..314c72f --- /dev/null +++ b/templates/KeyMile/login/base/syntax_errors/syntax_error.j2 @@ -0,0 +1,2 @@ +error: syntax error + diff --git a/templates/KeyMile/login/on_enter.j2 b/templates/KeyMile/login/on_enter.j2 new file mode 100644 index 0000000..fb31150 --- /dev/null +++ b/templates/KeyMile/login/on_enter.j2 @@ -0,0 +1 @@ +password: diff --git a/templates/KeyMile/login/password.j2 b/templates/KeyMile/login/password.j2 new file mode 100644 index 0000000..5d94c41 --- /dev/null +++ b/templates/KeyMile/login/password.j2 @@ -0,0 +1,2 @@ +Login failure: Unknown userclass + diff --git a/templates/KeyMile/on_cycle.j2 b/templates/KeyMile/on_cycle.j2 new file mode 100644 index 0000000..2a6191f --- /dev/null +++ b/templates/KeyMile/on_cycle.j2 @@ -0,0 +1 @@ +login as: diff --git a/templates/KeyMile/on_exit.j2 b/templates/KeyMile/on_exit.j2 new file mode 100644 index 0000000..989d95b --- /dev/null +++ b/templates/KeyMile/on_exit.j2 @@ -0,0 +1,2 @@ +SESSION CLOSED + diff --git a/test_cases/integration_tests/alcatel/configureTrafficVlanOnPort.txt b/test_cases/integration_tests/alcatel/configureTrafficVlanOnPort.txt index 6fd8515..a464a68 100644 --- a/test_cases/integration_tests/alcatel/configureTrafficVlanOnPort.txt +++ b/test_cases/integration_tests/alcatel/configureTrafficVlanOnPort.txt @@ -4,10 +4,10 @@ configure bridge port 1/1/1/1 no pvid configure bridge port 1/1/1/1 no vlan-id 7 configure bridge port 1/1/1/1:1:32 no pvid configure bridge port 1/1/1/1:1:32 noi vlan-id 7 -confiugre bridge port 1/1/1/1:1:32 vlan-id 7 network-vlan 2620 vlan-scope local +configure bridge port 1/1/1/1:1:32 vlan-id 7 network-vlan 2620 vlan-scope local configure bridge port 1/1/1/1 pvid 7 configure bridge port 1/1/1/1:1:32 pvid 7 -configure birdge port 1/1/4/1 vlan-id 2620 tag single-tagged +configure bridge port 1/1/4/1 vlan-id 2620 tag single-tagged configure bridge port 1/1/4/1 vlan-id 2620 l2fwder-vlan 2620 vlan-scope local tag single-tagged configure bridge port 1/1/4/1 vlan-id 7 l2fwder-vlan 2620 vlan-scope local tag single-tagged configure bridge port 1/1/4/1 vlan-id 7 network-vlan 2620 vlan-scope local single-tagged diff --git a/test_cases/integration_tests/edgecore/backup.txt b/test_cases/integration_tests/edgecore/backup.txt new file mode 100644 index 0000000..9b5d380 --- /dev/null +++ b/test_cases/integration_tests/edgecore/backup.txt @@ -0,0 +1,10 @@ +admin +secret +enable +enable +copy startup-config ftp +1.1.1.1 +backup +backup +/example.txt +quit \ No newline at end of file diff --git a/test_cases/integration_tests/edgecore/configureBox7.txt b/test_cases/integration_tests/edgecore/configureBox7.txt new file mode 100644 index 0000000..1cc3455 --- /dev/null +++ b/test_cases/integration_tests/edgecore/configureBox7.txt @@ -0,0 +1,9 @@ +admin +secret +enable +enable +configure +management all-client 10.218.20.21 10.218.20.22 +no logging host 10.10.103.254 +loopback-detection action shutdown +quit \ No newline at end of file diff --git a/test_cases/integration_tests/edgecore/configureBoxName10.txt b/test_cases/integration_tests/edgecore/configureBoxName10.txt new file mode 100644 index 0000000..82f10c4 --- /dev/null +++ b/test_cases/integration_tests/edgecore/configureBoxName10.txt @@ -0,0 +1,8 @@ +admin +secret +enable +enable +configure +prompt name_prompt +hostname test_device +quit \ No newline at end of file diff --git a/test_cases/integration_tests/edgecore/configureClock9.txt b/test_cases/integration_tests/edgecore/configureClock9.txt new file mode 100644 index 0000000..db1aa8b --- /dev/null +++ b/test_cases/integration_tests/edgecore/configureClock9.txt @@ -0,0 +1,10 @@ +admin +secret +enable +enable +configure +sntp server 77.244.98.1 +sntp client +clock timezone gmt hours 1 minute 0 +clock summer-time MESZ predefined europe +quit \ No newline at end of file diff --git a/test_cases/integration_tests/edgecore/configureInternet2.txt b/test_cases/integration_tests/edgecore/configureInternet2.txt new file mode 100644 index 0000000..445095c --- /dev/null +++ b/test_cases/integration_tests/edgecore/configureInternet2.txt @@ -0,0 +1,12 @@ +admin +secret +enable +enable +configure +interface ethernet 1/1 +description test_description +switchport mode hybrid +no shutdown +rate-limit input 1 +rate-limit output 1 +quit \ No newline at end of file diff --git a/test_cases/integration_tests/edgecore/configureLog11.txt b/test_cases/integration_tests/edgecore/configureLog11.txt new file mode 100644 index 0000000..af21cba --- /dev/null +++ b/test_cases/integration_tests/edgecore/configureLog11.txt @@ -0,0 +1,8 @@ +admin +secret +enable +enable +configure +logging host 10.218.23.2 port 514 +logging trap +quit \ No newline at end of file diff --git a/test_cases/integration_tests/edgecore/configureMVlan12.txt b/test_cases/integration_tests/edgecore/configureMVlan12.txt new file mode 100644 index 0000000..3707bf4 --- /dev/null +++ b/test_cases/integration_tests/edgecore/configureMVlan12.txt @@ -0,0 +1,13 @@ +admin +secret +enable +enable +configure +vlan database +vlan 22 name scription media ethernet +exit +ip dhcp snooping +ip dhcp snooping vlan 1 +ip dhcp snooping information option encode no-subtype +ip dhcp snooping information option remote-id string test sub-option port-description +quit \ No newline at end of file diff --git a/test_cases/integration_tests/edgecore/configurePort4.txt b/test_cases/integration_tests/edgecore/configurePort4.txt new file mode 100644 index 0000000..677408c --- /dev/null +++ b/test_cases/integration_tests/edgecore/configurePort4.txt @@ -0,0 +1,8 @@ +admin +secret +enable +enable +configure +interface ethernet 1/1 +no shutdown +quit \ No newline at end of file diff --git a/test_cases/integration_tests/edgecore/configureRelay13.txt b/test_cases/integration_tests/edgecore/configureRelay13.txt new file mode 100644 index 0000000..a074bb3 --- /dev/null +++ b/test_cases/integration_tests/edgecore/configureRelay13.txt @@ -0,0 +1,7 @@ +admin +secret +enable +enable +configure +pppoe intermediate-agent +quit \ No newline at end of file diff --git a/test_cases/integration_tests/edgecore/configureRelayOnPort14.txt b/test_cases/integration_tests/edgecore/configureRelayOnPort14.txt new file mode 100644 index 0000000..a30b7c1 --- /dev/null +++ b/test_cases/integration_tests/edgecore/configureRelayOnPort14.txt @@ -0,0 +1,13 @@ +admin +secret +enable +enable +configure +interface ethernet 1/1 +pppoe intermediate-agent port-enable +pppoe intermediate-agent trust +ip dhcp snooping trust +pppoe intermediate-agent port-format-type circuit-id 1/1 +ip dhcp snooping information option circuit-id tr101 node-identifier ip +ip dhcp snooping information option circuit-id tr101 no-vlan-field +quit \ No newline at end of file diff --git a/test_cases/integration_tests/edgecore/configureTVlan8.txt b/test_cases/integration_tests/edgecore/configureTVlan8.txt new file mode 100644 index 0000000..97c1a4b --- /dev/null +++ b/test_cases/integration_tests/edgecore/configureTVlan8.txt @@ -0,0 +1,8 @@ +admin +secret +enable +enable +configure +vlan database +vlan 1111 name scription media ethernet +quit \ No newline at end of file diff --git a/test_cases/integration_tests/edgecore/configureTVlanPort1.txt b/test_cases/integration_tests/edgecore/configureTVlanPort1.txt new file mode 100644 index 0000000..fd6e597 --- /dev/null +++ b/test_cases/integration_tests/edgecore/configureTVlanPort1.txt @@ -0,0 +1,8 @@ +admin +secret +enable +enable +configure +interface ethernet 1/1 +switchport allowed vlan add 1 tagged +quit \ No newline at end of file diff --git a/test_cases/integration_tests/edgecore/configureUVlan15.txt b/test_cases/integration_tests/edgecore/configureUVlan15.txt new file mode 100644 index 0000000..f08985c --- /dev/null +++ b/test_cases/integration_tests/edgecore/configureUVlan15.txt @@ -0,0 +1,9 @@ +admin +secret +enable +enable +configure +interface ethernet 1/1 +switchport allowed vlan add 1 untagged +switchport native vlan 1 +quit \ No newline at end of file diff --git a/test_cases/integration_tests/edgecore/display_data2.txt b/test_cases/integration_tests/edgecore/display_data2.txt new file mode 100644 index 0000000..ef5c230 --- /dev/null +++ b/test_cases/integration_tests/edgecore/display_data2.txt @@ -0,0 +1,8 @@ +admin +secret +enable +enable +show system +show process cpu +show memory +quit \ No newline at end of file diff --git a/test_cases/integration_tests/edgecore/display_information4.txt b/test_cases/integration_tests/edgecore/display_information4.txt new file mode 100644 index 0000000..7e24d3c --- /dev/null +++ b/test_cases/integration_tests/edgecore/display_information4.txt @@ -0,0 +1,6 @@ +admin +secret +enable +enable +show mac-address-table +quit \ No newline at end of file diff --git a/test_cases/integration_tests/edgecore/display_model3.txt b/test_cases/integration_tests/edgecore/display_model3.txt new file mode 100644 index 0000000..461ab56 --- /dev/null +++ b/test_cases/integration_tests/edgecore/display_model3.txt @@ -0,0 +1,6 @@ +admin +secret +enable +enable +show system +quit \ No newline at end of file diff --git a/test_cases/integration_tests/edgecore/display_state1.txt b/test_cases/integration_tests/edgecore/display_state1.txt new file mode 100644 index 0000000..a9897db --- /dev/null +++ b/test_cases/integration_tests/edgecore/display_state1.txt @@ -0,0 +1,8 @@ +admin +secret +enable +enable +show interfaces status ethernet 1/1 +show interfaces switchport ethernet 1/1 +show interfaces transceiver ethernet 1/1 +quit \ No newline at end of file diff --git a/test_cases/integration_tests/edgecore/unconfigureInternet3.txt b/test_cases/integration_tests/edgecore/unconfigureInternet3.txt new file mode 100644 index 0000000..0b8e7c5 --- /dev/null +++ b/test_cases/integration_tests/edgecore/unconfigureInternet3.txt @@ -0,0 +1,20 @@ +admin +secret +enable +enable +configure +interface ethernet 1/1 +rate-limit input 1000000 +rate-limit output 1000000 +no rate-limit input +no rate-limit output +shutdown +no description +no switchport mode +no switchport native vlan +no switchport allowed vlan +no pppoe intermediate-agent port-enable +no pppoe intermediate-agent port-format-type circuit-id +no ip dhcp snooping information option circuit-id tr101 no-vlan-field +no ip dhcp snooping information option circuit-id +quit \ No newline at end of file diff --git a/test_cases/integration_tests/edgecore/unconfigurePort5.txt b/test_cases/integration_tests/edgecore/unconfigurePort5.txt new file mode 100644 index 0000000..0e66ce9 --- /dev/null +++ b/test_cases/integration_tests/edgecore/unconfigurePort5.txt @@ -0,0 +1,8 @@ +admin +secret +enable +enable +configure +interface ethernet 1/1 +shutdown +quit \ No newline at end of file diff --git a/test_cases/integration_tests/keymile/backup.txt b/test_cases/integration_tests/keymile/backup.txt new file mode 100644 index 0000000..df2a0c5 --- /dev/null +++ b/test_cases/integration_tests/keymile/backup.txt @@ -0,0 +1,7 @@ +manager +secret +ftpserver 128.0.0.2 testuser testpass +cd /cfgm +save +upload /cfgm/configuration /testtftp/backups/keymilebackup.conf +exit \ No newline at end of file diff --git a/test_cases/integration_tests/keymile/getDslam.txt b/test_cases/integration_tests/keymile/getDslam.txt new file mode 100644 index 0000000..45ada2c --- /dev/null +++ b/test_cases/integration_tests/keymile/getDslam.txt @@ -0,0 +1,4 @@ +manager +secret +ls +exit \ No newline at end of file diff --git a/test_cases/integration_tests/keymile/getInventory.txt b/test_cases/integration_tests/keymile/getInventory.txt new file mode 100644 index 0000000..9af6ec6 --- /dev/null +++ b/test_cases/integration_tests/keymile/getInventory.txt @@ -0,0 +1,18 @@ +manager +secret +ls +cd /services/packet/nto1/ +ls +cd /services/packet/nto1/srvc-1/cfgm +get Service +cd /unit-11 +ls +cd /unit-19/main +get HardwareAndSoftware +get CurrentStatus +get EquipmentInventory +cd /unit-1/port-1 +ls +cd /unit-1/port-1/main +get OperationalStatus +exit \ No newline at end of file diff --git a/test_cases/integration_tests/keymile/getIpsx.txt b/test_cases/integration_tests/keymile/getIpsx.txt new file mode 100644 index 0000000..6537d4b --- /dev/null +++ b/test_cases/integration_tests/keymile/getIpsx.txt @@ -0,0 +1,8 @@ +manager +secret +cd /unit-19/status +get SubscriberList +cd /unit-19/cfgm +get SIP +get IP +exit \ No newline at end of file diff --git a/test_cases/integration_tests/keymile/getMonitoring.txt b/test_cases/integration_tests/keymile/getMonitoring.txt new file mode 100644 index 0000000..eaecda9 --- /dev/null +++ b/test_cases/integration_tests/keymile/getMonitoring.txt @@ -0,0 +1,13 @@ +manager +secret +ls +cd status +get CurrTemperature +cd .. +cd fan +ls +cd .. +cd unit-1 +ls +cd .. +exit \ No newline at end of file diff --git a/test_cases/integration_tests/keymile/getState.txt b/test_cases/integration_tests/keymile/getState.txt new file mode 100644 index 0000000..0cd3a14 --- /dev/null +++ b/test_cases/integration_tests/keymile/getState.txt @@ -0,0 +1,58 @@ +manager +secret +cd /unit-1/port-1/status +get AttainableRate +cd /unit-1/port-1/main +get AdministrativeStatus +get OperationalStatus +cd /unit-1/port-1/chan-1/cfgm +get ProfileName +cd /unit-5/port-1/chan-1/cfgm +get ChanProfile +cd /unit-1/port-1/chan-1/status +get status +cd /unit-1/port-1/chan-1/vcc-1/cfgm +get configuredProfiles +cd /unit-1/port-1/chan-1/vcc-1/status +get ServiceStatus +cd /unit-11 +ls +cd /unit-19 +ls +cd /unit-7/port-1/main +get AdministrativeStatus +get OperationalStatus +cd /unit-7/port-1 +ls +cd /unit-7/port-1/status +get PortMacStatus +get PortGeneralStatus +cd /unit-7/port-1/interface-1/cfgm +get configuredProfiles +get vlanProfile +get IfRateLimiting +cd /unit-7/port-1/interface-1/status +get ServiceStatus +cd /unit-7/port-1/status +get DDMStatus +cd /unit-2/port-1/main +ls +cd /unit-2/port-1/status +ls +get LineActualState +get LineOperationState +cd /unit-2/logports/logport-2/status +get ActualStatus +get OperationalWireState +cd /unit-2/logports/logport-2/main +get AdministrativeStatus +get OperationalStatus +cd /unit-2/logports/logport-2/cfgm +get SpanProfiles +cd /unit-2/logports/logport-2/interface-1/cfgm +get configuredProfiles +get vlanProfile +cd /unit-2/logports/logport-2/interface-1/status +get ServiceStatus +ls +exit \ No newline at end of file diff --git a/test_cases/integration_tests/keymile/getSubscriber.txt b/test_cases/integration_tests/keymile/getSubscriber.txt new file mode 100644 index 0000000..601fc6a --- /dev/null +++ b/test_cases/integration_tests/keymile/getSubscriber.txt @@ -0,0 +1,5 @@ +manager +secret +cd /unit-19/portgroup-1/port-1/status +get SubscriberList +exit \ No newline at end of file diff --git a/test_cases/integration_tests/keymile/getVoice.txt b/test_cases/integration_tests/keymile/getVoice.txt new file mode 100644 index 0000000..0f51655 --- /dev/null +++ b/test_cases/integration_tests/keymile/getVoice.txt @@ -0,0 +1,7 @@ +manager +secret +cd /unit-19/portgroup-1/port-1/cfgm +get pstnport +cd /unit-19/portgroup-2/port-1/cfgm +get isdnport +exit \ No newline at end of file diff --git a/test_cases/integration_tests/keymile/setChannelProfile.txt b/test_cases/integration_tests/keymile/setChannelProfile.txt new file mode 100644 index 0000000..1697bff --- /dev/null +++ b/test_cases/integration_tests/keymile/setChannelProfile.txt @@ -0,0 +1,9 @@ +manager +secret +cd /unit-5/port-1/chan-1/cfgm +set chanprofile profile +set chanprofile default +cd /unit-5/port-1/chan-1/cfgm +set ProfileName $profile +set ProfileName default +exit \ No newline at end of file diff --git a/test_cases/integration_tests/keymile/setInterface.txt b/test_cases/integration_tests/keymile/setInterface.txt new file mode 100644 index 0000000..dc0e318 --- /dev/null +++ b/test_cases/integration_tests/keymile/setInterface.txt @@ -0,0 +1,12 @@ +manager +secret +cd /unit-2/logports/logport-2/cfgm +CreateInterface default VCC_1_100 +DeleteInterface all +cd /unit-7/port-1/cfgm +CreateInterface default VCC_1_32100 +DeleteInterface all +cd /unit-5/port-1/chan-1/cfgm +CreateInterface default VC 1wdf +DeleteInterface all +exit \ No newline at end of file diff --git a/test_cases/integration_tests/keymile/setIpAddr.txt b/test_cases/integration_tests/keymile/setIpAddr.txt new file mode 100644 index 0000000..1a31d6d --- /dev/null +++ b/test_cases/integration_tests/keymile/setIpAddr.txt @@ -0,0 +1,15 @@ +manager +secret +cd /services/packet/1to1SingleTag/srvc-1/cfgm +set Service /unit-19/control 11 CoS0 Add +cd /services/packet/1to1SingleTag/srvc-2/cfgm +set Service /unit-19/media 1 CoS0 Add +cd /unit-19/cfgm +set Ip 11.1.1.1 155.255.255.0 2.3.3.3 +cd /cfgm +save +cd /unit-19/main +restart +manager +secret +exit \ No newline at end of file diff --git a/test_cases/integration_tests/keymile/setPortActive.txt b/test_cases/integration_tests/keymile/setPortActive.txt new file mode 100644 index 0000000..4f2f968 --- /dev/null +++ b/test_cases/integration_tests/keymile/setPortActive.txt @@ -0,0 +1,11 @@ +manager +secret +cd /unit-1/port-1/main +set AdministrativeStatus up +cd /unit-5/port-1/main +set AdministrativeStatus up +cd /unit-7/port-1/main +set AdministrativeStatus up +cd /unit-2/logports/logport-2/main +set AdministrativeStatus up +exit \ No newline at end of file diff --git a/test_cases/integration_tests/keymile/setPortDeactive.txt b/test_cases/integration_tests/keymile/setPortDeactive.txt new file mode 100644 index 0000000..79b499f --- /dev/null +++ b/test_cases/integration_tests/keymile/setPortDeactive.txt @@ -0,0 +1,11 @@ +manager +secret +cd /unit-1/port-1/main +set AdministrativeStatus down +cd /unit-5/port-1/main +set AdministrativeStatus down +cd /unit-7/port-1/main +set AdministrativeStatus down +cd /unit-2/logports/logport-2/main +set AdministrativeStatus down +exit \ No newline at end of file diff --git a/test_cases/integration_tests/keymile/setPortProfile.txt b/test_cases/integration_tests/keymile/setPortProfile.txt new file mode 100644 index 0000000..0b30451 --- /dev/null +++ b/test_cases/integration_tests/keymile/setPortProfile.txt @@ -0,0 +1,5 @@ +manager +secret +cd /unit-6/port-1/cfgm +set portprofiles true default 0 false default 0 false default 0 true default Priority +exit \ No newline at end of file diff --git a/test_cases/integration_tests/keymile/setSIPDomain.txt b/test_cases/integration_tests/keymile/setSIPDomain.txt new file mode 100644 index 0000000..a973089 --- /dev/null +++ b/test_cases/integration_tests/keymile/setSIPDomain.txt @@ -0,0 +1,10 @@ +manager +secret +cd /unit-19/cfgm +get Sip +set Proxy PrimaryOnly domain 5060 "" 0 true Options 10 "" 0 true Options 10 +set Registrar domain 5060 OneByOneRegistration 1 +set Sip $name domain 5060 +49 area 500 4 false None true 30 false false 1800 +cd /cfgm +save +exit \ No newline at end of file diff --git a/test_cases/integration_tests/keymile/setTraffic.txt b/test_cases/integration_tests/keymile/setTraffic.txt new file mode 100644 index 0000000..0f61dff --- /dev/null +++ b/test_cases/integration_tests/keymile/setTraffic.txt @@ -0,0 +1,13 @@ +manager +secret +cd /unit-7 +ls +cd /unit-7/port-1/cfgm +Set Mode "Speed1000 Autoneg On" +Set FlowControl false +CreateInterface VLAN_name +cd /unit-7/port-1/cfgm +Set Mode "1000MbitsFullDuplex" +Set FlowControl false +CreateInterface VLAN_name +exit \ No newline at end of file diff --git a/test_cases/integration_tests/keymile/setVCC.txt b/test_cases/integration_tests/keymile/setVCC.txt new file mode 100644 index 0000000..2000864 --- /dev/null +++ b/test_cases/integration_tests/keymile/setVCC.txt @@ -0,0 +1,6 @@ +manager +secret +cd /unit-1/port-1/chan-1/cfgm +CreateVcc default default +DeleteVcc all +exit \ No newline at end of file diff --git a/test_cases/integration_tests/keymile/setconfDsl.txt b/test_cases/integration_tests/keymile/setconfDsl.txt new file mode 100644 index 0000000..fe71c9a --- /dev/null +++ b/test_cases/integration_tests/keymile/setconfDsl.txt @@ -0,0 +1,18 @@ +manager +secret +cd /unit-1/port-1/main +Set Labels "umlctId)" "arrierId" "" +set AdministrativeStatus up +cd /unit-5/port-1/main +Set Labels "Id" "ierLind" "" +set AdministrativeStatus up +cd /unit-7/port-1/main +Set Labels "ctId" "d" "" +set AdministrativeStatus up +cd /unit-2/logports/cfgm +create port-1 default +cd /unit-2/logports/logport-1/cfgm +CreateInterface name +cd /unit-2/logports/logport-1/main +set AdministrativeStatus up +exit \ No newline at end of file diff --git a/test_cases/integration_tests/keymile/setconfVoice.txt b/test_cases/integration_tests/keymile/setconfVoice.txt new file mode 100644 index 0000000..66632b0 --- /dev/null +++ b/test_cases/integration_tests/keymile/setconfVoice.txt @@ -0,0 +1,16 @@ +manager +secret +cd /unit-19/portgroup-1/port-1/cfgm +set pstnport true { 11 } true false none none none none none +cd /unit-19/portgroup-1/port-1/main +Set Labels "ssdd" "sssd" "" +cd /unit-19/port-1/main +set AdministrativeStatus up +Set Labels www "carrierLineId" "" +cd /unit-19/portgroup-2/port-1/cfgm +set isdnport true {112} true false none none none none none +cd /unit-19/portgroup-2/port-1/main +Set Labels dada "test" "" +cd /unit-19/port-1/main +set AdministrativeStatus up +exit \ No newline at end of file diff --git a/test_cases/integration_tests/keymile/setdeconfVoicePort.txt b/test_cases/integration_tests/keymile/setdeconfVoicePort.txt new file mode 100644 index 0000000..33b5824 --- /dev/null +++ b/test_cases/integration_tests/keymile/setdeconfVoicePort.txt @@ -0,0 +1,6 @@ +manager +secret +cd /unit-19/portgroup-1/port-1/cfgm +get pstnport +cd / +exit \ No newline at end of file diff --git a/test_cases/integration_tests/keymile/setdeconfVoicePortIsdn.txt b/test_cases/integration_tests/keymile/setdeconfVoicePortIsdn.txt new file mode 100644 index 0000000..4af0ac6 --- /dev/null +++ b/test_cases/integration_tests/keymile/setdeconfVoicePortIsdn.txt @@ -0,0 +1,24 @@ +manager +secret +cd /unit-19/port-1/main +set AdministrativeStatus down +Set Labels "" "" "" +cd /unit-19/portgroup-1/port-1/cfgm +Set pstnport false {} true false none none none none none +cd /unit-19/portgroup-1/port-1/main +Set Labels "" "" "" +cd /unit-19/port-1/main +set AdministrativeStatus down +Set Labels "" "" "" +cd /unit-19/portgroup-2/port-1/cfgm +Set isdnport false {} true false false none none none none +cd /unit-19/portgroup-2/port-1/main +Set Labels "" "" "" + + + + + + + +exit \ No newline at end of file diff --git a/test_cases/integration_tests/keymile/setunconfDsl.txt b/test_cases/integration_tests/keymile/setunconfDsl.txt new file mode 100644 index 0000000..c8406f4 --- /dev/null +++ b/test_cases/integration_tests/keymile/setunconfDsl.txt @@ -0,0 +1,18 @@ +manager +secret +cd /unit-1/port-1/main +set AdministrativeStatus down +Set Labels "" "" "" +cd /unit-5/port-1/main +set AdministrativeStatus down +Set Labels "" "" "" +cd /unit-7/port-1/main +set AdministrativeStatus down +Set Labels "" "" "" +cd /unit-2/logports/logport-2/main +set AdministrativeStatus down +Set Labels "" "" "" +cd /unit-2/logports/logport-2/main +cd /unit-2/logports/cfgm +Delete logport-2 +exit \ No newline at end of file diff --git a/test_cases/integration_tests/keymile/testLoopback.txt b/test_cases/integration_tests/keymile/testLoopback.txt new file mode 100644 index 0000000..898cae6 --- /dev/null +++ b/test_cases/integration_tests/keymile/testLoopback.txt @@ -0,0 +1,8 @@ +manager +secret +cd /unit-19/port-1/status +Lock +/unit-19/port-1/status/StartQuickLoopbackTest +get QuickLoopbackTest +Unlock +exit \ No newline at end of file diff --git a/test_cases/integration_tests/keymile/testVoicePort.txt b/test_cases/integration_tests/keymile/testVoicePort.txt new file mode 100644 index 0000000..cacc582 --- /dev/null +++ b/test_cases/integration_tests/keymile/testVoicePort.txt @@ -0,0 +1,9 @@ +manager +secret +cd /unit-19/main +get HardwareAndSoftware +/unit-19/port-1/status/StartLineTest +get /unit-19/port-1/status/LineTestResults +cd /unit-6/port-1/main +set AdministrativeStatus up +exit \ No newline at end of file diff --git a/test_cases/integration_tests/keymile/testmelting.txt b/test_cases/integration_tests/keymile/testmelting.txt new file mode 100644 index 0000000..4255a3d --- /dev/null +++ b/test_cases/integration_tests/keymile/testmelting.txt @@ -0,0 +1,9 @@ +manager +secret +/unit-19/port-1/status/StartLineTest +get /unit-19/port-1/status/LineTestResults +/unit-1/port-1/status/StartMeltMeasurement +get /unit-1/port-1/status/MeltResults +cd /unit-6/port-1/main +set AdministrativeStatus up +exit \ No newline at end of file diff --git a/test_cases/unit_tests/edgecore/test_edgecore.py b/test_cases/unit_tests/edgecore/test_edgecore.py index 2bc31a7..1885d33 100644 --- a/test_cases/unit_tests/edgecore/test_edgecore.py +++ b/test_cases/unit_tests/edgecore/test_edgecore.py @@ -11,23 +11,84 @@ # License: https://github.com/inexio/NESi/LICENSE.rst from test_cases.unit_tests.test_core import TestCore +import pytest +from os import listdir +from os.path import isfile, join class TestEdgecore(TestCore): + PATH = 'test_cases/integration_tests/edgecore/' + DATA = [f for f in listdir('test_cases/integration_tests/edgecore/') if + isfile(join('test_cases/integration_tests/edgecore/', f)) and f != 'output.txt'] - def test_portup_portdown(self): - port = self.model.get_port("name", '1/1/1/1') - assert(self.model.get_port("name", '1/1/1/1').admin_state == '0') - port.admin_up() - assert(self.model.get_port("name", '1/1/1/1').admin_state == '1') - port.admin_down() - assert(self.model.get_port("name", '1/1/1/1').admin_state == '0') - - def test_ontportup_portdown(self): - port = self.model.get_ont_port("name", '1/1/4/1/1/1/1') - assert(self.model.get_ont_port("name", '1/1/4/1/1/1/1').admin_state == '0') - port.admin_up() - assert(self.model.get_ont_port("name", '1/1/4/1/1/1/1').admin_state == '1') - port.admin_down() - assert(self.model.get_ont_port("name", '1/1/4/1/1/1/1').admin_state == '0') + def test_box(self): + box = self.model + box.set('management_start_address', 'test') + box.set('management_end_address', 'test') + box.set('logging_host', 'test') + box.set('logging_port', 'test') + box.set('logging_level', 8) + box.set('loopback_detection_action', 'shutdown') + box.set('sntp_server_ip', '') + box.set('sntp_client', 'Enabled') + box.set('timezone_name', '') + box.set('timezone_time', '') + box.set('summer_time_name', 'test') + box.set('summer_time_region', 'test') + assert box.management_start_address == 'test' + assert box.management_end_address == 'test' + assert box.logging_host == 'test' + assert box.logging_port == 'test' + assert box.logging_level == 8 + assert box.loopback_detection_action == 'shutdown' + assert box.sntp_server_ip == '' + assert box.sntp_client == 'Enabled' + assert box.timezone_name == '' + assert box.timezone_time == '' + assert box.summer_time_name == 'test' + assert box.summer_time_region == 'test' + + def test_card(self): + card = self.model.get_card("name", '1') + card.set('mac_address', '11-11-11-11') + card.set('admin_state', '1') + card.set('operational_state', '1') + + assert card.mac_address == '11-11-11-11' + assert card.admin_state == '1' + assert card.operational_state == '1' + + def test_port(self): + port = self.model.get_port("name", '1/1') + port.set('mac_address', '11-11-11-11') + port.set('admin_state', '1') + port.set('operational_state', '1') + + assert port.mac_address == '11-11-11-11' + assert port.admin_state == '1' + assert port.operational_state == '1' + + def test_interface(self): + interface = self.model.get_interface("name", '1/1') + interface.set('ingress_state', 'Enabled') + interface.set('ingress_rate', 1) + interface.set('egress_state', 'Enabled') + interface.set('egress_rate', 1) + interface.set('vlan_membership_mode', 'Access') + interface.set('native_vlan', 1010) + interface.set('mac_address', '11-11-11-11') + interface.set('allowed_vlan', '1,1010(u)') + + assert interface.ingress_state == 'Enabled' + assert interface.ingress_rate == 1 + assert interface.egress_state == 'Enabled' + assert interface.egress_rate == 1 + assert interface.vlan_membership_mode == 'Access' + assert interface.native_vlan == 1010 + assert interface.mac_address == '11-11-11-11' + assert interface.allowed_vlan == '1,1010(u)' + + @pytest.mark.parametrize("path", DATA) + def test_integration(self, path): + self.run(self.PATH + path, self.PATH + 'output.txt') diff --git a/test_cases/unit_tests/huawei/test_huawei.py b/test_cases/unit_tests/huawei/test_huawei.py index dc2d5e9..e836525 100644 --- a/test_cases/unit_tests/huawei/test_huawei.py +++ b/test_cases/unit_tests/huawei/test_huawei.py @@ -192,12 +192,12 @@ def test_service_vlan(self): assert True def test_user(self): - user = self.model.get_user("name", 'root') - assert user.lock_status == 'Unlocked' + user = self.model.get_user("name", 'Root') + assert user.lock_status == 'unlocked' user.lock() - assert user.lock_status == 'Locked' + assert user.lock_status == 'locked' user.unlock() - assert user.lock_status == 'Unlocked' + assert user.lock_status == 'unlocked' assert user.reenter_num_temp == 3 user.set_reenter_num_temp(1) @@ -208,11 +208,11 @@ def test_user(self): except exceptions.SoftboxenError: assert True - assert user.status == 'Offline' + assert user.status == 'offline' user.set_online() - assert user.status == 'Online' + assert user.status == 'online' user.set_offline() - assert user.status == 'Offline' + assert user.status == 'offline' def test_vlan(self): vlan = self.model.get_vlan('number', 2620) diff --git a/test_cases/unit_tests/keymile/test_keymile.py b/test_cases/unit_tests/keymile/test_keymile.py index db82172..db68fa4 100644 --- a/test_cases/unit_tests/keymile/test_keymile.py +++ b/test_cases/unit_tests/keymile/test_keymile.py @@ -11,23 +11,72 @@ # License: https://github.com/inexio/NESi/LICENSE.rst from test_cases.unit_tests.test_core import TestCore +import pytest +from os import listdir +from os.path import isfile, join class TestKeymile(TestCore): + PATH = 'test_cases/integration_tests/keymile/' + DATA = [f for f in listdir('test_cases/integration_tests/keymile/') if + isfile(join('test_cases/integration_tests/keymile/', f)) and f != 'output.txt'] - def test_portup_portdown(self): - port = self.model.get_port("name", '1/1/1/1') - assert(self.model.get_port("name", '1/1/1/1').admin_state == '0') - port.admin_up() - assert(self.model.get_port("name", '1/1/1/1').admin_state == '1') - port.admin_down() - assert(self.model.get_port("name", '1/1/1/1').admin_state == '0') - - def test_ontportup_portdown(self): - port = self.model.get_ont_port("name", '1/1/4/1/1/1/1') - assert(self.model.get_ont_port("name", '1/1/4/1/1/1/1').admin_state == '0') - port.admin_up() - assert(self.model.get_ont_port("name", '1/1/4/1/1/1/1').admin_state == '1') - port.admin_down() - assert(self.model.get_ont_port("name", '1/1/4/1/1/1/1').admin_state == '0') + def test_box(self): + assert True + def test_card(self): + card = self.model.get_card("name", '19') + card.set_sip('gateway_name', 'home_domain', 1, 'country_code', 'area_code', 12, 11, True, 'Asserted', False, + 1, False, False, 1222) + assert card.gateway_name == 'gateway_name' + assert card.uas_request_timer is False + card.set_ip('1.1.1.1', '2.22.2.2', '111.111.111.111') + assert card.subnet_mask == '2.22.2.2' + card.set_label('"l1"', '"l2"', 'desc') + assert card.label1 == '"l1"' + card.set_proxy('PrimaryOnly', 'proxy_address', 11, 'proxy_address_sec', 12, True, + 'Register', 33) + assert card.proxy_mode == 'PrimaryOnly' + assert card.proxy_interval == 33 + + def test_channel(self): + channel = self.model.get_chan('id', 1) + channel.set_profile_name('name') + assert channel.chan_profile_name == 'name' + + def test_port(self): + port = self.model.get_port('id', 1) + port.set_profiles(True, 'n1', 1, False, 'n2', 0, True, 'dff', 11, False, 'n4', 'Priority') + assert port.profile1_name == 'n1' + assert port.profile1_enable is True + port.set_test_state('Passed') + assert port.loopbacktest_state == 'Passed' + port.lock_admin() + assert port.admin_state == '2' + port.unlock_admin() + assert port.admin_state == '3' + port.set_melttest_state('Passed') + assert port.melttest_state == 'Passed' + port.set_linetest_state('Passed') + assert port.linetest_state == 'Passed' + port.set_mode('mode') + assert port.mode == 'mode' + port.set_flow_control('test') + assert port.flow_control == 'test' + + def test_portgroupport(self): + port = self.model.get_portgroupport('name', '19/G1/1') + port.set_pstnport(True, True, True, 'sip', 'proxy', 'codec', 'pstn', 'enterprise') + assert port.enable is True + assert port.enterprise_profile == 'enterprise' + port.set_isdnport(False, True, True, True, 'sip', 'proxy', 'codec', 'isdn') + assert port.enable is False + assert port.isdnba_profile == 'isdn' + + def test_srcv(self): + srvc = self.model.get_srvc('id', 2) + srvc.set_service('address', 11, 'CoS0', 'Add') + + @pytest.mark.parametrize("path", DATA) + def test_integration(self, path): + self.run(self.PATH + path, self.PATH + 'output.txt') diff --git a/vendors/EdgeCore/__init__.py b/vendors/EdgeCore/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/vendors/EdgeCore/baseCommandProcessor.py b/vendors/EdgeCore/baseCommandProcessor.py new file mode 100644 index 0000000..9dc0d3c --- /dev/null +++ b/vendors/EdgeCore/baseCommandProcessor.py @@ -0,0 +1,74 @@ +# This file is part of the NESi software. +# +# Copyright (c) 2020 +# Original Software Design by Ilya Etingof . +# +# Software adapted by inexio . +# - Janis Groß +# - Philip Konrath +# - Alexander Dincher +# +# License: https://github.com/inexio/NESi/LICENSE.rst + +from nesi import exceptions +from nesi.softbox.cli import base + + +class BaseCommandProcessor(base.CommandProcessor): + """Create CLI REPR loop for example switch.""" + + def map_states(self, object, type): + if object.admin_state == '0': + if type in ('port', 'card'): + object.admin_state = 'Down' + elif object.admin_state == '1': + if type in ('port', 'card'): + object.admin_state = 'Up' + + if object.operational_state == '0': + if type in 'port': + object.operational_state = 'Down' + + elif object.operational_state == '1': + if type in 'port': + object.operational_state = 'Up' + + def do_exit(self, command, *args, context=None): + exc = exceptions.TerminalExitError() + raise exc + + def do_quit(self, command, *args, context=None): + exc = exceptions.TerminalExitError() + exc.return_to = 'sysexit' + raise exc + + def on_unknown_command(self, command, *args, context=None): + raise exceptions.CommandSyntaxError(command=command) + + def create_spacers(self, positions, args): + spacers = [] + previous_pos = 0 + i = 0 + for position in positions: + spacer = position - (previous_pos + len(str(args[i]))) + spacers.append(spacer) + previous_pos = position + i += 1 + + return spacers + + def user_input(self, prompt, allow_history=True, tmp_boundary=None): + self._write(prompt) + prompt_end_pos = self.prompt_end_pos + self.prompt_end_pos = len(prompt) - 1 + if not allow_history: + self.history_enabled = False + + if len(self.line_buffer) != 0: + input = self.line_buffer.pop(0) + else: + input = self._read(tmp_boundary).strip() + if not allow_history: + self.history_enabled = True + self.prompt_end_pos = prompt_end_pos + return input diff --git a/vendors/EdgeCore/configCommandProcessor.py b/vendors/EdgeCore/configCommandProcessor.py new file mode 100644 index 0000000..34f17c3 --- /dev/null +++ b/vendors/EdgeCore/configCommandProcessor.py @@ -0,0 +1,182 @@ +# This file is part of the NESi software. +# +# Copyright (c) 2020 +# Original Software Design by Ilya Etingof . +# +# Software adapted by inexio . +# - Janis Groß +# - Philip Konrath +# - Alexander Dincher +# +# License: https://github.com/inexio/NESi/LICENSE.rst +import random +import datetime +import re +import time + +from nesi import exceptions +from .baseCommandProcessor import BaseCommandProcessor + + +class ConfigCommandProcessor(BaseCommandProcessor): + + def on_unknown_command(self, command, *args, context=None): + if self._validate(command, '?'): + text = self._render( + '?', + context=context) + self._write(text) + else: + raise exceptions.CommandSyntaxError(command=command) + + def do_interface(self, command, *args, context=None): + if self._validate(args, 'ethernet', str): + interface_name, = self._dissect(args, 'ethernet', str) + + try: + _ = self._model.get_interface('name', interface_name) + except exceptions.SoftboxenError: + raise exceptions.CommandSyntaxError(command=command) + + from .interfaceCommandProcessor import InterfaceCommandProcessor + + subprocessor = self._create_subprocessor(InterfaceCommandProcessor, 'login', 'mainloop', 'enable', 'config', + 'interface') + subprocessor.set_interface_name(interface_name) + subprocessor.loop(return_to=ConfigCommandProcessor, context=dict(context)) + else: + raise exceptions.CommandSyntaxError(command=command) + + def do_vlan(self, command, *args, context=None): + if self._validate(args, 'database'): + from .vlanCommandProcessor import VlanCommandProcessor + + subprocessor = self._create_subprocessor(VlanCommandProcessor, 'login', 'mainloop', 'enable', 'config', + 'vlan') + subprocessor.loop(return_to=ConfigCommandProcessor, context=dict(context)) + else: + raise exceptions.CommandSyntaxError(command=command) + + def do_no(self, command, *args, context=None): + if self._validate(args, 'logging', 'host', str): + host, = self._dissect(args, 'logging', 'host', str) + box = self._model + if host in box.logging_host: + addresss = box.logging_host.split(', ') + ports = box.logging_port.split(', ') + index = 0 + for address in addresss: + if address == host: + break + index += 1 + addresss.remove(host) + ports.pop(index) + address_list = ', '.join(addresss) + port_list = ', '.join(ports) + box.set('logging_host', address_list) + box.set('logging_port', port_list) + else: + pass + else: + raise exceptions.CommandSyntaxError(command=command) + + def do_management(self, command, *args, context=None): + if self._validate(args, 'all-client', str, str): + start, end = self._dissect(args, 'all-client', str, str) + box = self._model + box.set('management_start_address', start) + box.set('management_end_address', end) + else: + raise exceptions.CommandSyntaxError(command=command) + + def do_loopback_detection(self, command, *args, context=None): + if self._validate(args, 'action', str): + prop, = self._dissect(args, 'action', str) + box = self._model + box.set('loopback_detection_action', prop) + else: + raise exceptions.CommandSyntaxError(command=command) + + def do_sntp(self, command, *args, context=None): + if self._validate(args, 'server', str): + ip, = self._dissect(args, 'server', str) + box = self._model + box.set('sntp_server_ip', ip) + elif self._validate(args, 'client'): + box = self._model + box.set('sntp_client', 'Enabled') + else: + raise exceptions.CommandSyntaxError(command=command) + + def do_clock(self, command, *args, context=None): + if self._validate(args, 'timezone', str, 'hours', str, 'minute', str): + name, h, m = self._dissect(args, 'timezone', str, 'hours', str, 'minute', str) + box = self._model + box.set('timezone_name', name) + box.set('timezone_time', (h + ',' + m)) + elif self._validate(args, 'summer-time', str, 'predefined', str): + name, region = self._dissect(args, 'summer-time', str, 'predefined', str) + box = self._model + box.set('summer_time_name', name) + box.set('summer_time_region', region) + else: + raise exceptions.CommandSyntaxError(command=command) + + def do_prompt(self, command, *args, context=None): + if self._validate(args, str): + name, = self._dissect(args, str) + box = self._model + box.set('hostname', name) + self.set_prompt_end_pos(context) + else: + raise exceptions.CommandSyntaxError(command=command) + + def do_hostname(self, command, *args, context=None): + if self._validate(args, str): + name, = self._dissect(args, str) + box = self._model + box.set('hostname', name) + self.set_prompt_end_pos(context) + else: + raise exceptions.CommandSyntaxError(command=command) + + def do_logging(self, command, *args, context=None): + if self._validate(args, 'host', str, 'port', str): + host, port = self._dissect(args, 'host', str, 'port', str) + box = self._model + if host not in box.logging_host: + address_list = box.logging_host + ', ' + host + port_list = box.logging_port + ', ' + port + box.set('logging_host', address_list) + box.set('logging_port', port_list) + + elif self._validate(args, 'trap'): + box = self._model + box.set('logging_level', 7) + else: + raise exceptions.CommandSyntaxError(command=command) + + def do_ip(self, command, *args, context=None): + if self._validate(args, 'dhcp', 'snooping'): + pass # No visible changes + + elif self._validate(args, 'dhcp', 'snooping', 'vlan', str): + pass # No visible changes + + elif self._validate(args, 'dhcp', 'snooping', 'information', 'option', 'encode', 'no-subtype'): + pass # No visible changes + + elif self._validate(args, 'dhcp', 'snooping', 'information', 'option', 'remote-id', 'string', str, 'sub-option', + 'port-description'): + pass # No visible changes + + else: + raise exceptions.CommandSyntaxError(command=command) + + def do_pppoe(self, command, *args, context=None): + if self._validate(args, 'intermediate-agent'): + pass # No visible changes + + else: + raise exceptions.CommandSyntaxError(command=command) + diff --git a/vendors/EdgeCore/enableCommandProcessor.py b/vendors/EdgeCore/enableCommandProcessor.py new file mode 100644 index 0000000..d3f392e --- /dev/null +++ b/vendors/EdgeCore/enableCommandProcessor.py @@ -0,0 +1,155 @@ +# This file is part of the NESi software. +# +# Copyright (c) 2020 +# Original Software Design by Ilya Etingof . +# +# Software adapted by inexio . +# - Janis Groß +# - Philip Konrath +# - Alexander Dincher +# +# License: https://github.com/inexio/NESi/LICENSE.rst +from datetime import datetime + +from nesi import exceptions +from .baseCommandProcessor import BaseCommandProcessor +import time + + +class EnableCommandProcessor(BaseCommandProcessor): + + def do_disable(self, command, *args, context=None): + + from .userViewCommandProcessor import UserViewCommandProcessor + + exc = exceptions.TerminalExitError() + exc.return_to = UserViewCommandProcessor + raise exc + + def do_exit(self, command, *args, context=None): + exc = exceptions.TerminalExitError() + exc.return_to = 'sysexit' + raise exc + + def on_unknown_command(self, command, *args, context=None): + if command == '?' and args == (): + text = self._render('?', context=context) + self._write(text) + else: + raise exceptions.CommandSyntaxError(command=command) + + def do_configure(self, command, *args, context=None): + + from .configCommandProcessor import ConfigCommandProcessor + + subprocessor = self._create_subprocessor( + ConfigCommandProcessor, 'login', 'mainloop', 'enable', 'config') + + subprocessor.loop(context=context, return_to=EnableCommandProcessor) + + def do_config(self, command, *args, context=None): + + from .configCommandProcessor import ConfigCommandProcessor + + subprocessor = self._create_subprocessor( + ConfigCommandProcessor, 'login', 'mainloop', 'enable', 'config') + + subprocessor.loop(context=context, return_to=EnableCommandProcessor) + + def do_show(self, command, *args, context=None): + if command == '?' and args == (): + text = self._render('show_?', context=context) + self._write(text) + elif self._validate(args, 'interfaces', 'status', 'ethernet', str): + port_name, = self._dissect(args, 'interfaces', 'status', 'ethernet', str) + try: + port = self._model.get_port('name', port_name) + self.map_states(port, 'port') + interface = self._model.get_interface('name', port_name) + except exceptions.SoftboxenError: + raise exceptions.CommandSyntaxError(command=command) + # TODO: Information of Interface + text = self._render('show_interface_status', context=dict(context, port=port, interface=interface)) + self._write(text) + elif self._validate(args, 'interfaces', 'switchport', 'ethernet', str): + port_name, = self._dissect(args, 'interfaces', 'switchport', 'ethernet', str) + try: + port = self._model.get_port('name', port_name) + self.map_states(port, 'port') + interface = self._model.get_interface('name', port_name) + except exceptions.SoftboxenError: + raise exceptions.CommandSyntaxError(command=command) + # TODO: Information of Interface + text = self._render('show_interface_switchport', context=dict(context, port=port, interface=interface)) + self._write(text) + elif self._validate(args, 'interfaces', 'transceiver', 'ethernet', str): + port_name, = self._dissect(args, 'interfaces', 'transceiver', 'ethernet', str) + try: + port = self._model.get_port('name', port_name) + self.map_states(port, 'port') + interface = self._model.get_interface('name', port_name) + except exceptions.SoftboxenError: + raise exceptions.CommandSyntaxError(command=command) + # TODO: Information of Interface + # erst ab port 25-28 + text = self._render('show_interface_transceiver', context=dict(context, port=port, interface=interface)) + self._write(text) + elif self._validate(args, 'system'): + try: + card = self._model.get_card('name', "1") + self.map_states(card, 'card') + box = self._model + except exceptions.SoftboxenError: + raise exceptions.CommandSyntaxError(command=command) + text = self._render('show_system', context=dict(context, card=card, box=box)) + self._write(text) + elif self._validate(args, 'process', 'cpu'): + text = self._render('show_process_cpu', context=context) + self._write(text) + elif self._validate(args, 'memory'): + text = self._render('show_memory', context=context) + self._write(text) + elif self._validate(args, 'mac-address-table'): + text = self._render('show_mac_address_table', context=context) + for interface in self._model.interfaces: + text += self._render('show_mac_address_table_entry', context=dict(context, interface=interface)) + card = self._model.get_card('name', "1") + self.map_states(card, 'card') + text += self._render('show_mac_address_table_unit', context=dict(context, card=card)) + self._write(text) + else: + raise exceptions.CommandSyntaxError(command=command) + + def do_copy(self, command, *args, context=None): + if self._validate(args, 'startup-config', 'ftp'): # Work in progess + ip = self.user_input("FTP server IP address: ", False, None) + user = self.user_input("User [Anonymous]: ", False, None) + self.hide_input = True + pw = self.user_input("Password: ", False, None) + self.hide_input = False + dest = self.user_input("Destination file name: ", False, None) + + for creds in self._model.credentials: + if creds.username == user: + user = self._model.get_user('id', creds.user_id) + if user.profile == 'backup': + break + + if creds.password != pw or '/' not in dest or ip.count('.') != 3: + text = self._render('copy_startup_config_ftp_failure', context=context) + self._write(text) + else: + text = self._render('copy_startup_config_ftp_success', context=context) + self._write(text) + + else: + raise exceptions.CommandSyntaxError(command=command) + + def on_help(self, command, *args, context=None): + if args == (): + text = self._render( + 'help', + context=context) + self._write(text) + else: + raise exceptions.CommandSyntaxError(command=command) diff --git a/vendors/EdgeCore/interfaceCommandProcessor.py b/vendors/EdgeCore/interfaceCommandProcessor.py new file mode 100644 index 0000000..3003971 --- /dev/null +++ b/vendors/EdgeCore/interfaceCommandProcessor.py @@ -0,0 +1,212 @@ +# This file is part of the NESi software. +# +# Copyright (c) 2020 +# Original Software Design by Ilya Etingof . +# +# Software adapted by inexio . +# - Janis Groß +# - Philip Konrath +# - Alexander Dincher +# +# License: https://github.com/inexio/NESi/LICENSE.rst + +import random +import re +from datetime import datetime, date +from ipaddress import IPv4Network +from nesi import exceptions +from .baseCommandProcessor import BaseCommandProcessor + + +class InterfaceCommandProcessor(BaseCommandProcessor): + + component_name = None + + def set_interface_name(self, name): + self.component_name = name + + def get_actual_interface(self, command): + if self.component_name is None: + raise exceptions.CommandExecutionError(command='Component name is None') + try: + return self._model.get_interface('name', self.component_name) + except exceptions.SoftboxenError: + raise exceptions.CommandSyntaxError(command=command) + + def get_actual_port(self, command): + if self.component_name is None: + raise exceptions.CommandExecutionError(command='Component name is None') + try: + return self._model.get_port('name', self.component_name) + except exceptions.SoftboxenError: + raise exceptions.CommandSyntaxError(command=command) + + def do_shutdown(self, command, *args, context=None): + if len(args) == 0: + port = self.get_actual_port(command) + port.admin_down() + else: + raise exceptions.CommandSyntaxError(command=command) + + def do_no(self, command, *args, context=None): + if self._validate(args, 'shutdown'): + port = self.get_actual_port(command) + port.admin_up() + + elif self._validate(args, 'rate-limit', 'input'): + interface = self.get_actual_interface(command) + interface.set('ingress_state', 'Disabled') + + elif self._validate(args, 'rate-limit', 'output'): + interface = self.get_actual_interface(command) + interface.set('egress_state', 'Disabled') + + elif self._validate(args, 'description'): + port = self.get_actual_port(command) + port.set('description', '') + + elif self._validate(args, 'switchport', 'mode'): + interface = self.get_actual_interface(command) + interface.set('vlan_membership_mode', 'Hybrid') + interface.set('native_vlan', 1) + + elif self._validate(args, 'switchport', 'native', 'vlan'): + interface = self.get_actual_interface(command) + interface.set('native_vlan', 1) + + elif self._validate(args, 'switchport', 'allowed', 'vlan'): + interface = self.get_actual_interface(command) + interface.set('allowed_vlan', '1(u)') + + elif self._validate(args, 'pppoe', 'intermediate-agent', 'port-enable'): + pass # No visible changes + + elif self._validate(args, 'pppoe', 'intermediate-agent', 'port-format-type', 'circuit-id'): + pass # No visible changes + + elif self._validate(args, 'ip', 'dhcp', 'snooping', 'information', 'option', 'circuit-id', 'tr101', + 'no-vlan-field'): + pass # No visible changes + + elif self._validate(args, 'ip', 'dhcp', 'snooping', 'information', 'option', 'circuit-id'): + pass # No visible changes + + else: + raise exceptions.CommandSyntaxError(command=command) + + def do_rate_limit(self, command, *args, context=None): + if self._validate(args, 'input', str): + rate, = self._dissect(args, 'input', str) + interface = self.get_actual_interface(command) + interface.set('ingress_state', 'Enabled') + interface.set('ingress_rate', int(rate)) + elif self._validate(args, 'output', str): + rate, = self._dissect(args, 'output', str) + interface = self.get_actual_interface(command) + interface.set('egress_state', 'Enabled') + interface.set('egress_rate', int(rate)) + else: + raise exceptions.CommandSyntaxError(command=command) + + def do_description(self, command, *args, context=None): + if self._validate(args, str): + descr, = self._dissect(args, str) + port = self.get_actual_port(command) + port.set('description', descr) + else: + raise exceptions.CommandSyntaxError(command=command) + + def do_switchport(self, command, *args, context=None): + if self._validate(args, 'mode', 'hybrid'): + interface = self.get_actual_interface(command) + interface.set('vlan_membership_mode', 'Hybrid') + + elif self._validate(args, 'mode', 'access'): + interface = self.get_actual_interface(command) + interface.set('vlan_membership_mode', 'Access') + + elif self._validate(args, 'mode', 'trunk'): + interface = self.get_actual_interface(command) + interface.set('vlan_membership_mode', 'Trunk') + + elif self._validate(args, 'allowed', 'vlan', 'add', str, 'tagged'): + interface = self.get_actual_interface(command) + id_list, = self._dissect(args, 'allowed', 'vlan', 'add', str, 'tagged') + if ',' in id_list: + ids = id_list.split(',') + for id in ids: + try: + id = int(id) + _ = self._model.get_vlan('number', id) + except Exception: + raise exceptions.CommandSyntaxError(command=command) + else: + try: + id = int(id_list) + _ = self._model.get_vlan('number', id) + except Exception: + raise exceptions.CommandSyntaxError(command=command) + id_list = id_list + '(t)' + interface.set('allowed_vlan', id_list) + + elif self._validate(args, 'allowed', 'vlan', 'add', str, 'untagged'): + interface = self.get_actual_interface(command) + id_list, = self._dissect(args, 'allowed', 'vlan', 'add', str, 'untagged') + if ',' in id_list: + ids = id_list.split(',') + for id in ids: + try: + id = int(id) + _ = self._model.get_vlan('number', id) + except Exception: + raise exceptions.CommandSyntaxError(command=command) + else: + try: + id = int(id_list) + _ = self._model.get_vlan('number', id) + except Exception: + raise exceptions.CommandSyntaxError(command=command) + id_list = id_list + '(u)' + interface.set('allowed_vlan', id_list) + + elif self._validate(args, 'native', 'vlan', str): #untagged + vlan_id, = self._dissect(args, 'native', 'vlan', str) + interface = self.get_actual_interface(command) + try: + vlan = self._model.get_vlan('number', int(vlan_id)) + except exceptions.SoftboxenError: + raise exceptions.CommandSyntaxError(command=command) + interface.set('native_vlan', int(vlan_id)) + + else: + raise exceptions.CommandSyntaxError(command=command) + + def do_pppoe(self, command, *args, context=None): + if self._validate(args, 'intermediate-agent', 'port-enable'): + pass # No visible changes + + elif self._validate(args, 'intermediate-agent', 'trust'): + pass # No visible changes + + elif self._validate(args, 'intermediate-agent', 'port-format-type', 'circuit-id', str): + pass # No visible changes + + else: + raise exceptions.CommandSyntaxError(command=command) + + def do_ip(self, command, *args, context=None): + if self._validate(args, 'dhcp', 'snooping'): + pass # No visible changes + + elif self._validate(args, 'dhcp', 'snooping', 'trust'): + pass # No visible changes + + elif self._validate(args, 'dhcp', 'snooping', 'information', 'option', 'circuit-id', 'tr101', 'node-identifier', + 'ip'): + pass # No visible changes + + elif self._validate(args, 'dhcp', 'snooping', 'information', 'option', 'circuit-id', 'tr101', 'no-vlan-field'): + pass # No visible changes + + else: + raise exceptions.CommandSyntaxError(command=command) diff --git a/vendors/EdgeCore/main.py b/vendors/EdgeCore/main.py new file mode 100644 index 0000000..77f1e67 --- /dev/null +++ b/vendors/EdgeCore/main.py @@ -0,0 +1,72 @@ +# This file is part of the NESi software. +# +# Copyright (c) 2020 +# Original Software Design by Ilya Etingof . +# +# Software adapted by inexio . +# - Janis Groß +# - Philip Konrath +# - Alexander Dincher +# +# License: https://github.com/inexio/NESi/LICENSE.rst + +from nesi.softbox.cli import base +from vendors.EdgeCore.userViewCommandProcessor import * +from nesi import exceptions + + +class PreLoginCommandProcessor(base.CommandProcessor): + + def on_unknown_command(self, command, *args, context=None): + subprocessor = self._create_subprocessor( + LoginCommandProcessor, 'login') + + context['username'] = context['raw_line'].replace('\r', '').replace('\n', '') + + try: + subprocessor.history_enabled = False + subprocessor.hide_input = True + context['ip'] = self._model.network_address + context['name'] = self._model.hostname + subprocessor.loop(context=context) + except exceptions.TerminalExitError as exc: + if exc.return_to is not None and exc.return_to != 'sysexit': + raise exc + else: + context['ip'] = self._model.network_address + self.on_exit(context) + raise exc + + +class LoginCommandProcessor(base.CommandProcessor): + + def on_unknown_command(self, command, *args, context=None): + username = context.pop('username') + password = command + + for creds in self._model.credentials: + if creds.username == username and creds.password == password: + user = self._model.get_user('id', creds.user_id) + if user.profile == 'root': + break + else: + text = self._render('password', context=context) + self._write(text) + raise exceptions.TerminalExitError() + + self._output.write(bytes(False)) + self._output.write(bytes(False)) + + subprocessor = self._create_subprocessor( + UserViewCommandProcessor, 'login', 'mainloop') + + subprocessor.loop(context=context) + + +class PostLoginCommandProcessor(base.CommandProcessor): + + def loop(self, context=None, return_to=None, command=None): + subprocessor = self._create_subprocessor( + UserViewCommandProcessor, 'login', 'mainloop') + + subprocessor.loop(context=context) diff --git a/vendors/EdgeCore/userViewCommandProcessor.py b/vendors/EdgeCore/userViewCommandProcessor.py new file mode 100644 index 0000000..4f61cae --- /dev/null +++ b/vendors/EdgeCore/userViewCommandProcessor.py @@ -0,0 +1,71 @@ +# This file is part of the NESi software. +# +# Copyright (c) 2020 +# Original Software Design by Ilya Etingof . +# +# Software adapted by inexio . +# - Janis Groß +# - Philip Konrath +# - Alexander Dincher +# +# License: https://github.com/inexio/NESi/LICENSE.rst +from datetime import datetime + +from nesi import exceptions +from .baseCommandProcessor import BaseCommandProcessor + + +class UserViewCommandProcessor(BaseCommandProcessor): + + def do_enable(self, command, *args, context=None): + + for i in range(0, 3): + self.hide_input = True + enable_pw = self.user_input("Password:", False, None) + self.hide_input = False + + for creds in self._model.credentials: + if creds.username == 'enable': + user = self._model.get_user('id', creds.user_id) + if user.profile == 'enable': + break + + if creds.password == enable_pw: + break + else: + text = self._render('enable_password', context=context) + self._write(text) + return + + from .enableCommandProcessor import EnableCommandProcessor + + subprocessor = self._create_subprocessor( + EnableCommandProcessor, 'login', 'mainloop', 'enable') + + subprocessor.loop(context=context) + + def do_disable(self, command, *args, context=None): + return + + def on_unknown_command(self, command, *args, context=None): + if self._validate(command, '?'): + text = self._render( + '?', + context=context) + self._write(text) + else: + raise exceptions.CommandSyntaxError(command=command) + + def do_exit(self, command, *args, context=None): + exc = exceptions.TerminalExitError() + exc.return_to = 'sysexit' + raise exc + + def on_help(self, command, *args, context=None): + if args == (): + text = self._render( + 'help', + context=context) + self._write(text) + else: + raise exceptions.CommandSyntaxError(command=command) diff --git a/vendors/EdgeCore/vlanCommandProcessor.py b/vendors/EdgeCore/vlanCommandProcessor.py new file mode 100644 index 0000000..b7f7f5b --- /dev/null +++ b/vendors/EdgeCore/vlanCommandProcessor.py @@ -0,0 +1,32 @@ +# This file is part of the NESi software. +# +# Copyright (c) 2020 +# Original Software Design by Ilya Etingof . +# +# Software adapted by inexio . +# - Janis Groß +# - Philip Konrath +# - Alexander Dincher +# +# License: https://github.com/inexio/NESi/LICENSE.rst + + +from .baseCommandProcessor import BaseCommandProcessor +from nesi import exceptions + + +class VlanCommandProcessor(BaseCommandProcessor): + + def do_vlan(self, command, *args, context=None): + # vlan $trafficVlan name $description media ethernet + # vlan $cpe_management_vlan name $description media ethernet + if self._validate(args, str, 'name', str, 'media', 'ethernet'): + number, name = self._dissect(args, str, 'name', str, 'media', 'ethernet') + try: + vlan = self._model.get_vlan('number', int(number)) + vlan.set('name', name) + except exceptions.SoftboxenError: + _ = self._model.add_vlan(number=int(number), name=name) + vlan = self._model.get_vlan('number', int(number)) + else: + raise exceptions.CommandSyntaxError(command=command) diff --git a/vendors/Huawei/baseCommandProcessor.py b/vendors/Huawei/baseCommandProcessor.py index 88b6ad3..5c4e9c9 100644 --- a/vendors/Huawei/baseCommandProcessor.py +++ b/vendors/Huawei/baseCommandProcessor.py @@ -97,7 +97,7 @@ def do_quit(self, command, *args, context=None): def do_undo(self, command, *args, context=None): if self._validate(args, 'alarm', 'output', 'all'): - # importend for future snmp interactions + # important for future snmp interactions return elif self._validate(args, 'event', 'output', 'all'): return diff --git a/vendors/Huawei/baseMixIn.py b/vendors/Huawei/baseMixIn.py index 2c80975..b1a8035 100644 --- a/vendors/Huawei/baseMixIn.py +++ b/vendors/Huawei/baseMixIn.py @@ -34,7 +34,7 @@ def do_config(self, command, *args, context=None): try: - admin = self._model.get_user('status', 'Online') + admin = self._model.get_user('status', 'online') assert admin.level != 'User' except (exceptions.SoftboxenError, AssertionError): raise exceptions.CommandSyntaxError(command=command) diff --git a/vendors/Huawei/configCommandProcessor.py b/vendors/Huawei/configCommandProcessor.py index 2427165..bf18286 100644 --- a/vendors/Huawei/configCommandProcessor.py +++ b/vendors/Huawei/configCommandProcessor.py @@ -778,7 +778,12 @@ def do_raio_anid(self, command, *args, context=None): raise exceptions.CommandSyntaxError(command=command) def do_undo(self, command, *args, context=None): - if self._validate(args, 'system', 'snmp-user', 'password', 'security'): + if self._validate(args, 'alarm', 'output', 'all'): + # important for future snmp interactions + return + elif self._validate(args, 'event', 'output', 'all'): + return + elif self._validate(args, 'system', 'snmp-user', 'password', 'security'): # importend for future snmp interactions return elif self._validate(args, 'smart'): @@ -883,7 +888,7 @@ def do_system(self, command, *args, context=None): raise exceptions.CommandSyntaxError(command=command) def do_terminal(self, command, *args, context=None): - creating_user = self._model.get_user('status', 'Online') + creating_user = self._model.get_user('status', 'online') if creating_user.level != 'Super' and creating_user.level != 'Admin': raise exceptions.CommandSyntaxError(command=command) if self._validate(args, 'user', 'name'): @@ -957,19 +962,15 @@ def do_terminal(self, command, *args, context=None): info = self.user_input(" User's Appended Info(<=30 chars):", False, 30) box = self._model - box.add_credentials(username=login, password=password) - try: - creds = self._model.get_credentials('username', login) - except exceptions.SoftboxenError: - raise exceptions.CommandSyntaxError(command=command) - - box.add_user(name=login, credentials_id=creds.id, level=lvl, profile=profile, reenter_num=reenter_num, - reenter_num_temp=reenter_num, append_info=info, lock_status='Unlocked') + box.add_user(name=login, level=lvl, profile=profile, reenter_num=reenter_num, + reenter_num_temp=reenter_num, append_info=info, lock_status='unlocked') try: user = self._model.get_user('name', login) except exceptions.SoftboxenError: raise exceptions.CommandSyntaxError(command=command) + box.add_credentials(username=login, password=password, user_id=user.id) + text = self._render('user_created', context=context) self._write(text) @@ -990,11 +991,11 @@ def do_terminal(self, command, *args, context=None): except exceptions.SoftboxenError: raise exceptions.CommandSyntaxError(command=command) - if locked_user.lock_status == 'Locked': + if locked_user.lock_status == 'locked': locked_user.set_reenter_num_temp(locked_user.reenter_num) locked_user.unlock() return - elif locked_user.lock_status == 'Unlocked': + elif locked_user.lock_status == 'unlocked': text = self._render('user_already_unlocked', context=context) self._write(text) else: @@ -1029,7 +1030,6 @@ def do_port(self, command, *args, context=None): def do_xdsl(self, command, *args, context=None): if self._validate(args, 'vectoring-group', 'link', 'add', str, str): profile_idx, port_idx = self._dissect(args, 'vectoring-group', 'link', 'add', str, str) - print(port_idx) portname = port_idx[0:3] + '/' + port_idx[4] try: diff --git a/vendors/Huawei/diagnoseCommandProcessor.py b/vendors/Huawei/diagnoseCommandProcessor.py index 911369a..8df1c24 100644 --- a/vendors/Huawei/diagnoseCommandProcessor.py +++ b/vendors/Huawei/diagnoseCommandProcessor.py @@ -108,7 +108,7 @@ def on_unknown_command(self, command, *args, context=None): def do_switch(self, command, *args, context=None): if self._validate(args, 'vdsl', 'mode', 'to', str): - user = self._model.get_user('status', 'Online') + user = self._model.get_user('status', 'online') if user.level != 'Super': raise exceptions.CommandSyntaxError(command=command) @@ -166,7 +166,7 @@ def do_switch(self, command, *args, context=None): self.on_cycle(context=context) time.sleep(10) self._model.set_last_logout(datetime.now().strftime("%m/%d/%Y %H:%M:%S")) - user = self._model.get_user('status', 'Online') + user = self._model.get_user('status', 'online') user.set_offline() exc = exceptions.TerminalExitError() exc.return_to = 'sysreboot' diff --git a/vendors/Huawei/enableCommandProcessor.py b/vendors/Huawei/enableCommandProcessor.py index e7d93b4..bbca42d 100644 --- a/vendors/Huawei/enableCommandProcessor.py +++ b/vendors/Huawei/enableCommandProcessor.py @@ -33,7 +33,7 @@ def do_quit(self, command, *args, context=None): answer = self.user_input("Are you sure to log out? (y/n)[n]:", False, 1) if answer == "y": self._model.set_last_logout(datetime.now().strftime("%m/%d/%Y %H:%M:%S")) - user = self._model.get_user('status', 'Online') + user = self._model.get_user('status', 'online') user.set_offline() self._model.enable_smart() self._model.enable_interactive() @@ -54,7 +54,7 @@ def do_config(self, command, *args, context=None): from .configCommandProcessor import ConfigCommandProcessor try: - admin = self._model.get_user('status', 'Online') + admin = self._model.get_user('status', 'online') assert admin.level != 'User' except (exceptions.SoftboxenError, AssertionError): raise exceptions.CommandSyntaxError(command=command) @@ -250,7 +250,7 @@ def do_reboot(self, command, *args, context=None): self.on_cycle(context=context) time.sleep(10) self._model.set_last_logout(datetime.now().strftime("%m/%d/%Y %H:%M:%S")) - user = self._model.get_user('status', 'Online') + user = self._model.get_user('status', 'online') user.set_offline() exc = exceptions.TerminalExitError() exc.return_to = 'sysreboot' diff --git a/vendors/Huawei/huaweiBaseCommandProcessor.py b/vendors/Huawei/huaweiBaseCommandProcessor.py index 572ebe0..b09a18d 100644 --- a/vendors/Huawei/huaweiBaseCommandProcessor.py +++ b/vendors/Huawei/huaweiBaseCommandProcessor.py @@ -587,7 +587,7 @@ def display_terminal_user(self, command, context): user_counter = 0 try: - exec_user = self._model.get_user('status', 'Online') + exec_user = self._model.get_user('status', 'online') except exceptions.SoftboxenError: raise exceptions.CommandSyntaxError(command=command) @@ -610,6 +610,7 @@ def display_terminal_user(self, command, context): context['spacer4'] = self.create_spacers((1,), ('',))[0] * ' ' context['spacer5'] = self.create_spacers((16,), (user.profile,))[0] * ' ' + user.status = user.status.capitalize() text += self._render('display_terminal_user_all_middle', context=dict(context, user=user)) user_counter += 1 diff --git a/vendors/Huawei/main.py b/vendors/Huawei/main.py index a93ce3f..e7dda0f 100644 --- a/vendors/Huawei/main.py +++ b/vendors/Huawei/main.py @@ -43,8 +43,8 @@ def on_unknown_command(self, command, *args, context=None): for creds in self._model.credentials: if creds.username == username and creds.password == password: - user = self._model.get_user('credentials_id', creds.id) - if user.lock_status == 'Locked': + user = self._model.get_user('id', creds.user_id) + if user.lock_status == 'locked': text = self._render('user_locked', context=context) self._write(text) raise exceptions.TerminalExitError() diff --git a/vendors/Huawei/userViewCommandProcessor.py b/vendors/Huawei/userViewCommandProcessor.py index ac1a067..e1c3c95 100644 --- a/vendors/Huawei/userViewCommandProcessor.py +++ b/vendors/Huawei/userViewCommandProcessor.py @@ -42,7 +42,7 @@ def do_quit(self, command, *args, context=None): answer = self.user_input("Are you sure to log out? (y/n)[n]:", False, 1) if answer == "y": self._model.set_last_logout(datetime.now().strftime("%m/%d/%Y %H:%M:%S")) - user = self._model.get_user('status', 'Online') + user = self._model.get_user('status', 'online') user.set_offline() self._model.enable_smart() self._model.enable_interactive() diff --git a/vendors/Huawei/vlanSrvprofCommandProcessor.py b/vendors/Huawei/vlanSrvprofCommandProcessor.py index 0677d3d..0a46789 100644 --- a/vendors/Huawei/vlanSrvprofCommandProcessor.py +++ b/vendors/Huawei/vlanSrvprofCommandProcessor.py @@ -100,7 +100,6 @@ def do_igmp(self, command, *args, context=None): def do_pitp(self, command, *args, context=None): if self._validate(args, 'enable'): self._model.set_pitp('enable') - print(context['srvprof'].vlan_mac) text = self._render('please_wait_commit', context=context) self._write(text) diff --git a/vendors/KeyMile/__init__.py b/vendors/KeyMile/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/vendors/KeyMile/accessPoints/root/eoamCommandProcessor.py b/vendors/KeyMile/accessPoints/root/eoamCommandProcessor.py new file mode 100644 index 0000000..5c9dd85 --- /dev/null +++ b/vendors/KeyMile/accessPoints/root/eoamCommandProcessor.py @@ -0,0 +1,33 @@ +# This file is part of the NESi software. +# +# Copyright (c) 2020 +# Original Software Design by Ilya Etingof . +# +# Software adapted by inexio . +# - Janis Groß +# - Philip Konrath +# - Alexander Dincher +# +# License: https://github.com/inexio/NESi/LICENSE.rst + +from nesi import exceptions +from vendors.KeyMile.baseCommandProcessor import BaseCommandProcessor + + +class EoamCommandProcessor(BaseCommandProcessor): + __name__ = 'eoam' + management_functions = ('main', 'cfgm', 'status') + access_points = () + + from .eoamManagementFunctions import main + from .eoamManagementFunctions import cfgm + from .eoamManagementFunctions import status + + def set(self, command, *args, context=None): + if self._validate(args, *()): + exc = exceptions.CommandSyntaxError(command=command) + exc.template = 'syntax_error' + exc.template_scopes = ('login', 'base', 'syntax_errors') + raise exc + else: + raise exceptions.CommandSyntaxError(command=command) diff --git a/vendors/KeyMile/accessPoints/root/eoamManagementFunctions.py b/vendors/KeyMile/accessPoints/root/eoamManagementFunctions.py new file mode 100644 index 0000000..c669d81 --- /dev/null +++ b/vendors/KeyMile/accessPoints/root/eoamManagementFunctions.py @@ -0,0 +1,52 @@ +main = { + 'General': { + 'Prop': { + 'Labels': 'rw', + 'AlarmStatus': 'r-' + } + }, + 'AdminAndOperStatus': { + 'Prop': { + 'AdministrativeStatus': 'rw', + 'OperationalStatus': 'r-' + } + } +} + +cfgm = { + 'DefaultMdLevel': { + 'Prop': { + 'DefaultMdSettings': 'rw' + } + }, + 'ContextMap': { + 'Prop': { + 'Mapping': 'rw' + } + }, + 'Aggregation': { + 'Prop': { + 'Role': 'rw', + 'Address': 'rw' + } + }, + 'Md': { + 'Cmd': ( + 'CreateMd', + 'DeleteMd' + ) + } +} + +status = { + 'DefaultMdMips': { + 'Prop': { + 'Mips': 'r-' + } + }, + 'ConfigurationErrors': { + 'Prop': { + 'InterfacesInError': 'r-' + } + } +} diff --git a/vendors/KeyMile/accessPoints/root/fan/alarmCommandProcessor.py b/vendors/KeyMile/accessPoints/root/fan/alarmCommandProcessor.py new file mode 100644 index 0000000..22266a9 --- /dev/null +++ b/vendors/KeyMile/accessPoints/root/fan/alarmCommandProcessor.py @@ -0,0 +1,24 @@ +# This file is part of the NESi software. +# +# Copyright (c) 2020 +# Original Software Design by Ilya Etingof . +# +# Software adapted by inexio . +# - Janis Groß +# - Philip Konrath +# - Alexander Dincher +# +# License: https://github.com/inexio/NESi/LICENSE.rst + +from nesi import exceptions +from vendors.KeyMile.baseCommandProcessor import BaseCommandProcessor + + +class AlarmCommandProcessor(BaseCommandProcessor): + __name__ = 'alarm' + management_functions = ('main', 'cfgm', 'fm') + access_points = () + + from .alarmManagementFunctions import main + from .alarmManagementFunctions import cfgm + from .alarmManagementFunctions import fm diff --git a/vendors/KeyMile/accessPoints/root/fan/alarmManagementFunctions.py b/vendors/KeyMile/accessPoints/root/fan/alarmManagementFunctions.py new file mode 100644 index 0000000..7ecdd32 --- /dev/null +++ b/vendors/KeyMile/accessPoints/root/fan/alarmManagementFunctions.py @@ -0,0 +1,32 @@ +main = { + 'General': { + 'Prop': { + 'Labels': 'rw', + 'AlarmStatus': 'r-' + } + } +} + +cfgm = { + 'General': { + 'Prop': { + 'Polarity': 'rw' + } + } +} + +fm = { + 'Status': { + 'Prop': { + 'AlarmStatus': 'r-' + }, + 'Cmd': ( + 'Acknowledge', + ) + }, + 'Configuration': { + 'Prop': { + 'AlarmConfiguration': 'rw' + } + } +} diff --git a/vendors/KeyMile/accessPoints/root/fan/fanCommandProcessor.py b/vendors/KeyMile/accessPoints/root/fan/fanCommandProcessor.py new file mode 100644 index 0000000..bffb664 --- /dev/null +++ b/vendors/KeyMile/accessPoints/root/fan/fanCommandProcessor.py @@ -0,0 +1,36 @@ +# This file is part of the NESi software. +# +# Copyright (c) 2020 +# Original Software Design by Ilya Etingof . +# +# Software adapted by inexio . +# - Janis Groß +# - Philip Konrath +# - Alexander Dincher +# +# License: https://github.com/inexio/NESi/LICENSE.rst + +from nesi import exceptions +from vendors.KeyMile.baseCommandProcessor import BaseCommandProcessor + + +class FanCommandProcessor(BaseCommandProcessor): + __name__ = 'fan' + management_functions = ('main', 'cfgm', 'fm') + access_points = () + + from .fanManagementFunctions import main + from .fanManagementFunctions import cfgm + from .fanManagementFunctions import fm + + def _init_access_points(self, context=None): + for i in range(1, 12): + identifier = 'alarm-' + str(i) + if identifier in self.access_points: + continue + self.access_points += (identifier,) + + def _init_context(self, context=None): + context['ls_Name'] = 'FANU4' + context['ls_MainMode'] = '' + context['ls_EquipmentState'] = 'Ok' diff --git a/vendors/KeyMile/accessPoints/root/fan/fanManagementFunctions.py b/vendors/KeyMile/accessPoints/root/fan/fanManagementFunctions.py new file mode 100644 index 0000000..3a7049a --- /dev/null +++ b/vendors/KeyMile/accessPoints/root/fan/fanManagementFunctions.py @@ -0,0 +1,42 @@ +main = { + 'General': { + 'Prop': { + 'Labels': 'rw', + 'AlarmStatus': 'r-' + } + }, + 'Equipment': { + 'Prop': { + 'CurrentStatus': 'r-' + } + }, + 'Inventory': { + 'Prop': { + 'EquipmentInventory': 'r-' + } + } +} + +cfgm = { + 'General': { + 'Prop': { + 'Option': 'rw' + } + } +} + +fm = { + 'Status': { + 'Prop': { + 'AlarmStatus': 'r-' + }, + 'Cmd': ( + 'Acknowledge', + ) + }, + 'Configuration': { + 'Prop': { + 'AlarmConfiguration': 'rw' + } + } +} diff --git a/vendors/KeyMile/accessPoints/root/mgmt_unit/mgmt_port/mgmtportCommandProcessor.py b/vendors/KeyMile/accessPoints/root/mgmt_unit/mgmt_port/mgmtportCommandProcessor.py new file mode 100644 index 0000000..a4e50c1 --- /dev/null +++ b/vendors/KeyMile/accessPoints/root/mgmt_unit/mgmt_port/mgmtportCommandProcessor.py @@ -0,0 +1,103 @@ +# This file is part of the NESi software. +# +# Copyright (c) 2020 +# Original Software Design by Ilya Etingof . +# +# Software adapted by inexio . +# - Janis Groß +# - Philip Konrath +# - Alexander Dincher +# +# License: https://github.com/inexio/NESi/LICENSE.rst + +from nesi import exceptions +from vendors.KeyMile.baseCommandProcessor import BaseCommandProcessor +import time + + +class MgmtportCommandProcessor(BaseCommandProcessor): + __name__ = 'mgmtport' + management_functions = ('main', 'cfgm', 'fm', 'pm', 'status') + access_points = () + + from .mgmtportManagementFunctions import main + from .mgmtportManagementFunctions import cfgm + from .mgmtportManagementFunctions import fm + from .mgmtportManagementFunctions import pm + from .mgmtportManagementFunctions import status + + def get_property(self, command, *args, context=None): + port = self.get_component() + card = self._model.get_card('name', self.component_name.split('/')[0]) + scopes = ('login', 'base', 'get') + if self._validate(args, *()): + exc = exceptions.CommandSyntaxError(command=command) + exc.template = 'syntax_error' + exc.template_scopes = ('login', 'base', 'syntax_errors') + raise exc + + elif self._validate((args[0],), 'AdministrativeStatus') and context['path'].split('/')[-1] == 'main': + self.map_states(port, 'port') + context['spacer'] = self.create_spacers((67,), (port.admin_state,))[0] * ' ' + text = self._render('administrative_status', *scopes, context=dict(context, port=port)) + self._write(text) + elif self._validate(args, 'Labels') and context['path'].split('/')[-1] == 'main': + context['spacer1'] = self.create_spacers((67,), (port.label1,))[0] * ' ' + context['spacer2'] = self.create_spacers((67,), (port.label2,))[0] * ' ' + context['spacer3'] = self.create_spacers((67,), (port.description,))[0] * ' ' + text = self._render('labels', *scopes, context=dict(context, port=port)) + self._write(text) + elif self._validate((args[0],), 'OperationalStatus') and context['path'].split('/')[-1] == 'main': + self.map_states(port, 'port') + port_operational_state = port.operational_state + context['port_operational_state'] = port_operational_state + context['spacer'] = self.create_spacers((67,), (port_operational_state,))[0] * ' ' + text = self._render('operational_status', *scopes, context=context) + self._write(text) + else: + raise exceptions.CommandExecutionError(command=command, template='invalid_property', + template_scopes=('login', 'base', 'execution_errors')) + + def _init_access_points(self, context=None): + self.access_points = () + return + + def _init_context(self, context=None): + context['ls_Name'] = '10/100/1000BASE-T' + context['ls_MainMode'] = 'Management' + context['ls_EquipmentState'] = '' + + def get_component(self): + return self._model.get_mgmt_port('name', self.component_name) + + def set(self, command, *args, context=None): + scopes = ('login', 'base', 'set') + card = self._model.get_card('name', self.component_name.split('/')[0]) + if self._validate(args, *()): + exc = exceptions.CommandSyntaxError(command=command) + exc.template = 'syntax_error' + exc.template_scopes = ('login', 'base', 'syntax_errors') + raise exc + elif self._validate(args, 'AdministrativeStatus', str) and context['path'].split('/')[-1] == 'main': + state, = self._dissect(args, 'AdministrativeStatus', str) + try: + port = self.get_component() + if state == 'up': + port.admin_up() + elif state == 'down': + port.admin_down() + else: + raise exceptions.SoftboxenError() + except exceptions.SoftboxenError(): + raise exceptions.CommandExecutionError(command=command, template='invalid_property', + template_scopes=('login', 'base', 'execution_errors')) + elif self._validate(args, 'Labels', str, str, str) and context['path'].split('/')[-1] == 'main': + label1, label2, description = self._dissect(args, 'Labels', str, str, str) + try: + port = self.get_component() + port.set_label(label1, label2, description) + except exceptions.SoftboxenError(): + raise exceptions.CommandExecutionError(command=command, template='invalid_property', + template_scopes=('login', 'base', 'execution_errors')) + else: + raise exceptions.CommandSyntaxError(command=command) diff --git a/vendors/KeyMile/accessPoints/root/mgmt_unit/mgmt_port/mgmtportManagementFunctions.py b/vendors/KeyMile/accessPoints/root/mgmt_unit/mgmt_port/mgmtportManagementFunctions.py new file mode 100644 index 0000000..c0a9d28 --- /dev/null +++ b/vendors/KeyMile/accessPoints/root/mgmt_unit/mgmt_port/mgmtportManagementFunctions.py @@ -0,0 +1,216 @@ +main = { + 'General': { + 'Prop': { + 'Labels': 'rw', + 'AlarmStatus': 'r-' + } + }, + 'AdminAndOperStatus': { + 'Prop': { + 'AdministrativeStatus': 'rw', + 'OperationalStatus': 'r-' + } + }, + 'SFP': { + 'Prop': { + 'EquipmentInventory': 'r-' + } + } + } + +cfgm = { + 'PortMode': { + 'Prop': { + 'PortMode': 'rw', + 'Redundancy': 'rw', + 'PortVlan': 'rw', + 'MTUSize': 'rw' + } + }, + 'Rstp': { + 'Prop': { + 'Rstp': 'rw', + 'RstpParams': 'rw' + } + }, + 'VlanList': { + 'Prop': { + 'ManagementVlan': 'r-', + 'ListType': 'rw', + 'VlanList': 'rw' + }, + 'Cmd': ( + 'FlushVlanList', + ) + }, + 'QoS': { + 'Prop': { + 'SchedulingProfileName': 'rw' + } + }, + 'Multicast': { + 'Prop': { + 'EnableIgmpClassifier': 'rw', + 'AllowStaticStreams': 'rw', + 'MulticastPortMode': 'rw' + } + }, + 'LinkAggregation': { + 'Prop': { + 'LinkAggregation': 'rw' + } + }, + 'PHY': { + 'Prop': { + 'PhyMode': 'rw', + 'PhyFlowControl': 'rw' + } + }, + 'Eoam': { + 'Prop': { + 'NetworkNetworkInterface': 'rw' + } + }, + 'PriorityMapping': { + 'Prop': { + 'DSCPTo802Dot1qTxPriorityMapping': 'rw' + } + }, + 'Mirroring': { + 'Prop': { + 'MirrorPortList': 'rw' + } + } + } + +fm = { + 'Status': { + 'Prop': { + 'AlarmStatus': 'r-' + }, + 'Cmd': ( + 'Acknowledge', + ) + }, + 'Configuration': { + 'Prop': { + 'AlarmConfiguration': 'rw' + } + } + } + +pm = { + 'UserCounter': { + 'Prop': { + 'UserCounterDisplayMode': 'rw', + 'UserCounterTable': 'r-' + }, + 'Cmd': ( + 'UserCounterReset', + ) + }, + 'History15min': { + 'Prop': { + 'History15minDisplayMode': 'rw', + 'History15minTable': 'r-' + } + }, + 'History24h': { + 'Prop': { + 'History24hDisplayMode': 'rw', + 'History24hTable': 'r-' + } + }, + 'Alarm15min': { + 'Prop': { + 'Alarm15minDisplayMode': 'rw', + 'Alarm15minTable': 'r-' + }, + 'Cmd': ( + 'Alarm15minReset', + ) + }, + 'Alarm24h': { + 'Prop': { + 'Alarm24hDisplayMode': 'rw', + 'Alarm24hTable': 'r-' + }, + 'Cmd': ( + 'Alarm24hReset', + ) + }, + 'PerformanceMonitoring': { + 'Cmd': ( + 'UserCounter', + 'GetHistory15min', + 'GetHistory24h', + 'GetAlarm15min', + 'GetAlarm24hRecursive', + 'ResetUserCounter', + 'ResetAlarm15min', + 'ResetAlarm24h' + ) + } + } + +status = { + 'PortMode': { + 'Prop': { + 'DefaultConfigEnabled': 'r-' + } + }, + 'MAC': { + 'Prop': { + 'PortMacStatus': 'r-' + } + }, + 'Phy': { + 'Prop': { + 'PortLinkStatus': 'r-' + } + }, + 'Rstp': { + 'Prop': { + 'PortRstpStatus': 'r-' + } + }, + 'LinkAggregation': { + 'Prop': { + 'Status': 'r-' + } + }, + 'Ddm': { + 'Prop': { + 'DdmStatus': 'r-' + } + }, + 'QoS': { + 'Prop': { + 'QosStatus': 'r-' + } + }, + 'Multicast': { + 'stream': { + 'Dynamic': { + 'Prop': { + 'ActiveStreams': 'r-' + }, + 'Cmd': ( + 'ClearActiveStreams', + ) + }, + 'Static': { + 'Prop': { + 'StaticStreams': 'r-' + } + }, + }, + + 'Vlan': { + 'Prop': { + 'AttachedVlans': 'r-' + } + + } + } + } diff --git a/vendors/KeyMile/accessPoints/root/mgmt_unit/mgmtunitCommandProcessor.py b/vendors/KeyMile/accessPoints/root/mgmt_unit/mgmtunitCommandProcessor.py new file mode 100644 index 0000000..e62b6e3 --- /dev/null +++ b/vendors/KeyMile/accessPoints/root/mgmt_unit/mgmtunitCommandProcessor.py @@ -0,0 +1,158 @@ +# This file is part of the NESi software. +# +# Copyright (c) 2020 +# Original Software Design by Ilya Etingof . +# +# Software adapted by inexio . +# - Janis Groß +# - Philip Konrath +# - Alexander Dincher +# +# License: https://github.com/inexio/NESi/LICENSE.rst +import time + +from nesi import exceptions +from vendors.KeyMile.baseCommandProcessor import BaseCommandProcessor + + +class MgmtunitCommandProcessor(BaseCommandProcessor): + __name__ = 'mgmtunit' + management_functions = ('main', 'fm') + access_points = () # 'internalPorts', only on certain cards + + from .mgmtunitManagementFunctions import main + from .mgmtunitManagementFunctions import cfgm + from .mgmtunitManagementFunctions import fm + from .mgmtunitManagementFunctions import status + + def _init_access_points(self, context=None): + self.access_points = () + try: + card = self.get_component() + + self.management_functions = ('main', 'cfgm', 'fm', 'status') + + for port in self._model.get_mgmt_ports('mgmt_card_id', card.id): + identifier = 'port-' + port.name.split('/')[-1] + if identifier in self.access_points: + continue + self.access_points += (identifier,) + + except exceptions.InvalidInputError: + pass + + def _init_context(self, context=None): + card = self.get_component() + context['ls_Name'] = card.board_name + ' ' + card.supplier_build_state + context['ls_MainMode'] = card.software[:-4] + context['ls_EquipmentState'] = 'Ok' + + def get_property(self, command, *args, context=None): + card = self.get_component() + scopes = ('login', 'base', 'get') + if self._validate(args, *()): + exc = exceptions.CommandSyntaxError(command=command) + exc.template = 'syntax_error' + exc.template_scopes = ('login', 'base', 'syntax_errors') + raise exc + elif self._validate(args, 'Labels') and context['path'].split('/')[-1] == 'main': + context['spacer1'] = self.create_spacers((67,), (card.label1,))[0] * ' ' + context['spacer2'] = self.create_spacers((67,), (card.label2,))[0] * ' ' + context['spacer3'] = self.create_spacers((67,), (card.description,))[0] * ' ' + text = self._render('labels', *scopes, context=dict(context, port=card)) + self._write(text) + elif self._validate(args, 'EquipmentInventory') and context['path'].split('/')[-1] == 'main': + unit_symbol = '"' + card.board_name + '"' + context['unit_symbol'] = unit_symbol + context['spacer_1'] = self.create_spacers((67,), (unit_symbol,))[0] * ' ' + unit_short_text = '"' + card.short_text + '"' + context['unit_short_text'] = unit_short_text + context['spacer_2'] = self.create_spacers((67,), (unit_short_text,))[0] * ' ' + unit_board_id = card.board_id + context['unit_board_id'] = unit_board_id + context['spacer_3'] = self.create_spacers((67,), (unit_board_id,))[0] * ' ' + unit_hardware_key = card.hardware_key + context['unit_hardware_key'] = unit_hardware_key + context['spacer_4'] = self.create_spacers((67,), (unit_hardware_key,))[0] * ' ' + unit_manufacturer_id = '"' + card.manufacturer_id + '"' + context['unit_manufacturer_id'] = unit_manufacturer_id + context['spacer_5'] = self.create_spacers((67,), (unit_manufacturer_id,))[0] * ' ' + unit_serial_number = '"' + card.serial_number + '"' + context['unit_serial_number'] = unit_serial_number + context['spacer_6'] = self.create_spacers((67,), (unit_serial_number,))[0] * ' ' + unit_manufacturer_part_number = '"' + card.manufacturer_part_number + '"' + context['unit_manufacturer_part_number'] = unit_manufacturer_part_number + context['spacer_7'] = self.create_spacers((67,), (unit_manufacturer_part_number,))[0] * ' ' + unit_manufacturer_build_state = '"' + card.manufacturer_build_state + '"' + context['unit_manufacturer_build_state'] = unit_manufacturer_build_state + context['spacer_8'] = self.create_spacers((67,), (unit_manufacturer_build_state,))[0] * ' ' + unit_supplier_part_number = '"' + card.model_name + '"' + context['unit_supplier_part_number'] = unit_supplier_part_number + context['spacer_9'] = self.create_spacers((67,), (unit_supplier_part_number,))[0] * ' ' + unit_supplier_build_state = '"' + card.supplier_build_state + '"' + context['unit_supplier_build_state'] = unit_supplier_build_state + context['spacer_10'] = self.create_spacers((67,), (unit_supplier_build_state,))[0] * ' ' + unit_customer_id = '"' + card.customer_id + '"' + context['unit_customer_id'] = unit_customer_id + context['spacer_11'] = self.create_spacers((67,), (unit_customer_id,))[0] * ' ' + unit_customer_product_id = '"' + card.customer_product_id + '"' + context['unit_customer_product_id'] = unit_customer_product_id + context['spacer_12'] = self.create_spacers((67,), (unit_customer_product_id,))[0] * ' ' + unit_boot_loader = '"' + card.boot_loader + '"' + context['unit_boot_loader'] = unit_boot_loader + context['spacer_13'] = self.create_spacers((67,), (unit_boot_loader,))[0] * ' ' + unit_processor = '"' + card.processor + '"' + context['unit_processor'] = unit_processor + context['spacer_14'] = self.create_spacers((67,), (unit_processor,))[0] * ' ' + text = self._render('equipment_inventory', *scopes, context=context) + self._write(text) + elif self._validate(args, 'CurrentStatus') and context['path'].split('/')[-1] == 'main': + unit_state = card.state + context['unit_state'] = unit_state + context['spacer_1'] = self.create_spacers((67,), (unit_state,))[0] * ' ' + unit_hardware = '"' + card.board_name + ' ' + card.supplier_build_state + '"' + context['unit_hardware'] = unit_hardware + context['spacer_2'] = self.create_spacers((67,), (unit_hardware,))[0] * ' ' + unit_software = '"' + card.software[:-4] + '"' + context['unit_software'] = unit_software + context['spacer_3'] = self.create_spacers((67,), (unit_software,))[0] * ' ' + unit_serial_number = '"' + card.serial_number + '"' + context['unit_serial_number'] = unit_serial_number + context['spacer_4'] = self.create_spacers((67,), (unit_serial_number,))[0] * ' ' + unit_manufacturer_name = '"' + card.manufacturer_name + '"' + context['unit_manufacturer_name'] = unit_manufacturer_name + context['spacer_5'] = self.create_spacers((67,), (unit_manufacturer_name,))[0] * ' ' + unit_model_name = '"' + card.model_name + '"' + context['unit_model_name'] = unit_model_name + context['spacer_6'] = self.create_spacers((67,), (unit_model_name,))[0] * ' ' + text = self._render('current_status', *scopes, context=context) + + self._write(text) + else: + raise exceptions.CommandExecutionError(command=command, template='invalid_property', + template_scopes=('login', 'base', 'execution_errors')) + + def get_component(self): + return self._model.get_mgmt_card('name', self.component_name) + + def set(self, command, *args, context=None): + try: + card = self.get_component() + except exceptions.SoftboxenError: + raise exceptions.CommandSyntaxError(command=command) + if self._validate(args, *()): + exc = exceptions.CommandSyntaxError(command=command) + exc.template = 'syntax_error' + exc.template_scopes = ('login', 'base', 'syntax_errors') + raise exc + elif self._validate(args, 'Labels', str, str, str) and context['path'].split('/')[-1] == 'main': + label1, label2, description = self._dissect(args, 'Labels', str, str, str) + try: + component = self.get_component() + component.set_label(label1, label2, description) + except exceptions.SoftboxenError(): + raise exceptions.CommandExecutionError(command=command, template='invalid_property', + template_scopes=('login', 'base', 'execution_errors')) + else: + raise exceptions.CommandSyntaxError(command=command) + diff --git a/vendors/KeyMile/accessPoints/root/mgmt_unit/mgmtunitManagementFunctions.py b/vendors/KeyMile/accessPoints/root/mgmt_unit/mgmtunitManagementFunctions.py new file mode 100644 index 0000000..e7a7937 --- /dev/null +++ b/vendors/KeyMile/accessPoints/root/mgmt_unit/mgmtunitManagementFunctions.py @@ -0,0 +1,115 @@ +main = { + 'General': { + 'Prop': { + 'Labels': 'rw', + 'AlarmStatus': 'r-' + } + }, + 'Equipment': { + 'Prop': { + 'AssignmentStatus': 'r-', + 'CurrentStatus': 'r-' + }, + 'Cmd': ( + 'Assign', + 'Unassign', + 'Restart', + 'StopInBoot' + ) + }, + 'Inventory': { + 'Prop': { + 'EquipmentInventory': 'r-' + } + }, + 'Logbooks': { + 'Cmd': ( + 'GetAlarmLogbook', + 'GetEventLogbook', + 'GetEquipmentLogbook' + ) + }, + 'Software': { + 'Prop': { + 'DiskSpace': 'r-', + 'SoftwareOnUnit': 'r-', + 'HardwareAndSoftware': 'r-', + 'Status': 'r-', + 'Configuration': 'rw' + }, + 'Cmd': ( + 'DeleteSoftware', + 'StartSoftware' + ), + 'File': { + 'Software': 'rw' + } + } + } + +cfgm = { + 'Filter': { + 'Prop': { + 'BroadcastFilter': 'rw' + } + }, + 'PriorityMapping': { + 'Prop': { + 'DSCPTo802Dot1qPriorityMapping': 'rw' + } + }, + 'PacketBuffer': { + 'Prop': { + 'PacketBufferProfileName': 'rw' + } + } + } + +fm = { + 'Status': { + 'Prop': { + 'AlarmStatus': 'r-' + }, + 'Cmd': ( + 'Acknowledge', + ) + }, + 'Configuration': { + 'Prop': { + 'AlarmConfiguration': 'rw' + } + } + } + +pm = { + 'PerformanceMonitoring': { + 'Cmd': ( + 'UserCounter', + 'GetHistory15min', + 'GetHistory24h', + 'GetAlarm15min', + 'GetAlarm24hRecursive', + 'ResetUserCounter', + 'ResetAlarm15min', + 'ResetAlarm24h' + ) + } + } + +status = { + 'QoS': { + 'Prop': { + 'QosPriorityMappingStatus': 'r-' + } + }, + 'PacketBuffer': { + 'Prop': { + 'PacketBufferStatus': 'r-' + } + }, + 'Redundancy': { + 'Prop': { + 'Status': 'r-' + } + } + } diff --git a/vendors/KeyMile/accessPoints/root/multicastCommandProcessor.py b/vendors/KeyMile/accessPoints/root/multicastCommandProcessor.py new file mode 100644 index 0000000..940da1d --- /dev/null +++ b/vendors/KeyMile/accessPoints/root/multicastCommandProcessor.py @@ -0,0 +1,35 @@ +# This file is part of the NESi software. +# +# Copyright (c) 2020 +# Original Software Design by Ilya Etingof . +# +# Software adapted by inexio . +# - Janis Groß +# - Philip Konrath +# - Alexander Dincher +# +# License: https://github.com/inexio/NESi/LICENSE.rst + +from nesi import exceptions +from vendors.KeyMile.baseCommandProcessor import BaseCommandProcessor + + +class MulticastCommandProcessor(BaseCommandProcessor): + __name__ = 'multicast' + management_functions = ('main', 'cfgm', 'fm', 'pm', 'status') + access_points = () + + from .multicastManagementFunctions import main + from .multicastManagementFunctions import cfgm + from .multicastManagementFunctions import fm + from .multicastManagementFunctions import pm + from .multicastManagementFunctions import status + + def set(self, command, *args, context=None): + if self._validate(args, *()): + exc = exceptions.CommandSyntaxError(command=command) + exc.template = 'syntax_error' + exc.template_scopes = ('login', 'base', 'syntax_errors') + raise exc + else: + raise exceptions.CommandSyntaxError(command=command) diff --git a/vendors/KeyMile/accessPoints/root/multicastManagementFunctions.py b/vendors/KeyMile/accessPoints/root/multicastManagementFunctions.py new file mode 100644 index 0000000..0b5c804 --- /dev/null +++ b/vendors/KeyMile/accessPoints/root/multicastManagementFunctions.py @@ -0,0 +1,161 @@ +main = { + 'General': { + 'Prop': { + 'Labels': 'rw', + 'AlarmStatus': 'r-' + } + } +} + +cfgm = { + 'Multicast': { + 'General': { + 'Prop': { + 'SnoopingMode': 'rw', + 'LocalIPAddressForIGMPGeneration': 'rw', + 'IPSourceAddressOfQueries': 'rw', + 'portGroupInactivityTimeout': 'rw' + }, + 'Cmd': ( + 'CreateVlan', + 'DeleteVlan' + ) + }, + 'PreJoin': { + 'Prop': { + 'preJoinIntervalPeriod': 'rw' + } + }, + 'PostLeave': { + 'Prop': { + 'postLeaveDelayPeriod': 'rw' + } + }, + 'Preview': { + 'Prop': { + 'previewSettings': 'rw' + } + }, + 'Bandwidth': { + 'Prop': { + 'defaultBandwidthPerStream': 'rw' + } + }, + 'Alarms': { + 'Prop': { + 'configuredMulticastStreamsThreshold': 'rw' + } + + } + } +} + +fm = { + 'Status': { + 'Prop': { + 'AlarmStatus': 'r-' + }, + 'Cmd': ( + 'Acknowledge', + ) + }, + 'Configuration': { + 'Prop': { + 'AlarmConfiguration': 'rw' + } + } +} + +pm = { + 'UserCounter': { + 'Prop': { + 'UserCounterDisplayMode': 'rw', + 'UserCounterTable': 'r-' + }, + 'Cmd': ( + 'UserCounterReset', + ) + }, + 'History15min': { + 'Prop': { + 'History15minDisplayMode': 'rw', + 'History15minTable': 'r-' + } + }, + 'History24h': { + 'Prop': { + 'History24hDisplayMode': 'rw', + 'History24hTable': 'r-' + } + }, + 'Alarm15min': { + 'Prop': { + 'Alarm15minDisplayMode': 'rw', + 'Alarm15minTable': 'r-' + }, + 'Cmd': ( + 'Alarm15minReset', + ) + }, + 'Alarm24h': { + 'Prop': { + 'Alarm24hDisplayMode': 'rw', + 'Alarm24hTable': 'r-' + }, + 'Cmd': ( + 'Alarm24hReset', + ) + }, + 'PerformanceMonitoring': { + 'Cmd': ( + 'UserCounter', + 'GetHistory15min', + 'GetHistory24h', + 'GetAlarm15min', + 'GetAlarm24hRecursive', + 'ResetUserCounter', + 'ResetAlarm15min', + 'ResetAlarm24h' + ) + } +} + +status = { + 'multicast': { + 'activeStreams': { + 'Dynamic': { + 'Prop': { + 'activeMulticastStreams': 'r-', + 'NumberOfActiveStreams': 'r-' + }, + 'Cmd': ( + 'clearAllStreams', + ) + }, + 'Static': { + 'Prop': { + 'StaticMulticastStreams': 'r-', + 'NumberOfStaticStreams': 'r-' + } + }, + }, + + 'unitConfiguration': { + 'Prop': { + 'multicastUnitConfigurationStatus': 'r-' + } + }, + 'portSummary': { + 'Prop': { + 'CoreUnitFrontPorts': 'r-', + 'CapableServiceUnits': 'r-' + } + }, + 'Router': { + 'Prop': { + 'learnedIpRouterSourceAddress': 'r-' + } + + } + } +} diff --git a/vendors/KeyMile/accessPoints/root/rootCommandProcessor.py b/vendors/KeyMile/accessPoints/root/rootCommandProcessor.py new file mode 100644 index 0000000..091b9aa --- /dev/null +++ b/vendors/KeyMile/accessPoints/root/rootCommandProcessor.py @@ -0,0 +1,114 @@ +# This file is part of the NESi software. +# +# Copyright (c) 2020 +# Original Software Design by Ilya Etingof . +# +# Software adapted by inexio . +# - Janis Groß +# - Philip Konrath +# - Alexander Dincher +# - Philipp-Noah Groß +# +# License: https://github.com/inexio/NESi/LICENSE.rst + +from nesi import exceptions +from vendors.KeyMile.baseCommandProcessor import BaseCommandProcessor + + +class RootCommandProcessor(BaseCommandProcessor): + __name__ = 'root' + management_functions = {'main', 'cfgm', 'fm', 'status'} + access_points = ('eoam', 'fan', 'multicast', 'services', 'tdmConnections') + + from .rootManagementFunctions import main + from .rootManagementFunctions import cfgm + from .rootManagementFunctions import fm + from .rootManagementFunctions import status + + def _init_access_points(self, context=None): + self.access_points = ('eoam', 'fan', 'multicast', 'services', 'tdmConnections') + for card in self._model.cards: + if 'unit-' + card.name in self.access_points: + continue + self.access_points += ('unit-' + card.name,) + + first_unit = 0 + unit_count = 0 + if self._model.version == '2500': + first_unit = 1 + unit_count = 21 + elif self._model.version == '2300': + first_unit = 7 + unit_count = 8 + elif self._model.version == '2200': + first_unit = 9 + unit_count = 4 + + for i in range(first_unit, first_unit + unit_count): + if 'unit-' + str(i) in self.access_points: + continue + + if 'unit-' + str(i - 1) not in self.access_points: + self.access_points += (i,) + else: + self.access_points = self.access_points[:self.access_points.index('unit-' + str(i - 1)) + 1] + ('unit-' + str(i),) + self.access_points[self.access_points.index('unit-' + str(i - 1)) + 1:] + + def _init_context(self, context=None): + context['ls_Name'] = self._model.model + ' ' + self._model.version + context['ls_MainMode'] = '' + context['ls_EquipmentState'] = 'Ok' + + def set(self, command, *args, context=None): + if self._validate(args, *()): + exc = exceptions.CommandSyntaxError(command=command) + exc.template = 'syntax_error' + exc.template_scopes = ('login', 'base', 'syntax_errors') + raise exc + elif self._validate(args, 'VlanId', str) and context['path'].split('/')[-1] == 'cfgm': + vlan_id, = self._dissect(args, 'VlanId', str) + vlan_id = int(vlan_id) + if not 1 < vlan_id < 4089: + raise exceptions.CommandExecutionError(template='syntax_error', + template_scopes=('login', 'base', 'syntax_errors'), + command=None) + + self._model.set_vlan_id(vlan_id) + elif self._validate(args, 'IP_Address', str, str, str) and context['path'].split('/')[-1] == 'cfgm': + new_ip, net_mask, gateway = self._dissect(args, 'IP_Address', str, str, str) + + self._model.set_mgmt_address(new_ip) + self._model.set_net_mask(net_mask) + self._model.set_default_gateway(gateway) + else: + raise exceptions.CommandExecutionError(command=command, template='invalid_property', + template_scopes=('login', 'base', 'execution_errors')) + + def do_save(self, command, *args, context=None): + if len(args) == 0 and context['path'].split('/')[-1] == 'cfgm': + pass + else: + raise exceptions.CommandSyntaxError(command=command) + + def get_property(self, command, *args, context=None): + scopes = ('login', 'base', 'get') + if self._validate(args, "CurrTemperature") and context['path'].split('/')[-1] == 'status': + context['currTemperature'] = self._model.currTemperature + context['spacer'] = self.create_spacers((67,), (context['currTemperature'],))[0] * ' ' + self._write(self._render('currTemperature', *scopes, context=context)) + elif self._validate(args, 'IP_Address') and context['path'].split('/')[-1] == 'cfgm': + context['ip_address'] = self._model.mgmt_address + context['spacer1'] = self.create_spacers((67,), (self._model.mgmt_address,))[0] * ' ' + + context['net_mask'] = self._model.net_mask + context['spacer2'] = self.create_spacers((67,), (self._model.net_mask,))[0] * ' ' + + context['default_gateway'] = self._model.default_gateway + context['spacer3'] = self.create_spacers((67,), (self._model.default_gateway,))[0] * ' ' + self._write(self._render('ip_address', *scopes, context=context)) + elif self._validate(args, 'VlanId') and context['path'].split('/')[-1] == 'cfgm': + context['vlan_id'] = self._model.network_element_management_vlan_id + context['spacer'] = self.create_spacers((67,), (context['vlan_id'],))[0] * ' ' + self._write(self._render('vlan_id', *scopes, context=context)) + else: + raise exceptions.CommandExecutionError(command=command, template='invalid_property', + template_scopes=('login', 'base', 'execution_errors')) diff --git a/vendors/KeyMile/accessPoints/root/rootManagementFunctions.py b/vendors/KeyMile/accessPoints/root/rootManagementFunctions.py new file mode 100644 index 0000000..479c920 --- /dev/null +++ b/vendors/KeyMile/accessPoints/root/rootManagementFunctions.py @@ -0,0 +1,333 @@ +main = { + 'General': { + 'Prop': { + 'Labels': 'rw', + 'AlarmStatus': 'r-' + } + }, + 'Inventory': { + 'Prop': { + 'EquipmentInventory': 'r-' + } + }, + 'Logbooks': { + 'Cmd': ( + 'GetAllLogbooks', + 'GetAlarmLogbook', + 'GetEventLogbook', + 'GetConfigLogbook', + 'GetEquipmentLogbook', + 'GetSessionLogbook' + ) + }, + 'NESoftwareDownload': { + 'Cmd': ( + 'StartEsw', + ) + } +} + +cfgm = { + 'ConfigurationManagement': { + 'Prop': { + 'ConfigurationStatus': 'r-', + 'BackupDescription': 'r-' + }, + 'Cmd': ( + 'Load', + 'Save', + 'Initialize', + 'ChangeDescription' + ), + 'File': { + 'Configuration': 'rw' + } + }, + 'ManagementInterface': { + 'Prop': { + 'IP_Address': 'rw', + 'VlanId': 'rw', + 'ManagementVlanCoS': 'rw' + } + }, + 'Packet': { + 'Prop': { + 'Bridge': 'rw', + 'MACMovement': 'rw', + 'Traceability': 'rw', + 'PPPoA': 'rw' + } + }, + 'SessionManagement': { + 'Prop': { + 'TelnetEnabled': 'r-', + 'SshEnabled': 'r-', + 'UsbEnabled': 'r-', + 'RetryTime': 'r-', + 'SessionmanagerTime': 'r-', + 'AuthenticationManagementInterfaces': 'r-', + 'LocalAuthenticationFallback': 'r-', + 'RadiusDefaultUserclass': 'r-' + } + }, + 'RadiusClient': { + 'Prop': { + 'CommonRadius': 'r-', + 'PrimaryRadiusServer': 'r-', + 'AlternateRadiusServer': 'r-' + } + }, + 'DateAndTime': { + 'SNTPClient': { + 'Prop': { + 'OperationMode': 'rw', + 'PrimaryServer': 'rw', + 'SecondaryServer': 'rw', + 'PollingInterval': 'rw', + 'BroadcastDelay': 'rw' + } + }, + 'TimeZone': { + 'Prop': { + 'TimeZone': 'rw', + 'DaylightSaving': 'r-' + } + }, + }, + 'ProfileManagement': { + 'Prop': { + 'ProfileCpsTable': 'r-' + }, + 'Cmd': ( + 'Check', + 'Delete' + ), + 'File': { + 'Profile': 'rw', + 'Cps': 'rw' + } + }, + 'QoS': { + 'Prop': { + 'PriorityMapping': 'rw', + 'QueueMode': 'rw' + } + }, + 'SNMP': { + 'General': { + 'Prop': { + 'SNMPSupport': 'rw', + 'SNMPParameters': 'r-' + }, + 'Cmd': ( + 'SetDefaultSNMPConfigurationTables', + ) + }, + 'USM': { + 'Prop': { + 'LocalUserTable': 'rw', + 'RemoteUserTable': 'rw' + } + }, + }, + 'SyslogDestinations': { + 'Destination1': { + 'Prop': { + 'SyslogDestination1': 'rw' + } + }, + 'Destination2': { + 'Prop': { + 'SyslogDestination2': 'rw' + } + }, + 'Destination3': { + 'Prop': { + 'SyslogDestination3': 'rw' + } + }, + 'Destination4': { + 'Prop': { + 'SyslogDestination4': 'rw' + } + }, + 'Destination5': { + 'Prop': { + 'SyslogDestination5': 'rw' + } + }, + 'Destination6': { + 'Prop': { + 'SyslogDestination6': 'rw' + } + }, + 'Destination7': { + 'Prop': { + 'SyslogDestination7': 'rw' + } + }, + 'Destination8': { + 'Prop': { + 'SyslogDestination8': 'rw' + } + }, + 'Destination9': { + 'Prop': { + 'SyslogDestination9': 'rw' + } + }, + 'Destination10': { + 'Prop': { + 'SyslogDestination10': 'rw' + } + }, + }, + 'SyslogSources': { + 'Prop': { + 'SyslogSourceConfiguration': 'rw' + } + }, + 'BatteryPowerSaving': { + 'Prop': { + 'PowerSavingEnabled': 'rw', + 'PowerSavingAlarm': 'rw', + 'PowerSavingThresholds': 'rw', + 'PowerSavingUnits': 'r-' + }, + 'Cmd': ( + 'PowerSavingAddUnit', + 'PowerSavingRemoveUnit' + ) + }, + 'Ipsec': { + 'Prop': { + 'Ipsec': 'rw' + } + }, + 'TemeratureLimits': { + 'Prop': { + 'ThresholdExceed': 'rw', + 'ThresholdWarning': 'rw' + } + }, + 'ESO': { + 'Prop': { + 'Eso1ClockSources': 'rw', + 'Eso2ClockSource': 'rw' + } + }, + 'PETS': { + 'Prop': { + 'ClockSources': 'rw', + 'PetsClockPriority': 'rw' + } + } +} + +fm = { + 'ActiveFailures': { + 'Prop': { + 'ActiveFailureTable': 'r-' + } + }, + 'Status': { + 'Prop': { + 'AlarmStatus': 'r-' + }, + 'Cmd': ( + 'Acknowledge', + ) + }, + 'Configuration': { + 'Prop': { + 'AlarmConfiguration': 'rw' + } + } +} + +status = { + 'DateAndTime': { + 'Time': { + 'Prop': { + 'Summary': 'r-' + }, + 'Cmd': ( + 'SetDateAndTime', + ) + }, + 'SNTPClient': { + 'Prop': { + 'PrimaryServerState': 'r-', + 'SecondaryServerState': 'r-', + 'LastResponseTime': 'r-', + 'LastJumpTime': 'r-', + 'LastAdjustmentTime': 'r-' + } + }, + }, + 'ManagementInterface': { + 'Prop': { + 'SshFingerprint': 'r-' + }, + 'Cmd': ( + 'Ping', + ) + }, + 'SessionManagement': { + 'Cmd': ( + 'ShowSessions', + ) + }, + 'RadiusClient': { + 'Prop': { + 'PrimaryRadiusServerStatus': 'r-', + 'AlternateRadiusServerStatus': 'r-' + } + }, + 'Ipsec': { + 'Prop': { + 'IpsecSAStatus': 'r-' + }, + 'Cmd': ( + 'GetIpsecLogbook', + ) + }, + 'Redundancy': { + 'Prop': { + 'NeConfigurationStatus': 'r-', + 'RedundancyRoles': 'r-', + 'RedundancyStatus': 'r-' + }, + 'Cmd': ( + 'ManualSwitchOver', + 'ForcedSwitchOver', + 'IsolateUnits', + 'JoinUnits' + ) + }, + 'Temperature': { + 'Prop': { + 'CurrTemperature': 'r-', + 'MaxTemperature': 'r-', + 'MinTemperature': 'r-' + }, + 'Cmd': ( + 'ResetMinMax', + ) + }, + 'ESO': { + 'Prop': { + 'ClockOutputEso1': 'r-', + 'ClockOutputEso2': 'r-' + } + }, + 'PETS': { + 'Prop': { + 'PetsClockSources': 'r-', + 'PetsOperationStatus': 'r-' + }, + 'Cmd': ( + 'PetsClockOperation', + ) + } +} diff --git a/vendors/KeyMile/accessPoints/root/services/macaccessctrlCommandProcessor.py b/vendors/KeyMile/accessPoints/root/services/macaccessctrlCommandProcessor.py new file mode 100644 index 0000000..995a39c --- /dev/null +++ b/vendors/KeyMile/accessPoints/root/services/macaccessctrlCommandProcessor.py @@ -0,0 +1,39 @@ +# This file is part of the NESi software. +# +# Copyright (c) 2020 +# Original Software Design by Ilya Etingof . +# +# Software adapted by inexio . +# - Janis Groß +# - Philip Konrath +# - Alexander Dincher +# +# License: https://github.com/inexio/NESi/LICENSE.rst + +from nesi import exceptions +from vendors.KeyMile.baseCommandProcessor import BaseCommandProcessor + + +class MacaccessctrlCommandProcessor(BaseCommandProcessor): + __name__ = 'macAccessCtrl' + management_functions = ('main', 'cfgm', 'fm', 'status') + access_points = () + + from .macaccessctrlManagementFunctions import main + from .macaccessctrlManagementFunctions import cfgm + from .macaccessctrlManagementFunctions import fm + from .macaccessctrlManagementFunctions import status + + def set(self, command, *args, context=None): + scopes = ('login', 'base', 'set') + try: + super().set(command, *args, context=None) + except exceptions.CommandExecutionError: + if self._validate(args, *()): + exc = exceptions.CommandSyntaxError(command=command) + exc.template = 'syntax_error' + exc.template_scopes = ('login', 'base', 'syntax_errors') + raise exc + else: + raise exceptions.CommandExecutionError(command=command, template='invalid_property', + template_scopes=('login', 'base', 'execution_errors')) diff --git a/vendors/KeyMile/accessPoints/root/services/macaccessctrlManagementFunctions.py b/vendors/KeyMile/accessPoints/root/services/macaccessctrlManagementFunctions.py new file mode 100644 index 0000000..4ec41f2 --- /dev/null +++ b/vendors/KeyMile/accessPoints/root/services/macaccessctrlManagementFunctions.py @@ -0,0 +1,61 @@ +main = { + 'General': { + 'Prop': { + 'Labels': 'rw', + 'AlarmStatus': 'r-' + } + } +} + +cfgm = { + 'General': { + 'Prop': { + 'Blacklist': 'rw' + } + } +} + +fm = { + 'Status': { + 'Prop': { + 'AlarmStatus': 'r-' + }, + 'Cmd': ( + 'Acknowledge', + ) + }, + 'Configuration': { + 'Prop': { + 'AlarmConfiguration': 'rw' + } + }, + 'DuplicatedMac': { + 'Prop': { + 'DuplicatedMacAccessList': 'r-' + }, + 'Cmd': ( + 'FlushMacAccessDuplicatedList', + ) + } +} + +status = { + 'DynamicList': { + 'Prop': { + 'DynamicList': 'r-' + }, + 'Cmd': ( + 'FlushMacAccessDynamicList', + 'DeleteMacAccessDynamicListEntry' + ) + }, + 'UNIBlacklist': { + 'Prop': { + 'Blacklist': 'r-', + 'BNGlist': 'r-' + }, + 'Cmd': ( + 'DeleteMacAccessBNGlistEntry', + ) + } +} diff --git a/vendors/KeyMile/accessPoints/root/services/packetCommandProcessor.py b/vendors/KeyMile/accessPoints/root/services/packetCommandProcessor.py new file mode 100644 index 0000000..51173c3 --- /dev/null +++ b/vendors/KeyMile/accessPoints/root/services/packetCommandProcessor.py @@ -0,0 +1,36 @@ +# This file is part of the NESi software. +# +# Copyright (c) 2020 +# Original Software Design by Ilya Etingof . +# +# Software adapted by inexio . +# - Janis Groß +# - Philip Konrath +# - Alexander Dincher +# +# License: https://github.com/inexio/NESi/LICENSE.rst + +from nesi import exceptions +from vendors.KeyMile.baseCommandProcessor import BaseCommandProcessor + + +class PacketCommandProcessor(BaseCommandProcessor): + __name__ = 'packet' + management_functions = ('main',) + access_points = ('1to1DoubleTag', '1to1SingleTag', 'mcast', 'nto1', 'pls', 'tls') + + from .packetManagementFunctions import main + + def set(self, command, *args, context=None): + scopes = ('login', 'base', 'set') + try: + super().set(command, *args, context=None) + except exceptions.CommandExecutionError: + if self._validate(args, *()): + exc = exceptions.CommandSyntaxError(command=command) + exc.template = 'syntax_error' + exc.template_scopes = ('login', 'base', 'syntax_errors') + raise exc + else: + raise exceptions.CommandExecutionError(command=command, template='invalid_property', + template_scopes=('login', 'base', 'execution_errors')) diff --git a/vendors/KeyMile/accessPoints/root/services/packetManagementFunctions.py b/vendors/KeyMile/accessPoints/root/services/packetManagementFunctions.py new file mode 100644 index 0000000..ebb0f2f --- /dev/null +++ b/vendors/KeyMile/accessPoints/root/services/packetManagementFunctions.py @@ -0,0 +1,8 @@ +main = { + 'General': { + 'Prop': { + 'Labels': 'rw', + 'AlarmStatus': 'r-' + } + } +} diff --git a/vendors/KeyMile/accessPoints/root/services/servicesCommandProcessor.py b/vendors/KeyMile/accessPoints/root/services/servicesCommandProcessor.py new file mode 100644 index 0000000..c2ff987 --- /dev/null +++ b/vendors/KeyMile/accessPoints/root/services/servicesCommandProcessor.py @@ -0,0 +1,38 @@ +# This file is part of the NESi software. +# +# Copyright (c) 2020 +# Original Software Design by Ilya Etingof . +# +# Software adapted by inexio . +# - Janis Groß +# - Philip Konrath +# - Alexander Dincher +# +# License: https://github.com/inexio/NESi/LICENSE.rst + +from nesi import exceptions +from vendors.KeyMile.baseCommandProcessor import BaseCommandProcessor + + +class ServicesCommandProcessor(BaseCommandProcessor): + __name__ = 'services' + management_functions = ('main', 'fm', 'status') + access_points = ('macAccessCtrl', 'packet') + + from .servicesManagementFunctions import main + from .servicesManagementFunctions import fm + from .servicesManagementFunctions import status + + def set(self, command, *args, context=None): + scopes = ('login', 'base', 'set') + try: + super().set(command, *args, context=None) + except exceptions.CommandExecutionError: + if self._validate(args, *()): + exc = exceptions.CommandSyntaxError(command=command) + exc.template = 'syntax_error' + exc.template_scopes = ('login', 'base', 'syntax_errors') + raise exc + else: + raise exceptions.CommandExecutionError(command=command, template='invalid_property', + template_scopes=('login', 'base', 'execution_errors')) diff --git a/vendors/KeyMile/accessPoints/root/services/servicesManagementFunctions.py b/vendors/KeyMile/accessPoints/root/services/servicesManagementFunctions.py new file mode 100644 index 0000000..b1bccfc --- /dev/null +++ b/vendors/KeyMile/accessPoints/root/services/servicesManagementFunctions.py @@ -0,0 +1,30 @@ +main = { + 'General': { + 'Prop': { + 'Labels': 'rw', + 'AlarmStatus': 'r-' + } + } +} + +fm = { + 'Status': { + 'Prop': { + 'AlarmStatus': 'r-' + }, + 'Cmd': ( + 'Acknowledge', + ) + }, + 'Configuration': { + 'Prop': { + 'AlarmConfiguration': 'rw' + } + } +} + +status = { + 'Prop': { + 'conflictList': 'r-' + } +} diff --git a/vendors/KeyMile/accessPoints/root/services/srvcCommandProcessor.py b/vendors/KeyMile/accessPoints/root/services/srvcCommandProcessor.py new file mode 100644 index 0000000..8681383 --- /dev/null +++ b/vendors/KeyMile/accessPoints/root/services/srvcCommandProcessor.py @@ -0,0 +1,95 @@ +# This file is part of the NESi software. +# +# Copyright (c) 2020 +# Original Software Design by Ilya Etingof . +# +# Software adapted by inexio . +# - Janis Groß +# - Philip Konrath +# - Alexander Dincher +# - Philipp-Noah Groß +# +# License: https://github.com/inexio/NESi/LICENSE.rst + +from nesi import exceptions +from vendors.KeyMile.baseCommandProcessor import BaseCommandProcessor + + +class SrvcCommandProcessor(BaseCommandProcessor): + __name__ = 'srvc' + management_functions = ('main', 'cfgm', 'status') + access_points = () + + from .srvcManagementFunctions import main + from .srvcManagementFunctions import cfgm + from .srvcManagementFunctions import status + + def get_property(self, command, *args, context=None): + service_name = self.component_name + services = self._model.get_srvcs('name', service_name) + service = None + for s in services: + if s.service_type.lower() == context['ServiceType'] and s.name == service_name: + service = s + context['service'] = service + break + + if not service: + raise exceptions.CommandExecutionError(command=command, template='invalid_property', + template_scopes=('login', 'base', 'execution_errors')) + + scopes = ('login', 'base', 'get') + if self._validate((args[0],), 'Service') and context['path'].split('/')[-1] == 'cfgm': + # TODO: Find missing templates, and replace placeholder templates + if service.service_type == '1to1doubletag': + template_name = 'service_onetoonedoubletag' + elif service.service_type == '1to1singletag': + template_name = 'service_onetoonesingletag' + elif service.service_type == 'mcast': + template_name = 'service_mcast' + elif service.service_type == 'nto1': + template_name = 'service_nto1' + elif service.service_type == 'pls': + template_name = 'service_pls' + elif service.service_type == 'tls': + template_name = 'service_tls' + else: + raise exceptions.CommandExecutionError(command=command) + context['spacer1'] = self.create_spacers((67,), (service.address,))[0] * ' ' + context['spacer2'] = self.create_spacers((67,), (service.svid,))[0] * ' ' + context['spacer3'] = self.create_spacers((67,), (service.stag_priority,))[0] * ' ' + context['spacer4'] = self.create_spacers((67,), (service.vlan_handling,))[0] * ' ' + text = self._render(template_name, *scopes, context=context) + self._write(text) + else: + raise exceptions.CommandExecutionError(command=command, template='invalid_property', + template_scopes=('login', 'base', 'execution_errors')) + + def set(self, command, *args, context=None): + if self._validate(args, *()): + exc = exceptions.CommandSyntaxError(command=command) + exc.template = 'syntax_error' + exc.template_scopes = ('login', 'base', 'syntax_errors') + raise exc + elif self._validate(args, 'Service', str, str, str, str) and context['path'].split('/')[-1] == 'cfgm': + address, svid, stag, vlan = self._dissect(args, 'Service', str, str, str, str) + try: + service_name = self.component_name + services = self._model.get_srvcs('name', service_name) + service = None + for s in services: + if s.service_type.lower() == context['ServiceType'] and s.name == service_name: + service = s + break + + if not service: + raise exceptions.CommandExecutionError(command=command, template='invalid_property', + template_scopes=('login', 'base', 'execution_errors')) + + service.set_service(address, int(svid), stag, vlan) + except exceptions.SoftboxenError: + raise exceptions.CommandExecutionError(command=command, template='invalid_property', + template_scopes=('login', 'base', 'execution_errors')) + + def get_component(self): + return self._model.get_srvcs('name', self.component_name) diff --git a/vendors/KeyMile/accessPoints/root/services/srvcManagementFunctions.py b/vendors/KeyMile/accessPoints/root/services/srvcManagementFunctions.py new file mode 100644 index 0000000..be32883 --- /dev/null +++ b/vendors/KeyMile/accessPoints/root/services/srvcManagementFunctions.py @@ -0,0 +1,31 @@ +main = { + 'General': { + 'Prop': { + 'Labels': 'rw', + 'AlarmStatus': 'r-' + } + }, + 'AdminOperStatus': { + 'Prop': { + 'AdminState': 'rw', + 'OperState': 'r-' + } + } + } + +cfgm = { + 'Nto1AccessService': { + 'Prop': { + 'Service': 'rw' + } + } + } + +status = { + 'mgmt': { + 'Prop': { + 'maList': 'r-', + 'mepList': 'r-' + } + } + } diff --git a/vendors/KeyMile/accessPoints/root/services/subpacketCommandProcessor.py b/vendors/KeyMile/accessPoints/root/services/subpacketCommandProcessor.py new file mode 100644 index 0000000..9d46cbb --- /dev/null +++ b/vendors/KeyMile/accessPoints/root/services/subpacketCommandProcessor.py @@ -0,0 +1,77 @@ +# This file is part of the NESi software. +# +# Copyright (c) 2020 +# Original Software Design by Ilya Etingof . +# +# Software adapted by inexio . +# - Janis Groß +# - Philip Konrath +# - Alexander Dincher +# - Philipp-Noah Groß +# +# License: https://github.com/inexio/NESi/LICENSE.rst + +from nesi import exceptions +from vendors.KeyMile.baseCommandProcessor import BaseCommandProcessor + + +class SubpacketCommandProcessor(BaseCommandProcessor): + __name__ = 'subpacket' + management_functions = ('main', 'cfgm') + access_points = () + + from .subpacketManagementFunctions import main + from .subpacketManagementFunctions import cfgm + + def _init_access_points(self, context=None): + self.access_points = () + try: + self.management_functions = ('main', 'cfgm') + s_type = context['ServiceType'] + + srvcs = self._model.get_srvcs('service_type', s_type) + for srvc in srvcs: + identifier = srvc.name + if identifier in self.access_points: + continue + self.access_points += (identifier,) + except exceptions.InvalidInputError: + pass + + def do_deleteservice(self, command, *args, context=None): + if self._validate(args, str) and context['path'].split('/')[-1] == 'cfgm': + srvc_id, = self._dissect(args, str) + service_name = 'srvc-' + srvc_id + service = None + services = self._model.get_srvcs('name', service_name) + for s in services: + if s.service_type == context['ServiceType']: + service = s + break + if service is None: + raise exceptions.CommandExecutionError(command=command, template='unknown_service_fragment', + template_scopes=('login', 'base', 'execution_errors')) + service.delete() + else: + raise exceptions.CommandSyntaxError(command=command) + + def do_createservice(self, command, *args, context=None): + if context['ServiceType'] == 'nto1' and context['path'].split('/')[-1] == 'cfgm': + if len(args) == 12: + address, svid = self._dissect(args[:2], str, str) + # TODO: validate address + srvc = self._model.add_srvc(service_type='nto1', address=address, svid=svid) + + else: + raise exceptions.CommandSyntaxError(command=command) + + elif context['ServiceType'] == '1to1singletag' and context['path'].split('/')[-1] == 'cfgm': + if len(args) == 4: + address, svid = self._dissect(args[:2], str, str) + # TODO: validate address + srvc = self._model.add_srvc(service_type='1to1singletag', address=address, svid=svid) + + else: + raise exceptions.CommandSyntaxError(command=command) + else: + raise exceptions.CommandSyntaxError(command=command) diff --git a/vendors/KeyMile/accessPoints/root/services/subpacketManagementFunctions.py b/vendors/KeyMile/accessPoints/root/services/subpacketManagementFunctions.py new file mode 100644 index 0000000..aa446e7 --- /dev/null +++ b/vendors/KeyMile/accessPoints/root/services/subpacketManagementFunctions.py @@ -0,0 +1,15 @@ +main = { + 'General': { + 'Prop': { + 'Labels': 'rw', + 'AlarmStatus': 'r-' + } + } + } + +cfgm = { + 'Cmd': ( + 'CreateService', + 'DeleteService' + ) + } diff --git a/vendors/KeyMile/accessPoints/root/tdmconnectionsCommandProcessor.py b/vendors/KeyMile/accessPoints/root/tdmconnectionsCommandProcessor.py new file mode 100644 index 0000000..0cd0f2e --- /dev/null +++ b/vendors/KeyMile/accessPoints/root/tdmconnectionsCommandProcessor.py @@ -0,0 +1,32 @@ +# This file is part of the NESi software. +# +# Copyright (c) 2020 +# Original Software Design by Ilya Etingof . +# +# Software adapted by inexio . +# - Janis Groß +# - Philip Konrath +# - Alexander Dincher +# +# License: https://github.com/inexio/NESi/LICENSE.rst + +from nesi import exceptions +from vendors.KeyMile.baseCommandProcessor import BaseCommandProcessor + + +class TdmconnectionsCommandProcessor(BaseCommandProcessor): + __name__ = 'tdmConnections' + management_functions = ('main', 'cfgm') + access_points = () + + from .tdmconnectionsManagementFunctions import main + from .tdmconnectionsManagementFunctions import cfgm + + def set(self, command, *args, context=None): + if self._validate(args, *()): + exc = exceptions.CommandSyntaxError(command=command) + exc.template = 'syntax_error' + exc.template_scopes = ('login', 'base', 'syntax_errors') + raise exc + else: + raise exceptions.CommandSyntaxError(command=command) \ No newline at end of file diff --git a/vendors/KeyMile/accessPoints/root/tdmconnectionsManagementFunctions.py b/vendors/KeyMile/accessPoints/root/tdmconnectionsManagementFunctions.py new file mode 100644 index 0000000..894d3f3 --- /dev/null +++ b/vendors/KeyMile/accessPoints/root/tdmconnectionsManagementFunctions.py @@ -0,0 +1,33 @@ +main = { + 'General': { + 'Prop': { + 'Labels': 'rw', + 'AlarmStatus': 'r-' + } + } +} + +cfgm = { + 'Connections': { + 'Cmd': ( + 'CreateConnection', + 'CreateBulkConnection', + 'CreateAdvancedConnection', + 'DeleteConnection', + 'DeleteMultipleConnections', + 'ShowConnections', + 'SetLabel1', + 'SetLabel2' + ) + }, + 'Ctps': { + 'Cmd': ( + 'ShowCtps', + ) + }, + 'Pbus': { + 'Prop': { + 'PbusUsage': 'r-' + } + } +} diff --git a/vendors/KeyMile/accessPoints/root/unit/logport/logportsCommandProcessor.py b/vendors/KeyMile/accessPoints/root/unit/logport/logportsCommandProcessor.py new file mode 100644 index 0000000..acae680 --- /dev/null +++ b/vendors/KeyMile/accessPoints/root/unit/logport/logportsCommandProcessor.py @@ -0,0 +1,101 @@ +# This file is part of the NESi software. +# +# Copyright (c) 2020 +# Original Software Design by Ilya Etingof . +# +# Software adapted by inexio . +# - Janis Groß +# - Philip Konrath +# - Alexander Dincher +# +# License: https://github.com/inexio/NESi/LICENSE.rst + +from nesi import exceptions +from vendors.KeyMile.baseCommandProcessor import BaseCommandProcessor + + +class LogportsCommandProcessor(BaseCommandProcessor): + __name__ = 'logports' + management_functions = ('main', 'cfgm') + access_points = () + + from .logportsManagementFunctions import main + from .logportsManagementFunctions import cfgm + + def _init_access_points(self, context=None): # work in progress + self.access_points = () + card = self._model.get_card('name', self.component_name.split('/')[0]) + + for logport in self._model.get_logports('card_id', card.id): + if logport.name.count('/') == 2: + identifier = 'logport-' + logport.name.split('/')[-1] + if identifier in self.access_points: + continue + self.access_points += (identifier,) + accpoint = list(self.access_points) + accpoint.sort(key=lambda x: int(x.split('-')[1])) + self.access_points = tuple(accpoint) + + def do_delete(self, command, *args, context=None): + if self._validate(args, str) and context['path'].split('/')[-1] == 'cfgm': + name, = self._dissect(args, str) + if name.startswith('logport-'): + id = name.split('-')[1] + try: + port = self._model.get_logport('name', self._parent.component_name + '/L/' + id) + port.delete() + except exceptions.SoftboxenError: + raise exceptions.CommandSyntaxError(command=command) + else: + raise exceptions.CommandSyntaxError(command=command) + else: + raise exceptions.CommandSyntaxError(command=command) + + def do_create(self, command, *args, context=None): + if self._validate(args, str, str, str, str, str) and context['path'].split('/')[-1] == 'cfgm': + p1, p2, p3, p4, profile = self._dissect(args, str, str, str, str, str) + self.create(p1, p2, p3, p4, profile, command) + elif self._validate(args, str, str, str, str) and context['path'].split('/')[-1] == 'cfgm': + p1, p2, p3, profile = self._dissect(args, str, str, str, str) + self.create(p1, p2, p3, '', profile, command) + elif self._validate(args, str, str, str) and context['path'].split('/')[-1] == 'cfgm': + p1, p2, profile = self._dissect(args, str, str, str) + self.create(p1, p2, '', '', profile, command) + elif self._validate(args, str, str) and context['path'].split('/')[-1] == 'cfgm': + p1, profile = self._dissect(args, str, str) + self.create(p1, '', '', '', profile, command) + else: + raise exceptions.CommandSyntaxError(command=command) + + def create(self, p1, p2, p3, p4, profile, command): + ids = [] + ids.append(int(p1.split('-')[1])) if p1.startswith('port-') else ids + ids.append(int(p2.split('-')[1])) if p2.startswith('port-') else ids + ids.append(int(p3.split('-')[1])) if p3.startswith('port-') else ids + ids.append(int(p4.split('-')[1])) if p4.startswith('port-') else ids + if len(ids) > 0: + ids.sort() + try: + for x in ids: + self._model.get_logport('name', self._parent.component_name + '/L/' + str(x)) + break + except exceptions.SoftboxenError: + name = self._parent.component_name + '/L/' + str(ids[0]) + ports = 'ports: ' + for x in ids: + ports += str(x) + ', ' + card = self._model.get_card('name', self._parent.component_name) + logport = self._model.add_logport(card_id=card.id, name=name, ports=ports[:-2]) + logport = self._model.get_logport('name', name) + logport.set_profile(profile) + else: + raise exceptions.CommandSyntaxError(command=command) + + def set(self, command, *args, context=None): + if self._validate(args, *()): + exc = exceptions.CommandSyntaxError(command=command) + exc.template = 'syntax_error' + exc.template_scopes = ('login', 'base', 'syntax_errors') + raise exc + else: + raise exceptions.CommandSyntaxError(command=command) diff --git a/vendors/KeyMile/accessPoints/root/unit/logport/logportsManagementFunctions.py b/vendors/KeyMile/accessPoints/root/unit/logport/logportsManagementFunctions.py new file mode 100644 index 0000000..b9fc7b2 --- /dev/null +++ b/vendors/KeyMile/accessPoints/root/unit/logport/logportsManagementFunctions.py @@ -0,0 +1,17 @@ +main = { + 'General': { + 'Prop': { + 'Labels': 'rw', + 'AlarmStatus': 'r-' + } + } +} + +cfgm = { + 'Logicalport': { + 'Cmd': ( + 'Create', + 'Delete' + ) + } +} \ No newline at end of file diff --git a/vendors/KeyMile/accessPoints/root/unit/logport/port/logportCommandProcessor.py b/vendors/KeyMile/accessPoints/root/unit/logport/port/logportCommandProcessor.py new file mode 100644 index 0000000..524347e --- /dev/null +++ b/vendors/KeyMile/accessPoints/root/unit/logport/port/logportCommandProcessor.py @@ -0,0 +1,141 @@ +# This file is part of the NESi software. +# +# Copyright (c) 2020 +# Original Software Design by Ilya Etingof . +# +# Software adapted by inexio . +# - Janis Groß +# - Philip Konrath +# - Alexander Dincher +# +# License: https://github.com/inexio/NESi/LICENSE.rst + +from nesi import exceptions +from vendors.KeyMile.accessPoints.root.unit.port.portCommandProcessor import PortCommandProcessor + + +class LogportCommandProcessor(PortCommandProcessor): + __name__ = 'logport' + management_functions = ('main', 'cfgm', 'fm', 'pm', 'status', 'ifMIB') + access_points = () + + from .logportManagementFunctions import main + from .logportManagementFunctions import cfgm + from .logportManagementFunctions import fm + from .logportManagementFunctions import pm + from .logportManagementFunctions import status + from .logportManagementFunctions import ifMIB + + def get_property(self, command, *args, context=None): + port = self.get_component() + context['port'] = port + scopes = ('login', 'base', 'get') + try: + super().get_property(command, *args, context=context) + except exceptions.CommandExecutionError: + if self._validate((args[0],), 'AttainableRate') and context['path'].split('/')[-1] == 'status': + text = self._render('attainable_rate', *scopes, context=context) + self._write(text) + elif self._validate((args[0],), 'ActualStatus') and context['path'].split('/')[-1] == 'status': + text = self._render('actual_status', *scopes, context=context) + self._write(text) + elif self._validate((args[0],), 'OperationalWireState') and context['path'].split('/')[-1] == 'status': + text = self._render('operational_wire_state', *scopes, context=context) + self._write(text) + elif self._validate((args[0],), 'SpanProfiles') and context['path'].split('/')[-1] == 'cfgm': + context['spacer1'] = self.create_spacers((67,), (port.profile,))[0] * ' ' + text = self._render('span_profiles', *scopes, context=context) + self._write(text) + else: + raise exceptions.CommandExecutionError(command=command, template='invalid_property', + template_scopes=('login', 'base', 'execution_errors')) + + def get_component(self): + return self._model.get_logport('name', self.component_name) + + def _init_access_points(self, context=None): + self.access_points = () + logport = self.get_component() + try: + _ = self._model.get_interface('logport_id', logport.id) + except exceptions.SoftboxenError: + pass + else: + for interface in self._model.get_interfaces('logport_id', logport.id): + identifier = 'interface-' + interface.name.split('/')[-1] + if identifier in self.access_points: + continue + self.access_points += (identifier,) + + def _init_context(self, context=None): + logport = self.get_component() + context['ls_Name'] = 'SHDSL Spam' + context['ls_MainMode'] = logport.ports + context['ls_EquipmentState'] = '' + + def do_deleteinterface(self, command, *args, context=None): + card = self._model.get_card('name', self._parent._parent.component_name) + if self._validate(args, str) and context['path'].split('/')[-1] == 'cfgm' and card.product == 'sdsl': + # all or interface_id + name, = self._dissect(args, str) + if name == 'all': + logport = self._model.get_logport('name', self.component_name) + for interface in self._model.get_interfaces('logport_id', logport.id): + interface.delete() + elif name.startswith('interface-'): + id = name.split('-')[1] + try: + interface = self._model.get_interface('name', self.component_name + '/' + id) + interface.delete() + except exceptions.SoftboxenError: + raise exceptions.CommandSyntaxError(command=command) + else: + raise exceptions.CommandSyntaxError(command=command) + else: + raise exceptions.CommandSyntaxError(command=command) + + def do_createinterface(self, command, *args, context=None): + scopes = ('login', 'base', 'set') + card = self._model.get_card('name', self._parent._parent.component_name) + if self._validate(args, str) and context['path'].split('/')[-1] == 'cfgm' and card.product == 'sdsl': + # vcc profile and vlan profile + vlan_prof, = self._dissect(args, str) + # TODO: Check if profiles := default or profile names + try: + logport = self._model.get_logport('name', self.component_name) + id = 1 + for interface in self._model.get_interfaces('logport_id', logport.id): + if interface.logport_id is not None: + new_id = int(interface.name[-1]) + 1 + id = new_id if new_id > id else id + try: + self._model.get_interface('name', self.component_name + '/' + str(id)) + assert False + except exceptions.SoftboxenError: + self._model.add_interface(logport_id=logport.id, vlan_profile=vlan_prof) + context['spacer1'] = self.create_spacers((57,), (str(id),))[0] * ' ' + context['id'] = str(id) + # TODO: Template is unknown + text = self._render('interface_success', *scopes, context=context) + self._write(text) + except AssertionError: + raise exceptions.CommandSyntaxError(command=command) + + except exceptions.SoftboxenError: + raise exceptions.CommandSyntaxError(command=command) + else: + raise exceptions.CommandSyntaxError(command=command) + + def set(self, command, *args, context=None): + scopes = ('login', 'base', 'set') + try: + super().set(command, *args, context=context) + except exceptions.CommandExecutionError: + if self._validate(args, *()): + exc = exceptions.CommandSyntaxError(command=command) + exc.template = 'syntax_error' + exc.template_scopes = ('login', 'base', 'syntax_errors') + raise exc + else: + raise exceptions.CommandExecutionError(command=command, template='invalid_property', + template_scopes=('login', 'base', 'execution_errors')) diff --git a/vendors/KeyMile/accessPoints/root/unit/logport/port/logportManagementFunctions.py b/vendors/KeyMile/accessPoints/root/unit/logport/port/logportManagementFunctions.py new file mode 100644 index 0000000..f2fa827 --- /dev/null +++ b/vendors/KeyMile/accessPoints/root/unit/logport/port/logportManagementFunctions.py @@ -0,0 +1,313 @@ +main = { + 'AdminAndOperStatus': { + 'Prop': { + 'AdministrativeStatus': 'rw', + 'OperationalStatus': 'r-' + } + }, + 'General': { + 'Prop': { + 'Labels': 'rw', + 'AlarmStatus': 'r-' + } + } + } + +cfgm = { + 'Multicast': { + 'Prop': { + 'MaxNumberOfMulticastStreams': 'rw', + 'EnableIgmpClassifier': 'rw', + 'AllowStaticStreams': 'rw', + 'EnableFastLeave': 'rw', + 'GroupManagement': 'rw', + 'Bandwidth': 'rw' + }, + 'Cmd': ( + 'GetGroupList', + ) + }, + 'Traceability': { + 'Prop': { + 'AgentRemoteId': 'rw' + } + }, + 'Security': { + 'Prop': { + 'ServiceOptions': 'rw', + 'MaxNumberOfMac': 'rw' + } + }, + 'AccessControl': { + 'Prop': { + 'ClassificationKey': 'rw', + 'MAT': 'rw' + } + }, + 'RateLimiter': { + 'Prop': { + 'RateLimiting': 'rw', + 'RateLimitingCoS': 'rw' + } + }, + 'Qos': { + 'Prop': { + 'WfqProfile': 'rw' + } + }, + 'subinterface': { + 'Cmd': ( + 'CreateInterface', + 'DeleteInterface' + ) + }, + 'Clock': { + 'Prop': { + 'Referenceclk': 'rw' + } + } + } + +fm = { + 'Status': { + 'Prop': { + 'AlarmStatus': 'r-' + }, + 'Cmd': ( + 'Acknowledge', + ) + }, + 'Configuration': { + 'Prop': { + 'AlarmConfiguration': 'rw' + } + } + } + +pm = { + 'PerformanceMonitoring': { + 'Cmd': ( + 'UserCounter', + 'GetHistory15min', + 'GetHistory24h', + 'GetAlarm15min', + 'GetAlarm24hRecursive', + 'ResetUserCounter', + 'ResetAlarm15min', + 'ResetAlarm24h' + ) + }, + 'UserCounter': { + 'Prop': { + 'UserCounterDisplayMode': 'rw', + 'UserCounterTable': 'r-' + }, + 'Cmd': ( + 'UserCounterReset', + ) + }, + 'History15min': { + 'Prop': { + 'History15minDisplayMode': 'rw', + 'History15minTable': 'r-' + } + }, + 'History24h': { + 'Prop': { + 'History24hDisplayMode': 'rw', + 'History24hTable': 'r-' + } + }, + 'Alarm15min': { + 'Prop': { + 'Alarm15minDisplayMode': 'rw', + 'Alarm15minTable': 'r-' + }, + 'Cmd': ( + 'Alarm15minReset', + ) + }, + 'Alarm24h': { + 'Prop': { + 'Alarm24hDisplayMode': 'rw', + 'Alarm24hTable': 'r-' + }, + 'Cmd': ( + 'Alarm24hReset', + ) + } + } + +status = { + 'statistics': { + 'Prop': { + 'counters': 'r-', + 'PolicingCounters': 'r-' + }, + 'Cmd': ( + 'ResetPortCounters', + ) + }, + 'Nto1MacAccessDynamicList': { + 'Prop': { + 'UnicastList': 'r-' + } + }, + 'HostPortStatistics': { + 'GeneralCounters': { + 'Prop': { + 'GeneralList': 'r-' + }, + 'Cmd': ( + 'ResetGeneralCounters', + ) + }, + 'ProtocolCounters': { + 'IgmpCounters': { + 'Prop': { + 'IgmpProtocolList': 'r-' + }, + 'Cmd': ( + 'ResetIgmpCounters', + ) + }, + 'DhcpCounters': { + 'Prop': { + 'DhcpProtocolList': 'r-' + }, + 'Cmd': ( + 'ResetDhcpCounters', + ) + }, + 'Dhcpv6Counters': { + 'Prop': { + 'Dhcpv6ProtocolList': 'r-' + }, + 'Cmd': ( + 'ResetDhcpv6Counters', + ) + }, + 'ArpCounters': { + 'Prop': { + 'ArpProtocolList': 'r-' + }, + 'Cmd': ( + 'ResetArpCounters', + ) + }, + 'PPPoECounters': { + 'Prop': { + 'PPPoEProtocolList': 'r-' + }, + 'Cmd': ( + 'ResetPPPoECounters', + ) + }, + 'UnknownSourceMACCounters': { + 'Prop': { + 'UnknownSrcMACProtocolList': 'r-' + }, + 'Cmd': ( + 'ResetUnknownSrcMACCounters', + ) + }, + 'Ndp': { + 'Prop': { + 'NdpList': 'r-' + }, + 'Cmd': ( + 'ResetNdpCounters', + ) + }, + }, + }, + 'TLSMacForwardingList': { + 'Prop': { + 'MacForwardingList': 'r-' + }, + 'Cmd': ( + 'FlushMacForwardingList', + ) + }, + '1to1MacForwardingList': { + 'Prop': { + 'One2OneMacForwardingList': 'r-' + } + }, + 'Qos': { + 'Prop': { + 'wfqueues': 'r-' + } + }, + 'Support': { + 'Cmd': ( + 'StartReport', + ), + 'File': { + 'ReportFile': 'r-' + } + }, + 'Multicast': { + 'stream': { + 'Dynamic': { + 'Prop': { + 'ActiveStreams': 'r-' + }, + 'Cmd': ( + 'ClearActiveStreams', + ) + }, + 'Static': { + 'Prop': { + 'StaticStreams': 'r-' + } + }, + }, + + 'Vlan': { + 'Prop': { + 'AttachedVlans': 'r-' + } + }, + 'Preview': { + 'Cmd': ( + 'ResetPreviewSettings', + ) + }, + 'Bandwidth': { + 'Prop': { + 'bandwidthStatus': 'r-' + } + }, + }, + 'General': { + 'Prop': { + 'OperationalWireState': 'r-', + 'ActualStatus': 'r-', + 'DSLMode': 'r-', + 'ReferenceCLK': 'r-' + } + }, + 'Inventory': { + 'Prop': { + 'Inventory': 'r-' + } + } + } + +ifMIB = { + 'Interfaces': { + 'Prop': { + 'IfTable': 'rw' + } + }, + 'IfMIB': { + 'Objects': { + 'Prop': { + 'XTable': 'rw', + 'StackTable': 'rw' + } + + } + } + } diff --git a/vendors/KeyMile/accessPoints/root/unit/port/chan/chanCommandProcessor.py b/vendors/KeyMile/accessPoints/root/unit/port/chan/chanCommandProcessor.py new file mode 100644 index 0000000..bcfc07d --- /dev/null +++ b/vendors/KeyMile/accessPoints/root/unit/port/chan/chanCommandProcessor.py @@ -0,0 +1,242 @@ +# This file is part of the NESi software. +# +# Copyright (c) 2020 +# Original Software Design by Ilya Etingof . +# +# Software adapted by inexio . +# - Janis Groß +# - Philip Konrath +# - Alexander Dincher +# +# License: https://github.com/inexio/NESi/LICENSE.rst + +from nesi import exceptions +from vendors.KeyMile.baseCommandProcessor import BaseCommandProcessor + + +class ChanCommandProcessor(BaseCommandProcessor): + __name__ = 'chan' + management_functions = ('main', 'cfgm', 'fm', 'pm', 'status') + access_points = () + + from .chanManagementFunctions import main + from .chanManagementFunctions import cfgm + from .chanManagementFunctions import fm + from .chanManagementFunctions import pm + from .chanManagementFunctions import status + + def _init_access_points(self, context=None): + self.access_points = () + chan = self.get_component() + card = self._model.get_card('name', self.component_name.split('/')[0]) + + for interface in self._model.get_interfaces('chan_id', chan.id): + if interface.chan_id is not None: + if card.product != 'adsl': + ap_name = 'interface-' + else: + ap_name = 'vcc-' + identifier = ap_name + interface.name.split('/')[-1] + if identifier in self.access_points: + continue + self.access_points += (identifier,) + + def do_deletevcc(self, command, *args, context=None): + card = self._model.get_card('name', self._parent._parent.component_name) + if self._validate(args, str) and context['path'].split('/')[-1] == 'cfgm' and card.product == 'adsl': + # all or vcc_id + name, = self._dissect(args, str) + if name == 'all': + chan = self.get_component() + for vcc in self._model.get_interfaces('chan_id', chan.id): + vcc.delete() + elif name.startswith('vcc-'): + id = name.split('-')[1] + try: + vcc = self._model.get_interface('name', self.component_name + '/' + id) + vcc.delete() + except exceptions.SoftboxenError: + raise exceptions.CommandSyntaxError(command=command) + else: + raise exceptions.CommandSyntaxError(command=command) + else: + raise exceptions.CommandSyntaxError(command=command) + + def do_deleteinterface(self, command, *args, context=None): + card = self._model.get_card('name', self._parent._parent.component_name) + if self._validate(args, str) and context['path'].split('/')[-1] == 'cfgm' and card.product != 'adsl' and card.product != 'sdsl': + # all or interface_id + name, = self._dissect(args, str) + if name == 'all': + chan = self.get_component() + for interface in self._model.get_interfaces('chan_id', chan.id): + interface.delete() + elif name.startswith('interface-'): + id = name.split('-')[1] + try: + interface = self._model.get_interface('name', self.component_name + '/' + id) + interface.delete() + except exceptions.SoftboxenError: + raise exceptions.CommandSyntaxError(command=command) + else: + raise exceptions.CommandSyntaxError(command=command) + else: + raise exceptions.CommandSyntaxError(command=command) + + def do_createinterface(self, command, *args, context=None): + scopes = ('login', 'base', 'set') + card = self._model.get_card('name', self._parent._parent.component_name) + if self._validate(args, str) and context['path'].split('/')[-1] == 'cfgm' and 'SUV' in card.board_name: + # vcc profile and vlan profile + vlan_prof, = self._dissect(args, str) + # TODO: Check if profiles := default or profile names + try: + chan = self.get_component() + id = 1 + for interface in self._model.get_interfaces('chan_id', chan.id): + if interface.chan_id is not None: + new_id = int(interface.name[-1]) + 1 + id = new_id if new_id > id else id + try: + name = self.component_name + '/' + str(id) + self._model.get_interface('name', name) + assert False + except exceptions.SoftboxenError as exe: + interf = self._model.add_interface(chan_id=chan.id, vlan_profile=vlan_prof) + context['spacer1'] = self.create_spacers((57,), (str(id),))[0] * ' ' + context['id'] = str(id) + # TODO: Template is unknown + text = self._render('interface_success', *scopes, context=context) + self._write(text) + except AssertionError: + raise exceptions.CommandSyntaxError(command=command) + + except exceptions.SoftboxenError: + raise exceptions.CommandSyntaxError(command=command) + elif self._validate(args, str, str) and context['path'].split('/')[-1] == 'cfgm': + # vcc profile and vlan profile + vlan_prof, vcc_prof = self._dissect(args, str, str) + # TODO: Check if profiles := default or profile names + try: + chan = self.get_component() + id = 1 + for interface in self._model.get_interfaces('chan_id', chan.id): + if interface.chan_id is not None: + new_id = int(interface.name[-1]) + 1 + id = new_id if new_id > id else id + try: + name = self.component_name + '/' + str(id) + self._model.get_interface('name', name) + assert False + except exceptions.SoftboxenError as exe: + interf = self._model.add_interface(chan_id=chan.id, vlan_profile=vlan_prof, + vcc_profile=vcc_prof) + context['spacer1'] = self.create_spacers((57,), (str(id),))[0] * ' ' + context['id'] = str(id) + # TODO: Template is unknown + text = self._render('interface_success', *scopes, context=context) + self._write(text) + except AssertionError: + raise exceptions.CommandSyntaxError(command=command) + + except exceptions.SoftboxenError: + raise exceptions.CommandSyntaxError(command=command) + else: + raise exceptions.CommandSyntaxError(command=command) + + def do_createvcc(self, command, *args, context=None): + scopes = ('login', 'base', 'set') + card = self._model.get_card('name', self._parent._parent.component_name) + if self._validate(args, str, str) and context['path'].split('/')[-1] == 'cfgm' and card.product == 'adsl': + # vcc profile and vlan profile + vcc_prof, vlan_prof = self._dissect(args, str, str) + # TODO: Check if profiles := default or profile names + try: + chan = self.get_component() + id = 1 + for vcc in self._model.get_interfaces('chan_id', chan.id): + if vcc.chan_id is not None: + new_id = int(vcc.name[-1]) + 1 + id = new_id if new_id > id else id + try: + name = self.component_name + '/' + str(id) + self._model.get_interface('name', name) + assert False + except exceptions.SoftboxenError as exe: + vcc = self._model.add_interface(chan_id=chan.id, vcc_profile=vcc_prof, + vlan_profile=vlan_prof) + context['spacer1'] = self.create_spacers((63,), (str(id),))[0] * ' ' + context['id'] = str(id) + # TODO: unknown Template + text = self._render('vcc_success', *scopes, context=context) + self._write(text) + except AssertionError: + raise exceptions.CommandSyntaxError(command=command) + + except exceptions.SoftboxenError: + raise exceptions.CommandSyntaxError(command=command) + else: + raise exceptions.CommandSyntaxError(command=command) + + def set(self, command, *args, context=None): + card = self._model.get_card('name', self._parent._parent.component_name) + if self._validate(args, *()): + exc = exceptions.CommandSyntaxError(command=command) + exc.template = 'syntax_error' + exc.template_scopes = ('login', 'base', 'syntax_errors') + raise exc + elif self._validate(args, 'chanprofile', str) and 'SUV' in card.board_name: + name, = self._dissect(args, 'chanprofile', str) + try: + #TODO: Check if profile with this name exists or default + channel = self.get_component() + channel.set_profile_name(name) + except exceptions.SoftboxenError: + raise exceptions.CommandSyntaxError(command=command) + elif self._validate(args, 'ProfileName', str) and 'SUV' not in card.board_name: + name, = self._dissect(args, 'ProfileName', str) + try: + # TODO: Check if profile with this name exists or default + channel = self.get_component() + channel.set_profile_name(name) + except exceptions.SoftboxenError: + raise exceptions.CommandSyntaxError(command=command) + else: + raise exceptions.CommandSyntaxError(command=command) + + def get_component(self): + return self._model.get_chan('name', self.component_name) + + def get_property(self, command, *args, context=None): + card = self._model.get_card('name', self._parent._parent.component_name) + scopes = ('login', 'base', 'get') + if self._validate(args, *()): + exc = exceptions.CommandSyntaxError(command=command) + exc.template = 'syntax_error' + exc.template_scopes = ('login', 'base', 'syntax_errors') + raise exc + elif self._validate(args, 'Chanprofile') and 'SUV' in card.board_name: + channel = self.get_component() + context['spacer1'] = self.create_spacers((67,), (channel.chan_profile_name,))[0] * ' ' + context['profile_name'] = channel.chan_profile_name + text = self._render('chan_profile', *scopes, context=context) + self._write(text) + elif self._validate(args, 'ProfileName') and 'SUV' not in card.board_name: + channel = self.get_component() + context['spacer1'] = self.create_spacers((67,), (channel.chan_profile_name,))[0] * ' ' + context['profile_name'] = channel.chan_profile_name + text = self._render('chan_profile', *scopes, context=context) + self._write(text) + elif self._validate(args, 'Status') and context['path'].split('/')[-1] == 'status': + channel = self.get_component() + context['spacer1'] = self.create_spacers((67,), (channel.curr_rate_d,))[0] * ' ' + context['spacer2'] = self.create_spacers((67,), (channel.prev_rate_d,))[0] * ' ' + context['spacer3'] = self.create_spacers((67,), (channel.curr_delay_d,))[0] * ' ' + context['spacer4'] = self.create_spacers((67,), (channel.curr_rate_u,))[0] * ' ' + context['spacer5'] = self.create_spacers((67,), (channel.prev_rate_u,))[0] * ' ' + context['spacer6'] = self.create_spacers((67,), (channel.curr_delay_u,))[0] * ' ' + text = self._render('status', *scopes, context=dict(context, channel=channel)) + self._write(text) + else: + raise exceptions.CommandExecutionError(command=command, template='invalid_property', + template_scopes=('login', 'base', 'execution_errors')) diff --git a/vendors/KeyMile/accessPoints/root/unit/port/chan/chanManagementFunctions.py b/vendors/KeyMile/accessPoints/root/unit/port/chan/chanManagementFunctions.py new file mode 100644 index 0000000..ab83570 --- /dev/null +++ b/vendors/KeyMile/accessPoints/root/unit/port/chan/chanManagementFunctions.py @@ -0,0 +1,100 @@ +main = { + 'General': { + 'Prop': { + 'Labels': 'rw', + 'AlarmStatus': 'r-' + } + } +} + +cfgm = { + 'Profile': { + 'Prop': { + 'ChanProfile': 'rw' + } + }, + 'subinterface': { + 'Cmd': ( + 'CreateInterface', + 'DeleteInterface' + ) + } +} + +fm = { + 'Status': { + 'Prop': { + 'AlarmStatus': 'r-' + }, + 'Cmd': ( + 'Acknowledge', + ) + }, + 'Configuration': { + 'Prop': { + 'AlarmConfiguration': 'rw' + } + } +} + +pm = { + 'PerformanceMonitoring': { + 'Cmd': ( + 'UserCounter', + 'GetHistory15min', + 'GetHistory24h', + 'GetAlarm15min', + 'GetAlarm24hRecursive', + 'ResetUserCounter', + 'ResetAlarm15min', + 'ResetAlarm24h' + ) + }, + 'UserCounter': { + 'Prop': { + 'UserCounterDisplayMode': 'rw', + 'UserCounterTable': 'r-' + }, + 'Cmd': ( + 'UserCounterReset', + ) + }, + 'History15min': { + 'Prop': { + 'History15minDisplayMode': 'rw', + 'History15minTable': 'r-' + } + }, + 'History24h': { + 'Prop': { + 'History24hDisplayMode': 'rw', + 'History24hTable': 'r-' + } + }, + 'Alarm15min': { + 'Prop': { + 'Alarm15minDisplayMode': 'rw', + 'Alarm15minTable': 'r-' + }, + 'Cmd': ( + 'Alarm15minReset', + ) + }, + 'Alarm24h': { + 'Prop': { + 'Alarm24hDisplayMode': 'rw', + 'Alarm24hTable': 'r-' + }, + 'Cmd': ( + 'Alarm24hReset', + ) + } +} + +status = { + 'General': { + 'Prop': { + 'Status': 'r-' + } + } +} diff --git a/vendors/KeyMile/accessPoints/root/unit/port/interface/interfaceCommandProcessor.py b/vendors/KeyMile/accessPoints/root/unit/port/interface/interfaceCommandProcessor.py new file mode 100644 index 0000000..012f532 --- /dev/null +++ b/vendors/KeyMile/accessPoints/root/unit/port/interface/interfaceCommandProcessor.py @@ -0,0 +1,71 @@ +# This file is part of the NESi software. +# +# Copyright (c) 2020 +# Original Software Design by Ilya Etingof . +# +# Software adapted by inexio . +# - Janis Groß +# - Philip Konrath +# - Alexander Dincher +# +# License: https://github.com/inexio/NESi/LICENSE.rst + +from nesi import exceptions +from vendors.KeyMile.baseCommandProcessor import BaseCommandProcessor + + +class InterfaceCommandProcessor(BaseCommandProcessor): + __name__ = 'interface' + management_functions = ('main', 'cfgm', 'pm', 'status') + access_points = () + + from .interfaceManagementFunctions import main + from .interfaceManagementFunctions import cfgm + from .interfaceManagementFunctions import pm + from .interfaceManagementFunctions import status + + def set(self, command, *args, context=None): + if self._validate(args, *()): + exc = exceptions.CommandSyntaxError(command=command) + exc.template = 'syntax_error' + exc.template_scopes = ('login', 'base', 'syntax_errors') + raise exc + else: + raise exceptions.CommandSyntaxError(command=command) + + def get_component(self): + return self._model.get_interface('name', self.component_name) + + def get_property(self, command, *args, context=None): + scopes = ('login', 'base', 'get') + if self._validate(args, *()): + exc = exceptions.CommandSyntaxError(command=command) + exc.template = 'syntax_error' + exc.template_scopes = ('login', 'base', 'syntax_errors') + raise exc + elif self._validate(args, 'ServiceStatus') and context['path'].split('/')[-1] == 'status': + vcc = self.get_component() + context['spacer1'] = self.create_spacers((67,), (vcc.vcc_profile,))[0] * ' ' + context['spacer2'] = self.create_spacers((67,), (vcc.vlan_profile,))[0] * ' ' + text = self._render('service_status', *scopes, context=dict(context, vcc=vcc)) + self._write(text) + elif self._validate(args, 'configuredProfiles') and context['path'].split('/')[-1] == 'cfgm': + vcc = self.get_component() + services_connected = '"' + vcc.services_connected + '"' + context['vcc_services_connected'] = services_connected + context['spacer1'] = self.create_spacers((67,), (vcc.number_of_conn_services,))[0] * ' ' + context['spacer2'] = self.create_spacers((67,), (vcc.reconfiguration_allowed,))[0] * ' ' + context['spacer3'] = self.create_spacers((67,), (services_connected,))[0] * ' ' + text = self._render('configured_profiles', *scopes, context=dict(context, vcc=vcc)) + self._write(text) + elif self._validate(args, 'VlanProfile') and context['path'].split('/')[-1] == 'cfgm': + vcc = self.get_component() + context['spacer1'] = self.create_spacers((67,), (vcc.vlan_profile,))[0] * ' ' + text = self._render('vlan_profile', *scopes, context=dict(context, vcc=vcc)) + self._write(text) + elif self._validate(args, 'IfRateLimiting') and context['path'].split('/')[-1] == 'cfgm': + vcc = self.get_component() + text = self._render('if_rate_limiting', *scopes, context=dict(context, vcc=vcc)) + self._write(text) + else: + raise exceptions.CommandSyntaxError(command=command) diff --git a/vendors/KeyMile/accessPoints/root/unit/port/interface/interfaceManagementFunctions.py b/vendors/KeyMile/accessPoints/root/unit/port/interface/interfaceManagementFunctions.py new file mode 100644 index 0000000..9278f33 --- /dev/null +++ b/vendors/KeyMile/accessPoints/root/unit/port/interface/interfaceManagementFunctions.py @@ -0,0 +1,104 @@ +main = { + 'General': { + 'Prop': { + 'Labels': 'rw', + 'AlarmStatus': 'r-' + } + } +} + +cfgm = { + 'Traceability': { + 'Prop': { + 'AutomaticAgentCircuitId': 'rw', + 'AgentCircuitId': 'rw' + } + }, + 'Filter': { + 'Prop': { + 'MACSourceFilteringMode': 'rw', + 'MacAccessWhitelist': 'rw', + 'NumberOfMacForFloodingPrev': 'rw', + 'L2CPFilter': 'rw', + 'DestMacBlacklistProfile': 'rw', + 'SrcMacBlacklist': 'rw' + } + }, + 'IfRateLimiter': { + 'Prop': { + 'IfRateLimiting': 'rw' + } + }, + 'Profiles': { + 'Prop': { + 'configuredProfiles': 'rw' + } + } +} + +pm = { + 'PerformanceMonitoring': { + 'Cmd': ( + 'UserCounter', + 'GetHistory15min', + 'GetHistory24h', + 'GetAlarm15min', + 'GetAlarm24hRecursive', + 'ResetUserCounter', + 'ResetAlarm15min', + 'ResetAlarm24h' + ) + }, + 'UserCounter': { + 'Prop': { + 'UserCounterDisplayMode': 'rw', + 'UserCounterTable': 'r-' + }, + 'Cmd': ( + 'UserCounterReset', + ) + }, + 'History15min': { + 'Prop': { + 'History15minDisplayMode': 'rw', + 'History15minTable': 'r-' + } + }, + 'History24h': { + 'Prop': { + 'History24hDisplayMode': 'rw', + 'History24hTable': 'r-' + } + }, + 'Alarm15min': { + 'Prop': { + 'Alarm15minDisplayMode': 'rw', + 'Alarm15minTable': 'r-' + }, + 'Cmd': ( + 'Alarm15minReset', + ) + }, + 'Alarm24h': { + 'Prop': { + 'Alarm24hDisplayMode': 'rw', + 'Alarm24hTable': 'r-' + }, + 'Cmd': ( + 'Alarm24hReset', + ) + } +} + +status = { + 'ServiceInfo': { + 'Prop': { + 'ServiceStatus': 'r-' + } + }, + 'UserConnection': { + 'Prop': { + 'CurrentPppConnectionState': 'r-' + } + } +} diff --git a/vendors/KeyMile/accessPoints/root/unit/port/portCommandProcessor.py b/vendors/KeyMile/accessPoints/root/unit/port/portCommandProcessor.py new file mode 100644 index 0000000..7449412 --- /dev/null +++ b/vendors/KeyMile/accessPoints/root/unit/port/portCommandProcessor.py @@ -0,0 +1,410 @@ +# This file is part of the NESi software. +# +# Copyright (c) 2020 +# Original Software Design by Ilya Etingof . +# +# Software adapted by inexio . +# - Janis Groß +# - Philip Konrath +# - Alexander Dincher +# +# License: https://github.com/inexio/NESi/LICENSE.rst + +from nesi import exceptions +from vendors.KeyMile.baseCommandProcessor import BaseCommandProcessor +import time + + +class PortCommandProcessor(BaseCommandProcessor): + __name__ = 'port' + management_functions = ('main', 'cfgm', 'fm', 'pm', 'status') + access_points = () + + from .portManagementFunctions import main + from .portManagementFunctions import cfgm + from .portManagementFunctions import fm + from .portManagementFunctions import pm + from .portManagementFunctions import status + + def get_property(self, command, *args, context=None): + port = self.get_component() + context['port'] = port + card = self._model.get_card('name', self.component_name.split('/')[0]) + scopes = ('login', 'base', 'get') + if self._validate(args, *()): + exc = exceptions.CommandSyntaxError(command=command) + exc.template = 'syntax_error' + exc.template_scopes = ('login', 'base', 'syntax_errors') + raise exc + + elif self._validate(args, 'Portprofile') and context['path'].split('/')[-1] == 'cfgm' and 'SUVM'\ + not in card.board_name and 'SUVD2' not in card.board_name and self.__name__ == 'port': + context['spacer1'] = self.create_spacers((67,), (port.profile1_name,))[0] * ' ' + context['profile_name'] = port.profile1_name + text = self._render('port_profile', *scopes, context=context) + self._write(text) + elif self._validate(args, 'Portprofiles') and context['path'].split('/')[-1] == 'cfgm' and \ + 'SUVD2' in card.board_name and self.__name__ == 'port': + context['spacer1'] = self.create_spacers((67,), (port.profile1_name,))[0] * ' ' + context['profile_name'] = port.profile1_name + text = self._render('port_profile', *scopes, context=context) + self._write(text) + elif self._validate(args, 'Portprofiles') and self.__name__ == 'port' and \ + context['path'].split('/')[-1] == 'cfgm' and 'SUVM' in card.board_name: + context['spacer1'] = self.create_spacers((67,), (port.profile1_enable,))[0] * ' ' + context['spacer2'] = self.create_spacers((67,), (port.profile1_name,))[0] * ' ' + context['spacer3'] = self.create_spacers((67,), (port.profile1_elength,))[0] * ' ' + context['spacer4'] = self.create_spacers((67,), (port.profile2_enable,))[0] * ' ' + context['spacer5'] = self.create_spacers((67,), (port.profile2_name,))[0] * ' ' + context['spacer6'] = self.create_spacers((67,), (port.profile2_elength,))[0] * ' ' + context['spacer7'] = self.create_spacers((67,), (port.profile3_enable,))[0] * ' ' + context['spacer8'] = self.create_spacers((67,), (port.profile3_name,))[0] * ' ' + context['spacer9'] = self.create_spacers((67,), (port.profile3_elength,))[0] * ' ' + context['spacer10'] = self.create_spacers((67,), (port.profile4_enable,))[0] * ' ' + context['spacer11'] = self.create_spacers((67,), (port.profile4_name,))[0] * ' ' + context['spacer12'] = self.create_spacers((67,), (port.profile_mode,))[0] * ' ' + text = self._render('port_profiles', *scopes, context=dict(context, port=port)) + self._write(text) + elif self._validate((args[0],), 'AttainableRate') and context['path'].split('/')[-1] == 'status': + context['spacer1'] = self.create_spacers((67,), (port.downstream,))[0] * ' ' + context['spacer2'] = self.create_spacers((67,), (port.upstream,))[0] * ' ' + text = self._render('attainable_rate', *scopes, context=dict(context, port=port)) + self._write(text) + elif self._validate((args[0],), 'PortMacStatus') and context['path'].split('/')[-1] == 'status' and \ + card.product == 'ftth': + text = self._render('port_mac_status', *scopes, context=context) + self._write(text) + elif self._validate((args[0],), 'DDMStatus') and context['path'].split('/')[-1] == 'status' and \ + card.product == 'ftth': + text = self._render('ddm_status', *scopes, context=context) + self._write(text) + elif self._validate((args[0],), 'PortGeneralStatus') and context['path'].split('/')[-1] == 'status' and \ + card.product == 'ftth': + text = self._render('port_general_status', *scopes, context=context) + self._write(text) + elif self._validate((args[0],), 'VendorId') and context['path'].split('/')[-1] == 'status': + text = self._render('vendor_id', *scopes, context=context) + self._write(text) + elif self._validate((args[0],), 'LineActualState') and context['path'].split('/')[-1] == 'status' and \ + card.product == 'sdsl': + text = self._render('line_actual_state', *scopes, context=context) + self._write(text) + elif self._validate((args[0],), 'LineOperationState') and context['path'].split('/')[-1] == 'status' and \ + card.product == 'sdsl': + text = self._render('line_operation_state', *scopes, context=context) + self._write(text) + elif self._validate((args[0],), 'QuickLoopbackTest') and context['path'].split('/')[-1] == 'status'\ + and (card.product == 'isdn' or 'SUI' in card.board_name) and self.__name__ == 'port': + context['spacer'] = self.create_spacers((67,), (port.loopbacktest_state,))[0] * ' ' + context['loopbacktest_state'] = port.loopbacktest_state + text = self._render('quickloopbacktest', *scopes, context=context) + self._write(text) + elif self._validate((args[0],), 'LineTestResults') and context['path'].split('/')[-1] == 'status'\ + and 'SUP' in card.board_name and self.__name__ == 'port': + context['spacer'] = self.create_spacers((67,), (port.linetest_state,))[0] * ' ' + context['test_state'] = port.linetest_state + text = self._render('line_results_device', *scopes, context=context) + self._write(text) + elif self._validate((args[0],), 'MeltResults') and context['path'].split('/')[-1] == 'status'\ + and card.product != 'isdn' and self.__name__ == 'port': + context['spacer'] = self.create_spacers((67,), (port.melttest_state,))[0] * ' ' + context['test_state'] = port.melttest_state + text = self._render('melt_results_device', *scopes, context=context) + self._write(text) + elif self._validate((args[0],), 'AdministrativeStatus') and context['path'].split('/')[-1] == 'main': + self.map_states(port, 'port') + context['spacer'] = self.create_spacers((67,), (port.admin_state,))[0] * ' ' + text = self._render('administrative_status', *scopes, context=dict(context, port=port)) + self._write(text) + elif self._validate(args, 'Labels') and context['path'].split('/')[-1] == 'main': + context['spacer1'] = self.create_spacers((67,), (port.label1,))[0] * ' ' + context['spacer2'] = self.create_spacers((67,), (port.label2,))[0] * ' ' + context['spacer3'] = self.create_spacers((67,), (port.description,))[0] * ' ' + text = self._render('labels', *scopes, context=dict(context, port=port)) + self._write(text) + elif self._validate(args, 'UnicastList') and context['path'].split('/')[-1] == 'status': + port = self.get_component() + try: + chan = self._model.get_chan('port_id', port.id) + self._model.get_interface('chan_id', chan.id) + except exceptions.InvalidInputError: + text = self._render('unicast_list_empty', *scopes, context=context) + else: + text = self._render('unicast_list', *scopes, context=context) # where does the templates mac-address come from + self._write(text) + elif self._validate((args[0],), 'OperationalStatus') and context['path'].split('/')[-1] == 'main': + self.map_states(port, 'port') + port_operational_state = port.operational_state + context['port_operational_state'] = port_operational_state + context['spacer'] = self.create_spacers((67,), (port_operational_state,))[0] * ' ' + text = self._render('operational_status', *scopes, context=context) + self._write(text) + else: + raise exceptions.CommandExecutionError(command=command, template='invalid_property', + template_scopes=('login', 'base', 'execution_errors')) + + def _init_access_points(self, context=None): + self.access_points = () + port = self.get_component() + + for chan in self._model.get_chans('port_id', port.id): + identifier = 'chan-' + chan.name.split('/')[-1] + if identifier in self.access_points: + continue + self.access_points += (identifier,) + + for interface in self._model.get_interfaces('port_id', port.id): + identifier = 'interface-' + interface.name.split('/')[-1] + if identifier in self.access_points: + continue + self.access_points += (identifier,) + + def _init_context(self, context=None): + port = self.get_component() + card = self._model.get_card('id', port.card_id) + if card.product == 'vdsl' or card.product == 'xdsl': + context['ls_Name'] = 'VDSL' + context['ls_MainMode'] = 'VDSL2' + elif card.product == 'sdsl': + context['ls_Name'] = 'SHDSL' + context['ls_MainMode'] = '' + elif card.product == 'adsl': + context['ls_Name'] = 'ADSL' + context['ls_MainMode'] = '' + elif card.product == 'isdn': + context['ls_Name'] = 'ISDN' + context['ls_MainMode'] = 'BA' + elif card.product == 'analog': + context['ls_Name'] = 'PSTN' + context['ls_MainMode'] = '' + elif card.product == 'ftth': + context['ls_Name'] = '100/1000Base-BX10 cSFP' + context['ls_MainMode'] = '' + else: + context['ls_Name'] = '' + context['ls_MainMode'] = '' + context['ls_EquipmentState'] = '' + + def do_lock(self, command, *args, context=None): + card = self._model.get_card('name', self.component_name.split('/')[0]) + if len(args) == 0 and context['path'].split('/')[-1] == 'status' and (card.board_name.startswith('SUP') or card.board_name.startswith('SUI')) and self.__name__ == 'port': + try: + port = self.get_component() + port.lock_admin() + except exceptions.SoftboxenError: + raise exceptions.CommandSyntaxError(command=command) + else: + raise exceptions.CommandSyntaxError(command=command) + + def do_startquickloopbacktest(self, command, *args, context=None): + card = self._model.get_card('name', self.component_name.split('/')[0]) + if len(args) == 0 and context['path'].split('/')[-1] == 'status' and card.board_name.startswith('SUI') \ + and self.__name__ == 'port': + try: + port = self.get_component() + port.set_test_state('Running') + time.sleep(5) + port.set_test_state('Passed') + except exceptions.SoftboxenError: + raise exceptions.CommandSyntaxError(command=command) + else: + raise exceptions.CommandSyntaxError(command=command) + + def do_startlinetest(self, command, *args, context=None): + card = self._model.get_card('name', self.component_name.split('/')[0]) + if len(args) == 0 and context['path'].split('/')[-1] == 'status' and 'SUP' in card.board_name \ + and self.__name__ == 'port': + try: + port = self.get_component() + port.set_test_state('Running') + time.sleep(5) + port.set_linetest_state('Passed') + except exceptions.SoftboxenError: + raise exceptions.CommandSyntaxError(command=command) + else: + raise exceptions.CommandSyntaxError(command=command) + + def do_startmeltmeasurement(self, command, *args, context=None): + card = self._model.get_card('name', self.component_name.split('/')[0]) + if len(args) == 0 and context['path'].split('/')[-1] == 'status' and card.product != 'isdn' \ + and self.__name__ == 'port': + try: + port = self.get_component() + port.set_melttest_state('Running') + time.sleep(5) + port.set_melttest_state('Passed') + except exceptions.SoftboxenError: + raise exceptions.CommandSyntaxError(command=command) + else: + raise exceptions.CommandSyntaxError(command=command) + + def do_unlock(self, command, *args, context=None): + card = self._model.get_card('name', self.component_name.split('/')[0]) + if len(args) == 0 and context['path'].split('/')[-1] == 'status' and (card.board_name.startswith('SUP') or card.board_name.startswith('SUI')) and self.__name__ == 'port': + try: + port = self.get_component() + port.unlock_admin() + except exceptions.SoftboxenError: + raise exceptions.CommandSyntaxError(command=command) + else: + raise exceptions.CommandSyntaxError(command=command) + + def do_deleteinterface(self, command, *args, context=None): + card = self._model.get_card('name', self.component_name.split('/')[0]) + if self._validate(args, str) and context['path'].split('/')[-1] == 'cfgm' and card.product == 'ftth': + # all or interface_id + name, = self._dissect(args, str) + if name == 'all': + port = self.get_component() + for interface in self._model.get_interfaces('port_id', port.id): + interface.delete() + elif name.startswith('interface-'): + id = name.split('-')[1] + try: + interface = self._model.get_interface('name', self.component_name + '/' + id) + interface.delete() + except exceptions.SoftboxenError: + raise exceptions.CommandSyntaxError(command=command) + else: + raise exceptions.CommandSyntaxError(command=command) + else: + raise exceptions.CommandSyntaxError(command=command) + + def do_createinterface(self, command, *args, context=None): + scopes = ('login', 'base', 'set') + card = self._model.get_card('name', self.component_name.split('/')[0]) + if self._validate(args, str) and context['path'].split('/')[-1] == 'cfgm' and 'SUE' in card.board_name: + # vcc profile and vlan profile + vlan_prof, = self._dissect(args, str) + # TODO: Check if profiles := default or profile names + try: + port = self.get_component() + id = 1 + for interface in self._model.get_interfaces('port_id', port.id): + if interface.port_id is not None: + new_id = int(interface.name[-1]) + 1 + id = new_id if new_id > id else id + try: + name = self.component_name + '/' + str(id) + self._model.get_interface('name', name) + assert False + except exceptions.SoftboxenError as exe: + interf = self._model.add_interface(port_id=port.id, vlan_profile=vlan_prof) + context['spacer1'] = self.create_spacers((57,), (str(id),))[0] * ' ' + context['id'] = str(id) + # TODO: unknown Template + text = self._render('interface_success', *scopes, context=context) + self._write(text) + except AssertionError: + raise exceptions.CommandSyntaxError(command=command) + + except exceptions.SoftboxenError: + raise exceptions.CommandSyntaxError(command=command) + else: + raise exceptions.CommandSyntaxError(command=command) + + def get_component(self): + return self._model.get_port('name', self.component_name) + + def set(self, command, *args, context=None): + scopes = ('login', 'base', 'set') + card = self._model.get_card('name', self.component_name.split('/')[0]) + if self._validate(args, *()): + exc = exceptions.CommandSyntaxError(command=command) + exc.template = 'syntax_error' + exc.template_scopes = ('login', 'base', 'syntax_errors') + raise exc + elif self._validate(args, 'Portprofile', str) and context['path'].split('/')[-1] == 'cfgm' and 'SUVM'\ + not in card.board_name and 'SUVD2' not in card.board_name and self.__name__ == 'port': + profile, = self._dissect(args, 'Portprofile', str) + try: + port = self.get_component() + port.set_profile(profile) + + except exceptions.SoftboxenError: + raise exceptions.CommandExecutionError(command=command, template='invalid_property', + template_scopes=('login', 'base', 'execution_errors')) + elif self._validate(args, 'Portprofiles', str) and context['path'].split('/')[-1] == 'cfgm' and \ + 'SUVD2' in card.board_name and self.__name__ == 'port': + profile, = self._dissect(args, 'Portprofiles', str) + try: + port = self.get_component() + port.set_profile(profile) + + except exceptions.SoftboxenError: + raise exceptions.CommandExecutionError(command=command, template='invalid_property', + template_scopes=('login', 'base', 'execution_errors')) + elif self._validate(args, 'Portprofiles', str, str, str, str, str, str, str, str, str, str, str, str) and \ + context['path'].split('/')[-1] == 'cfgm' and 'SUVM' in card.board_name and self.__name__ == 'port': + en1, name1, elen1, en2, name2, elen2, en3, name3, elen3, en4, name4, mode = self._dissect(args, + 'Portprofiles', str, str, str, str, str, str, str, str, str, str, str, str) + try: + port = self.get_component() + en1 = True if en1.lower() == 'true' else False + en2 = True if en2.lower() == 'true' else False + en3 = True if en3.lower() == 'true' else False + en4 = True if en4.lower() == 'true' else False + port.set_profiles(en1, name1, int(elen1), en2, name2, int(elen2), en3, name3, int(elen3), en4, name4, mode) + + except exceptions.SoftboxenError: + raise exceptions.CommandExecutionError(command=command, template='invalid_property', + template_scopes=('login', 'base', 'execution_errors')) + elif self._validate(args, 'AdministrativeStatus', str) and context['path'].split('/')[-1] == 'main': + state, = self._dissect(args, 'AdministrativeStatus', str) + try: + port = self.get_component() + if state == 'up': + port.admin_up() + elif state == 'down': + port.admin_down() + else: + raise exceptions.SoftboxenError() + except exceptions.SoftboxenError: + raise exceptions.CommandExecutionError(command=command, template='invalid_property', + template_scopes=('login', 'base', 'execution_errors')) + elif self._validate(self.args_in_quotes_joiner(args=args), 'Labels', str, str, str) and context['path'].split('/')[-1] == 'main': + label1, label2, description = self._dissect(self.args_in_quotes_joiner(args=args), 'Labels', str, str, str) + try: + port = self.get_component() + port.set_label(label1, label2, description) + except exceptions.SoftboxenError: + raise exceptions.CommandExecutionError(command=command, template='invalid_property', + template_scopes=('login', 'base', 'execution_errors')) + + elif self._validate(args, 'Mode', str) and context['path'].split('/')[-1] == 'cfgm' and "SUE" in \ + card.board_name and self.__name__ == 'port' and card.product == 'ftth': + if '"' in args[1]: + _, mode = self.args_in_quotes_joiner(args=args) + else: + mode, = self._dissect(args, 'Mode', str) + try: + port = self.get_component() + port.set_mode(mode) + except exceptions.SoftboxenError: + raise exceptions.CommandExecutionError(command=command, template='invalid_property', + template_scopes=('login', 'base', 'execution_errors')) + + elif self._validate(args, 'Mode', str, str, str) and context['path'].split('/')[-1] == 'cfgm' and "SUE" in \ + card.board_name and self.__name__ == 'port' and card.product == 'ftth': + if '"' in args[1]: + _, mode = self.args_in_quotes_joiner(args=args) + else: + mode, = self._dissect(args, 'Mode', str) + try: + port = self.get_component() + port.set_mode(mode) + except exceptions.SoftboxenError: + raise exceptions.CommandExecutionError(command=command, template='invalid_property', + template_scopes=('login', 'base', 'execution_errors')) + + elif self._validate(args, 'FlowControl', str) and context['path'].split('/')[-1] == 'cfgm' and "SUE" in \ + card.board_name and self.__name__ == 'port' and card.product == 'ftth': + ctrl, = self._dissect(args, 'FlowControl', str) + try: + port = self.get_component() + port.set_flow_control(ctrl) + except exceptions.SoftboxenError: + raise exceptions.CommandExecutionError(command=command, template='invalid_property', + template_scopes=('login', 'base', 'execution_errors')) + else: + raise exceptions.CommandSyntaxError(command=command) diff --git a/vendors/KeyMile/accessPoints/root/unit/port/portManagementFunctions.py b/vendors/KeyMile/accessPoints/root/unit/port/portManagementFunctions.py new file mode 100644 index 0000000..9529dba --- /dev/null +++ b/vendors/KeyMile/accessPoints/root/unit/port/portManagementFunctions.py @@ -0,0 +1,334 @@ +main = { + 'General': { + 'Prop': { + 'Labels': 'rw', + 'AlarmStatus': 'r-' + } + }, + 'AdminAndOperStatus': { + 'Prop': { + 'AdministrativeStatus': 'rw', + 'OperationalStatus': 'r-' + } + } +} + +cfgm = { + 'Multicast': { + 'Prop': { + 'MaxNumberOfMulticastStreams': 'rw', + 'EnableIgmpClassifier': 'rw', + 'AllowStaticStreams': 'rw', + 'EnableFastLeave': 'rw', + 'GroupManagement': 'rw', + 'Bandwidth': 'rw' + }, + 'Cmd': ( + 'GetGroupList', + ) + }, + 'Traceability': { + 'Prop': { + 'AgentRemoteId': 'rw' + } + }, + 'Security': { + 'Prop': { + 'ServiceOptions': 'rw', + 'MaxNumberOfMac': 'rw' + } + }, + 'AccessControl': { + 'Prop': { + 'ClassificationKey': 'rw', + 'MAT': 'rw' + } + }, + 'RateLimiter': { + 'Prop': { + 'RateLimiting': 'rw', + 'RateLimitingCoS': 'rw' + } + }, + 'Qos': { + 'Prop': { + 'WfqProfile': 'rw' + } + }, + 'Wire': { + 'Prop': { + 'MeltConfiguration': 'rw' + } + }, + 'Profiles': { + 'Prop': { + 'PortProfiles': 'rw' + } + }, + 'Misc': { + 'Prop': { + 'SpecificDPBO': 'rw', + 'SpecificUPBO': 'rw' + } + } +} + +fm = { + 'Status': { + 'Prop': { + 'AlarmStatus': 'r-' + }, + 'Cmd': ( + 'Acknowledge', + ) + }, + 'Configuration': { + 'Prop': { + 'AlarmConfiguration': 'rw' + } + } +} + +pm = { + 'PerformanceMonitoring': { + 'Cmd': ( + 'UserCounter', + 'GetHistory15min', + 'GetHistory24h', + 'GetAlarm15min', + 'GetAlarm24hRecursive', + 'ResetUserCounter', + 'ResetAlarm15min', + 'ResetAlarm24h' + ) + }, + 'UserCounter': { + 'Prop': { + 'UserCounterDisplayMode': 'rw', + 'UserCounterTable': 'r-' + }, + 'Cmd': ( + 'UserCounterReset', + ) + }, + 'History15min': { + 'Prop': { + 'History15minDisplayMode': 'rw', + 'History15minTable': 'r-' + } + }, + 'History24h': { + 'Prop': { + 'History24hDisplayMode': 'rw', + 'History24hTable': 'r-' + } + }, + 'Alarm15min': { + 'Prop': { + 'Alarm15minDisplayMode': 'rw', + 'Alarm15minTable': 'r-' + }, + 'Cmd': ( + 'Alarm15minReset', + ) + }, + 'Alarm24h': { + 'Prop': { + 'Alarm24hDisplayMode': 'rw', + 'Alarm24hTable': 'r-' + }, + 'Cmd': ( + 'Alarm24hReset', + ) + } +} + +status = { + 'General': { + 'Prop': { + 'Standard': 'r-', + 'PowerMgmStatus': 'r-', + 'Vdsl2Parameters': 'r-', + 'EstUPBOElectricalLength': 'r-', + 'LineRate': 'r-', + 'LineSnrMargin': 'r-', + 'AttainableNetDataRate': 'r-', + 'AttainableRate': 'r-', + 'OutputPower': 'r-', + 'BandStatus': 'r-' + } + }, + 'statistics': { + 'Prop': { + 'counters': 'r-', + 'PolicingCounters': 'r-' + }, + 'Cmd': ( + 'ResetPortCounters', + ) + }, + 'Nto1MacAccessDynamicList': { + 'Prop': { + 'UnicastList': 'r-' + } + }, + 'HostPortStatistics': { + 'GeneralCounters': { + 'Prop': { + 'GeneralList': 'r-' + }, + 'Cmd': ( + 'ResetGeneralCounters', + ) + }, + 'ProtocolCounters': { + 'IgmpCounters': { + 'Prop': { + 'IgmpProtocolList': 'r-' + }, + 'Cmd': ( + 'ResetIgmpCounters', + ) + }, + 'DhcpCounters': { + 'Prop': { + 'DhcpProtocolList': 'r-' + }, + 'Cmd': ( + 'ResetDhcpCounters', + ) + }, + 'ArpCounters': { + 'Prop': { + 'ArpProtocolList': 'r-' + }, + 'Cmd': ( + 'ResetArpCounters', + ) + }, + 'PPPoECounters': { + 'Prop': { + 'PPPoEProtocolList': 'r-' + }, + 'Cmd': ( + 'ResetPPPoECounters', + ) + }, + 'UnknownSourceMACCounters': { + 'Prop': { + 'UnknownSrcMACProtocolList': 'r-' + }, + 'Cmd': ( + 'ResetUnknownSrcMACCounters', + ) + }, + }, + }, + 'TLSMacForwardingList': { + 'Prop': { + 'MacForwardingList': 'r-' + }, + 'Cmd': ( + 'FlushMacForwardingList', + ) + }, + '1to1MacForwardingList': { + 'Prop': { + 'One2OneMacForwardingList': 'r-' + } + }, + 'Qos': { + 'Prop': { + 'wfqueues': 'r-' + } + }, + 'Multicast': { + 'stream': { + 'Dynamic': { + 'Prop': { + 'ActiveStreams': 'r-' + }, + 'Cmd': ( + 'ClearActiveStreams', + ) + }, + 'Static': { + 'Prop': { + 'StaticStreams': 'r-' + } + }, + }, + + 'Vlan': { + 'Prop': { + 'AttachedVlans': 'r-' + } + }, + 'Preview': { + 'Cmd': ( + 'ResetPreviewSettings', + ) + }, + 'Bandwidth': { + 'Prop': { + 'bandwidthStatus': 'r-' + } + }, + }, + 'LineTest': { + 'MELT': { + 'Prop': { + 'MeltResults': 'r-' + }, + 'Cmd': ( + 'StartMeltMeasurement', + ) + }, + 'Delt': { + 'Prop': { + 'DeltMeasurementStatus': 'r-', + 'RecordedDeltMeasurements': 'r-' + }, + 'Cmd': ( + 'StartDeltMeasurement', + ) + }, + 'Selt': { + 'Prop': { + 'SeltMeasurementStatus': 'r-', + 'RecordedSeltMeasurements': 'r-', + 'CableType': 'rw', + 'BandplanProfile': 'rw', + 'TargetSnrm': 'rw' + }, + 'Cmd': ( + 'StartSeltMeasurement', + ) + }, + }, + 'Defects': { + 'Prop': { + 'Defects': 'r-' + } + }, + 'LineInventory': { + 'Prop': { + 'VendorId': 'r-' + } + }, + 'Maintenance': { + 'Prop': { + 'DslOperationStatus': 'r-' + } + }, + 'Subcarrier': { + 'Cmd': ( + 'ShowBitAllocation', + ) + }, + 'RfiBands': { + 'Prop': { + 'NotchStatus': 'r-' + } + } +} diff --git a/vendors/KeyMile/accessPoints/root/unit/portgroup/port/portgroupportCommandProcessor.py b/vendors/KeyMile/accessPoints/root/unit/portgroup/port/portgroupportCommandProcessor.py new file mode 100644 index 0000000..126721d --- /dev/null +++ b/vendors/KeyMile/accessPoints/root/unit/portgroup/port/portgroupportCommandProcessor.py @@ -0,0 +1,192 @@ +# This file is part of the NESi software. +# +# Copyright (c) 2020 +# Original Software Design by Ilya Etingof . +# +# Software adapted by inexio . +# - Janis Groß +# - Philip Konrath +# - Alexander Dincher +# +# License: https://github.com/inexio/NESi/LICENSE.rst + +from nesi import exceptions +from vendors.KeyMile.accessPoints.root.unit.port.portCommandProcessor import PortCommandProcessor + + +class PortgroupportCommandProcessor(PortCommandProcessor): + __name__ = 'portgroupport' + management_functions = ('main', 'cfgm', 'status') + access_points = () + + from .portgroupportManagementFunctions import main + from .portgroupportManagementFunctions import cfgm + from .portgroupportManagementFunctions import status + + def get_component(self): + return self._model.get_portgroupport('name', self.component_name) + + def get_property(self, command, *args, context=None): + port = self.get_component() + scopes = ('login', 'base', 'get') + try: + super().get_property(command, *args, context=context) + except exceptions.CommandExecutionError: + if self._validate((args[0],), 'SubscriberList') and context['path'].split('/')[-1] == 'status' and \ + self._model.get_card('name', self._parent._parent.component_name).product in ('isdn', 'analog'): + text = self._render('subscriberList_top', *scopes, context=context) + i = 0 + for subscriber in self._model.get_subscribers('portgroupport_id', port.id): + + context['i'] = i + context['spacer1'] = self.create_spacers((63,), (subscriber.number,))[0] * ' ' + context['spacer2'] = self.create_spacers((63,), (subscriber.registration_state,))[0] * ' ' + i += 1 + text += self._render('subscriberList_item2', *scopes, + context=dict(context, subscriber=subscriber)) + text += self._render('subscriberList_bottom', *scopes, context=context) + + self._write(text) + elif self._validate((args[0],), 'Isdnport') and context['path'].split('/')[-1] == 'cfgm' and \ + port.type == 'ISDN': + context['spacer1'] = self.create_spacers((67,), (port.enable,))[0] * ' ' + context['spacer2'] = self.create_spacers((67,), (port.register_as_global,))[0] * ' ' + context['spacer3'] = self.create_spacers((67,), (port.register_default_number_only,))[0] * ' ' + context['spacer4'] = self.create_spacers((67,), (port.sip_profile,))[0] * ' ' + context['spacer5'] = self.create_spacers((67,), (port.proxy_registrar_profile,))[0] * ' ' + context['spacer6'] = self.create_spacers((67,), (port.codec_sdp_profile,))[0] * ' ' + context['spacer7'] = self.create_spacers((67,), (port.isdnba_profile,))[0] * ' ' + context['spacer8'] = self.create_spacers((67,), (port.layer_1_permanently_activated,))[0] * ' ' + text = self._render('isdnport_top', *scopes, context=dict(context, port=port)) + + i = 0 + for subscriber in self._model.get_subscribers('portgroupport_id', port.id): + if subscriber.portgroupport_id == port.id: + context['i'] = i + context['spacer10'] = self.create_spacers((63,), (subscriber.number,))[0] * ' ' + context['spacer11'] = self.create_spacers((63,), (subscriber.autorisation_user_name,))[0] * ' ' + context['spacer12'] = self.create_spacers((63,), (subscriber.autorisation_password,))[0] * ' ' + context['spacer13'] = self.create_spacers((63,), (subscriber.display_name,))[0] * ' ' + context['spacer14'] = self.create_spacers((65,), (subscriber.privacy,))[0] * ' ' + i += 1 + text += self._render('isdnport_middle', *scopes, context=dict(context, subscriber=subscriber)) + + text += self._render('isdnport_bottom', *scopes, context=dict(context, port=port)) + self._write(text) + elif self._validate((args[0],), 'pstnport') and context['path'].split('/')[-1] == 'cfgm' and \ + port.type == 'PSTN': + context['spacer1'] = self.create_spacers((67,), (port.enable,))[0] * ' ' + context['spacer2'] = self.create_spacers((67,), (port.register_as_global,))[0] * ' ' + context['spacer3'] = self.create_spacers((67,), (port.pay_phone,))[0] * ' ' + context['spacer4'] = self.create_spacers((67,), (port.sip_profile,))[0] * ' ' + context['spacer5'] = self.create_spacers((67,), (port.proxy_registrar_profile,))[0] * ' ' + context['spacer6'] = self.create_spacers((67,), (port.codec_sdp_profile,))[0] * ' ' + context['spacer7'] = self.create_spacers((67,), (port.pstn_profile,))[0] * ' ' + context['spacer8'] = self.create_spacers((67,), (port.enterprise_profile,))[0] * ' ' + text = self._render('pstnport_top', *scopes, context=dict(context, port=port)) + + i = 0 + for subscriber in self._model.get_subscribers('portgroupport_id', port.id): + if subscriber.portgroupport_id == port.id: + context['i'] = i + context['spacer10'] = self.create_spacers((63,), (subscriber.number,))[0] * ' ' + context['spacer11'] = self.create_spacers((63,), (subscriber.autorisation_user_name,))[0] * ' ' + context['spacer12'] = self.create_spacers((63,), (subscriber.autorisation_password,))[0] * ' ' + context['spacer13'] = self.create_spacers((63,), (subscriber.display_name,))[0] * ' ' + context['spacer14'] = self.create_spacers((65,), (subscriber.privacy,))[0] * ' ' + i += 1 + text += self._render('pstnport_middle', *scopes, context=dict(context, subscriber=subscriber)) + + text += self._render('pstnport_bottom', *scopes, context=dict(context, port=port)) + self._write(text) + else: + raise exceptions.CommandExecutionError(command=command, template='invalid_property', + template_scopes=('login', 'base', 'execution_errors')) + + def _init_access_points(self, context=None): + pass + + def _init_context(self, context=None): + context['ls_Name'] = 'ISDN-BA' + context['ls_MainMode'] = '' + context['ls_EquipmentState'] = '' + + def do_deleteinterface(self, command, *args, context=None): + raise exceptions.CommandSyntaxError(command=command) + + def do_createinterface(self, command, *args, context=None): + raise exceptions.CommandSyntaxError(command=command) + + def set(self, command, *args, context=None): + scopes = ('login', 'base', 'set') + try: + super().set(command, *args, context=context) + except exceptions.CommandSyntaxError: + if self._validate(args, *()): + exc = exceptions.CommandSyntaxError(command=command) + exc.template = 'syntax_error' + exc.template_scopes = ('login', 'base', 'syntax_errors') + raise exc + elif args[0] in ('pstnport', 'isdnport') and context['path'].split('/')[-1] == 'cfgm': + enable = True if args[1].lower() == 'true' else False + number = None + username = '' + password = '' + displayname = '' + privacy = 'None' + index_end = 2 + if args[2] != '{}': + if args[2].startswith('{') and args[2].endswith('}'): + number = args[2][1:-1] + else: + index_start = args.index('{') + index_end = args.index('}') + number = args[index_start + 1] if index_start + 1 < index_end else None + username = args[index_start + 2] if index_start + 2 < index_end else '' + password = args[index_start + 3] if index_start + 3 < index_end else '' + displayname = args[index_start + 4] if index_start + 4 < index_end else '' + privacy = args[index_start + 5] if index_start + 5 < index_end else 'None' + + register = True if args[index_end + 1].lower() == 'true' else False + + try: + port = self.get_component() + if number is not None: + try: + subscriber = self._model.get_subscriber('number', int(number)) + if username is not None: + subscriber.set('autorisation_user_name', username) + if password is not None: + subscriber.set('autorisation_password', password) + if displayname is not None: + subscriber.set('display_name', displayname) + if privacy is not None: + subscriber.set('privacy', privacy) + except exceptions.SoftboxenError: + address = self.component_name + self._model.add_subscriber(number=int(number), autorisation_user_name=username, + address=address, privacy=privacy, display_name=displayname, + autorisation_password=password, portgroupport_id=port.id) + pass + if args[0] == 'isdnport': + regdefault = True if args[index_end + 2].lower().lower() == 'true' else False + layer1 = True if args[index_end + 3].lower() == 'true' else False + sip = args[index_end + 4] + proxy = args[index_end + 5] + codec = args[index_end + 6] + isdnba = args[index_end + 7] + port.set_isdnport(enable, register, regdefault, layer1, sip, proxy, codec, isdnba) + elif args[0] == 'pstnport': + phone = True if args[index_end + 2].lower() == 'true' else False + sip = args[index_end + 3] + proxy = args[index_end + 4] + codec = args[index_end + 5] + pstn = args[index_end + 6] + enterprise = args[index_end + 7] + port.set_pstnport(enable, register, phone, sip, proxy, codec, pstn, enterprise) + except exceptions.SoftboxenError: + raise exceptions.CommandExecutionError(command=command, template='invalid_property', + template_scopes=('login', 'base', 'execution_errors')) + else: + raise exceptions.CommandExecutionError(command=command, template='invalid_property', + template_scopes=('login', 'base', 'execution_errors')) \ No newline at end of file diff --git a/vendors/KeyMile/accessPoints/root/unit/portgroup/port/portgroupportManagementFunctions.py b/vendors/KeyMile/accessPoints/root/unit/portgroup/port/portgroupportManagementFunctions.py new file mode 100644 index 0000000..5add929 --- /dev/null +++ b/vendors/KeyMile/accessPoints/root/unit/portgroup/port/portgroupportManagementFunctions.py @@ -0,0 +1,264 @@ +main = { + 'General': { + 'Prop': { + 'Labels': 'rw', + 'AlarmStatus': 'r-' + } + }, + 'AdminAndOperStatus': { + 'Prop': { + 'AdministrativeStatus': 'rw', + 'OperationalStatus': 'r-' + } + } +} + +cfgm = { + 'Multicast': { + 'Prop': { + 'MaxNumberOfMulticastStreams': 'rw', + 'EnableIgmpClassifier': 'rw', + 'AllowStaticStreams': 'rw', + 'EnableFastLeave': 'rw', + 'GroupManagement': 'rw', + 'Bandwidth': 'rw' + }, + 'Cmd': ( + 'GetGroupList', + ) + }, + 'Traceability': { + 'Prop': { + 'AgentRemoteId': 'rw' + } + }, + 'Security': { + 'Prop': { + 'ServiceOptions': 'rw', + 'MaxNumberOfMac': 'rw' + } + }, + 'AccessControl': { + 'Prop': { + 'ClassificationKey': 'rw', + 'MAT': 'rw' + } + }, + 'RateLimiter': { + 'Prop': { + 'RateLimiting': 'rw', + 'RateLimitingCoS': 'rw' + } + }, + 'Qos': { + 'Prop': { + 'WfqProfile': 'rw' + } + }, + 'Wire': { + 'Prop': { + 'MeltConfiguration': 'rw' + } + }, + 'Profiles': { + 'Prop': { + 'PortProfiles': 'rw' + } + }, + 'Misc': { + 'Prop': { + 'SpecificDPBO': 'rw', + 'SpecificUPBO': 'rw' + } + } +} + +status = { + 'General': { + 'Prop': { + 'Standard': 'r-', + 'PowerMgmStatus': 'r-', + 'Vdsl2Parameters': 'r-', + 'EstUPBOElectricalLength': 'r-', + 'LineRate': 'r-', + 'LineSnrMargin': 'r-', + 'AttainableNetDataRate': 'r-', + 'AttainableRate': 'r-', + 'OutputPower': 'r-', + 'BandStatus': 'r-' + } + }, + 'statistics': { + 'Prop': { + 'counters': 'r-', + 'PolicingCounters': 'r-' + }, + 'Cmd': ( + 'ResetPortCounters', + ) + }, + 'Nto1MacAccessDynamicList': { + 'Prop': { + 'UnicastList': 'r-' + } + }, + 'HostPortStatistics': { + 'GeneralCounters': { + 'Prop': { + 'GeneralList': 'r-' + }, + 'Cmd': ( + 'ResetGeneralCounters', + ) + }, + 'ProtocolCounters': { + 'IgmpCounters': { + 'Prop': { + 'IgmpProtocolList': 'r-' + }, + 'Cmd': ( + 'ResetIgmpCounters', + ) + }, + 'DhcpCounters': { + 'Prop': { + 'DhcpProtocolList': 'r-' + }, + 'Cmd': ( + 'ResetDhcpCounters', + ) + }, + 'ArpCounters': { + 'Prop': { + 'ArpProtocolList': 'r-' + }, + 'Cmd': ( + 'ResetArpCounters', + ) + }, + 'PPPoECounters': { + 'Prop': { + 'PPPoEProtocolList': 'r-' + }, + 'Cmd': ( + 'ResetPPPoECounters', + ) + }, + 'UnknownSourceMACCounters': { + 'Prop': { + 'UnknownSrcMACProtocolList': 'r-' + }, + 'Cmd': ( + 'ResetUnknownSrcMACCounters', + ) + }, + }, + }, + 'TLSMacForwardingList': { + 'Prop': { + 'MacForwardingList': 'r-' + }, + 'Cmd': ( + 'FlushMacForwardingList', + ) + }, + '1to1MacForwardingList': { + 'Prop': { + 'One2OneMacForwardingList': 'r-' + } + }, + 'Qos': { + 'Prop': { + 'wfqueues': 'r-' + } + }, + 'Multicast': { + 'stream': { + 'Dynamic': { + 'Prop': { + 'ActiveStreams': 'r-' + }, + 'Cmd': ( + 'ClearActiveStreams', + ) + }, + 'Static': { + 'Prop': { + 'StaticStreams': 'r-' + } + }, + }, + + 'Vlan': { + 'Prop': { + 'AttachedVlans': 'r-' + } + }, + 'Preview': { + 'Cmd': ( + 'ResetPreviewSettings', + ) + }, + 'Bandwidth': { + 'Prop': { + 'bandwidthStatus': 'r-' + } + }, + }, + 'LineTest': { + 'MELT': { + 'Prop': { + 'MeltResults': 'r-' + }, + 'Cmd': ( + 'StartMeltMeasurement', + ) + }, + 'Delt': { + 'Prop': { + 'DeltMeasurementStatus': 'r-', + 'RecordedDeltMeasurements': 'r-' + }, + 'Cmd': ( + 'StartDeltMeasurement', + ) + }, + 'Selt': { + 'Prop': { + 'SeltMeasurementStatus': 'r-', + 'RecordedSeltMeasurements': 'r-', + 'CableType': 'rw', + 'BandplanProfile': 'rw', + 'TargetSnrm': 'rw' + }, + 'Cmd': ( + 'StartSeltMeasurement', + ) + }, + }, + 'Defects': { + 'Prop': { + 'Defects': 'r-' + } + }, + 'LineInventory': { + 'Prop': { + 'VendorId': 'r-' + } + }, + 'Maintenance': { + 'Prop': { + 'DslOperationStatus': 'r-' + } + }, + 'Subcarrier': { + 'Cmd': ( + 'ShowBitAllocation', + ) + }, + 'RfiBands': { + 'Prop': { + 'NotchStatus': 'r-' + } + } +} diff --git a/vendors/KeyMile/accessPoints/root/unit/portgroup/portgroupCommandProcessor.py b/vendors/KeyMile/accessPoints/root/unit/portgroup/portgroupCommandProcessor.py new file mode 100644 index 0000000..74fc2e6 --- /dev/null +++ b/vendors/KeyMile/accessPoints/root/unit/portgroup/portgroupCommandProcessor.py @@ -0,0 +1,48 @@ +# This file is part of the NESi software. +# +# Copyright (c) 2020 +# Original Software Design by Ilya Etingof . +# +# Software adapted by inexio . +# - Janis Groß +# - Philip Konrath +# - Alexander Dincher +# +# License: https://github.com/inexio/NESi/LICENSE.rst + +from nesi import exceptions +from vendors.KeyMile.baseCommandProcessor import BaseCommandProcessor + + +class PortgroupCommandProcessor(BaseCommandProcessor): + __name__ = 'portgroup' + management_functions = ('main', 'cfgm') + access_points = () + + from .portgroupManagementFunctions import main + from .portgroupManagementFunctions import cfgm + + def _init_access_points(self, context=None): # work in progress + self.access_points = () + card = self._model.get_card('name', self.component_name.split('/')[0]) + + for gport in self._model.get_portgroupports('card_id', card.id): + if gport.name.split('/')[1] == 'G' + self.component_name.split('/')[-1][1:]: + identifier = 'port-' + gport.name.split('/')[-1] + if identifier in self.access_points: + continue + self.access_points += (identifier,) + + def _init_context(self, context=None): + context['ls_Name'] = 'ISDN-BA' + context['ls_MainMode'] = '16 Ports' + context['ls_EquipmentState'] = '' + + def set(self, command, *args, context=None): + if self._validate(args, *()): + exc = exceptions.CommandSyntaxError(command=command) + exc.template = 'syntax_error' + exc.template_scopes = ('login', 'base', 'syntax_errors') + raise exc + else: + raise exceptions.CommandSyntaxError(command=command) diff --git a/vendors/KeyMile/accessPoints/root/unit/portgroup/portgroupManagementFunctions.py b/vendors/KeyMile/accessPoints/root/unit/portgroup/portgroupManagementFunctions.py new file mode 100644 index 0000000..d281df9 --- /dev/null +++ b/vendors/KeyMile/accessPoints/root/unit/portgroup/portgroupManagementFunctions.py @@ -0,0 +1,17 @@ +main = { + 'General': { + 'Prop': { + 'Labels': 'rw', + 'AlarmStatus': 'r-' + } + } +} + +cfgm = { + 'General': { + 'Cmd': { + 'CreatePort', + 'DeletePort' + } + } +} \ No newline at end of file diff --git a/vendors/KeyMile/accessPoints/root/unit/unitCommandProcessor.py b/vendors/KeyMile/accessPoints/root/unit/unitCommandProcessor.py new file mode 100644 index 0000000..5f4cdc3 --- /dev/null +++ b/vendors/KeyMile/accessPoints/root/unit/unitCommandProcessor.py @@ -0,0 +1,327 @@ +# This file is part of the NESi software. +# +# Copyright (c) 2020 +# Original Software Design by Ilya Etingof . +# +# Software adapted by inexio . +# - Janis Groß +# - Philip Konrath +# - Alexander Dincher +# +# License: https://github.com/inexio/NESi/LICENSE.rst +import time + +from nesi import exceptions +from vendors.KeyMile.baseCommandProcessor import BaseCommandProcessor + + +class UnitCommandProcessor(BaseCommandProcessor): + __name__ = 'unit' + management_functions = ('main', 'fm') + access_points = () # 'internalPorts', only on certain cards + + from .unitManagementFunctions import main + from .unitManagementFunctions import cfgm + from .unitManagementFunctions import fm + from .unitManagementFunctions import status + + def _init_access_points(self, context=None): + self.access_points = () + try: + card = self.get_component() + + self.management_functions = ('main', 'cfgm', 'fm', 'status') + + try: + _ = self._model.get_logport('card_id', card.id) + except exceptions.SoftboxenError: + pass + else: + self.access_points += ('logports',) + + for port in self._model.get_ports('card_id', card.id): + identifier = 'port-' + port.name.split('/')[-1] + if identifier in self.access_points: + continue + self.access_points += (identifier,) + + for gport in self._model.get_portgroupports('card_id', card.id): + identifier = 'portgroup-' + gport.name.split('/')[1][1] + if identifier in self.access_points: + continue + self.access_points += (identifier,) + except exceptions.InvalidInputError: + pass + + def _init_context(self, context=None): + try: + card = self.get_component() + except exceptions.SoftboxenError: + context['ls_Name'] = '' + context['ls_MainMode'] = '' + context['ls_EquipmentState'] = 'Empty' + else: + context['ls_Name'] = card.board_name + ' ' + card.supplier_build_state + context['ls_MainMode'] = card.software[:-4] + context['ls_EquipmentState'] = 'Ok' + + def get_property(self, command, *args, context=None): + try: + card = self.get_component() + except exceptions.InvalidInputError: + if args[0] in ('CurrentStatus', 'EquipmentInventory'): + card = None + else: + raise + scopes = ('login', 'base', 'get') + if self._validate(args, *()): + exc = exceptions.CommandSyntaxError(command=command) + exc.template = 'syntax_error' + exc.template_scopes = ('login', 'base', 'syntax_errors') + raise exc + elif self._validate(args, 'SubscriberList') and context['path'].split('/')[-1] == 'status' and \ + (card.product == 'isdn' or card.product == 'analog'): + text = self._render('subscriberList_top', *scopes, context=context) + i = 0 + for subscriber in self._model.subscribers: + if subscriber.registration_state == 'Unregistered': + context['i'] = i + context['spacer1'] = self.create_spacers((63,), (subscriber.number,))[0] * ' ' + context['spacer2'] = self.create_spacers((63,), (subscriber.registration_state,))[0] * ' ' + context['spacer3'] = self.create_spacers((63,), (subscriber.address,))[0] * ' ' + + i += 1 + text += self._render('subscriberList_item', *scopes, context=dict(context, subscriber=subscriber)) + text += self._render('subscriberList_bottom', *scopes, context=context) + self._write(text) + elif self._validate(args, 'SIP') and context['path'].split('/')[-1] == 'cfgm' and \ + (card.product == 'isdn' or card.product == 'analog'): + context['spacer1'] = self.create_spacers((67,), (card.gateway_name,))[0] * ' ' + context['spacer2'] = self.create_spacers((67,), (card.home_domain,))[0] * ' ' + context['spacer3'] = self.create_spacers((67,), (card.sip_port_number,))[0] * ' ' + context['spacer4'] = self.create_spacers((65,), (card.country_code,))[0] * ' ' + context['spacer5'] = self.create_spacers((65,), (card.area_code,))[0] * ' ' + context['spacer6'] = self.create_spacers((67,), (card.retransmission_timer,))[0] * ' ' + context['spacer7'] = self.create_spacers((67,), (card.max_retransmission_interval,))[0] * ' ' + context['spacer8'] = self.create_spacers((67,), (card.sip_extension,))[0] * ' ' + context['spacer9'] = self.create_spacers((67,), (card.asserted_id_mode,))[0] * ' ' + context['spacer10'] = self.create_spacers((67,), (card.overlap_signalling,))[0] * ' ' + context['spacer11'] = self.create_spacers((67,), (card.overlap_timer,))[0] * ' ' + context['spacer12'] = self.create_spacers((67,), (card.uac_request_timer,))[0] * ' ' + context['spacer13'] = self.create_spacers((67,), (card.uas_request_timer,))[0] * ' ' + context['spacer14'] = self.create_spacers((67,), (card.session_expiration,))[0] * ' ' + text = self._render('sip', *scopes, context=dict(context, card=card)) + self._write(text) + elif self._validate(args, 'Proxy') and context['path'].split('/')[-1] == 'cfgm' and \ + (card.product == 'isdn' or card.product == 'analog'): + context['spacer1'] = self.create_spacers((67,), (card.proxy_mode,))[0] * ' ' + context['spacer2'] = self.create_spacers((67,), (card.proxy_address,))[0] * ' ' + context['spacer3'] = self.create_spacers((67,), (card.proxy_port,))[0] * ' ' + context['spacer4'] = self.create_spacers((67,), (card.proxy_address_sec,))[0] * ' ' + context['spacer5'] = self.create_spacers((67,), (card.proxy_port_sec,))[0] * ' ' + context['spacer6'] = self.create_spacers((67,), (card.proxy_enable,))[0] * ' ' + context['spacer7'] = self.create_spacers((67,), (card.proxy_method,))[0] * ' ' + context['spacer8'] = self.create_spacers((67,), (card.proxy_interval,))[0] * ' ' + text = self._render('proxy', *scopes, context=dict(context, card=card)) + self._write(text) + elif self._validate(args, 'IP') and context['path'].split('/')[-1] == 'cfgm' and \ + (card.product == 'isdn' or card.product == 'analog'): + context['spacer1'] = self.create_spacers((67,), (card.gateway_ipaddress,))[0] * ' ' + context['spacer2'] = self.create_spacers((67,), (card.subnet_mask,))[0] * ' ' + context['spacer3'] = self.create_spacers((67,), (card.default_gateway,))[0] * ' ' + text = self._render('ip', *scopes, context=dict(context, card=card)) + self._write(text) + + elif self._validate(args, 'Labels') and context['path'].split('/')[-1] == 'main': + context['spacer1'] = self.create_spacers((67,), (card.label1,))[0] * ' ' + context['spacer2'] = self.create_spacers((67,), (card.label2,))[0] * ' ' + context['spacer3'] = self.create_spacers((67,), (card.description,))[0] * ' ' + text = self._render('labels', *scopes, context=dict(context, port=card)) + self._write(text) + + elif self._validate(args, 'Registrar') and context['path'].split('/')[-1] == 'cfgm': + context['spacer1'] = self.create_spacers((67,), (card.registrar_adress,))[0] * ' ' + context['spacer2'] = self.create_spacers((67,), (card.registrar_port,))[0] * ' ' + context['spacer3'] = self.create_spacers((67,), (card.registration_mode,))[0] * ' ' + context['spacer4'] = self.create_spacers((67,), (card.registration_expiration_time,))[0] * ' ' + text = self._render('registrar', *scopes, context=dict(context, card=card)) + self._write(text) + + elif self._validate(args, 'HardwareAndSoftware') and context['path'].split('/')[-1] == 'main': + unit_hardware = '"' + card.board_name + '"' + context['unit_hardware'] = unit_hardware + context['spacer_1'] = self.create_spacers((67,), (unit_hardware,))[0] * ' ' + unit_supplier_build_state = '"' + card.supplier_build_state + '"' + context['unit_supplier_build_state'] = unit_supplier_build_state + context['spacer_2'] = self.create_spacers((67,), (unit_supplier_build_state,))[0] * ' ' + unit_board_id = card.board_id + context['unit_board_id'] = unit_board_id + context['spacer_3'] = self.create_spacers((67,), (unit_board_id,))[0] * ' ' + unit_hardware_key = card.hardware_key + context['unit_hardware_key'] = unit_hardware_key + context['spacer_4'] = self.create_spacers((67,), (unit_hardware_key,))[0] * ' ' + unit_software = '"' + card.software + '"' + context['unit_software'] = unit_software + context['spacer_5'] = self.create_spacers((67,), (unit_software,))[0] * ' ' + unit_software_name = '"' + card.software_name + '"' + context['unit_software_name'] = unit_software_name + context['spacer_6'] = self.create_spacers((67,), (unit_software_name,))[0] * ' ' + unit_software_revision = '"' + card.software_revision + '"' + context['unit_software_revision'] = unit_software_revision + context['spacer_7'] = self.create_spacers((67,), (unit_software_revision,))[0] * ' ' + text = self._render('hardware_and_software', *scopes, context=context) + self._write(text) + + elif self._validate(args, 'CurrentStatus') and context['path'].split('/')[-1] == 'main': + if card is None: + text = self._render('current_status_empty', *scopes, context=context) + else: + unit_state = card.state + context['unit_state'] = unit_state + context['spacer_1'] = self.create_spacers((67,), (unit_state,))[0] * ' ' + unit_hardware = '"' + card.board_name + ' ' + card.supplier_build_state + '"' + context['unit_hardware'] = unit_hardware + context['spacer_2'] = self.create_spacers((67,), (unit_hardware,))[0] * ' ' + unit_software = '"' + card.software[:-4] + '"' + context['unit_software'] = unit_software + context['spacer_3'] = self.create_spacers((67,), (unit_software,))[0] * ' ' + unit_serial_number = '"' + card.serial_number + '"' + context['unit_serial_number'] = unit_serial_number + context['spacer_4'] = self.create_spacers((67,), (unit_serial_number,))[0] * ' ' + unit_manufacturer_name = '"' + card.manufacturer_name + '"' + context['unit_manufacturer_name'] = unit_manufacturer_name + context['spacer_5'] = self.create_spacers((67,), (unit_manufacturer_name,))[0] * ' ' + unit_model_name = '"' + card.model_name + '"' + context['unit_model_name'] = unit_model_name + context['spacer_6'] = self.create_spacers((67,), (unit_model_name,))[0] * ' ' + text = self._render('current_status', *scopes, context=context) + + self._write(text) + + elif self._validate(args, 'EquipmentInventory') and context['path'].split('/')[-1] == 'main': + if card is None: + text = self._render('equipment_inventory_empty', *scopes, context=context) + else: + unit_symbol = '"' + card.board_name + '"' + context['unit_symbol'] = unit_symbol + context['spacer_1'] = self.create_spacers((67,), (unit_symbol,))[0] * ' ' + unit_short_text = '"' + card.short_text + '"' + context['unit_short_text'] = unit_short_text + context['spacer_2'] = self.create_spacers((67,), (unit_short_text,))[0] * ' ' + unit_board_id = card.board_id + context['unit_board_id'] = unit_board_id + context['spacer_3'] = self.create_spacers((67,), (unit_board_id,))[0] * ' ' + unit_hardware_key = card.hardware_key + context['unit_hardware_key'] = unit_hardware_key + context['spacer_4'] = self.create_spacers((67,), (unit_hardware_key,))[0] * ' ' + unit_manufacturer_id = '"' + card.manufacturer_id + '"' + context['unit_manufacturer_id'] = unit_manufacturer_id + context['spacer_5'] = self.create_spacers((67,), (unit_manufacturer_id,))[0] * ' ' + unit_serial_number = '"' + card.serial_number + '"' + context['unit_serial_number'] = unit_serial_number + context['spacer_6'] = self.create_spacers((67,), (unit_serial_number,))[0] * ' ' + unit_manufacturer_part_number = '"' + card.manufacturer_part_number + '"' + context['unit_manufacturer_part_number'] = unit_manufacturer_part_number + context['spacer_7'] = self.create_spacers((67,), (unit_manufacturer_part_number,))[0] * ' ' + unit_manufacturer_build_state = '"' + card.manufacturer_build_state + '"' + context['unit_manufacturer_build_state'] = unit_manufacturer_build_state + context['spacer_8'] = self.create_spacers((67,), (unit_manufacturer_build_state,))[0] * ' ' + unit_supplier_part_number = '"' + card.model_name + '"' + context['unit_supplier_part_number'] = unit_supplier_part_number + context['spacer_9'] = self.create_spacers((67,), (unit_supplier_part_number,))[0] * ' ' + unit_supplier_build_state = '"' + card.supplier_build_state + '"' + context['unit_supplier_build_state'] = unit_supplier_build_state + context['spacer_10'] = self.create_spacers((67,), (unit_supplier_build_state,))[0] * ' ' + unit_customer_id = '"' + card.customer_id + '"' + context['unit_customer_id'] = unit_customer_id + context['spacer_11'] = self.create_spacers((67,), (unit_customer_id,))[0] * ' ' + unit_customer_product_id = '"' + card.customer_product_id + '"' + context['unit_customer_product_id'] = unit_customer_product_id + context['spacer_12'] = self.create_spacers((67,), (unit_customer_product_id,))[0] * ' ' + unit_boot_loader = '"' + card.boot_loader + '"' + context['unit_boot_loader'] = unit_boot_loader + context['spacer_13'] = self.create_spacers((67,), (unit_boot_loader,))[0] * ' ' + unit_processor = '"' + card.processor + '"' + context['unit_processor'] = unit_processor + context['spacer_14'] = self.create_spacers((67,), (unit_processor,))[0] * ' ' + text = self._render('equipment_inventory', *scopes, context=context) + + self._write(text) + + else: + raise exceptions.CommandExecutionError(command=command, template='invalid_property', + template_scopes=('login', 'base', 'execution_errors')) + + def get_component(self): + return self._model.get_card('name', self.component_name) + + def set(self, command, *args, context=None): + try: + card = self.get_component() + except exceptions.SoftboxenError: + raise exceptions.CommandSyntaxError(command=command) + if self._validate(args, *()): + exc = exceptions.CommandSyntaxError(command=command) + exc.template = 'syntax_error' + exc.template_scopes = ('login', 'base', 'syntax_errors') + raise exc + elif self._validate(args, 'Labels', str, str, str) and context['path'].split('/')[-1] == 'main': + label1, label2, description = self._dissect(args, 'Labels', str, str, str) + try: + component = self.get_component() + component.set_label(label1, label2, description) + except exceptions.SoftboxenError(): + raise exceptions.CommandExecutionError(command=command, template='invalid_property', + template_scopes=('login', 'base', 'execution_errors')) + elif self._validate(args, 'Ip', str, str, str) and context['path'].split('/')[-1] == 'cfgm': + ip1, ip2, ip3 = self._dissect(args, 'Ip', str, str, str) + try: + component = self.get_component() + component.set_ip(ip1, ip2, ip3) + except exceptions.SoftboxenError(): + raise exceptions.CommandExecutionError(command=command, template='invalid_property', + template_scopes=('login', 'base', 'execution_errors')) + elif self._validate(args, 'SIP', str, str, str, str, str, str, str, str, str, str, str, str, str, str) and \ + context['path'].split('/')[-1] == 'cfgm' and (card.product == 'isdn' or card.product == 'analog'): + gw, hd, spn, cc, ac, rt, mri, se, aim, os, ot, uac, uas, sessione = self._dissect( + args, 'Sip', str, str, str, str, str, str, str, str, str, str, str, str, str, str) + try: + se = True if se.lower() == 'true' else False + os = True if os.lower() == 'true' else False + uac = True if uac.lower() == 'true' else False + uas = True if uas.lower() == 'true' else False + aim = None if aim.lower() == 'none' else aim + + card.set_sip(gw, hd, int(spn), cc, ac, int(rt), int(mri), se, aim, os, int(ot), uac, uas, int(sessione)) + except exceptions.SoftboxenError: + raise exceptions.CommandSyntaxError(command=command) + elif self._validate((args[0],), 'Digitmap') and \ + context['path'].split('/')[-1] == 'cfgm' and (card.product == 'isdn' or card.product == 'analog'): + pass + elif self._validate(args, 'Registrar', str, str, str, str) and \ + context['path'].split('/')[-1] == 'cfgm' and (card.product == 'isdn' or card.product == 'analog'): + ra, rp, rm, rt = self._dissect(args, 'Registrar', str, str, str, str) + try: + card.set_registrar(ra, int(rp), rm, int(rt)) + except exceptions.SoftboxenError: + raise exceptions.CommandSyntaxError(command=command) + elif self._validate(args[:9], 'Proxy', str, str, str, str, str, str, str, str) and \ + context['path'].split('/')[-1] == 'cfgm' and (card.product == 'isdn' or card.product == 'analog'): + pm, pa1, pp1, pa2, pp2, pe, pmethod, pi = self._dissect(args, 'Proxy', str, str, str, str, str, str, str, str) + try: + pe = True if pe.lower() == 'true' else False + card.set_proxy(pm, pa1, int(pp1), pa2, int(pp2), pe, pmethod, int(pi)) + except exceptions.SoftboxenError: + raise exceptions.CommandSyntaxError(command=command) + else: + raise exceptions.CommandSyntaxError(command=command) + + def do_restart(self, command, *args, context=None): + card = self.get_component() + if len(args) == 0 and context['path'].split('/')[-1] == 'main' and (card.product == 'isdn' or card.product == 'analog'): + time.sleep(10) + exc = exceptions.TerminalExitError() + exc.return_to = 'sysreboot' + raise exc + else: + raise exceptions.CommandSyntaxError(command=command) diff --git a/vendors/KeyMile/accessPoints/root/unit/unitManagementFunctions.py b/vendors/KeyMile/accessPoints/root/unit/unitManagementFunctions.py new file mode 100644 index 0000000..0a5adbd --- /dev/null +++ b/vendors/KeyMile/accessPoints/root/unit/unitManagementFunctions.py @@ -0,0 +1,194 @@ +main = { + 'General': { + 'Prop': { + 'Labels': 'rw', + 'AlarmStatus': 'r-' + } + }, + 'Equipment': { + 'Prop': { + 'AssignmentStatus': 'r-', + 'CurrentStatus': 'r-' + }, + 'Cmd': ( + 'Assign', + 'Unassign', + 'Restart', + 'StopInBoot' + ) + }, + 'Inventory': { + 'Prop': { + 'EquipmentInventory': 'r-' + } + }, + 'Logbooks': { + 'Cmd': ( + 'GetAlarmLogbook', + 'GetEventLogbook', + 'GetEquipmentLogbook' + ) + }, + 'Software': { + 'Prop': { + 'DiskSpace': 'r-', + 'SoftwareOnUnit': 'r-', + 'HardwareAndSoftware': 'r-', + 'Status': 'r-', + 'Configuration': 'rw' + }, + 'Cmd': ( + 'DeleteSoftware', + 'StartSoftware' + ), + 'File': { + 'Software': 'rw' + } + } +} + +cfgm = { + 'Vlan': { + 'Prop': { + 'VlanCosTable': 'r-' + } + }, + 'Security': { + 'Prop': { + 'filtering': 'rw', + 'EoamMode': 'rw' + } + }, + 'Logon': { + 'Prop': { + 'LogonOptions': 'rw', + 'OneToOneOptions': 'rw' + } + }, + 'Mac': { + 'Prop': { + 'MacServiceBased': 'rw' + } + }, + 'HostPort': { + 'Prop': { + 'PolicerProfile': 'rw', + 'TrunkPolicerProfile': 'rw', + 'ProtRateLimiter': 'rw' + } + }, + 'QoS': { + 'Prop': { + 'ColorMarking': 'rw' + } + }, + 'Wire': { + 'General': { + 'Prop': { + 'MeltConfiguration': 'rw' + } + }, + 'Thresholds': { + 'Prop': { + 'MeltAlarmThresholds': 'rw' + } + } + } +} + +fm = { + 'Status': { + 'Prop': { + 'AlarmStatus': 'r-' + }, + 'Cmd': ( + 'Acknowledge', + ) + }, + 'Configuration': { + 'Prop': { + 'AlarmConfiguration': 'rw' + } + } +} + +status = { + 'MacAllocationTable': { + 'Prop': { + 'MacAllocationTableEntries': 'r-' + } + }, + 'SwitchPort': { + 'Prop': { + 'Mac': 'r-', + 'MacStatus': 'r-' + } + }, + 'HostPortStatistics': { + 'GeneralCounters': { + 'Prop': { + 'GeneralList': 'r-' + }, + 'Cmd': ( + 'ResetGeneralCounters', + ) + }, + 'ProtocolCounters': { + 'IgmpCounters': { + 'Prop': { + 'IgmpProtocolList': 'r-' + }, + 'Cmd': ( + 'ResetIgmpCounters', + ) + }, + 'DhcpCounters': { + 'Prop': { + 'DhcpProtocolList': 'r-' + }, + 'Cmd': ( + 'ResetDhcpCounters', + ) + }, + 'ArpCounters': { + 'Prop': { + 'ArpProtocolList': 'r-' + }, + 'Cmd': ( + 'ResetArpCounters', + ) + }, + 'PPPoECounters': { + 'Prop': { + 'PPPoEProtocolList': 'r-' + }, + 'Cmd': ( + 'ResetPPPoECounters', + ) + }, + 'UnknownSourceMACCounters': { + 'Prop': { + 'UnknownSrcMACProtocolList': 'r-' + }, + 'Cmd': ( + 'ResetUnknownSrcMACCounters', + ) + }, + }, + }, + 'BufferManagement': { + 'Prop': { + 'BufferMgmtStatus': 'r-' + } + }, + 'Maintenance': { + 'Prop': { + 'MeltLineTestStatus': 'r-', + 'SearchTone': 'rw' + }, + 'Cmd': ( + 'StartMeltAll', + 'StopMeltAll' + ) + } +} diff --git a/vendors/KeyMile/baseCommandProcessor.py b/vendors/KeyMile/baseCommandProcessor.py new file mode 100644 index 0000000..071caed --- /dev/null +++ b/vendors/KeyMile/baseCommandProcessor.py @@ -0,0 +1,613 @@ +# This file is part of the NESi software. +# +# Copyright (c) 2020 +# Original Software Design by Ilya Etingof . +# +# Software adapted by inexio . +# - Janis Groß +# - Philip Konrath +# - Alexander Dincher +# +# License: https://github.com/inexio/NESi/LICENSE.rst + +from time import sleep +from nesi import exceptions +from nesi.softbox.cli import base +import re +import importlib + + +class BaseCommandProcessor(base.CommandProcessor): + """Create CLI REPR loop for example switch.""" + + management_functions = () + access_points = () + + component_name = None + + def set_component_name(self, name): + self.component_name = name + + main = {} + + cfgm = {} + + fm = {} + + pm = {} + + status = {} + + def on_unknown_command(self, command, *args, context=None): + if len(args) == 0: + if '/' in command: + if command.startswith('/'): + path = '/' + '/'.join([x for x in command.split('/') if x][:-1]).replace('_', '-') + else: + path = '/'.join([x for x in command.split('/') if x][:-1]).replace('_', '-') + command = [x for x in command.split('/') if x][-1] + + current_path = context['path'] + try: + command_proc = self.change_directory(path, context=context) + command_proc._parse_and_execute_command(command, context=context) + except exceptions.SoftboxenError: + context['path'] = current_path + self.set_prompt_end_pos(context=context) + raise exceptions.CommandExecutionError(template='invalid_management_function_error', + template_scopes=('login', 'base', 'execution_errors'), + command=None) + context['path'] = current_path + self.set_prompt_end_pos(context=context) + else: + raise exceptions.CommandExecutionError(template='invalid_management_function_error', + template_scopes=('login', 'base', 'execution_errors'), + command=None) + else: + raise exceptions.CommandExecutionError(template='invalid_management_function_error', + template_scopes=('login', 'base', 'execution_errors'), + command=None) + + def do_ftpserver(self, command, *args, context=None): + if self._validate(args, str, str, str): + ip, login, pw = self._dissect(args, str, str, str) + try: + self._model.set_ftp_data(ip, login, pw) + except exceptions.SoftboxenError: + raise exceptions.CommandSyntaxError(command=command) + else: + raise exceptions.CommandSyntaxError(command=command) + + def do_upload(self, command, *args, context=None): + if self._validate(args, '/cfgm/configuration', str) and context['path'].split('/')[-1] != 'cfgm': + path, = self._dissect(args, '/cfgm/configuration', str) + sleep(10) # NOTE: as of now there is no ftp server mocking + # mechanism so the only way to simulate an upload is by doing a sleep + else: + raise exceptions.CommandSyntaxError(command=command) + + def map_states(self, object, type): + if object.admin_state == '0': + if type == 'port': + object.admin_state = 'Down' + elif object.admin_state == '1': + if type == 'port': + object.admin_state = 'Up' + elif object.admin_state == '2': + if type == 'port': + object.admin_state = 'Locked' + elif object.admin_state == '3': + if type == 'port': + object.admin_state = 'Unlocked' + + if object.operational_state == '0': + if type == 'port': + object.operational_state = 'Down' + elif object.operational_state == '1': + if type == 'port': + object.operational_state = 'Up' + + def create_spacers(self, positions, args): + spacers = [] + previous_pos = 0 + i = 0 + for position in positions: + spacer = position - (previous_pos + len(str(args[i]))) + spacers.append(spacer) + previous_pos = position + i += 1 + + return spacers + + def do_help(self, command, *args, context=None): + help_scopes = ('login', 'base', 'help') + if self._validate(args, str): + help_arg, = self._dissect(args, str) + + if help_arg == 'cd': + self._write(self._render('help_cd', *help_scopes, context=context)) + elif help_arg == 'pwd': + self._write(self._render('help_pwd', *help_scopes, context=context)) + elif help_arg == 'ls': + self._write(self._render('help_ls', *help_scopes, context=context)) + elif help_arg == 'show': + self._write(self._render('help_show', *help_scopes, context=context)) + elif help_arg == 'mode': + self._write(self._render('help_mode', *help_scopes, context=context)) + elif help_arg == 'ftpserver': + self._write(self._render('help_ftpserver', *help_scopes, context=context)) + elif help_arg == 'upload': + self._write(self._render('help_upload', *help_scopes, context=context)) + elif help_arg == 'download': + self._write(self._render('help_download', *help_scopes, context=context)) + elif help_arg == 'get': + self._write(self._render('help_get', *help_scopes, context=context)) + elif help_arg == 'set': + self._write(self._render('help_set', *help_scopes, context=context)) + elif help_arg == 'profile': + self._write(self._render('help_profile', *help_scopes, context=context)) + elif help_arg == 'help': + self._write(self._render('help_help', *help_scopes, context=context)) + elif help_arg == 'exit': + self._write(self._render('help_exit', *help_scopes, context=context)) + else: + raise exceptions.CommandSyntaxError(command=command) + elif self._validate(args, ): + self._write(self._render('help', *help_scopes, context=context)) + else: + raise exceptions.CommandSyntaxError(command=command) + + def do_pwd(self, command, *args, context=None): + context['spacer'] = self.create_spacers((67,), (context['path'],))[0] * ' ' + self._write(self._render('pwd', 'login', 'base', context=context)) + + def ls(self, context=None): + scopes = ('login', 'base', 'ls') + if re.search('(pm|fm|status|main|cfgm)', context['path']): + mf_type = context['path'].split('/')[-1] + + mf_layers = {} + if mf_type == 'status': + mf_layers = self.status + elif mf_type == 'cfgm': + mf_layers = self.cfgm + elif mf_type == 'fm': + mf_layers = self.fm + elif mf_type == 'pm': + mf_layers = self.pm + elif mf_type == 'main': + mf_layers = self.main + + def generate_ls_text(layers, depth): + text = '' + for layer in layers: + if layer not in ('Cmd', 'Prop', 'File'): + context['mf_layer'] = depth * ' ' + layer + text += self._render('ls_mf_header', *scopes, context=context) + depth += 1 + text += generate_ls_text(layers[layer], depth) + depth -= 1 + else: + if layer == 'Cmd': + prop_type = layer + ' ' + else: + prop_type = layer + + context['prop_type'] = depth * ' ' + prop_type + + for property in layers[layer]: + context['prop_name'] = property + if prop_type in ('File', 'Prop'): + context['prop_rw_rights'] = layers[layer].get(property, '') + else: + context['prop_rw_rights'] = '' + text += self._render('ls_mf_body', *scopes, context=context) + return text + + text = generate_ls_text(mf_layers, 0) + self._write(text) + + else: + self._init_context(context=context) + text = self._render('ls_header', *scopes, context=context) + + self._init_access_points(context=context) + + text += self._render('ls_mf_list', *scopes, context=context) + for management_function in self.management_functions: + context['list_entry'] = management_function + text += self._render('ls_list_body', *scopes, context=context) + + text += self._render('ls_ap_list', *scopes, context=context) + + for access_point in self.access_points: + context['list_entry'] = access_point + text += self._render('ls_list_body', *scopes, context=context) + + self._write(text) + + def do_ls(self, command, *args, context=None): + if self._validate(args, ): + self.ls(context=context) + elif self._validate(args, '-e'): + pass + elif self._validate(args, str): + path = args[0] + current_path = context['path'] + + try: + tmp_cmdproc = self.change_directory(path, context=context) + tmp_cmdproc.ls(context=context) + except exceptions.CommandExecutionError: + context['path'] = current_path + self.set_prompt_end_pos(context=context) + raise exceptions.CommandExecutionError(template='invalid_management_function_error', + template_scopes=('login', 'base', 'execution_errors'), + command=None) + + context['path'] = current_path + self.set_prompt_end_pos(context=context) + else: + raise exceptions.CommandExecutionError(template='invalid_management_function_error', + template_scopes=('login', 'base', 'execution_errors'), + command=command) + + def change_directory(self, path, context=None): + path = path.lower() + + if re.search('^(?:[^.]+/)+\.{1,2}$', path): + raise exceptions.CommandExecutionError(template='invalid_management_function_error', + template_scopes=('login', 'base', 'execution_errors'), + command=None) + if re.search('^(?:[^.]+/)+\.{1,2}(?:/.+)+$', path): + raise exceptions.CommandExecutionError(template='invalid_address_error', + template_scopes=('login', 'base', 'execution_errors'), + command=None) + + allowed_path_components = ( + 'unit-[0-9]+', 'port-[0-9]+', 'portgroup-[0-9]+', 'chan-[0-9]+', 'interface-[0-9]+', 'vcc-[0-9]+', + 'alarm-[0-9]+', 'main', 'cfgm', 'fm', 'pm', 'status', 'eoam', 'fan', 'multicast', 'services', 'packet', + 'srvc-[0-9]', 'macaccessctrl', 'tdmconnections', 'logports', 'logport-[0-9]', '1to1doubletag', + '1to1singletag', 'mcast', 'nto1', 'pls', 'tls', '\.', '\.\.' + ) + + components = [x for x in path.split('/') if x] + if path.startswith('/'): + if path == '/': + if self.__name__ != 'root': + return self._parent.change_directory(path, context=context) + else: + context['path'] = '/' + return self + + if self.__name__ != 'root': + subprocessor = self._parent.change_directory(path, context=context) + else: + context['path'] = '/' + subprocessor = self.change_directory(path.lstrip('/'), context=context) + elif path.startswith('.'): + if path.startswith('...'): + if '/' in path: + raise exceptions.CommandExecutionError(template='invalid_address_error', + template_scopes=('login', 'base', 'execution_errors'), + command=None) + else: + raise exceptions.CommandExecutionError(command=None, template=None, + template_scopes=()) # TODO: fix exception to not require all fields as empty + + if path == '.': + return self + + if path.startswith('./'): + if path == './': + return self + + return self.change_directory(path[2:], context=context) + + if path.startswith('..'): + splitted_path = [x for x in context['path'].split('/') if x] + exit_component = None + if len(splitted_path) != 0: + exit_component = splitted_path.pop() + context['path'] = '/' + '/'.join(splitted_path) + + if exit_component in ('main', 'cfgm', 'fm', 'pm', 'status'): + self.set_prompt_end_pos(context=context) + if path != '..': + return self.change_directory(path[3:], context=context) + return self + + if path == '..' or path == '../': + if self.__name__ == 'root': + return self + return self._parent + + if self.__name__ == 'root': + return self.change_directory(path[3:], context=context) + + return self._parent.change_directory(path[3:], context=context) + else: + if not re.search('^(' + '|'.join(allowed_path_components) + ')$', components[0]): + raise exceptions.CommandExecutionError(template='invalid_management_function_error', + template_scopes=('login', 'base', 'execution_errors'), + command=None) + + remaining_args = '/'.join(components[1:]) + + component_type = None + component_id = None + if '-' in components[0]: + component_type = components[0].split('-')[0] + component_id = components[0].split('-')[1] + if component_type == 'port': + if self.__name__ == 'portgroup': + component_type = 'portgroupport' + elif self.__name__ == 'mgmtunit': + component_type = 'mgmtport' + if component_type == 'unit': + if component_id == '11': + component_type = 'mgmtunit' + if component_id == '13': + try: + self._model.get_mgmt_card('name', '13') + except exceptions.InvalidInputError: + component_type = 'unit' + else: + component_type = 'mgmtunit' + if component_type == 'vcc': + component_type = 'interface' + + command_processor = component_type.capitalize() + 'CommandProcessor' + else: + if components[0] in ('1to1doubletag', '1to1singletag', 'mcast', 'nto1', 'pls', 'tls'): + if context['path'].split('/')[-1] in ( + '1to1doubletag', '1to1singletag', 'mcast', 'nto1', 'pls', 'tls'): + raise exceptions.CommandExecutionError(command=None, template=None, + template_scopes=()) # TODO: fix exception to not require all fields as empty + + context['ServiceType'] = components[0] + + command_processor = 'SubpacketCommandProcessor' + else: + command_processor = components[0].capitalize() + 'CommandProcessor' + + if component_type: + relation_is_valid = self._validate_layer_relation(component_type, self.__name__) + else: + relation_is_valid = self._validate_layer_relation(components[0], self.__name__) + if components[0] not in ('main', 'cfgm', 'fm', 'pm', 'status'): + if relation_is_valid is False: + raise exceptions.CommandExecutionError(command=None, template=None, + template_scopes=()) # TODO: fix exception to not require all fields as empty + + if component_type == 'unit': + if (self._model.version == '2200' and not 9 <= int(component_id) <= 12) or (self._model.version == '2300' and not 7 <= int(component_id) <= 14) or (self._model.version == '2500' and not 1 <= int(component_id) <= 21): + raise exceptions.CommandExecutionError(command=None, template=None, + template_scopes=()) # TODO: fix exception to not require all fields as empty# + + if components[0] in ('main', 'cfgm', 'fm', 'pm', 'status'): + if context['path'].split('/')[-1] in ('main', 'cfgm', 'fm', 'pm', 'status'): + raise exceptions.CommandExecutionError(command=None, template='invalid_address_error', template_scopes=('login', 'base', 'execution_errors')) + + self._init_access_points(context=context) # make sure all management_functions are loaded correctly + + if components[0] not in self.management_functions: + raise exceptions.CommandExecutionError(command=None, template=None, + template_scopes=()) # TODO: fix exception to not require all fields as empty + + if context['path'] == '/': + new_path = components[0] + else: + new_path = '/' + components[0] + context['path'] += new_path + self.set_prompt_end_pos(context=context) + return self + + subprocessor = self._create_command_processor_obj(command_processor) + + if self.component_name: + if components[0] == 'logports': + component_name = self.component_name + '/L' + elif component_type == 'portgroup': + component_name = self.component_name + '/G' + component_id + else: + component_name = self.component_name + '/' + component_id + subprocessor.set_component_name(component_name) + else: + if component_type == 'srvc': + component_name = 'srvc-' + component_id + else: + component_name = component_id + subprocessor.set_component_name(component_name) + + if component_type: + component_exists = self._check_for_component(subprocessor) + if component_exists is False: + raise exceptions.CommandExecutionError(command=None, template=None, + template_scopes=()) # TODO: fix exception to not require all fields as empty + + if context['path'] == '/': + new_path = components[0] + else: + new_path = '/' + components[0] + context['path'] += new_path + + if len(remaining_args) > 0: + subprocessor = subprocessor.change_directory(remaining_args, context=context) + + return subprocessor + + def _validate_layer_relation(self, component_type, name): + relations = { + 'root': ('unit', 'mgmtunit', 'fan', 'eoam', 'tdmconnections', 'multicast', 'services'), + 'unit': ('port', 'portgroup', 'logports', 'huntgroup'), + 'mgmtunit': ('mgmtport',), + 'fan': ('alarm',), + 'services': ('packet', 'macaccessctrl'), + 'port': ('chan', 'interface'), + 'portgroup': ('portgroupport',), + 'chan': ('vcc', 'interface',), + 'logports': ('logport',), + 'logport': ('interface',), + 'packet': ('1to1doubletag', '1to1singletag', 'mcast', 'nto1', 'pls', 'tls'), + 'subpacket': ('srvc',), + } + + try: + if component_type not in relations[name]: + return False + except KeyError: + return False + + return True + + def _check_for_component(self, command_processor): + if command_processor.__name__ in ('portgroup', 'unit', 'mgmtunit', 'alarm'): + return True + + try: + command_processor.get_component() + except exceptions.InvalidInputError: + return False + + return True + + def _create_command_processor_obj(self, command_processor): + module_paths = { + 'UnitCommandProcessor': 'vendors.KeyMile.accessPoints.root.unit.unitCommandProcessor', + 'PortCommandProcessor': 'vendors.KeyMile.accessPoints.root.unit.port.portCommandProcessor', + 'ChanCommandProcessor': 'vendors.KeyMile.accessPoints.root.unit.port.chan.chanCommandProcessor', + 'InterfaceCommandProcessor': 'vendors.KeyMile.accessPoints.root.unit.port.interface.interfaceCommandProcessor', + 'FanCommandProcessor': 'vendors.KeyMile.accessPoints.root.fan.fanCommandProcessor', + 'AlarmCommandProcessor': 'vendors.KeyMile.accessPoints.root.fan.alarmCommandProcessor', + 'EoamCommandProcessor': 'vendors.KeyMile.accessPoints.root.eoamCommandProcessor', + 'MulticastCommandProcessor': 'vendors.KeyMile.accessPoints.root.multicastCommandProcessor', + 'TdmconnectionsCommandProcessor': 'vendors.KeyMile.accessPoints.root.tdmconnectionsCommandProcessor', + 'ServicesCommandProcessor': 'vendors.KeyMile.accessPoints.root.services.servicesCommandProcessor', + 'PortgroupCommandProcessor': 'vendors.KeyMile.accessPoints.root.unit.portgroup.portgroupCommandProcessor', + 'PortgroupportCommandProcessor': 'vendors.KeyMile.accessPoints.root.unit.portgroup.port.portgroupportCommandProcessor', + 'LogportsCommandProcessor': 'vendors.KeyMile.accessPoints.root.unit.logport.logportsCommandProcessor', + 'LogportCommandProcessor': 'vendors.KeyMile.accessPoints.root.unit.logport.port.logportCommandProcessor', + 'PacketCommandProcessor': 'vendors.KeyMile.accessPoints.root.services.packetCommandProcessor', + 'MacaccessctrlCommandProcessor': 'vendors.KeyMile.accessPoints.root.services.macaccessctrlCommandProcessor', + 'SubpacketCommandProcessor': 'vendors.KeyMile.accessPoints.root.services.subpacketCommandProcessor', + 'SrvcCommandProcessor': 'vendors.KeyMile.accessPoints.root.services.srvcCommandProcessor', + 'MgmtunitCommandProcessor': 'vendors.KeyMile.accessPoints.root.mgmt_unit.mgmtunitCommandProcessor', + 'MgmtportCommandProcessor': 'vendors.KeyMile.accessPoints.root.mgmt_unit.mgmt_port.mgmtportCommandProcessor', + } + + return self._create_subprocessor( + getattr(importlib.import_module(module_paths[command_processor]), command_processor), 'login', 'base') + + def do_get(self, command, *args, context=None): + if len(args) >= 1: + if '/' in args[0]: + path = '' + for component in args[0].split('/')[:-1]: + path += component + '/' + prop = args[0].split('/')[-1] + current_path = context['path'] + try: + tmp_cmdproc = self.change_directory(path, context=context) + tmp_cmdproc.get_property(command, prop, context=context) + except exceptions.SoftboxenError: + context['path'] = current_path + self.set_prompt_end_pos(context=context) + raise exceptions.CommandExecutionError(template='invalid_property', + template_scopes=('login', 'base', 'syntax_errors'), + command=None) + context['path'] = current_path + self.set_prompt_end_pos(context=context) + else: + try: + self.get_property(command, args[0], context=context) + except exceptions.SoftboxenError: + raise exceptions.CommandExecutionError(template='invalid_property', + template_scopes=('login', 'base', 'execution_errors'), + command=None) + else: + raise exceptions.CommandExecutionError(template='invalid_management_function_error', + template_scopes=('login', 'base', 'execution_errors'), + command=None) + + def get_property(self, command, *args, context=None): + raise exceptions.CommandExecutionError(command=command, template='invalid_property', + template_scopes=('login', 'base', 'execution_errors')) + + def do_set(self, command, *args, context=None): + if len(args) == 0: + raise exceptions.CommandExecutionError(command=command, template='invalid_property', + template_scopes=('login', 'base', 'execution_errors')) + elif args[0].count('/') > 0: + path = '' + for el in args[0].split('/')[:-1]: + path += el + '/' + current_path = context['path'] + try: + proc = self.change_directory(str(path[:-1]), context=context) + res = (args[0].split('/')[-1],) + args[1:] + proc.set(command, *res, context=context) + except exceptions.CommandExecutionError: + context['path'] = current_path + self.set_prompt_end_pos(context=context) + raise exceptions.CommandExecutionError(template='syntax_error', + template_scopes=('login', 'base', 'syntax_errors'), + command=None) + context['path'] = current_path + self.set_prompt_end_pos(context=context) + elif args[0].count('/') == 0: + self.set(command, *args, context=context) + + return + + def set(self, command, *args, context=None): + # interface method + return + + def do_cd(self, command, *args, context=None): + if self._validate(args, ): + raise exceptions.CommandSyntaxError() + elif self._validate(args, str): + path = args[0] + current_path = context['path'] + try: + subprocessor = self.change_directory(path, context=context) + except: + context['path'] = current_path + raise + subprocessor.loop(context=context, return_to=subprocessor._parent) + else: + raise exceptions.CommandExecutionError(template='invalid_management_function_error', + template_scopes=('login', 'base', 'execution_errors'), + command=command) + + def do_exit(self, command, *args, context=None): + exc = exceptions.TerminalExitError() + exc.return_to = 'sysexit' + raise exc + + def _init_access_points(self, context=None): + pass # Abstract method not implemented + + def _init_context(self, context=None): + context['ls_Name'] = '' + context['ls_MainMode'] = '' + context['ls_EquipmentState'] = '' + + def args_in_quotes_joiner(self, args): + quoted_args = [] + new_args = [] + save = False + for i in range(len(args)): + if args[i].startswith("\""): + save = True + if save: + quoted_args.append(args[i]) + else: + new_args.append(args[i]) + if args[i].endswith("\""): + save = False + new_args.append(' '.join(quoted_args).replace("\"", "")) + quoted_args = [] + + return new_args diff --git a/vendors/KeyMile/main.py b/vendors/KeyMile/main.py new file mode 100644 index 0000000..ff9abd4 --- /dev/null +++ b/vendors/KeyMile/main.py @@ -0,0 +1,64 @@ +# This file is part of the NESi software. +# +# Copyright (c) 2020 +# Original Software Design by Ilya Etingof . +# +# Software adapted by inexio . +# - Janis Groß +# - Philip Konrath +# - Alexander Dincher +# +# License: https://github.com/inexio/NESi/LICENSE.rst + +from nesi.softbox.cli import base +from vendors.KeyMile.accessPoints.root.rootCommandProcessor import RootCommandProcessor +from nesi import exceptions + + +class PreLoginCommandProcessor(base.CommandProcessor): + + def on_unknown_command(self, command, *args, context=None): + subprocessor = self._create_subprocessor( + LoginCommandProcessor, 'login') + + context['username'] = context['raw_line'].replace('\r', '').replace('\n', '') + + try: + subprocessor.history_enabled = False + subprocessor.star_input = True + subprocessor.loop(context=context) + except exceptions.TerminalExitError as exc: + if exc.return_to is not None and exc.return_to != 'sysexit': + raise exc + else: + self.on_exit(context) + raise exc + + +class LoginCommandProcessor(base.CommandProcessor): + + def on_unknown_command(self, command, *args, context=None): + username = context.pop('username') + password = command + + for creds in self._model.credentials: + if creds.username == username and creds.password == password: + break + + else: + text = self._render('password', context=context) + self._write(text) + raise exceptions.TerminalExitError() + + self.case_sensitive = False + + subprocessor = self._create_subprocessor( + RootCommandProcessor, 'login', 'base') + + context['path'] = '/' + + self._write(self._render('login_message', 'login', 'base', context=context)) + + subprocessor.loop(context=context, return_to=RootCommandProcessor) + + self.on_exit(context)