Justin Cooksey

So, moving to Linux ...

I've been using MacOS for a few years now for my own development environment, and always enjoyed using something different from the required work Windows systems. MacOS, and Apple hardware, have always been pretty on point in my oppinion. However, for a while now, I'd wanted to jump back in to Linux as my primary OS. I have already been moving away from commercial applications, getting rid of my Adobe account and migrating to using Darktable along with other subscription based applications (not all). This is my inital experience migrating from developing on Windows and MacOS to developing on Linux, or in particular Fedora 41.

Most of my development work is in Python, although work means I do a fair share of PowerShell, so the initial focus is around Python and getting my normal tools up and running.

Visual Studio Code

Visual Studio Code (VSCode) does come as a FlatPak via the Software app in Fedora 41, and its a pretty recent version (as of time of writting) at 1.96.1 with the latest being 1.96.4. However I opted to install directly off the VSCode web site and use the rpm download. This installed without any issues and the Fedora Software app does show it as installed after using this method. I had no issues at all on first run and syning in the Extenxsion I use by sing Setting Sync to replicate what I have on my MacOS machine.

Shell

I haven't yet explored and/or moved to ZSH at this time. I know that along with Oh My Zsh it makes for a pretty useful Shell, but at this point I'm sticking with the default bash and will look at options little later on.

Python

Fedora 41 came with Python 3.13.1, which at the time of writing is the latest release version of Python. Sometimes though we need to be able to run our code against other, older versions of Python. Enter pyenv ...

pyenv

If you havent used pyenv before the Real Python site has a great article on Managing Multiple Python Versions With pyenv

pyenv took a little bit longer to get operational. This was because the default install of Fedora 41 does not install development packages, so I had to do a little research and test and research again before I got it all working. First off was to install the development-tools group of packages after which I still had some missing libraries to add in as well. The final result is as follows:

sudo dnf install @development-tools
sudo dnf install python3-tkinter python3-xlib bzip2-devel ncurses-devel libffi-devel readline-devel tk-devel libsqlite3x-devel

This has now allowed me to install and use other versions of Python on my Fedora 41 based laptop. Which means I can now update this web site with this article ...

Justin Cooksey

Well it was bound to happen! Three years now after being asked to migrate DHCP from Windows DHCP server to Cisco Routers, and automating that convertion, it's finally going back the other way.

This time the PowerShell script will read through the file (an exported Cisco Router configuration) and build the Scopes in the Windows DHCP Role. The script will need to be run on the server becoming the DHCP server for those new scopes. The user would need to have administrator privilege to allow the DHCP settings to be made.

The script follows these steps:

  1. Reads through the configuration file and, using Regular Expressions, finds all DHCP Pools (Scopes), Static Assignments and Exclusions.
  2. Creates all the Scopes, along with all options found under that Pool in the router configuration file.
  3. Processes the Exclusions in to each Scope
  4. Process all static assignments

Still a little bit in the works at the time of this posting, but testing across multiple configurations has found it working well. The Code Repository can be found on GitHub

Some DHCP Options are being handled as follows.

Code Cisco Config Option Description
3 default-router Default Gateway
6 dns-server Domain Nameservers
15 domain-name Domain Name
42 option 42 ip NTP Servers
43 option 43 hex Vendor Specific Option, usually WAP Controller IP
51 lease Lease time
66 next-server TFTP Server
66 option 66 ip TFTP Server
67 bootfile Boot filename
67 option 67 ascii Boot filename

Example Cisco Config

ip dhcp excluded-address 10.10.0.1 10.10.1.0
ip dhcp excluded-address 10.10.3.220 10.10.3.223
ip dhcp excluded-address 192.168.0.1 192.168.0.9
!
ip dhcp pool PoolNumber1
 network 10.10.0.0 255.255.248.0
 update dns both override
 dns-server 10.10.255.1 10.10.255.2 
 domain-name domainname.local
 option 42 ip 10.10.249.11 10.10.248.11 
 default-router 10.10.0.1 
 lease 8
!
ip dhcp pool PoolNumber2
 network 192.168.0.0 255.255.255.0
 dns-server 192.168.0.10
 option 43 hex f108.0afe.0064
 default-router 192.168.0.1
!
ip dhcp pool Device1
 host 10.10.1.30 255.255.248.0
 client-identifier 01b7.37eb.1f1a.0a
 default-router 10.10.0.1 
!
ip dhcp pool Device2
 host 192.168.0.44 255.255.255.0
 client-identifier 0132.c19f.b7f3.3b

This script makes use of the IPv4Calc Module

Justin Cooksey

Ansible and Netbox are not just for the high end data centre systems. They can also be used on networks using small to medium business switches and routers such as the Cisco SMB Product range.

Initial Auditing and OnBoarding

Initally I started with brand new empty Netbox. In which I manually created a base setup adding in each:

  • Site
  • Patch
  • Device model in use
  • Prefix, to begin with just the management subnets

Then creating a yaml file host listing to beging with, I ran an Ansible Playbook that then went through that list of devices pulling base device information:

  • IP Address (Management)
  • Hostname
  • Model
  • Serial number
  • Firmware (This was not initally used)

This was then to record in to Netbox as new devices as well as exported to CSV. After I had the devices in Netbox I could do some base housekeeping and put them in the right sites, patches and rack locations.

Netbox, the Source of Truth

Once the devices were in and housekeeping done Netbox then became the Source of Truth for both our engineers and technicians and also for Ansible. I could remove the hosts yaml file an dpointing AQnsible at Netbox for its inventory I could now allow playbooks to be run against a site and other locations or across the whole group.

Minimum config

One of the frist tasks was to ensure I had all devices, configured to a standard. I hoped that they have been, but over time, without continued audits and checks, things can become a little out. So using Ansible I was able to ensure some defaults are set, such has:

  • Disabling of access methods, such as HTTP, Telnet and also HTTPS
  • NTP time servers and synchronised time
  • Name Servers
  • Monitoring service setting (SNMP)

Backup config

Another task for Ansible was to get regular configuration backups for all devices. Running an Ansible Playbook on a daily schedule (Cron) to pull the current configuration and store it on the local file system of the Ansible server. This was then replicated off site over secure protocols.

- name: Gather Facts
  gather_facts: no
  hosts: device_roles_switch
  vars:
    output_path: "{{ lookup('env', 'HOME') }}/backups/"

  tasks:
    ## Create backup folder for today
    - name: Get date stamp for filename creation
      set_fact: date="{{lookup('pipe','date +%Y%m%d')}}"
      run_once: true

    # Get Switch Config
    - name: Get Config
      community.ciscosmb.facts:
        gather_subset:
          - config

    - name: Save Config
      copy:
        content: "{{ ansible_net_config }}"
        dest: "{{ output_path }}{{ inventory_hostname }}-{{ date }}.txt"

Finding Trunks and Devices

Another task was find all the trunks between switches & patches and docuemnt them correctly in Netbox. Running an Ansible Playbook to use LLDP from gather facts to then determine th elinks between device, that could then be documented as Netbox cables. Once that was done I also used the Netbox Topology Views plugin to visualise the network.

Once that was done I could also use MAC address searches to determine what ports IP Phones, DAPs and WAPs were connected to among other devices. Since a standard brand of those was used throughout it was only a matter of searching for the manufacturer portion of the MAC address.