diff --git a/awx/main/management/commands/run_fact_cache_receiver.py b/awx/main/management/commands/run_fact_cache_receiver.py index 1d03757eb2..4bc97eea05 100644 --- a/awx/main/management/commands/run_fact_cache_receiver.py +++ b/awx/main/management/commands/run_fact_cache_receiver.py @@ -120,6 +120,12 @@ class FactBrokerWorker(ConsumerMixin): ret = self._do_fact_scan_create_update(host_obj, module_name, facts, self.timestamp) if job.store_facts is True: + if module_name == 'insights': + try: + host_obj.insights_machine_id = facts['machine_id'] + host_obj.save() + except StandardError: + logger.warn('Failed to find insights machine id in insights fact scan.') self._do_gather_facts_update(host_obj, module_name, facts, self.timestamp) message.ack() diff --git a/awx/main/migrations/0038_v320_release.py b/awx/main/migrations/0038_v320_release.py index 3ffcd98c81..cd8aa60024 100644 --- a/awx/main/migrations/0038_v320_release.py +++ b/awx/main/migrations/0038_v320_release.py @@ -236,4 +236,15 @@ class Migration(migrations.Migration): migrations.DeleteModel( name='Permission', ), + + # Insights + migrations.AddField( + model_name='host', + name='insights_machine_id', + field=models.TextField(default=None, help_text='Red Hat Insights host unique identifier.', null=True, db_index=True, blank=True), + ), + migrations.AlterUniqueTogether( + name='host', + unique_together=set([('insights_machine_id', 'inventory'), ('name', 'inventory')]), + ), ] diff --git a/awx/main/models/inventory.py b/awx/main/models/inventory.py index 9659a35ba0..a63fa3859e 100644 --- a/awx/main/models/inventory.py +++ b/awx/main/models/inventory.py @@ -350,7 +350,7 @@ class Host(CommonModelNameNotUnique): class Meta: app_label = 'main' - unique_together = (("name", "inventory"),) # FIXME: Add ('instance_id', 'inventory') after migration. + unique_together = (("name", "inventory"), ("insights_machine_id", "inventory"),) # FIXME: Add ('instance_id', 'inventory') after migration. ordering = ('name',) inventory = models.ForeignKey( @@ -411,6 +411,13 @@ class Host(CommonModelNameNotUnique): default={}, help_text=_('Arbitrary JSON structure of most recent ansible_facts, per-host.'), ) + insights_machine_id = models.TextField( + blank=True, + default=None, + null=True, + db_index=True, + help_text=_('Red Hat Insights host unique identifier.'), + ) objects = HostManager() diff --git a/awx/playbooks/scan_facts.yml b/awx/playbooks/scan_facts.yml index d24d07d6fa..56b649c3c8 100644 --- a/awx/playbooks/scan_facts.yml +++ b/awx/playbooks/scan_facts.yml @@ -17,6 +17,9 @@ get_checksum: '{{ scan_use_checksum }}' recursive: '{{ scan_use_recursive }}' when: scan_file_paths is defined and ansible_os_family != "Windows" + - name: "Scan Insights for Machine ID (Unix/Linux)" + scan_insights: + when: ansible_os_family != "Windows" - name: "Scan packages (Windows)" win_scan_packages: diff --git a/awx/plugins/library/scan_insights.py b/awx/plugins/library/scan_insights.py new file mode 100755 index 0000000000..5b6829dcb2 --- /dev/null +++ b/awx/plugins/library/scan_insights.py @@ -0,0 +1,68 @@ +#!/usr/bin/env python + +from ansible.module_utils.basic import * # noqa +import uuid + +DOCUMENTATION = ''' +--- +module: scan_insights +short_description: Return insights UUID as fact data +description: + - Inspects the /etc/redhat-access-insights/machine-id file for insights uuid and returns the found UUID as fact data +version_added: "2.3" +options: +requirements: [ ] +author: Chris Meyers +''' + +EXAMPLES = ''' +# Example fact output: +# host | success >> { +# "ansible_facts": { +# "insights": { +# "machine_id": "4da7d1f8-14f3-4cdc-acd5-a3465a41f25d" +# }, ... } +''' + + +INSIGHTS_MACHINE_ID_FILE='/etc/redhat-access-insights/machine-id' + + +def get_machine_uuid(filname): + machine_uuid = None + try: + f = open(INSIGHTS_MACHINE_ID_FILE, "r") + except IOError: + return None + else: + try: + data = f.readline() + machine_uuid = str(uuid.UUID(data)) + except (IOError, ValueError): + pass + finally: + f.close() + return machine_uuid + + +def main(): + module = AnsibleModule( + argument_spec = dict() + ) + + machine_uuid = get_machine_uuid(INSIGHTS_MACHINE_ID_FILE) + + if machine_uuid is not None: + results = { + 'ansible_facts': { + 'insights': { + 'machine_id': machine_uuid + } + } + } + else: + results = dict(skipped=True, msg="Insights machine id not found") + module.exit_json(**results) + + +main()