Skip to content

Commit

Permalink
initial commit
Browse files Browse the repository at this point in the history
  • Loading branch information
derek-shnosh committed Aug 27, 2019
1 parent 24a2c01 commit 8538c8e
Show file tree
Hide file tree
Showing 4 changed files with 225 additions and 0 deletions.
92 changes: 92 additions & 0 deletions readme.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
# FreeZTP Provisioning Watcher

Watches specified directory for [FreeZTP][freeztp] custom merged-config files which are created after a switch is successfully provisioned. File name is parsed for hostname and host IP address to initiate a TFTP transfer of the specified IOS image.

_**Use-case**_: Copy IOS image .bin file to C2960X switch post FreeZTP provisioning to avoid the auto-install function using a .tar file (lengthy process).

## Considerations

- Ensure that FreeZTP **imagediscoveryfile-option** is set to **disable**.

```bash
ztp set dhcpd INTERFACE-{dhcp_interface} imagediscoveryfile-option disable
```

- Custom merged-config file syntax must begin with **{{keystore_id}}_{{ipaddr}}**; e.g.

`{{keystore_id}}_{{ipaddr}}_{{idarray|join("-")}}_merged.cfg`

_**Full custom log file config example...**_

```bash
ztp set logging merged-config-to-custom-file '/etc/ztp/logs/merged/{{association}}/{{keystore_id}}_{{ipaddr}}_{{idarray|join("-")}}_merged.cfg'
```

\*_**Suggestion**_: Disable logging merged configs to the main log file via;

```bash
ztp set logging merged-config-to-mainlog disable
```

## Installation/Usage

1. Clone repo to desired location.

```bash
sudo git clone {URL} /var/git/ztp-watcher
```

2. Edit **ztp-watcher.service** systemd unit file with path.

```bash
sudo nano /var/git/ztp-watcher/ztp-watcher.service
```

- _**Edit `ExecStart` and `WorkingDirectory` paths accordingly**_

```bash
...
ExecStart=/bin/bash -c 'cd /var/git/ztp-watcher; python3 ztp-watcher.py'
WorkingDirectory=/var/git/ztp-watcher/
...
```

3. Make a copy of **ztpconfig_sample.yaml** as **ztpconfig.yaml** and edit for environment.

```bash
sudo cp /var/git/ztp-watcher/ztpconfig_sample.yaml /var/git/ztp-watcher/ztpconfig.yaml
sudo nano /var/git/ztp-watcher/ztpconfig.yaml
```

- _**Edit values accordingly**_
> **watch_dir** must match path from the `ztp set logging merged-config-to-custom-file` path.

```yaml
logfile: '/etc/ztp/logs/ztpwatcher.log'
watch_dir: '/etc/ztp/logs/merged/'
tftpaddr: '172.17.251.251'
imgfile: 'c2960x-universalk9-mz.152-4.E8.bin'
username: 'cisco'
password: 'cisco'
```

5. Copy **.service** file to **/etc/systemd/system/**, then enable and start it.

```bash
cp /{path}/ztp-watcher.service /etc/systemd/system/
sudo systemctl enable ztp-watcher.service
sudo systemctl start ztp-watcher.service
```

## References

- https://github.com/PackeTsar/freeztp/
- https://github.com/torfsen/python-systemd-tutorial
- https://pynet.twb-tech.com/blog/nornir/intro.html
- https://pynet.twb-tech.com/blog/nornir/os-upgrade-p1.html
- https://www.michaelcho.me/article/using-pythons-watchdog-to-monitor-changes-to-a-directory




[freeztp]: https://github.com/PackeTsar/freeztp/
114 changes: 114 additions & 0 deletions ztp-watcher.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
#!/usr/bin/python3
# Author: DS, Synergy Information Solutions, Inc.


import time
import os
import threading
import logging
import yaml
from watchdog.observers import Observer
from watchdog.events import FileSystemEventHandler
from nornir import InitNornir
from nornir.plugins.tasks.networking import netmiko_send_command


with open('./ztpconfig.yaml', 'r') as f:
config = yaml.safe_load(f)

logfile = config['logfile']
watch_dir = config['watch_dir']
tftpaddr = config['tftpaddr']
imgfile = config['imgfile']
username = config['username']
password = config['password']

ignorefiles = ['.swp', '.save']


def std_log(agg_result):
for k, multi_result in agg_result.items():
for result_obj in multi_result:
Logger(f'{k}\n{result_obj.result}')


class Logger:

def __init__(self, logdata):
logging.basicConfig(format='\n%(asctime)s %(message)s',
datefmt='%m/%d/%Y %I:%M:%S %p',
filename=logfile,
level=logging.INFO)
logging.info(f'-- {logdata}')


class Watcher:

def __init__(self):
self.observer = Observer()

def run(self):

event_handler = Handler()
self.observer.schedule(event_handler, watch_dir, recursive=False)
self.observer.start()
Logger('Starting FreeZTP Provisioning Watcher.')
try:
while True:
time.sleep(5)

except KeyboardInterrupt:
self.observer.stop()
print('\nKeyboard interrupt.')
Logger('Stopping FreeZTP Provisioning Watcher (Keyboard interrupt).')

except:
self.observer.stop()
print('Error.')
Logger('Error.\n')


class Handler(FileSystemEventHandler):

def os_upgrade(self, hostname, hostaddr, tftpaddr, imgfile):
nr = InitNornir(
inventory={
'options': {
'hosts': {
hostname: {
'hostname': hostaddr,
'username': username,
'password': password,
'platform': 'ios'
}
}
}
}
)
result = nr.run(
task=netmiko_send_command,
command_string=f'copy tftp://{tftpaddr}/{imgfile} flash:',
delay_factor=6,
)
std_log(result)

def on_created(self, event):

if event.is_directory:
return None

else:
newfile = event.src_path.rpartition('/')[2]
if not any(str in newfile for str in ignorefiles):
Logger(f'File created: {newfile}')
hostname = newfile.split('_')[0]
hostaddr = newfile.split('_')[1]
Logger(f'Transferring file to {hostname} (IP: {hostaddr}).')
x = threading.Thread(target=self.os_upgrade, args=(
hostname, hostaddr, tftpaddr, imgfile))
x.start()


if __name__ == '__main__':
w = Watcher()
w.run()
13 changes: 13 additions & 0 deletions ztp-watcher.service
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
[Unit]
Description=FreeZTP Provisioning Watcher
After=network.target

[Service]
ExecStart=/bin/bash -c 'cd /var/git/ztp-watcher; python3 ztp-watcher.py'
WorkingDirectory=/var/git/ztp-watcher/
Environment=PYTHONUNBUFFERED=1
Type=simple
Restart=on-abort

[Install]
WantedBy=multi-user.target
6 changes: 6 additions & 0 deletions ztpconfig_sample.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
logfile: /etc/ztp/logs/ztpwatcher.log
watch_dir: /etc/ztp/logs/merged/
tftpaddr: 172.17.251.251
imgfile: c2960x-universalk9-mz.152-4.E8.bin
username: cisco
password: cisco

0 comments on commit 8538c8e

Please sign in to comment.