Skip to content

Commit

Permalink
version 1.3.0 (#3)
Browse files Browse the repository at this point in the history
* feat: handling secrets without the need for `no_log`
* feat: POST method module
* fix: dependencies, duplicate import
* feat: docs updates, new examples
* feat: boilerplate
  • Loading branch information
simonkowallik authored Dec 4, 2024
1 parent 8b24b17 commit 911b69c
Show file tree
Hide file tree
Showing 23 changed files with 863 additions and 351 deletions.
9 changes: 9 additions & 0 deletions .github/dependabot.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
version: 2
updates:
- package-ecosystem: "pip"
directory: "/"
schedule:
interval: "weekly"
ignore:
# ignore external dependency
- dependency-name: "ansible-core"
22 changes: 3 additions & 19 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -28,25 +28,9 @@ clean-test: ## remove test and coverage artifacts
find . -name '.mypy_cache' -exec rm -fr {} +
rm -rf ansible_collections/f5_ps_ansible/f5os/tests/output

lint: ruff pylint ## check style with ruff and pylint

pylint:
pylint ansible_collections/f5_ps_ansible/f5os/plugins/modules/*.py
pylint ansible_collections/f5_ps_ansible/f5os/plugins/module_utils/*.py

black:
black ansible_collections/f5_ps_ansible/f5os/plugins/modules/*.py
black ansible_collections/f5_ps_ansible/f5os/plugins/module_utils/*.py

ruff:
ruff format ansible_collections/f5_ps_ansible/f5os/plugins/modules/*.py
ruff format ansible_collections/f5_ps_ansible/f5os/plugins/module_utils/*.py

isort:
isort ansible_collections/f5_ps_ansible/f5os/plugins/modules/*.py
isort ansible_collections/f5_ps_ansible/f5os/plugins/module_utils/*.py

code-format: isort black ruff # more is MORE!
code-format:
ruff check --select I --fix --exclude .venv
ruff format --exclude .venv

doc: docs ## alias for docs

Expand Down
3 changes: 2 additions & 1 deletion ansible_collections/f5_ps_ansible/f5os/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,8 @@ Using `requirements.yml`:
type: git
```
`f5_ps_ansible.f5os` is currently **NOT** available on Ansible Galaxy!
> [!NOTE]
> `f5_ps_ansible.f5os` is currently **NOT** available on Ansible Galaxy!


## Dependencies
Expand Down
2 changes: 1 addition & 1 deletion ansible_collections/f5_ps_ansible/f5os/galaxy.yml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
---
namespace: f5_ps_ansible
name: f5os
version: 1.2.0
version: 1.3.0
readme: README.md
authors:
- Simon Kowallik <[email protected]>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,10 @@ def put(self, *args, **kwargs):
"""update a resource."""
return self.call("PUT", *args, **kwargs)

def post(self, *args, **kwargs):
"""update a resource."""
return self.call("POST", *args, **kwargs)

def patch(self, *args, **kwargs):
"""update a resource."""
return self.call("PATCH", *args, **kwargs)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,11 @@
description: A JMESPath query to filter the current configuration before it is compared to the desired configuration.
required: False
type: str
secrets:
description: A list of secrets to redact from the output. Any value in this list will be redacted with 'VALUE_SPECIFIED_IN_NO_LOG_PARAMETER'.
required: False
type: list
elements: str
attributes:
check_mode:
description: The module supports check mode and will report what changes would have been made.
Expand All @@ -67,16 +72,20 @@

EXAMPLES = r"""
- name: 'Set the login banner'
vars:
f5os_api_prefix: "{{ '/restconf' if ansible_httpapi_port == '8888' else '/api' }}"
f5_ps_ansible.f5os.f5os_restconf_config:
uri: "{{ '/restconf' if ansible_httpapi_port == '8888' else '/api' }}/data/openconfig-system:system/config/login-banner"
uri: "{{ f5os_api_prefix }}/data/openconfig-system:system/config/login-banner"
config:
openconfig-system:login-banner: |-
With great power comes great responsibility!
-- Spider-man's grandpa
- name: 'Configure trunked VLANs'
vars:
f5os_api_prefix: "{{ '/restconf' if ansible_httpapi_port == '8888' else '/api' }}"
f5_ps_ansible.f5os.f5os_restconf_config:
uri: "{{ '/restconf' if ansible_httpapi_port == '8888' else '/api' }}/data/openconfig-interfaces:interfaces/interface={{ item.interface }}/openconfig-if-aggregate:aggregation/openconfig-vlan:switched-vlan/config/trunk-vlans={{ item.id }}"
uri: "{{ f5os_api_prefix }}/data/openconfig-interfaces:interfaces/interface={{ item.interface }}/openconfig-if-aggregate:aggregation/openconfig-vlan:switched-vlan/config/trunk-vlans={{ item.id }}"
state: "{{ item.state | default('present') }}"
config:
openconfig-vlan:trunk-vlans: ['{{ item.id }}']
Expand All @@ -90,8 +99,10 @@
state: absent # Remove VLAN 30 from interface 7.0
- name: 'Partially configure LLDP'
vars:
f5os_api_prefix: "{{ '/restconf' if ansible_httpapi_port == '8888' else '/api' }}"
f5_ps_ansible.f5os.f5os_restconf_config:
uri: "{{ '/restconf' if ansible_httpapi_port == '8888' else '/api' }}/data/openconfig-lldp:lldp/config"
uri: "{{ f5os_api_prefix }}/data/openconfig-lldp:lldp/config"
method: PATCH # Use PATCH to partially update the configuration
config:
openconfig-lldp:config:
Expand All @@ -111,6 +122,7 @@
- name: 'Using PATCH on a group of resources (list) with additional config endpoints'
vars:
f5os_api_prefix: "{{ '/restconf' if ansible_httpapi_port == '8888' else '/api' }}"
server:
address: 9.9.9.11
port: 53
Expand All @@ -136,6 +148,26 @@
config:
address: "{{ server.address }}"
port: "{{ server.port }}" # no need to change to int, the type is ignored by the ansible module
- name: 'Set system proxy for automatic licensing and qkview uploads'
# https://clouddocs.f5.com/training/community/rseries-training/html/rseries_security.html#proxy-server-via-api-for-licensing-and-qkview-uploads-to-ihealth
vars:
f5os_api_prefix: "{{ '/restconf' if ansible_httpapi_port == '8888' else '/api' }}"
proxy_username: f5os-proxy-user
proxy_password: "{{ lookup('env', 'PROXY_PASSWORD') }}"
proxy_server: https://proxyserver.internal.example.net
f5_ps_ansible.f5os.f5os_restconf_config:
uri: '{{ f5os_api_prefix }}/data/openconfig-system:system/f5-system-diagnostics-qkview:diagnostics/f5-system-diagnostics-proxy:proxy'
config:
f5-system-diagnostics-proxy:proxy:
config:
proxy-username: "{{ proxy_username }}"
proxy-password: "{{ proxy_password }}"
proxy-server: "{{ proxy_server }}"
keys_ignore:
- proxy-password
secrets:
- "{{ proxy_password }}" # redact the proxy password in logs and debug messages (no_log)
"""

RETURN = r"""
Expand Down Expand Up @@ -198,6 +230,7 @@ def main():
),
keys_ignore=dict(required=False, type="list", default=[]),
config_query=dict(required=False, type="str", default=""),
secrets=dict(required=False, type="list", default=[], no_log=True),
)
module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=True)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,10 @@
type: str
attributes:
check_mode:
description: The module supports check mode and will report what changes would have been made.
description: The module supports check mode.
support: full
diff_mode:
description: The module supports diff mode and will report the differences between the desired and actual state.
description: The module does not supports diff mode.
support: none
notes:
- This module requires the f5networks.f5os collection to be installed on the ansible controller.
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
# -*- coding: utf-8 -*-
#
# Copyright: Simon Kowallik for the F5 DevCentral Community
# GNU General Public License v3.0 (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)

from __future__ import absolute_import, division, print_function

__metaclass__ = type

DOCUMENTATION = r"""
---
module: f5os_restconf_post
short_description: POST to resources of the F5OS RESTCONF API.
description:
- POST/Write to resources of the F5OS RESTCONF API.
author:
- Simon Kowallik (@simonkowallik)
version_added: "1.3.0"
options:
uri:
description: The URI of the resource to write to.
required: True
type: str
config:
description: The desired configuration to apply to the resource (PATCH) or to replace the resource with (PUT).
required: False
type: dict
secrets:
description: A list of secrets to redact from the output. Any value in this list will be redacted with 'VALUE_SPECIFIED_IN_NO_LOG_PARAMETER'.
required: False
type: list
elements: str
attributes:
check_mode:
description: The module does not support check mode.
support: none
diff_mode:
description: The module does not support diff mode.
support: none
notes:
- This module requires the f5networks.f5os collection to be installed on the ansible controller.
- This module uses the httpapi of the f5networks.f5os collection.
"""

EXAMPLES = r"""
- name: 'Update user password'
vars:
f5os_api_prefix: "{{ '/restconf' if ansible_httpapi_port == '8888' else '/api' }}"
f5os_username: admin
f5os_password: "{{ lookup('env', 'F5OS_PASSWORD') }}"
block:
- name: 'Set user password'
f5_ps_ansible.f5os.f5os_restconf_post:
uri: '{{ f5os_api_prefix }}/data/openconfig-system:system/aaa/authentication/f5-system-aaa:users/f5-system-aaa:user={{ f5os_username }}/config/f5-system-aaa:set-password'
config:
f5-system-aaa:password: "{{ f5os_password }}"
secrets:
- "{{ f5os_password }}"
- name: 'Get ansible_date_time variable'
ansible.builtin.setup:
gather_subset: [min]
- name: 'Set last changed - prevents prompting to change password on next login'
f5_ps_ansible.f5os.f5os_restconf_config:
uri: '{{ f5os_api_prefix }}/data/openconfig-system:system/aaa/authentication/f5-system-aaa:users/f5-system-aaa:user={{ f5os_username }}/config'
method: PATCH
config:
f5-system-aaa:config:
last-change: "{{ ansible_date_time.date }}"
config_query: |-
"f5-system-aaa:config"."last-change" | { "f5-system-aaa:config": { "last-change": @ } }
"""

RETURN = r"""
api_response:
description: The API response received from the F5OS RESTCONF API.
returned: always
type: dict
"""

from ansible.module_utils._text import to_text
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.connection import ConnectionError

from ansible_collections.f5_ps_ansible.f5os.plugins.module_utils.utils import (
APIClient,
format_bool_values,
number_values_to_string,
)


def main():
"""entry point for module execution"""
argument_spec = dict(
uri=dict(required=True, type="str"),
config=dict(required=False, type="dict", default=None),
secrets=dict(required=False, type="list", default=[], no_log=True),
)
module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=True)

result = {"changed": True, "failed": True}

desired_config = number_values_to_string(module.params["config"])
desired_config = format_bool_values(desired_config)

api_client = APIClient(module)
try:
api_response = api_client.post(uri=module.params["uri"], config=desired_config)
result.update({"api_response": api_response or {}})
if api_response.get("code", 0) >= 200 and api_response.get("code", 0) < 300:
result["failed"] = False
except ConnectionError as exc:
module.fail_json(msg=to_text(exc))

module.exit_json(**result)


if __name__ == "__main__":
main()
Loading

0 comments on commit 911b69c

Please sign in to comment.