Skip to content

Commit

Permalink
Merge pull request #139 from SUNET/feature.post_flight_check
Browse files Browse the repository at this point in the history
Post flight task for firmware upgrades
  • Loading branch information
indy-independence authored Nov 2, 2020
2 parents 4640b86 + 3eec27f commit 8394167
Show file tree
Hide file tree
Showing 4 changed files with 184 additions and 44 deletions.
12 changes: 10 additions & 2 deletions docs/apiref/firmware.rst
Original file line number Diff line number Diff line change
Expand Up @@ -152,15 +152,17 @@ The API method will accept a few parameters:
* filename: Mandatory. Name of the new firmware, for example "test.swi".
* url: Optional, can also be configured as an environment variable, FIRMQRE_URL. URL to the firmware storage, for example "http://hostname/firmware/". This should typically point to the CNaaS NMS server and files will be downloaded from the CNaaS HTTP server.
* download: Optional, default is false. Only download the firmware.
* pre_flight: Optional, default is false. If false, check disk-space etc before downloading the firmware.
* pre_flight: Optional, default is false. If true, check disk-space etc before downloading the firmware.
* post_flight: Optional, default is false. If true, update OS version after the upgrade have been finished.
* post_waittime: Optional, default is 0. Defines the time we should wait before trying to connect to an updated device.
* activate: Optional, default is false. Control whether we should install the new firmware or not.
* reboot: Optional, default is false. When the firmware is downloaded, reboot the switch.
* start_at: Schedule a firmware upgrade to be started sometime in the future.

An example CURL command can look like this:
::

curl -k -s -H "Content-Type: application/json" -X POST https://hostname/api/v1.0/firmware/upgrade -d '{"group": "ACCESS", "filename": "test_firmware.swi", "url": "http://hostname/", "pre-flight": true, "download": true, "activate": true, "reboot": true, "start_at": "2019-12-24 00:00:00"}'
curl -k -s -H "Content-Type: application/json" -X POST https://hostname/api/v1.0/firmware/upgrade -d '{"group": "ACCESS", "filename": "test_firmware.swi", "url": "http://hostname/", "pre-flight": true, "download": true, "activate": true, "reboot": true, "start_at": "2019-12-24 00:00:00", "post_flight": true, "post_waittime": 600'}

The output from the job will look like this:

Expand Down Expand Up @@ -207,6 +209,12 @@ The output from the job will look like this:
"result": "Device reboot done.",
"diff": "",
"failed": false
},
{
"result": "Post-flight, OS version updated for device eosaccess, now 4.23.2F-15405360.4232F.",
"task_name": "arista_post_flight_check",
"diff": "",
"failed": false
}
],
"_totals": {
Expand Down
2 changes: 1 addition & 1 deletion src/cnaas_nms/api/device.py
Original file line number Diff line number Diff line change
Expand Up @@ -501,7 +501,7 @@ def post(self):
else:
return empty_result(
status='error',
data=f"No devices to synchronize was specified"
data=f"No devices to synchronize were specified"
), 400

scheduler = Scheduler()
Expand Down
66 changes: 53 additions & 13 deletions src/cnaas_nms/api/firmware.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,9 @@
import requests

from datetime import datetime
from typing import Optional

from flask import request
from flask import request, make_response
from flask_restx import Resource, Namespace, fields
from flask_jwt_extended import jwt_required, get_jwt_identity

Expand All @@ -14,6 +15,9 @@
from cnaas_nms.tools.log import get_logger
from cnaas_nms.tools.get_apidata import get_apidata
from cnaas_nms.version import __api_version__
from cnaas_nms.confpush.nornir_helper import cnaas_init, inventory_selector
from cnaas_nms.db.device import Device
from cnaas_nms.db.settings import get_groups

logger = get_logger()

Expand All @@ -36,6 +40,8 @@
'group': fields.String(required=False),
'hostname': fields.String(required=False),
'pre_flight': fields.Boolean(required=False),
'post_flight': fields.Boolean(required=False),
'post_wattime': fields.Integer(required=False),
'reboot': fields.Boolean(required=False)})


Expand Down Expand Up @@ -240,26 +246,56 @@ def post(self):
return empty_result(status='error',
data='pre_flight should be a boolean')

if 'post_flight' in json_data:
if isinstance(json_data['post_flight'], bool):
kwargs['post_flight'] = json_data['post_flight']
else:
return empty_result(status='error',
data='post_flight should be a boolean')

if 'post_waittime' in json_data:
if isinstance(json_data['post_waittime'], int):
kwargs['post_waittime'] = json_data['post_waittime']
else:
return empty_result(status='error',
data='post_waittime should be an integer')

if 'filename' in json_data:
if isinstance(json_data['filename'], str):
kwargs['filename'] = json_data['filename']
else:
return empty_result(status='error',
data='filename should be a string')

if 'group' in json_data:
if isinstance(json_data['group'], str):
kwargs['group'] = json_data['group']
else:
return empty_result(status='error',
data='group should be a string')
total_count: Optional[int] = None
nr = cnaas_init()

if 'hostname' in json_data:
if isinstance(json_data['hostname'], str):
kwargs['hostname'] = json_data['hostname']
else:
return empty_result(status='error',
data='hostname should be a string')
hostname = str(json_data['hostname'])
if not Device.valid_hostname(hostname):
return empty_result(
status='error',
data=f"Hostname '{hostname}' is not a valid hostname"
), 400
_, total_count, _ = inventory_selector(nr, hostname=hostname)
if total_count != 1:
return empty_result(
status='error',
data=f"Hostname '{hostname}' not found or is not a managed device"
), 400
kwargs['hostname'] = hostname
elif 'group' in json_data:
group_name = str(json_data['group'])
if group_name not in get_groups():
return empty_result(status='error', data='Could not find a group with name {}'.format(group_name))
kwargs['group'] = group_name
_, total_count, _ = inventory_selector(nr, group=group_name)
kwargs['group'] = group_name
else:
return empty_result(
status='error',
data=f"No devices to upgrade were specified"
), 400

if 'start_at' in json_data:
try:
Expand All @@ -286,7 +322,11 @@ def post(self):
res = empty_result(data='Scheduled job to upgrade devices')
res['job_id'] = job_id

return res
resp = make_response(json.dumps(res), 200)
if total_count:
resp.headers['X-Total-Count'] = total_count
resp.headers['Content-Type'] = "application/json"
return resp


# Firmware
Expand Down
Loading

0 comments on commit 8394167

Please sign in to comment.