Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save samdoran/8de48b29dfe8ce1a85dfc0decf73f08b to your computer and use it in GitHub Desktop.
Save samdoran/8de48b29dfe8ce1a85dfc0decf73f08b to your computer and use it in GitHub Desktop.
HiveOS Ansible plugins
#!/usr/bin/python
# -*- coding: utf-8 -*-
# Copyright (c) 2019 Ansible Project
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
ANSIBLE_METADATA = {'metadata_version': '1.1',
'status': ['preview'],
'supported_by': 'network'}
DOCUMENTATION = """
module: hiveos_facts
version_added: "2.0"
author: ""
short_description: Collect facts from remote devices running Aerohive HiveOS
description:
- Collects a base set of device facts from a remote device that
is running HiveOS. This module prepends all of the
base network fact keys with C(ansible_net_<fact>). The facts
module will always collect a base set of facts from the device
and can enable or disable collection of additional facts.
extends_documentation_fragment: HiveOS
notes:
- Tested against HiveOS 15.6
options:
gather_subset:
description:
- When supplied, this argument will restrict the facts collected
to a given subset. Possible values for this argument include
all, hardware, config, and interfaces. Can specify a list of
values to include a larger subset. Values can also be used
with an initial C(M(!)) to specify that a specific subset should
not be collected.
required: false
default: '!config'
"""
EXAMPLES = """
# Collect all facts from the device
- hiveos_facts:
gather_subset: all
# Collect only the config and default facts
- hiveos_facts:
gather_subset:
- config
# Do not collect hardware facts
- hiveos_facts:
gather_subset:
- "!hardware"
"""
RETURN = """
ansible_net_gather_subset:
description: The list of fact subsets collected from the device
returned: always
type: list
# default
ansible_net_model:
description: The model name returned from the device
returned: always
type: string
ansible_net_serialnum:
description: The serial number of the remote device
returned: always
type: string
ansible_net_version:
description: The operating system version running on the remote device
returned: always
type: string
ansible_net_hostname:
description: The configured hostname of the device
returned: always
type: string
ansible_net_image:
description: The image file the device is running
returned: always
type: string
# hardware
ansible_net_filesystems:
description: All file system names available on the device
returned: when hardware is configured
type: list
ansible_net_filesystems_info:
description: A hash of all file systems containing info about each file system (e.g. free and total space)
returned: when hardware is configured
type: dict
ansible_net_memfree_mb:
description: The available free memory on the remote device in Mb
returned: when hardware is configured
type: int
ansible_net_memtotal_mb:
description: The total memory on the remote device in Mb
returned: when hardware is configured
type: int
# config
ansible_net_config:
description: The current active config from the device
returned: when config is configured
type: string
# interfaces
ansible_net_all_ipv4_addresses:
description: All IPv4 addresses configured on the device
returned: when interfaces is configured
type: list
ansible_net_all_ipv6_addresses:
description: All IPv6 addresses configured on the device
returned: when interfaces is configured
type: list
ansible_net_interfaces:
description: A hash of all interfaces running on the system
returned: when interfaces is configured
type: dict
ansible_net_neighbors:
description: The list of LLDP neighbors from the remote device
returned: when interfaces is configured
type: dict
"""
import re
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.network.hiveos.hiveos import run_commands
from ansible.module_utils.six import iteritems
class FactsBase(object):
COMMANDS = frozenset()
def __init__(self, module):
self.module = module
self.facts = {}
self.responses = None
def populate(self):
self.responses = run_commands(self.module, commands=self.COMMANDS, check_rc=False)
def run(self, cmd):
return run_commands(self.module, commands=cmd, check_rc=False)
class Default(FactsBase):
COMMANDS = [
'show version',
'show hw-info',
'show run | include hostname'
]
def populate(self):
super(Default, self).populate()
# output from the first list index show version
data_0 = self.responses[0]
# output from the second list index show hw-info
data_1 = self.responses[1]
# output from the third list index show run | include hostname
data_2 = self.responses[2]
if data_0:
self.facts['version'] = self.parse_version(data_0)
self.facts['model'] = self.parse_model(data_0)
if data_1:
self.facts['serialnum'] = self.parse_serialnum(data_1)
if data_2:
self.facts['hostname'] = self.parse_hostname(data_2)
def parse_version(self, data):
match = re.search(r'Version:\s+\w+\s(\S+)\s', data)
if match:
return match.group(1)
def parse_model(self, data):
match = re.search(r'Platform:\s*(\S+)', data)
if match:
return match.group(1)
def parse_serialnum(self, data):
match = re.search(r'Serial number:\s+(\w+)', data)
if match:
return match.group(1)
def parse_hostname(self, data):
match = re.search(r'^hostname\s+(\S+)$', data)
if match:
return match.group(1)
class Hardware(FactsBase):
COMMANDS = [
'show system disk-info',
'show cpu',
'show memory',
]
def populate(self):
super(Hardware, self).populate()
data = self.responses[0]
if data:
self.facts['filesystems'] = self.parse_filesystems(data)
data = self.responses[1]
if data:
self.facts['processor_total'] = re.search(r'^CPU total \w+:\s+(\S+)', data).group(1)
self.facts['processor_user'] = re.search(r'CPU user \w+:\s+(\S+)', data).group(1)
self.facts['processor_sys'] = re.search(r'CPU system \w+:\s+(\S+)', data).group(1)
data = self.responses[2]
if data:
self.facts['memtotal_kb'] = re.search(r'Total Memory: \s+(\d+)', data).groups(1)
self.facts['memfree_kb'] = re.search(r'Free Memory: \s+(\d+)', data).groups(1)
self.facts['memused_kb'] = re.search(r'Used Memory: \s+(\d+)', data).groups(1)
def parse_filesystems(self, data):
return re.findall(r'^/dev|tmpfs', data, re.M)
class Config(FactsBase):
COMMANDS = ['show config running']
def populate(self):
super(Config, self).populate()
data = self.responses[0]
if data:
self.facts['config'] = data
FACT_SUBSETS = dict(
default=Default,
hardware=Hardware,
config=Config,
)
VALID_SUBSETS = frozenset(FACT_SUBSETS.keys())
global warnings
warnings = []
def main():
"""main entry point for module execution
"""
argument_spec = {
'gather_subset': {'default': ['!config'], 'type': 'list'},
}
module = AnsibleModule(
argument_spec=argument_spec,
supports_check_mode=True
)
gather_subset = module.params['gather_subset']
runable_subsets = set()
exclude_subsets = set()
for subset in gather_subset:
if subset == 'all':
runable_subsets.update(VALID_SUBSETS)
continue
if subset.startswith('!'):
subset = subset[1:]
if subset == 'all':
exclude_subsets.update(VALID_SUBSETS)
continue
exclude = True
else:
exclude = False
if subset not in VALID_SUBSETS:
module.fail_json(msg='Bad subset')
if exclude:
exclude_subsets.add(subset)
else:
runable_subsets.add(subset)
if not runable_subsets:
runable_subsets.update(VALID_SUBSETS)
runable_subsets.difference_update(exclude_subsets)
runable_subsets.add('default')
facts = {}
facts['gather_subset'] = list(runable_subsets)
instances = []
for key in runable_subsets:
instances.append(FACT_SUBSETS[key](module))
for inst in instances:
inst.populate()
facts.update(inst.facts)
ansible_facts = {}
for key, value in iteritems(facts):
key = 'ansible_net_%s' % key
ansible_facts[key] = value
module.exit_json(ansible_facts=ansible_facts, warnings=warnings)
if __name__ == '__main__':
main()
#!/usr/bin/python
# -*- coding: utf-8 -*-
# Copyright (c) 2019 Ansible Project
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
from __future__ import (absolute_import, division, print_function)
__metaclass__ = type
import re
import json
from itertools import chain
from ansible.module_utils.network.common.utils import to_list
from ansible.module_utils._text import to_text
from ansible.plugins.cliconf import CliconfBase
class Cliconf(CliconfBase):
def get_config(self, source='running', flags=None, format=None):
if source not in ('running', 'backup', 'bootstrap', 'current', 'default', 'failed', 'version',):
raise ValueError("fetching configuration from %s is not supported" % source)
if format:
raise ValueError("'format' value %s is not supported for get_config" % format)
cmd = 'show config %s' % source
return self.send_command(cmd)
def get(self, command, prompt=None, answer=None, sendonly=False, newline=True, check_all=False):
return self.send_command(command=command, prompt=prompt, answer=answer, sendonly=sendonly, newline=newline, check_all=check_all)
def get_device_info(self):
device_info = {}
device_info['network_os'] = 'hiveos'
reply = self.get('show version')
data = to_text(reply, errors='surrogate_or_strict').strip()
match = re.search(r'Version:\s+\w+\s(\S+)\s', data)
if match:
device_info['network_os_version'] = match.group(1)
match = re.search(r'Platform:\s*(\S+)', data)
if match:
device_info['network_os_model'] = match.group(1)
reply = self.get('show config running | include hostname')
reply = to_text(reply, errors='surrogate_or_strict').strip()
device_info['network_os_hostname'] = reply.split(' ')[-1]
return device_info
def get_capabilities(self):
result = super(Cliconf, self).get_capabilities()
# result['device_info'] = self.get_device_info()
return json.dumps(result)
def edit_config(self, candidate=None, commit=True, replace=False, comment=None):
for cmd in chain(['configure'], to_list(candidate)):
self.send_command(cmd)
#!/usr/bin/python
# -*- coding: utf-8 -*-
# Copyright (c) 2019 Ansible Project
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
from __future__ import (absolute_import, division, print_function)
__metaclass__ = type
import re
from ansible.errors import AnsibleConnectionFailure
from ansible.plugins.terminal import TerminalBase
class TerminalModule(TerminalBase):
terminal_stdout_re = [
re.compile(br"[\r\n]?[\w\+\-\.:\/\[\]]+(?:\([^\)]+\)){0,3}(?:[>#]) ?$"),
]
terminal_stderr_re = [
re.compile(br"(invalid|ambigious|incomplete) (input|command)", re.I),
]
def on_open_shell(self):
try:
cmd = 'console page 0'
self._exec_cli_command(cmd)
except AnsibleConnectionFailure:
raise AnsibleConnectionFailure('unable to set terminal parameters')
def on_close_shell(self):
try:
cmd = 'console page 22'
self._exec_cli_command(cmd)
except AnsibleConnectionFailure:
raise AnsibleConnectionFailure('unable to set terminal parameters')
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment