Skip to content

Commit

Permalink
feat: dokku_acl_app and dokku_acl_service modules (#132)
Browse files Browse the repository at this point in the history
Add `dokku_acl_app` and `dokku_acl_service` modules for managing access control lists for
individual apps/services.

Note: The `dokku acl:allowed` command is currently not exposed via ansible modules.
If needed, a `dokku_acl_allowed` module could be added (but it would anyhow just pipe through standard output).
  • Loading branch information
ltalirz authored Nov 28, 2021
1 parent a6706ad commit 2c3a91e
Show file tree
Hide file tree
Showing 5 changed files with 355 additions and 0 deletions.
67 changes: 67 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,73 @@ Scheduled for deletion after 07/2021. Use `dokku_packages_state` instead.

## Libraries

### dokku_acl_app

Manage access control list for a given dokku application

#### Requirements

- the `dokku-acl` plugin

#### Parameters

|Parameter|Choices/Defaults|Comments|
|---------|----------------|--------|
|app<br /><sup>*required*</sup>||The name of the app|
|state|*Choices:* <ul><li>**present** (default)</li><li>absent</li></ul>|Whether the ACLs should be present or absent|
|users<br /><sup>*required*</sup>||The list of users who can manage the app|

#### Example

```yaml
- name: let leopold manage hello-world
dokku_acl_app:
app: hello-world
users:
- leopold
- name: remove leopold from hello-world
dokku_acl_app:
app: hello-world
users:
- leopold
state: absent
```

### dokku_acl_service

Manage access control list for a given dokku service

#### Requirements

- the `dokku-acl` plugin

#### Parameters

|Parameter|Choices/Defaults|Comments|
|---------|----------------|--------|
|service<br /><sup>*required*</sup>||The name of the service|
|state|*Choices:* <ul><li>**present** (default)</li><li>absent</li></ul>|Whether the ACLs should be present or absent|
|type<br /><sup>*required*</sup>||The type of the service|
|users<br /><sup>*required*</sup>||The list of users who can manage the service|

#### Example

```yaml
- name: let leopold manage mypostgres postgres service
dokku_acl_service:
service: mypostgres
type: postgres
users:
- leopold
- name: remove leopold from mypostgres postgres service
dokku_acl_service:
service: hello-world
type: postgres
users:
- leopold
state: absent
```

### dokku_app

Create or destroy dokku apps
Expand Down
114 changes: 114 additions & 0 deletions library/dokku_acl_app.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.dokku_utils import subprocess_check_output

DOCUMENTATION = """
---
module: dokku_acl_app
short_description: Manage access control list for a given dokku application
options:
app:
description:
- The name of the app
required: True
default: null
aliases: []
users:
description:
- The list of users who can manage the app
required: True
aliases: []
state:
description:
- Whether the ACLs should be present or absent
required: False
default: present
choices: ["present", "absent" ]
aliases: []
author: Leopold Talirz
requirements:
- the `dokku-acl` plugin
"""

EXAMPLES = """
- name: let leopold manage hello-world
dokku_acl_app:
app: hello-world
users:
- leopold
- name: remove leopold from hello-world
dokku_acl_app:
app: hello-world
users:
- leopold
state: absent
"""


def dokku_acl_app_set(data):
is_error = True
has_changed = False
meta = {"present": False}

has_changed = False

# get users for app
command = "dokku acl:list {0}".format(data["app"])
output, error = subprocess_check_output(command)

if error is not None:
meta["error"] = error
return (is_error, has_changed, meta)

users = set(output)

if data["state"] == "absent":
for user in data["users"]:
if user not in users:
continue

command = "dokku --quiet acl:remove {0} {1}".format(data["app"], user)
output, error = subprocess_check_output(command)
has_changed = True
if error is not None:
meta["error"] = error
return (is_error, has_changed, meta)
else:
for user in data["users"]:
if user in users:
continue

command = "dokku --quiet acl:add {0} {1}".format(data["app"], user)
output, error = subprocess_check_output(command)
has_changed = True
if error is not None:
meta["error"] = error
return (is_error, has_changed, meta)

is_error = False
return (is_error, has_changed, meta)


def main():
fields = {
"app": {"required": True, "type": "str"},
"users": {"required": True, "type": "list"},
"state": {
"required": False,
"default": "present",
"choices": ["absent", "present"],
"type": "str",
},
}

module = AnsibleModule(argument_spec=fields, supports_check_mode=False)
is_error, has_changed, result = dokku_acl_app_set(module.params)

if is_error:
module.fail_json(msg=result["error"], meta=result)
module.exit_json(changed=has_changed, meta=result)


if __name__ == "__main__":
main()
127 changes: 127 additions & 0 deletions library/dokku_acl_service.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.dokku_utils import subprocess_check_output

DOCUMENTATION = """
---
module: dokku_acl_service
short_description: Manage access control list for a given dokku service
options:
service:
description:
- The name of the service
required: True
default: null
aliases: []
type:
description:
- The type of the service
required: True
default: null
aliases: []
users:
description:
- The list of users who can manage the service
required: True
aliases: []
state:
description:
- Whether the ACLs should be present or absent
required: False
default: present
choices: ["present", "absent" ]
aliases: []
author: Leopold Talirz
requirements:
- the `dokku-acl` plugin
"""

EXAMPLES = """
- name: let leopold manage mypostgres postgres service
dokku_acl_service:
service: mypostgres
type: postgres
users:
- leopold
- name: remove leopold from mypostgres postgres service
dokku_acl_service:
service: hello-world
type: postgres
users:
- leopold
state: absent
"""


def dokku_acl_service_set(data):
is_error = True
has_changed = False
meta = {"present": False}

has_changed = False

# get users for service
command = "dokku --quiet acl:list {0}".format(data["service"])
output, error = subprocess_check_output(command)

if error is not None:
meta["error"] = error
return (is_error, has_changed, meta)

users = set(output)

if data["state"] == "absent":
for user in data["users"]:
if user not in users:
continue

command = "dokku --quiet acl:remove {0} {1} {2}".format(
data["type"], data["service"], user
)
output, error = subprocess_check_output(command)
has_changed = True
if error is not None:
meta["error"] = error
return (is_error, has_changed, meta)
else:
for user in data["users"]:
if user in users:
continue

command = "dokku --quiet acl:add {0} {1} {2}".format(
data["type"], data["service"], user
)
output, error = subprocess_check_output(command)
has_changed = True
if error is not None:
meta["error"] = error
return (is_error, has_changed, meta)

is_error = False
return (is_error, has_changed, meta)


def main():
fields = {
"service": {"required": True, "type": "str"},
"type": {"required": True, "type": "str"},
"users": {"required": True, "type": "list"},
"state": {
"required": False,
"default": "present",
"choices": ["absent", "present"],
"type": "str",
},
}

module = AnsibleModule(argument_spec=fields, supports_check_mode=False)
is_error, has_changed, result = dokku_acl_service_set(module.params)

if is_error:
module.fail_json(msg=result["error"], meta=result)
module.exit_json(changed=has_changed, meta=result)


if __name__ == "__main__":
main()
2 changes: 2 additions & 0 deletions molecule/default/converge.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@
url: https://github.com/josegonzalez/dokku-global-cert
- name: http-auth
url: https://github.com/dokku/dokku-http-auth
- name: acl
url: https://github.com/dokku-community/dokku-acl
dokku_hostname: test.domain
dokku_users:
- name: Giuseppe Verdi
Expand Down
45 changes: 45 additions & 0 deletions molecule/default/verify.yml
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,51 @@
dokku_app:
app: example-app

# Testing dokku_acl_app
- name: Let gverdi manage example-app
dokku_acl_app:
app: example-app
users:
- gverdi

- name: List ACLs for example-app # noqa 301
command: dokku acl:list example-app
register: dokku_acl_list

- name: Check that gverdi is in list of ACLs for example-app
assert:
that:
# Note: As of Nov 2021, `dokku acl:list` writes to stderr
# Feel free to remove this the stderr case when the following issue is fixed
# https://github.com/dokku-community/dokku-acl/issues/34
- ("'gverdi' in dokku_acl_list.stdout") or ("'gverdi' in dokku_acl_list.stderr")
msg: |-
'gverdi' not found in output of 'dokku acl:list example-app':
{{ dokku_acl_list.stdout }}
- name: Remove permission for gverdi to manage example-app
dokku_acl_app:
app: example-app
users:
- gverdi
state: absent

- name: List ACLs for example-app # noqa 301
command: dokku acl:list example-app
register: dokku_acl_list

- name: Check that gverdi is no longer in list of ACLs for example-app
assert:
that:
# Note: As of Nov 2021, `dokku acl:list` writes to stderr
# Feel free to remove this the stderr case when the following issue is fixed
# https://github.com/dokku-community/dokku-acl/issues/34
- ("'gverdi' not in dokku_acl_list.stdout") and ("'gverdi' not in dokku_acl_list.stderr")
msg: |-
'gverdi' found in output of 'dokku acl:list example-app':
{{ dokku_acl_list.stdout }}
# Testing dokku_clone
- name: clone example-app
dokku_clone:
Expand Down

0 comments on commit 2c3a91e

Please sign in to comment.