예제 #1
0
파일: views.py 프로젝트: hmpf/nav
def set_voice_vlan(handler: ManagementHandler, interface, request):
    """Set voicevlan on interface

    A voice vlan is a normal vlan that is defined by the user of NAV as
    a vlan that is used only for ip telephone traffic.

    To set a voice vlan we have to make sure the interface is configured
    to tag both the voicevlan and the "access-vlan".

    """
    if 'voicevlan' in request.POST:
        cdp_changed = False
        voice_vlan = fetch_voice_vlan_for_netbox(request, handler)
        use_cisco_voice_vlan = CONFIG.is_cisco_voice_enabled() and is_cisco(
            interface.netbox)
        enable_cdp_for_cisco_voice_port = CONFIG.is_cisco_voice_cdp_enabled()

        # Either the voicevlan is turned off or turned on
        turn_on_voice_vlan = request.POST.get('voicevlan') == 'true'
        account = get_account(request)
        try:
            if turn_on_voice_vlan:
                if use_cisco_voice_vlan:
                    handler.set_cisco_voice_vlan(interface, voice_vlan)
                    if enable_cdp_for_cisco_voice_port:
                        handler.enable_cisco_cdp(interface)
                        cdp_changed = True
                else:
                    handler.set_interface_voice_vlan(interface, voice_vlan)
                _logger.info(
                    '%s: %s:%s - %s%s',
                    account.login,
                    interface.netbox.get_short_sysname(),
                    interface.ifname,
                    'voice vlan enabled',
                    ', CDP enabled' if cdp_changed else '',
                )
            else:
                if use_cisco_voice_vlan:
                    handler.disable_cisco_voice_vlan(interface)
                    if enable_cdp_for_cisco_voice_port:
                        handler.disable_cisco_cdp(interface)
                        cdp_changed = True
                else:
                    handler.set_access(interface, interface.vlan)
                _logger.info(
                    '%s: %s:%s - %s%s',
                    account.login,
                    interface.netbox.get_short_sysname(),
                    interface.ifname,
                    'voice vlan disabled',
                    ', CDP disabled' if cdp_changed else '',
                )
        except (ManagementError, ValueError, NotImplementedError) as error:
            messages.error(request, "Error setting voicevlan: %s" % error)
예제 #2
0
파일: views.py 프로젝트: hmpf/nav
def get_management_handler(netbox: Netbox) -> ManagementHandler:
    """Gets a ManagementHandler instance from the ManagementFactory"""
    timeout = CONFIG.getfloat("general", "timeout", fallback=3)
    retries = CONFIG.getint("general", "retries", fallback=3)

    try:
        return ManagementFactory.get_instance(netbox,
                                              timeout=timeout,
                                              retries=retries)
    except ManagementError as error:
        _logger.error('Error getting ManagementHandler instance %s: %s',
                      netbox, error)
예제 #3
0
파일: views.py 프로젝트: hmpf/nav
def commit_configuration(request):
    """Commit pending config changes to startup config"""
    if not CONFIG.is_commit_enabled():
        _logger.debug('Not doing a configuration commit, it is configured off')
        return HttpResponse(
            "Configuration commit is configured to not be done")

    interface = get_object_or_404(Interface,
                                  pk=request.POST.get('interfaceid'))

    handler = get_management_handler(interface.netbox)
    if handler:
        try:
            handler.commit_configuration()
        except ManagementError as error:
            error_message = 'Error committing configuration on {}: {}'.format(
                handler.netbox, error)
            _logger.error(error_message)
            return HttpResponse(error_message, status=500)
        except (AttributeError, NotImplementedError):
            error_message = 'Error committing configuration on {}: {}'.format(
                handler.netbox, 'Configuration commit not supported')
            _logger.error(error_message)
            return HttpResponse(error_message, status=500)

        return HttpResponse()
    else:
        return HttpResponse(status=500)
예제 #4
0
파일: views.py 프로젝트: hmpf/nav
def restart_interfaces(request):
    """Restart the interface by setting admin status to down and up"""
    if not CONFIG.is_restart_interface_enabled():
        _logger.debug(
            "Not doing a restart of interfaces, it is configured off")
        return HttpResponse()

    interfaceids = request.POST.getlist("interfaceid",
                                        request.POST.getlist("interfaceid[]"))
    if not interfaceids:
        return HttpResponse(status=400,
                            content=b"Missing interfaceid argument")
    interfaces = Interface.objects.filter(
        pk__in=interfaceids).select_related("netbox")
    if not interfaces:
        return HttpResponse(status=400, content=b"No interfaces selected")
    netboxes = set(i.netbox for i in interfaces)
    if len(netboxes) > 1:
        return HttpResponse(
            status=400,
            content=b"Can't restart interfaces from different netboxes")
    netbox = list(netboxes)[0]

    handler = get_management_handler(netbox)
    if handler:
        try:
            # Restart interface so that clients fetch new addresses
            handler.cycle_interfaces(interfaces)
        except NoResponseError:
            # Failures aren't grossly important here, we ignore them
            pass
        return HttpResponse()
    else:
        return HttpResponse(status=500,
                            content=b"Could not create management handler")
예제 #5
0
파일: views.py 프로젝트: hmpf/nav
def handle_trunk_edit(request, agent, interface):
    """Edit a trunk"""

    native_vlan = int(request.POST.get('native_vlan', 1))
    trunked_vlans = [int(vlan) for vlan in request.POST.getlist('trunk_vlans')]

    if should_check_access_rights(get_account(request)):
        # A user can avoid the form restrictions by sending a forged post
        # request Make sure only the allowed vlans are set

        old_native, old_trunked = agent.get_native_and_trunked_vlans(interface)
        allowed_vlans = [
            v.vlan for v in find_allowed_vlans_for_user(get_account(request))
        ]

        trunked_vlans = filter_vlans(trunked_vlans, old_trunked, allowed_vlans)
        native_vlan = native_vlan if native_vlan in allowed_vlans else old_native

    _logger.info('Interface %s - native: %s, trunk: %s', interface,
                 native_vlan, trunked_vlans)
    LogEntry.add_log_entry(
        request.account,
        u'set-vlan',
        u'{actor}: {object} - native vlan: "%s", trunk vlans: "%s"' %
        (native_vlan, trunked_vlans),
        subsystem=u'portadmin',
        object=interface,
    )

    if trunked_vlans:
        agent.set_trunk(interface, native_vlan, trunked_vlans)
    else:
        agent.set_access(interface, native_vlan)
    if CONFIG.is_commit_enabled():
        agent.commit_configuration()
예제 #6
0
def find_allowed_vlans_for_user(account):
    """Find the allowed vlans for this user based on organization"""
    allowed_vlans = []
    for org in account.organizations.all():
        allowed_vlans.extend(find_vlans_in_org(org))

    defaultvlan = CONFIG.find_default_vlan()
    if defaultvlan and defaultvlan not in allowed_vlans:
        allowed_vlans.append(defaultvlan)

    return allowed_vlans
예제 #7
0
파일: views.py 프로젝트: hmpf/nav
def render_trunk_edit(request, interfaceid):
    """Controller for rendering trunk edit view"""

    interface = Interface.objects.get(pk=interfaceid)
    handler = get_management_handler(interface.netbox)
    if request.method == 'POST':
        try:
            handle_trunk_edit(request, handler, interface)
        except ManagementError as error:
            messages.error(request, 'Error editing trunk: %s' % error)
        else:
            messages.success(request, 'Trunk edit successful')

    account = request.account
    netbox = interface.netbox
    add_readonly_reason(request, handler)
    try:
        vlans = handler.get_netbox_vlans()  # All vlans on this netbox
        native_vlan, trunked_vlans = handler.get_native_and_trunked_vlans(
            interface)
    except ManagementError as error:
        vlans = native_vlan = trunked_vlans = allowed_vlans = None
        messages.error(request,
                       'Error getting trunk information: {}'.format(error))
    else:
        if should_check_access_rights(account):
            allowed_vlans = find_allowed_vlans_for_user_on_netbox(
                account, interface.netbox, handler)
        else:
            allowed_vlans = vlans

    extra_path = [
        (
            netbox.sysname,
            reverse('portadmin-sysname', kwargs={'sysname': netbox.sysname}),
        ),
        ("Trunk %s" % interface, ),
    ]

    context = get_base_context(extra_path)
    context.update({
        'interface': interface,
        'available_vlans': vlans,
        'native_vlan': native_vlan,
        'trunked_vlans': trunked_vlans,
        'allowed_vlans': allowed_vlans,
        'trunk_edit': CONFIG.get_trunk_edit(),
        'readonly': not handler.is_configurable(),
    })

    return render(request, 'portadmin/trunk_edit.html', context)
예제 #8
0
def check_format_on_ifalias(ifalias):
    """Verify that format on ifalias is correct if it is defined in config"""
    if not ifalias:
        return True
    ifalias_format = CONFIG.get_ifaliasformat()
    if ifalias_format:
        ifalias_format = re.compile(ifalias_format)
        if ifalias_format.match(ifalias):
            return True
        else:
            _logger.error('Wrong format on ifalias: %s', ifalias)
            return False
    else:
        return True
예제 #9
0
def add_dot1x_info(interfaces, handler):
    """Add information about dot1x state for interfaces"""

    # Skip if port access control is not enabled (and thus not dot1x)
    if not handler.is_port_access_control_enabled():
        return

    dot1x_states = handler.get_dot1x_enabled_interfaces()

    url_template = CONFIG.get_dot1x_external_url()
    for interface in interfaces:
        interface.dot1xenabled = dot1x_states.get(interface.ifindex)
        if url_template:
            interface.dot1x_external_url = url_template.format(
                netbox=interface.netbox, interface=interface)
예제 #10
0
파일: utils.py 프로젝트: hmpf/nav
def find_allowed_vlans_for_user_on_netbox(
        account: profiles.Account,
        netbox: manage.Netbox,
        handler: ManagementHandler = None) -> List[FantasyVlan]:
    """Finds allowed vlans for this user on this netbox"""
    netbox_vlans = find_vlans_on_netbox(netbox, handler=handler)

    if CONFIG.is_vlan_authorization_enabled():
        if is_admin(account):
            allowed_vlans = netbox_vlans
        else:
            all_allowed_vlans = find_allowed_vlans_for_user(account)
            allowed_vlans = intersect(all_allowed_vlans, netbox_vlans)
    else:
        allowed_vlans = netbox_vlans

    return sorted(allowed_vlans, key=attrgetter('vlan'))
예제 #11
0
파일: utils.py 프로젝트: hmpf/nav
def set_editable_flag_on_interfaces(interfaces: Sequence[manage.Interface],
                                    vlans: Sequence[FantasyVlan]):
    """Sets the pseudo-attribute `iseditable` on each interface in the interfaces
    list, indicating whether the PortAdmin UI should allow edits to it or not.

    An interface will be considered "editable" only if its native vlan matches one of
    the vlan tags from `vlans`. An interface may be considered non-editable if it is
    an uplink, depending on how portadmin is configured.
    """
    vlan_tags = {vlan.vlan for vlan in vlans}

    for interface in interfaces:
        vlan_is_acceptable = interface.vlan in vlan_tags
        is_link = bool(interface.to_netbox)
        refuse_link_edit = not CONFIG.get_link_edit() and is_link

        interface.iseditable = vlan_is_acceptable and not refuse_link_edit
예제 #12
0
def find_allowed_vlans_for_user_on_netbox(account, netbox, factory=None):
    """Find allowed vlans for this user on this netbox

    ::returns list of Fantasyvlans

    """
    netbox_vlans = find_vlans_on_netbox(netbox, factory=factory)

    if CONFIG.is_vlan_authorization_enabled():
        if is_admin(account):
            allowed_vlans = netbox_vlans
        else:
            all_allowed_vlans = find_allowed_vlans_for_user(account)
            allowed_vlans = intersect(all_allowed_vlans, netbox_vlans)
    else:
        allowed_vlans = netbox_vlans

    return sorted(allowed_vlans, key=attrgetter('vlan'))
예제 #13
0
파일: views.py 프로젝트: hmpf/nav
def set_vlan(account, handler: ManagementHandler, interface, request):
    """Set vlan on netbox if it is requested"""
    if 'vlan' in request.POST:
        try:
            vlan = int(request.POST.get('vlan'))
        except ValueError:
            messages.error(
                request,
                "Ignoring request to set vlan={}".format(
                    request.POST.get('vlan')),
            )
            return

        try:
            if is_cisco(interface.netbox):
                # If Cisco and trunk voice vlan (not Cisco voice vlan),
                # we have to set native vlan instead of access vlan
                voice_activated = request.POST.get('voice_activated', False)
                if not CONFIG.is_cisco_voice_enabled() and voice_activated:
                    handler.set_native_vlan(interface, vlan)
                else:
                    handler.set_vlan(interface, vlan)
            else:
                handler.set_vlan(interface, vlan)

            interface.vlan = vlan
            LogEntry.add_log_entry(
                account,
                u'set-vlan',
                u'{actor}: {object} - vlan set to "%s"' % vlan,
                subsystem=u'portadmin',
                object=interface,
            )
            _logger.info(
                '%s: %s:%s - vlan set to %s',
                account.login,
                interface.netbox.get_short_sysname(),
                interface.ifname,
                vlan,
            )
        except (ManagementError, TypeError) as error:
            _logger.error('Error setting vlan: %s', error)
            messages.error(request, "Error setting vlan: %s" % error)
예제 #14
0
파일: views.py 프로젝트: hmpf/nav
def fetch_voice_vlan_for_netbox(request: HttpRequest,
                                handler: ManagementHandler):
    """Fetch the voice vlan for this netbox

    There may be multiple voice vlans configured. Pick the one that exists
    on this netbox. If multiple vlans exist, we cannot know which one to use.

    """
    voice_vlans = CONFIG.fetch_voice_vlans()
    if not voice_vlans:
        return

    voice_vlans_on_netbox = list(
        set(voice_vlans) & set(handler.get_netbox_vlan_tags()))
    if not voice_vlans_on_netbox:
        # Should this be reported? At the moment I do not think so.
        return
    if len(voice_vlans_on_netbox) > 1:
        messages.error(request, 'Multiple voice vlans configured on this '
                       'netbox')
        return

    return voice_vlans_on_netbox[0]
예제 #15
0
def should_check_access_rights(account):
    """Return boolean indicating that this user is restricted"""
    return (CONFIG.is_vlan_authorization_enabled() and not is_admin(account))
예제 #16
0
파일: views.py 프로젝트: hmpf/nav
def populate_infodict(request, netbox, interfaces):
    """Populate a dictionary used in every http response"""
    allowed_vlans = []
    voice_vlan = None
    readonly = False
    handler = None

    try:
        handler = get_and_populate_livedata(netbox, interfaces)
        allowed_vlans = find_and_populate_allowed_vlans(
            request.account, netbox, interfaces, handler)
        voice_vlan = fetch_voice_vlan_for_netbox(request, handler)
        if voice_vlan:
            if CONFIG.is_cisco_voice_enabled() and is_cisco(netbox):
                set_voice_vlan_attribute_cisco(voice_vlan, interfaces, handler)
            else:
                set_voice_vlan_attribute(voice_vlan, interfaces)
        mark_detained_interfaces(interfaces)
        if CONFIG.is_dot1x_enabled():
            add_dot1x_info(interfaces, handler)
    except NoResponseError:
        readonly = True
        messages.error(
            request,
            "%s did not respond within the set timeouts. Values displayed are from database"
            % netbox.sysname,
        )
        if isinstance(handler, SNMPHandler) and not netbox.read_only:
            messages.error(request, "Read only community not set")
    except ProtocolError:
        readonly = True
        messages.error(
            request,
            "Protocol error when contacting %s. Values displayed are from database"
            % netbox.sysname,
        )
    except DeviceNotConfigurableError as error:
        readonly = True
        messages.error(request, str(error))

    if handler and not handler.is_configurable():
        add_readonly_reason(request, handler)
        readonly = True

    ifaliasformat = CONFIG.get_ifaliasformat()
    aliastemplate = ''
    if ifaliasformat:
        tmpl = get_aliastemplate()
        aliastemplate = tmpl.render({'ifaliasformat': ifaliasformat})

    save_to_database(interfaces)

    auditlog_api_parameters = {
        'object_model': 'interface',
        'object_pks': ','.join([str(i.pk) for i in interfaces]),
        'subsystem': 'portadmin',
    }

    info_dict = get_base_context([(netbox.sysname, )], form=get_form(request))
    info_dict.update({
        'handlertype':
        type(handler).__name__,
        'interfaces':
        interfaces,
        'netbox':
        netbox,
        'voice_vlan':
        voice_vlan,
        'allowed_vlans':
        allowed_vlans,
        'readonly':
        readonly,
        'aliastemplate':
        aliastemplate,
        'trunk_edit':
        CONFIG.get_trunk_edit(),
        'auditlog_api_parameters':
        json.dumps(auditlog_api_parameters),
    })
    return info_dict