graphiant.naas.graphiant_data_exchange module – Manage Graphiant Data Exchange services, customers, matches, and invitations

Note

This module is part of the graphiant.naas collection (version 26.6.0).

You might already have this collection installed if you are using the ansible package. It is not included in ansible-core. To check whether it is installed, run ansible-galaxy collection list.

To install it, use: ansible-galaxy collection install graphiant.naas. You need further requirements to be able to use this module, see Requirements for details.

To use it in a playbook, specify: graphiant.naas.graphiant_data_exchange.

New in graphiant.naas 25.12.0

Synopsis

  • This module provides comprehensive Data Exchange management capabilities for Graphiant’s B2B peering platform.

  • Enables creating and deleting Data Exchange services and customers.

  • Provides service-to-customer matching operations with automatic match response file management.

  • Supports invitation acceptance with gateway service deployment and VPN configuration.

Requirements

The below requirements are needed on the host that executes this module.

  • python >= 3.7

  • graphiant-sdk >= 26.6.0

  • tabulate

Parameters

Parameter

Comments

access_token

string

Bearer token for API authentication (for example, from graphiant login, which opens a browser for sign-in (SSO or non-SSO) and retrieves the token).

If not passed as a module argument, the collection reads GRAPHIANT_ACCESS_TOKEN (set after graphiant login when you source ~/.graphiant/env.sh).

When a bearer token is present (module argument or environment), it takes precedence over username and password.

If no valid token is available, the module authenticates with username and password when both are supplied.

config_file

string

Path to the YAML configuration file for the operation.

Required for create_services, delete_services, create_customers, update_customers, delete_customers, match_service_to_customers, and accept_invitation operations.

Can be an absolute path or relative path. Relative paths are resolved using the configured config_path.

Configuration files support Jinja2 templating syntax for dynamic generation.

For create_services, file must contain data_exchange_services list. Optional policy.globalObjectOps

per service attaches Graphiant routing policies to devices (device names resolved to IDs).

For create_customers, update_customers, or delete_customers, file must contain data_exchange_customers list.

For match_service_to_customers, file must contain data_exchange_matches list.

For accept_invitation, file must contain data_exchange_acceptances list. Optional globalObjectOps

per acceptance attaches Graphiant routing policies to gateway devices (device names resolved to IDs).

Match responses are saved to output/ directory near the configuration file.

detailed_logs

boolean

Enable detailed logging output for troubleshooting and monitoring.

When enabled, provides comprehensive logs of all Data Exchange operations.

Logs are captured and included in the msg return value for display using ansible.builtin.debug module.

Choices:

  • false ← (default)

  • true

host

aliases: base_url

string / required

Graphiant portal host URL for API connectivity.

Example: “https://api.graphiant.com

matches_file

string

Path to the matches responses JSON file for match ID lookup.

Optional for accept_invitation operation. If not provided, attempts API lookup using the service name (works when the service is already visible in the consumer tenant).

When the service is not yet visible via API (e.g. during a dry-run before acceptance, or when the producer has not shared the service yet), provide this file using -e matches_file=....

Can be an absolute path or relative path. Relative paths are resolved using the configured config_path.

This file is automatically generated by match_service_to_customers operation (Workflow 3) and saved to output/ under the config file directory (e.g. de_workflows_configs/output/sample_data_exchange_matches_responses_latest.json).

File contains match details including customer_id, service_id, match_id, and status.

Match ID resolution priority:

  1. If matches_file provided with match_id and service_id - uses both directly

  2. If matches_file provided with only service_id - looks up match_id via API

  3. If matches_file provided but no entry found - attempts API lookup using service name

  4. If matches_file not provided - attempts API lookup (works if service is visible to consumer)

operation

string / required

The specific Data Exchange operation to perform.

create_services: Create Data Exchange services from YAML configuration (Workflow 1).

Configuration file must contain data_exchange_services list with service definitions.

Services define peering services with LAN segments, sites, and service prefixes.

Optional policy.globalObjectOps: keys are device names (resolved to device IDs) or device IDs;

values can include routingPolicyOps to attach Graphiant filters per device (e.g. Policy-DC1-Primary: Attach).

Configure Graphiant filters first with graphiant.naas.graphiant_global_config and configure_graphiant_filters.

update_services: Update existing Data Exchange services (Workflow 1b). Only prefixTags can be changed. The service must already exist; use create_services for new services. Configuration file must contain data_exchange_services list where each entry has serviceName and policy.prefixTags. At least one prefix must remain after the update. Supports --check and --diff to preview changes before applying.

delete_services: Delete Data Exchange services from YAML configuration. Services must be deleted after customers that depend on them.

create_customers: Create Data Exchange customers from YAML configuration (Workflow 2).

Configuration file must contain data_exchange_customers list with customer definitions.

Customers can be non-Graphiant peers that can be invited to connect to services.

Existing customers are skipped (idempotent). When run with --check and --diff, detects

adminEmail drift on existing customers and surfaces it as a diff — no changes are made;

to apply email changes use update_customers instead.

update_customers: Update email list on existing Data Exchange customers (Workflow 2b). Only invite.adminEmail can be changed. The customer must already exist; use create_customers for new customers. Configuration file must contain data_exchange_customers list where each entry has name and invite.adminEmail. Supports --check and --diff to preview changes before applying.

delete_customers: Delete Data Exchange customers from YAML configuration. Customers must be deleted before services they depend on.

match_service_to_customers: Match services to customers from YAML configuration (Workflow 3).

Configuration file must contain data_exchange_matches list with match definitions.

Automatically saves match responses to JSON file for use in Workflow 4.

Updates existing match entries or appends new ones based on customer_name and service_name.

accept_invitation: Accept Data Exchange service invitation (Workflow 4).

Configuration file must contain data_exchange_acceptances list with acceptance details.

matches_file is optional: when omitted, attempts API lookup (requires service to be visible

in the consumer tenant). When the service is not visible via API, provide matches_file saved

by Workflow 3 (match_service_to_customers) with -e matches_file=....

Supports dry-run mode for validation without API calls.

Use ipsecGatewayPeers (recommended, multi-peer, requires graphiant_sdk >= 26.6.0) or

ipsecGatewayDetails (legacy, single-peer) under siteToSiteVpn in the config file.

Each remotePeers entry provisions one IPSec interface pair per gateway device; BGP routing

is shared across peers; tunnel null fields are auto-filled by the playbook before the API call.

For query operations (get_services_summary, get_customers_summary, get_service_health),

use graphiant.naas.graphiant_data_exchange_info module instead.

Choices:

  • "create_services"

  • "update_services"

  • "delete_services"

  • "create_customers"

  • "update_customers"

  • "delete_customers"

  • "match_service_to_customers"

  • "accept_invitation"

password

string

Graphiant portal password for authentication.

Required for password-based login when no valid bearer token is available from access_token or GRAPHIANT_ACCESS_TOKEN.

state

string

The desired state of the Data Exchange resources.

present: Maps to create_services when operation not specified.

absent: Maps to delete_services when operation not specified.

Choices:

  • "present" ← (default)

  • "absent"

username

string

Graphiant portal username for authentication.

Required for password-based login when no valid bearer token is available from access_token or GRAPHIANT_ACCESS_TOKEN.

vault_data_exchange_bgp_md5_passwords

dictionary

Dict of customer name to BGP MD5 password for accept_invitation. Key must match the customerName field in the acceptance config. Precedence{{ “:” }} YAML md5Password non-null wins; secrets store fills null/absent; absent from both means no MD5 auth (optional field).

Fetch from your organization’s secrets store and pass as a module param. Secrets are never written to disk — passed in memory only (no_log: true).

Ansible Vault{{ “:” }} load with ansible.builtin.include_vars (no_log: true) and pass via vault_data_exchange_bgp_md5_passwords{{ ":" }} "{{ vault_data_exchange_bgp_md5_passwords | default({} }}”). Other secrets stores (HashiCorp Vault, AWS Secrets Manager, etc.){{ “:” }} pre-fetch and pass as an extra var. See configs/vault_secrets.yml.example for the expected dict structure.

Default: {}

vault_data_exchange_psk

dictionary

Nested dict of IPSec tunnel preshared keys for accept_invitation ipsecGatewayPeers configs. Structure{{ “:” }} customerName peer name tunnel1/tunnel2 psk string. Precedence{{ “:” }} YAML psk non-null wins; secrets store fills null/absent; if both are null the API auto-fills the PSK (recommended fallback when vault is omitted).

Fetch from your organization’s secrets store and pass as a module param. Secrets are never written to disk — passed in memory only (no_log: true).

Ansible Vault{{ “:” }} load with ansible.builtin.include_vars (no_log: true) and pass via vault_data_exchange_psk{{ ":" }} "{{ vault_data_exchange_psk | default({} }}”). Other secrets stores (HashiCorp Vault, AWS Secrets Manager, etc.){{ “:” }} pre-fetch and pass as an extra var. See configs/vault_secrets.yml.example for the expected dict structure.

Default: {}

Attributes

Attribute

Support

Description

check_mode

Support: full

Supported. In check mode, no API writes are performed; payloads that would be sent are logged with a [check_mode] prefix.

Notes

Note

  • Data Exchange Workflows:

  • - Workflow 1 (Create Services): Create Data Exchange services that can be shared with customers.

  • - Workflow 2 (Create Customers): Create Data Exchange customers (nonGraphiant peers).

  • - Workflow 3 (Match Services): Match services to customers and establish peering relationships.

  • - Workflow 4 (Accept Invitation): Accept service invitations for non Graphiant customers.

  • Configuration files support Jinja2 templating syntax for dynamic configuration generation.

  • Match responses are automatically saved to JSON files in the output directory near the configuration file.

  • The module automatically resolves names to IDs for sites, LAN segments, services, customers, and regions.

  • All operations are idempotent and safe to run multiple times without creating duplicates.

  • For accept_invitation operation, minimum 2 gateways per region are required for redundancy.

  • Check mode (--check) is supported. In check mode, the module runs all logic (config load, validation,

  • name-to-ID resolution) but the API client skips write operations and logs payloads with [check_mode].

  • Use --check to validate accept_invitation without making API calls.

See Also

See also

graphiant.naas.graphiant_interfaces

Configure interfaces and circuits for Data Exchange prerequisites

graphiant.naas.graphiant_global_config

Configure global objects (LAN segments, VPN profiles) required for Data Exchange

graphiant.naas.graphiant_sites

Configure sites required for Data Exchange services

graphiant.naas.graphiant_data_exchange_info

Query Data Exchange services, customers, and service health information

Examples

- name: Workflow 1 - Create Data Exchange services
  graphiant.naas.graphiant_data_exchange:
    operation: create_services
    config_file: "de_workflows_configs/sample_data_exchange_services.yaml"
    host: "{{ graphiant_host }}"
    username: "{{ graphiant_username }}"
    password: "{{ graphiant_password }}"
    detailed_logs: true
  register: create_services_result

- name: Display services creation result
  ansible.builtin.debug:
    msg: "{{ create_services_result.msg }}"

- name: Workflow 1 - Create services with Jinja2 template (scale testing)
  graphiant.naas.graphiant_data_exchange:
    operation: create_services
    config_file: "de_workflows_configs/sample_data_exchange_services_scale.yaml"
    host: "{{ graphiant_host }}"
    username: "{{ graphiant_username }}"
    password: "{{ graphiant_password }}"
    detailed_logs: true

- name: Workflow 1b - Preview prefixTags changes (check + diff)
  graphiant.naas.graphiant_data_exchange:
    operation: update_services
    config_file: "de_workflows_configs/sample_data_exchange_services_update.yaml"
    host: "{{ graphiant_host }}"
    username: "{{ graphiant_username }}"
    password: "{{ graphiant_password }}"
    detailed_logs: true
  register: update_services_result
  # Run playbook with: ansible-playbook playbook.yml --check --diff

- name: Workflow 1b - Apply prefixTags update
  graphiant.naas.graphiant_data_exchange:
    operation: update_services
    config_file: "de_workflows_configs/sample_data_exchange_services_update.yaml"
    host: "{{ graphiant_host }}"
    username: "{{ graphiant_username }}"
    password: "{{ graphiant_password }}"
    detailed_logs: true
  register: update_services_result

- name: Display service update result
  ansible.builtin.debug:
    msg: "{{ update_services_result.msg }}"

- name: Workflow 2 - Preview customer creation and detect adminEmail drift (check + diff)
  graphiant.naas.graphiant_data_exchange:
    operation: create_customers
    config_file: "de_workflows_configs/sample_data_exchange_customers.yaml"
    host: "{{ graphiant_host }}"
    username: "{{ graphiant_username }}"
    password: "{{ graphiant_password }}"
    detailed_logs: true
  register: create_customers_result
  # Run playbook with: ansible-playbook playbook.yml --check --diff
  # Existing customers with changed adminEmail show a diff and suggest using update_customers

- name: Workflow 2 - Create Data Exchange customers
  graphiant.naas.graphiant_data_exchange:
    operation: create_customers
    config_file: "de_workflows_configs/sample_data_exchange_customers.yaml"
    host: "{{ graphiant_host }}"
    username: "{{ graphiant_username }}"
    password: "{{ graphiant_password }}"
    detailed_logs: true
  register: create_customers_result

- name: Display customers creation result
  ansible.builtin.debug:
    msg: "{{ create_customers_result.msg }}"

- name: Workflow 2 - Create customers from custom config file
  graphiant.naas.graphiant_data_exchange:
    operation: create_customers
    config_file: "de_workflows_configs/sample_data_exchange_customers_scale2.yaml"
    host: "{{ graphiant_host }}"
    username: "{{ graphiant_username }}"
    password: "{{ graphiant_password }}"
    detailed_logs: true

- name: Workflow 3 - Match Data Exchange services to customers
  graphiant.naas.graphiant_data_exchange:
    operation: match_service_to_customers
    config_file: "de_workflows_configs/sample_data_exchange_matches.yaml"
    host: "{{ graphiant_host }}"
    username: "{{ graphiant_username }}"
    password: "{{ graphiant_password }}"
    detailed_logs: true
  register: match_result

- name: Display match result
  ansible.builtin.debug:
    msg: "{{ match_result.msg }}"

- name: Workflow 4 - Accept invitation with matches_file (check mode; service not yet visible via API)
  graphiant.naas.graphiant_data_exchange:
    operation: accept_invitation
    config_file: "de_workflows_configs/sample_data_exchange_acceptance.yaml"
    # matches_file is optional. Required when service is not visible via API in the consumer tenant
    # (e.g. before the invitation is accepted). The file is saved by Workflow 3 (match_service_to_customers).
    # Pass via: -e matches_file=de_workflows_configs/output/sample_data_exchange_matches_responses_latest.json
    matches_file: "de_workflows_configs/output/sample_data_exchange_matches_responses_latest.json"
    host: "{{ graphiant_host }}"
    username: "{{ graphiant_username }}"
    password: "{{ graphiant_password }}"
    detailed_logs: true
  register: accept_result
  # Run playbook with: ansible-playbook playbook.yml --check

- name: Display acceptance result
  ansible.builtin.debug:
    msg: "{{ accept_result.msg }}"

- name: Workflow 4 - Accept invitation (apply; matches_file optional when service is visible via API)
  graphiant.naas.graphiant_data_exchange:
    operation: accept_invitation
    config_file: "de_workflows_configs/sample_data_exchange_acceptance.yaml"
    # Omit matches_file to use API lookup (works after invitation has been accepted once,
    # when the service is visible to the consumer tenant). Or provide it explicitly:
    # matches_file: "de_workflows_configs/output/sample_data_exchange_matches_responses_latest.json"
    host: "{{ graphiant_host }}"
    username: "{{ graphiant_username }}"
    password: "{{ graphiant_password }}"
    detailed_logs: true
  register: accept_result

- name: Display acceptance result
  ansible.builtin.debug:
    msg: "{{ accept_result.msg }}"

- name: Workflow 4 - Accept invitation with secrets (BGP MD5 password and custom PSKs)
  # Secrets are fetched from your secrets store and passed as module params (never written to disk).
  # Ansible Vault: load vault_secrets.yml with include_vars (no_log: true) before this task,
  #   then run the playbook with --vault-password-file configs/vault-password-file.sh.
  # Other secrets stores (HashiCorp Vault, AWS Secrets Manager, etc.): pre-fetch and pass as extra vars.
  # See configs/vault_secrets.yml.example for the expected dict structure.
  graphiant.naas.graphiant_data_exchange:
    operation: accept_invitation
    config_file: "de_workflows_configs/sample_data_exchange_acceptance.yaml"
    matches_file: "de_workflows_configs/output/sample_data_exchange_matches_responses_latest.json"
    vault_data_exchange_bgp_md5_passwords: "{{ vault_data_exchange_bgp_md5_passwords | default({}) }}"
    vault_data_exchange_psk: "{{ vault_data_exchange_psk | default({}) }}"
    host: "{{ graphiant_host }}"
    username: "{{ graphiant_username }}"
    password: "{{ graphiant_password }}"
    detailed_logs: true
  no_log: true
  register: accept_result

- name: Delete Data Exchange customers (must be deleted before services)
  graphiant.naas.graphiant_data_exchange:
    operation: delete_customers
    config_file: "de_workflows_configs/sample_data_exchange_customers.yaml"
    host: "{{ graphiant_host }}"
    username: "{{ graphiant_username }}"
    password: "{{ graphiant_password }}"

- name: Delete Data Exchange services
  graphiant.naas.graphiant_data_exchange:
    operation: delete_services
    config_file: "de_workflows_configs/sample_data_exchange_services.yaml"
    host: "{{ graphiant_host }}"
    username: "{{ graphiant_username }}"
    password: "{{ graphiant_password }}"


- name: Complete Data Exchange workflow (all four workflows)
  block:
    - name: Workflow 1 - Create services
      graphiant.naas.graphiant_data_exchange:
        operation: create_services
        config_file: "de_workflows_configs/sample_data_exchange_services.yaml"
        host: "{{ graphiant_host }}"
        username: "{{ graphiant_username }}"
        password: "{{ graphiant_password }}"
        detailed_logs: true
      register: create_services_result

    - name: Workflow 2 - Create customers
      graphiant.naas.graphiant_data_exchange:
        operation: create_customers
        config_file: "de_workflows_configs/sample_data_exchange_customers.yaml"
        host: "{{ graphiant_host }}"
        username: "{{ graphiant_username }}"
        password: "{{ graphiant_password }}"
        detailed_logs: true
      register: create_customers_result

    - name: Workflow 3 - Match services to customers
      graphiant.naas.graphiant_data_exchange:
        operation: match_service_to_customers
        config_file: "de_workflows_configs/sample_data_exchange_matches.yaml"
        host: "{{ graphiant_host }}"
        username: "{{ graphiant_username }}"
        password: "{{ graphiant_password }}"
        detailed_logs: true
      register: match_result

    - name: Workflow 4 - Accept invitations
      graphiant.naas.graphiant_data_exchange:
        operation: accept_invitation
        config_file: "de_workflows_configs/sample_data_exchange_acceptance.yaml"
        # matches_file is optional; provide when service is not visible via API
        matches_file: "de_workflows_configs/output/sample_data_exchange_matches_responses_latest.json"
        host: "{{ graphiant_host }}"
        username: "{{ graphiant_username }}"
        password: "{{ graphiant_password }}"
        detailed_logs: true
      register: accept_result

    - name: Display workflow results
      ansible.builtin.debug:
        msg: "{{ item.msg }}"
      loop:
        - "{{ create_services_result }}"
        - "{{ create_customers_result }}"
        - "{{ match_result }}"
        - "{{ accept_result }}"

Return Values

Common return values are documented here, the following are the fields unique to this module:

Key

Description

changed

boolean

Whether the operation made changes to the system.

true for create, delete, match, and accept operations.

false for operations that don’t make changes (e.g., dry-run mode).

Returned: always

Sample: true

config_file

string

The configuration file used for the operation.

Only returned for operations that require a configuration file.

Returned: when applicable

Sample: "de_workflows_configs/sample_data_exchange_services.yaml"

diff

dictionary

Ansible --diff output showing before/after state for each changed item.

Returned for create_services, update_services, create_customers, and update_customers when the playbook is run with --diff and at least one item would change.

For create_customers with --check --diff, shows adminEmail drift on existing customers (before = current emails, after = desired emails) with a note to use update_customers.

For new items, before is empty and after is the full target config.

For updates and drift, before shows current values and after shows target values.

Returned: when playbook uses --diff and create_services, update_services, create_customers, or update_customers has changes or drift

Sample: {"after": "=== de-service-1 (prefixTags) ===\n{\"prefixTags\": [{\"prefix\": \"100.1.1.0/24\", \"tag\": \"new-s-1-prefix1\"}]}\n", "before": "=== de-service-1 (prefixTags) ===\n{\"prefixTags\": [{\"prefix\": \"10.1.1.0/24\", \"tag\": \"s-1-prefix1\"}]}\n"}

msg

string

Result message from the operation, including detailed logs when detailed_logs is enabled.

For summary operations, includes tabulated output for easy reading.

For health operations, includes tabulated health status for all matched customers.

Returned: always

Sample: "Successfully created 3 Data Exchange services\n\nDetailed logs:\n2025-10-19 23:08:05,315 - Graphiant_playbook - INFO - Creating service 'de-service-1'...\n2025-10-19 23:08:05,450 - Graphiant_playbook - INFO - Successfully created service 'de-service-1'\n"

operation

string

The operation that was performed.

One of create_services, update_services, delete_services, create_customers, update_customers, delete_customers, match_service_to_customers, or accept_invitation.

Returned: always

Sample: "create_services"

result_data

dictionary

Result data from the operation, including structured data for summary and health operations.

For summary operations, contains service/customer details with IDs, names, status, and counts.

For health operations, contains health metrics for all matched customers.

Returned: when applicable

Sample: {"services": [{"id": 123, "matched_customers": 2, "name": "de-service-1", "status": "ACTIVE"}], "summary": {"created": 3, "total": 3}}

Authors

  • Graphiant Team (@graphiant)