From 67cc6ad8a5ce1d05c8bad5f405827e179d6a0a09 Mon Sep 17 00:00:00 2001 From: Patrick Toal Date: Tue, 7 Jul 2020 16:19:18 -0400 Subject: [PATCH] Host provisioning integrations with netbox --- filter_plugins/netbox_filters.py | 43 ++++++ library/ovirt4.py | 257 ------------------------------- netbox_inventory.yml | 23 --- pi-dhcp.yml | 22 --- pimgmt.yml | 42 +++++ roles/requirements.yml | 3 +- 6 files changed, 87 insertions(+), 303 deletions(-) create mode 100644 filter_plugins/netbox_filters.py delete mode 100755 library/ovirt4.py delete mode 100644 netbox_inventory.yml delete mode 100644 pi-dhcp.yml create mode 100644 pimgmt.yml diff --git a/filter_plugins/netbox_filters.py b/filter_plugins/netbox_filters.py new file mode 100644 index 0000000..3df0190 --- /dev/null +++ b/filter_plugins/netbox_filters.py @@ -0,0 +1,43 @@ +# I started this to create a filter that would translate netbox to linux-system-roles/network. + +from ansible.utils.display import Display + +display = Display() + +def get_type(intf_type): + # This is not ideal. Fix it. + # https://github.com/netbox-community/netbox/blob/3eb2d45e8deedfc71cfba9a3c2f919df760b6dca/netbox/dcim/migrations/0082_3569_interface_fields.py + if intf_type['id'] == 0: + return 'vlan' + elif 799 < intf_type['id'] < 2000: + return 'ethernet' + elif intf_type['id'] == 200: + return 'bond' + + +def translate_interface(interface): + display.vv(interface) + + lsrint = { + 'name': interface['name'], + 'interface_name': interface['name'], + 'state': 'up' if interface['enabled'] else 'down', + 'persistent_state': 'present' if interface['enabled'] else 'absent', + } + lsrint['type'] = get_type(interface['type']) + + if lsrint['type'] == "vlan": + #Interface name must be in the format . + lsrint['parent'] = interface['name'].split('.',1)[0] + + if interface.get('ip_address'): + lsrint['ip']['address'] = [ ip['address'] for ip in interface['ip_addresses'] ] + + return lsrint + +def nbint_to_lsr_network(interfaces): + return [ translate_interface(netif) for netif in interfaces ] + +class FilterModule(object): + def filters(self): + return {'nbint_to_lsr_network': nbint_to_lsr_network} diff --git a/library/ovirt4.py b/library/ovirt4.py deleted file mode 100755 index 74205ae..0000000 --- a/library/ovirt4.py +++ /dev/null @@ -1,257 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- -# -# Copyright (c) 2016 Red Hat, Inc. -# -# This file is part of Ansible -# -# Ansible is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# Ansible is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with Ansible. If not, see . -# - -""" -oVirt dynamic inventory script -================================= - -Generates dynamic inventory file for oVirt. - -Script will return following attributes for each virtual machine: - - id - - name - - host - - cluster - - status - - description - - fqdn - - os_type - - template - - tags - - statistics - - devices - -When run in --list mode, virtual machines are grouped by the following categories: - - cluster - - tag - - status - - Note: If there is some virtual machine which has has more tags it will be in both tag - records. - -Examples: - # Execute update of system on webserver virtual machine: - - $ ansible -i contrib/inventory/ovirt4.py webserver -m yum -a "name=* state=latest" - - # Get webserver virtual machine information: - - $ contrib/inventory/ovirt4.py --host webserver - -Author: Ondra Machacek (@machacekondra) -""" - -import argparse -import os -import sys - -from collections import defaultdict - -from ansible.module_utils.six.moves import configparser - -import json - -try: - import ovirtsdk4 as sdk - import ovirtsdk4.types as otypes -except ImportError: - print('oVirt inventory script requires ovirt-engine-sdk-python >= 4.0.0') - sys.exit(1) - - -def parse_args(): - """ - Create command line parser for oVirt dynamic inventory script. - """ - parser = argparse.ArgumentParser( - description='Ansible dynamic inventory script for oVirt.', - ) - parser.add_argument( - '--list', - action='store_true', - default=True, - help='Get data of all virtual machines (default: True).', - ) - parser.add_argument( - '--host', - help='Get data of virtual machines running on specified host.', - ) - parser.add_argument( - '--pretty', - action='store_true', - default=False, - help='Pretty format (default: False).', - ) - return parser.parse_args() - - -def create_connection(): - """ - Create a connection to oVirt engine API. - """ - # Get the path of the configuration file, by default use - # 'ovirt.ini' file in script directory: - default_path = os.path.join( - os.path.dirname(os.path.realpath(__file__)), - 'ovirt.ini', - ) - config_path = os.environ.get('OVIRT_INI_PATH', default_path) - - # Create parser and add ovirt section if it doesn't exist: - config = configparser.SafeConfigParser( - defaults={ - 'ovirt_url': os.environ.get('OVIRT_URL'), - 'ovirt_username': os.environ.get('OVIRT_USERNAME'), - 'ovirt_password': os.environ.get('OVIRT_PASSWORD'), - 'ovirt_ca_file': os.environ.get('OVIRT_CAFILE', ''), - } - ) - if not config.has_section('ovirt'): - config.add_section('ovirt') - config.read(config_path) - - # Create a connection with options defined in ini file: - return sdk.Connection( - url=config.get('ovirt', 'ovirt_url'), - username=config.get('ovirt', 'ovirt_username'), - password=config.get('ovirt', 'ovirt_password', raw=True), - ca_file=config.get('ovirt', 'ovirt_ca_file') or None, - insecure=not config.get('ovirt', 'ovirt_ca_file'), - ) - - -def get_dict_of_struct(connection, vm): - """ - Transform SDK Vm Struct type to Python dictionary. - """ - if vm is None: - return dict() - - vms_service = connection.system_service().vms_service() - clusters_service = connection.system_service().clusters_service() - vm_service = vms_service.vm_service(vm.id) - devices = vm_service.reported_devices_service().list() - tags = vm_service.tags_service().list() - stats = vm_service.statistics_service().list() - labels = vm_service.affinity_labels_service().list() - groups = clusters_service.cluster_service( - vm.cluster.id - ).affinity_groups_service().list() - - return { - 'id': vm.id, - 'name': vm.name, - 'host': connection.follow_link(vm.host).name if vm.host else None, - 'cluster': connection.follow_link(vm.cluster).name, - 'status': str(vm.status), - 'description': vm.description, - 'fqdn': vm.fqdn, - 'os_type': vm.os.type, - 'template': connection.follow_link(vm.template).name, - 'tags': [tag.name for tag in tags], - 'affinity_labels': [label.name for label in labels], - 'affinity_groups': [ - group.name for group in groups - if vm.name in [vm.name for vm in connection.follow_link(group.vms)] - ], - 'statistics': dict( - (stat.name, stat.values[0].datum) for stat in stats if stat.values - ), - 'devices': dict( - (device.name, [ip.address for ip in device.ips]) for device in devices if device.ips - ), - 'ansible_host': next((device.ips[0].address for device in devices if device.ips), None) - } - - -def get_data(connection, vm_name=None): - """ - Obtain data of `vm_name` if specified, otherwise obtain data of all vms. - """ - vms_service = connection.system_service().vms_service() - clusters_service = connection.system_service().clusters_service() - - if vm_name: - vm = vms_service.list(search='name=%s' % vm_name) or [None] - data = get_dict_of_struct( - connection=connection, - vm=vm[0], - ) - else: - vms = dict() - data = defaultdict(list) - for vm in vms_service.list(): - name = vm.name - vm_service = vms_service.vm_service(vm.id) - cluster_service = clusters_service.cluster_service(vm.cluster.id) - - # Add vm to vms dict: - vms[name] = get_dict_of_struct(connection, vm) - - # Add vm to cluster group: - cluster_name = connection.follow_link(vm.cluster).name - data['cluster_%s' % cluster_name].append(name) - - # Add vm to tag group: - tags_service = vm_service.tags_service() - for tag in tags_service.list(): - data['tag_%s' % tag.name].append(name) - - # Add vm to status group: - data['status_%s' % vm.status].append(name) - - # Add vm to affinity group: - for group in cluster_service.affinity_groups_service().list(): - if vm.name in [ - v.name for v in connection.follow_link(group.vms) - ]: - data['affinity_group_%s' % group.name].append(vm.name) - - # Add vm to affinity label group: - affinity_labels_service = vm_service.affinity_labels_service() - for label in affinity_labels_service.list(): - data['affinity_label_%s' % label.name].append(name) - - data["_meta"] = { - 'hostvars': vms, - } - - return data - - -def main(): - args = parse_args() - connection = create_connection() - - print( - json.dumps( - obj=get_data( - connection=connection, - vm_name=args.host, - ), - sort_keys=args.pretty, - indent=args.pretty * 2, - ) - ) - - -if __name__ == '__main__': - main() diff --git a/netbox_inventory.yml b/netbox_inventory.yml deleted file mode 100644 index 5046885..0000000 --- a/netbox_inventory.yml +++ /dev/null @@ -1,23 +0,0 @@ ---- -plugin: netbox.netbox.nb_inventory -api_endpoint: http://netbox.mgmt.toal.ca -validate_certs: True -config_context: True -flatten_config_context: True -flatten_custom_fields: True -interfaces: True -services: True -plurals: False - -group_by: - - site - - tag - - role - - platform - - cluster - -query_filters: - - tag: ansible - -#query_filters: -# - role: network-edge-router diff --git a/pi-dhcp.yml b/pi-dhcp.yml deleted file mode 100644 index aff2c61..0000000 --- a/pi-dhcp.yml +++ /dev/null @@ -1,22 +0,0 @@ ---- -- name: Set Up DHCP System - hosts: dhcp-server - become: true - - tasks: - - name: DHCP Daemon is installed - apt: - name: isc-dhcp-server - state: latest - notify: Restart DHCPD - - - name: Generate dhcpd.conf - template: - src: dhcpd.conf.j2 - dest: "{{ dhcpd_conf_path }}" - - handlers: - - name: Restart DHCPD - service: - name: isc-dhcpd-server - state: restarted \ No newline at end of file diff --git a/pimgmt.yml b/pimgmt.yml new file mode 100644 index 0000000..bf07fde --- /dev/null +++ b/pimgmt.yml @@ -0,0 +1,42 @@ +--- +# Configure a Raspberry Pi running Fedora 32+ for Management functions. +- name: Configure interfaces + hosts: pimgmt + gather_facts: false + connection: local + vars: + network_provider: nm + + tasks: + - set_fact: + network_connections: >- + {{ network_connections|default([]) + [{ + 'name': item.name, + 'state': item.enabled |ternary('up','down') + }] }} + loop: "{{ interfaces }}" + + - debug: + msg: "Connections = {{ network_connections }}" + +# - name: Set Up DHCP System +# hosts: dhcp-server +# become: true + +# tasks: +# - name: DHCP Daemon is installed +# apt: +# name: isc-dhcp-server +# state: latest +# notify: Restart DHCPD + +# - name: Generate dhcpd.conf +# template: +# src: dhcpd.conf.j2 +# dest: "{{ dhcpd_conf_path }}" + +# handlers: +# - name: Restart DHCPD +# service: +# name: isc-dhcpd-server +# state: restarted \ No newline at end of file diff --git a/roles/requirements.yml b/roles/requirements.yml index d7889ba..2252121 100644 --- a/roles/requirements.yml +++ b/roles/requirements.yml @@ -17,4 +17,5 @@ # Infra - name: bertvv.bind -- name: bertvv.dhcp +- name: bertvv.dhcp +- name: linux-system-roles.network