From ce799ad9d7c77e16a66f6b27bf7ecaf1a16861f3 Mon Sep 17 00:00:00 2001
From: paentraygues <paentraygues@hexaglobe.com>
Date: Thu, 1 Aug 2024 16:13:07 +0200
Subject: [PATCH 1/4] feat: nb_inventory
 admin_service_name_with_ip_as_primary_ip : Use IP attached to a service name
 as usage: ansible [-h] [--version] [-v] [-b] [--become-method BECOME_METHOD] 
               [--become-user BECOME_USER]                [-K |
 --become-password-file BECOME_PASSWORD_FILE]                [-i INVENTORY]
 [--list-hosts] [-l SUBSET] [-P POLL_INTERVAL]                [-B SECONDS]
 [-o] [-t TREE] [--private-key PRIVATE_KEY_FILE]                [-u
 REMOTE_USER] [-c CONNECTION] [-T TIMEOUT]                [--ssh-common-args
 SSH_COMMON_ARGS]                [--sftp-extra-args SFTP_EXTRA_ARGS]          
      [--scp-extra-args SCP_EXTRA_ARGS]                [--ssh-extra-args
 SSH_EXTRA_ARGS]                [-k | --connection-password-file
 CONNECTION_PASSWORD_FILE] [-C]                [-D] [-e EXTRA_VARS]
 [--vault-id VAULT_IDS]                [-J | --vault-password-file
 VAULT_PASSWORD_FILES] [-f FORKS]                [-M MODULE_PATH]
 [--playbook-dir BASEDIR]                [--task-timeout TASK_TIMEOUT] [-a
 MODULE_ARGS] [-m MODULE_NAME]                pattern

Define and run a single task 'playbook' against a set of hosts

positional arguments:
  pattern               host pattern

options:
  --become-password-file BECOME_PASSWORD_FILE, --become-pass-file BECOME_PASSWORD_FILE
                        Become password file
  --connection-password-file CONNECTION_PASSWORD_FILE, --conn-pass-file CONNECTION_PASSWORD_FILE
                        Connection password file
  --list-hosts          outputs a list of matching hosts; does not execute
                        anything else
  --playbook-dir BASEDIR
                        Since this tool does not use playbooks, use this as a
                        substitute playbook directory. This sets the relative
                        path for many features including roles/ group_vars/
                        etc.
  --task-timeout TASK_TIMEOUT
                        set task timeout limit in seconds, must be positive
                        integer.
  --vault-id VAULT_IDS  the vault identity to use. This argument may be
                        specified multiple times.
  --vault-password-file VAULT_PASSWORD_FILES, --vault-pass-file VAULT_PASSWORD_FILES
                        vault password file
  --version             show program's version number, config file location,
                        configured module search path, module location,
                        executable location and exit
  -B SECONDS, --background SECONDS
                        run asynchronously, failing after X seconds
                        (default=N/A)
  -C, --check           don't make any changes; instead, try to predict some
                        of the changes that may occur
  -D, --diff            when changing (small) files and templates, show the
                        differences in those files; works great with --check
  -J, --ask-vault-password, --ask-vault-pass
                        ask for vault password
  -K, --ask-become-pass
                        ask for privilege escalation password
  -M MODULE_PATH, --module-path MODULE_PATH
                        prepend colon-separated path(s) to module library
                        (default={{ ANSIBLE_HOME ~
                        "/plugins/modules:/usr/share/ansible/plugins/modules"
                        }}). This argument may be specified multiple times.
  -P POLL_INTERVAL, --poll POLL_INTERVAL
                        set the poll interval if using -B (default=15)
  -a MODULE_ARGS, --args MODULE_ARGS
                        The action's options in space separated k=v format: -a
                        'opt1=val1 opt2=val2' or a json string: -a '{"opt1":
                        "val1", "opt2": "val2"}'
  -e EXTRA_VARS, --extra-vars EXTRA_VARS
                        set additional variables as key=value or YAML/JSON, if
                        filename prepend with @. This argument may be
                        specified multiple times.
  -f FORKS, --forks FORKS
                        specify number of parallel processes to use
                        (default=5)
  -h, --help            show this help message and exit
  -i INVENTORY, --inventory INVENTORY, --inventory-file INVENTORY
                        specify inventory host path or comma separated host
                        list. --inventory-file is deprecated. This argument
                        may be specified multiple times.
  -k, --ask-pass        ask for connection password
  -l SUBSET, --limit SUBSET
                        further limit selected hosts to an additional pattern
  -m MODULE_NAME, --module-name MODULE_NAME
                        Name of the action to execute (default=command)
  -o, --one-line        condense output
  -t TREE, --tree TREE  log output to this directory
  -v, --verbose         Causes Ansible to print more debug messages. Adding
                        multiple -v will increase the verbosity, the builtin
                        plugins currently evaluate up to -vvvvvv. A reasonable
                        level to start is -vvv, connection debugging might
                        require -vvvv. This argument may be specified multiple
                        times.

Privilege Escalation Options:
  control how and which user you become as on target hosts

  --become-method BECOME_METHOD
                        privilege escalation method to use (default=sudo), use
                        `ansible-doc -t become -l` to list valid choices.
  --become-user BECOME_USER
                        run operations as this user (default=root)
  -b, --become          run operations with become (does not imply password
                        prompting)

Connection Options:
  control as whom and how to connect to hosts

  --private-key PRIVATE_KEY_FILE, --key-file PRIVATE_KEY_FILE
                        use this file to authenticate the connection
  --scp-extra-args SCP_EXTRA_ARGS
                        specify extra arguments to pass to scp only (e.g. -l)
  --sftp-extra-args SFTP_EXTRA_ARGS
                        specify extra arguments to pass to sftp only (e.g. -f,
                        -l)
  --ssh-common-args SSH_COMMON_ARGS
                        specify common arguments to pass to sftp/scp/ssh (e.g.
                        ProxyCommand)
  --ssh-extra-args SSH_EXTRA_ARGS
                        specify extra arguments to pass to ssh only (e.g. -R)
  -T TIMEOUT, --timeout TIMEOUT
                        override the connection timeout in seconds (default
                        depends on connection)
  -c CONNECTION, --connection CONNECTION
                        connection type to use (default=ssh)
  -u REMOTE_USER, --user REMOTE_USER
                        connect as this user (default=None)

Some actions do not make sense in Ad-Hoc (include, meta, etc)
---
 plugins/inventory/nb_inventory.py | 28 ++++++++++++++++++++++++++++
 1 file changed, 28 insertions(+)

diff --git a/plugins/inventory/nb_inventory.py b/plugins/inventory/nb_inventory.py
index 03444b6b4..da5293063 100644
--- a/plugins/inventory/nb_inventory.py
+++ b/plugins/inventory/nb_inventory.py
@@ -249,6 +249,10 @@
             description: Use out of band IP as `ansible host`
             type: boolean
             default: false
+        admin_service_name_with_ip_as_primary_ip:
+            description: Use IP attached to a service name as `ansible host`
+            type: string
+            default: None
         rename_variables:
             description:
                 - Rename variables evaluated by nb_inventory, before writing them.
@@ -854,6 +858,19 @@ def extract_oob_ip(self, host):
         except Exception:
             return
 
+    # service_name_with_ip_as_primary_ip
+    def extract_ip_with_service_name(self, host, service_name):
+        try:
+            for service in self.extract_services(host):
+                if service.get("name") == service_name:
+                    ip_address_info = service.get("ipaddresses", [])
+                    if ip_address_info:
+                        cidr = ip_address_info[0].get("address")
+                        return str(cidr.split('/')[0])
+        except Exception as e:
+            print(f"Error: {e}")
+            return
+
     def extract_tags(self, host):
         try:
             tag_zero = host["tags"][0]
@@ -1948,6 +1965,14 @@ def _fill_host_variables(self, host, hostname):
             if self.oob_ip_as_primary_ip:
                 self._set_variable(hostname, "ansible_host", extracted_oob_ip)
 
+        if self.admin_service_name_with_ip_as_primary_ip:
+            extracted_admin_service_ip = self.extract_ip_with_service_name(host=host,
+                                                service_name=self.admin_service_name_with_ip_as_primary_ip)
+            self._set_variable(hostname, "admin_service_ip", extracted_admin_service_ip)
+            if self.admin_service_name_with_ip_as_primary_ip:
+                self._set_variable(hostname, "ansible_host", extracted_admin_service_ip)
+
+
         for attribute, extractor in self.group_extractors.items():
             extracted_value = extractor(host)
 
@@ -2140,6 +2165,9 @@ def parse(self, inventory, loader, path, cache=True):
         self.key = self.get_option("key")
         self.ca_path = self.get_option("ca_path")
         self.oob_ip_as_primary_ip = self.get_option("oob_ip_as_primary_ip")
+        self.admin_service_name_with_ip_as_primary_ip = self.get_option(
+            "admin_service_name_with_ip_as_primary_ip"
+        )
 
         self._set_authorization()
 

From cdeb6c5a9cbac3f378b4f28e895064fd233638bc Mon Sep 17 00:00:00 2001
From: paentraygues <paentraygues@hexaglobe.com>
Date: Thu, 1 Aug 2024 16:38:42 +0200
Subject: [PATCH 2/4] feat: nb_inventory
 admin_service_name_with_ip_as_primary_ip : lint fix

---
 plugins/inventory/nb_inventory.py | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/plugins/inventory/nb_inventory.py b/plugins/inventory/nb_inventory.py
index da5293063..995af4142 100644
--- a/plugins/inventory/nb_inventory.py
+++ b/plugins/inventory/nb_inventory.py
@@ -1966,8 +1966,9 @@ def _fill_host_variables(self, host, hostname):
                 self._set_variable(hostname, "ansible_host", extracted_oob_ip)
 
         if self.admin_service_name_with_ip_as_primary_ip:
-            extracted_admin_service_ip = self.extract_ip_with_service_name(host=host,
-                                                service_name=self.admin_service_name_with_ip_as_primary_ip)
+            extracted_admin_service_ip = self.extract_ip_with_service_name(
+                host=host, service_name=self.admin_service_name_with_ip_as_primary_ip
+            )
             self._set_variable(hostname, "admin_service_ip", extracted_admin_service_ip)
             if self.admin_service_name_with_ip_as_primary_ip:
                 self._set_variable(hostname, "ansible_host", extracted_admin_service_ip)

From 70ea16121214c8e3c07e10e707ab8e78f1b07331 Mon Sep 17 00:00:00 2001
From: paentraygues <paentraygues@hexaglobe.com>
Date: Thu, 1 Aug 2024 16:41:16 +0200
Subject: [PATCH 3/4] feat: nb_inventory
 admin_service_name_with_ip_as_primary_ip : lint fix2

---
 plugins/inventory/nb_inventory.py | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/plugins/inventory/nb_inventory.py b/plugins/inventory/nb_inventory.py
index 995af4142..d563fad3b 100644
--- a/plugins/inventory/nb_inventory.py
+++ b/plugins/inventory/nb_inventory.py
@@ -866,7 +866,7 @@ def extract_ip_with_service_name(self, host, service_name):
                     ip_address_info = service.get("ipaddresses", [])
                     if ip_address_info:
                         cidr = ip_address_info[0].get("address")
-                        return str(cidr.split('/')[0])
+                        return str(cidr.split("/")[0])
         except Exception as e:
             print(f"Error: {e}")
             return
@@ -1973,7 +1973,6 @@ def _fill_host_variables(self, host, hostname):
             if self.admin_service_name_with_ip_as_primary_ip:
                 self._set_variable(hostname, "ansible_host", extracted_admin_service_ip)
 
-
         for attribute, extractor in self.group_extractors.items():
             extracted_value = extractor(host)
 

From 64280e6bdea6d1122393d069f8ff3797c082c870 Mon Sep 17 00:00:00 2001
From: paentraygues <paentraygues@hexaglobe.com>
Date: Tue, 6 Aug 2024 10:52:19 +0200
Subject: [PATCH 4/4] + changelog fragment
 1295-nb_inventory_admin_service_name_with_ip_as_primary_ip

---
 .../1295-nb_inventory_admin_service_name_with_ip_as_primary_ip  | 2 ++
 1 file changed, 2 insertions(+)
 create mode 100644 changelogs/fragments/1295-nb_inventory_admin_service_name_with_ip_as_primary_ip

diff --git a/changelogs/fragments/1295-nb_inventory_admin_service_name_with_ip_as_primary_ip b/changelogs/fragments/1295-nb_inventory_admin_service_name_with_ip_as_primary_ip
new file mode 100644
index 000000000..3a1b51332
--- /dev/null
+++ b/changelogs/fragments/1295-nb_inventory_admin_service_name_with_ip_as_primary_ip
@@ -0,0 +1,2 @@
+minor_changes:
+    - nb_inventory admin_service_name_with_ip_as_primary_ip : Use IP attached to a service name as ansible host