diff --git a/roles/telemetry_chargeback/README.md b/roles/telemetry_chargeback/README.md index 6dd432c8..06f9d7c5 100644 --- a/roles/telemetry_chargeback/README.md +++ b/roles/telemetry_chargeback/README.md @@ -1,5 +1,4 @@ telemetry_chargeback -=================== The **`telemetry_chargeback`** role validates and tests the **RHOSO CloudKitty** chargeback feature. It performs CloudKitty configuration validation and generates synthetic test data for chargeback scenario testing. @@ -33,6 +32,8 @@ Role Variables ### User-Configurable Variables (defaults/main.yml) +These variables can be overridden when importing the role or set at the play level. Users can customize these based on their deployment environment and test requirements. + | Variable | Default Value | Description | |----------|---------------|-------------| | `openstack_cmd` | `"openstack"` | OpenStack CLI command (customize if not in PATH) | @@ -40,9 +41,6 @@ Role Variables | `cloudkitty_debug_dir` | `"{{ (cloudkitty_debug \| bool) \| ternary(artifacts_dir_zuul + '/debug_ck_db', '') }}"` | Directory for debug output (auto-set based on debug flag) | | `logs_dir_zuul` | `"{{ cifmw_basedir }}/logs"` | Directory for log files | | `artifacts_dir_zuul` | `"{{ cifmw_basedir }}/artifacts"` | Directory for generated artifacts and test output | -| `cert_dir` | `"{{ cifmw_basedir }}/ck-certs"` | Directory for CloudKitty client certificates | -| `local_cert_dir` | `"{{ cifmw_basedir }}/flush_certs"` | Local directory for flush certificates (cleaned up after run) | -| `remote_cert_dir` | `"osp-certs"` | Remote directory inside OpenStack pod for certificates | | `cert_secret_name` | `"cert-cloudkitty-client-internal"` | OpenShift secret name for client certificates | | `client_secret` | `"secret/cloudkitty-lokistack-gateway-client-http"` | Secret for flush client certificates | | `ca_configmap` | `"cm/cloudkitty-lokistack-ca-bundle"` | ConfigMap for CA bundle | @@ -51,6 +49,7 @@ Role Variables | `openstackpod` | `"openstackclient"` | OpenStack client pod name for exec/cp operations | | `lookback` | `6` | Days to look back for Loki query time range | | `limit` | `50` | Limit for Loki query results | +| `cloudkitty_test_scenarios` | `[]` | List of test scenario files to run (empty = auto-discover) | How It Works ------------ @@ -68,7 +67,8 @@ The role executes the following workflow: - Configures Loki push/query URLs 3. **Test Scenario Discovery** - - Automatically finds all `test_*.yml` files in `files/` directory + - **Auto-discovery** (default): Finds all `test_*.yml` files in `files/` directory + - **User-provided**: Uses scenarios from `cloudkitty_test_scenarios` variable 4. **Scenario Execution Loop** (for each discovered scenario) - Generates synthetic Loki log data (`gen_synth_loki_data.py`) @@ -79,6 +79,9 @@ The role executes the following workflow: - Removes temporary certificate directories - Always runs (even on failure) via block/rescue/always structure +### Loop Variable + +The role uses `{{ scenario_name }}` as the loop variable when processing multiple test scenarios, making it easy to track which scenario is currently executing. Python Scripts -------------- diff --git a/roles/telemetry_chargeback/tasks/ingest_loki_data.yml b/roles/telemetry_chargeback/tasks/ingest_loki_data.yml index 762f2dd6..1d33622e 100644 --- a/roles/telemetry_chargeback/tasks/ingest_loki_data.yml +++ b/roles/telemetry_chargeback/tasks/ingest_loki_data.yml @@ -1,32 +1,23 @@ --- # Ingest data generated by gen_synth_loki_data.yml to Loki -- name: "Ingest data log to Loki via API" - block: +- name: "TEST Push data to Loki" + ansible.builtin.uri: + ## loki_push_url will be used in future role developement + url: "{{ loki_push_url }}" + method: POST + src: "{{ cloudkitty_data_file }}" + body_format: json + client_cert: "{{ cert_dir }}/tls.crt" + client_key: "{{ cert_dir }}/tls.key" + validate_certs: false + status_code: 204 + return_content: true + register: loki_response + ignore_errors: true + failed_when: loki_response.status != 204 - - name: "Push data to Loki" - ansible.builtin.uri: - ## loki_push_url will be used in future role developement - url: "{{ loki_push_url }}" - method: POST - src: "{{ cloudkitty_data_file }}" - body_format: json - client_cert: "{{ cert_dir }}/tls.crt" - client_key: "{{ cert_dir }}/tls.key" - validate_certs: false - status_code: 204 - return_content: true - register: loki_response - ignore_errors: false - failed_when: loki_response.status != 204 - - # Success - - name: "Confirm ingestion success" - ansible.builtin.debug: - msg: "Ingestion Successful!" - - rescue: - # Rescue block - - name: "Debug failure" - ansible.builtin.debug: - msg: "Ingest failed. Loki Status: {{ loki_response.status | default('N/A') }}" +- name: "Ingest Status Message" + ansible.builtin.debug: + msg: "Ingestion Successful" + when: loki_response.status | default(0) == 204 diff --git a/roles/telemetry_chargeback/tasks/load_loki_data.yml b/roles/telemetry_chargeback/tasks/load_loki_data.yml index 37c2aedb..9376dd78 100644 --- a/roles/telemetry_chargeback/tasks/load_loki_data.yml +++ b/roles/telemetry_chargeback/tasks/load_loki_data.yml @@ -4,3 +4,6 @@ - name: "Flush data to Loki storage for {{ scenario_name }}" ansible.builtin.include_tasks: flush_loki_data.yml + +- name: "Retrieve data log from Loki for {{ scenario_name }}" + ansible.builtin.include_tasks: retrieve_loki_data.yml diff --git a/roles/telemetry_chargeback/tasks/retrieve_loki_data.yml b/roles/telemetry_chargeback/tasks/retrieve_loki_data.yml new file mode 100644 index 00000000..e2111529 --- /dev/null +++ b/roles/telemetry_chargeback/tasks/retrieve_loki_data.yml @@ -0,0 +1,71 @@ +--- +- name: "Expected Count {{ scenario_name }}" + ansible.builtin.debug: + msg: "Input file has {{ synth_data_rates.data_log.log_count }} data entries that Loki has to return" + +# Query Loki +- name: "Retrieve Logs from Loki via API {{ scenario_name }}" + block: + - name: "Query Loki API" + ansible.builtin.uri: + url: "{{ loki_query_url }}?query={{ logql_query | urlencode }}&start={{ synth_data_rates.time.begin_step.nanosec }}&limit={{ limit }}" + method: GET + client_cert: "{{ cert_dir }}/tls.crt" + client_key: "{{ cert_dir }}/tls.key" + ca_path: "{{ cert_dir }}/ca.crt" + validate_certs: false + return_content: true + body_format: json + register: loki_response + # Wait condition + until: + - loki_response.status == 200 + - loki_response.json.status == 'success' + - loki_response.json.data.result | length > 0 + - (loki_response.json.data.result | map(attribute='values') | map('length') | sum) >= (synth_data_rates.data_log.log_count | int) + retries: 25 + delay: 60 + + - name: "Save Loki Data to JSON file" + ansible.builtin.copy: + content: "{{ loki_response.json | to_json }}" + dest: "{{ artifacts_dir_zuul }}/{{ scenario_name }}{{ cloudkitty_loki_data_suffix }}" + mode: '0644' + + # Validate + - name: "Verify Data Integrity {{ scenario_name }}" + vars: + actual_count: "{{ loki_response.json.data.result | map(attribute='values') | map('length') | sum }}" + ansible.builtin.assert: + that: + - loki_response.json.status == 'success' + - loki_response.json.data.result | length > 0 + - actual_count | int == (synth_data_rates.data_log.log_count | int) + fail_msg: >- + Query did not return all data entries. Expected + {{ synth_data_rates.data_log.log_count }} log entries, but Loki + only returned {{ actual_count }} + success_msg: "Query returned all data entries. Input file had {{ synth_data_rates.data_log.log_count }} entries and Loki returned {{ actual_count }}" + + rescue: + - name: "Debug failure" + ansible.builtin.debug: + msg: + - "Status: {{ loki_response.status | default('Unknown') }}" + - "Body: {{ loki_response.content | default('No Content') }}" + - "Msg: {{ loki_response.msg | default('Request failed') }}" + + # Failure + - name: "Report Retrieval Failure" + ansible.builtin.fail: + msg: "Retrieval Failed" + +- name: "Generate chargeback stats from Loki-retrieved data file: {{ scenario_name }}" + ansible.builtin.command: + cmd: > + python3 "{{ cloudkitty_summary_script }}" + -j "{{ artifacts_dir_zuul }}/{{ scenario_name }}{{ cloudkitty_loki_data_suffix }}" + -o "{{ artifacts_dir_zuul }}/{{ scenario_name }}{{ cloudkitty_loki_totals_metrics_suffix }}" + --debug "{{ cloudkitty_debug_dir }}" + register: synth_rating_info + changed_when: synth_rating_info.rc == 0