summaryrefslogtreecommitdiffstats
path: root/ansible_collections/azure/azcollection/plugins/inventory
diff options
context:
space:
mode:
Diffstat (limited to 'ansible_collections/azure/azcollection/plugins/inventory')
-rw-r--r--ansible_collections/azure/azcollection/plugins/inventory/azure_rm.py99
1 files changed, 77 insertions, 22 deletions
diff --git a/ansible_collections/azure/azcollection/plugins/inventory/azure_rm.py b/ansible_collections/azure/azcollection/plugins/inventory/azure_rm.py
index 3442aa124..12970dec3 100644
--- a/ansible_collections/azure/azcollection/plugins/inventory/azure_rm.py
+++ b/ansible_collections/azure/azcollection/plugins/inventory/azure_rm.py
@@ -105,6 +105,14 @@ exclude_host_filters:
- tags['tagkey2'] is defined and tags['tagkey2'] == 'tagkey2'
# excludes hosts that are powered off
- powerstate != 'running'
+
+# includes a host to the inventory when any of these expressions is true, can refer to any vars defined on the host
+include_host_filters:
+ # includes hosts that in the eastus region and power on
+ - location in ['eastus'] and powerstate == 'running'
+ # includes hosts in the eastus region and power on OR includes hosts in the eastus2 region and tagkey is tagkey
+ - location in ['eastus'] and powerstate == 'running'
+ - location in ['eastus2'] and tags['tagkey'] is defined and tags['tagkey'] == 'tagkey'
'''
# FUTURE: do we need a set of sane default filters, separate from the user-defineable ones?
@@ -130,12 +138,15 @@ from ansible.errors import AnsibleParserError, AnsibleError
from ansible.module_utils.parsing.convert_bool import boolean
from ansible.module_utils._text import to_native, to_bytes, to_text
from itertools import chain
+from os import environ
try:
from azure.core._pipeline_client import PipelineClient
from azure.core.pipeline.policies import BearerTokenCredentialPolicy
from azure.core.configuration import Configuration
from azure.mgmt.core.tools import parse_resource_id
+ from azure.core.pipeline import PipelineResponse
+ from azure.mgmt.core.polling.arm_polling import ARMPolling
except ImportError:
Configuration = object
parse_resource_id = object
@@ -199,7 +210,7 @@ class InventoryModule(BaseInventoryPlugin, Constructable):
if re.match(r'.{0,}azure_rm\.y(a)?ml$', path):
return True
# display.debug("azure_rm inventory filename must end with 'azure_rm.yml' or 'azure_rm.yaml'")
- return False
+ raise AnsibleError("azure_rm inventory filename must end with 'azure_rm.yml' or 'azure_rm.yaml'")
def parse(self, inventory, loader, path, cache=True):
super(InventoryModule, self).parse(inventory, loader, path)
@@ -215,6 +226,8 @@ class InventoryModule(BaseInventoryPlugin, Constructable):
self._filters = self.get_option('exclude_host_filters') + self.get_option('default_host_filters')
+ self._include_filters = self.get_option('include_host_filters')
+
try:
self._credential_setup()
self._get_hosts()
@@ -222,8 +235,9 @@ class InventoryModule(BaseInventoryPlugin, Constructable):
raise
def _credential_setup(self):
+ auth_source = environ.get('ANSIBLE_AZURE_AUTH_SOURCE', None) or self.get_option('auth_source')
auth_options = dict(
- auth_source=self.get_option('auth_source'),
+ auth_source=auth_source,
profile=self.get_option('profile'),
subscription_id=self.get_option('subscription_id'),
client_id=self.get_option('client_id'),
@@ -238,6 +252,18 @@ class InventoryModule(BaseInventoryPlugin, Constructable):
adfs_authority_url=self.get_option('adfs_authority_url')
)
+ if self.templar.is_template(auth_options["tenant"]):
+ auth_options["tenant"] = self.templar.template(variable=auth_options["tenant"], disable_lookups=False)
+
+ if self.templar.is_template(auth_options["client_id"]):
+ auth_options["client_id"] = self.templar.template(variable=auth_options["client_id"], disable_lookups=False)
+
+ if self.templar.is_template(auth_options["secret"]):
+ auth_options["secret"] = self.templar.template(variable=auth_options["secret"], disable_lookups=False)
+
+ if self.templar.is_template(auth_options["subscription_id"]):
+ auth_options["subscription_id"] = self.templar.template(variable=auth_options["subscription_id"], disable_lookups=False)
+
self.azure_auth = AzureRMAuth(**auth_options)
self._clientconfig = AzureRMRestConfiguration(self.azure_auth.azure_credential_track2, self.azure_auth.subscription_id,
@@ -297,12 +323,14 @@ class InventoryModule(BaseInventoryPlugin, Constructable):
for h in self._hosts:
# FUTURE: track hostnames to warn if a hostname is repeated (can happen for legacy and for composed inventory_hostname)
inventory_hostname = self._get_hostname(h, hostnames=constructable_hostnames, strict=constructable_config_strict)
- if self._filter_host(inventory_hostname, h.hostvars):
+ if self._filter_exclude_host(inventory_hostname, h.hostvars):
+ continue
+ if not self._filter_include_host(inventory_hostname, h.hostvars):
continue
self.inventory.add_host(inventory_hostname)
# FUTURE: configurable default IP list? can already do this via hostvar_expressions
self.inventory.set_variable(inventory_hostname, "ansible_host",
- next(chain(h.hostvars['public_ipv4_addresses'], h.hostvars['private_ipv4_addresses']), None))
+ next(chain(h.hostvars['public_ipv4_address'], h.hostvars['private_ipv4_addresses']), None))
for k, v in iteritems(h.hostvars):
# FUTURE: configurable hostvar prefix? Makes docs harder...
self.inventory.set_variable(inventory_hostname, k, v)
@@ -313,10 +341,10 @@ class InventoryModule(BaseInventoryPlugin, Constructable):
self._add_host_to_keyed_groups(constructable_config_keyed_groups, h.hostvars, inventory_hostname, strict=constructable_config_strict)
# FUTURE: fix underlying inventory stuff to allow us to quickly access known groupvars from reconciled host
- def _filter_host(self, inventory_hostname, hostvars):
+ def _filter_host(self, filter, inventory_hostname, hostvars):
self.templar.available_variables = hostvars
- for condition in self._filters:
+ for condition in filter:
# FUTURE: should warn/fail if conditional doesn't return True or False
conditional = "{{% if {0} %}} True {{% else %}} False {{% endif %}}".format(condition)
try:
@@ -329,6 +357,12 @@ class InventoryModule(BaseInventoryPlugin, Constructable):
return False
+ def _filter_include_host(self, inventory_hostname, hostvars):
+ return self._filter_host(self._include_filters, inventory_hostname, hostvars)
+
+ def _filter_exclude_host(self, inventory_hostname, hostvars):
+ return self._filter_host(self._filters, inventory_hostname, hostvars)
+
def _get_hostname(self, host, hostnames=None, strict=False):
hostname = None
errors = []
@@ -441,8 +475,18 @@ class InventoryModule(BaseInventoryPlugin, Constructable):
request_new = self.new_client.post(url, query_parameters, header_parameters, body_content)
response = self.new_client.send_request(request_new)
-
- return json.loads(response.body())
+ if response.status_code == 202:
+ try:
+ poller = ARMPolling(timeout=3)
+ poller.initialize(client=self.new_client,
+ initial_response=PipelineResponse(None, response, None),
+ deserialization_callback=lambda r: r)
+ poller.run()
+ return poller.resource().context['deserialized_data']
+ except Exception as ec:
+ raise
+ else:
+ return json.loads(response.body())
def send_request(self, url, api_version):
query_parameters = {'api-version': api_version}
@@ -525,9 +569,11 @@ class AzureHost(object):
network_interface_id=[],
security_group_id=[],
security_group=[],
- public_ipv4_addresses=[],
+ public_ip_address=[],
+ public_ipv4_address=[],
public_dns_hostnames=[],
private_ipv4_addresses=[],
+ subnet=[],
id=self._vm_model['id'],
location=self._vm_model['location'],
name=self._vm_model['name'],
@@ -550,25 +596,34 @@ class AzureHost(object):
resource_group=parse_resource_id(self._vm_model['id']).get('resource_group').lower(),
default_inventory_hostname=self.default_inventory_hostname,
creation_time=self._vm_model['properties']['timeCreated'],
+ license_type=self._vm_model['properties'].get('licenseType', 'Unknown')
)
# set nic-related values from the primary NIC first
for nic in sorted(self.nics, key=lambda n: n.is_primary, reverse=True):
# and from the primary IP config per NIC first
for ipc in sorted(nic._nic_model['properties']['ipConfigurations'], key=lambda i: i['properties'].get('primary', False), reverse=True):
- private_ip = ipc['properties'].get('privateIPAddress')
- if private_ip:
- new_hostvars['private_ipv4_addresses'].append(private_ip)
- pip_id = ipc['properties'].get('publicIPAddress', {}).get('id')
- if pip_id:
- new_hostvars['public_ip_id'] = pip_id
-
- pip = nic.public_ips[pip_id]
- new_hostvars['public_ip_name'] = pip._pip_model['name']
- new_hostvars['public_ipv4_addresses'].append(pip._pip_model['properties'].get('ipAddress', None))
- pip_fqdn = pip._pip_model['properties'].get('dnsSettings', {}).get('fqdn')
- if pip_fqdn:
- new_hostvars['public_dns_hostnames'].append(pip_fqdn)
+ try:
+ subnet = ipc['properties'].get('subnet')
+ if subnet:
+ new_hostvars['subnet'].append(subnet)
+ private_ip = ipc['properties'].get('privateIPAddress')
+ if private_ip:
+ new_hostvars['private_ipv4_addresses'].append(private_ip)
+ pip_id = ipc['properties'].get('publicIPAddress', {}).get('id')
+ if pip_id and pip_id in nic.public_ips:
+ pip = nic.public_ips[pip_id]
+ new_hostvars['public_ipv4_address'].append(pip._pip_model['properties'].get('ipAddress', None))
+ new_hostvars['public_ip_address'].append({
+ 'id': pip_id,
+ 'name': pip._pip_model['name'],
+ 'ipv4_address': pip._pip_model['properties'].get('ipAddress', None),
+ })
+ pip_fqdn = pip._pip_model['properties'].get('dnsSettings', {}).get('fqdn')
+ if pip_fqdn:
+ new_hostvars['public_dns_hostnames'].append(pip_fqdn)
+ except Exception:
+ continue
new_hostvars['mac_address'].append(nic._nic_model['properties'].get('macAddress'))
new_hostvars['network_interface'].append(nic._nic_model['name'])