1
0
Fork 0
mirror of https://github.com/ansible-collections/community.general.git synced 2024-09-14 20:13:21 +02:00

plugins/connection/lxd: convert FQDN to instance name (#7360)

* plugins/connection/lxd: convert FQDN to instance name

This allows to use FQDNs in the inventory and have the
connection driver do the translation when talking to
LXD that uses hostnames (no ".") for instance names.
Those are either globally unique or unique per network/
project in LXD.

```
all:
  # Groups and hosts
  children:
    lxd_dmz:
      vars:
        ansible_lxd_project: dmz
      hosts:
        www01.dmz.example.com:
        www02.dmz.example.com:
```

```
$ lxc list --project dmz
+---------+---------+----------------+------+-----------+-----------+----------+
|  NAME |  STATE  |        IPV4      | IPV6 |   TYPE    | SNAPSHOTS | LOCATION |
+-------+---------+------------------+------+-----------+-----------+----------+
| www01 | RUNNING | 192.0.2.1 (eth0) |      | CONTAINER | 0         | t1       |
+-------+---------+------------------+------+-----------+-----------+----------+
| www02 | RUNNING | 192.0.2.2 (eth0) |      | CONTAINER | 0         | t3       |
+-------+---------+------------------+------+-----------+-----------+----------+
```

Signed-off-by: Simon Deziel <simon.deziel@canonical.com>

* plugins/connection/lxd: VMs/containers are called instances

Update error string parsing to support the new format:

  $ lxc stop c1 -- true
  $ lxc exec c1 -- true
  Error: Instance is not running

  $ lxc exec does-not-exist -- true
  Error: Instance not found

Signed-off-by: Simon Deziel <simon.deziel@canonical.com>

* plugins/connection/lxd: add changelog fragment

Signed-off-by: Simon Deziel <simon.deziel@canonical.com>

---------

Signed-off-by: Simon Deziel <simon.deziel@canonical.com>
This commit is contained in:
Simon Deziel 2023-10-25 06:47:27 +00:00 committed by GitHub
parent 8c7778735d
commit c7150dd818
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 21 additions and 12 deletions

View file

@ -0,0 +1,3 @@
minor_changes:
- lxd connection plugin - automatically translate ``remote_addr`` from FQDN to (short) hostname (https://github.com/ansible-collections/community.general/pull/7360).
- lxd connection plugin - update error parsing to work with newer messages mentioning instances (https://github.com/ansible-collections/community.general/pull/7360).

View file

@ -16,7 +16,9 @@ DOCUMENTATION = '''
options: options:
remote_addr: remote_addr:
description: description:
- Container identifier. - Instance (container/VM) identifier.
- Since community.general 8.0.0, a FQDN can be provided; in that case, the first component (the part before C(.))
is used as the instance identifier.
default: inventory_hostname default: inventory_hostname
vars: vars:
- name: inventory_hostname - name: inventory_hostname
@ -71,26 +73,30 @@ class Connection(ConnectionBase):
if self._play_context.remote_user is not None and self._play_context.remote_user != 'root': if self._play_context.remote_user is not None and self._play_context.remote_user != 'root':
self._display.warning('lxd does not support remote_user, using container default: root') self._display.warning('lxd does not support remote_user, using container default: root')
def _host(self):
""" translate remote_addr to lxd (short) hostname """
return self.get_option("remote_addr").split(".", 1)[0]
def _connect(self): def _connect(self):
"""connect to lxd (nothing to do here) """ """connect to lxd (nothing to do here) """
super(Connection, self)._connect() super(Connection, self)._connect()
if not self._connected: if not self._connected:
self._display.vvv(u"ESTABLISH LXD CONNECTION FOR USER: root", host=self.get_option('remote_addr')) self._display.vvv(u"ESTABLISH LXD CONNECTION FOR USER: root", host=self._host())
self._connected = True self._connected = True
def exec_command(self, cmd, in_data=None, sudoable=True): def exec_command(self, cmd, in_data=None, sudoable=True):
""" execute a command on the lxd host """ """ execute a command on the lxd host """
super(Connection, self).exec_command(cmd, in_data=in_data, sudoable=sudoable) super(Connection, self).exec_command(cmd, in_data=in_data, sudoable=sudoable)
self._display.vvv(u"EXEC {0}".format(cmd), host=self.get_option('remote_addr')) self._display.vvv(u"EXEC {0}".format(cmd), host=self._host())
local_cmd = [self._lxc_cmd] local_cmd = [self._lxc_cmd]
if self.get_option("project"): if self.get_option("project"):
local_cmd.extend(["--project", self.get_option("project")]) local_cmd.extend(["--project", self.get_option("project")])
local_cmd.extend([ local_cmd.extend([
"exec", "exec",
"%s:%s" % (self.get_option("remote"), self.get_option("remote_addr")), "%s:%s" % (self.get_option("remote"), self._host()),
"--", "--",
self.get_option("executable"), "-c", cmd self.get_option("executable"), "-c", cmd
]) ])
@ -104,11 +110,11 @@ class Connection(ConnectionBase):
stdout = to_text(stdout) stdout = to_text(stdout)
stderr = to_text(stderr) stderr = to_text(stderr)
if stderr == "error: Container is not running.\n": if "is not running" in stderr:
raise AnsibleConnectionFailure("container not running: %s" % self.get_option('remote_addr')) raise AnsibleConnectionFailure("instance not running: %s" % self._host())
if stderr == "error: not found\n": if "not found" in stderr:
raise AnsibleConnectionFailure("container not found: %s" % self.get_option('remote_addr')) raise AnsibleConnectionFailure("instance not found: %s" % self._host())
return process.returncode, stdout, stderr return process.returncode, stdout, stderr
@ -116,7 +122,7 @@ class Connection(ConnectionBase):
""" put a file from local to lxd """ """ put a file from local to lxd """
super(Connection, self).put_file(in_path, out_path) super(Connection, self).put_file(in_path, out_path)
self._display.vvv(u"PUT {0} TO {1}".format(in_path, out_path), host=self.get_option('remote_addr')) self._display.vvv(u"PUT {0} TO {1}".format(in_path, out_path), host=self._host())
if not os.path.isfile(to_bytes(in_path, errors='surrogate_or_strict')): if not os.path.isfile(to_bytes(in_path, errors='surrogate_or_strict')):
raise AnsibleFileNotFound("input path is not a file: %s" % in_path) raise AnsibleFileNotFound("input path is not a file: %s" % in_path)
@ -127,7 +133,7 @@ class Connection(ConnectionBase):
local_cmd.extend([ local_cmd.extend([
"file", "push", "file", "push",
in_path, in_path,
"%s:%s/%s" % (self.get_option("remote"), self.get_option("remote_addr"), out_path) "%s:%s/%s" % (self.get_option("remote"), self._host(), out_path)
]) ])
local_cmd = [to_bytes(i, errors='surrogate_or_strict') for i in local_cmd] local_cmd = [to_bytes(i, errors='surrogate_or_strict') for i in local_cmd]
@ -139,14 +145,14 @@ class Connection(ConnectionBase):
""" fetch a file from lxd to local """ """ fetch a file from lxd to local """
super(Connection, self).fetch_file(in_path, out_path) super(Connection, self).fetch_file(in_path, out_path)
self._display.vvv(u"FETCH {0} TO {1}".format(in_path, out_path), host=self.get_option('remote_addr')) self._display.vvv(u"FETCH {0} TO {1}".format(in_path, out_path), host=self._host())
local_cmd = [self._lxc_cmd] local_cmd = [self._lxc_cmd]
if self.get_option("project"): if self.get_option("project"):
local_cmd.extend(["--project", self.get_option("project")]) local_cmd.extend(["--project", self.get_option("project")])
local_cmd.extend([ local_cmd.extend([
"file", "pull", "file", "pull",
"%s:%s/%s" % (self.get_option("remote"), self.get_option("remote_addr"), in_path), "%s:%s/%s" % (self.get_option("remote"), self._host(), in_path),
out_path out_path
]) ])