Monday 19 February 2024

netmiko - show command

import netmiko
import re

ip = 'sbx-nxos-mgmt.cisco.com'
username = 'admin'
password = '<removed>'
device_type = 'cisco_xe'
port = '22'

net_connect = netmiko.ConnectHandler(ip=ip, device_type=device_type, username=username, password=password, port=port)

show_run = net_connect.send_command('show run')
show_ip_route = net_connect.send_command('show ip route')
print(show_run)
print('*'*100,)
print(show_ip_route)

Thursday 19 May 2022

Ansible and ACI

These are some ansible playbooks to do basic configuration on Cisco ACI using ansible.
Information taken from here:

https://github.com/CiscoDevNet/aci_ansible_learning_labs_code_samples/

"inventory" should look like this:

[apic:vars]

username=admin
password=<removed>
ansible_python_interpreter="/home/username/ansible/aci_ansible_learning_labs_code_samples/venv/bin/python"

[apic]

sandboxapicdc.cisco.com

1. Create Tenant:

---
- name: ENSURE APPLICATION CONFIGURATION EXISTS
  hosts: apic
  connection: local
  gather_facts: False
  vars_prompt:
    - name: "tenant"
      prompt: "What would you like to name your Tenant?"
      private: no

  tasks:
    - name: ENSURE APPLICATIONS TENANT EXISTS
      aci_tenant:
        host: "{{ ansible_host }}"
        username: "{{ username }}"
        password: "{{ password }}"
        state: "present"
        validate_certs: False
        tenant: "{{ tenant }}"
        description: "Tenant Created Using Ansible"


ansible-playbook -i inventory 01_aci_tenant_pb.yml


What would you like to name your Tenant?: test-tenant

PLAY [ENSURE APPLICATION CONFIGURATION EXISTS] *********************************************************************

TASK [ENSURE APPLICATIONS TENANT EXISTS] ***************************************************************************
changed: [sandboxapicdc.cisco.com]

PLAY RECAP *********************************************************************************************************
sandboxapicdc.cisco.com    : ok=1    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0  

2. Create Tenant, VRF and Bridge Domain:

! This is a modified version of the playbook which assumes that the tenant does not exists and prompts for both the tenant and VRF name to be created.

---
- name: ENSURE APPLICATION CONFIGURATION EXISTS
  hosts: apic
  connection: local
  gather_facts: False
  vars_prompt:
    - name: "tenant"
      prompt: "What would you like to name your Tenant?"
      private: no
    - name: "vrf"
      prompt: "What would you like to name your VRF?"
      private: no

  tasks:
    - name: ENSURE APPLICATIONS TENANT EXISTS
      aci_tenant:
        host: "{{ ansible_host }}"
        username: "{{ username }}"
        password: "{{ password }}"
        state: "present"
        validate_certs: False
        tenant: "{{ tenant }}"
        description: "Tenant Created Using Ansible"

    - name: ENSURE TENANT VRF EXISTS
      aci_vrf:
        host: "{{ ansible_host }}"
        username: "{{ username }}"
        password: "{{ password }}"
        state: "present"
        validate_certs: False
        tenant: "{{ tenant }}"
        vrf: "{{ vrf }}"
        description: "VRF Created Using Ansible"

    - name: ENSURE TENANT BRIDGE DOMAIN EXISTS
      aci_bd:
        host: "{{ ansible_host }}"
        username: "{{ username }}"
        password: "{{ password }}"
        state: "present"
        validate_certs: False
        tenant: "{{ tenant }}"
        bd: "{{ bd | default('prod_bd') }}"
        vrf: "{{ vrf }}"
        description: "BD Created Using Ansible"

    - name: ENSURE BRIDGE DOMAIN SUBNET EXISTS
      aci_bd_subnet:
        host: "{{ ansible_host }}"
        username: "{{ username }}"
        password: "{{ password }}"
        state: "present"
        validate_certs: False
        tenant: "{{ tenant }}"
        bd: "{{ bd | default('prod_bd') }}"
        gateway: "10.10.101.1"
        mask: 24
        description: "Subnet Created Using Ansible"


ansible-playbook 02_aci_tenant_network_pb.yml -i inventory

What would you like to name your Tenant?: test-tenant
What would you like to name your VRF?: test-VRF

PLAY [ENSURE APPLICATION CONFIGURATION EXISTS] *******************************************************************************

TASK [ENSURE APPLICATIONS TENANT EXISTS] *************************************************************************************
changed: [sandboxapicdc.cisco.com]

TASK [ENSURE TENANT VRF EXISTS] **********************************************************************************************
changed: [sandboxapicdc.cisco.com]

TASK [ENSURE TENANT BRIDGE DOMAIN EXISTS] ************************************************************************************
changed: [sandboxapicdc.cisco.com]

TASK [ENSURE BRIDGE DOMAIN SUBNET EXISTS] ************************************************************************************
changed: [sandboxapicdc.cisco.com]

PLAY RECAP *******************************************************************************************************************
sandboxapicdc.cisco.com    : ok=4    changed=4    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0  

Paramiko - config grab with Cisco IOS

import time
import paramiko
import getpass
from datetime import datetime

routers = ["192.168.0.1"]
username = raw_input("Please enter your username: ")
password = getpass.getpass("Please enter your password: ")

now_time = datetime.now()
str_now_time = str(now_time)

sshcon = paramiko.SSHClient()
sshcon.set_missing_host_key_policy(paramiko.AutoAddPolicy())
for target in routers:
f = open("{0}-{1}-txt".format(target,str_now_time) , "w")
print ('Attempting to connect to {0}'.format(target))
sshcon.connect(hostname=target,username=username,password=password,look_for_keys=False)
remote_connection = sshcon.invoke_shell()
remote_connection.send("ter len 0\n")
time.sleep(5)
remote_connection.send("show run\n")
time.sleep(5)
output = remote_connection.recv(65535)
# print(output)
print ('Writing config to file')
f.write(output)
sshcon.close
print("Job completed successfully")

Friday 19 November 2021

Making a Raspberrypi Stop Motion Video

This guide explains how to make a stop motion video using a raspberrypi with the camera module. As part of this exercise I also wanted to transfer the file over to another remote PC in an automated fashion.
The reason I wanted to do this was the using video made the filesize umanageable. With stop motion you can alter the interval, duration of process etc.

High level steps:

1. pi1 takes a picture every 10 seconds 
2. pi1 copies the picture to pi2
3. pi1 deletes the local copy and takes another picture and repeats the process.
4. On pi2 there is a scheduled cronjob that creates a video from the still images and then deletes the images files.

On pi1:

Create a folder to store our images:
mkdir /home/pi/camera

Create a script to capture the images:

sudo nano /home/pi/camera.sh

Add the following to the camera.sh shell script. The script itself runs through a for loop, you can see in this example it runs through 3600 iterations.  Within the loop the script takes a picture and outputs it to a file with a filename called picture-i (where i is the number where we are in the loop). The script then pauses for 10 seconds. This means that this script would take roughly 10 hours to work through the loop until it stops - you can obviously modify the values to suit your needs.  The script then writes the file to pi2 using scp - you need to have already setup ssh login without password for this to work. The script then deletes the local file and returns to the start of the loop. The deletion of the local file is purely to save space - it is not compulsory:

#!/bin/bash

#DATE=$(date +"%Y-%m-%d_%H%M%S")

for ((i=1; i<=3600; i++))

do

        DATE=$(date +"%Y-%m-%d_%H-%M-%S")

        echo "*** Taking Picture $i ***" 

        raspistill -o /home/pi/camera/picture-$i.jpg

        sleep 10


        echo "*** Writing file $i to remote server ***"

        scp /home/pi/camera/*.jpg pi@pi2:/home/pi/camera

        rm /home/pi/camera/*.jpg

done

Press CTRL + X, followed by Y to close the file and save it:

Make the script executable:
sudo chmod +x camera.sh

Now we move to pi2

Create a folder to store our images:
mkdir /home/pi/camera

Back on pi1 if we execute the script we should the .jpg files appearing in our folder on pi2.
cd /home/pi/camera
./camera.sh

We now need a method to create the video from the still images and delete the images to save space.

Create a script to make the video:
sudo nano /home/pi/make-video.sh

Add the following:
!/bin/bash

#DATE=$(date +"%Y-%m-%d_%H%M%S")

ffmpeg -framerate 25 -i /home/pi/camera/picture-%d.jpg /home/pi/Video-$(date +%d-%m-%Y-%H-%M).mp4

rm /home/pi/camera/*.jpg


Press CTRL + X, followed by Y to close the file and save it:

Make the script executable:
sudo chmod +x make-video.sh

Executing this script uses ffmpeg to create a video file at 25fps using the current date and time in the filename. It then removes all .jpg files from the folder.

Finally we create a cronjob to create the video periodically:

crontab -e

Add the following:
0 8 * * * sh /home/pi/camera/make-video.sh

This will run the script at 8am every day.

You can also create a cronjob on p1 to automate the other script.

crontab -e

Add the following:

15 8 * * * sh /home/pi/camera/camera.sh

Thursday 18 February 2021

BIG-IP

! Load factory default cofig
tmsh load /sys config default

! Run management interface setup utility
config# config



Tuesday 2 February 2021

F5 BIGIP Ansible

See here for more info:

https://github.com/F5Networks/f5-ansible/blob/devel/examples/0000-getting-started/playbook.yaml

Directory structure looks like this:

├── inventory

│   └── hosts

└── playbook.yaml

"hosts" file contains a single entry "localhost" (the F5 IP address is defined within the script).


<save the below to playbook.yaml>

 ---


- name: Create a VIP, pool and pool members

  hosts: all

  connection: local


  vars:

    provider:

      password: admin

      server: 192.168.1.245

      user: admin

      validate_certs: no

      server_port: 443


  tasks:

    - name: Create a pool

      bigip_pool:

        provider: "{{ provider }}"

        lb_method: ratio-member

        name: web

        slow_ramp_time: 120

      delegate_to: localhost


    - name: Add members to pool

      bigip_pool_member:

        provider: "{{ provider }}"

        description: "webserver {{ item.name }}"

        host: "{{ item.host }}"

        name: "{{ item.name }}"

        pool: web

        port: 80

      with_items:

        - host: 10.10.10.10

          name: web01

        - host: 10.10.10.20

          name: web02

      delegate_to: localhost


    - name: Create a VIP

      bigip_virtual_server:

        provider: "{{ provider }}"

        description: foo-vip

        destination: 172.16.10.108

        name: vip-1

        pool: web

        port: 80

        snat: Automap

        profiles:

          - http

          - clientssl

      delegate_to: localhost


Friday 9 November 2018

Script to create tenant / app profile / EPG

#   Note that this script expects HTTP port 80 on the APIC, which is off by default.
# To enable HTTP in the APIC, navigate to FABRIC, FABRIC POLICIES Pod Policies     Policies   Management Acces    default  then enable HTTP
import requests
import json

def get_cookies(apic):
    username = 'admin'
    password = 'ciscoapic'
    url = apic + '/api/aaaLogin.json'
    auth = dict(aaaUser=dict(attributes=dict(name=username, pwd=password)))
    authenticate = requests.post(url, data=json.dumps(auth), verify=False)
    return authenticate.cookies

def add_tenant(apic,cookies):
    jsondata = {"fvTenant":{"attributes":{"dn":"uni/tn-acme","name":"acme","rn":"tn-acme","status":"created"},"children":[]}}
    result = requests.post('{0}://{1}/api/node/mo/uni/tn-acme.json'.format(protocol,host), cookies=cookies, data=json.dumps(jsondata), verify=False)
    print result.status_code
    print result.text

def get_tenants(apic,cookies):
    uri = '/api/class/fvTenant.json'
    url = apic + uri
    req = requests.get(url, cookies=cookies, verify=False)
    response = req.text
    return response

def add_application_profile(apic,cookies):
    jsondata = {"fvAp":{"attributes":{"dn":"uni/tn-acme/ap-Accounting","name":"Accounting","rn":"ap-Accounting","status":"created"},"children":[]}}
    result = requests.post("{0}://{1}/api/node/mo/uni/tn-acme/ap-Accounting.json".format(protocol, host), cookies=cookies, data=json.dumps(jsondata), verify=False)
    print result.status_code
    print result.text

def add_EPG1(apic,cookies):
    jsondata = {"fvAEPg":{"attributes":{"dn":"uni/tn-acme/ap-Accounting/epg-Payroll","name":"Payroll","rn":"epg-Payroll","status":"created"},"children":[{"fvCrtrn":{"attributes":{"dn":"uni/tn-acme/ap-Accounting/epg-Payroll/crtrn","name":"default","rn":"crtrn","status":"created,modified"},"children":[]}}]}}
    result = requests.post("{0}://{1}/api/node/mo/uni/tn-acme/ap-Accounting/epg-Payroll.json".format(protocol, host), cookies=cookies, data=json.dumps(jsondata), verify=False)
    print result.status_code
    print result.text

def add_EPG2(apic,cookies):
    jsondata = {"fvAEPg":{"attributes":{"dn":"uni/tn-acme/ap-Accounting/epg-Bills","name":"Bills","rn":"epg-Bills","status":"created"},"children":[{"fvCrtrn":{"attributes":{"dn":"uni/tn-acme/ap-Accounting/epg-Bills/crtrn","name":"default","rn":"crtrn","status":"created,modified"},"children":[]}}]}}
    result = requests.post("{0}://{1}/api/node/mo/uni/tn-acme/ap-Accounting/epg-Bills.json".format(protocol, host), cookies=cookies, data=json.dumps(jsondata), verify=False)
    print result.status_code
    print result.text

if __name__ == "__main__":
    protocol = 'http'
    host = '192.168.10.1'
    apic = '{0}://{1}'.format(protocol, host)
    cookies = get_cookies(apic)
    add_tenant(apic,cookies)
    add_application_profile(apic,cookies)
    add_EPG1(apic,cookies)
    add_EPG2(apic,cookies)
    rsp = get_tenants(apic,cookies)

rsp_dict = json.loads(rsp)
tenants = rsp_dict['imdata']

for tenant in tenants:
    print tenant['fvTenant']['attributes']['name']