diff --git a/meta/runtime.yml b/meta/runtime.yml index a5ba4505f..0c3c0e52d 100644 --- a/meta/runtime.yml +++ b/meta/runtime.yml @@ -78,6 +78,7 @@ action_groups: - smart_class_parameter - smart_class_parameter_override_value - smart_proxy + - smart_proxy_refresh - snapshot - snapshot_info - status_info diff --git a/plugins/modules/smart_proxy_refresh.py b/plugins/modules/smart_proxy_refresh.py new file mode 100644 index 000000000..cc21678b6 --- /dev/null +++ b/plugins/modules/smart_proxy_refresh.py @@ -0,0 +1,90 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +# (c) Evgeni Golov +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +from __future__ import absolute_import, division, print_function +__metaclass__ = type + + +DOCUMENTATION = ''' +--- +module: smart_proxy_refresh +version_added: 5.8.0 +short_description: Refresh Smart Proxy features +description: + - Refresh Smart Proxy features +author: + - "Evgeni Golov (@evgeni)" +options: + smart_proxy: + description: + - Name of the Smart Proxy + required: true + type: str +attributes: + check_mode: + support: none + diff_mode: + support: none +extends_documentation_fragment: + - theforeman.foreman.foreman + - theforeman.foreman.foreman.taxonomy +''' + +EXAMPLES = ''' +- name: "Refresh Smart Proxy" + theforeman.foreman.smart_proxy_refresh: + username: "admin" + password: "changeme" + server_url: "https://foreman.example.com" + name: "foreman-proxy.example.com" +''' + +RETURN = ''' +entity: + description: Final state of the affected entities grouped by their type. + returned: success + type: dict + contains: + smart_proxies: + description: List of smart_proxies. + type: list + elements: dict +''' + +from ansible_collections.theforeman.foreman.plugins.module_utils.foreman_helper import ForemanTaxonomicAnsibleModule + + +class ForemanSmartProxyRefreshModule(ForemanTaxonomicAnsibleModule): + pass + + +def main(): + module = ForemanSmartProxyRefreshModule( + foreman_spec=dict( + smart_proxy=dict(type='entity', required=True), + ), + supports_check_mode=False, + ) + + with module.api_connection(): + smart_proxy = module.lookup_entity('smart_proxy') + entity = module.resource_action('smart_proxies', 'refresh', {'id': smart_proxy['id']}) + module.exit_json(entity=entity) + + +if __name__ == '__main__': + main() diff --git a/tests/fixtures/apidoc/smart_proxy_refresh.json b/tests/fixtures/apidoc/smart_proxy_refresh.json new file mode 120000 index 000000000..f9e401512 --- /dev/null +++ b/tests/fixtures/apidoc/smart_proxy_refresh.json @@ -0,0 +1 @@ +foreman.json \ No newline at end of file diff --git a/tests/test_playbooks/fixtures/smart_proxy_refresh-0.yml b/tests/test_playbooks/fixtures/smart_proxy_refresh-0.yml new file mode 100644 index 000000000..a86aa4b0b --- /dev/null +++ b/tests/test_playbooks/fixtures/smart_proxy_refresh-0.yml @@ -0,0 +1,182 @@ +interactions: +- request: + body: null + headers: + Accept: + - application/json;version=2 + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + User-Agent: + - apypie (https://github.com/Apipie/apypie) + method: GET + uri: https://foreman.example.org/api/status + response: + body: + string: '{"result":"ok","status":200,"version":"3.18.0-develop","api_version":2}' + headers: + Cache-Control: + - max-age=0, private, must-revalidate + Connection: + - Keep-Alive + Content-Length: + - '71' + Content-Type: + - application/json; charset=utf-8 + Foreman_api_version: + - '2' + Foreman_current_location: + - ; ANY + Foreman_current_organization: + - ; ANY + Foreman_version: + - 3.18.0-develop + Keep-Alive: + - timeout=15, max=100 + Referrer-Policy: + - strict-origin-when-cross-origin + content-security-policy: + - 'default-src ''self''; child-src ''self''; connect-src ''self'' ws: wss:; + img-src ''self'' data:; script-src ''unsafe-eval'' ''unsafe-inline'' ''self''; + style-src ''unsafe-inline'' ''self''' + strict-transport-security: + - max-age=631139040; includeSubdomains + x-content-type-options: + - nosniff + x-download-options: + - noopen + x-frame-options: + - sameorigin + x-permitted-cross-domain-policies: + - none + x-xss-protection: + - '0' + status: + code: 200 + message: OK +- request: + body: null + headers: + Accept: + - application/json;version=2 + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + User-Agent: + - apypie (https://github.com/Apipie/apypie) + method: GET + uri: https://foreman.example.org/api/smart_proxies?search=name%3D%22foreman-proxy.example.com%22&per_page=4294967296 + response: + body: + string: "{\n \"total\": 1,\n \"subtotal\": 1,\n \"page\": 1,\n \"per_page\": + 4294967296,\n \"search\": \"name=\\\"foreman.example.org\\\"\",\n \"sort\": + {\n \"by\": null,\n \"order\": null\n },\n \"results\": [{\"created_at\":\"2025-11-19 + 09:15:31 UTC\",\"updated_at\":\"2025-11-19 09:15:31 UTC\",\"hosts_count\":1,\"name\":\"foreman.example.org\",\"id\":1,\"url\":\"https://foreman.example.org:8443\",\"features\":[{\"capabilities\":[],\"name\":\"Puppet + CA\",\"id\":5},{\"capabilities\":[],\"name\":\"Puppet\",\"id\":13},{\"capabilities\":[],\"name\":\"Logs\",\"id\":9}]}]\n}\n" + headers: + Cache-Control: + - max-age=0, private, must-revalidate + Connection: + - Keep-Alive + Content-Length: + - '588' + Content-Type: + - application/json; charset=utf-8 + Foreman_api_version: + - '2' + Foreman_current_location: + - ; ANY + Foreman_current_organization: + - ; ANY + Foreman_version: + - 3.18.0-develop + Keep-Alive: + - timeout=15, max=98 + Referrer-Policy: + - strict-origin-when-cross-origin + content-security-policy: + - 'default-src ''self''; child-src ''self''; connect-src ''self'' ws: wss:; + img-src ''self'' data:; script-src ''unsafe-eval'' ''unsafe-inline'' ''self''; + style-src ''unsafe-inline'' ''self''' + strict-transport-security: + - max-age=631139040; includeSubdomains + x-content-type-options: + - nosniff + x-download-options: + - noopen + x-frame-options: + - sameorigin + x-permitted-cross-domain-policies: + - none + x-xss-protection: + - '0' + status: + code: 200 + message: OK +- request: + body: '{}' + headers: + Accept: + - application/json;version=2 + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + Content-Length: + - '2' + Content-Type: + - application/json + User-Agent: + - apypie (https://github.com/Apipie/apypie) + method: PUT + uri: https://foreman.example.org/api/smart_proxies/1/refresh + response: + body: + string: '{"created_at":"2025-11-19 09:15:31 UTC","updated_at":"2025-11-19 09:15:31 + UTC","hosts_count":1,"name":"foreman.example.org","id":1,"url":"https://foreman.example.org:8443","features":[{"capabilities":[],"name":"Puppet + CA","id":5},{"capabilities":[],"name":"Puppet","id":13},{"capabilities":[],"name":"Logs","id":9}],"locations":[{"id":2,"name":"Default + Location","title":"Default Location","description":null}],"organizations":[{"id":1,"name":"Default + Organization","title":"Default Organization","description":null}]}' + headers: + Cache-Control: + - max-age=0, private, must-revalidate + Connection: + - Keep-Alive + Content-Length: + - '576' + Content-Type: + - application/json; charset=utf-8 + Foreman_api_version: + - '2' + Foreman_current_location: + - ; ANY + Foreman_current_organization: + - ; ANY + Foreman_version: + - 3.18.0-develop + Keep-Alive: + - timeout=15, max=97 + Referrer-Policy: + - strict-origin-when-cross-origin + content-security-policy: + - 'default-src ''self''; child-src ''self''; connect-src ''self'' ws: wss:; + img-src ''self'' data:; script-src ''unsafe-eval'' ''unsafe-inline'' ''self''; + style-src ''unsafe-inline'' ''self''' + strict-transport-security: + - max-age=631139040; includeSubdomains + x-content-type-options: + - nosniff + x-download-options: + - noopen + x-frame-options: + - sameorigin + x-permitted-cross-domain-policies: + - none + x-xss-protection: + - '0' + status: + code: 200 + message: OK +version: 1 diff --git a/tests/test_playbooks/smart_proxy_refresh.yml b/tests/test_playbooks/smart_proxy_refresh.yml new file mode 100644 index 000000000..1ffbbe99d --- /dev/null +++ b/tests/test_playbooks/smart_proxy_refresh.yml @@ -0,0 +1,31 @@ +--- +- hosts: localhost + collections: + - theforeman.foreman + gather_facts: false + vars_files: + - vars/server.yml + tasks: + - include_tasks: tasks/organization.yml + vars: + organization_state: present + +- hosts: tests + collections: + - theforeman.foreman + gather_facts: false + vars_files: + - vars/server.yml + tasks: + - include_tasks: tasks/smart_proxy_refresh.yml + +- hosts: localhost + collections: + - theforeman.foreman + gather_facts: false + vars_files: + - vars/server.yml + tasks: + - include_tasks: tasks/organization.yml + vars: + organization_state: absent diff --git a/tests/test_playbooks/tasks/smart_proxy_refresh.yml b/tests/test_playbooks/tasks/smart_proxy_refresh.yml new file mode 100644 index 000000000..f7d42c1e0 --- /dev/null +++ b/tests/test_playbooks/tasks/smart_proxy_refresh.yml @@ -0,0 +1,12 @@ +--- +- name: "Refresh Smart Proxy '{{ smart_proxy_name }}'" + vars: + smart_proxy_name: "{{ foreman_proxy }}" + smart_proxy_refresh: + username: "{{ foreman_username }}" + password: "{{ foreman_password }}" + server_url: "{{ foreman_server_url }}" + validate_certs: "{{ foreman_validate_certs }}" + smart_proxy: "{{ smart_proxy_name }}" + register: result +... diff --git a/tests/vcr_python_wrapper.py b/tests/vcr_python_wrapper.py index 35f58afeb..fb397c127 100755 --- a/tests/vcr_python_wrapper.py +++ b/tests/vcr_python_wrapper.py @@ -182,7 +182,8 @@ def filter_request(request): method_matcher = 'safe_method_matcher' query_matcher = 'query' - if test_params['test_name'] in ['domain', 'hostgroup', 'katello_hostgroup', 'luna_hostgroup', 'realm', 'subnet', 'puppetclasses_import']: + if test_params['test_name'] in ['domain', 'hostgroup', 'katello_hostgroup', 'luna_hostgroup', 'realm', + 'subnet', 'puppetclasses_import', 'smart_proxy_refresh']: fam_vcr.register_matcher('query_ignore_proxy', query_matcher_ignore_proxy) query_matcher = 'query_ignore_proxy' elif test_params['test_name'] in ['snapshot', 'snapshot_info']: