netbox-community / netbox

The premier source of truth powering network automation. Open source under Apache 2. Try NetBox Cloud free: https://netboxlabs.com/free-netbox-cloud/
http://netboxlabs.com/oss/netbox/
Apache License 2.0
15.8k stars 2.54k forks source link

Custom Scripts - Module & Script Attributes #16050

Closed Arshnika closed 3 months ago

Arshnika commented 4 months ago

Deployment Type

Self-hosted

NetBox Version

v4.0.0

Python Version

3.10

Steps to Reproduce

  1. Create a custom script module including multiple scripts
  2. Define a "name" for the module
  3. Define a "name" and "description" for the scripts.
  4. Add the script module to NetBox

Expected Behavior

When the script module is added, NetBox should reflect all configured attributes on the GUI interface.

image

Observed Behavior

Custom_Scripts

abhi1693 commented 4 months ago

Please share a sample script code for us to reproduce this.

Arshnika commented 4 months ago

@abhi1693,

#!/usr/bin/env python3
from typing import Protocol
from extras.scripts import *
from extras.models import Tag
from dcim.choices import DeviceStatusChoices, SiteStatusChoices
from ipam.choices import PrefixStatusChoices, VLANStatusChoices
from ipam.models import IPAddress, Prefix, VLAN
from circuits.choices import CircuitStatusChoices
from dcim.models import Device, DeviceRole, DeviceType, Manufacturer, Site, Region, Interface, SiteGroup
from dcim.utils import ContentType
from tenancy.models import Tenant, Contact, ContactAssignment
from timezone_field import TimeZoneField, TimeZoneFormField
from django.utils.text import slugify
from django.forms import PasswordInput
from utilities import querysets
from extras.models import Tag
from circuits.models import Provider, CircuitType, Circuit, CircuitTermination
from meraki.exceptions import APIError

class Meraki_Get_CDP_LLDP_Neighbors(Script):

    class Meta:
            name = 'Get CDP/LLDP Neighbors'
            description = 'Get CDP/LLDP neighbors from Meraki Dashboard API'
            commit_default = False
            #field_order = ['site_name', 'switch_count', 'switch_model']

    #-----------------------------------------------------------
    #--- Get Values from HTML Form -----------------------------
    #-----------------------------------------------------------

    Store_Name = ObjectVar(model=Site, label='Store Name:')
    Protocols = (
        ('lldp', 'LLDP'),
        ('cdp', 'CDP'),
    )
    Protocol = ChoiceVar(choices=Protocols)

    def run(self, data, commit):

        import pynetbox
        import meraki
        import requests
        import os
        from dotenv import load_dotenv
        requests.packages.urllib3.disable_warnings()

        directory = os.path.dirname(os.path.abspath(__file__))
        dotenv_path = directory + '/.env'
        load_dotenv(dotenv_path)
        API_KEY_Meraki = os.environ.get("meraki_api", "default")
        API_KEY_NetBox = os.environ.get("netbox_api", "default")

        def printNei(m, serial, name, protocol):

            #----------------------------------------------------------
            #---- Print device neighbors. -----------------------------
            #---- Filters per protocol if protocol is provided. -------
            #----------------------------------------------------------

            CDP_Neighbors = ''
            LLDP_Neighbors = ''

            dp = m.devices.getDeviceLldpCdp(serial)
            for port in dp.get("ports", []):
                for proto in dp.get("ports").get(port):
                    nei = dp.get("ports").get(port).get(proto)
                    ip = nei.get("address", nei.get("managementAddress"))
                    if proto == "cdp" and protocol != "lldp":
                        systemName = nei.get("deviceId", "noname")
                        CDP_Neighbors += f'{proto.upper():4} LOCAL {name[:35]:35} SOURCE-PORT {nei.get("sourcePort"):8} REMOTE DEVICE {systemName.split(".")[0][:45]:45} REMOTE PORT {nei.get("portId"):24} REMOTE IP {ip}'
                        CDP_Neighbors += '\n'
                    elif proto == "lldp" and protocol != "cdp":
                        systemName = nei.get("systemName", "noname")
                        LLDP_Neighbors += f'{proto.upper():4} LOCAL {name[:35]:35} SOURCE-PORT {nei.get("sourcePort"):8} REMOTE DEVICE {systemName.split(".")[0][:45]:45} REMOTE PORT {nei.get("portId"):24} REMOTE IP {ip}'
                        LLDP_Neighbors += '\n'

            if protocol == 'cdp':
                return CDP_Neighbors
            else:
                return LLDP_Neighbors

        def main():

            org_id = '602356450160806405'
            protocol = data['Protocol']
            store_name = str(data['Store_Name'])

            nb = pynetbox.api (
                'https://netbox.sul.local',
                token=API_KEY_NetBox,
                threading = True,
            )
            nb.http_session.verify = False

            m = meraki.DashboardAPI(API_KEY_Meraki,suppress_logging=True)
            org_networks = m.organizations.getOrganizationNetworks(org_id)

            nb_site = nb.dcim.sites.get(name=store_name)
            nb_mer_sitename = nb_site.custom_fields['meraki_sitename']

            Neighbors = ''
            for net in org_networks:
                mer_netid = net['id']
                mer_sitename = net['name'][+9:]

                if mer_sitename == nb_mer_sitename:
                    mer_devices = m.networks.getNetworkDevices(mer_netid)
                    for mer_device in mer_devices:
                        serial, name = mer_device.get("serial"), mer_device.get(
                            "name", mer_device.get("serial", "MISSING")
                        )
                        Neighbors += printNei(m, serial, name, protocol)
                    break

            if Neighbors == '':
                Neighbors = 'Operation was not completed.\nEither the Meraki sitename is not the same as the Meraki sitename in NetBox or the Meraki site has not been created in NetBox.'
            return Neighbors

        return main()
Arshnika commented 4 months ago

Hi @abhi1693,

BTW, we have also upgraded NetBox to version 4.0.1 but to no avail.

Arshnika commented 4 months ago

Hi @abhi1693,

Just wondering whether you have been able to find the root cause of the issue?

Thanks.

hendrikbl commented 4 months ago

We just updated to v4.0.2 and are facing the same issue. Neither the modules name attribute nor the scripts Meta name and description value are used.

jeremystretch commented 4 months ago

@arthanson please update the status & severity for this bug report.