Search code examples
salt-stacklxclxd

How to configure LXD container devices using saltstack "lxd_container.present" function?


I have the following working Salt state file which: 1) downloads an image 2) creates a container from that image and 3) adds a nic afterwards.

These states work using the following setup:

  • salt-ssh: version 3004
  • Python: 3.9.7
  • LXC (snapd): version 5.0.0
  • PyLXD: version 2.3.0
  • Linux ubuntu: aarch64
---
# Create Penguin Container
#---

get_focal:
  lxd_image.present:
    - name: 'focal'
    - source:
        type: simplestreams
        server: https://cloud-images.ubuntu.com/releases 
        name: '20.04'

create_penguin:
  lxd_container.present:
    - name: penguin
    - profiles: ['default']
    - source: 'focal'
    - running: true
    - devices:
    ### I want to create NIC here. ###

add_nic_card:
  cmd.run: 
    - name: |
        lxc config device add penguin eth0 nic nictype=bridged parent=br0

I need to combine states #2 and #3 so the nic is created simultaneously with the container. This should be possible according to the official documentation. However, I've not been able to get the syntax right, and the error codes aren't helpful.

I've tried numerous variations of the following:

variation 1


create_penguin:
  lxd_container.present:
    - name: penguin
    - profiles: ['default']
    - source: 'focal'
    - running: true
    - devices:
        eth0: {
          type: "nic",
          nictype: "bridged",
          parent: "br0" }

variation 2

create_penguin:
  lxd_container.present:
    - name: penguin
    - profiles:
      - default
    - source: 'focal'
    - running: true
    - devices:
        eth0:
          type: nic
          nictype: bridged
          parent: br0

Variation 2 produces the following error:

----------
          ID: create_penguin
    Function: lxd_container.present
        Name: penguin
      Result: False
     Comment: An exception occurred in this state: Traceback (most recent call last):
                File "/var/tmp/.ubuntu_a31665_salt/pyall/salt/state.py", line 2179, in call
                  ret = self.states[cdata["full"]](
                File "/var/tmp/.ubuntu_a31665_salt/pyall/salt/loader/lazy.py", line 149, in __call__
                  return self.loader.run(run_func, *args, **kwargs)
                File "/var/tmp/.ubuntu_a31665_salt/pyall/salt/loader/lazy.py", line 1201, in run
                  return self._last_context.run(self._run_as, _func_or_method, *args, **kwargs)
                File "/var/tmp/.ubuntu_a31665_salt/pyall/salt/loader/lazy.py", line 1216, in _run_as
                  return _func_or_method(*args, **kwargs)
                File "/var/tmp/.ubuntu_a31665_salt/pyall/salt/loader/lazy.py", line 1249, in wrapper
                  return f(*args, **kwargs)
                File "/var/tmp/.ubuntu_a31665_salt/pyall/salt/states/lxd_container.py", line 235, in present
                  __salt__["lxd.container_create"](
                File "/var/tmp/.ubuntu_a31665_salt/pyall/salt/loader/lazy.py", line 149, in __call__
                  return self.loader.run(run_func, *args, **kwargs)
                File "/var/tmp/.ubuntu_a31665_salt/pyall/salt/loader/lazy.py", line 1201, in run
                  return self._last_context.run(self._run_as, _func_or_method, *args, **kwargs)
                File "/var/tmp/.ubuntu_a31665_salt/pyall/salt/loader/lazy.py", line 1216, in _run_as
                  return _func_or_method(*args, **kwargs)
                File "/var/tmp/.ubuntu_a31665_salt/pyall/salt/modules/lxd.py", line 691, in container_create
                  container_device_add(name, dn, **dargs)
                File "/var/tmp/.ubuntu_a31665_salt/pyall/salt/modules/lxd.py", line 1431, in container_device_add
                  return _set_property_dict_item(container, "devices", device_name, kwargs)
                File "/var/tmp/.ubuntu_a31665_salt/pyall/salt/modules/lxd.py", line 3544, in _set_property_dict_item
                  raise SaltInvocationError("path must be given as parameter")
              salt.exceptions.SaltInvocationError: path must be given as parameter
     Started: 09:43:31.807609
    Duration: 5147.141 ms
     Changes:   
----------


Solution

  • I took cue from the lxd-formula and as described in documentation, we need supply a dict to devices: in YAML format. So, the curly brackets { .. } are not required.

    Following that, I found that the below syntax works fine:

    create_penguin:
      lxd_container.present:
        - name: penguin
        - profiles: ['default']
        - source: 'focal'
        - running: true
        - devices:
            eth0:
              type: nic
              nictype: bridged
              parent: br0
            # another network interface
            eth1:
              type: nic
              nictype: bridged
              parent: br0
    

    For reference, my setup:

    component version
    Salt 3003.3
    Python 3.8.10
    dist ubuntu 20.04 focal
    lxc (apt) 4.0.9
    pylxd 2.3.1

    And output from Saltstack (had removed eth1 from the state):

    ----------
              ID: create_penguin
        Function: lxd_container.present
            Name: penguin
          Result: True
         Comment: 1 changes
         Started: 12:38:58.041506
        Duration: 27277.86 ms
         Changes:   
                  ----------
                  devices:
                      ----------
                      eth0:
                          Added device "eth0"