from first import first
from jnpr.healthbot.exception import SchemaError, NotFoundError
from jnpr.healthbot.swagger.models.device_schema import DeviceSchema
from jnpr.healthbot.swagger.models.device_group_schema import DeviceGroupSchema
from jnpr.healthbot.swagger.models.network_group_schema import NetworkGroupSchema
from jnpr.healthbot.swagger.models.device_health_tree import DeviceHealthTree
from jnpr.healthbot.swagger.models.device_group_health_tree import DeviceGroupHealthTree
from jnpr.healthbot.swagger.models.network_health_tree import NetworkHealthTree
from jnpr.healthbot.modules import BaseModule
import logging
logger = logging.getLogger(__file__)
[docs]class Device(BaseModule):
[docs] def __init__(self, hbot):
"""
:param object hbot: :class:`jnpr.healthbot.HealthBotClient` client instance
"""
super().__init__(hbot)
[docs] def add(self, device_id: str = None, host: str = None,
username: str = None, password: str = None,
schema: DeviceSchema = None, **kwargs):
"""
Add device to HealthBot
:param str device_id: The name of the device as provided by the User
:param str host: The hostname/ip-address of the target device
:param str username: The login user-name for the target device
:param str password: The login password for the user
:param object schema: `DeviceSchema <jnpr.healthbot.swagger.models.html#deviceschema>`_
Example:
::
from jnpr.healthbot import HealthBotClient
from jnpr.healthbot import DeviceSchema
with HealthBotClient('xx.xxx.x.xx', 'xxxx', 'xxxx') as hb:
ds = DeviceSchema(device_id='xyz', host='xx.xxx.xxx.xxx',
authentication={"password": {"password": "xxxxx", "username": "xxxxx"}})
# we can also later assign values like this
ds.description = "HbEZ testing"
# This will add device in candidate DB
hb.device.add(schema=ds)
# commit changes to master DB
hb.commit()
"""
def _add_device(device_id=None):
if kwargs:
if schema is not None:
raise SystemError("schema and kwargs are mutually exclusive")
device_schema = DeviceSchema(device_id=device_id, host=host, **kwargs)
if username is not None and password is not None:
device_schema.authentication = {
"password": {
"password": password,
"username": username
}
}
payload = self.hbot._create_payload(device_schema)
elif schema is not None:
payload = self.hbot._create_payload(schema)
device_id = schema.device_id
else:
payload = {
"authentication": {
"password": {
"password": password,
"username": username
}
},
"device-id": device_id,
"host": host,
}
url = self.hbot.urlfor.device(device_id)
response = self.api.post(url, json=payload)
if response.status_code != 200:
logger.error(response.text)
response.raise_for_status()
return True
if schema is not None:
if not isinstance(schema, DeviceSchema):
raise SchemaError(DeviceSchema)
device_id = schema.device_id
host = schema.host
devices_list_url = self.hbot.urlfor.devices() + self.hbot.apiopt_candidate
resp = self.api.get(devices_list_url)
# The API will return a 404 if there are no devices in the system. We need to check for
# this condition
if resp.status_code == 404:
return _add_device(device_id)
# examine the existing devices and see if there is one that already
# exists by this name and host values
existing_devices = resp.json()['device']
found = first(
filter(
lambda i: i['device-id'] == device_id and i['host'] == host,
existing_devices))
if found:
logger.debug(
"Device with given device-id '{}' already exists. Updating same.".format(device_id))
# if we are here, then we need to add this new device
return _add_device(device_id)
[docs] def delete(self, device_id: str, force: bool = False):
"""
Remove device from HealthBot
:param str device_id: The name of the device as provided by the User
:param bool force: If True, Delete given device from all the device
group (if present)
Example:
::
from jnpr.healthbot import HealthBotClient
with HealthBotClient('xx.xxx.x.xx', 'xxxx', 'xxxx') as hb:
# This will delete device in candidate DB
hb.device.delete('xyz')
# commit changes to master DB
hb.commit()
:returns: True when OK
"""
device_url = self.hbot.urlfor.device(device_id)
if force:
groups_list_url = self.hbot.urlfor.device_groups()
# Remove Device from the Device Group (requirement before removing
# Device)
device_groups_response = self.api.get(groups_list_url)
# device_groups is the list of dictionaries, each containing the information of
# device groups present in HBot
device_groups = device_groups_response.json()
for each_device_group in device_groups["device-group"]:
device_list = each_device_group['devices']
device_group_name = each_device_group['device-group-name']
# checking if the given device_id present in this device group
if device_id in device_list:
# Delete the device from the device group
device_list.remove(device_id)
dev_grp_schema = self.hbot.device_group.get(
device_group_name)
dev_grp_schema.devices = device_list
self.hbot.device_group.update(dev_grp_schema)
# Remove Device from HealthBot
response = self.api.delete(device_url)
if response.status_code != 204:
logger.error(response.text)
response.raise_for_status()
return True
[docs] def get_ids(self):
"""
Return Device IDs for all the devices in HealthBot system
:return: list of device IDs
Example:
::
from jnpr.healthbot import HealthBotClient
with HealthBotClient('xx.xxx.x.xx', 'xxxx', 'xxxx') as hb:
print(hb.device.get_ids())
"""
devices_list_url = self.hbot.urlfor.device()
resp = self.api.get(devices_list_url)
if resp.status_code == 404:
return []
return resp.json()
[docs] def get(self, device_id: str = None, uncommitted: bool = True):
"""
Get `DeviceSchema <jnpr.healthbot.swagger.models.html#deviceschema>`_ for
given device id or list for all devices
:param str device_id: The name of the device as provided by the User
:param bool uncommitted: True includes fetches uncommitted changes,
False restricts data set to only committed changes
Example:
::
from jnpr.healthbot import HealthBotClient
with HealthBotClient('xx.xxx.x.xx', 'xxxx', 'xxxx') as hb:
device = hb.device.get('vmx')
print(device)
devices = hb.device.get()
for device in devices:
print(device)
:return: `DeviceSchema(s) <jnpr.healthbot.swagger.models.html#deviceschema>`_
"""
if device_id is not None:
device_url = self.hbot.urlfor.device(device_id)
if uncommitted:
device_url += self.hbot.apiopt_candidate
response = self.api.get(device_url)
if response.status_code != 200:
logger.error(response.text)
response.raise_for_status()
return self.hbot._create_schema(response, DeviceSchema)
else:
device_list = []
devices_list_url = self.hbot.urlfor.devices()
if uncommitted:
devices_list_url += self.hbot.apiopt_candidate
resp = self.api.get(devices_list_url)
if resp.status_code == 404:
return []
# examine the existing devices and return a list of devices
existing_devices = resp.json()['device']
for device in existing_devices:
device = self.hbot._create_schema(device, DeviceSchema)
device_list.append(device)
return device_list
[docs] def update(self, schema: DeviceSchema = None, **kwargs):
"""
Update `DeviceSchema <jnpr.healthbot.swagger.models.html#deviceschema>`_ for
given device schema
Passing Schema invoke `put` and kwargs `post`
:param obj schema: `DeviceSchema <jnpr.healthbot.swagger.models.html#deviceschema>`_
:param object kwargs: key values, which can be used to create
DeviceSchema
Check `DeviceSchema <jnpr.healthbot.swagger.models.html#deviceschema>`_
for details about which all keys can be used
Example:
::
from jnpr.healthbot import HealthBotClient
with HealthBotClient('xx.xxx.x.xx', 'xxxx', 'xxxx') as hb:
schemaObj = hb.device.get('xyz')
schemaObj.description = 'changed description'
hb.device.update(schemaObj)
hb.device.update(device_id="xyz", host='xx.xxx.x.xx', system_id="xxxx")
:returns: True when OK
"""
if schema is None:
schema = DeviceSchema(**kwargs)
call = self.api.post
else:
if not isinstance(schema, DeviceSchema):
raise SchemaError(DeviceSchema)
call = self.api.put
payload = self.hbot._create_payload(schema)
device_id = schema.device_id
device_url = self.hbot.urlfor.device(device_id)
response = call(device_url, json=payload)
if response.status_code != 200:
logger.error(response.text)
response.raise_for_status()
return True
[docs] def get_facts(self, device_id: str = None, uncommitted: bool = True):
"""
Get device(s) facts. Get facts for provided device id, if device
id is not provided, get facts for all devices
:param str device_id: The name of the device as provided by the User
:param bool uncommitted: True includes fetches uncommitted changes,
False restricts data set to only committed changes
Example:
::
from jnpr.healthbot import HealthBotClient
from pprint import pprint
with HealthBotClient('xx.xxx.x.xx', 'xxxx', 'xxxx') as hb:
facts = hb.device.get_facts('vmx')
pprint(facts)
facts = hb.device.get_facts()
pprint(facts)
:return: Single/List of dicts of facts
"""
if device_id is not None:
device_url = self.hbot.urlfor.device_facts(device_id)
if uncommitted:
device_url += self.hbot.apiopt_candidate
response = self.api.get(device_url)
response.raise_for_status()
return response.json()
else:
device_url = self.hbot.urlfor.devices_facts()
if uncommitted:
device_url += self.hbot.apiopt_candidate
response = self.api.get(device_url)
if response.status_code != 200:
logger.error(response.text)
response.raise_for_status()
return response.json()
[docs] def health(self, device_id: str):
"""
Returns health of given Device id
`DeviceHealthTree <jnpr.healthbot.swagger.models.html#deviceheathtree>`_
:param str device_id: The name of the device as provided by the User
Example:
::
from jnpr.healthbot import HealthBotClient
with HealthBotClient('xx.xxx.x.xx', 'xxxx', 'xxxx') as hb:
print(hb.device.health('core'))
:return: `DeviceHealthTree <jnpr.healthbot.swagger.models.html#deviceheathtree>`_
"""
device_health_url = self.hbot.urlfor.device_health(device_id)
resp = self.api.get(device_health_url)
if resp.status_code == 404:
return {}
return self.hbot._create_schema(resp, DeviceHealthTree)
[docs]class DeviceGroup(BaseModule):
[docs] def __init__(self, hbot):
"""
:param object hbot: :class:`jnpr.healthbot.HealthBotClient` client instance
"""
super().__init__(hbot)
[docs] def add(self, schema: DeviceGroupSchema = None, **kwargs):
"""
Add device group to HealthBot
:param object schema: `DeviceGroupSchema <jnpr.healthbot.swagger.models.html#devicegroupschema>`_
:param object kwargs: key values, which can be used to create
DeviceGroupSchema
Check `DeviceGroupSchema <jnpr.healthbot.swagger.models.html#devicegroupschema>`_
for details about which all keys can be used
Example:
::
from jnpr.healthbot import HealthBotClient
from jnpr.healthbot import DeviceSchema
from jnpr.healthbot import DeviceGroupSchema
with HealthBotClient('xx.xxx.x.xx', 'xxxx', 'xxxx') as hb:
ds = DeviceSchema(device_id='xyz', host='xx.xxx.xxx.xxx',
authentication={"password": {"password": "xxxxx", "username": "xxxxx"}})
# This will add device in candidate DB
hb.device.add(schema=ds)
dgs = DeviceGroupSchema(device_group_name="edge",
description="All devices on the edge",
devices=['xyz'])
hb.device_group.add(dgs)
# commit changes to master DB
hb.commit()
:returns: True when OK
"""
if schema is None:
schema = DeviceGroupSchema(**kwargs)
else:
if not isinstance(schema, DeviceGroupSchema):
raise SchemaError(DeviceGroupSchema)
payload = self.hbot._create_payload(schema)
device_group_url = self.hbot.urlfor.device_group(
payload['device-group-name'])
# Add Device Group to the Healthbot
response = self.api.post(device_group_url, json=payload)
if response.status_code != 200:
logger.error(response.text)
response.raise_for_status()
return True
[docs] def delete(self, device_group_name: str, force: bool = False):
"""
Remove device group to HealthBot
:param str device_group_name: The name of the device group to be deleted
:param bool force: If True, First delete services for given device group
Example:
::
hb.devices.delete('edge')
hb.commit()
:returns: True when OK
"""
if force:
services_device_group_url = self.hbot.urlfor.services_device_group()
response = self.api.get(services_device_group_url)
if device_group_name in response.json():
services_device_group_url = self.hbot.urlfor.services_device_group(
device_group_name)
response = self.api.delete(services_device_group_url)
if response.status_code != 204:
logger.error(response.text)
response.raise_for_status()
device_group_url = self.hbot.urlfor.device_group(device_group_name)
response = self.api.delete(device_group_url)
if response.status_code != 204:
logger.error(response.text)
response.raise_for_status()
return True
[docs] def get(self, device_group_name: str = None, uncommitted: bool = True):
"""
Get `DeviceGroupSchema <jnpr.healthbot.swagger.models.html#devicegroupschema>`_ for
given device group name or list for all device groups
:param str device_group_name: Name of the device-group
:param bool uncommitted: True includes fetches uncommitted changes,
False restricts data set to only committed changes
Example:
::
device_group_schema = hb.device_group.get('edge')
groups = hb.device_group.get()
for group in groups:
print(group)
:return: `DeviceGroupSchema(s) <jnpr.healthbot.swagger.models.html#devicegroupschema>`_
"""
if device_group_name is not None:
device_group_url = self.hbot.urlfor.device_group(device_group_name)
if uncommitted:
device_group_url += self.hbot.apiopt_candidate
res = self.api.get(device_group_url)
# if 404 is returned, it means there is not a device group by that name
# we need to explicitly check for this given the API behavior
if res.status_code == 404:
return None
return self.hbot._create_schema(res, DeviceGroupSchema)
else:
device_groups_url = self.hbot.urlfor.device_groups()
if uncommitted:
device_groups_url += self.hbot.apiopt_candidate
response = self.api.get(device_groups_url)
if response.status_code == 404:
return []
response_json = response.json()
if response.status_code != 200:
logger.error(response.text)
raise NotFoundError(response_json)
device_group_list = []
existing_device_groups = response_json['device-group']
for device_group in existing_device_groups:
obj = self.hbot._create_schema(device_group, DeviceGroupSchema)
device_group_list.append(obj)
return device_group_list
[docs] def update(self, schema: DeviceGroupSchema = None, **kwargs):
"""
Update `DeviceGroupSchema <jnpr.healthbot.swagger.models.html#devicegroupschema>`_ for
given device schema
Passing Schema invoke `put` and kwargs `post`
:param obj schema: `DeviceGroupSchema <jnpr.healthbot.swagger.models.html#devicegroupschema>`_
:param object kwargs: key values, which can be used to create
DeviceGroupSchema
Check `DeviceGroupSchema <jnpr.healthbot.swagger.models.html#devicegroupschema>`_
for details about which all keys can be used
Example:
::
from jnpr.healthbot import HealthBotClient
with HealthBotClient('xx.xxx.x.xx', 'xxxx', 'xxxx') as hb:
schemaObj = hb.device_group.get('Core')
schemaObj.description = "Changed"
hb.device_group.update(schemaObj)
:returns: True when OK
"""
if schema is None:
schema = DeviceGroupSchema(**kwargs)
call = self.api.post
else:
if not isinstance(schema, DeviceGroupSchema):
raise SchemaError(DeviceGroupSchema)
call = self.api.put
payload = self.hbot._create_payload(schema)
device_group_url = self.hbot.urlfor.device_group(
payload['device-group-name'])
response = call(device_group_url, json=payload)
if response.status_code != 200:
logger.error(response.text)
response.raise_for_status()
return True
[docs] def check_device_in_group(self, device_name: str, device_group_name: str):
"""
This method check if the device is a member of the given device-group
:param str device_name: Name of the device
:param str device_group_name: Name of the device-group
Example:
::
from jnpr.healthbot import HealthBotClient
with HealthBotClient('xx.xxx.x.xx', 'xxxx', 'xxxx') as hb:
print(hb.device_group.check_device_in_group('vmx', 'QFabric'))
Returns:
True if action successful
"""
# retrieve the current device-group dataset and determine if the given device name is already
# a member of the group. If so, return True
group_data = self.get(device_group_name)
if group_data is None:
return False
device_list = group_data.to_dict().get('devices', [])
return device_name in device_list
[docs] def add_device_in_group(self, device_name: str, device_group_name: str):
"""
This method ensures that the given device is a member of the given
device-group
:param str device_name: Name of the device
:param str device_group_name: Name of the device-group
Example:
::
from jnpr.healthbot import HealthBotClient
with HealthBotClient('xx.xxx.x.xx', 'xxxx', 'xxxx') as hb:
hb.device_group.add_device_in_group('vmx', 'QFabric')
Raises:
HTTPError: When error making changes via the HBOT API
Returns:
True if action successful
"""
# retrieve the current device-group dataset and determine if the given device name is already
# a member of the group. If so, return True
if self.check_device_in_group(device_name, device_group_name):
return True
# add the device to the list and then store back to the server
group_data = self.get(device_group_name)
if group_data is None:
device_list = []
group_data = DeviceGroupSchema(device_group_name=device_group_name)
else:
device_list = group_data.to_dict().get('devices', [])
device_list.append(device_name)
group_data.devices = device_list
return self.add(group_data)
[docs] def health(self, device_group_name: str):
"""
Returns health of given Device id
`DeviceGroupHealthTree <jnpr.healthbot.swagger.models.html#devicegroupheathtree>`_
:param str device_group_name: The name of the device group
Example:
::
from jnpr.healthbot import HealthBotClient
with HealthBotClient('xx.xxx.x.xx', 'xxxx', 'xxxx') as hb:
print(hb.device_group.health('edge'))
:return: `DeviceGroupHealthTree <jnpr.healthbot.swagger.models.html#devicegroupheathtree>`_
"""
device_group_health_url = self.hbot.urlfor.device_group_health(
device_group_name)
resp = self.api.get(device_group_health_url)
if resp.status_code == 404:
return {}
return self.hbot._create_schema(resp, DeviceGroupHealthTree)
[docs]class NetworkGroup(BaseModule):
[docs] def __init__(self, hbot):
"""
:param object hbot: :class:`jnpr.healthbot.HealthBotClient` client instance
"""
super().__init__(hbot)
[docs] def add(self, schema: NetworkGroupSchema = None, **kwargs):
"""
Create Network Group
:param object schema: `NetworkGroupSchema <jnpr.healthbot.swagger.models.html#networkgroupschema>`_
:param object kwargs: key values, which can be used to create
NetworkGroupSchema
Check `NetworkGroupSchema <jnpr.healthbot.swagger.models.html#networkgroupschema>`_
for details about which all keys can be used
Example:
::
from jnpr.healthbot import HealthBotClient
with HealthBotClient('xx.xxx.x.xx', 'xxxx', 'xxxx') as hb:
hb.devices.add_network_group(network_group_name="HbEZ")
# or
from jnpr.healthbot import HealthBotClient
from jnpr.healthbot import NetworkGroupSchema
with HealthBotClient('xx.xxx.x.xx', 'xxxx', 'xxxx') as hb:
ngs = NetworkGroupSchema(network_group_name="HbEZ")
hb.network_group.add(schema = ngs)
"""
if schema is None:
schema = NetworkGroupSchema(**kwargs)
else:
if not isinstance(schema, NetworkGroupSchema):
raise SchemaError(NetworkGroupSchema)
payload = self.hbot._create_payload(schema)
# check if the group already exists. If it does, then return now
# ... this means this function will not do an "ensure / merge" of data
# if the group already exists
network_group_url = self.hbot.urlfor.network_group(
payload['network-group-name'])
resp = self.api.get(network_group_url + self.hbot.apiopt_candidate)
if resp.ok:
return True
response = self.api.post(network_group_url, json=payload)
if response.status_code != 200:
logger.error(response.text)
response.raise_for_status()
return True
[docs] def delete(self, network_group_name: str):
"""
Delete Network Group
:param str network_group_name: The name of the network group to be deleted
Example:
::
from jnpr.healthbot import HealthBotClient
with HealthBotClient('xx.xxx.x.xx', 'xxxx', 'xxxx') as hb:
hb.network_group.delete(network_group_name="HbEZ")
"""
payload = {'network-group-name': network_group_name}
network_group_url = self.hbot.urlfor.network_group(network_group_name)
response = self.api.delete(network_group_url, json=payload)
if response.status_code != 200:
logger.error(response.text)
response.raise_for_status()
return True
[docs] def get(self, network_group_name: str = None, uncommitted: bool = True):
"""
get Network Group(s) details
:param str network_group_name: The name of the network group to be fetched
:param bool uncommitted: True includes fetches uncommitted changes,
False restricts data set to only committed changes
Example:
::
from jnpr.healthbot import HealthBotClient
with HealthBotClient('xx.xxx.x.xx', 'xxxx', 'xxxx') as hb:
print(hb.network_group.get(network_group_name="HbEZ"))
# for all network groups
print(hb.network_group.get())
"""
if network_group_name is not None:
network_group_url = self.hbot.urlfor.network_group(
network_group_name)
if uncommitted:
network_group_url += self.hbot.apiopt_candidate
response = self.api.get(network_group_url)
if response.status_code != 200:
logger.error(response.text)
response.raise_for_status()
return self.hbot._create_schema(response, NetworkGroupSchema)
else:
network_groups_url = self.hbot.urlfor.network_groups()
if uncommitted:
network_groups_url += self.hbot.apiopt_candidate
response = self.api.get(network_groups_url)
if response.status_code == 404:
return []
response_json = response.json()
if response.status_code != 200:
logger.error(response.text)
raise NotFoundError(response_json)
response.raise_for_status()
network_group_list = []
existing_network_groups = response_json['network-group']
for network_group in existing_network_groups:
obj = self.hbot._create_schema(
network_group, NetworkGroupSchema)
network_group_list.append(obj)
return network_group_list
[docs] def update(self, schema: NetworkGroupSchema = None, **kwargs):
"""
Update `NetworkGroupSchema <jnpr.healthbot.swagger.models.html#networkgroupschema>`_ for
given network schema object
Passing Schema invoke `put` and kwargs `post`
:param obj schema: `NetworkGroupSchema <jnpr.healthbot.swagger.models.html#networkgroupschema>`_
:param object kwargs: key values, which can be used to create
NetworkGroupSchema.
Example:
::
from jnpr.healthbot import HealthBotClient
with HealthBotClient('xx.xxx.x.xx', 'xxxx', 'xxxx') as hb:
schemaObj = hb.network_group.get("HbEZ")
schemaObj.description = "HbEZ example"
hb.network_group.update(schemaObj)
:returns: True when OK
"""
if schema is None:
schema = NetworkGroupSchema(**kwargs)
call = self.api.post
else:
if not isinstance(schema, NetworkGroupSchema):
raise SchemaError(NetworkGroupSchema)
call = self.api.put
payload = self.hbot._create_payload(schema)
network_group_url = self.hbot.urlfor.network_group(
payload['network-group-name'])
response = call(network_group_url, json=payload)
if response.status_code != 200:
logger.error(response.text)
return True
[docs] def health(self, network_group_name: str):
"""
Returns health of given Device id
`NetworkHealthTree <jnpr.healthbot.swagger.models.html#networkheathtree>`_
:param str network_group_name: The name of the network group
Example:
::
from jnpr.healthbot import HealthBotClient
with HealthBotClient('xx.xxx.x.xx', 'xxxx', 'xxxx') as hb:
print(hb.network_group.health('core'))
:return: `NetworkHealthTree <jnpr.healthbot.swagger.models.html#networkheathtree>`_
"""
network_group_health_url = self.hbot.urlfor.network_group_health(
network_group_name)
resp = self.api.get(network_group_health_url)
if resp.status_code == 404:
return {}
return self.hbot._create_schema(resp, NetworkHealthTree)