Repository: ansible/ansible

Issue:
lxd_container config always changed
##### ISSUE TYPE
 - Bug Report

##### COMPONENT NAME
lxd_container

##### ANSIBLE VERSION
```
ansible 2.4.1.0
```

##### OS / ENVIRONMENT
N/A

##### SUMMARY
When changing an existing container's config, the ansible task is always marked as changed

##### STEPS TO REPRODUCE
<!---
For bugs, show exactly how to reproduce the problem, using a minimal test-case.
For new features, show how the feature would be used.
-->

```yaml
- name: "Set LXD permissions"
  become: yes
  lxd_container:
    name: "{{ inventory_hostname_short }}"
    config:
      security.privileged: "true"
      raw.apparmor: "mount fstype=nfs,"

```

From the looks of things, https://github.com/ansible/ansible/blob/devel/lib/ansible/modules/cloud/lxd/lxd_container.py#L493 is related

##### EXPECTED RESULTS
Task would be marked as changed once, then not changed again

##### ACTUAL RESULTS
Task is marked as changed on every run

As an aside, an example in the docs for config usage would be nice


Discussion:
cc @hnakamur
[click here for bot help](https://github.com/ansible/ansibullbot/blob/master/ISSUE_HELP.md)
<!--- boilerplate: notify --->
I confirm this annoying bug.
Running ansible 2.4.3.

https://github.com/ansible/ansible/blob/a50db37c6c36c4d43e4767424c80e3a4d3e2704b/lib/ansible/modules/cloud/lxd/lxd_container.py#L473

Not really clean and not tested but could change : 
```
    def _apply_container_configs(self):
        old_metadata = self.old_container_json['metadata']
        body_json = {
            'architecture': old_metadata['architecture'],
            'config': old_metadata['config'],
            'devices': old_metadata['devices'],
            'profiles': old_metadata['profiles']
        }
        if self._needs_to_change_container_config('architecture'):
            body_json['architecture'] = self.config['architecture']
        if self._needs_to_change_container_config('config'):
            for k, v in self.config['config'].items():
                body_json['config'][k] = v
        if self._needs_to_change_container_config('ephemeral'):
            body_json['ephemeral'] = self.config['ephemeral']
        if self._needs_to_change_container_config('devices'):
            body_json['devices'] = self.config['devices']
        if self._needs_to_change_container_config('profiles'):
            body_json['profiles'] = self.config['profiles']
        self.client.do('PUT', '/1.0/containers/{0}'.format(self.name), body_json=body_json)
        self.actions.append('apply_container_configs')
```

by : 
```
    def _apply_container_configs(self):
        old_metadata = self.old_container_json['metadata']
        body_json = {
            'architecture': old_metadata['architecture'],
            'config': old_metadata['config'],
            'devices': old_metadata['devices'],
            'profiles': old_metadata['profiles']
        }
        config_changed = False
        if self._needs_to_change_container_config('architecture'):
            body_json['architecture'] = self.config['architecture']
            config_changed = True
        if self._needs_to_change_container_config('config'):
            for k, v in self.config['config'].items():
                body_json['config'][k] = v
            config_changed = True
        if self._needs_to_change_container_config('ephemeral'):
            body_json['ephemeral'] = self.config['ephemeral']
            config_changed = True
        if self._needs_to_change_container_config('devices'):
            body_json['devices'] = self.config['devices']
            config_changed = True
        if self._needs_to_change_container_config('profiles'):
            body_json['profiles'] = self.config['profiles']
            config_changed = True
        if config_changed:
            self.client.do('PUT', '/1.0/containers/{0}'.format(self.name), body_json=body_json)
            self.actions.append('apply_container_configs')
```

Resolving patch:
diff --git a/lib/ansible/modules/cloud/lxd/lxd_container.py b/lib/ansible/modules/cloud/lxd/lxd_container.py
--- a/lib/ansible/modules/cloud/lxd/lxd_container.py
+++ b/lib/ansible/modules/cloud/lxd/lxd_container.py
@@ -457,9 +457,13 @@ def _needs_to_change_container_config(self, key):
             return False
         if key == 'config':
             old_configs = dict((k, v) for k, v in self.old_container_json['metadata'][key].items() if not k.startswith('volatile.'))
+            for k, v in self.config['config'].items():
+                if old_configs[k] != v:
+                    return True
+            return False
         else:
             old_configs = self.old_container_json['metadata'][key]
-        return self.config[key] != old_configs
+            return self.config[key] != old_configs
 
     def _needs_to_apply_container_configs(self):
         return (


Test patch: