Skip to content

Commit

Permalink
Add path and env options for podman_secret (#766)
Browse files Browse the repository at this point in the history
Fix #741
Signed-off-by: Sagi Shnaidman <[email protected]>
  • Loading branch information
sshnaidm authored May 29, 2024
1 parent f9ab05b commit d75126d
Show file tree
Hide file tree
Showing 2 changed files with 186 additions and 15 deletions.
81 changes: 68 additions & 13 deletions plugins/modules/podman_secret.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
data:
description:
- The value of the secret. Required when C(state) is C(present).
Mutually exclusive with C(env) and C(path).
type: str
driver:
description:
Expand All @@ -31,6 +32,11 @@
description:
- Driver-specific key-value options.
type: dict
env:
description:
- The name of the environment variable that contains the secret.
Mutually exclusive with C(data) and C(path).
type: str
executable:
description:
- Path to C(podman) executable if it is not in the C($PATH) on the
Expand All @@ -53,6 +59,11 @@
- The name of the secret.
required: True
type: str
path:
description:
- Path to the file that contains the secret.
Mutually exclusive with C(data) and C(env).
type: path
state:
description:
- Whether to create or remove the named secret.
Expand All @@ -67,7 +78,7 @@
type: dict
debug:
description:
- Enable debug mode for module.
- Enable debug mode for module. It prints secrets diff.
type: bool
default: False
'''
Expand Down Expand Up @@ -99,6 +110,8 @@
name: mysecret
"""

import os

from ansible.module_utils.basic import AnsibleModule
from ansible_collections.containers.podman.plugins.module_utils.podman.common import LooseVersion
from ansible_collections.containers.podman.plugins.module_utils.podman.common import get_podman_version
Expand All @@ -116,7 +129,7 @@ def podman_secret_exists(module, executable, name, version):
return rc == 0


def need_update(module, executable, name, data, skip, driver, driver_opts, debug, labels):
def need_update(module, executable, name, data, path, env, skip, driver, driver_opts, debug, labels):
cmd = [executable, 'secret', 'inspect', '--showsecret', name]
rc, out, err = module.run_command(cmd)
if rc != 0:
Expand All @@ -132,10 +145,37 @@ def need_update(module, executable, name, data, skip, driver, driver_opts, debug
if debug:
module.log("PODMAN-SECRET-DEBUG: Idempotency of driver %s is not supported" % driver)
return True
if secret['SecretData'] != data:
diff['after'] = "<different-secret>"
diff['before'] = "<secret>"
return True
if data:
if secret['SecretData'] != data:
if debug:
diff['after'] = data
diff['before'] = secret['SecretData']
else:
diff['after'] = "<different-secret>"
diff['before'] = "<secret>"
return True
if path:
with open(path, 'rb') as f:
text = f.read().decode('utf-8')
if secret['SecretData'] != text:
if debug:
diff['after'] = text
diff['before'] = secret['SecretData']
else:
diff['after'] = "<different-secret>"
diff['before'] = "<secret>"
return True
if env:
env_data = os.environ.get(env)
if secret['SecretData'] != env_data:
if debug:
diff['after'] = env_data
diff['before'] = secret['SecretData']
else:
diff['after'] = "<different-secret>"
diff['before'] = "<secret>"
return True

if driver_opts:
for k, v in driver_opts.items():
if secret['Spec']['Driver']['Options'].get(k) != v:
Expand All @@ -155,13 +195,13 @@ def need_update(module, executable, name, data, skip, driver, driver_opts, debug
return False


def podman_secret_create(module, executable, name, data, force, skip,
def podman_secret_create(module, executable, name, data, path, env, force, skip,
driver, driver_opts, debug, labels):
podman_version = get_podman_version(module, fail=False)
if (podman_version is not None and
LooseVersion(podman_version) >= LooseVersion('4.7.0')
and (driver is None or driver == 'file')):
if need_update(module, executable, name, data, skip, driver, driver_opts, debug, labels):
if need_update(module, executable, name, data, path, env, skip, driver, driver_opts, debug, labels):
podman_secret_remove(module, executable, name)
else:
return {"changed": False}
Expand All @@ -183,9 +223,20 @@ def podman_secret_create(module, executable, name, data, force, skip,
cmd.append('--label')
cmd.append("=".join([k, v]))
cmd.append(name)
cmd.append('-')
if data:
cmd.append('-')
elif path:
cmd.append(path)
elif env:
if os.environ.get(env) is None:
module.fail_json(msg="Environment variable %s is not set" % env)
cmd.append("--env")
cmd.append(env)

rc, out, err = module.run_command(cmd, data=data, binary_data=True)
if data:
rc, out, err = module.run_command(cmd, data=data, binary_data=True)
else:
rc, out, err = module.run_command(cmd)
if rc != 0:
module.fail_json(msg="Unable to create secret: %s" % err)

Expand Down Expand Up @@ -220,13 +271,17 @@ def main():
state=dict(type='str', default='present', choices=['absent', 'present']),
name=dict(type='str', required=True),
data=dict(type='str', no_log=True),
env=dict(type='str'),
path=dict(type='path'),
force=dict(type='bool', default=False),
skip_existing=dict(type='bool', default=False),
driver=dict(type='str'),
driver_opts=dict(type='dict'),
labels=dict(type='dict'),
debug=dict(type='bool', default=False),
),
required_if=[('state', 'present', ['path', 'env', 'data'], True)],
mutually_exclusive=[['path', 'env', 'data']],
)

state = module.params['state']
Expand All @@ -235,16 +290,16 @@ def main():

if state == 'present':
data = module.params['data']
if data is None:
raise Exception("'data' is required when 'state' is 'present'")
force = module.params['force']
skip = module.params['skip_existing']
driver = module.params['driver']
driver_opts = module.params['driver_opts']
debug = module.params['debug']
labels = module.params['labels']
path = module.params['path']
env = module.params['env']
results = podman_secret_create(module, executable,
name, data, force, skip,
name, data, path, env, force, skip,
driver, driver_opts, debug, labels)
else:
results = podman_secret_remove(module, executable, name)
Expand Down
120 changes: 118 additions & 2 deletions tests/integration/targets/podman_secret/tasks/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,10 @@
containers.podman.podman_secret:
executable: "{{ test_executable | default('podman') }}"
state: absent
name: mysecret
name: "{{ item }}"
loop:
- mysecret
- mysecret2

- name: Create secret
containers.podman.podman_secret:
Expand Down Expand Up @@ -283,7 +286,10 @@
containers.podman.podman_secret:
executable: "{{ test_executable | default('podman') }}"
state: absent
name: mysecret
name: "{{ item }}"
loop:
- mysecret
- mysecret2

- name: Create secret if not exists and skip existing
containers.podman.podman_secret:
Expand Down Expand Up @@ -323,6 +329,116 @@
state: absent
name: mysecret2


- when: podman_version_gt470
block:

- name: Create a file with secret data
copy:
content: "secret content 1"
dest: ~/mysecret-1

- name: Create secret from file
containers.podman.podman_secret:
executable: "{{ test_executable | default('podman') }}"
name: mysecret2
path: ~/mysecret-1
state: present
register: secret1

- name: Create secret again
containers.podman.podman_secret:
executable: "{{ test_executable | default('podman') }}"
name: mysecret2
path: ~/mysecret-1
state: present
register: secret2

- name: Check outputs
assert:
that:
- secret1 is changed
- secret2 is not changed

- name: Create another secret in other file
copy:
content: "secret content 2"
dest: ~/mysecret-2

- name: Create secret from other file
containers.podman.podman_secret:
executable: "{{ test_executable | default('podman') }}"
name: mysecret3
path: ~/mysecret-2
state: present
debug: true
register: secret3

- name: Check outputs
assert:
that:
- secret3 is changed

- name: Create a secret from non existing file
containers.podman.podman_secret:
executable: "{{ test_executable | default('podman') }}"
name: mysecret4
path: ~/mysecret-3
state: present
debug: true
register: secret4
ignore_errors: true

- name: Check outputs
assert:
that:
- secret4 is failed

- name: Create a secret from non-existing environment variable
containers.podman.podman_secret:
executable: "{{ test_executable | default('podman') }}"
name: mysecret5
env: NON_EXISTING_ENV
state: present
register: secret5
ignore_errors: true

- name: Check outputs
assert:
that:
- secret5 is failed
- "'Environment variable NON_EXISTING_ENV is not set' in secret5.msg"

- name: Create a secret from existing environment variable
containers.podman.podman_secret:
executable: "{{ test_executable | default('podman') }}"
name: mysecret5
env: EXISTING_ENV
state: present
environment:
EXISTING_ENV: "secret env content"
register: secret6

- name: Show secret6
containers.podman.podman_secret_info:
executable: "{{ test_executable | default('podman') }}"
name: mysecret5
showsecret: true
register: secret6_info

- name: Check outputs
assert:
that:
- secret6 is changed
- secret6_info is success
- secret6_info.secrets.0.SecretData == "secret env content"

- name: Remove secret
containers.podman.podman_secret:
executable: "{{ test_executable | default('podman') }}"
state: absent
name: mysecret5

always:
- name: Remove container that uses secret
containers.podman.podman_container:
Expand Down

0 comments on commit d75126d

Please sign in to comment.