From a9cdf076904f1782ddfcbbe48bff7b068b40d934 Mon Sep 17 00:00:00 2001 From: Chris Meyers Date: Wed, 5 Aug 2020 13:33:24 -0400 Subject: [PATCH] push global invsource fields onto invsource obj --- awx/api/serializers.py | 2 +- awx/main/migrations/0118_inventory_plugins.py | 32 ++++++++++++++- awx/main/models/inventory.py | 34 ++++++++++++++- awx/main/tasks.py | 30 ++++++-------- awx/settings/defaults.py | 41 +------------------ 5 files changed, 79 insertions(+), 60 deletions(-) diff --git a/awx/api/serializers.py b/awx/api/serializers.py index 9cf953262b..83575025e7 100644 --- a/awx/api/serializers.py +++ b/awx/api/serializers.py @@ -1937,7 +1937,7 @@ class InventorySourceOptionsSerializer(BaseSerializer): class Meta: fields = ('*', 'source', 'source_path', 'source_script', 'source_vars', 'credential', - 'overwrite', 'overwrite_vars', + 'enabled_var', 'enabled_value', 'host_filter', 'overwrite', 'overwrite_vars', 'custom_virtualenv', 'timeout', 'verbosity') def get_related(self, obj): diff --git a/awx/main/migrations/0118_inventory_plugins.py b/awx/main/migrations/0118_inventory_plugins.py index e69a3b7740..da21337d69 100644 --- a/awx/main/migrations/0118_inventory_plugins.py +++ b/awx/main/migrations/0118_inventory_plugins.py @@ -4,7 +4,7 @@ import logging import json import yaml -from django.db import migrations +from django.db import migrations, models from awx.main.models.base import VarsDictProperty @@ -90,4 +90,34 @@ class Migration(migrations.Migration): model_name='inventoryupdate', name='source_regions', ), + migrations.AddField( + model_name='inventorysource', + name='enabled_value', + field=models.TextField(blank=True, default='', help_text='Only used when enabled_var is set. Value when the host is considered enabled. For example if enabled_var="status.power_state"and enabled_value="powered_on" with host variables:{ "status": { "power_state": "powered_on", "created": "2020-08-04T18:13:04+00:00", "healthy": true }, "name": "foobar", "ip_address": "192.168.2.1"}The host would be marked enabled. If power_state where any value other than powered_on then the host would be disabled when imported into Tower. If the key is not found then the host will be enabled'), + ), + migrations.AddField( + model_name='inventorysource', + name='enabled_var', + field=models.TextField(blank=True, default='', help_text='Retrieve the enabled state from the given dict of host variables. The enabled variable may be specified as "foo.bar", in which case the lookup will traverse into nested dicts, equivalent to: from_dict.get("foo", {}).get("bar", default)'), + ), + migrations.AddField( + model_name='inventorysource', + name='host_filter', + field=models.TextField(blank=True, default='', help_text='Regex where only matching hosts will be imported into Tower.'), + ), + migrations.AddField( + model_name='inventoryupdate', + name='enabled_value', + field=models.TextField(blank=True, default='', help_text='Only used when enabled_var is set. Value when the host is considered enabled. For example if enabled_var="status.power_state"and enabled_value="powered_on" with host variables:{ "status": { "power_state": "powered_on", "created": "2020-08-04T18:13:04+00:00", "healthy": true }, "name": "foobar", "ip_address": "192.168.2.1"}The host would be marked enabled. If power_state where any value other than powered_on then the host would be disabled when imported into Tower. If the key is not found then the host will be enabled'), + ), + migrations.AddField( + model_name='inventoryupdate', + name='enabled_var', + field=models.TextField(blank=True, default='', help_text='Retrieve the enabled state from the given dict of host variables. The enabled variable may be specified as "foo.bar", in which case the lookup will traverse into nested dicts, equivalent to: from_dict.get("foo", {}).get("bar", default)'), + ), + migrations.AddField( + model_name='inventoryupdate', + name='host_filter', + field=models.TextField(blank=True, default='', help_text='Regex where only matching hosts will be imported into Tower.'), + ), ] diff --git a/awx/main/models/inventory.py b/awx/main/models/inventory.py index 6e3a22434c..79568ce2a2 100644 --- a/awx/main/models/inventory.py +++ b/awx/main/models/inventory.py @@ -7,7 +7,6 @@ import time import logging import re import copy -import json import os.path from urllib.parse import urljoin import yaml @@ -863,6 +862,39 @@ class InventorySourceOptions(BaseModel): default='', help_text=_('Inventory source variables in YAML or JSON format.'), ) + enabled_var = models.TextField( + blank=True, + default='', + help_text=_('Retrieve the enabled state from the given dict of host ' + 'variables. The enabled variable may be specified as "foo.bar", ' + 'in which case the lookup will traverse into nested dicts, ' + 'equivalent to: from_dict.get("foo", {}).get("bar", default)'), + ) + enabled_value = models.TextField( + blank=True, + default='', + help_text=_('Only used when enabled_var is set. Value when the host is ' + 'considered enabled. For example if enabled_var="status.power_state"' + 'and enabled_value="powered_on" with host variables:' + '{' + ' "status": {' + ' "power_state": "powered_on",' + ' "created": "2020-08-04T18:13:04+00:00",' + ' "healthy": true' + ' },' + ' "name": "foobar",' + ' "ip_address": "192.168.2.1"' + '}' + 'The host would be marked enabled. If power_state where any ' + 'value other than powered_on then the host would be disabled ' + 'when imported into Tower. If the key is not found then the ' + 'host will be enabled'), + ) + host_filter = models.TextField( + blank=True, + default='', + help_text=_('Regex where only matching hosts will be imported into Tower.'), + ) overwrite = models.BooleanField( default=False, help_text=_('Overwrite local groups and hosts from remote inventory source.'), diff --git a/awx/main/tasks.py b/awx/main/tasks.py index acd7548a91..4809d2c136 100644 --- a/awx/main/tasks.py +++ b/awx/main/tasks.py @@ -23,6 +23,7 @@ import fcntl from pathlib import Path from uuid import uuid4 import urllib.parse as urlparse +import shlex # Django from django.conf import settings @@ -2559,23 +2560,18 @@ class RunInventoryUpdate(BaseTask): args.extend(['--venv', inventory_update.ansible_virtualenv_path]) src = inventory_update.source - # Add several options to the shell arguments based on the - # inventory-source-specific setting in the AWX configuration. - # These settings are "per-source"; it's entirely possible that - # they will be different between cloud providers if an AWX user - # actively uses more than one. - if getattr(settings, '%s_ENABLED_VAR' % src.upper(), False): - args.extend(['--enabled-var', - getattr(settings, '%s_ENABLED_VAR' % src.upper())]) - if getattr(settings, '%s_ENABLED_VALUE' % src.upper(), False): - args.extend(['--enabled-value', - getattr(settings, '%s_ENABLED_VALUE' % src.upper())]) - if getattr(settings, '%s_GROUP_FILTER' % src.upper(), False): - args.extend(['--group-filter', - getattr(settings, '%s_GROUP_FILTER' % src.upper())]) - if getattr(settings, '%s_HOST_FILTER' % src.upper(), False): - args.extend(['--host-filter', - getattr(settings, '%s_HOST_FILTER' % src.upper())]) + if inventory_update.enabled_var: + args.extend(['--enabled-var', shlex.quote(inventory_update.enabled_var)]) + args.extend(['--enabled-value', shlex.quote(inventory_update.enabled_value)]) + else: + if getattr(settings, '%s_ENABLED_VAR' % src.upper(), False): + args.extend(['--enabled-var', + getattr(settings, '%s_ENABLED_VAR' % src.upper())]) + if getattr(settings, '%s_ENABLED_VALUE' % src.upper(), False): + args.extend(['--enabled-value', + getattr(settings, '%s_ENABLED_VALUE' % src.upper())]) + if inventory_update.host_filter: + args.extend(['--host-filter', shlex.quote(inventory_update.host_filter)]) if getattr(settings, '%s_EXCLUDE_EMPTY_GROUPS' % src.upper()): args.append('--exclude-empty-groups') if getattr(settings, '%s_INSTANCE_ID_VAR' % src.upper(), False): diff --git a/awx/settings/defaults.py b/awx/settings/defaults.py index 93e373e401..5aa0b834ea 100644 --- a/awx/settings/defaults.py +++ b/awx/settings/defaults.py @@ -669,59 +669,32 @@ INV_ENV_VARIABLE_BLOCKED = ("HOME", "USER", "_", "TERM") # ---------------- # -- Amazon EC2 -- # ---------------- - -# Inventory variable name/values for determining if host is active/enabled. EC2_ENABLED_VAR = 'ec2_state' EC2_ENABLED_VALUE = 'running' - -# Inventory variable name containing unique instance ID. EC2_INSTANCE_ID_VAR = 'ec2_id' - -# Filter for allowed group/host names when importing inventory from EC2. -EC2_GROUP_FILTER = r'^.+$' -EC2_HOST_FILTER = r'^.+$' EC2_EXCLUDE_EMPTY_GROUPS = True - # ------------ # -- VMware -- # ------------ -# Inventory variable name/values for determining whether a host is -# active in vSphere. VMWARE_ENABLED_VAR = 'guest.gueststate' VMWARE_ENABLED_VALUE = 'running' - -# Inventory variable name containing the unique instance ID. VMWARE_INSTANCE_ID_VAR = 'config.instanceUuid, config.instanceuuid' - -# Filter for allowed group and host names when importing inventory -# from VMware. -VMWARE_GROUP_FILTER = r'^.+$' -VMWARE_HOST_FILTER = r'^.+$' VMWARE_EXCLUDE_EMPTY_GROUPS = True VMWARE_VALIDATE_CERTS = False + # --------------------------- # -- Google Compute Engine -- # --------------------------- - -# Inventory variable name/value for determining whether a host is active -# in Google Compute Engine. GCE_ENABLED_VAR = 'status' GCE_ENABLED_VALUE = 'running' - -# Filter for allowed group and host names when importing inventory from -# Google Compute Engine. -GCE_GROUP_FILTER = r'^.+$' -GCE_HOST_FILTER = r'^.+$' GCE_EXCLUDE_EMPTY_GROUPS = True GCE_INSTANCE_ID_VAR = 'gce_id' # -------------------------------------- # -- Microsoft Azure Resource Manager -- # -------------------------------------- -AZURE_RM_GROUP_FILTER = r'^.+$' -AZURE_RM_HOST_FILTER = r'^.+$' AZURE_RM_ENABLED_VAR = 'powerstate' AZURE_RM_ENABLED_VALUE = 'running' AZURE_RM_INSTANCE_ID_VAR = 'id' @@ -732,8 +705,6 @@ AZURE_RM_EXCLUDE_EMPTY_GROUPS = True # --------------------- OPENSTACK_ENABLED_VAR = 'status' OPENSTACK_ENABLED_VALUE = 'ACTIVE' -OPENSTACK_GROUP_FILTER = r'^.+$' -OPENSTACK_HOST_FILTER = r'^.+$' OPENSTACK_EXCLUDE_EMPTY_GROUPS = True OPENSTACK_INSTANCE_ID_VAR = 'openstack.id' @@ -742,8 +713,6 @@ OPENSTACK_INSTANCE_ID_VAR = 'openstack.id' # --------------------- RHV_ENABLED_VAR = 'status' RHV_ENABLED_VALUE = 'up' -RHV_GROUP_FILTER = r'^.+$' -RHV_HOST_FILTER = r'^.+$' RHV_EXCLUDE_EMPTY_GROUPS = True RHV_INSTANCE_ID_VAR = 'id' @@ -752,8 +721,6 @@ RHV_INSTANCE_ID_VAR = 'id' # --------------------- TOWER_ENABLED_VAR = 'remote_tower_enabled' TOWER_ENABLED_VALUE = 'true' -TOWER_GROUP_FILTER = r'^.+$' -TOWER_HOST_FILTER = r'^.+$' TOWER_EXCLUDE_EMPTY_GROUPS = True TOWER_INSTANCE_ID_VAR = 'remote_tower_id' @@ -762,8 +729,6 @@ TOWER_INSTANCE_ID_VAR = 'remote_tower_id' # --------------------- SATELLITE6_ENABLED_VAR = 'foreman.enabled' SATELLITE6_ENABLED_VALUE = 'True' -SATELLITE6_GROUP_FILTER = r'^.+$' -SATELLITE6_HOST_FILTER = r'^.+$' SATELLITE6_EXCLUDE_EMPTY_GROUPS = True SATELLITE6_INSTANCE_ID_VAR = 'foreman.id' # SATELLITE6_GROUP_PREFIX and SATELLITE6_GROUP_PATTERNS defined in source vars @@ -773,8 +738,6 @@ SATELLITE6_INSTANCE_ID_VAR = 'foreman.id' # --------------------- #CUSTOM_ENABLED_VAR = #CUSTOM_ENABLED_VALUE = -CUSTOM_GROUP_FILTER = r'^.+$' -CUSTOM_HOST_FILTER = r'^.+$' CUSTOM_EXCLUDE_EMPTY_GROUPS = False #CUSTOM_INSTANCE_ID_VAR = @@ -783,8 +746,6 @@ CUSTOM_EXCLUDE_EMPTY_GROUPS = False # --------------------- #SCM_ENABLED_VAR = #SCM_ENABLED_VALUE = -SCM_GROUP_FILTER = r'^.+$' -SCM_HOST_FILTER = r'^.+$' SCM_EXCLUDE_EMPTY_GROUPS = False #SCM_INSTANCE_ID_VAR =