Source code for towerlib.entities.host

#!/usr/bin/env python
# -*- coding: utf-8 -*-
# File: host.py
#
# Copyright 2018 Costas Tyfoxylos
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
#  of this software and associated documentation files (the "Software"), to
#  deal in the Software without restriction, including without limitation the
#  rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
#  sell copies of the Software, and to permit persons to whom the Software is
#  furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
#  all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
#  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
#  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
#  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
#  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
#  FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
#  DEALINGS IN THE SOFTWARE.
#

"""
Main code for host.

.. _Google Python Style Guide:
   http://google.github.io/styleguide/pyguide.html

"""

import logging

from towerlib.towerlibexceptions import InvalidGroup, InvalidValue
from .core import Entity, EntityManager, validate_max_length, validate_json

__author__ = '''Costas Tyfoxylos <ctyfoxylos@schubergphilis.com>'''
__docformat__ = '''google'''
__date__ = '''2018-01-03'''
__copyright__ = '''Copyright 2018, Costas Tyfoxylos'''
__credits__ = ["Costas Tyfoxylos"]
__license__ = '''MIT'''
__maintainer__ = '''Costas Tyfoxylos'''
__email__ = '''<ctyfoxylos@schubergphilis.com>'''
__status__ = '''Development'''  # "Prototype", "Development", "Production".

# This is the main prefix used for logging
LOGGER_BASENAME = '''host'''
LOGGER = logging.getLogger(LOGGER_BASENAME)
LOGGER.addHandler(logging.NullHandler())


[docs]class Host(Entity): """Models the host entity of ansible tower.""" def __init__(self, tower_instance, data): Entity.__init__(self, tower_instance, data) @property def name(self): """The name of the host. Returns: string: The name of the host. """ return self._data.get('name') @name.setter def name(self, value): """Update the name of the hosts. Returns: None: """ max_characters = 512 conditions = [validate_max_length(value, max_characters)] if all(conditions): self._update_values('name', value) else: raise InvalidValue(f'{value} is invalid. Condition max_characters must be less than or equal to ' f'{max_characters}') @property def description(self): """The description of the host. Returns: string: The description of the host. """ return self._data.get('description') @description.setter def description(self, value): """Update the description on the host. Returns: None: """ self._update_values('description', value) @property def inventory(self): """The inventory that the host is part of. Returns: Inventory: The inventory that the host is part of. """ return self._tower.get_inventory_by_id(self._data.get('inventory')) @property def enabled(self): """Flag about whether the host is enabled in tower. Returns: bool: True if the host is enabled, False otherwise. """ return self._data.get('enabled') @enabled.setter def enabled(self, value): """Update the enabled status of the host. Returns: None: """ self._update_values('enabled', value) @property def instance_id(self): """Not sure what this is. Returns: string: """ return self._data.get('instance_id') @instance_id.setter def instance_id(self, value): """Update the instance_id of the host. Returns: None: """ max_characters = 1024 conditions = [validate_max_length(value, max_characters)] if all(conditions): self._update_values('instance_id', value) else: raise InvalidValue(f'{value} is invalid. Condition max_characters must be less than or equal to ' f'{max_characters}') @property def variables(self): """The variables set on the host. Returns: string: A string of the variables set on the host usually in yaml format. """ return self._data.get('variables') @variables.setter def variables(self, value): """Update the variables on the host. Returns: None: """ conditions = [validate_json(value)] if all(conditions): self._update_values('variables', value) else: raise InvalidValue(f'{value} is not valid json.') @property def has_active_failures(self): """Flag about whether the host has active failures. Returns: bool: True if the host has active failures, False otherwise. """ return self._data.get('has_active_failures') @property def has_inventory_sources(self): """Flag about whether the host has inventory sources. Returns: bool: True if the host has inventory sources, False otherwise. """ return self._data.get('has_inventory_sources') @property def last_job(self): """The id of the last job. Returns: integer: The id of the last job. """ return self._data.get('last_job') @property def last_job_host_summary(self): """The id of the last job summary. Returns: integer: The id of the last job summary.. """ return self._data.get('last_job_host_summary') @property def insights_system_id(self): """Not sure what this is. Returns: None. """ return self._data.get('insights_system_id') @property def created_by(self): """The user that created the host. Returns: User: The user that created the host. """ url = self._data.get('related', {}).get('created_by') return self._tower._get_object_by_url('User', url) # pylint: disable=protected-access @property def modified_by(self): """The person that modified the host last. Returns: User: The user that modified the host in tower last. """ url = self._data.get('related', {}).get('modified_by') return self._tower._get_object_by_url('User', url) # pylint: disable=protected-access @property def groups(self): """The groups that the host is part of. Returns: EntityManager: EntityManager of the groups of the host. """ url = self._data.get('related', {}).get('groups') return EntityManager(self._tower, entity_object='Group', primary_match_field='name', url=url) @property def all_groups(self): """The groups that the host is directly and indirectly part of. Returns: EntityManager: EntityManager of the groups of the host. """ url = self._data.get('related', {}).get('all_groups') return EntityManager(self._tower, entity_object='Group', primary_match_field='name', url=url) @property def recent_jobs(self): """The most recent jobs run on the host. Returns: list if dict: The most recent jobs run on the host. """ return self._data.get('summary_fields', {}).get('recent_jobs') @property def ansible_facts(self): """Returns ansible facts gathered about the host in json. Args: None Returns: json: Json representation of ansible facts Raises: None """ url = f'{self._tower.api}/hosts/{self.id}/ansible_facts/' response = self._tower.session.get(url) if not response.ok: self._logger.error('Error finding ansible facts for %s.', self._data.get('name')) return response.json() if response.ok else '{}'
[docs] def associate_with_groups(self, groups): """Associate the host with the provided groups. Args: groups: The groups to associate the host with. Accepts a single group string or a list or tuple of groups. Returns: bool: True on complete success, False otherwise. Raises: InvalidGroup: The group provided as argument does not exist. """ if not isinstance(groups, (list, tuple)): groups = [groups] lower_inventory_group_names = [ group.name.lower() for group in self.inventory.groups] missing_groups = [group_name for group_name in groups if group_name.lower() not in lower_inventory_group_names] if missing_groups: raise InvalidGroup(missing_groups) lower_group_names = [name.lower() for name in groups] final_groups = [group for group in self.inventory.groups if group.name.lower() in lower_group_names] return all(group._add_host_by_id(self.id) # pylint: disable=protected-access for group in final_groups)
[docs] def disassociate_with_groups(self, groups): """Disassociate the host from the provided groups. Args: groups: The group name(s) to disassociate the host from. Accepts a single group string or a list or tuple of groups. Returns: bool: True on complete success, False otherwise. Raises: InvalidGroup: The group provided as argument does not exist. """ if not isinstance(groups, (list, tuple)): groups = [groups] missing_groups = [group_name for group_name in groups if group_name not in self.groups] if missing_groups: raise InvalidGroup(missing_groups) lower_group_names = [name.lower() for name in groups] inventory_groups = [group for group in self.inventory.groups if group.name.lower() in lower_group_names] return all(group._remove_host_by_id(self.id) # pylint: disable=protected-access for group in inventory_groups)
@property def job_events(self): """The job_events for the host. Returns: job_events (list): All job events of the host """ return self._tower.job_events.filter({'host': self.id})