From e0acbe63836a32fbfa092b06010cde8043758603 Mon Sep 17 00:00:00 2001 From: grok Date: Sun, 17 Aug 2025 17:30:41 +0200 Subject: [PATCH] add claude_rhel_inventory.yml --- claude_rhel_inventory.yml | 248 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 248 insertions(+) create mode 100644 claude_rhel_inventory.yml diff --git a/claude_rhel_inventory.yml b/claude_rhel_inventory.yml new file mode 100644 index 0000000..94dceb1 --- /dev/null +++ b/claude_rhel_inventory.yml @@ -0,0 +1,248 @@ +--- +- name: Gather Red Hat Insights Inventory + hosts: localhost + gather_facts: false + vars: + # Red Hat Insights API configuration + insights_base_url: "https://console.redhat.com/api" + insights_username: "{{ vault_insights_username | default('') }}" + insights_password: "{{ vault_insights_password | default('') }}" + # Alternative: Use offline token instead of username/password + insights_offline_token: "{{ vault_insights_offline_token | default('') }}" + + # Output configuration + output_dir: "./insights_inventory" + output_format: "json" # Options: json, yaml, csv + + # API endpoints + inventory_endpoint: "/inventory/v1/hosts" + system_profile_endpoint: "/inventory/v1/hosts/{host_id}/system_profile" + + # Filters (optional) + insights_filters: + # Display name contains filter + # display_name: "prod" + # Operating system filter + # operating_system: "RHEL" + # Tags filter (format: namespace/key=value) + # tags: "environment/prod" + # Staleness filter (fresh, stale, stale_warning, unknown) + # staleness: "fresh" + + tasks: + - name: Create output directory + file: + path: "{{ output_dir }}" + state: directory + mode: '0755' + + - name: Get access token using offline token + uri: + url: "https://sso.redhat.com/auth/realms/redhat-external/protocol/openid-connect/token" + method: POST + body_format: form-urlencoded + body: + grant_type: "refresh_token" + client_id: "rhsm-api" + refresh_token: "{{ insights_offline_token }}" + headers: + Content-Type: "application/x-www-form-urlencoded" + register: token_response + when: insights_offline_token | length > 0 + no_log: true + + - name: Set access token from offline token response + set_fact: + access_token: "{{ token_response.json.access_token }}" + when: insights_offline_token | length > 0 + + - name: Get access token using username/password + uri: + url: "https://sso.redhat.com/auth/realms/redhat-external/protocol/openid-connect/token" + method: POST + body_format: form-urlencoded + body: + grant_type: "password" + client_id: "rhsm-api" + username: "{{ insights_username }}" + password: "{{ insights_password }}" + headers: + Content-Type: "application/x-www-form-urlencoded" + register: token_response_pwd + when: + - insights_offline_token | length == 0 + - insights_username | length > 0 + - insights_password | length > 0 + no_log: true + + - name: Set access token from username/password response + set_fact: + access_token: "{{ token_response_pwd.json.access_token }}" + when: + - insights_offline_token | length == 0 + - insights_username | length > 0 + - insights_password | length > 0 + + - name: Fail if no authentication method provided + fail: + msg: "Please provide either insights_offline_token or both insights_username and insights_password" + when: access_token is not defined + + - name: Build query parameters for API request + set_fact: + query_params: "{{ query_params | default({}) | combine({item.key: item.value}) }}" + loop: "{{ insights_filters | dict2items }}" + when: insights_filters is defined + + - name: Get initial inventory page + uri: + url: "{{ insights_base_url }}{{ inventory_endpoint }}" + method: GET + headers: + Authorization: "Bearer {{ access_token }}" + Content-Type: "application/json" + body_format: json + body: "{{ query_params | default({}) }}" + register: initial_inventory_response + + - name: Initialize inventory collection + set_fact: + all_hosts: "{{ initial_inventory_response.json.results }}" + total_hosts: "{{ initial_inventory_response.json.total }}" + current_page: 1 + per_page: "{{ initial_inventory_response.json.per_page | default(50) }}" + + - name: Display initial inventory stats + debug: + msg: "Found {{ total_hosts }} total hosts. Retrieved {{ all_hosts | length }} hosts on first page." + + - name: Get remaining inventory pages + uri: + url: "{{ insights_base_url }}{{ inventory_endpoint }}" + method: GET + headers: + Authorization: "Bearer {{ access_token }}" + Content-Type: "application/json" + body_format: json + body: "{{ (query_params | default({})) | combine({'page': item, 'per_page': per_page}) }}" + register: inventory_page_response + loop: "{{ range(2, ((total_hosts | int / per_page | int) | round(0, 'ceil') | int) + 1) }}" + when: (total_hosts | int) > per_page + + - name: Combine all inventory pages + set_fact: + all_hosts: "{{ all_hosts + item.json.results }}" + loop: "{{ inventory_page_response.results | default([]) }}" + when: inventory_page_response.results is defined + + - name: Get detailed system profiles for each host + uri: + url: "{{ insights_base_url }}/inventory/v1/hosts/{{ item.id }}/system_profile" + method: GET + headers: + Authorization: "Bearer {{ access_token }}" + Content-Type: "application/json" + register: system_profiles + loop: "{{ all_hosts }}" + loop_control: + label: "{{ item.display_name | default(item.id) }}" + + - name: Combine host data with system profiles + set_fact: + enriched_hosts: "{{ enriched_hosts | default([]) + [item.0 | combine({'system_profile': item.1.json.results})] }}" + loop: "{{ all_hosts | zip(system_profiles.results) | list }}" + loop_control: + label: "{{ item.0.display_name | default(item.0.id) }}" + + - name: Create summary statistics + set_fact: + inventory_summary: + total_hosts: "{{ enriched_hosts | length }}" + collection_timestamp: "{{ ansible_date_time.iso8601 }}" + operating_systems: "{{ enriched_hosts | map(attribute='system_profile') | map(attribute='operating_system') | flatten | map(attribute='name') | unique | list }}" + architectures: "{{ enriched_hosts | map(attribute='system_profile') | map(attribute='arch') | flatten | unique | list }}" + insights_client_versions: "{{ enriched_hosts | map(attribute='insights_id') | select | list | length }}" + + - name: Save inventory as JSON + copy: + content: "{{ {'summary': inventory_summary, 'hosts': enriched_hosts} | to_nice_json }}" + dest: "{{ output_dir }}/insights_inventory.json" + when: output_format == "json" + + - name: Save inventory as YAML + copy: + content: "{{ {'summary': inventory_summary, 'hosts': enriched_hosts} | to_nice_yaml }}" + dest: "{{ output_dir }}/insights_inventory.yml" + when: output_format == "yaml" + + - name: Create CSV headers + set_fact: + csv_headers: "id,display_name,fqdn,account,org_id,subscription_manager_id,insights_id,satellite_id,updated,created,stale_timestamp,operating_system,arch,kernel_version,cpu_count,memory,network_interfaces,tags" + when: output_format == "csv" + + - name: Generate CSV content + set_fact: + csv_content: "{{ csv_content | default(csv_headers + '\n') + + item.id + ',' + + (item.display_name | default('') | string) + ',' + + (item.fqdn | default('') | string) + ',' + + (item.account | string) + ',' + + (item.org_id | string) + ',' + + (item.subscription_manager_id | default('') | string) + ',' + + (item.insights_id | default('') | string) + ',' + + (item.satellite_id | default('') | string) + ',' + + (item.updated | string) + ',' + + (item.created | string) + ',' + + (item.stale_timestamp | default('') | string) + ',' + + ((item.system_profile.operating_system.name | default('')) | string) + ',' + + (item.system_profile.arch | default('') | string) + ',' + + (item.system_profile.kernel_version | default('') | string) + ',' + + (item.system_profile.cpu_count | default('') | string) + ',' + + (item.system_profile.system_memory_bytes | default('') | string) + ',' + + (item.system_profile.network_interfaces | length | default('') | string) + ',' + + (item.tags | map(attribute='key') | join(';') | default('')) + '\n' }}" + loop: "{{ enriched_hosts }}" + when: output_format == "csv" + + - name: Save inventory as CSV + copy: + content: "{{ csv_content }}" + dest: "{{ output_dir }}/insights_inventory.csv" + when: output_format == "csv" + + - name: Save individual host files + copy: + content: "{{ item | to_nice_json }}" + dest: "{{ output_dir }}/hosts/{{ item.display_name | default(item.id) }}.json" + loop: "{{ enriched_hosts }}" + loop_control: + label: "{{ item.display_name | default(item.id) }}" + + - name: Create host directory + file: + path: "{{ output_dir }}/hosts" + state: directory + mode: '0755' + + - name: Display collection summary + debug: + var: inventory_summary + + - name: Display completion message + debug: + msg: | + Insights inventory collection completed successfully! + + Summary: + - Total hosts collected: {{ inventory_summary.total_hosts }} + - Output directory: {{ output_dir }} + - Output format: {{ output_format }} + - Collection timestamp: {{ inventory_summary.collection_timestamp }} + + Files created: + - Main inventory: {{ output_dir }}/insights_inventory.{{ output_format }} + - Individual host files: {{ output_dir }}/hosts/ + + Operating Systems found: {{ inventory_summary.operating_systems | join(', ') }} + Architectures found: {{ inventory_summary.architectures | join(', ') }} +