Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Post flight task for firmware upgrades #139

Merged
merged 17 commits into from
Nov 2, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
17 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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