Projet
This commit is contained in:
17
fastprod_backend/Pipfile
Normal file
17
fastprod_backend/Pipfile
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
[[source]]
|
||||||
|
url = "https://pypi.org/simple"
|
||||||
|
verify_ssl = true
|
||||||
|
name = "pypi"
|
||||||
|
|
||||||
|
[packages]
|
||||||
|
flask = "*"
|
||||||
|
nornir = "*"
|
||||||
|
pyyaml = "*"
|
||||||
|
nornir-napalm = "*"
|
||||||
|
nornir-netmiko = "*"
|
||||||
|
nornir-utils = "*"
|
||||||
|
|
||||||
|
[dev-packages]
|
||||||
|
|
||||||
|
[requires]
|
||||||
|
python_version = "3.12"
|
||||||
1112
fastprod_backend/Pipfile.lock
generated
Normal file
1112
fastprod_backend/Pipfile.lock
generated
Normal file
File diff suppressed because it is too large
Load Diff
106
fastprod_backend/fastprod/api.py
Normal file
106
fastprod_backend/fastprod/api.py
Normal file
@@ -0,0 +1,106 @@
|
|||||||
|
from flask import Flask,jsonify,request,abort, make_response
|
||||||
|
from werkzeug.exceptions import HTTPException
|
||||||
|
from nornir import InitNornir
|
||||||
|
|
||||||
|
|
||||||
|
import json
|
||||||
|
|
||||||
|
ALLOWED_EXTENSIONS = {'conf'}
|
||||||
|
UPLOAD_FOLDER = 'fastprod/upload_files/'
|
||||||
|
|
||||||
|
|
||||||
|
def init_nornir():
|
||||||
|
app.config['nr'] = InitNornir(config_file="fastprod/inventory/config.yaml")
|
||||||
|
app.config['UPLOAD_FOLDER'] = UPLOAD_FOLDER
|
||||||
|
|
||||||
|
def allowed_file(filename):
|
||||||
|
return '.' in filename and \
|
||||||
|
filename.rsplit('.', 1)[1].lower() in ALLOWED_EXTENSIONS
|
||||||
|
|
||||||
|
app = Flask(__name__)
|
||||||
|
from services.devices import ( get_inventory, add_device,get_device_by_name,delete_device,get_device_interfaces,get_device_interfaces_ip,get_device_technical_info)
|
||||||
|
from services.config import (get_config_by_device)
|
||||||
|
from services.tasks import (run_show_commands_by_device,run_config_commands_by_device)
|
||||||
|
init_nornir()
|
||||||
|
|
||||||
|
@app.route("/")
|
||||||
|
def hello_world():
|
||||||
|
return jsonify({
|
||||||
|
"env": "DEV",
|
||||||
|
"name": "fastprod_backend",
|
||||||
|
"version": 1.0
|
||||||
|
})
|
||||||
|
|
||||||
|
@app.route("/devices", methods=['GET', 'POST'])
|
||||||
|
def devices():
|
||||||
|
if request.method == 'GET':
|
||||||
|
init_nornir()
|
||||||
|
devices = get_inventory()
|
||||||
|
return jsonify(devices=devices, total_count=len(devices))
|
||||||
|
if request.method == 'POST':
|
||||||
|
data = request.get_json()
|
||||||
|
new_device = add_device(data)
|
||||||
|
return jsonify(device=new_device)
|
||||||
|
|
||||||
|
@app.route("/devices/<device_name>", methods=['GET', 'DELETE'])
|
||||||
|
def device_by_name(device_name):
|
||||||
|
if request.method == 'GET':
|
||||||
|
device = get_device_by_name(device_name)
|
||||||
|
return jsonify(device=device)
|
||||||
|
if request.method == 'DELETE':
|
||||||
|
device = get_device_by_name(device_name)
|
||||||
|
delete_device(device)
|
||||||
|
return jsonify(message="Device deleted")
|
||||||
|
|
||||||
|
|
||||||
|
@app.route("/devices/<device_name>/interfaces", methods=['GET'])
|
||||||
|
def get_interfaces(device_name):
|
||||||
|
device = get_device_by_name(device_name)
|
||||||
|
interfaces = get_device_interfaces(device)
|
||||||
|
return jsonify(interfaces=interfaces)
|
||||||
|
|
||||||
|
@app.route("/devices/<device_name>/interfaces/ip", methods=['GET'])
|
||||||
|
def get_interfaces_ip(device_name):
|
||||||
|
if request.method == 'GET':
|
||||||
|
device = get_device_by_name(device_name)
|
||||||
|
interfaces_ip = get_device_interfaces_ip(device)
|
||||||
|
return jsonify(interfaces_ip=interfaces_ip)
|
||||||
|
|
||||||
|
@app.route("/devices/<device_name>/facts", methods=['GET'])
|
||||||
|
def get_technical_info(device_name):
|
||||||
|
if request.method == 'GET':
|
||||||
|
device = get_device_by_name(device_name)
|
||||||
|
technical_info = get_device_technical_info(device)
|
||||||
|
return jsonify(interfaces_ip=technical_info)
|
||||||
|
|
||||||
|
@app.route("/devices/<device_name>/config", methods=['GET','POST'])
|
||||||
|
def get_config(device_name):
|
||||||
|
device = get_device_by_name(device_name)
|
||||||
|
if request.method == 'GET':
|
||||||
|
config = get_config_by_device(device)
|
||||||
|
return jsonify(interfaces_ip=config)
|
||||||
|
if request.method == 'POST':
|
||||||
|
if request.get_json().get('mode') == 'enable':
|
||||||
|
commands = request.get_json().get('commands')
|
||||||
|
result = run_show_commands_by_device(device, commands=commands)
|
||||||
|
return jsonify(result=result)
|
||||||
|
if request.get_json().get('mode') == 'config':
|
||||||
|
commands = request.get_json().get('commands')
|
||||||
|
result = run_config_commands_by_device(device, commands=commands)
|
||||||
|
return jsonify(result=result, commands=commands)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@app.errorhandler(HTTPException)
|
||||||
|
def handle_exception(e):
|
||||||
|
"""Return JSON instead of HTML for HTTP errors."""
|
||||||
|
# start with the correct headers and status code from the error
|
||||||
|
response = e.get_response()
|
||||||
|
# replace the body with JSON
|
||||||
|
response.data = json.dumps({
|
||||||
|
"code": e.code,
|
||||||
|
"name": e.name,
|
||||||
|
"description": e.description,
|
||||||
|
})
|
||||||
|
response.content_type = "application/json"
|
||||||
|
return response
|
||||||
10
fastprod_backend/fastprod/inventory/config.yaml
Normal file
10
fastprod_backend/fastprod/inventory/config.yaml
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
inventory:
|
||||||
|
plugin: SimpleInventory
|
||||||
|
options:
|
||||||
|
host_file: "fastprod/inventory/hosts.yaml"
|
||||||
|
group_file: "fastprod/inventory/groups.yaml"
|
||||||
|
defaults_file: "fastprod/inventory/defaults.yaml"
|
||||||
|
runner:
|
||||||
|
plugin: threaded
|
||||||
|
options:
|
||||||
|
num_workers: 20
|
||||||
2
fastprod_backend/fastprod/inventory/defaults.yaml
Normal file
2
fastprod_backend/fastprod/inventory/defaults.yaml
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
username: cisco
|
||||||
|
password: cisco
|
||||||
4
fastprod_backend/fastprod/inventory/groups.yaml
Normal file
4
fastprod_backend/fastprod/inventory/groups.yaml
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
ios:
|
||||||
|
platform: ios
|
||||||
|
data:
|
||||||
|
vendor: Cisco
|
||||||
67
fastprod_backend/fastprod/inventory/hosts.yaml
Normal file
67
fastprod_backend/fastprod/inventory/hosts.yaml
Normal file
@@ -0,0 +1,67 @@
|
|||||||
|
ESW1-CPE-BAT-A:
|
||||||
|
data:
|
||||||
|
building: A
|
||||||
|
device_model: C3725
|
||||||
|
device_name: ESW1-CPE-BAT-A
|
||||||
|
device_type: router_switch
|
||||||
|
locality: lyon
|
||||||
|
groups:
|
||||||
|
- ios
|
||||||
|
hostname: 172.16.100.123
|
||||||
|
port: 22
|
||||||
|
ESW1-CPE-BAT-B:
|
||||||
|
data:
|
||||||
|
building: B
|
||||||
|
device_model: C3725
|
||||||
|
device_name: ESW1-CPE-BAT-B
|
||||||
|
device_type: router_switch
|
||||||
|
locality: lyon
|
||||||
|
groups:
|
||||||
|
- ios
|
||||||
|
hostname: 172.16.100.187
|
||||||
|
port: 22
|
||||||
|
R1-CPE-BAT-A:
|
||||||
|
data:
|
||||||
|
building: A
|
||||||
|
device_model: C7200
|
||||||
|
device_name: R1-CPE-BAT-A
|
||||||
|
device_type: router
|
||||||
|
locality: lyon
|
||||||
|
room: 1
|
||||||
|
groups:
|
||||||
|
- ios
|
||||||
|
hostname: 172.16.100.125
|
||||||
|
port: 22
|
||||||
|
R1-CPE-BAT-B:
|
||||||
|
data:
|
||||||
|
building: B
|
||||||
|
device_model: C7200
|
||||||
|
device_name: R1-CPE-BAT-B
|
||||||
|
device_type: router
|
||||||
|
locality: lyon
|
||||||
|
groups:
|
||||||
|
- ios
|
||||||
|
hostname: 172.16.100.189
|
||||||
|
port: 22
|
||||||
|
R2-CPE-BAT-A:
|
||||||
|
data:
|
||||||
|
building: A
|
||||||
|
device_model: C7200
|
||||||
|
device_name: R2-CPE-BAT-A
|
||||||
|
device_type: router
|
||||||
|
locality: lyon
|
||||||
|
groups:
|
||||||
|
- ios
|
||||||
|
hostname: 172.16.100.126
|
||||||
|
port: 22
|
||||||
|
R2-CPE-BAT-B:
|
||||||
|
data:
|
||||||
|
building: B
|
||||||
|
device_model: C7200
|
||||||
|
device_name: R2-CPE-BAT-B
|
||||||
|
device_type: router
|
||||||
|
locality: lyon
|
||||||
|
groups:
|
||||||
|
- ios
|
||||||
|
hostname: 172.16.100.190
|
||||||
|
port: 22
|
||||||
18
fastprod_backend/fastprod/services/config.py
Normal file
18
fastprod_backend/fastprod/services/config.py
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
from api import app
|
||||||
|
from nornir_napalm.plugins.tasks import napalm_get, napalm_configure, napalm_cli
|
||||||
|
from nornir.core.task import Task, Result
|
||||||
|
from nornir_utils.plugins.functions import print_result
|
||||||
|
|
||||||
|
def get_config_by_device(device):
|
||||||
|
nr = app.config.get('nr')
|
||||||
|
result = nr.filter(device_name=device.get('name')).run(task=napalm_get, getters=["get_config"])
|
||||||
|
return result[device.get('name')][0].result.get("get_config")
|
||||||
|
|
||||||
|
|
||||||
|
def run_config_from_file_by_device(device=None, file_path=None):
|
||||||
|
nr = app.config.get('nr')
|
||||||
|
if device and file_path:
|
||||||
|
result = nr.filter(device_name=device.get('name')).run(task=netmiko_send_config,
|
||||||
|
config_file=file_path)
|
||||||
|
print_result(result)
|
||||||
|
return result[device.get('name')].changed
|
||||||
70
fastprod_backend/fastprod/services/devices.py
Normal file
70
fastprod_backend/fastprod/services/devices.py
Normal file
@@ -0,0 +1,70 @@
|
|||||||
|
from api import app
|
||||||
|
from flask import Flask,jsonify,request,abort, make_response
|
||||||
|
from utils.inventory import *
|
||||||
|
from nornir import InitNornir
|
||||||
|
from nornir_utils.plugins.functions import print_result
|
||||||
|
from nornir_napalm.plugins.tasks import napalm_get,napalm_configure, napalm_cli
|
||||||
|
from nornir_netmiko.tasks import netmiko_send_config,netmiko_send_command, netmiko_save_config, netmiko_commit
|
||||||
|
|
||||||
|
def get_inventory():
|
||||||
|
hosts = app.config.get('nr').inventory.dict().get('hosts').keys()
|
||||||
|
return list(map(lambda item: app.config.get('nr').inventory.dict().get('hosts').get(item), hosts))
|
||||||
|
|
||||||
|
def add_device(device):
|
||||||
|
device = add_item_to_hosts_yaml(item=device)
|
||||||
|
return device
|
||||||
|
|
||||||
|
def get_device_by_name(name):
|
||||||
|
host = app.config.get('nr').inventory.hosts.get(name)
|
||||||
|
if not host:
|
||||||
|
abort(make_response(jsonify(message="device not found"), 404))
|
||||||
|
return host.dict()
|
||||||
|
|
||||||
|
def delete_device(device):
|
||||||
|
try:
|
||||||
|
delete_item_from_hosts_yaml(item=device)
|
||||||
|
except Exception as e:
|
||||||
|
abort(make_response(jsonify(message="Unable to delete this device", error=str(e)), 500))
|
||||||
|
|
||||||
|
def get_device_interfaces(device):
|
||||||
|
nr = app.config.get('nr')
|
||||||
|
result = nr.filter(device_name=device.get('name')).run(task=napalm_get,
|
||||||
|
getters=["get_interfaces"])
|
||||||
|
print_result(result)
|
||||||
|
print(result)
|
||||||
|
interfaces = result[device.get('name')][0].result.get('get_interfaces')
|
||||||
|
return list(map(lambda item: dict(name=item, **interfaces.get(item)), interfaces))
|
||||||
|
|
||||||
|
def get_device_technical_info(device):
|
||||||
|
nr = app.config.get('nr')
|
||||||
|
result = nr.filter(device_name=device.get('name')).run(
|
||||||
|
task=napalm_get,
|
||||||
|
getters=["get_facts"]
|
||||||
|
)
|
||||||
|
|
||||||
|
print_result(result)
|
||||||
|
|
||||||
|
facts = result[device.get('name')][0].result.get('get_facts')
|
||||||
|
|
||||||
|
return {
|
||||||
|
"hostname": facts.get("hostname"),
|
||||||
|
"vendor": facts.get("vendor"),
|
||||||
|
"model": facts.get("model"),
|
||||||
|
"serial_number": facts.get("serial_number"),
|
||||||
|
"os_version": facts.get("os_version"),
|
||||||
|
"uptime": facts.get("uptime"),
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def get_device_interfaces_ip(device):
|
||||||
|
nr = app.config.get('nr')
|
||||||
|
result = nr.filter(device_name=device.get('name')).run(task=napalm_get,
|
||||||
|
getters=["get_interfaces_ip"])
|
||||||
|
print_result(result)
|
||||||
|
interfaces = result[device.get('name')][0].result.get('get_interfaces_ip')
|
||||||
|
def transformer(item):
|
||||||
|
ip_address = list(interfaces.get(item).get('ipv4').keys())[0]
|
||||||
|
prefix_length = interfaces.get(item).get('ipv4').get(list(interfaces.get(item).get('ipv4').keys())[0]).get('prefix_length')
|
||||||
|
return dict(name=item, ip=ip_address, prefix_length=prefix_length)
|
||||||
|
return list(map(lambda item: transformer(item), interfaces))
|
||||||
|
#return interfaces
|
||||||
35
fastprod_backend/fastprod/services/tasks.py
Normal file
35
fastprod_backend/fastprod/services/tasks.py
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
from api import app
|
||||||
|
from nornir_napalm.plugins.tasks import napalm_get, napalm_configure, napalm_cli
|
||||||
|
from nornir.core.task import Task, Result
|
||||||
|
from nornir_utils.plugins.functions import print_result
|
||||||
|
from nornir_netmiko.tasks import netmiko_send_config, netmiko_send_command, netmiko_save_config,netmiko_commit
|
||||||
|
|
||||||
|
def run_show_commands_by_device(device=None, commands=[]):
|
||||||
|
nr = app.config.get('nr')
|
||||||
|
commands_sent = []
|
||||||
|
if device:
|
||||||
|
if len(commands) > 1:
|
||||||
|
for command in commands:
|
||||||
|
result = nr.filter(device_name=device.get('name')).run(task=napalm_cli,
|
||||||
|
commands=[command])
|
||||||
|
print_result(result)
|
||||||
|
output = result[device.get('name')][0].result.get(command)
|
||||||
|
commands_sent.append(dict(command=command, result=output))
|
||||||
|
output = commands_sent
|
||||||
|
else:
|
||||||
|
result = nr.filter(device_name=device.get('name')).run(task=napalm_cli,
|
||||||
|
commands=commands)
|
||||||
|
|
||||||
|
output = result[device.get('name')][0].result.get(commands[0])
|
||||||
|
commands_sent.append(dict(command=commands[0], result= output))
|
||||||
|
output = commands_sent
|
||||||
|
return output
|
||||||
|
|
||||||
|
def run_config_commands_by_device(device=None, commands=[]):
|
||||||
|
nr = app.config.get('nr')
|
||||||
|
commands_sent = []
|
||||||
|
if device:
|
||||||
|
result = nr.filter(device_name=device.get('name')).run(task=netmiko_send_config,
|
||||||
|
config_commands=[commands])
|
||||||
|
print_result(result)
|
||||||
|
return result[device.get('name')].changed
|
||||||
28
fastprod_backend/fastprod/utils/inventory.py
Normal file
28
fastprod_backend/fastprod/utils/inventory.py
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
import yaml
|
||||||
|
|
||||||
|
def update_hosts_yaml(file_path="fastprod/inventory/hosts.yaml", items=None):
|
||||||
|
if items:
|
||||||
|
with open(file_path, 'w') as yaml_file:
|
||||||
|
yaml.safe_dump(items, yaml_file)
|
||||||
|
return True
|
||||||
|
|
||||||
|
def add_item_to_hosts_yaml(file_path="fastprod/inventory/hosts.yaml", save=True, item=None):
|
||||||
|
with open(file_path, 'r') as yaml_file:
|
||||||
|
hosts = yaml.safe_load(yaml_file)
|
||||||
|
|
||||||
|
new_hosts = hosts.copy()
|
||||||
|
new_hosts[item.get('data').get('device_name')] = item
|
||||||
|
|
||||||
|
if save:
|
||||||
|
update_hosts_yaml(items=new_hosts)
|
||||||
|
|
||||||
|
return new_hosts[item.get('data').get('device_name')]
|
||||||
|
|
||||||
|
def delete_item_from_hosts_yaml(yaml_file_path="fastprod/inventory/hosts.yaml", save=True,item=None, ):
|
||||||
|
with open(yaml_file_path,'r') as yaml_file:
|
||||||
|
hosts = yaml.safe_load(yaml_file)
|
||||||
|
new_hosts = hosts.copy()
|
||||||
|
del new_hosts[item.get('data').get('device_name')]
|
||||||
|
if save:
|
||||||
|
update_hosts_yaml(items=new_hosts)
|
||||||
|
return True
|
||||||
53
fastprod_backend/nornir.log
Normal file
53
fastprod_backend/nornir.log
Normal file
@@ -0,0 +1,53 @@
|
|||||||
|
2025-11-27 10:29:07,377 - nornir.core - INFO - run() - Running task 'napalm_get' with args {'getters': ['get_interfaces']} on 1 hosts
|
||||||
|
2025-11-27 10:30:31,532 - nornir.core - INFO - run() - Running task 'napalm_get' with args {'getters': ['get_interfaces']} on 1 hosts
|
||||||
|
2025-11-27 10:32:16,142 - nornir.core - INFO - run() - Running task 'napalm_get' with args {'getters': ['get_interfaces']} on 1 hosts
|
||||||
|
2025-11-27 10:33:00,527 - nornir.core - INFO - run() - Running task 'napalm_get' with args {'getters': ['get_interfaces']} on 1 hosts
|
||||||
|
2025-11-27 10:42:31,649 - nornir.core - INFO - run() - Running task 'napalm_get' with args {'getters': ['get_interfaces_ip']} on 1 hosts
|
||||||
|
2025-11-27 10:43:18,016 - nornir.core - INFO - run() - Running task 'napalm_get' with args {'getters': ['get_interfaces_ip']} on 1 hosts
|
||||||
|
2025-11-27 10:44:05,459 - nornir.core - INFO - run() - Running task 'napalm_get' with args {'getters': ['get_interfaces_ip']} on 1 hosts
|
||||||
|
2025-11-27 10:44:18,600 - nornir.core - INFO - run() - Running task 'napalm_get' with args {'getters': ['get_interfaces_ip']} on 1 hosts
|
||||||
|
2025-11-27 10:47:29,054 - nornir.core - INFO - run() - Running task 'napalm_get' with args {'getters': ['get_interfaces_ip']} on 1 hosts
|
||||||
|
2025-11-27 10:47:38,118 - nornir.core - INFO - run() - Running task 'napalm_get' with args {'getters': ['get_interfaces_ip']} on 1 hosts
|
||||||
|
2025-11-27 10:49:17,515 - nornir.core - INFO - run() - Running task 'napalm_get' with args {'getters': ['get_interfaces_ip']} on 1 hosts
|
||||||
|
2025-11-27 10:50:27,409 - nornir.core - INFO - run() - Running task 'napalm_get' with args {'getters': ['get_interfaces_ip']} on 1 hosts
|
||||||
|
2025-11-27 10:55:14,616 - nornir.core - INFO - run() - Running task 'napalm_get' with args {'getters': ['get_facts']} on 1 hosts
|
||||||
|
2025-11-27 10:55:35,609 - nornir.core - INFO - run() - Running task 'napalm_get' with args {'getters': ['get_facts']} on 1 hosts
|
||||||
|
2025-11-27 11:03:38,869 - nornir.core - INFO - run() - Running task 'napalm_get' with args {'getters': ['get_config']} on 1 hosts
|
||||||
|
2025-11-27 11:11:30,181 - nornir.core - INFO - run() - Running task 'napalm_get' with args {'getters': ['get_interfaces']} on 1 hosts
|
||||||
|
2025-11-27 11:12:43,941 - nornir.core - INFO - run() - Running task 'napalm_get' with args {'getters': ['get_interfaces']} on 1 hosts
|
||||||
|
2025-11-27 11:12:47,660 - nornir.core - INFO - run() - Running task 'napalm_get' with args {'getters': ['get_config']} on 1 hosts
|
||||||
|
2025-11-27 11:12:58,676 - nornir.core - INFO - run() - Running task 'napalm_get' with args {'getters': ['get_config']} on 1 hosts
|
||||||
|
2025-11-27 11:13:05,327 - nornir.core - INFO - run() - Running task 'napalm_get' with args {'getters': ['get_config']} on 1 hosts
|
||||||
|
2025-11-27 11:13:07,216 - nornir.core - INFO - run() - Running task 'napalm_get' with args {'getters': ['get_config']} on 1 hosts
|
||||||
|
2025-11-27 11:13:17,120 - nornir.core - INFO - run() - Running task 'napalm_get' with args {'getters': ['get_config']} on 1 hosts
|
||||||
|
2025-11-27 11:17:14,064 - nornir.core - INFO - run() - Running task 'napalm_get' with args {'getters': ['get_interfaces']} on 1 hosts
|
||||||
|
2025-11-27 11:17:51,306 - nornir.core - INFO - run() - Running task 'napalm_get' with args {'getters': ['get_interfaces']} on 1 hosts
|
||||||
|
2025-11-27 11:18:37,859 - nornir.core - INFO - run() - Running task 'napalm_get' with args {'getters': ['get_interfaces']} on 1 hosts
|
||||||
|
2025-11-27 11:18:53,937 - nornir.core - INFO - run() - Running task 'napalm_get' with args {'getters': ['get_interfaces']} on 1 hosts
|
||||||
|
2025-11-27 11:23:38,281 - nornir.core - INFO - run() - Running task 'napalm_get' with args {'getters': ['get_interfaces']} on 1 hosts
|
||||||
|
2025-11-27 11:29:27,867 - nornir.core - INFO - run() - Running task 'napalm_get' with args {'getters': ['get_config']} on 1 hosts
|
||||||
|
2025-11-27 11:29:31,935 - nornir.core - INFO - run() - Running task 'napalm_get' with args {'getters': ['get_config']} on 1 hosts
|
||||||
|
2025-11-27 11:34:46,926 - nornir.core - INFO - run() - Running task 'napalm_cli' with args {'commands': ['show ip route']} on 1 hosts
|
||||||
|
2025-11-27 11:35:32,732 - nornir.core - INFO - run() - Running task 'napalm_cli' with args {'commands': ['show ip route']} on 1 hosts
|
||||||
|
2025-11-27 11:40:04,424 - nornir.core - INFO - run() - Running task 'napalm_cli' with args {'commands': ['show ip route']} on 1 hosts
|
||||||
|
2025-11-27 11:40:04,522 - nornir.core - INFO - run() - Running task 'napalm_cli' with args {'commands': ['show ip interfaces brief']} on 1 hosts
|
||||||
|
2025-11-27 11:52:28,952 - nornir.core - INFO - run() - Running task 'netmiko_send_config' with args {'config_commands': [['interface loopback 8', 'ip add 8.8.8.8 255.255.255.255', 'description created_from_postman']]} on 1 hosts
|
||||||
|
2025-11-27 11:52:29,772 - nornir.core.task - ERROR - start() - Host 'R1-CPE-BAT-A': task 'netmiko_send_config' failed with traceback:
|
||||||
|
Traceback (most recent call last):
|
||||||
|
File "/home/cpe/.local/share/virtualenvs/fastprod_backend-xSm6n0LL/lib/python3.12/site-packages/nornir/core/task.py", line 98, in start
|
||||||
|
r = self.task(self, **self.params)
|
||||||
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
File "/home/cpe/.local/share/virtualenvs/fastprod_backend-xSm6n0LL/lib/python3.12/site-packages/nornir_netmiko/tasks/netmiko_send_config.py", line 38, in netmiko_send_config
|
||||||
|
result = net_connect.send_config_set(config_commands=config_commands, **kwargs)
|
||||||
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
File "/home/cpe/.local/share/virtualenvs/fastprod_backend-xSm6n0LL/lib/python3.12/site-packages/netmiko/base_connection.py", line 111, in wrapper_decorator
|
||||||
|
return_val = func(self, *args, **kwargs)
|
||||||
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
File "/home/cpe/.local/share/virtualenvs/fastprod_backend-xSm6n0LL/lib/python3.12/site-packages/netmiko/base_connection.py", line 2294, in send_config_set
|
||||||
|
[True for cmd in config_commands_tmp if re.search(bypass_commands, cmd)]
|
||||||
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
File "/usr/lib/python3.12/re/__init__.py", line 177, in search
|
||||||
|
return _compile(pattern, flags).search(string)
|
||||||
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
TypeError: expected string or bytes-like object, got 'list'
|
||||||
|
|
||||||
3
fastprod_backend/start.sh
Executable file
3
fastprod_backend/start.sh
Executable file
@@ -0,0 +1,3 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
export FLASK_APP=fastprod/api.py
|
||||||
|
pipenv run flask run --host=0.0.0.0 --port=5000
|
||||||
Reference in New Issue
Block a user