Update CI - Continue work from #195 (#202)

* Upgrade Ansible and OKD versions for CI

* Use ubi9 and fix sanity

* Use correct pip install

* Try using quotes

* Ensure python3.9

* Upgrade ansible and molecule versions

* Remove DeploymentConfig

DeploymentConfigs are deprecated and seem to now be causing idempotence
problems. Replacing them with Deployments fixes it.

* Attempt to fix ldap integration tests

Signed-off-by: Alina Buzachis <abuzachis@redhat.com>

* Move sanity and unit tests to GH actions

Signed-off-by: Alina Buzachis <abuzachis@redhat.com>

* Firt round of sanity fixes

Signed-off-by: Alina Buzachis <abuzachis@redhat.com>

* Add kubernetes.core collection as sanity requirement

Signed-off-by: Alina Buzachis <abuzachis@redhat.com>

* Add ignore-2.16.txt

Signed-off-by: Alina Buzachis <abuzachis@redhat.com>

* Attempt to fix units

Signed-off-by: Alina Buzachis <abuzachis@redhat.com>

* Add ignore-2.17

Signed-off-by: Alina Buzachis <abuzachis@redhat.com>

* Attempt to fix unit tests

Signed-off-by: Alina Buzachis <abuzachis@redhat.com>

* Add pytest-ansible to test-requirements.txt

Signed-off-by: Alina Buzachis <abuzachis@redhat.com>

* Add changelog fragment

Signed-off-by: Alina Buzachis <abuzachis@redhat.com>

* Add workflow for ansible-lint

Signed-off-by: Alina Buzachis <abuzachis@redhat.com>

* Apply black

Signed-off-by: Alina Buzachis <abuzachis@redhat.com>

* Fix linters

Signed-off-by: Alina Buzachis <abuzachis@redhat.com>

* Add # fmt: skip

Signed-off-by: Alina Buzachis <abuzachis@redhat.com>

* Yet another round of linting

Signed-off-by: Alina Buzachis <abuzachis@redhat.com>

* Yet another round of linting

Signed-off-by: Alina Buzachis <abuzachis@redhat.com>

* Remove setup.cfg

Signed-off-by: Alina Buzachis <abuzachis@redhat.com>

* Revert #fmt

Signed-off-by: Alina Buzachis <abuzachis@redhat.com>

* Use ansible-core 2.14

Signed-off-by: Alina Buzachis <abuzachis@redhat.com>

* Cleanup ansible-lint ignores

Signed-off-by: Alina Buzachis <abuzachis@redhat.com>

* Try using service instead of pod IP

* Fix typo

* Actually use the correct port

* See if NetworkPolicy is preventing connection

* using Pod internal IP

* fix adm prune auth roles syntax

* adding some retry steps

* fix: openshift_builds target

* add flag --force-with-deps when building downstream collection

* Remove yamllint from tox linters, bump minimum python supported version to 3.9, Remove support for ansible-core < 2.14

---------

Signed-off-by: Alina Buzachis <abuzachis@redhat.com>
Co-authored-by: Mike Graves <mgraves@redhat.com>
Co-authored-by: Alina Buzachis <abuzachis@redhat.com>
This commit is contained in:
Bikouo Aubin
2023-11-15 18:00:38 +01:00
committed by GitHub
parent cb796e1298
commit a63e5b7b36
76 changed files with 4364 additions and 3510 deletions

View File

@@ -10,7 +10,7 @@ from __future__ import absolute_import, division, print_function
__metaclass__ = type
# STARTREMOVE (downstream)
DOCUMENTATION = r'''
DOCUMENTATION = r"""
module: k8s
@@ -142,9 +142,9 @@ requirements:
- "python >= 3.6"
- "kubernetes >= 12.0.0"
- "PyYAML >= 3.11"
'''
"""
EXAMPLES = r'''
EXAMPLES = r"""
- name: Create a k8s namespace
community.okd.k8s:
name: testing
@@ -169,10 +169,10 @@ EXAMPLES = r'''
app: galaxy
service: web
ports:
- protocol: TCP
targetPort: 8000
name: port-8000-tcp
port: 8000
- protocol: TCP
targetPort: 8000
name: port-8000-tcp
port: 8000
- name: Remove an existing Service object
community.okd.k8s:
@@ -206,18 +206,18 @@ EXAMPLES = r'''
state: present
definition: "{{ lookup('template', '/testing/deployment.yml') | from_yaml }}"
validate:
fail_on_error: yes
fail_on_error: true
- name: warn on validation errors, check for unexpected properties
community.okd.k8s:
state: present
definition: "{{ lookup('template', '/testing/deployment.yml') | from_yaml }}"
validate:
fail_on_error: no
strict: yes
'''
fail_on_error: false
strict: true
"""
RETURN = r'''
RETURN = r"""
result:
description:
- The created, patched, or otherwise present object. Will be empty in the case of a deletion.
@@ -254,22 +254,26 @@ result:
type: int
sample: 48
error:
description: error while trying to create/delete the object.
description: Error while trying to create/delete the object.
returned: error
type: complex
'''
"""
# ENDREMOVE (downstream)
from ansible_collections.kubernetes.core.plugins.module_utils.args_common import (
NAME_ARG_SPEC, RESOURCE_ARG_SPEC, AUTH_ARG_SPEC, WAIT_ARG_SPEC, DELETE_OPTS_ARG_SPEC
NAME_ARG_SPEC,
RESOURCE_ARG_SPEC,
AUTH_ARG_SPEC,
WAIT_ARG_SPEC,
DELETE_OPTS_ARG_SPEC,
)
def validate_spec():
return dict(
fail_on_error=dict(type='bool'),
fail_on_error=dict(type="bool"),
version=dict(),
strict=dict(type='bool', default=True)
strict=dict(type="bool", default=True),
)
@@ -279,30 +283,41 @@ def argspec():
argument_spec.update(RESOURCE_ARG_SPEC)
argument_spec.update(AUTH_ARG_SPEC)
argument_spec.update(WAIT_ARG_SPEC)
argument_spec['merge_type'] = dict(type='list', elements='str', choices=['json', 'merge', 'strategic-merge'])
argument_spec['validate'] = dict(type='dict', default=None, options=validate_spec())
argument_spec['append_hash'] = dict(type='bool', default=False)
argument_spec['apply'] = dict(type='bool', default=False)
argument_spec['template'] = dict(type='raw', default=None)
argument_spec['delete_options'] = dict(type='dict', default=None, options=DELETE_OPTS_ARG_SPEC)
argument_spec['continue_on_error'] = dict(type='bool', default=False)
argument_spec['state'] = dict(default='present', choices=['present', 'absent', 'patched'])
argument_spec['force'] = dict(type='bool', default=False)
argument_spec["merge_type"] = dict(
type="list", elements="str", choices=["json", "merge", "strategic-merge"]
)
argument_spec["validate"] = dict(type="dict", default=None, options=validate_spec())
argument_spec["append_hash"] = dict(type="bool", default=False)
argument_spec["apply"] = dict(type="bool", default=False)
argument_spec["template"] = dict(type="raw", default=None)
argument_spec["delete_options"] = dict(
type="dict", default=None, options=DELETE_OPTS_ARG_SPEC
)
argument_spec["continue_on_error"] = dict(type="bool", default=False)
argument_spec["state"] = dict(
default="present", choices=["present", "absent", "patched"]
)
argument_spec["force"] = dict(type="bool", default=False)
return argument_spec
def main():
mutually_exclusive = [
('resource_definition', 'src'),
('merge_type', 'apply'),
('template', 'resource_definition'),
('template', 'src'),
("resource_definition", "src"),
("merge_type", "apply"),
("template", "resource_definition"),
("template", "src"),
]
from ansible_collections.community.okd.plugins.module_utils.k8s import OKDRawModule
module = OKDRawModule(argument_spec=argspec(), supports_check_mode=True, mutually_exclusive=mutually_exclusive)
module = OKDRawModule(
argument_spec=argspec(),
supports_check_mode=True,
mutually_exclusive=mutually_exclusive,
)
module.run_module()
if __name__ == '__main__':
if __name__ == "__main__":
main()

View File

@@ -96,31 +96,31 @@ EXAMPLES = r"""
- name: Sync all groups from an LDAP server
openshift_adm_groups_sync:
src:
kind: LDAPSyncConfig
apiVersion: v1
url: ldap://localhost:1390
insecure: true
bindDN: cn=admin,dc=example,dc=org
bindPassword: adminpassword
rfc2307:
groupsQuery:
baseDN: "cn=admins,ou=groups,dc=example,dc=org"
scope: sub
derefAliases: never
filter: (objectClass=*)
pageSize: 0
groupUIDAttribute: dn
groupNameAttributes: [ cn ]
groupMembershipAttributes: [ member ]
usersQuery:
baseDN: "ou=users,dc=example,dc=org"
scope: sub
derefAliases: never
pageSize: 0
userUIDAttribute: dn
userNameAttributes: [ mail ]
tolerateMemberNotFoundErrors: true
tolerateMemberOutOfScopeErrors: true
kind: LDAPSyncConfig
apiVersion: v1
url: ldap://localhost:1390
insecure: true
bindDN: cn=admin,dc=example,dc=org
bindPassword: adminpassword
rfc2307:
groupsQuery:
baseDN: "cn=admins,ou=groups,dc=example,dc=org"
scope: sub
derefAliases: never
filter: (objectClass=*)
pageSize: 0
groupUIDAttribute: dn
groupNameAttributes: [cn]
groupMembershipAttributes: [member]
usersQuery:
baseDN: "ou=users,dc=example,dc=org"
scope: sub
derefAliases: never
pageSize: 0
userUIDAttribute: dn
userNameAttributes: [mail]
tolerateMemberNotFoundErrors: true
tolerateMemberOutOfScopeErrors: true
# Sync all groups except the ones from the deny_groups from an LDAP server
- name: Sync all groups from an LDAP server using deny_groups
@@ -192,20 +192,21 @@ builds:
# ENDREMOVE (downstream)
import copy
import traceback
from ansible_collections.kubernetes.core.plugins.module_utils.args_common import AUTH_ARG_SPEC
from ansible_collections.kubernetes.core.plugins.module_utils.args_common import (
AUTH_ARG_SPEC,
)
def argument_spec():
args = copy.deepcopy(AUTH_ARG_SPEC)
args.update(
dict(
state=dict(type='str', choices=['absent', 'present'], default='present'),
type=dict(type='str', choices=['ldap', 'openshift'], default='ldap'),
sync_config=dict(type='dict', aliases=['config', 'src'], required=True),
deny_groups=dict(type='list', elements='str', default=[]),
allow_groups=dict(type='list', elements='str', default=[]),
state=dict(type="str", choices=["absent", "present"], default="present"),
type=dict(type="str", choices=["ldap", "openshift"], default="ldap"),
sync_config=dict(type="dict", aliases=["config", "src"], required=True),
deny_groups=dict(type="list", elements="str", default=[]),
allow_groups=dict(type="list", elements="str", default=[]),
)
)
return args
@@ -213,12 +214,14 @@ def argument_spec():
def main():
from ansible_collections.community.okd.plugins.module_utils.openshift_groups import (
OpenshiftGroupsSync
OpenshiftGroupsSync,
)
module = OpenshiftGroupsSync(argument_spec=argument_spec(), supports_check_mode=True)
module = OpenshiftGroupsSync(
argument_spec=argument_spec(), supports_check_mode=True
)
module.run_module()
if __name__ == '__main__':
if __name__ == "__main__":
main()

View File

@@ -31,14 +31,14 @@ requirements:
"""
EXAMPLES = r"""
- name: Migrate TemplateInstances in namespace=test
community.okd.openshift_adm_migrate_template_instances:
namespace: test
register: _result
- name: Migrate TemplateInstances in namespace=test
community.okd.openshift_adm_migrate_template_instances:
namespace: test
register: _result
- name: Migrate TemplateInstances in all namespaces
community.okd.openshift_adm_migrate_template_instances:
register: _result
- name: Migrate TemplateInstances in all namespaces
community.okd.openshift_adm_migrate_template_instances:
register: _result
"""
RETURN = r"""
@@ -235,7 +235,9 @@ result:
from ansible.module_utils._text import to_native
from ansible_collections.community.okd.plugins.module_utils.openshift_common import AnsibleOpenshiftModule
from ansible_collections.community.okd.plugins.module_utils.openshift_common import (
AnsibleOpenshiftModule,
)
try:
from kubernetes.dynamic.exceptions import DynamicApiError
@@ -339,9 +341,7 @@ class OpenShiftMigrateTemplateInstances(AnsibleOpenshiftModule):
if ti_to_be_migrated:
if self.check_mode:
self.exit_json(
**{"changed": True, "result": ti_to_be_migrated}
)
self.exit_json(**{"changed": True, "result": ti_to_be_migrated})
else:
for ti_elem in ti_to_be_migrated:
results["result"].append(
@@ -363,7 +363,9 @@ def argspec():
def main():
argument_spec = argspec()
module = OpenShiftMigrateTemplateInstances(argument_spec=argument_spec, supports_check_mode=True)
module = OpenShiftMigrateTemplateInstances(
argument_spec=argument_spec, supports_check_mode=True
)
module.run_module()

View File

@@ -5,10 +5,11 @@
# 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
# STARTREMOVE (downstream)
DOCUMENTATION = r'''
DOCUMENTATION = r"""
module: openshift_adm_prune_auth
@@ -58,9 +59,9 @@ options:
requirements:
- python >= 3.6
- kubernetes >= 12.0.0
'''
"""
EXAMPLES = r'''
EXAMPLES = r"""
- name: Prune all roles from default namespace
openshift_adm_prune_auth:
resource: roles
@@ -72,10 +73,10 @@ EXAMPLES = r'''
namespace: testing
label_selectors:
- phase=production
'''
"""
RETURN = r'''
RETURN = r"""
cluster_role_binding:
type: list
description: list of cluster role binding deleted.
@@ -96,37 +97,45 @@ group:
type: list
description: list of Security Context Constraints deleted.
returned: I(resource=users)
'''
"""
# ENDREMOVE (downstream)
import copy
from ansible_collections.kubernetes.core.plugins.module_utils.args_common import AUTH_ARG_SPEC
from ansible_collections.kubernetes.core.plugins.module_utils.args_common import (
AUTH_ARG_SPEC,
)
def argument_spec():
args = copy.deepcopy(AUTH_ARG_SPEC)
args.update(
dict(
resource=dict(type='str', required=True, choices=['roles', 'clusterroles', 'users', 'groups']),
namespace=dict(type='str'),
name=dict(type='str'),
label_selectors=dict(type='list', elements='str'),
resource=dict(
type="str",
required=True,
choices=["roles", "clusterroles", "users", "groups"],
),
namespace=dict(type="str"),
name=dict(type="str"),
label_selectors=dict(type="list", elements="str"),
)
)
return args
def main():
from ansible_collections.community.okd.plugins.module_utils.openshift_adm_prune_auth import (
OpenShiftAdmPruneAuth)
OpenShiftAdmPruneAuth,
)
module = OpenShiftAdmPruneAuth(argument_spec=argument_spec(),
mutually_exclusive=[("name", "label_selectors")],
supports_check_mode=True)
module = OpenShiftAdmPruneAuth(
argument_spec=argument_spec(),
mutually_exclusive=[("name", "label_selectors")],
supports_check_mode=True,
)
module.run_module()
if __name__ == '__main__':
if __name__ == "__main__":
main()

View File

@@ -5,10 +5,11 @@
# 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
# STARTREMOVE (downstream)
DOCUMENTATION = r'''
DOCUMENTATION = r"""
module: openshift_adm_prune_builds
@@ -45,14 +46,14 @@ options:
requirements:
- python >= 3.6
- kubernetes >= 12.0.0
'''
"""
EXAMPLES = r'''
EXAMPLES = r"""
# Run deleting older completed and failed builds and also including
# all builds whose associated BuildConfig no longer exists
- name: Run delete orphan Builds
community.okd.openshift_adm_prune_builds:
orphans: True
orphans: true
# Run deleting older completed and failed builds keep younger than 2hours
- name: Run delete builds, keep younger than 2h
@@ -63,9 +64,9 @@ EXAMPLES = r'''
- name: Run delete builds from namespace
community.okd.openshift_adm_prune_builds:
namespace: testing_namespace
'''
"""
RETURN = r'''
RETURN = r"""
builds:
description:
- The builds that were deleted
@@ -92,33 +93,38 @@ builds:
description: Current status details for the object.
returned: success
type: dict
'''
"""
# ENDREMOVE (downstream)
import copy
from ansible_collections.kubernetes.core.plugins.module_utils.args_common import AUTH_ARG_SPEC
from ansible_collections.kubernetes.core.plugins.module_utils.args_common import (
AUTH_ARG_SPEC,
)
def argument_spec():
args = copy.deepcopy(AUTH_ARG_SPEC)
args.update(
dict(
namespace=dict(type='str'),
keep_younger_than=dict(type='int'),
orphans=dict(type='bool', default=False),
namespace=dict(type="str"),
keep_younger_than=dict(type="int"),
orphans=dict(type="bool", default=False),
)
)
return args
def main():
from ansible_collections.community.okd.plugins.module_utils.openshift_builds import (
OpenShiftPruneBuilds,
)
from ansible_collections.community.okd.plugins.module_utils.openshift_builds import OpenShiftPruneBuilds
module = OpenShiftPruneBuilds(argument_spec=argument_spec(), supports_check_mode=True)
module = OpenShiftPruneBuilds(
argument_spec=argument_spec(), supports_check_mode=True
)
module.run_module()
if __name__ == '__main__':
if __name__ == "__main__":
main()

View File

@@ -5,10 +5,11 @@
# 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
# STARTREMOVE (downstream)
DOCUMENTATION = r'''
DOCUMENTATION = r"""
module: openshift_adm_prune_deployments
@@ -45,32 +46,34 @@ options:
requirements:
- python >= 3.6
- kubernetes >= 12.0.0
'''
"""
EXAMPLES = r'''
EXAMPLES = r"""
- name: Prune Deployments from testing namespace
community.okd.openshift_adm_prune_deployments:
namespace: testing
- name: Prune orphans deployments, keep younger than 2hours
community.okd.openshift_adm_prune_deployments:
orphans: True
orphans: true
keep_younger_than: 120
'''
"""
RETURN = r'''
RETURN = r"""
replication_controllers:
type: list
description: list of replication controllers candidate for pruning.
returned: always
'''
"""
# ENDREMOVE (downstream)
import copy
try:
from ansible_collections.kubernetes.core.plugins.module_utils.args_common import AUTH_ARG_SPEC
from ansible_collections.kubernetes.core.plugins.module_utils.args_common import (
AUTH_ARG_SPEC,
)
except ImportError as e:
pass
@@ -79,22 +82,28 @@ def argument_spec():
args = copy.deepcopy(AUTH_ARG_SPEC)
args.update(
dict(
namespace=dict(type='str',),
keep_younger_than=dict(type='int',),
orphans=dict(type='bool', default=False),
namespace=dict(
type="str",
),
keep_younger_than=dict(
type="int",
),
orphans=dict(type="bool", default=False),
)
)
return args
def main():
from ansible_collections.community.okd.plugins.module_utils.openshift_adm_prune_deployments import (
OpenShiftAdmPruneDeployment)
OpenShiftAdmPruneDeployment,
)
module = OpenShiftAdmPruneDeployment(argument_spec=argument_spec(), supports_check_mode=True)
module = OpenShiftAdmPruneDeployment(
argument_spec=argument_spec(), supports_check_mode=True
)
module.run_module()
if __name__ == '__main__':
if __name__ == "__main__":
main()

View File

@@ -5,10 +5,11 @@
# 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
# STARTREMOVE (downstream)
DOCUMENTATION = r'''
DOCUMENTATION = r"""
module: openshift_adm_prune_images
@@ -84,9 +85,9 @@ requirements:
- python >= 3.6
- kubernetes >= 12.0.0
- docker-image-py
'''
"""
EXAMPLES = r'''
EXAMPLES = r"""
# Prune if only images and their referrers were more than an hour old
- name: Prune image with referrer been more than an hour old
community.okd.openshift_adm_prune_images:
@@ -102,10 +103,10 @@ EXAMPLES = r'''
community.okd.openshift_adm_prune_images:
registry_url: http://registry.example.org
registry_validate_certs: false
'''
"""
RETURN = r'''
RETURN = r"""
updated_image_streams:
description:
- The images streams updated.
@@ -275,41 +276,44 @@ deleted_images:
},
...
]
'''
"""
# ENDREMOVE (downstream)
import copy
from ansible_collections.kubernetes.core.plugins.module_utils.args_common import AUTH_ARG_SPEC
from ansible_collections.kubernetes.core.plugins.module_utils.args_common import (
AUTH_ARG_SPEC,
)
def argument_spec():
args = copy.deepcopy(AUTH_ARG_SPEC)
args.update(
dict(
namespace=dict(type='str'),
all_images=dict(type='bool', default=True),
keep_younger_than=dict(type='int'),
prune_over_size_limit=dict(type='bool', default=False),
registry_url=dict(type='str'),
registry_validate_certs=dict(type='bool'),
registry_ca_cert=dict(type='path'),
prune_registry=dict(type='bool', default=True),
ignore_invalid_refs=dict(type='bool', default=False),
namespace=dict(type="str"),
all_images=dict(type="bool", default=True),
keep_younger_than=dict(type="int"),
prune_over_size_limit=dict(type="bool", default=False),
registry_url=dict(type="str"),
registry_validate_certs=dict(type="bool"),
registry_ca_cert=dict(type="path"),
prune_registry=dict(type="bool", default=True),
ignore_invalid_refs=dict(type="bool", default=False),
)
)
return args
def main():
from ansible_collections.community.okd.plugins.module_utils.openshift_adm_prune_images import (
OpenShiftAdmPruneImages
OpenShiftAdmPruneImages,
)
module = OpenShiftAdmPruneImages(argument_spec=argument_spec(), supports_check_mode=True)
module = OpenShiftAdmPruneImages(
argument_spec=argument_spec(), supports_check_mode=True
)
module.run_module()
if __name__ == '__main__':
if __name__ == "__main__":
main()

View File

@@ -5,9 +5,10 @@
# 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'''
DOCUMENTATION = r"""
module: openshift_auth
@@ -74,46 +75,49 @@ requirements:
- urllib3
- requests
- requests-oauthlib
'''
"""
EXAMPLES = r'''
- hosts: localhost
EXAMPLES = r"""
- name: Example Playbook
hosts: localhost
module_defaults:
group/community.okd.okd:
host: https://k8s.example.com/
ca_cert: ca.pem
tasks:
- block:
# It's good practice to store login credentials in a secure vault and not
# directly in playbooks.
- include_vars: openshift_passwords.yml
- name: Authenticate to OpenShift cluster and gell a list of all pods from any namespace
block:
# It's good practice to store login credentials in a secure vault and not
# directly in playbooks.
- name: Include 'openshift_passwords.yml'
ansible.builtin.include_vars: openshift_passwords.yml
- name: Log in (obtain access token)
community.okd.openshift_auth:
username: admin
password: "{{ openshift_admin_password }}"
register: openshift_auth_results
- name: Log in (obtain access token)
community.okd.openshift_auth:
username: admin
password: "{{ openshift_admin_password }}"
register: openshift_auth_results
# Previous task provides the token/api_key, while all other parameters
# are taken from module_defaults
- name: Get a list of all pods from any namespace
kubernetes.core.k8s_info:
api_key: "{{ openshift_auth_results.openshift_auth.api_key }}"
kind: Pod
register: pod_list
# Previous task provides the token/api_key, while all other parameters
# are taken from module_defaults
- name: Get a list of all pods from any namespace
kubernetes.core.k8s_info:
api_key: "{{ openshift_auth_results.openshift_auth.api_key }}"
kind: Pod
register: pod_list
always:
- name: If login succeeded, try to log out (revoke access token)
when: openshift_auth_results.openshift_auth.api_key is defined
community.okd.openshift_auth:
state: absent
api_key: "{{ openshift_auth_results.openshift_auth.api_key }}"
'''
always:
- name: If login succeeded, try to log out (revoke access token)
when: openshift_auth_results.openshift_auth.api_key is defined
community.okd.openshift_auth:
state: absent
api_key: "{{ openshift_auth_results.openshift_auth.api_key }}"
"""
# Returned value names need to match k8s modules parameter names, to make it
# easy to pass returned values of openshift_auth to other k8s modules.
# Discussion: https://github.com/ansible/ansible/pull/50807#discussion_r248827899
RETURN = r'''
RETURN = r"""
openshift_auth:
description: OpenShift authentication facts.
returned: success
@@ -164,7 +168,7 @@ k8s_auth:
description: Username for authenticating with the API server.
returned: success
type: str
'''
"""
import traceback
@@ -179,52 +183,52 @@ import hashlib
# 3rd party imports
try:
import requests
HAS_REQUESTS = True
except ImportError:
HAS_REQUESTS = False
try:
from requests_oauthlib import OAuth2Session
HAS_REQUESTS_OAUTH = True
except ImportError:
HAS_REQUESTS_OAUTH = False
try:
from urllib3.util import make_headers
HAS_URLLIB3 = True
except ImportError:
HAS_URLLIB3 = False
K8S_AUTH_ARG_SPEC = {
'state': {
'default': 'present',
'choices': ['present', 'absent'],
"state": {
"default": "present",
"choices": ["present", "absent"],
},
'host': {'required': True},
'username': {},
'password': {'no_log': True},
'ca_cert': {'type': 'path', 'aliases': ['ssl_ca_cert']},
'validate_certs': {
'type': 'bool',
'default': True,
'aliases': ['verify_ssl']
},
'api_key': {'no_log': True},
"host": {"required": True},
"username": {},
"password": {"no_log": True},
"ca_cert": {"type": "path", "aliases": ["ssl_ca_cert"]},
"validate_certs": {"type": "bool", "default": True, "aliases": ["verify_ssl"]},
"api_key": {"no_log": True},
}
def get_oauthaccesstoken_objectname_from_token(token_name):
"""
openshift convert the access token to an OAuthAccessToken resource name using the algorithm
https://github.com/openshift/console/blob/9f352ba49f82ad693a72d0d35709961428b43b93/pkg/server/server.go#L609-L613
openshift convert the access token to an OAuthAccessToken resource name using the algorithm
https://github.com/openshift/console/blob/9f352ba49f82ad693a72d0d35709961428b43b93/pkg/server/server.go#L609-L613
"""
sha256Prefix = "sha256~"
content = token_name.strip(sha256Prefix)
b64encoded = urlsafe_b64encode(hashlib.sha256(content.encode()).digest()).rstrip(b'=')
b64encoded = urlsafe_b64encode(hashlib.sha256(content.encode()).digest()).rstrip(
b"="
)
return sha256Prefix + b64encoded.decode("utf-8")
@@ -234,42 +238,48 @@ class OpenShiftAuthModule(AnsibleModule):
self,
argument_spec=K8S_AUTH_ARG_SPEC,
required_if=[
('state', 'present', ['username', 'password']),
('state', 'absent', ['api_key']),
]
("state", "present", ["username", "password"]),
("state", "absent", ["api_key"]),
],
)
if not HAS_REQUESTS:
self.fail("This module requires the python 'requests' package. Try `pip install requests`.")
self.fail(
"This module requires the python 'requests' package. Try `pip install requests`."
)
if not HAS_REQUESTS_OAUTH:
self.fail("This module requires the python 'requests-oauthlib' package. Try `pip install requests-oauthlib`.")
self.fail(
"This module requires the python 'requests-oauthlib' package. Try `pip install requests-oauthlib`."
)
if not HAS_URLLIB3:
self.fail("This module requires the python 'urllib3' package. Try `pip install urllib3`.")
self.fail(
"This module requires the python 'urllib3' package. Try `pip install urllib3`."
)
def execute_module(self):
state = self.params.get('state')
verify_ssl = self.params.get('validate_certs')
ssl_ca_cert = self.params.get('ca_cert')
state = self.params.get("state")
verify_ssl = self.params.get("validate_certs")
ssl_ca_cert = self.params.get("ca_cert")
self.auth_username = self.params.get('username')
self.auth_password = self.params.get('password')
self.auth_api_key = self.params.get('api_key')
self.con_host = self.params.get('host')
self.auth_username = self.params.get("username")
self.auth_password = self.params.get("password")
self.auth_api_key = self.params.get("api_key")
self.con_host = self.params.get("host")
# python-requests takes either a bool or a path to a ca file as the 'verify' param
if verify_ssl and ssl_ca_cert:
self.con_verify_ca = ssl_ca_cert # path
else:
self.con_verify_ca = verify_ssl # bool
self.con_verify_ca = verify_ssl # bool
# Get needed info to access authorization APIs
self.openshift_discover()
changed = False
result = dict()
if state == 'present':
if state == "present":
new_api_key = self.openshift_login()
result = dict(
host=self.con_host,
@@ -285,87 +295,114 @@ class OpenShiftAuthModule(AnsibleModule):
self.exit_json(changed=changed, openshift_auth=result, k8s_auth=result)
def openshift_discover(self):
url = urljoin(self.con_host, '.well-known/oauth-authorization-server')
url = urljoin(self.con_host, ".well-known/oauth-authorization-server")
ret = requests.get(url, verify=self.con_verify_ca)
if ret.status_code != 200:
self.fail_request("Couldn't find OpenShift's OAuth API", method='GET', url=url,
reason=ret.reason, status_code=ret.status_code)
self.fail_request(
"Couldn't find OpenShift's OAuth API",
method="GET",
url=url,
reason=ret.reason,
status_code=ret.status_code,
)
try:
oauth_info = ret.json()
self.openshift_auth_endpoint = oauth_info['authorization_endpoint']
self.openshift_token_endpoint = oauth_info['token_endpoint']
self.openshift_auth_endpoint = oauth_info["authorization_endpoint"]
self.openshift_token_endpoint = oauth_info["token_endpoint"]
except Exception:
self.fail_json(msg="Something went wrong discovering OpenShift OAuth details.",
exception=traceback.format_exc())
self.fail_json(
msg="Something went wrong discovering OpenShift OAuth details.",
exception=traceback.format_exc(),
)
def openshift_login(self):
os_oauth = OAuth2Session(client_id='openshift-challenging-client')
authorization_url, state = os_oauth.authorization_url(self.openshift_auth_endpoint,
state="1", code_challenge_method='S256')
auth_headers = make_headers(basic_auth='{0}:{1}'.format(self.auth_username, self.auth_password))
os_oauth = OAuth2Session(client_id="openshift-challenging-client")
authorization_url, state = os_oauth.authorization_url(
self.openshift_auth_endpoint, state="1", code_challenge_method="S256"
)
auth_headers = make_headers(
basic_auth="{0}:{1}".format(self.auth_username, self.auth_password)
)
# Request authorization code using basic auth credentials
ret = os_oauth.get(
authorization_url,
headers={'X-Csrf-Token': state, 'authorization': auth_headers.get('authorization')},
headers={
"X-Csrf-Token": state,
"authorization": auth_headers.get("authorization"),
},
verify=self.con_verify_ca,
allow_redirects=False
allow_redirects=False,
)
if ret.status_code != 302:
self.fail_request("Authorization failed.", method='GET', url=authorization_url,
reason=ret.reason, status_code=ret.status_code)
self.fail_request(
"Authorization failed.",
method="GET",
url=authorization_url,
reason=ret.reason,
status_code=ret.status_code,
)
# In here we have `code` and `state`, I think `code` is the important one
qwargs = {}
for k, v in parse_qs(urlparse(ret.headers['Location']).query).items():
for k, v in parse_qs(urlparse(ret.headers["Location"]).query).items():
qwargs[k] = v[0]
qwargs['grant_type'] = 'authorization_code'
qwargs["grant_type"] = "authorization_code"
# Using authorization code given to us in the Location header of the previous request, request a token
ret = os_oauth.post(
self.openshift_token_endpoint,
headers={
'Accept': 'application/json',
'Content-Type': 'application/x-www-form-urlencoded',
"Accept": "application/json",
"Content-Type": "application/x-www-form-urlencoded",
# This is just base64 encoded 'openshift-challenging-client:'
'Authorization': 'Basic b3BlbnNoaWZ0LWNoYWxsZW5naW5nLWNsaWVudDo='
"Authorization": "Basic b3BlbnNoaWZ0LWNoYWxsZW5naW5nLWNsaWVudDo=",
},
data=urlencode(qwargs),
verify=self.con_verify_ca
verify=self.con_verify_ca,
)
if ret.status_code != 200:
self.fail_request("Failed to obtain an authorization token.", method='POST',
url=self.openshift_token_endpoint,
reason=ret.reason, status_code=ret.status_code)
self.fail_request(
"Failed to obtain an authorization token.",
method="POST",
url=self.openshift_token_endpoint,
reason=ret.reason,
status_code=ret.status_code,
)
return ret.json()['access_token']
return ret.json()["access_token"]
def openshift_logout(self):
name = get_oauthaccesstoken_objectname_from_token(self.auth_api_key)
headers = {
'Accept': 'application/json',
'Content-Type': 'application/json',
'Authorization': "Bearer {0}".format(self.auth_api_key)
"Accept": "application/json",
"Content-Type": "application/json",
"Authorization": "Bearer {0}".format(self.auth_api_key),
}
url = "{0}/apis/oauth.openshift.io/v1/useroauthaccesstokens/{1}".format(self.con_host, name)
url = "{0}/apis/oauth.openshift.io/v1/useroauthaccesstokens/{1}".format(
self.con_host, name
)
json = {
"apiVersion": "oauth.openshift.io/v1",
"kind": "DeleteOptions",
"gracePeriodSeconds": 0
"gracePeriodSeconds": 0,
}
ret = requests.delete(url, json=json, verify=self.con_verify_ca, headers=headers)
ret = requests.delete(
url, json=json, verify=self.con_verify_ca, headers=headers
)
if ret.status_code != 200:
self.fail_json(
msg="Couldn't delete user oauth access token '{0}' due to: {1}".format(name, ret.json().get("message")),
status_code=ret.status_code
msg="Couldn't delete user oauth access token '{0}' due to: {1}".format(
name, ret.json().get("message")
),
status_code=ret.status_code,
)
return True
@@ -376,7 +413,7 @@ class OpenShiftAuthModule(AnsibleModule):
def fail_request(self, msg, **kwargs):
req_info = {}
for k, v in kwargs.items():
req_info['req_' + k] = v
req_info["req_" + k] = v
self.fail_json(msg=msg, **req_info)
@@ -388,5 +425,5 @@ def main():
module.fail_json(msg=str(e), exception=traceback.format_exc())
if __name__ == '__main__':
if __name__ == "__main__":
main()

View File

@@ -5,10 +5,11 @@
# 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
# STARTREMOVE (downstream)
DOCUMENTATION = r'''
DOCUMENTATION = r"""
module: openshift_build
@@ -134,9 +135,9 @@ options:
requirements:
- python >= 3.6
- kubernetes >= 12.0.0
'''
"""
EXAMPLES = r'''
EXAMPLES = r"""
# Starts build from build config default/hello-world
- name: Starts build from build config
community.okd.openshift_build:
@@ -171,9 +172,9 @@ EXAMPLES = r'''
build_phases:
- New
state: cancelled
'''
"""
RETURN = r'''
RETURN = r"""
builds:
description:
- The builds that were started/cancelled.
@@ -200,37 +201,47 @@ builds:
description: Current status details for the object.
returned: success
type: dict
'''
"""
# ENDREMOVE (downstream)
import copy
from ansible_collections.kubernetes.core.plugins.module_utils.args_common import AUTH_ARG_SPEC
from ansible_collections.kubernetes.core.plugins.module_utils.args_common import (
AUTH_ARG_SPEC,
)
def argument_spec():
args = copy.deepcopy(AUTH_ARG_SPEC)
args_options = dict(
name=dict(type='str', required=True),
value=dict(type='str', required=True)
name=dict(type="str", required=True), value=dict(type="str", required=True)
)
args.update(
dict(
state=dict(type='str', choices=['started', 'cancelled', 'restarted'], default="started"),
build_args=dict(type='list', elements='dict', options=args_options),
commit=dict(type='str'),
env_vars=dict(type='list', elements='dict', options=args_options),
build_name=dict(type='str'),
build_config_name=dict(type='str'),
namespace=dict(type='str', required=True),
incremental=dict(type='bool'),
no_cache=dict(type='bool'),
wait=dict(type='bool', default=False),
wait_sleep=dict(type='int', default=5),
wait_timeout=dict(type='int', default=120),
build_phases=dict(type='list', elements='str', default=[], choices=["New", "Pending", "Running"]),
state=dict(
type="str",
choices=["started", "cancelled", "restarted"],
default="started",
),
build_args=dict(type="list", elements="dict", options=args_options),
commit=dict(type="str"),
env_vars=dict(type="list", elements="dict", options=args_options),
build_name=dict(type="str"),
build_config_name=dict(type="str"),
namespace=dict(type="str", required=True),
incremental=dict(type="bool"),
no_cache=dict(type="bool"),
wait=dict(type="bool", default=False),
wait_sleep=dict(type="int", default=5),
wait_timeout=dict(type="int", default=120),
build_phases=dict(
type="list",
elements="str",
default=[],
choices=["New", "Pending", "Running"],
),
)
)
return args
@@ -238,23 +249,24 @@ def argument_spec():
def main():
mutually_exclusive = [
('build_name', 'build_config_name'),
("build_name", "build_config_name"),
]
from ansible_collections.community.okd.plugins.module_utils.openshift_builds import (
OpenShiftBuilds
OpenShiftBuilds,
)
module = OpenShiftBuilds(
argument_spec=argument_spec(),
mutually_exclusive=mutually_exclusive,
required_one_of=[
[
'build_name',
'build_config_name',
"build_name",
"build_config_name",
]
],
)
module.run_module()
if __name__ == '__main__':
if __name__ == "__main__":
main()

View File

@@ -5,10 +5,11 @@
# 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
# STARTREMOVE (downstream)
DOCUMENTATION = r'''
DOCUMENTATION = r"""
module: openshift_import_image
@@ -75,9 +76,9 @@ requirements:
- python >= 3.6
- kubernetes >= 12.0.0
- docker-image-py
'''
"""
EXAMPLES = r'''
EXAMPLES = r"""
# Import tag latest into a new image stream.
- name: Import tag latest into new image stream
community.okd.openshift_import_image:
@@ -122,10 +123,10 @@ EXAMPLES = r'''
- mystream3
source: registry.io/repo/image:latest
all: true
'''
"""
RETURN = r'''
RETURN = r"""
result:
description:
- List with all ImageStreamImport that have been created.
@@ -153,42 +154,44 @@ result:
description: Current status details for the object.
returned: success
type: dict
'''
"""
# ENDREMOVE (downstream)
import copy
from ansible_collections.kubernetes.core.plugins.module_utils.args_common import AUTH_ARG_SPEC
from ansible_collections.kubernetes.core.plugins.module_utils.args_common import (
AUTH_ARG_SPEC,
)
def argument_spec():
args = copy.deepcopy(AUTH_ARG_SPEC)
args.update(
dict(
namespace=dict(type='str', required=True),
name=dict(type='raw', required=True),
all=dict(type='bool', default=False),
validate_registry_certs=dict(type='bool'),
reference_policy=dict(type='str', choices=["source", "local"], default="source"),
scheduled=dict(type='bool', default=False),
source=dict(type='str'),
namespace=dict(type="str", required=True),
name=dict(type="raw", required=True),
all=dict(type="bool", default=False),
validate_registry_certs=dict(type="bool"),
reference_policy=dict(
type="str", choices=["source", "local"], default="source"
),
scheduled=dict(type="bool", default=False),
source=dict(type="str"),
)
)
return args
def main():
from ansible_collections.community.okd.plugins.module_utils.openshift_import_image import (
OpenShiftImportImage
OpenShiftImportImage,
)
module = OpenShiftImportImage(
argument_spec=argument_spec(),
supports_check_mode=True
argument_spec=argument_spec(), supports_check_mode=True
)
module.run_module()
if __name__ == '__main__':
if __name__ == "__main__":
main()

View File

@@ -2,13 +2,14 @@
# -*- coding: utf-8 -*-
from __future__ import absolute_import, division, print_function
__metaclass__ = type
# Copyright (c) 2020-2021, Red Hat
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
# STARTREMOVE (downstream)
DOCUMENTATION = r'''
DOCUMENTATION = r"""
module: openshift_process
short_description: Process an OpenShift template.openshift.io/v1 Template
@@ -49,6 +50,7 @@ options:
description:
- The namespace that resources should be created, updated, or deleted in.
- Only used when I(state) is present or absent.
type: str
parameters:
description:
- 'A set of key: value pairs that will be used to set/override values in the Template.'
@@ -70,9 +72,9 @@ options:
type: str
default: rendered
choices: [ absent, present, rendered ]
'''
"""
EXAMPLES = r'''
EXAMPLES = r"""
- name: Process a template in the cluster
community.okd.openshift_process:
name: nginx-example
@@ -87,8 +89,8 @@ EXAMPLES = r'''
community.okd.k8s:
namespace: default
definition: '{{ item }}'
wait: yes
apply: yes
wait: true
apply: true
loop: '{{ result.resources }}'
- name: Process a template with parameters from an env file and create the resources
@@ -98,7 +100,7 @@ EXAMPLES = r'''
namespace_target: default
parameter_file: 'files/nginx.env'
state: present
wait: yes
wait: true
- name: Process a local template and create the resources
community.okd.openshift_process:
@@ -113,10 +115,10 @@ EXAMPLES = r'''
parameter_file: files/example.env
namespace_target: default
state: absent
wait: yes
'''
wait: true
"""
RETURN = r'''
RETURN = r"""
result:
description:
- The created, patched, or otherwise present object. Will be empty in the case of a deletion.
@@ -200,11 +202,13 @@ resources:
conditions:
type: complex
description: Array of status conditions for the object. Not guaranteed to be present
'''
"""
# ENDREMOVE (downstream)
from ansible_collections.kubernetes.core.plugins.module_utils.args_common import (
AUTH_ARG_SPEC, RESOURCE_ARG_SPEC, WAIT_ARG_SPEC
AUTH_ARG_SPEC,
RESOURCE_ARG_SPEC,
WAIT_ARG_SPEC,
)
@@ -213,24 +217,26 @@ def argspec():
argument_spec.update(AUTH_ARG_SPEC)
argument_spec.update(WAIT_ARG_SPEC)
argument_spec.update(RESOURCE_ARG_SPEC)
argument_spec['state'] = dict(type='str', default='rendered', choices=['present', 'absent', 'rendered'])
argument_spec['namespace'] = dict(type='str')
argument_spec['namespace_target'] = dict(type='str')
argument_spec['parameters'] = dict(type='dict')
argument_spec['name'] = dict(type='str')
argument_spec['parameter_file'] = dict(type='str')
argument_spec["state"] = dict(
type="str", default="rendered", choices=["present", "absent", "rendered"]
)
argument_spec["namespace"] = dict(type="str")
argument_spec["namespace_target"] = dict(type="str")
argument_spec["parameters"] = dict(type="dict")
argument_spec["name"] = dict(type="str")
argument_spec["parameter_file"] = dict(type="str")
return argument_spec
def main():
from ansible_collections.community.okd.plugins.module_utils.openshift_process import (
OpenShiftProcess)
OpenShiftProcess,
)
module = OpenShiftProcess(argument_spec=argspec(), supports_check_mode=True)
module.run_module()
if __name__ == '__main__':
if __name__ == "__main__":
main()

View File

@@ -5,10 +5,11 @@
# 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
# STARTREMOVE (downstream)
DOCUMENTATION = r'''
DOCUMENTATION = r"""
module: openshift_registry_info
@@ -40,9 +41,9 @@ requirements:
- python >= 3.6
- kubernetes >= 12.0.0
- docker-image-py
'''
"""
EXAMPLES = r'''
EXAMPLES = r"""
# Get registry information
- name: Read integrated registry information
community.okd.openshift_registry_info:
@@ -50,11 +51,11 @@ EXAMPLES = r'''
# Read registry integrated information and attempt to contact using local client.
- name: Attempt to contact integrated registry using local client
community.okd.openshift_registry_info:
check: yes
'''
check: true
"""
RETURN = r'''
RETURN = r"""
internal_hostname:
description:
- The internal registry hostname.
@@ -79,36 +80,30 @@ check:
description: message describing the ping operation.
returned: always
type: str
'''
"""
# ENDREMOVE (downstream)
import copy
from ansible_collections.kubernetes.core.plugins.module_utils.args_common import AUTH_ARG_SPEC
from ansible_collections.kubernetes.core.plugins.module_utils.args_common import (
AUTH_ARG_SPEC,
)
def argument_spec():
args = copy.deepcopy(AUTH_ARG_SPEC)
args.update(
dict(
check=dict(type='bool', default=False)
)
)
args.update(dict(check=dict(type="bool", default=False)))
return args
def main():
from ansible_collections.community.okd.plugins.module_utils.openshift_registry import (
OpenShiftRegistry
OpenShiftRegistry,
)
module = OpenShiftRegistry(
argument_spec=argument_spec(),
supports_check_mode=True
)
module = OpenShiftRegistry(argument_spec=argument_spec(), supports_check_mode=True)
module.run_module()
if __name__ == '__main__':
if __name__ == "__main__":
main()

View File

@@ -9,7 +9,7 @@ from __future__ import absolute_import, division, print_function
__metaclass__ = type
# STARTREMOVE (downstream)
DOCUMENTATION = r'''
DOCUMENTATION = r"""
module: openshift_route
short_description: Expose a Service as an OpenShift Route.
@@ -133,9 +133,9 @@ options:
- insecure
default: insecure
type: str
'''
"""
EXAMPLES = r'''
EXAMPLES = r"""
- name: Create hello-world deployment
community.okd.k8s:
definition:
@@ -155,10 +155,10 @@ EXAMPLES = r'''
app: hello-kubernetes
spec:
containers:
- name: hello-kubernetes
image: paulbouwer/hello-kubernetes:1.8
ports:
- containerPort: 8080
- name: hello-kubernetes
image: paulbouwer/hello-kubernetes:1.8
ports:
- containerPort: 8080
- name: Create Service for the hello-world deployment
community.okd.k8s:
@@ -170,8 +170,8 @@ EXAMPLES = r'''
namespace: default
spec:
ports:
- port: 80
targetPort: 8080
- port: 80
targetPort: 8080
selector:
app: hello-kubernetes
@@ -183,9 +183,9 @@ EXAMPLES = r'''
annotations:
haproxy.router.openshift.io/balance: roundrobin
register: route
'''
"""
RETURN = r'''
RETURN = r"""
result:
description:
- The Route object that was created or updated. Will be empty in the case of deletion.
@@ -303,20 +303,28 @@ duration:
returned: when C(wait) is true
type: int
sample: 48
'''
"""
# ENDREMOVE (downstream)
import copy
from ansible.module_utils._text import to_native
from ansible_collections.community.okd.plugins.module_utils.openshift_common import AnsibleOpenshiftModule
from ansible_collections.community.okd.plugins.module_utils.openshift_common import (
AnsibleOpenshiftModule,
)
try:
from ansible_collections.kubernetes.core.plugins.module_utils.k8s.runner import perform_action
from ansible_collections.kubernetes.core.plugins.module_utils.k8s.waiter import Waiter
from ansible_collections.kubernetes.core.plugins.module_utils.k8s.runner import (
perform_action,
)
from ansible_collections.kubernetes.core.plugins.module_utils.k8s.waiter import (
Waiter,
)
from ansible_collections.kubernetes.core.plugins.module_utils.args_common import (
AUTH_ARG_SPEC, WAIT_ARG_SPEC, COMMON_ARG_SPEC
AUTH_ARG_SPEC,
WAIT_ARG_SPEC,
COMMON_ARG_SPEC,
)
except ImportError as e:
pass
@@ -329,7 +337,6 @@ except ImportError:
class OpenShiftRoute(AnsibleOpenshiftModule):
def __init__(self):
super(OpenShiftRoute, self).__init__(
argument_spec=self.argspec,
@@ -339,7 +346,7 @@ class OpenShiftRoute(AnsibleOpenshiftModule):
self.append_hash = False
self.apply = False
self.warnings = []
self.params['merge_type'] = None
self.params["merge_type"] = None
@property
def argspec(self):
@@ -347,80 +354,95 @@ class OpenShiftRoute(AnsibleOpenshiftModule):
spec.update(copy.deepcopy(WAIT_ARG_SPEC))
spec.update(copy.deepcopy(COMMON_ARG_SPEC))
spec['service'] = dict(type='str', aliases=['svc'])
spec['namespace'] = dict(required=True, type='str')
spec['labels'] = dict(type='dict')
spec['name'] = dict(type='str')
spec['hostname'] = dict(type='str')
spec['path'] = dict(type='str')
spec['wildcard_policy'] = dict(choices=['Subdomain'], type='str')
spec['port'] = dict(type='str')
spec['tls'] = dict(type='dict', options=dict(
ca_certificate=dict(type='str'),
certificate=dict(type='str'),
destination_ca_certificate=dict(type='str'),
key=dict(type='str', no_log=False),
insecure_policy=dict(type='str', choices=['allow', 'redirect', 'disallow'], default='disallow'),
))
spec['termination'] = dict(choices=['edge', 'passthrough', 'reencrypt', 'insecure'], default='insecure')
spec['annotations'] = dict(type='dict')
spec["service"] = dict(type="str", aliases=["svc"])
spec["namespace"] = dict(required=True, type="str")
spec["labels"] = dict(type="dict")
spec["name"] = dict(type="str")
spec["hostname"] = dict(type="str")
spec["path"] = dict(type="str")
spec["wildcard_policy"] = dict(choices=["Subdomain"], type="str")
spec["port"] = dict(type="str")
spec["tls"] = dict(
type="dict",
options=dict(
ca_certificate=dict(type="str"),
certificate=dict(type="str"),
destination_ca_certificate=dict(type="str"),
key=dict(type="str", no_log=False),
insecure_policy=dict(
type="str",
choices=["allow", "redirect", "disallow"],
default="disallow",
),
),
)
spec["termination"] = dict(
choices=["edge", "passthrough", "reencrypt", "insecure"], default="insecure"
)
spec["annotations"] = dict(type="dict")
return spec
def execute_module(self):
service_name = self.params.get('service')
namespace = self.params['namespace']
termination_type = self.params.get('termination')
if termination_type == 'insecure':
service_name = self.params.get("service")
namespace = self.params["namespace"]
termination_type = self.params.get("termination")
if termination_type == "insecure":
termination_type = None
state = self.params.get('state')
state = self.params.get("state")
if state != 'absent' and not service_name:
if state != "absent" and not service_name:
self.fail_json("If 'state' is not 'absent' then 'service' must be provided")
# We need to do something a little wonky to wait if the user doesn't supply a custom condition
custom_wait = self.params.get('wait') and not self.params.get('wait_condition') and state != 'absent'
custom_wait = (
self.params.get("wait")
and not self.params.get("wait_condition")
and state != "absent"
)
if custom_wait:
# Don't use default wait logic in perform_action
self.params['wait'] = False
self.params["wait"] = False
route_name = self.params.get('name') or service_name
labels = self.params.get('labels')
hostname = self.params.get('hostname')
path = self.params.get('path')
wildcard_policy = self.params.get('wildcard_policy')
port = self.params.get('port')
annotations = self.params.get('annotations')
route_name = self.params.get("name") or service_name
labels = self.params.get("labels")
hostname = self.params.get("hostname")
path = self.params.get("path")
wildcard_policy = self.params.get("wildcard_policy")
port = self.params.get("port")
annotations = self.params.get("annotations")
if termination_type and self.params.get('tls'):
tls_ca_cert = self.params['tls'].get('ca_certificate')
tls_cert = self.params['tls'].get('certificate')
tls_dest_ca_cert = self.params['tls'].get('destination_ca_certificate')
tls_key = self.params['tls'].get('key')
tls_insecure_policy = self.params['tls'].get('insecure_policy')
if tls_insecure_policy == 'disallow':
if termination_type and self.params.get("tls"):
tls_ca_cert = self.params["tls"].get("ca_certificate")
tls_cert = self.params["tls"].get("certificate")
tls_dest_ca_cert = self.params["tls"].get("destination_ca_certificate")
tls_key = self.params["tls"].get("key")
tls_insecure_policy = self.params["tls"].get("insecure_policy")
if tls_insecure_policy == "disallow":
tls_insecure_policy = None
else:
tls_ca_cert = tls_cert = tls_dest_ca_cert = tls_key = tls_insecure_policy = None
tls_ca_cert = (
tls_cert
) = tls_dest_ca_cert = tls_key = tls_insecure_policy = None
route = {
'apiVersion': 'route.openshift.io/v1',
'kind': 'Route',
'metadata': {
'name': route_name,
'namespace': namespace,
'labels': labels,
"apiVersion": "route.openshift.io/v1",
"kind": "Route",
"metadata": {
"name": route_name,
"namespace": namespace,
"labels": labels,
},
'spec': {}
"spec": {},
}
if annotations:
route['metadata']['annotations'] = annotations
route["metadata"]["annotations"] = annotations
if state != 'absent':
route['spec'] = self.build_route_spec(
service_name, namespace,
if state != "absent":
route["spec"] = self.build_route_spec(
service_name,
namespace,
port=port,
wildcard_policy=wildcard_policy,
hostname=hostname,
@@ -434,79 +456,120 @@ class OpenShiftRoute(AnsibleOpenshiftModule):
)
result = perform_action(self.svc, route, self.params)
timeout = self.params.get('wait_timeout')
sleep = self.params.get('wait_sleep')
timeout = self.params.get("wait_timeout")
sleep = self.params.get("wait_sleep")
if custom_wait:
v1_routes = self.find_resource('Route', 'route.openshift.io/v1', fail=True)
v1_routes = self.find_resource("Route", "route.openshift.io/v1", fail=True)
waiter = Waiter(self.client, v1_routes, wait_predicate)
success, result['result'], result['duration'] = waiter.wait(timeout=timeout, sleep=sleep, name=route_name, namespace=namespace)
success, result["result"], result["duration"] = waiter.wait(
timeout=timeout, sleep=sleep, name=route_name, namespace=namespace
)
self.exit_json(**result)
def build_route_spec(self, service_name, namespace, port=None, wildcard_policy=None, hostname=None, path=None, termination_type=None,
tls_insecure_policy=None, tls_ca_cert=None, tls_cert=None, tls_key=None, tls_dest_ca_cert=None):
v1_services = self.find_resource('Service', 'v1', fail=True)
def build_route_spec(
self,
service_name,
namespace,
port=None,
wildcard_policy=None,
hostname=None,
path=None,
termination_type=None,
tls_insecure_policy=None,
tls_ca_cert=None,
tls_cert=None,
tls_key=None,
tls_dest_ca_cert=None,
):
v1_services = self.find_resource("Service", "v1", fail=True)
try:
target_service = v1_services.get(name=service_name, namespace=namespace)
except NotFoundError:
if not port:
self.fail_json(msg="You need to provide the 'port' argument when exposing a non-existent service")
self.fail_json(
msg="You need to provide the 'port' argument when exposing a non-existent service"
)
target_service = None
except DynamicApiError as exc:
self.fail_json(msg='Failed to retrieve service to be exposed: {0}'.format(exc.body),
error=exc.status, status=exc.status, reason=exc.reason)
self.fail_json(
msg="Failed to retrieve service to be exposed: {0}".format(exc.body),
error=exc.status,
status=exc.status,
reason=exc.reason,
)
except Exception as exc:
self.fail_json(msg='Failed to retrieve service to be exposed: {0}'.format(to_native(exc)),
error='', status='', reason='')
self.fail_json(
msg="Failed to retrieve service to be exposed: {0}".format(
to_native(exc)
),
error="",
status="",
reason="",
)
route_spec = {
'tls': {},
'to': {
'kind': 'Service',
'name': service_name,
"tls": {},
"to": {
"kind": "Service",
"name": service_name,
},
'port': {
'targetPort': self.set_port(target_service, port),
"port": {
"targetPort": self.set_port(target_service, port),
},
'wildcardPolicy': wildcard_policy
"wildcardPolicy": wildcard_policy,
}
# Want to conditionally add these so we don't overwrite what is automically added when nothing is provided
if termination_type:
route_spec['tls'] = dict(termination=termination_type.capitalize())
route_spec["tls"] = dict(termination=termination_type.capitalize())
if tls_insecure_policy:
if termination_type == 'edge':
route_spec['tls']['insecureEdgeTerminationPolicy'] = tls_insecure_policy.capitalize()
elif termination_type == 'passthrough':
if tls_insecure_policy != 'redirect':
self.fail_json("'redirect' is the only supported insecureEdgeTerminationPolicy for passthrough routes")
route_spec['tls']['insecureEdgeTerminationPolicy'] = tls_insecure_policy.capitalize()
elif termination_type == 'reencrypt':
self.fail_json("'tls.insecure_policy' is not supported with reencrypt routes")
if termination_type == "edge":
route_spec["tls"][
"insecureEdgeTerminationPolicy"
] = tls_insecure_policy.capitalize()
elif termination_type == "passthrough":
if tls_insecure_policy != "redirect":
self.fail_json(
"'redirect' is the only supported insecureEdgeTerminationPolicy for passthrough routes"
)
route_spec["tls"][
"insecureEdgeTerminationPolicy"
] = tls_insecure_policy.capitalize()
elif termination_type == "reencrypt":
self.fail_json(
"'tls.insecure_policy' is not supported with reencrypt routes"
)
else:
route_spec['tls']['insecureEdgeTerminationPolicy'] = None
route_spec["tls"]["insecureEdgeTerminationPolicy"] = None
if tls_ca_cert:
if termination_type == 'passthrough':
self.fail_json("'tls.ca_certificate' is not supported with passthrough routes")
route_spec['tls']['caCertificate'] = tls_ca_cert
if termination_type == "passthrough":
self.fail_json(
"'tls.ca_certificate' is not supported with passthrough routes"
)
route_spec["tls"]["caCertificate"] = tls_ca_cert
if tls_cert:
if termination_type == 'passthrough':
self.fail_json("'tls.certificate' is not supported with passthrough routes")
route_spec['tls']['certificate'] = tls_cert
if termination_type == "passthrough":
self.fail_json(
"'tls.certificate' is not supported with passthrough routes"
)
route_spec["tls"]["certificate"] = tls_cert
if tls_key:
if termination_type == 'passthrough':
if termination_type == "passthrough":
self.fail_json("'tls.key' is not supported with passthrough routes")
route_spec['tls']['key'] = tls_key
route_spec["tls"]["key"] = tls_key
if tls_dest_ca_cert:
if termination_type != 'reencrypt':
self.fail_json("'destination_certificate' is only valid for reencrypt routes")
route_spec['tls']['destinationCACertificate'] = tls_dest_ca_cert
if termination_type != "reencrypt":
self.fail_json(
"'destination_certificate' is only valid for reencrypt routes"
)
route_spec["tls"]["destinationCACertificate"] = tls_dest_ca_cert
else:
route_spec['tls'] = None
route_spec["tls"] = None
if hostname:
route_spec['host'] = hostname
route_spec["host"] = hostname
if path:
route_spec['path'] = path
route_spec["path"] = path
return route_spec
@@ -514,7 +577,7 @@ class OpenShiftRoute(AnsibleOpenshiftModule):
if port_arg:
return port_arg
for p in service.spec.ports:
if p.protocol == 'TCP':
if p.protocol == "TCP":
if p.name is not None:
return p.name
return p.targetPort
@@ -525,7 +588,7 @@ def wait_predicate(route):
if not (route.status and route.status.ingress):
return False
for ingress in route.status.ingress:
match = [x for x in ingress.conditions if x.type == 'Admitted']
match = [x for x in ingress.conditions if x.type == "Admitted"]
if not match:
return False
match = match[0]
@@ -538,5 +601,5 @@ def main():
OpenShiftRoute().run_module()
if __name__ == '__main__':
if __name__ == "__main__":
main()