[Python] Variables losing values in Flask application

Discussão em 'Python' iniciado por Stack, Abril 15, 2025.

  1. Stack

    Stack Membro Participativo

    I've been working on a Flask backend for quite some time and as this is my first attempt, I've been running into a lot of issues.

    I have a linux server running the flask backend and I have a templates and static folder for my html and css.

    The website functions as a way for people to log in via SSO, connect to a Cisco switch, and update the speed and duplex settings of the device.

    I'm using Netmiko to establish a connection and retrieving user input through forms on the HTML pages. The problem I'm having is, it seems like my variables for the user inputed port and host devices don't retain their values when stored in the session.

    Further, it appears my connector (net_connector) loses its value at random intervals. Please note, I'm aware of the spaghetti code in the duplex and speed settings. I had functions created for them but removed them temporarily

    from flask import Flask, render_template, request, redirect, url_for, Response, session
    from netmiko import ConnectHandler
    from cryptography.fernet import Fernet
    from datetime import timedelta
    import re
    import socket
    import ipaddress
    import os
    import requests

    net_connect = None

    app = Flask(__name__)
    app.config.update(
    SESSION_COOKIE_SECURE=True,
    SESSION_COOKIE_HTTPONLY=True,
    SESSION_COOKIE_SAMESITE='Lax'
    )

    app.secret_key = os.urandom(24)
    app.permanent_session_lifetime = timedelta(minutes=30)

    CLIENT_ID = 'removed for example'
    CLIENT_SECRET = 'removed for example'
    AUTHORIZATION_BASE_URL = 'removed for example'
    TOKEN_URL = 'removed for example'
    REDIRECT_URI = 'removed for example'

    #encrypt using functions

    blocked_subnets = {
    Removed from example
    }

    def decrypt():
    with open('encryptedPWD.txt') as f:
    encpwd = ''.join(f.readlines())
    encpwdbyt = bytes(encpwd, 'utf-8')

    with open('refKey.txt') as f:
    refKey = ''.join(f.readlines())
    refKeybyt = bytes(refKey, 'utf-8')

    keytouse = Fernet(refKeybyt)
    myPass = keytouse.decrypt(encpwdbyt).decode('utf-8').strip()
    return myPass

    def Connect(hostn):

    global net_connect
    myPass = decrypt()

    try:
    net_connect = ConnectHandler(
    device_type='cisco_ios',
    host=hostn,
    username='REMOVED FOR EXAMPLE',
    password=myPass
    )
    return "Connection to {} successful!".format(hostn)
    except Exception as e:
    print("Error connecting to {}: {}".format(hostn, str(e)))
    return render_template('denied.html')
    # return "Connection to {} failed: {}".format(hostn, str(e))

    def dns_query(host):
    result = socket.getaddrinfo(host, None, socket.AF_INET)
    ip_address = result[0][4][0]
    return ip_address

    def dns_query_ip(host):
    try:
    result = socket.getaddrinfo(host, None, socket.AF_INET)
    ip_address = result[0][4][0]
    print(ip_address)
    return ip_address
    except socket.herror:
    return None

    def duplex(interface):
    if net_connect is None:
    return "Connection to device is not established."
    output = net_connect.send_command(f'show interface {interface}')
    return output

    @app.errorhandler(Exception)
    def handle_error(exception):
    # Log the exception
    app.logger.error(exception)

    return render_template('error.html', error_message="An unexpected error occurred. If this error was thrown while accessing a device using a hostname, try using the IP address instead", exception=exception)


    #SSO related Routes
    @app.route('/sso')
    def sso():
    code = request.args.get('code')
    if not code:
    return 'Authorization code not found in request.'


    response = requests.post(TOKEN_URL, data={
    'grant_type': 'authorization_code',
    'code': code,
    'redirect_uri': REDIRECT_URI,
    'client_id': CLIENT_ID,
    'client_secret': CLIENT_SECRET,
    'scope': 'openid profile'
    })
    response_data = response.json()
    access_token = response_data.get('access_token')

    #
    session['access_token'] = access_token

    return redirect(url_for('index'))

    @app.route('/auth_login')
    def auth_login():
    authorization_url = (
    f"{AUTHORIZATION_BASE_URL}?response_type=code"
    f"&client_id={CLIENT_ID}"
    f"&redirect_uri={REDIRECT_URI}"
    f"&response_mode=query"
    f"&scope=openid profile"
    )
    return redirect(authorization_url)

    #End of SSO Related Routes

    @app.route('/', methods=['GET', 'POST'])
    def initial():
    if 'access_token' in session:
    if request.method == 'POST':
    return render_template('index.html')
    else:
    return redirect(url_for('auth_login'))

    @app.route('/index')
    def index():
    if 'access_token' in session:
    return render_template('index.html') # if state
    else:
    return redirect(url_for('auth_login'))

    @app.route('/submit', methods=['POST'])
    def submit():
    if request.method == 'POST':
    host_input = request.form['hostInput']
    port_input = request.form['portInput']

    app.logger.info(f"Setting session values: host_input={host_input}, port_input={port_input}")

    session['host_input'] = request.form['hostInput']
    session['port_input'] = request.form['portInput']
    return redirect(url_for('check')) # send to submit

    @app.route('/check', methods=['GET', 'POST'])
    def check():
    host_input = session.get('host_input')
    port_input = session.get('port_input')


    if host_input is None or port_input is None:
    return render_template('error.html',
    error_message="Host or port input is missing.")

    result_messege = Connect(host_input)
    output = net_connect.send_command(f'show run interface {port_input}')
    if re.match("^[a-zA-Z]", host_input):
    host_input = dns_query_ip(host_input)
    for subnet in blocked_subnets:
    if host_input.startswith(subnet):
    error_message = f'Device {host_input} is a restricted device'
    return render_template('denied.html', error_message=error_message)
    if 'trunk'in output:
    net_connect.disconnect()
    error_message = f"Port {port_input} is a trunk port and cannot be modified."
    return render_template('denied.html', error_message=error_message)
    else:
    return redirect(url_for('result', result_messege=result_messege, host_input=host_input, port_input=port_input))

    @app.route('/result', methods=['GET', 'POST'])
    def result():
    host_input = session.get('host_input')
    port_input = session.get('port_input')

    port_messege = duplex(port_input)
    status_messege = net_connect.send_command(f'show interface {port_input} status')

    return render_template('result.html', port_messege=port_messege, status_messege=status_messege)

    @app.route('/updatedDuplex', methods=['GET', 'POST'])
    def updateduplex():
    host_input = session.get('host_input')
    port_input = session.get('port_input')

    if net_connect is None:
    return render_template('error.html',
    error_message=f"No active connection. Host: {host_input} Port: {port_input}")

    if request.method == 'POST':
    chosen_option = request.form.get('duplex')
    if chosen_option == 'auto':
    option = net_connect.send_config_set([f'interface {port_input}', 'duplex auto'])
    port_messege = net_connect.send_command(f'show interface {port_input}')
    status_messege = net_connect.send_command(f'show interface {port_input} status')
    elif chosen_option == 'full':
    option = net_connect.send_config_set([f'interface {port_input}', 'duplex full'])
    port_messege = net_connect.send_command(f'show interface {port_input}')
    status_messege = net_connect.send_command(f'show interface {port_input} status')
    elif chosen_option == 'half':
    option = net_connect.send_config_set([f'interface {port_input}', 'duplex half'])
    port_messege = net_connect.send_command(f'show interface {port_input}')
    status_messege = net_connect.send_command(f'show interface {port_input} status')
    return render_template('result.html', port_messege=port_messege, status_messege=status_messege)

    @app.route('/updatedSpeed', methods=['GET', 'POST'])
    def updatedspeed():
    host_input = session.get('host_input')
    port_input = session.get('port_input')


    if request.method == 'POST':
    chosen_option = request.form.get('speed')
    #port_messege = request.form.get('port_messege') # Retrieve port_input from query parameters
    if chosen_option == 'auto':
    net_connect(host_input)
    option = net_connect.send_config_set([f'interface {port_input}', 'speed auto'])
    port_messege = net_connect.send_command(f'show interface {port_input}')
    status_messege = net_connect.send_command(f'show interface {port_input} status')
    net_connect.disconnect()
    elif chosen_option == '10':
    option = net_connect.send_config_set([f'interface {port_input}', 'speed 10'])
    port_messege = net_connect.send_command(f'show interface {port_input}')
    status_messege = net_connect.send_command(f'show interface {port_input} status')
    elif chosen_option == '100':
    option = net_connect.send_config_set([f'interface {port_input}', 'speed 100'])
    port_messege = net_connect.send_command(f'show interface {port_input}')
    status_messege = net_connect.send_command(f'show interface {port_input} status')
    elif chosen_option == '1000':
    option = net_connect.send_config_set([f'interface {port_input}', 'speed 1000'])
    port_messege = net_connect.send_command(f'show interface {port_input}')
    status_messege = net_connect.send_command(f'show interface {port_input} status')
    return render_template('result.html', option=option, port_messege=port_messege, status_messege=status_messege)

    @app.route('/disconnect')
    def disconnect():
    if net_connect is not None:
    #net_connect.send_command('copy ru st') Disabled until deployment. Discuss further will pete.
    net_connect.disconnect()
    print("Disconnected from the device")
    else:
    print("No active connection to disconnect from")
    return redirect('index')

    @app.route('/refdisc', methods=['POST'])
    def refdisc():
    net_connect.disconnect()
    return Response("Disconnected from the device", status=200)


    @app.route('/denied')
    def denied():
    return render_template('denied.html')

    @app.route('/incorrect')
    def incorrect():
    return render_template('incorrect.html')


    @app.route('/logout')
    def logout():
    session.pop('access_token', None)
    return redirect(url_for('auth_login'))


    if __name__ == '__main__':
    app.run(host='0.0.0.0')


    The main issues I appear to be getting are on the results page. I'll see "'NoneType' object has no attribute 'send_command'". Occasionally, I'll get a message about port and host inputs not having a value.

    This is what I see in the browsers search bar: https://IPADDRESS/result?result_messege=Connection+to+1.1.1.1+successful!&host_input=1.1.1.1&port_input=GigabitEthernet1/0/7

    Again, I know the code isn't great and I apologize. This was all new to me and has been a work in progress.

    Continue reading...

Compartilhe esta Página