diff options
Diffstat (limited to 'ansible_collections/community/okd/molecule')
41 files changed, 4517 insertions, 0 deletions
diff --git a/ansible_collections/community/okd/molecule/default/README.md b/ansible_collections/community/okd/molecule/default/README.md new file mode 100644 index 000000000..153dfa515 --- /dev/null +++ b/ansible_collections/community/okd/molecule/default/README.md @@ -0,0 +1,19 @@ +Wait tests +---------- + +wait tests require at least one node, and don't work on the normal k8s +openshift-origin container as provided by ansible-test --docker -v k8s + +minikube, Kubernetes from Docker or any other Kubernetes service will +suffice. + +If kubectl is already using the right config file and context, you can +just do + +``` +cd tests/integration/targets/okd +./runme.sh -vv +``` + +otherwise set one or both of `K8S_AUTH_KUBECONFIG` and `K8S_AUTH_CONTEXT` +and use the same command diff --git a/ansible_collections/community/okd/molecule/default/converge.yml b/ansible_collections/community/okd/molecule/default/converge.yml new file mode 100644 index 000000000..7fe9e8209 --- /dev/null +++ b/ansible_collections/community/okd/molecule/default/converge.yml @@ -0,0 +1,99 @@ +--- +- name: Converge + hosts: localhost + connection: local + gather_facts: no + vars: + ansible_python_interpreter: '{{ virtualenv_interpreter }}' + vars_files: + - vars/main.yml + tasks: + # OpenShift Resources + - name: Create a project + community.okd.k8s: + name: testing + kind: Project + api_version: project.openshift.io/v1 + apply: no + register: output + + - name: show output + debug: + var: output + + - name: Create deployment config + community.okd.k8s: + state: present + name: hello-world + namespace: testing + definition: '{{ okd_dc_template }}' + wait: yes + wait_condition: + type: Available + status: True + vars: + k8s_pod_name: hello-world + k8s_pod_image: python + k8s_pod_command: + - python + - '-m' + - http.server + k8s_pod_env: + - name: TEST + value: test + okd_dc_triggers: + - type: ConfigChange + register: output + + - name: Show output + debug: + var: output + + - vars: + image: docker.io/python + image_name: python + image_tag: latest + k8s_pod_image: python + k8s_pod_command: + - python + - '-m' + - http.server + namespace: idempotence-testing + block: + - name: Create a namespace + community.okd.k8s: + name: '{{ namespace }}' + kind: Namespace + api_version: v1 + + - name: Create imagestream + community.okd.k8s: + namespace: '{{ namespace }}' + definition: '{{ okd_imagestream_template }}' + + - name: Create DeploymentConfig to reference ImageStream + community.okd.k8s: + name: '{{ k8s_pod_name }}' + namespace: '{{ namespace }}' + definition: '{{ okd_dc_template }}' + vars: + k8s_pod_name: is-idempotent-dc + + - name: Create Deployment to reference ImageStream + community.okd.k8s: + name: '{{ k8s_pod_name }}' + namespace: '{{ namespace }}' + definition: '{{ k8s_deployment_template | combine(metadata) }}' + vars: + k8s_pod_annotations: + "alpha.image.policy.openshift.io/resolve-names": "*" + k8s_pod_name: is-idempotent-deployment + annotation: + - from: + kind: ImageStreamTag + name: "{{ image_name }}:{{ image_tag}}}" + fieldPath: 'spec.template.spec.containers[?(@.name=="{{ k8s_pod_name }}")].image}' + metadata: + metadata: + annotations: + image.openshift.io/triggers: '{{ annotation | to_json }}' diff --git a/ansible_collections/community/okd/molecule/default/destroy.yml b/ansible_collections/community/okd/molecule/default/destroy.yml new file mode 100644 index 000000000..0bd583e1c --- /dev/null +++ b/ansible_collections/community/okd/molecule/default/destroy.yml @@ -0,0 +1,6 @@ +--- +- name: Destroy + hosts: localhost + connection: local + gather_facts: no + tasks: [] diff --git a/ansible_collections/community/okd/molecule/default/files/crd-resource.yml b/ansible_collections/community/okd/molecule/default/files/crd-resource.yml new file mode 100644 index 000000000..23d0663c3 --- /dev/null +++ b/ansible_collections/community/okd/molecule/default/files/crd-resource.yml @@ -0,0 +1,21 @@ +--- +apiVersion: certmanager.k8s.io/v1alpha1 +kind: Certificate +metadata: + name: acme-crt +spec: + secretName: acme-crt-secret + dnsNames: + - foo.example.com + - bar.example.com + acme: + config: + - ingressClass: nginx + domains: + - foo.example.com + - bar.example.com + issuerRef: + name: letsencrypt-prod + # We can reference ClusterIssuers by changing the kind here. + # The default value is Issuer (i.e. a locally namespaced Issuer) + kind: Issuer diff --git a/ansible_collections/community/okd/molecule/default/files/example.env b/ansible_collections/community/okd/molecule/default/files/example.env new file mode 100644 index 000000000..f98f7d9ee --- /dev/null +++ b/ansible_collections/community/okd/molecule/default/files/example.env @@ -0,0 +1,9 @@ +# +NAME=example +# Multiline values shouldn't break things +export CONTENT=This is a long message\ + that may take one or more lines to parse\ + but should still work without issue + +# This shouldn't throw an error +UNUSED= diff --git a/ansible_collections/community/okd/molecule/default/files/kuard-extra-property.yml b/ansible_collections/community/okd/molecule/default/files/kuard-extra-property.yml new file mode 100644 index 000000000..1da160b33 --- /dev/null +++ b/ansible_collections/community/okd/molecule/default/files/kuard-extra-property.yml @@ -0,0 +1,22 @@ +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + labels: + app: kuard + name: kuard + namespace: default +spec: + replicas: 3 + selector: + matchLabels: + app: kuard + unwanted: value + template: + metadata: + labels: + app: kuard + spec: + containers: + - image: gcr.io/kuar-demo/kuard-amd64:1 + name: kuard diff --git a/ansible_collections/community/okd/molecule/default/files/kuard-invalid-type.yml b/ansible_collections/community/okd/molecule/default/files/kuard-invalid-type.yml new file mode 100644 index 000000000..6ff8018ef --- /dev/null +++ b/ansible_collections/community/okd/molecule/default/files/kuard-invalid-type.yml @@ -0,0 +1,21 @@ +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + labels: + app: kuard + name: kuard + namespace: default +spec: + replicas: hello + selector: + matchLabels: + app: kuard + template: + metadata: + labels: + app: kuard + spec: + containers: + - image: gcr.io/kuar-demo/kuard-amd64:1 + name: kuard diff --git a/ansible_collections/community/okd/molecule/default/files/nginx.env b/ansible_collections/community/okd/molecule/default/files/nginx.env new file mode 100644 index 000000000..939ad0d7f --- /dev/null +++ b/ansible_collections/community/okd/molecule/default/files/nginx.env @@ -0,0 +1,12 @@ +# Want to make sure comments don't break it +export NAME=test123 +NAMESPACE=openshift + + + + +# Blank lines should be fine too + +# Equals in comments shouldn't break things=True +MEMORY_LIMIT=1Gi + diff --git a/ansible_collections/community/okd/molecule/default/files/pod-template.yaml b/ansible_collections/community/okd/molecule/default/files/pod-template.yaml new file mode 100644 index 000000000..ac388ad67 --- /dev/null +++ b/ansible_collections/community/okd/molecule/default/files/pod-template.yaml @@ -0,0 +1,23 @@ +--- +kind: Template +apiVersion: template.openshift.io/v1 +metadata: + name: pod-template +objects: + - apiVersion: v1 + kind: Pod + metadata: + name: "Pod-${{ NAME }}" + spec: + containers: + - args: + - /bin/sh + - -c + - while true; do echo $(date); sleep 15; done + image: python:3.7-alpine + imagePullPolicy: Always + name: python +parameters: + - name: NAME + description: trailing name of the pod + required: true diff --git a/ansible_collections/community/okd/molecule/default/files/setup-crd.yml b/ansible_collections/community/okd/molecule/default/files/setup-crd.yml new file mode 100644 index 000000000..15debdbdd --- /dev/null +++ b/ansible_collections/community/okd/molecule/default/files/setup-crd.yml @@ -0,0 +1,53 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + name: certificates.certmanager.k8s.io + annotations: + "api-approved.kubernetes.io": "https://github.com/kubernetes/kubernetes/pull/78458" +spec: + group: certmanager.k8s.io + versions: + - name: v1alpha1 + served: true + storage: true + schema: + openAPIV3Schema: + type: object + properties: + certificate: + type: string + secretName: + type: string + dnsNames: + type: array + items: + type: string + acme: + type: object + properties: + config: + type: array + items: + type: object + properties: + ingressClass: + type: string + domains: + type: array + items: + type: string + issuerRef: + type: object + properties: + name: + type: string + kind: + type: string + scope: Namespaced + names: + kind: Certificate + plural: certificates + shortNames: + - cert + - certs diff --git a/ansible_collections/community/okd/molecule/default/files/simple-template.yaml b/ansible_collections/community/okd/molecule/default/files/simple-template.yaml new file mode 100644 index 000000000..29c85b9cd --- /dev/null +++ b/ansible_collections/community/okd/molecule/default/files/simple-template.yaml @@ -0,0 +1,34 @@ +--- +apiVersion: template.openshift.io/v1 +kind: Template +labels: + template: simple-example-test +message: |- + The following configmaps have been created in your project: ${NAME}. +metadata: + annotations: + description: A super basic template for testing + openshift.io/display-name: Super basic template + openshift.io/provider-display-name: Red Hat, Inc. + tags: quickstart,examples + name: simple-example +objects: +- apiVersion: v1 + kind: ConfigMap + metadata: + annotations: + description: Big example + name: ${NAME} + data: + content: "${CONTENT}" +parameters: +- description: The name assigned to the ConfigMap + displayName: Name + name: NAME + required: true + value: example +- description: The value for the content key of the configmap + displayName: Content + name: CONTENT + required: true + value: '' diff --git a/ansible_collections/community/okd/molecule/default/molecule.yml b/ansible_collections/community/okd/molecule/default/molecule.yml new file mode 100644 index 000000000..43407bd26 --- /dev/null +++ b/ansible_collections/community/okd/molecule/default/molecule.yml @@ -0,0 +1,49 @@ +--- +dependency: + name: galaxy + options: + requirements-file: requirements.yml +driver: + name: delegated +platforms: + - name: cluster + groups: + - k8s +provisioner: + name: ansible + log: true + options: + vvv: True + config_options: + inventory: + enable_plugins: community.okd.openshift + lint: | + set -e + ansible-lint + inventory: + hosts: + plugin: community.okd.openshift + host_vars: + localhost: + virtualenv: ${MOLECULE_EPHEMERAL_DIRECTORY}/virtualenv + virtualenv_command: '{{ ansible_playbook_python }} -m virtualenv' + virtualenv_interpreter: '{{ virtualenv }}/bin/python' + playbook_namespace: molecule-tests + env: + ANSIBLE_FORCE_COLOR: 'true' + ANSIBLE_COLLECTIONS_PATHS: ${OVERRIDE_COLLECTION_PATH:-$MOLECULE_PROJECT_DIRECTORY} +verifier: + name: ansible + lint: | + set -e + ansible-lint +scenario: + name: default + test_sequence: + - dependency + - lint + - syntax + - prepare + - converge + - idempotence + - verify diff --git a/ansible_collections/community/okd/molecule/default/prepare.yml b/ansible_collections/community/okd/molecule/default/prepare.yml new file mode 100644 index 000000000..f155ec1d4 --- /dev/null +++ b/ansible_collections/community/okd/molecule/default/prepare.yml @@ -0,0 +1,61 @@ +--- +- name: Prepare + hosts: localhost + connection: local + gather_facts: no + + tasks: + - pip: + name: virtualenv + + - pip: + name: + - kubernetes>=12.0.0 + - coverage + - python-ldap + virtualenv: "{{ virtualenv }}" + virtualenv_command: "{{ virtualenv_command }}" + virtualenv_site_packages: no + + - name: 'Configure htpasswd secret (username: test, password: testing123)' + community.okd.k8s: + definition: + apiVersion: v1 + kind: Secret + metadata: + name: htpass-secret + namespace: openshift-config + stringData: + htpasswd: "test:$2y$05$zgjczyp96jCIp//CGmnWiefhd7G3l54IdsZoV4IwA1UWtd04L0lE2" + + - name: Configure htpasswd identity provider + community.okd.k8s: + definition: + apiVersion: config.openshift.io/v1 + kind: OAuth + metadata: + name: cluster + spec: + identityProviders: + - name: htpasswd_provider + mappingMethod: claim + type: HTPasswd + htpasswd: + fileData: + name: htpass-secret + + - name: Create ClusterRoleBinding for test user + community.okd.k8s: + definition: + apiVersion: rbac.authorization.k8s.io/v1 + kind: ClusterRoleBinding + metadata: + name: test-cluster-reader + roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: cluster-admin + subjects: + - apiGroup: rbac.authorization.k8s.io + kind: User + name: test diff --git a/ansible_collections/community/okd/molecule/default/roles/openshift_adm_groups/defaults/main.yml b/ansible_collections/community/okd/molecule/default/roles/openshift_adm_groups/defaults/main.yml new file mode 100644 index 000000000..b58e2d3ce --- /dev/null +++ b/ansible_collections/community/okd/molecule/default/roles/openshift_adm_groups/defaults/main.yml @@ -0,0 +1,4 @@ +--- +ldap_admin_user: "admin" +ldap_admin_password: "testing123!" +ldap_root: "dc=ansible,dc=redhat"
\ No newline at end of file diff --git a/ansible_collections/community/okd/molecule/default/roles/openshift_adm_groups/library/openshift_ldap_entry.py b/ansible_collections/community/okd/molecule/default/roles/openshift_adm_groups/library/openshift_ldap_entry.py new file mode 100644 index 000000000..6f5ca4b24 --- /dev/null +++ b/ansible_collections/community/okd/molecule/default/roles/openshift_adm_groups/library/openshift_ldap_entry.py @@ -0,0 +1,186 @@ +# 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: openshift_ldap_entry + +short_description: add/remove entry to LDAP Server. + +author: + - Aubin Bikouo (@abikouo) + +description: + - This module perform basic operations on the LDAP Server (add/remove entries). + - Similar to `community.general.ldap_entry` this has been created to avoid dependency with this collection for the test. + - This module is not supported outside of testing this collection. + +options: + attributes: + description: + - If I(state=present), attributes necessary to create an entry. Existing + entries are never modified. To assert specific attribute values on an + existing entry, use M(community.general.ldap_attrs) module instead. + type: dict + objectClass: + description: + - If I(state=present), value or list of values to use when creating + the entry. It can either be a string or an actual list of + strings. + type: list + elements: str + state: + description: + - The target state of the entry. + choices: [present, absent] + default: present + type: str + bind_dn: + description: + - A DN to bind with. If this is omitted, we'll try a SASL bind with the EXTERNAL mechanism as default. + - If this is blank, we'll use an anonymous bind. + type: str + required: true + bind_pw: + description: + - The password to use with I(bind_dn). + type: str + dn: + required: true + description: + - The DN of the entry to add or remove. + type: str + server_uri: + description: + - A URI to the LDAP server. + - The default value lets the underlying LDAP client library look for a UNIX domain socket in its default location. + type: str + default: ldapi:/// + +requirements: + - python-ldap +''' + +EXAMPLES = r''' +''' + + +RETURN = r''' +# Default return values +''' + +import traceback + +from ansible.module_utils.basic import AnsibleModule, missing_required_lib +from ansible.module_utils.common.text.converters import to_native, to_bytes + +LDAP_IMP_ERR = None +try: + import ldap + import ldap.modlist + + HAS_LDAP = True +except ImportError: + LDAP_IMP_ERR = traceback.format_exc() + HAS_LDAP = False + + +def argument_spec(): + args = {} + args['attributes'] = dict(default={}, type='dict') + args['objectClass'] = dict(type='list', elements='str') + args['state'] = dict(default='present', choices=['present', 'absent']) + args['bind_dn'] = dict(required=True) + args['bind_pw'] = dict(default='', no_log=True) + args['dn'] = dict(required=True) + args['server_uri'] = dict(default='ldapi:///') + return args + + +class LdapEntry(AnsibleModule): + def __init__(self): + + AnsibleModule.__init__( + self, + argument_spec=argument_spec(), + required_if=[('state', 'present', ['objectClass'])], + ) + + if not HAS_LDAP: + self.fail_json(msg=missing_required_lib('python-ldap'), exception=LDAP_IMP_ERR) + + self.__connection = None + # Add the objectClass into the list of attributes + self.params['attributes']['objectClass'] = (self.params['objectClass']) + + # Load attributes + if self.params['state'] == 'present': + self.attrs = {} + for name, value in self.params['attributes'].items(): + if isinstance(value, list): + self.attrs[name] = list(map(to_bytes, value)) + else: + self.attrs[name] = [to_bytes(value)] + + @property + def connection(self): + if not self.__connection: + ldap.set_option(ldap.OPT_X_TLS_REQUIRE_CERT, ldap.OPT_X_TLS_NEVER) + self.__connection = ldap.initialize(self.params['server_uri']) + try: + self.__connection.simple_bind_s(self.params['bind_dn'], self.params['bind_pw']) + except ldap.LDAPError as e: + self.fail_json(msg="Cannot bind to the server due to: %s" % e) + return self.__connection + + def add(self): + """ If self.dn does not exist, returns a callable that will add it. """ + changed = False + msg = "LDAP Entry '%s' already exist." % self.params["dn"] + if not self._is_entry_present(): + modlist = ldap.modlist.addModlist(self.attrs) + self.connection.add_s(self.params['dn'], modlist) + changed = True + msg = "LDAP Entry '%s' successfully created." % self.params["dn"] + self.exit_json(changed=changed, msg=msg) + + def delete(self): + """ If self.dn exists, returns a callable that will delete it. """ + changed = False + msg = "LDAP Entry '%s' does not exist." % self.params["dn"] + if self._is_entry_present(): + self.connection.delete_s(self.params['dn']) + changed = True + msg = "LDAP Entry '%s' successfully deleted." % self.params["dn"] + self.exit_json(changed=changed, msg=msg) + + def _is_entry_present(self): + try: + self.connection.search_s(self.params['dn'], ldap.SCOPE_BASE) + except ldap.NO_SUCH_OBJECT: + is_present = False + else: + is_present = True + + return is_present + + def execute(self): + try: + if self.params['state'] == 'present': + self.add() + else: + self.delete() + except Exception as e: + self.fail_json(msg="Entry action failed.", details=to_native(e), exception=traceback.format_exc()) + + +def main(): + module = LdapEntry() + module.execute() + + +if __name__ == '__main__': + main() diff --git a/ansible_collections/community/okd/molecule/default/roles/openshift_adm_groups/library/openshift_ldap_entry_info.py b/ansible_collections/community/okd/molecule/default/roles/openshift_adm_groups/library/openshift_ldap_entry_info.py new file mode 100644 index 000000000..ba49f724d --- /dev/null +++ b/ansible_collections/community/okd/molecule/default/roles/openshift_adm_groups/library/openshift_ldap_entry_info.py @@ -0,0 +1,109 @@ +# 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: openshift_ldap_entry_info + +short_description: Validate entry from LDAP server. + +author: + - Aubin Bikouo (@abikouo) + +description: + - This module connect to a ldap server and search for entry. + - This module is not supported outside of testing this collection. + +options: + bind_dn: + description: + - A DN to bind with. If this is omitted, we'll try a SASL bind with the EXTERNAL mechanism as default. + - If this is blank, we'll use an anonymous bind. + type: str + required: true + bind_pw: + description: + - The password to use with I(bind_dn). + type: str + required: True + dn: + description: + - The DN of the entry to test. + type: str + required: True + server_uri: + description: + - A URI to the LDAP server. + - The default value lets the underlying LDAP client library look for a UNIX domain socket in its default location. + type: str + default: ldapi:/// + required: True + +requirements: + - python-ldap +''' + +EXAMPLES = r''' +''' + + +RETURN = r''' +# Default return values +''' + +import traceback + +from ansible.module_utils.basic import AnsibleModule, missing_required_lib + +LDAP_IMP_ERR = None +try: + import ldap + import ldap.modlist + HAS_LDAP = True +except ImportError: + LDAP_IMP_ERR = traceback.format_exc() + HAS_LDAP = False + + +def argument_spec(): + args = {} + args['bind_dn'] = dict(required=True) + args['bind_pw'] = dict(required=True, no_log=True) + args['dn'] = dict(required=True) + args['server_uri'] = dict(required=True) + return args + + +def execute(): + module = AnsibleModule( + argument_spec=argument_spec(), + supports_check_mode=True + ) + + if not HAS_LDAP: + module.fail_json(msg=missing_required_lib("python-ldap"), exception=LDAP_IMP_ERR) + + ldap.set_option(ldap.OPT_X_TLS_REQUIRE_CERT, ldap.OPT_X_TLS_NEVER) + connection = ldap.initialize(module.params['server_uri']) + try: + connection.simple_bind_s(module.params['bind_dn'], module.params['bind_pw']) + except ldap.LDAPError as e: + module.fail_json(msg="Cannot bind to the server due to: %s" % e) + + try: + connection.search_s(module.params['dn'], ldap.SCOPE_BASE) + module.exit_json(changed=False, found=True) + except ldap.NO_SUCH_OBJECT: + module.exit_json(changed=False, found=False) + + +def main(): + execute() + + +if __name__ == '__main__': + main() diff --git a/ansible_collections/community/okd/molecule/default/roles/openshift_adm_groups/meta/main.yml b/ansible_collections/community/okd/molecule/default/roles/openshift_adm_groups/meta/main.yml new file mode 100644 index 000000000..eef26f23d --- /dev/null +++ b/ansible_collections/community/okd/molecule/default/roles/openshift_adm_groups/meta/main.yml @@ -0,0 +1,4 @@ +--- +collections: + - community.okd + - kubernetes.core
\ No newline at end of file diff --git a/ansible_collections/community/okd/molecule/default/roles/openshift_adm_groups/tasks/activeDirectory.yml b/ansible_collections/community/okd/molecule/default/roles/openshift_adm_groups/tasks/activeDirectory.yml new file mode 100644 index 000000000..da99f324e --- /dev/null +++ b/ansible_collections/community/okd/molecule/default/roles/openshift_adm_groups/tasks/activeDirectory.yml @@ -0,0 +1,235 @@ +- block: + - name: Get LDAP definition + set_fact: + ldap_entries: "{{ lookup('template', 'ad/definition.j2') | from_yaml }}" + + - name: Delete openshift groups if existing + community.okd.k8s: + state: absent + kind: Group + version: "user.openshift.io/v1" + name: "{{ item }}" + with_items: + - admins + - developers + + - name: Delete existing LDAP Entries + openshift_ldap_entry: + bind_dn: "{{ ldap_bind_dn }}" + bind_pw: "{{ ldap_bind_pw }}" + server_uri: "{{ ldap_server_uri }}" + dn: "{{ item.dn }}" + state: absent + with_items: "{{ ldap_entries.users + ldap_entries.units | reverse | list }}" + + - name: Create LDAP Entries + openshift_ldap_entry: + bind_dn: "{{ ldap_bind_dn }}" + bind_pw: "{{ ldap_bind_pw }}" + server_uri: "{{ ldap_server_uri }}" + dn: "{{ item.dn }}" + attributes: "{{ item.attr }}" + objectClass: "{{ item.class }}" + with_items: "{{ ldap_entries.units + ldap_entries.users }}" + + - name: Load test configurations + set_fact: + sync_config: "{{ lookup('template', 'ad/sync-config.j2') | from_yaml }}" + + - name: Synchronize Groups + community.okd.openshift_adm_groups_sync: + config: "{{ sync_config }}" + check_mode: yes + register: result + + - name: Validate Group going to be created + assert: + that: + - result is changed + - admins_group + - devs_group + - '"jane.smith@ansible.org" in {{ admins_group.users }}' + - '"jim.adams@ansible.org" in {{ admins_group.users }}' + - '"jordanbulls@ansible.org" in {{ devs_group.users }}' + - admins_group.users | length == 2 + - devs_group.users | length == 1 + vars: + admins_group: "{{ result.groups | selectattr('metadata.name', 'equalto', 'admins') | first }}" + devs_group: "{{ result.groups | selectattr('metadata.name', 'equalto', 'developers') | first }}" + + + - name: Synchronize Groups (Remove check_mode) + community.okd.openshift_adm_groups_sync: + config: "{{ sync_config }}" + register: result + + - name: Validate Group going to be created + assert: + that: + - result is changed + + - name: Read admins group + kubernetes.core.k8s_info: + kind: Group + version: "user.openshift.io/v1" + name: admins + register: result + + - name: Validate group was created + assert: + that: + - result.resources | length == 1 + - '"jane.smith@ansible.org" in {{ result.resources.0.users }}' + - '"jim.adams@ansible.org" in {{ result.resources.0.users }}' + + - name: Read developers group + kubernetes.core.k8s_info: + kind: Group + version: "user.openshift.io/v1" + name: developers + register: result + + - name: Validate group was created + assert: + that: + - result.resources | length == 1 + - '"jordanbulls@ansible.org" in {{ result.resources.0.users }}' + + - name: Define user dn to delete + set_fact: + user_to_delete: "cn=Jane,ou=engineers,ou=activeD,{{ ldap_root }}" + + - name: Delete 1 admin user + openshift_ldap_entry: + bind_dn: "{{ ldap_bind_dn }}" + bind_pw: "{{ ldap_bind_pw }}" + server_uri: "{{ ldap_server_uri }}" + dn: "{{ user_to_delete }}" + state: absent + + - name: Synchronize Openshift groups using allow_groups + community.okd.openshift_adm_groups_sync: + config: "{{ sync_config }}" + allow_groups: + - developers + type: openshift + register: openshift_sync + + - name: Validate that only developers group was sync + assert: + that: + - openshift_sync is changed + - openshift_sync.groups | length == 1 + - openshift_sync.groups.0.metadata.name == "developers" + + - name: Read admins group + kubernetes.core.k8s_info: + kind: Group + version: "user.openshift.io/v1" + name: admins + register: result + + - name: Validate admins group content has not changed + assert: + that: + - result.resources | length == 1 + - '"jane.smith@ansible.org" in {{ result.resources.0.users }}' + - '"jim.adams@ansible.org" in {{ result.resources.0.users }}' + + - name: Synchronize Openshift groups using deny_groups + community.okd.openshift_adm_groups_sync: + config: "{{ sync_config }}" + deny_groups: + - developers + type: openshift + register: openshift_sync + + - name: Validate that only admins group was sync + assert: + that: + - openshift_sync is changed + - openshift_sync.groups | length == 1 + - openshift_sync.groups.0.metadata.name == "admins" + + - name: Read admins group + kubernetes.core.k8s_info: + kind: Group + version: "user.openshift.io/v1" + name: admins + register: result + + - name: Validate admins group contains only 1 user now + assert: + that: + - result.resources | length == 1 + - result.resources.0.users == ["jim.adams@ansible.org"] + + - name: Set users to delete (delete all developers users) + set_fact: + user_to_delete: "cn=Jordan,ou=engineers,ou=activeD,{{ ldap_root }}" + + - name: Delete 1 admin user + openshift_ldap_entry: + bind_dn: "{{ ldap_bind_dn }}" + bind_pw: "{{ ldap_bind_pw }}" + server_uri: "{{ ldap_server_uri }}" + dn: "{{ user_to_delete }}" + state: absent + + - name: Prune groups + community.okd.openshift_adm_groups_sync: + config: "{{ sync_config }}" + state: absent + register: result + + - name: Validate result is changed (only developers group be deleted) + assert: + that: + - result is changed + - result.groups | length == 1 + + - name: Get developers group info + kubernetes.core.k8s_info: + kind: Group + version: "user.openshift.io/v1" + name: developers + register: result + + - name: assert group was deleted + assert: + that: + - result.resources | length == 0 + + - name: Get admins group info + kubernetes.core.k8s_info: + kind: Group + version: "user.openshift.io/v1" + name: admins + register: result + + - name: assert group was not deleted + assert: + that: + - result.resources | length == 1 + + - name: Prune groups once again (idempotency) + community.okd.openshift_adm_groups_sync: + config: "{{ sync_config }}" + state: absent + register: result + + - name: Assert nothing was changed + assert: + that: + - result is not changed + + always: + - name: Delete openshift groups if existing + community.okd.k8s: + state: absent + kind: Group + version: "user.openshift.io/v1" + name: "{{ item }}" + with_items: + - admins + - developers diff --git a/ansible_collections/community/okd/molecule/default/roles/openshift_adm_groups/tasks/augmentedActiveDirectory.yml b/ansible_collections/community/okd/molecule/default/roles/openshift_adm_groups/tasks/augmentedActiveDirectory.yml new file mode 100644 index 000000000..f70d3bd8e --- /dev/null +++ b/ansible_collections/community/okd/molecule/default/roles/openshift_adm_groups/tasks/augmentedActiveDirectory.yml @@ -0,0 +1,174 @@ +- block: + - name: Get LDAP definition + set_fact: + ldap_entries: "{{ lookup('template', 'augmented-ad/definition.j2') | from_yaml }}" + + - name: Delete openshift groups if existing + community.okd.k8s: + state: absent + kind: Group + version: "user.openshift.io/v1" + name: "{{ item }}" + with_items: + - banking + - insurance + + - name: Delete existing LDAP entries + openshift_ldap_entry: + bind_dn: "{{ ldap_bind_dn }}" + bind_pw: "{{ ldap_bind_pw }}" + server_uri: "{{ ldap_server_uri }}" + dn: "{{ item.dn }}" + state: absent + with_items: "{{ ldap_entries.users + ldap_entries.groups + ldap_entries.units | reverse | list }}" + + - name: Create LDAP Entries + openshift_ldap_entry: + bind_dn: "{{ ldap_bind_dn }}" + bind_pw: "{{ ldap_bind_pw }}" + server_uri: "{{ ldap_server_uri }}" + dn: "{{ item.dn }}" + attributes: "{{ item.attr }}" + objectClass: "{{ item.class }}" + with_items: "{{ ldap_entries.units + ldap_entries.groups + ldap_entries.users }}" + + - name: Load test configurations + set_fact: + sync_config: "{{ lookup('template', 'augmented-ad/sync-config.j2') | from_yaml }}" + + - name: Synchronize Groups + community.okd.openshift_adm_groups_sync: + config: "{{ sync_config }}" + check_mode: yes + register: result + + - name: Validate that 'banking' and 'insurance' groups were created + assert: + that: + - result is changed + - banking_group + - insurance_group + - '"james-allan@ansible.org" in {{ banking_group.users }}' + - '"gordon-kane@ansible.org" in {{ banking_group.users }}' + - '"alice-courtney@ansible.org" in {{ insurance_group.users }}' + - banking_group.users | length == 2 + - insurance_group.users | length == 1 + vars: + banking_group: "{{ result.groups | selectattr('metadata.name', 'equalto', 'banking') | first }}" + insurance_group: "{{ result.groups | selectattr('metadata.name', 'equalto', 'insurance') | first }}" + + + - name: Synchronize Groups (Remove check_mode) + community.okd.openshift_adm_groups_sync: + config: "{{ sync_config }}" + register: result + + - name: Validate Group going to be created + assert: + that: + - result is changed + + - name: Define facts for group to create + set_fact: + ldap_groups: + - name: banking + users: + - "james-allan@ansible.org" + - "gordon-kane@ansible.org" + - name: insurance + users: + - "alice-courtney@ansible.org" + + + - name: Read 'banking' openshift group + kubernetes.core.k8s_info: + kind: Group + version: "user.openshift.io/v1" + name: banking + register: result + + - name: Validate group info + assert: + that: + - result.resources | length == 1 + - '"james-allan@ansible.org" in {{ result.resources.0.users }}' + - '"gordon-kane@ansible.org" in {{ result.resources.0.users }}' + + - name: Read 'insurance' openshift group + kubernetes.core.k8s_info: + kind: Group + version: "user.openshift.io/v1" + name: insurance + register: result + + - name: Validate group info + assert: + that: + - result.resources | length == 1 + - 'result.resources.0.users == ["alice-courtney@ansible.org"]' + + - name: Delete employee from 'insurance' group + openshift_ldap_entry: + bind_dn: "{{ ldap_bind_dn }}" + bind_pw: "{{ ldap_bind_pw }}" + server_uri: "{{ ldap_server_uri }}" + dn: "cn=Alice,ou=employee,ou=augmentedAD,{{ ldap_root }}" + state: absent + + - name: Prune groups + community.okd.openshift_adm_groups_sync: + config: "{{ sync_config }}" + state: absent + register: result + + - name: Validate result is changed (only insurance group be deleted) + assert: + that: + - result is changed + - result.groups | length == 1 + + - name: Get 'insurance' openshift group info + kubernetes.core.k8s_info: + kind: Group + version: "user.openshift.io/v1" + name: insurance + register: result + + - name: assert group was deleted + assert: + that: + - result.resources | length == 0 + + - name: Get 'banking' openshift group info + kubernetes.core.k8s_info: + kind: Group + version: "user.openshift.io/v1" + name: banking + register: result + + - name: assert group was not deleted + assert: + that: + - result.resources | length == 1 + + - name: Prune groups once again (idempotency) + community.okd.openshift_adm_groups_sync: + config: "{{ sync_config }}" + state: absent + register: result + + - name: Assert no change was made + assert: + that: + - result is not changed + + always: + - name: Delete openshift groups if existing + community.okd.k8s: + state: absent + kind: Group + version: "user.openshift.io/v1" + name: "{{ item }}" + with_items: + - banking + - insurance
\ No newline at end of file diff --git a/ansible_collections/community/okd/molecule/default/roles/openshift_adm_groups/tasks/main.yml b/ansible_collections/community/okd/molecule/default/roles/openshift_adm_groups/tasks/main.yml new file mode 100644 index 000000000..88bfd67f8 --- /dev/null +++ b/ansible_collections/community/okd/molecule/default/roles/openshift_adm_groups/tasks/main.yml @@ -0,0 +1,62 @@ +--- +- name: Get cluster information + kubernetes.core.k8s_cluster_info: + register: info + +- name: Create LDAP Pod + community.okd.k8s: + namespace: "default" + wait: yes + definition: + kind: Pod + apiVersion: v1 + metadata: + name: ldap-pod + labels: + app: ldap + spec: + containers: + - name: ldap + image: bitnami/openldap + env: + - name: LDAP_ADMIN_USERNAME + value: "{{ ldap_admin_user }}" + - name: LDAP_ADMIN_PASSWORD + value: "{{ ldap_admin_password }}" + - name: LDAP_USERS + value: "ansible" + - name: LDAP_PASSWORDS + value: "ansible123" + - name: LDAP_ROOT + value: "{{ ldap_root }}" + ports: + - containerPort: 1389 + register: pod_info + +- name: Set Pod Internal IP + set_fact: + podIp: "{{ pod_info.result.status.podIP }}" + +- name: Set LDAP Common facts + set_fact: + ldap_server_uri: "ldap://{{ podIp }}:1389" + ldap_bind_dn: "cn={{ ldap_admin_user }},{{ ldap_root }}" + ldap_bind_pw: "{{ ldap_admin_password }}" + +- name: Display LDAP Server URI + debug: + var: ldap_server_uri + +- name: Test existing user from LDAP server + openshift_ldap_entry_info: + bind_dn: "{{ ldap_bind_dn }}" + bind_pw: "{{ ldap_bind_pw }}" + dn: "ou=users,{{ ldap_root }}" + server_uri: "{{ ldap_server_uri }}" + # ignore_errors: true + # register: ping_ldap + +- include_tasks: "tasks/python-ldap-not-installed.yml" +- include_tasks: "tasks/rfc2307.yml" +- include_tasks: "tasks/activeDirectory.yml" +- include_tasks: "tasks/augmentedActiveDirectory.yml" diff --git a/ansible_collections/community/okd/molecule/default/roles/openshift_adm_groups/tasks/python-ldap-not-installed.yml b/ansible_collections/community/okd/molecule/default/roles/openshift_adm_groups/tasks/python-ldap-not-installed.yml new file mode 100644 index 000000000..a79af51c2 --- /dev/null +++ b/ansible_collections/community/okd/molecule/default/roles/openshift_adm_groups/tasks/python-ldap-not-installed.yml @@ -0,0 +1,42 @@ +- block: + - name: Create temp directory + tempfile: + state: directory + register: test_dir + + - set_fact: + test_dir: "{{ test_dir.path }}" + + - set_fact: + venv: "{{ test_dir }}/virtualenv" + + - pip: + name: + - kubernetes + virtualenv: "{{ venv }}" + virtualenv_command: "{{ virtualenv_command }}" + virtualenv_site_packages: false + + - name: Load test configurations + set_fact: + configs: "{{ lookup('template', 'rfc2307/sync-config.j2') | from_yaml }}" + + - name: Synchronize Groups without python-ldap + community.okd.openshift_adm_groups_sync: + config: "{{ configs.simple }}" + register: result + ignore_errors: true + vars: + ansible_python_interpreter: "{{ venv }}/bin/python" + + - name: Check that module failed gracefully + assert: + that: + - '"Failed to import the required Python library (python-ldap)" in result.msg' + + always: + - name: Remove temp directory + file: + path: "{{ test_dir }}" + state: absent + ignore_errors: true diff --git a/ansible_collections/community/okd/molecule/default/roles/openshift_adm_groups/tasks/rfc2307.yml b/ansible_collections/community/okd/molecule/default/roles/openshift_adm_groups/tasks/rfc2307.yml new file mode 100644 index 000000000..7660bf625 --- /dev/null +++ b/ansible_collections/community/okd/molecule/default/roles/openshift_adm_groups/tasks/rfc2307.yml @@ -0,0 +1,468 @@ +- block: + - name: Get LDAP definition + set_fact: + ldap_resources: "{{ lookup('template', 'rfc2307/definition.j2') | from_yaml }}" + + - name: Delete openshift groups if existing + community.okd.k8s: + state: absent + kind: Group + version: "user.openshift.io/v1" + name: "{{ item }}" + with_items: + - admins + - engineers + - developers + + - name: Delete existing LDAP entries + openshift_ldap_entry: + bind_dn: "{{ ldap_bind_dn }}" + bind_pw: "{{ ldap_bind_pw }}" + server_uri: "{{ ldap_server_uri }}" + dn: "{{ item.dn }}" + state: absent + with_items: "{{ ldap_resources.users + ldap_resources.groups + ldap_resources.units | reverse | list }}" + + - name: Create LDAP units + openshift_ldap_entry: + bind_dn: "{{ ldap_bind_dn }}" + bind_pw: "{{ ldap_bind_pw }}" + server_uri: "{{ ldap_server_uri }}" + dn: "{{ item.dn }}" + attributes: "{{ item.attr }}" + objectClass: "{{ item.class }}" + with_items: "{{ ldap_resources.units }}" + + - name: Create LDAP Groups + openshift_ldap_entry: + bind_dn: "{{ ldap_bind_dn }}" + bind_pw: "{{ ldap_bind_pw }}" + server_uri: "{{ ldap_server_uri }}" + dn: "{{ item.dn }}" + attributes: "{{ item.attr }}" + objectClass: "{{ item.class }}" + with_items: "{{ ldap_resources.groups }}" + + - name: Create LDAP users + openshift_ldap_entry: + bind_dn: "{{ ldap_bind_dn }}" + bind_pw: "{{ ldap_bind_pw }}" + server_uri: "{{ ldap_server_uri }}" + dn: "{{ item.dn }}" + attributes: "{{ item.attr }}" + objectClass: "{{ item.class }}" + with_items: "{{ ldap_resources.users }}" + + - name: Load test configurations + set_fact: + configs: "{{ lookup('template', 'rfc2307/sync-config.j2') | from_yaml }}" + + - name: Synchronize Groups + community.okd.openshift_adm_groups_sync: + config: "{{ configs.simple }}" + check_mode: yes + register: result + + - name: Validate Group going to be created + assert: + that: + - result is changed + - admins_group + - devs_group + - '"jane.smith@ansible.org" in {{ admins_group.users }}' + - '"jim.adams@ansible.org" in {{ devs_group.users }}' + - '"jordanbulls@ansible.org" in {{ devs_group.users }}' + - admins_group.users | length == 1 + - devs_group.users | length == 2 + vars: + admins_group: "{{ result.groups | selectattr('metadata.name', 'equalto', 'admins') | first }}" + devs_group: "{{ result.groups | selectattr('metadata.name', 'equalto', 'developers') | first }}" + + - name: Synchronize Groups - User defined mapping + community.okd.openshift_adm_groups_sync: + config: "{{ configs.user_defined }}" + check_mode: yes + register: result + + - name: Validate Group going to be created + assert: + that: + - result is changed + - admins_group + - devs_group + - '"jane.smith@ansible.org" in {{ admins_group.users }}' + - '"jim.adams@ansible.org" in {{ devs_group.users }}' + - '"jordanbulls@ansible.org" in {{ devs_group.users }}' + - admins_group.users | length == 1 + - devs_group.users | length == 2 + vars: + admins_group: "{{ result.groups | selectattr('metadata.name', 'equalto', 'ansible-admins') | first }}" + devs_group: "{{ result.groups | selectattr('metadata.name', 'equalto', 'ansible-devs') | first }}" + + - name: Synchronize Groups - Using dn for every query + community.okd.openshift_adm_groups_sync: + config: "{{ configs.dn_everywhere }}" + check_mode: yes + register: result + + - name: Validate Group going to be created + assert: + that: + - result is changed + - admins_group + - devs_group + - '"cn=Jane,ou=people,ou=rfc2307,{{ ldap_root }}" in {{ admins_group.users }}' + - '"cn=Jim,ou=people,ou=rfc2307,{{ ldap_root }}" in {{ devs_group.users }}' + - '"cn=Jordan,ou=people,ou=rfc2307,{{ ldap_root }}" in {{ devs_group.users }}' + - admins_group.users | length == 1 + - devs_group.users | length == 2 + vars: + admins_group: "{{ result.groups | selectattr('metadata.name', 'equalto', 'cn=admins,ou=groups,ou=rfc2307,' + ldap_root ) | first }}" + devs_group: "{{ result.groups | selectattr('metadata.name', 'equalto', 'cn=developers,ou=groups,ou=rfc2307,' + ldap_root ) | first }}" + + - name: Synchronize Groups - Partially user defined mapping + community.okd.openshift_adm_groups_sync: + config: "{{ configs.partially_user_defined }}" + check_mode: yes + register: result + + - name: Validate Group going to be created + assert: + that: + - result is changed + - admins_group + - devs_group + - '"jane.smith@ansible.org" in {{ admins_group.users }}' + - '"jim.adams@ansible.org" in {{ devs_group.users }}' + - '"jordanbulls@ansible.org" in {{ devs_group.users }}' + - admins_group.users | length == 1 + - devs_group.users | length == 2 + vars: + admins_group: "{{ result.groups | selectattr('metadata.name', 'equalto', 'ansible-admins') | first }}" + devs_group: "{{ result.groups | selectattr('metadata.name', 'equalto', 'developers') | first }}" + + - name: Delete Group 'engineers' if created before + community.okd.k8s: + state: absent + kind: Group + version: "user.openshift.io/v1" + name: 'engineers' + wait: yes + ignore_errors: yes + + - name: Synchronize Groups - Partially user defined mapping + community.okd.openshift_adm_groups_sync: + config: "{{ configs.out_scope }}" + check_mode: yes + register: result + ignore_errors: yes + + - name: Assert group sync failed due to non-existent member + assert: + that: + - result is failed + - result.msg.startswith("Entry not found for base='cn=Matthew,ou=people,ou=outrfc2307,{{ ldap_root }}'") + + - name: Define sync configuration with tolerateMemberNotFoundErrors + set_fact: + config_out_of_scope_tolerate_not_found: "{{ configs.out_scope | combine({'rfc2307': merge_rfc2307 })}}" + vars: + merge_rfc2307: "{{ configs.out_scope.rfc2307 | combine({'tolerateMemberNotFoundErrors': 'true'}) }}" + + - name: Synchronize Groups - Partially user defined mapping (tolerateMemberNotFoundErrors=true) + community.okd.openshift_adm_groups_sync: + config: "{{ config_out_of_scope_tolerate_not_found }}" + check_mode: yes + register: result + + - name: Assert group sync did not fail (tolerateMemberNotFoundErrors=true) + assert: + that: + - result is changed + - result.groups | length == 1 + - result.groups.0.metadata.name == 'engineers' + - result.groups.0.users == ['Abraham'] + + - name: Create Group 'engineers' + community.okd.k8s: + state: present + wait: yes + definition: + kind: Group + apiVersion: "user.openshift.io/v1" + metadata: + name: engineers + users: [] + + - name: Try to sync LDAP group with Openshift existing group not created using sync should failed + community.okd.openshift_adm_groups_sync: + config: "{{ config_out_of_scope_tolerate_not_found }}" + check_mode: yes + register: result + ignore_errors: yes + + - name: Validate group sync failed + assert: + that: + - result is failed + - '"openshift.io/ldap.host label did not match sync host" in result.msg' + + - name: Define allow_groups and deny_groups groups + set_fact: + allow_groups: + - "cn=developers,ou=groups,ou=rfc2307,{{ ldap_root }}" + deny_groups: + - "cn=admins,ou=groups,ou=rfc2307,{{ ldap_root }}" + + - name: Synchronize Groups using allow_groups + community.okd.openshift_adm_groups_sync: + config: "{{ configs.simple }}" + allow_groups: "{{ allow_groups }}" + register: result + check_mode: yes + + - name: Validate Group going to be created + assert: + that: + - result is changed + - result.groups | length == 1 + - result.groups.0.metadata.name == "developers" + + - name: Synchronize Groups using deny_groups + community.okd.openshift_adm_groups_sync: + config: "{{ configs.simple }}" + deny_groups: "{{ deny_groups }}" + register: result + check_mode: yes + + - name: Validate Group going to be created + assert: + that: + - result is changed + - result.groups | length == 1 + - result.groups.0.metadata.name == "developers" + + - name: Synchronize groups, remove check_mode + community.okd.openshift_adm_groups_sync: + config: "{{ configs.simple }}" + register: result + + - name: Validate result is changed + assert: + that: + - result is changed + + - name: Read Groups + kubernetes.core.k8s_info: + kind: Group + version: "user.openshift.io/v1" + name: admins + register: result + + - name: Validate group was created + assert: + that: + - result.resources | length == 1 + - '"jane.smith@ansible.org" in {{ result.resources.0.users }}' + + - name: Read Groups + kubernetes.core.k8s_info: + kind: Group + version: "user.openshift.io/v1" + name: developers + register: result + + - name: Validate group was created + assert: + that: + - result.resources | length == 1 + - '"jim.adams@ansible.org" in {{ result.resources.0.users }}' + - '"jordanbulls@ansible.org" in {{ result.resources.0.users }}' + + - name: Set users to delete (no admins users anymore and only 1 developer kept) + set_fact: + users_to_delete: + - "cn=Jane,ou=people,ou=rfc2307,{{ ldap_root }}" + - "cn=Jim,ou=people,ou=rfc2307,{{ ldap_root }}" + + - name: Delete users from LDAP servers + openshift_ldap_entry: + bind_dn: "{{ ldap_bind_dn }}" + bind_pw: "{{ ldap_bind_pw }}" + server_uri: "{{ ldap_server_uri }}" + dn: "{{ item }}" + state: absent + with_items: "{{ users_to_delete }}" + + - name: Define sync configuration with tolerateMemberNotFoundErrors + set_fact: + config_simple_tolerate_not_found: "{{ configs.simple | combine({'rfc2307': merge_rfc2307 })}}" + vars: + merge_rfc2307: "{{ configs.simple.rfc2307 | combine({'tolerateMemberNotFoundErrors': 'true'}) }}" + + - name: Synchronize groups once again after users deletion + community.okd.openshift_adm_groups_sync: + config: "{{ config_simple_tolerate_not_found }}" + register: result + + - name: Validate result is changed + assert: + that: + - result is changed + + - name: Read Groups + kubernetes.core.k8s_info: + kind: Group + version: "user.openshift.io/v1" + name: admins + register: result + + - name: Validate admins group does not contains users anymore + assert: + that: + - result.resources | length == 1 + - result.resources.0.users == [] + + - name: Read Groups + kubernetes.core.k8s_info: + kind: Group + version: "user.openshift.io/v1" + name: developers + register: result + + - name: Validate group was created + assert: + that: + - result.resources | length == 1 + - '"jordanbulls@ansible.org" in {{ result.resources.0.users }}' + + - name: Set group to delete + set_fact: + groups_to_delete: + - "cn=developers,ou=groups,ou=rfc2307,{{ ldap_root }}" + + - name: Delete Group from LDAP servers + openshift_ldap_entry: + bind_dn: "{{ ldap_bind_dn }}" + bind_pw: "{{ ldap_bind_pw }}" + server_uri: "{{ ldap_server_uri }}" + dn: "{{ item }}" + state: absent + with_items: "{{ groups_to_delete }}" + + - name: Prune groups + community.okd.openshift_adm_groups_sync: + config: "{{ config_simple_tolerate_not_found }}" + state: absent + register: result + check_mode: yes + + - name: Validate that only developers group is candidate for Prune + assert: + that: + - result is changed + - result.groups | length == 1 + - result.groups.0.metadata.name == "developers" + + - name: Read Group (validate that check_mode did not performed update in the cluster) + kubernetes.core.k8s_info: + kind: Group + version: "user.openshift.io/v1" + name: developers + register: result + + - name: Assert group was found + assert: + that: + - result.resources | length == 1 + + - name: Prune using allow_groups + community.okd.openshift_adm_groups_sync: + config: "{{ config_simple_tolerate_not_found }}" + allow_groups: + - developers + state: absent + register: result + check_mode: yes + + - name: assert developers group was candidate for prune + assert: + that: + - result is changed + - result.groups | length == 1 + - result.groups.0.metadata.name == "developers" + + - name: Prune using deny_groups + community.okd.openshift_adm_groups_sync: + config: "{{ config_simple_tolerate_not_found }}" + deny_groups: + - developers + state: absent + register: result + check_mode: yes + + - name: assert nothing found candidate for prune + assert: + that: + - result is not changed + - result.groups | length == 0 + + - name: Prune groups + community.okd.openshift_adm_groups_sync: + config: "{{ config_simple_tolerate_not_found }}" + state: absent + register: result + + - name: Validate result is changed + assert: + that: + - result is changed + - result.groups | length == 1 + + - name: Get developers group info + kubernetes.core.k8s_info: + kind: Group + version: "user.openshift.io/v1" + name: developers + register: result + + - name: assert group was deleted + assert: + that: + - result.resources | length == 0 + + - name: Get admins group info + kubernetes.core.k8s_info: + kind: Group + version: "user.openshift.io/v1" + name: admins + register: result + + - name: assert group was not deleted + assert: + that: + - result.resources | length == 1 + + - name: Prune groups once again (idempotency) + community.okd.openshift_adm_groups_sync: + config: "{{ config_simple_tolerate_not_found }}" + state: absent + register: result + + - name: Assert nothing changed + assert: + that: + - result is not changed + - result.groups | length == 0 + + always: + - name: Delete openshift groups if existing + community.okd.k8s: + state: absent + kind: Group + version: "user.openshift.io/v1" + name: "{{ item }}" + with_items: + - admins + - engineers + - developers
\ No newline at end of file diff --git a/ansible_collections/community/okd/molecule/default/roles/openshift_adm_groups/templates/ad/definition.j2 b/ansible_collections/community/okd/molecule/default/roles/openshift_adm_groups/templates/ad/definition.j2 new file mode 100644 index 000000000..f1cc6d9f0 --- /dev/null +++ b/ansible_collections/community/okd/molecule/default/roles/openshift_adm_groups/templates/ad/definition.j2 @@ -0,0 +1,39 @@ +units: + - dn: "ou=activeD,{{ ldap_root }}" + class: + - organizationalUnit + attr: + ou: activeD + - dn: "ou=engineers,ou=activeD,{{ ldap_root }}" + class: + - organizationalUnit + attr: + ou: engineers +users: + - dn: cn=Jane,ou=engineers,ou=activeD,{{ ldap_root }} + class: + - inetOrgPerson + attr: + cn: Jane + sn: Smith + displayName: Jane Smith + mail: jane.smith@ansible.org + employeeType: admins + - dn: cn=Jim,ou=engineers,ou=activeD,{{ ldap_root }} + class: + - inetOrgPerson + attr: + cn: Jim + sn: Adams + displayName: Jim Adams + mail: jim.adams@ansible.org + employeeType: admins + - dn: cn=Jordan,ou=engineers,ou=activeD,{{ ldap_root }} + class: + - inetOrgPerson + attr: + cn: Jordan + sn: Bulls + displayName: Jordan Bulls + mail: jordanbulls@ansible.org + employeeType: developers
\ No newline at end of file diff --git a/ansible_collections/community/okd/molecule/default/roles/openshift_adm_groups/templates/ad/sync-config.j2 b/ansible_collections/community/okd/molecule/default/roles/openshift_adm_groups/templates/ad/sync-config.j2 new file mode 100644 index 000000000..5599affa8 --- /dev/null +++ b/ansible_collections/community/okd/molecule/default/roles/openshift_adm_groups/templates/ad/sync-config.j2 @@ -0,0 +1,12 @@ +kind: LDAPSyncConfig +apiVersion: v1 +url: "{{ ldap_server_uri }}" +insecure: true +activeDirectory: + usersQuery: + baseDN: "ou=engineers,ou=activeD,{{ ldap_root }}" + scope: sub + derefAliases: never + filter: (objectclass=inetOrgPerson) + userNameAttributes: [ mail ] + groupMembershipAttributes: [ employeeType ]
\ No newline at end of file diff --git a/ansible_collections/community/okd/molecule/default/roles/openshift_adm_groups/templates/augmented-ad/definition.j2 b/ansible_collections/community/okd/molecule/default/roles/openshift_adm_groups/templates/augmented-ad/definition.j2 new file mode 100644 index 000000000..039c30828 --- /dev/null +++ b/ansible_collections/community/okd/molecule/default/roles/openshift_adm_groups/templates/augmented-ad/definition.j2 @@ -0,0 +1,59 @@ +units: + - dn: "ou=augmentedAD,{{ ldap_root }}" + class: + - organizationalUnit + attr: + ou: augmentedAD + - dn: "ou=employee,ou=augmentedAD,{{ ldap_root }}" + class: + - organizationalUnit + attr: + ou: employee + - dn: "ou=category,ou=augmentedAD,{{ ldap_root }}" + class: + - organizationalUnit + attr: + ou: category +groups: + - dn: "cn=banking,ou=category,ou=augmentedAD,{{ ldap_root }}" + class: + - groupOfNames + attr: + cn: banking + description: Banking employees + member: + - cn=James,ou=employee,ou=augmentedAD,{{ ldap_root }} + - cn=Gordon,ou=employee,ou=augmentedAD,{{ ldap_root }} + - dn: "cn=insurance,ou=category,ou=augmentedAD,{{ ldap_root }}" + class: + - groupOfNames + attr: + cn: insurance + description: Insurance employees + member: + - cn=Alice,ou=employee,ou=augmentedAD,{{ ldap_root }} +users: + - dn: cn=James,ou=employee,ou=augmentedAD,{{ ldap_root }} + class: + - inetOrgPerson + attr: + cn: James + sn: Allan + mail: james-allan@ansible.org + businessCategory: cn=banking,ou=category,ou=augmentedAD,{{ ldap_root }} + - dn: cn=Gordon,ou=employee,ou=augmentedAD,{{ ldap_root }} + class: + - inetOrgPerson + attr: + cn: Gordon + sn: Kane + mail: gordon-kane@ansible.org + businessCategory: cn=banking,ou=category,ou=augmentedAD,{{ ldap_root }} + - dn: cn=Alice,ou=employee,ou=augmentedAD,{{ ldap_root }} + class: + - inetOrgPerson + attr: + cn: Alice + sn: Courtney + mail: alice-courtney@ansible.org + businessCategory: cn=insurance,ou=category,ou=augmentedAD,{{ ldap_root }}
\ No newline at end of file diff --git a/ansible_collections/community/okd/molecule/default/roles/openshift_adm_groups/templates/augmented-ad/sync-config.j2 b/ansible_collections/community/okd/molecule/default/roles/openshift_adm_groups/templates/augmented-ad/sync-config.j2 new file mode 100644 index 000000000..197204465 --- /dev/null +++ b/ansible_collections/community/okd/molecule/default/roles/openshift_adm_groups/templates/augmented-ad/sync-config.j2 @@ -0,0 +1,20 @@ +kind: LDAPSyncConfig +apiVersion: v1 +url: "{{ ldap_server_uri }}" +insecure: true +augmentedActiveDirectory: + groupsQuery: + baseDN: "ou=category,ou=augmentedAD,{{ ldap_root }}" + scope: sub + derefAliases: never + pageSize: 0 + groupUIDAttribute: dn + groupNameAttributes: [ cn ] + usersQuery: + baseDN: "ou=employee,ou=augmentedAD,{{ ldap_root }}" + scope: sub + derefAliases: never + filter: (objectclass=inetOrgPerson) + pageSize: 0 + userNameAttributes: [ mail ] + groupMembershipAttributes: [ businessCategory ]
\ No newline at end of file diff --git a/ansible_collections/community/okd/molecule/default/roles/openshift_adm_groups/templates/rfc2307/definition.j2 b/ansible_collections/community/okd/molecule/default/roles/openshift_adm_groups/templates/rfc2307/definition.j2 new file mode 100644 index 000000000..521eaee98 --- /dev/null +++ b/ansible_collections/community/okd/molecule/default/roles/openshift_adm_groups/templates/rfc2307/definition.j2 @@ -0,0 +1,102 @@ +units: + - dn: "ou=rfc2307,{{ ldap_root }}" + class: + - organizationalUnit + attr: + ou: rfc2307 + - dn: "ou=groups,ou=rfc2307,{{ ldap_root }}" + class: + - organizationalUnit + attr: + ou: groups + - dn: "ou=people,ou=rfc2307,{{ ldap_root }}" + class: + - organizationalUnit + attr: + ou: people + - dn: "ou=outrfc2307,{{ ldap_root }}" + class: + - organizationalUnit + attr: + ou: outrfc2307 + - dn: "ou=groups,ou=outrfc2307,{{ ldap_root }}" + class: + - organizationalUnit + attr: + ou: groups + - dn: "ou=people,ou=outrfc2307,{{ ldap_root }}" + class: + - organizationalUnit + attr: + ou: people +groups: + - dn: "cn=admins,ou=groups,ou=rfc2307,{{ ldap_root }}" + class: + - groupOfNames + attr: + cn: admins + description: System Administrators + member: + - cn=Jane,ou=people,ou=rfc2307,{{ ldap_root }} + - dn: "cn=developers,ou=groups,ou=rfc2307,{{ ldap_root }}" + class: + - groupOfNames + attr: + cn: developers + description: Developers + member: + - cn=Jim,ou=people,ou=rfc2307,{{ ldap_root }} + - cn=Jordan,ou=people,ou=rfc2307,{{ ldap_root }} + - dn: "cn=engineers,ou=groups,ou=outrfc2307,{{ ldap_root }}" + class: + - groupOfNames + attr: + cn: engineers + description: Engineers + member: + - cn=Jim,ou=people,ou=rfc2307,{{ ldap_root }} + - cn=Jordan,ou=people,ou=rfc2307,{{ ldap_root }} + - cn=Julia,ou=people,ou=outrfc2307,{{ ldap_root }} + - cn=Matthew,ou=people,ou=outrfc2307,{{ ldap_root }} +users: + - dn: cn=Jane,ou=people,ou=rfc2307,{{ ldap_root }} + class: + - person + - organizationalPerson + - inetOrgPerson + attr: + cn: Jane + sn: Smith + displayName: Jane Smith + mail: jane.smith@ansible.org + admin: yes + - dn: cn=Jim,ou=people,ou=rfc2307,{{ ldap_root }} + class: + - person + - organizationalPerson + - inetOrgPerson + attr: + cn: Jim + sn: Adams + displayName: Jim Adams + mail: jim.adams@ansible.org + - dn: cn=Jordan,ou=people,ou=rfc2307,{{ ldap_root }} + class: + - person + - organizationalPerson + - inetOrgPerson + attr: + cn: Jordan + sn: Bulls + displayName: Jordan Bulls + mail: jordanbulls@ansible.org + - dn: cn=Julia,ou=people,ou=outrfc2307,{{ ldap_root }} + class: + - person + - organizationalPerson + - inetOrgPerson + attr: + cn: Julia + sn: Abraham + displayName: Julia Abraham + mail: juliaabraham@ansible.org
\ No newline at end of file diff --git a/ansible_collections/community/okd/molecule/default/roles/openshift_adm_groups/templates/rfc2307/sync-config.j2 b/ansible_collections/community/okd/molecule/default/roles/openshift_adm_groups/templates/rfc2307/sync-config.j2 new file mode 100644 index 000000000..70198ca4b --- /dev/null +++ b/ansible_collections/community/okd/molecule/default/roles/openshift_adm_groups/templates/rfc2307/sync-config.j2 @@ -0,0 +1,105 @@ +simple: + kind: LDAPSyncConfig + apiVersion: v1 + url: "{{ ldap_server_uri }}" + insecure: true + rfc2307: + groupsQuery: + baseDN: "ou=groups,ou=rfc2307,{{ ldap_root }}" + scope: sub + derefAliases: never + filter: (objectclass=groupOfNames) + groupUIDAttribute: dn + groupNameAttributes: [ cn ] + groupMembershipAttributes: [ member ] + usersQuery: + baseDN: "ou=people,ou=rfc2307,{{ ldap_root }}" + scope: sub + derefAliases: never + userUIDAttribute: dn + userNameAttributes: [ mail ] +user_defined: + kind: LDAPSyncConfig + apiVersion: v1 + url: "{{ ldap_server_uri }}" + insecure: true + groupUIDNameMapping: + "cn=admins,ou=groups,ou=rfc2307,{{ ldap_root }}": ansible-admins + "cn=developers,ou=groups,ou=rfc2307,{{ ldap_root }}": ansible-devs + rfc2307: + groupsQuery: + baseDN: "ou=groups,ou=rfc2307,{{ ldap_root }}" + scope: sub + derefAliases: never + filter: (objectclass=groupOfNames) + groupUIDAttribute: dn + groupNameAttributes: [ cn ] + groupMembershipAttributes: [ member ] + usersQuery: + baseDN: "ou=people,ou=rfc2307,{{ ldap_root }}" + scope: sub + derefAliases: never + userUIDAttribute: dn + userNameAttributes: [ mail ] +partially_user_defined: + kind: LDAPSyncConfig + apiVersion: v1 + url: "{{ ldap_server_uri }}" + insecure: true + groupUIDNameMapping: + "cn=admins,ou=groups,ou=rfc2307,{{ ldap_root }}": ansible-admins + rfc2307: + groupsQuery: + baseDN: "ou=groups,ou=rfc2307,{{ ldap_root }}" + scope: sub + derefAliases: never + filter: (objectclass=groupOfNames) + groupUIDAttribute: dn + groupNameAttributes: [ cn ] + groupMembershipAttributes: [ member ] + usersQuery: + baseDN: "ou=people,ou=rfc2307,{{ ldap_root }}" + scope: sub + derefAliases: never + userUIDAttribute: dn + userNameAttributes: [ mail ] +dn_everywhere: + kind: LDAPSyncConfig + apiVersion: v1 + url: "{{ ldap_server_uri }}" + insecure: true + rfc2307: + groupsQuery: + baseDN: "ou=groups,ou=rfc2307,{{ ldap_root }}" + scope: sub + derefAliases: never + filter: (objectclass=groupOfNames) + groupUIDAttribute: dn + groupNameAttributes: [ dn ] + groupMembershipAttributes: [ member ] + usersQuery: + baseDN: "ou=people,ou=rfc2307,{{ ldap_root }}" + scope: sub + derefAliases: never + userUIDAttribute: dn + userNameAttributes: [ dn ] +out_scope: + kind: LDAPSyncConfig + apiVersion: v1 + url: "{{ ldap_server_uri }}" + insecure: true + rfc2307: + groupsQuery: + baseDN: "ou=groups,ou=outrfc2307,{{ ldap_root }}" + scope: sub + derefAliases: never + filter: (objectclass=groupOfNames) + groupUIDAttribute: dn + groupNameAttributes: [ cn ] + groupMembershipAttributes: [ member ] + usersQuery: + baseDN: "ou=people,ou=outrfc2307,{{ ldap_root }}" + scope: sub + derefAliases: never + userUIDAttribute: dn + userNameAttributes: [ sn ]
\ No newline at end of file diff --git a/ansible_collections/community/okd/molecule/default/tasks/openshift_adm_prune_auth_clusterroles.yml b/ansible_collections/community/okd/molecule/default/tasks/openshift_adm_prune_auth_clusterroles.yml new file mode 100644 index 000000000..4de4894e2 --- /dev/null +++ b/ansible_collections/community/okd/molecule/default/tasks/openshift_adm_prune_auth_clusterroles.yml @@ -0,0 +1,318 @@ +- block: + - set_fact: + test_sa: "clusterrole-sa" + test_ns: "clusterrole-ns" + + - name: Ensure namespace + kubernetes.core.k8s: + kind: Namespace + name: "{{ test_ns }}" + + - name: Get cluster information + kubernetes.core.k8s_cluster_info: + register: cluster_info + no_log: true + + - set_fact: + cluster_host: "{{ cluster_info['connection']['host'] }}" + + - name: Create Service account + kubernetes.core.k8s: + definition: + apiVersion: v1 + kind: ServiceAccount + metadata: + name: "{{ test_sa }}" + namespace: "{{ test_ns }}" + + - name: Read Service Account + kubernetes.core.k8s_info: + kind: ServiceAccount + namespace: "{{ test_ns }}" + name: "{{ test_sa }}" + register: result + + - set_fact: + secret_token: "{{ result.resources[0]['secrets'][0]['name'] }}" + + - name: Get secret details + kubernetes.core.k8s_info: + kind: Secret + namespace: '{{ test_ns }}' + name: '{{ secret_token }}' + register: _secret + retries: 10 + delay: 10 + until: + - ("'openshift.io/token-secret.value' in _secret.resources[0]['metadata']['annotations']") or ("'token' in _secret.resources[0]['data']") + + - set_fact: + api_token: "{{ _secret.resources[0]['metadata']['annotations']['openshift.io/token-secret.value'] }}" + when: "'openshift.io/token-secret.value' in _secret.resources[0]['metadata']['annotations']" + + - set_fact: + api_token: "{{ _secret.resources[0]['data']['token'] | b64decode }}" + when: "'token' in _secret.resources[0]['data']" + + - name: list Node should failed (forbidden user) + kubernetes.core.k8s_info: + api_key: "{{ api_token }}" + host: "{{ cluster_host }}" + validate_certs: no + kind: Node + register: error + ignore_errors: true + + - assert: + that: + - '"nodes is forbidden: User" in error.msg' + + - name: list Pod for all namespace should failed + kubernetes.core.k8s_info: + api_key: "{{ api_token }}" + host: "{{ cluster_host }}" + validate_certs: no + kind: Pod + register: error + ignore_errors: true + + - assert: + that: + - '"pods is forbidden: User" in error.msg' + + - name: list Pod for test namespace should failed + kubernetes.core.k8s_info: + api_key: "{{ api_token }}" + host: "{{ cluster_host }}" + validate_certs: no + kind: Pod + namespace: "{{ test_ns }}" + register: error + ignore_errors: true + + - assert: + that: + - '"pods is forbidden: User" in error.msg' + + - set_fact: + test_labels: + phase: dev + cluster_roles: + - name: pod-manager + resources: + - pods + verbs: + - list + api_version_binding: "authorization.openshift.io/v1" + - name: node-manager + resources: + - nodes + verbs: + - list + api_version_binding: "rbac.authorization.k8s.io/v1" + + - name: Create cluster roles + kubernetes.core.k8s: + definition: + kind: ClusterRole + apiVersion: "rbac.authorization.k8s.io/v1" + metadata: + name: "{{ item.name }}" + labels: "{{ test_labels }}" + rules: + - apiGroups: [""] + resources: "{{ item.resources }}" + verbs: "{{ item.verbs }}" + with_items: '{{ cluster_roles }}' + + - name: Create Role Binding (namespaced) + kubernetes.core.k8s: + definition: + kind: RoleBinding + apiVersion: "rbac.authorization.k8s.io/v1" + metadata: + name: "{{ cluster_roles[0].name }}-binding" + namespace: "{{ test_ns }}" + labels: "{{ test_labels }}" + subjects: + - kind: ServiceAccount + name: "{{ test_sa }}" + namespace: "{{ test_ns }}" + apiGroup: "" + roleRef: + kind: ClusterRole + name: "{{ cluster_roles[0].name }}" + apiGroup: "" + + - name: list Pod for all namespace should failed + kubernetes.core.k8s_info: + api_key: "{{ api_token }}" + host: "{{ cluster_host }}" + validate_certs: no + kind: Pod + register: error + ignore_errors: true + + - assert: + that: + - '"pods is forbidden: User" in error.msg' + + - name: list Pod for test namespace should succeed + kubernetes.core.k8s_info: + api_key: "{{ api_token }}" + host: "{{ cluster_host }}" + validate_certs: no + kind: Pod + namespace: "{{ test_ns }}" + no_log: true + + - name: Create Cluster role Binding + kubernetes.core.k8s: + definition: + kind: ClusterRoleBinding + apiVersion: "{{ item.api_version_binding }}" + metadata: + name: "{{ item.name }}-binding" + labels: "{{ test_labels }}" + subjects: + - kind: ServiceAccount + name: "{{ test_sa }}" + namespace: "{{ test_ns }}" + apiGroup: "" + roleRef: + kind: ClusterRole + name: "{{ item.name }}" + apiGroup: "" + with_items: "{{ cluster_roles }}" + + - name: list Pod for all namespace should succeed + kubernetes.core.k8s_info: + api_key: "{{ api_token }}" + host: "{{ cluster_host }}" + validate_certs: no + kind: Pod + no_log: true + + - name: list Pod for test namespace should succeed + kubernetes.core.k8s_info: + api_key: "{{ api_token }}" + host: "{{ cluster_host }}" + validate_certs: no + kind: Pod + namespace: "{{ test_ns }}" + no_log: true + + - name: list Node using ServiceAccount + kubernetes.core.k8s_info: + api_key: "{{ api_token }}" + host: "{{ cluster_host }}" + validate_certs: no + kind: Node + namespace: "{{ test_ns }}" + no_log: true + + - name: Prune clusterroles (check mode) + community.okd.openshift_adm_prune_auth: + resource: clusterroles + label_selectors: + - phase=dev + register: check + check_mode: true + + - name: validate clusterrole binding candidates for prune + assert: + that: + - '"{{ item.name }}-binding" in check.cluster_role_binding' + - '"{{ test_ns }}/{{ cluster_roles[0].name }}-binding" in check.role_binding' + with_items: "{{ cluster_roles }}" + + - name: Prune Cluster Role for managing Pod + community.okd.openshift_adm_prune_auth: + resource: clusterroles + name: "{{ cluster_roles[0].name }}" + + - name: list Pod for all namespace should failed + kubernetes.core.k8s_info: + api_key: "{{ api_token }}" + host: "{{ cluster_host }}" + validate_certs: no + kind: Pod + register: error + no_log: true + ignore_errors: true + + - assert: + that: + - '"pods is forbidden: User" in error.msg' + + - name: list Pod for test namespace should failed + kubernetes.core.k8s_info: + api_key: "{{ api_token }}" + host: "{{ cluster_host }}" + validate_certs: no + kind: Pod + namespace: "{{ test_ns }}" + register: error + no_log: true + ignore_errors: true + + - assert: + that: + - '"pods is forbidden: User" in error.msg' + + - name: list Node using ServiceAccount + kubernetes.core.k8s_info: + api_key: "{{ api_token }}" + host: "{{ cluster_host }}" + validate_certs: no + kind: Node + namespace: "{{ test_ns }}" + no_log: true + + - name: Prune clusterroles (remaining) + community.okd.openshift_adm_prune_auth: + resource: clusterroles + label_selectors: + - phase=dev + + - name: list Node using ServiceAccount should fail + kubernetes.core.k8s_info: + api_key: "{{ api_token }}" + host: "{{ cluster_host }}" + validate_certs: no + kind: Node + namespace: "{{ test_ns }}" + register: error + ignore_errors: true + + - assert: + that: + - '"nodes is forbidden: User" in error.msg' + + always: + - name: Ensure namespace is deleted + kubernetes.core.k8s: + state: absent + kind: Namespace + name: "{{ test_ns }}" + ignore_errors: true + + - name: Delete ClusterRoleBinding + kubernetes.core.k8s: + kind: ClusterRoleBinding + api_version: "rbac.authorization.k8s.io/v1" + name: "{{ item.name }}-binding" + state: absent + ignore_errors: true + with_items: "{{ cluster_roles }}" + when: cluster_roles is defined + + - name: Delete ClusterRole + kubernetes.core.k8s: + kind: ClusterRole + api_version: "rbac.authorization.k8s.io/v1" + name: "{{ item.name }}" + state: absent + ignore_errors: true + with_items: "{{ cluster_roles }}" + when: cluster_roles is defined diff --git a/ansible_collections/community/okd/molecule/default/tasks/openshift_adm_prune_auth_roles.yml b/ansible_collections/community/okd/molecule/default/tasks/openshift_adm_prune_auth_roles.yml new file mode 100644 index 000000000..1724a1938 --- /dev/null +++ b/ansible_collections/community/okd/molecule/default/tasks/openshift_adm_prune_auth_roles.yml @@ -0,0 +1,340 @@ +- block: + - set_fact: + test_ns: "prune-roles" + sa_name: "roles-sa" + pod_name: "pod-prune" + role_definition: + - name: pod-list + labels: + action: list + verbs: + - list + role_binding: + api_version: rbac.authorization.k8s.io/v1 + - name: pod-create + labels: + action: create + verbs: + - create + - get + role_binding: + api_version: authorization.openshift.io/v1 + - name: pod-delete + labels: + action: delete + verbs: + - delete + role_binding: + api_version: rbac.authorization.k8s.io/v1 + + - name: Ensure namespace + kubernetes.core.k8s: + kind: Namespace + name: '{{ test_ns }}' + + - name: Get cluster information + kubernetes.core.k8s_cluster_info: + register: cluster_info + no_log: true + + - set_fact: + cluster_host: "{{ cluster_info['connection']['host'] }}" + + - name: Create Service account + kubernetes.core.k8s: + definition: + apiVersion: v1 + kind: ServiceAccount + metadata: + name: '{{ sa_name }}' + namespace: '{{ test_ns }}' + + - name: Read Service Account + kubernetes.core.k8s_info: + kind: ServiceAccount + namespace: '{{ test_ns }}' + name: '{{ sa_name }}' + register: sa_out + + - set_fact: + secret_token: "{{ sa_out.resources[0]['secrets'][0]['name'] }}" + + - name: Get secret details + kubernetes.core.k8s_info: + kind: Secret + namespace: '{{ test_ns }}' + name: '{{ secret_token }}' + register: r_secret + retries: 10 + delay: 10 + until: + - ("'openshift.io/token-secret.value' in r_secret.resources[0]['metadata']['annotations']") or ("'token' in r_secret.resources[0]['data']") + + - set_fact: + api_token: "{{ r_secret.resources[0]['metadata']['annotations']['openshift.io/token-secret.value'] }}" + when: "'openshift.io/token-secret.value' in r_secret.resources[0]['metadata']['annotations']" + + - set_fact: + api_token: "{{ r_secret.resources[0]['data']['token'] | b64decode }}" + when: "'token' in r_secret.resources[0]['data']" + + - name: list resources using service account + kubernetes.core.k8s_info: + api_key: '{{ api_token }}' + host: '{{ cluster_host }}' + validate_certs: no + kind: Pod + namespace: '{{ test_ns }}' + register: error + ignore_errors: true + + - assert: + that: + - '"pods is forbidden: User" in error.msg' + + - name: Create a role to manage Pod from namespace "{{ test_ns }}" + kubernetes.core.k8s: + definition: + kind: Role + apiVersion: rbac.authorization.k8s.io/v1 + metadata: + namespace: "{{ test_ns }}" + name: "{{ item.name }}" + labels: "{{ item.labels }}" + rules: + - apiGroups: [""] + resources: ["pods"] + verbs: "{{ item.verbs }}" + with_items: "{{ role_definition }}" + + - name: Create Role Binding + kubernetes.core.k8s: + definition: + kind: RoleBinding + apiVersion: "{{ item.role_binding.api_version }}" + metadata: + name: "{{ item.name }}-bind" + namespace: "{{ test_ns }}" + subjects: + - kind: ServiceAccount + name: "{{ sa_name }}" + namespace: "{{ test_ns }}" + apiGroup: "" + roleRef: + kind: Role + name: "{{ item.name }}" + namespace: "{{ test_ns }}" + apiGroup: "" + with_items: "{{ role_definition }}" + + - name: Create Pod should succeed + kubernetes.core.k8s: + api_key: "{{ api_token }}" + host: "{{ cluster_host }}" + validate_certs: no + namespace: "{{ test_ns }}" + definition: + kind: Pod + metadata: + name: "{{ pod_name }}" + spec: + containers: + - name: python + image: python:3.7-alpine + command: + - /bin/sh + - -c + - while true; do echo $(date); sleep 15; done + imagePullPolicy: IfNotPresent + register: result + + - name: assert pod creation succeed + assert: + that: + - result is successful + + - name: List Pod + kubernetes.core.k8s_info: + api_key: "{{ api_token }}" + host: "{{ cluster_host }}" + validate_certs: no + namespace: "{{ test_ns }}" + kind: Pod + register: result + + - name: assert user is still authorize to list pods + assert: + that: + - result is successful + + - name: Prune auth roles (check mode) + community.okd.openshift_adm_prune_auth: + resource: roles + namespace: "{{ test_ns }}" + register: check + check_mode: true + + - name: validate that list role binding are candidates for prune + assert: + that: '"{{ test_ns }}/{{ item.name }}-bind" in check.role_binding' + with_items: "{{ role_definition }}" + + - name: Prune resource using label_selectors option + community.okd.openshift_adm_prune_auth: + resource: roles + namespace: "{{ test_ns }}" + label_selectors: + - action=delete + register: prune + + - name: assert that role binding 'delete' was pruned + assert: + that: + - prune is changed + - '"{{ test_ns }}/{{ role_definition[2].name }}-bind" in check.role_binding' + + - name: assert that user could not delete pod anymore + kubernetes.core.k8s: + api_key: "{{ api_token }}" + host: "{{ cluster_host }}" + validate_certs: no + state: absent + namespace: "{{ test_ns }}" + kind: Pod + name: "{{ pod_name }}" + register: result + ignore_errors: true + + - name: assert pod deletion failed due to forbidden user + assert: + that: + - '"forbidden: User" in error.msg' + + - name: List Pod + kubernetes.core.k8s_info: + api_key: "{{ api_token }}" + host: "{{ cluster_host }}" + validate_certs: no + namespace: "{{ test_ns }}" + kind: Pod + register: result + + - name: assert user is still able to list pods + assert: + that: + - result is successful + + - name: Create Pod should succeed + kubernetes.core.k8s: + api_key: "{{ api_token }}" + host: "{{ cluster_host }}" + validate_certs: no + namespace: "{{ test_ns }}" + definition: + kind: Pod + metadata: + name: "{{ pod_name }}-1" + spec: + containers: + - name: python + image: python:3.7-alpine + command: + - /bin/sh + - -c + - while true; do echo $(date); sleep 15; done + imagePullPolicy: IfNotPresent + register: result + + - name: assert user is still authorize to create pod + assert: + that: + - result is successful + + - name: Prune role using name + community.okd.openshift_adm_prune_auth: + resource: roles + namespace: "{{ test_ns }}" + name: "{{ role_definition[1].name }}" + register: prune + + - name: assert that role binding 'create' was pruned + assert: + that: + - prune is changed + - '"{{ test_ns }}/{{ role_definition[1].name }}-bind" in check.role_binding' + + - name: Create Pod (should failed) + kubernetes.core.k8s: + api_key: "{{ api_token }}" + host: "{{ cluster_host }}" + validate_certs: no + namespace: "{{ test_ns }}" + definition: + kind: Pod + metadata: + name: "{{ pod_name }}-2" + spec: + containers: + - name: python + image: python:3.7-alpine + command: + - /bin/sh + - -c + - while true; do echo $(date); sleep 15; done + imagePullPolicy: IfNotPresent + register: result + ignore_errors: true + + - name: assert user is not authorize to create pod anymore + assert: + that: + - '"forbidden: User" in error.msg' + + - name: List Pod + kubernetes.core.k8s_info: + api_key: "{{ api_token }}" + host: "{{ cluster_host }}" + validate_certs: no + namespace: "{{ test_ns }}" + kind: Pod + register: result + + - name: assert user is still able to list pods + assert: + that: + - result is successful + + - name: Prune all role for namespace (neither name nor label_selectors are specified) + community.okd.openshift_adm_prune_auth: + resource: roles + namespace: "{{ test_ns }}" + register: prune + + - name: assert that role binding 'list' was pruned + assert: + that: + - prune is changed + - '"{{ test_ns }}/{{ role_definition[0].name }}-bind" in check.role_binding' + + - name: List Pod + kubernetes.core.k8s_info: + api_key: "{{ api_token }}" + host: "{{ cluster_host }}" + validate_certs: no + namespace: "{{ test_ns }}" + kind: Pod + register: result + ignore_errors: true + + - name: assert user is not authorize to list pod anymore + assert: + that: + - '"forbidden: User" in error.msg' + + always: + - name: Ensure namespace is deleted + kubernetes.core.k8s: + state: absent + kind: Namespace + name: "{{ test_ns }}" + ignore_errors: true diff --git a/ansible_collections/community/okd/molecule/default/tasks/openshift_adm_prune_deployments.yml b/ansible_collections/community/okd/molecule/default/tasks/openshift_adm_prune_deployments.yml new file mode 100644 index 000000000..baa024188 --- /dev/null +++ b/ansible_collections/community/okd/molecule/default/tasks/openshift_adm_prune_deployments.yml @@ -0,0 +1,269 @@ +- name: Prune deployments + block: + - set_fact: + dc_name: "hello" + deployment_ns: "prune-deployments" + deployment_ns_2: "prune-deployments-2" + + + - name: Ensure namespace + community.okd.k8s: + kind: Namespace + name: '{{ deployment_ns }}' + + - name: Create deployment config + community.okd.k8s: + namespace: '{{ deployment_ns }}' + definition: + kind: DeploymentConfig + apiVersion: apps.openshift.io/v1 + metadata: + name: '{{ dc_name }}' + spec: + replicas: 1 + selector: + name: '{{ dc_name }}' + template: + metadata: + labels: + name: '{{ dc_name }}' + spec: + containers: + - name: hello-openshift + imagePullPolicy: IfNotPresent + image: python:3.7-alpine + command: [ "/bin/sh", "-c", "while true;do date;sleep 2s; done"] + wait: yes + + - name: prune deployments (no candidate DeploymentConfig) + community.okd.openshift_adm_prune_deployments: + namespace: "{{ deployment_ns }}" + register: test_prune + + - assert: + that: + - test_prune is not changed + - test_prune.replication_controllers | length == 0 + + - name: Update DeploymentConfig - set replicas to 0 + community.okd.k8s: + namespace: "{{ deployment_ns }}" + definition: + kind: DeploymentConfig + apiVersion: "apps.openshift.io/v1" + metadata: + name: "{{ dc_name }}" + spec: + replicas: 0 + selector: + name: "{{ dc_name }}" + template: + metadata: + labels: + name: "{{ dc_name }}" + spec: + containers: + - name: hello-openshift + imagePullPolicy: IfNotPresent + image: python:3.7-alpine + command: [ "/bin/sh", "-c", "while true;do date;sleep 2s; done"] + wait: yes + + - name: Wait for ReplicationController candidate for pruning + kubernetes.core.k8s_info: + kind: ReplicationController + namespace: "{{ deployment_ns }}" + register: result + retries: 10 + delay: 30 + until: + - result.resources.0.metadata.annotations["openshift.io/deployment.phase"] in ("Failed", "Complete") + + - name: Prune deployments - should delete 1 ReplicationController + community.okd.openshift_adm_prune_deployments: + namespace: "{{ deployment_ns }}" + check_mode: yes + register: test_prune + + - name: Read ReplicationController + kubernetes.core.k8s_info: + kind: ReplicationController + namespace: "{{ deployment_ns }}" + register: replications + + - name: Assert that Replication controller was not deleted + assert: + that: + - replications.resources | length == 1 + - 'replications.resources.0.metadata.name is match("{{ dc_name }}-*")' + + - name: Assure that candidate ReplicationController was found for pruning + assert: + that: + - test_prune is changed + - test_prune.replication_controllers | length == 1 + - test_prune.replication_controllers.0.metadata.name == replications.resources.0.metadata.name + - test_prune.replication_controllers.0.metadata.namespace == replications.resources.0.metadata.namespace + + - name: Prune deployments - keep younger than 45min (check_mode) + community.okd.openshift_adm_prune_deployments: + keep_younger_than: 45 + namespace: "{{ deployment_ns }}" + check_mode: true + register: keep_younger + + - name: assert no candidate was found + assert: + that: + - keep_younger is not changed + - keep_younger.replication_controllers == [] + + - name: Ensure second namespace is created + community.okd.k8s: + kind: Namespace + name: '{{ deployment_ns_2 }}' + + - name: Create deployment config from 2nd namespace + community.okd.k8s: + namespace: '{{ deployment_ns_2 }}' + definition: + kind: DeploymentConfig + apiVersion: apps.openshift.io/v1 + metadata: + name: '{{ dc_name }}2' + spec: + replicas: 1 + selector: + name: '{{ dc_name }}2' + template: + metadata: + labels: + name: '{{ dc_name }}2' + spec: + containers: + - name: hello-openshift + imagePullPolicy: IfNotPresent + image: python:3.7-alpine + command: [ "/bin/sh", "-c", "while true;do date;sleep 2s; done"] + wait: yes + + - name: Stop deployment config - replicas = 0 + community.okd.k8s: + namespace: '{{ deployment_ns_2 }}' + definition: + kind: DeploymentConfig + apiVersion: apps.openshift.io/v1 + metadata: + name: '{{ dc_name }}2' + spec: + replicas: 0 + selector: + name: '{{ dc_name }}2' + template: + metadata: + labels: + name: '{{ dc_name }}2' + spec: + containers: + - name: hello-openshift + imagePullPolicy: IfNotPresent + image: python:3.7-alpine + command: [ "/bin/sh", "-c", "while true;do date;sleep 2s; done"] + wait: yes + + - name: Wait for ReplicationController candidate for pruning + kubernetes.core.k8s_info: + kind: ReplicationController + namespace: "{{ deployment_ns_2 }}" + register: result + retries: 10 + delay: 30 + until: + - result.resources.0.metadata.annotations["openshift.io/deployment.phase"] in ("Failed", "Complete") + + # Prune from one namespace should not have any effect on others namespaces + - name: Prune deployments from 2nd namespace + community.okd.openshift_adm_prune_deployments: + namespace: "{{ deployment_ns_2 }}" + check_mode: yes + register: test_prune + + - name: Assure that candidate ReplicationController was found for pruning + assert: + that: + - test_prune is changed + - test_prune.replication_controllers | length == 1 + - "test_prune.replication_controllers.0.metadata.namespace == deployment_ns_2" + + # Prune without namespace option + - name: Prune from all namespace should update more deployments + community.okd.openshift_adm_prune_deployments: + check_mode: yes + register: no_namespace_prune + + - name: Assure multiple ReplicationController were found for pruning + assert: + that: + - no_namespace_prune is changed + - no_namespace_prune.replication_controllers | length == 2 + + # Execute Prune from 2nd namespace + - name: Read ReplicationController before Prune operation + kubernetes.core.k8s_info: + kind: ReplicationController + namespace: "{{ deployment_ns_2 }}" + register: replications + + - assert: + that: + - replications.resources | length == 1 + + - name: Prune DeploymentConfig from 2nd namespace + community.okd.openshift_adm_prune_deployments: + namespace: "{{ deployment_ns_2 }}" + register: _prune + + - name: Assert DeploymentConfig was deleted + assert: + that: + - _prune is changed + - _prune.replication_controllers | length == 1 + - _prune.replication_controllers.0.details.name == replications.resources.0.metadata.name + + # Execute Prune without namespace option + - name: Read ReplicationController before Prune operation + kubernetes.core.k8s_info: + kind: ReplicationController + namespace: "{{ deployment_ns }}" + register: replications + + - assert: + that: + - replications.resources | length == 1 + + - name: Prune from all namespace should update more deployments + community.okd.openshift_adm_prune_deployments: + register: _prune + + - name: Assure multiple ReplicationController were found for pruning + assert: + that: + - _prune is changed + - _prune.replication_controllers | length > 0 + + always: + - name: Delete 1st namespace + community.okd.k8s: + state: absent + kind: Namespace + name: "{{ deployment_ns }}" + ignore_errors: yes + when: deployment_ns is defined + + - name: Delete 2nd namespace + community.okd.k8s: + state: absent + kind: Namespace + name: "{{ deployment_ns_2 }}" + ignore_errors: yes + when: deployment_ns_2 is defined
\ No newline at end of file diff --git a/ansible_collections/community/okd/molecule/default/tasks/openshift_auth.yml b/ansible_collections/community/okd/molecule/default/tasks/openshift_auth.yml new file mode 100644 index 000000000..aeeee4c72 --- /dev/null +++ b/ansible_collections/community/okd/molecule/default/tasks/openshift_auth.yml @@ -0,0 +1,111 @@ +--- +- block: + - set_fact: + admin_user: test + admin_pass: testing123 + + - name: Retrieve cluster info + kubernetes.core.k8s_cluster_info: + register: k8s_cluster + + - name: set openshift host value + set_fact: + openshift_host: "{{ k8s_cluster.connection.host }}" + + - name: Log in (obtain access token) + community.okd.openshift_auth: + username: "{{ admin_user }}" + password: "{{ admin_pass }}" + host: '{{ openshift_host }}' + verify_ssl: false + register: openshift_auth_results + + - set_fact: + auth_api_key: "{{ openshift_auth_results.openshift_auth.api_key }}" + + - name: "Get the {{ admin_user }} User" + kubernetes.core.k8s_info: + api_key: "{{ auth_api_key }}" + host: '{{ openshift_host }}' + verify_ssl: false + kind: User + api_version: user.openshift.io/v1 + name: "{{ admin_user }}" + register: user_result + + - name: assert that the user was found + assert: + that: (user_result.resources | length) == 1 + + - name: list available tokens + kubernetes.core.k8s_info: + kind: UserOAuthAccessToken + version: oauth.openshift.io/v1 + register: tokens + + - debug: var=tokens + + - set_fact: + token_names: "{{ tokens.resources | map(attribute='metadata.name') | list }}" + + - block: + - debug: var=token_names + + - name: Revoke access token + community.okd.openshift_auth: + state: absent + api_key: "{{ auth_api_key }}" + host: '{{ openshift_host }}' + verify_ssl: false + register: _revoke + + - name: Ensure that token has been revoked + assert: + that: + - _revoke is changed + + - name: "Get the {{ admin_user }} User (after token deletion)" + kubernetes.core.k8s_info: + api_key: "{{ auth_api_key }}" + host: '{{ openshift_host }}' + verify_ssl: false + kind: User + api_version: user.openshift.io/v1 + name: "{{ admin_user }}" + ignore_errors: true + retries: 50 + until: user_result is failed + delay: 20 + register: user_result + + - name: Ensure that task has failed due to revoked token + assert: + that: + - user_result is failed + + - name: Revoke access token once again (should fail) + community.okd.openshift_auth: + state: absent + api_key: "{{ auth_api_key }}" + host: '{{ openshift_host }}' + verify_ssl: false + register: _revoke + ignore_errors: true + + - name: Ensure that nothing changed + assert: + that: + - _revoke is failed + - _revoke.msg.startswith("Couldn't delete user oauth access token") + + when: token_names | length > 0 + + always: + - name: If login succeeded, try to log out (revoke access token) + when: auth_api_key is defined + community.okd.openshift_auth: + state: absent + api_key: "{{ auth_api_key }}" + host: '{{ openshift_host }}' + verify_ssl: false + ignore_errors: true diff --git a/ansible_collections/community/okd/molecule/default/tasks/openshift_builds.yml b/ansible_collections/community/okd/molecule/default/tasks/openshift_builds.yml new file mode 100644 index 000000000..b564f8bcd --- /dev/null +++ b/ansible_collections/community/okd/molecule/default/tasks/openshift_builds.yml @@ -0,0 +1,245 @@ +- block: + - set_fact: + build_ns: "builds" + build_config: "start-build" + is_name: "ruby" + prune_build: "prune-build" + + - name: Ensure namespace + kubernetes.core.k8s: + kind: Namespace + name: "{{ build_ns }}" + + - name: Create ImageStream + community.okd.k8s: + namespace: "{{ build_ns }}" + definition: + apiVersion: image.openshift.io/v1 + kind: ImageStream + metadata: + name: "{{ is_name }}" + spec: + lookupPolicy: + local: false + tags: [] + + - name: Create build configuration + community.okd.k8s: + namespace: "{{ build_ns }}" + definition: + kind: BuildConfig + apiVersion: build.openshift.io/v1 + metadata: + name: "{{ build_config }}" + spec: + source: + dockerfile: | + FROM openshift/ruby-22-centos7 + RUN sleep 60s + USER ansible + strategy: + type: Docker + output: + to: + kind: "ImageStreamTag" + name: "{{ is_name }}:latest" + + - name: Start Build from Build configuration + community.okd.openshift_build: + namespace: "{{ build_ns }}" + build_config_name: "{{ build_config }}" + register: new_build + + - name: Assert that a build has been created + assert: + that: + - new_build is changed + - new_build.builds.0.metadata.name == "{{ build_config }}-1" + + - name: Start a new Build from previous Build + community.okd.openshift_build: + namespace: "{{ build_ns }}" + build_name: "{{ new_build.builds.0.metadata.name }}" + register: rerun_build + + - name: Assert that another build has been created + assert: + that: + - rerun_build is changed + - rerun_build.builds.0.metadata.name == "{{ build_config }}-2" + + - name: Cancel first build created + community.okd.openshift_build: + namespace: "{{ build_ns }}" + build_name: "{{ build_config }}-1" + state: cancelled + wait: yes + register: cancel + + - name: Assert that the Build was cancelled + assert: + that: + - cancel is changed + - cancel.builds | length == 1 + - cancel.builds.0.metadata.name == "{{ build_config }}-1" + - cancel.builds.0.metadata.namespace == "{{ build_ns }}" + - cancel.builds.0.status.cancelled + + - name: Get Build info + kubernetes.core.k8s_info: + version: build.openshift.io/v1 + kind: Build + namespace: "{{ build_ns }}" + name: "{{ cancel.builds.0.metadata.name }}" + register: build + + - name: Assert that build phase is cancelled + assert: + that: + - build.resources | length == 1 + - build.resources.0.status.cancelled + - build.resources.0.status.phase == 'Cancelled' + + - name: Cancel and restart Build using build config name + community.okd.openshift_build: + namespace: "{{ build_ns }}" + build_config_name: "{{ build_config }}" + state: restarted + build_phases: + - Running + - New + register: restart + + - name: assert that new build was created + assert: + that: + - restart is changed + - restart.builds | length == 1 + - 'restart.builds.0.metadata.name == "{{ build_config }}-3"' + + - name: Get Build 2 info + kubernetes.core.k8s_info: + version: build.openshift.io/v1 + kind: Build + namespace: "{{ build_ns }}" + name: "{{ build_config }}-2" + register: build + + - name: Assert that build phase is cancelled + assert: + that: + - build.resources | length == 1 + - build.resources.0.status.cancelled + - build.resources.0.status.phase == 'Cancelled' + + - name: Get Build info + kubernetes.core.k8s_info: + version: build.openshift.io/v1 + kind: Build + namespace: "{{ build_ns }}" + name: "{{ build_config }}-3" + register: build + + - name: Assert that Build is not cancelled + assert: + that: + - build.resources | length == 1 + - '"cancelled" not in build.resources.0.status' + - "build.resources.0.status.phase in ('New', 'Pending', 'Running')" + + - name: Prune Builds keep younger than 30min + community.okd.openshift_adm_prune_builds: + keep_younger_than: 30 + namespace: "{{ build_ns }}" + register: prune + check_mode: yes + + - name: Assert that no Builds were found + assert: + that: + - not prune.changed + - prune.builds | length == 0 + + - name: Prune Builds without namespace + community.okd.openshift_adm_prune_builds: + register: prune_without_ns + check_mode: yes + + - name: Assert that completed build are candidate for prune + assert: + that: + - prune_without_ns is changed + - prune_without_ns.builds | length > 0 + - '"{{ build_config }}-1" in build_names' + - '"{{ build_config }}-2" in build_names' + vars: + build_names: '{{ prune_without_ns.builds | map(attribute="metadata") | flatten | map(attribute="name") | list }}' + + - name: Prune Builds using namespace + community.okd.openshift_adm_prune_builds: + namespace: "{{ build_ns }}" + register: prune_with_ns + check_mode: yes + + - name: Assert that prune operation found the completed build + assert: + that: + - prune_with_ns is changed + - prune_with_ns.builds | length == 2 + + - name: Check Build before prune + kubernetes.core.k8s_info: + kind: Build + api_version: build.openshift.io/v1 + name: "{{ build_config }}-1" + namespace: "{{ build_ns }}" + register: resource + + - name: Validate that any previous build operation executed with check_mode did not deleted the build + assert: + that: + - resource.resources | length == 1 + + - name: Execute prune operation + community.okd.openshift_adm_prune_builds: + namespace: "{{ build_ns }}" + register: prune + + - name: assert prune is changed + assert: + that: + - prune is changed + + - name: Check Build + kubernetes.core.k8s_info: + kind: Build + api_version: build.openshift.io/v1 + name: "{{ build_config }}-1" + namespace: "{{ build_ns }}" + register: resource + + - name: Assert that the Build does not exist anymore + assert: + that: + - resource.resources | length == 0 + + - name: Check Build + kubernetes.core.k8s_info: + kind: Build + api_version: build.openshift.io/v1 + name: "{{ build_config }}-2" + namespace: "{{ build_ns }}" + register: resource + + - name: Assert that the Build does not exist anymore + assert: + that: + - resource.resources | length == 0 + + always: + - name: Ensure namespace is deleted + kubernetes.core.k8s: + state: absent + kind: Namespace + name: "{{ build_ns }}" + ignore_errors: true diff --git a/ansible_collections/community/okd/molecule/default/tasks/openshift_import_images.yml b/ansible_collections/community/okd/molecule/default/tasks/openshift_import_images.yml new file mode 100644 index 000000000..04392bb26 --- /dev/null +++ b/ansible_collections/community/okd/molecule/default/tasks/openshift_import_images.yml @@ -0,0 +1,179 @@ +- name: Openshift import image testing + block: + + - set_fact: + test_ns: "import-images" + + - name: Ensure namespace + community.okd.k8s: + kind: Namespace + name: '{{ test_ns }}' + + - name: Import image using tag (should import latest tag only) + community.okd.openshift_import_image: + namespace: "{{ test_ns }}" + name: "ansible/awx" + check_mode: yes + register: import_tag + + - name: Assert only latest was imported + assert: + that: + - import_tag is changed + - import_tag.result | length == 1 + - import_tag.result.0.spec.import + - import_tag.result.0.spec.images.0.from.kind == "DockerImage" + - import_tag.result.0.spec.images.0.from.name == "ansible/awx" + + - name: check image stream + kubernetes.core.k8s_info: + kind: ImageStream + namespace: "{{ test_ns }}" + name: awx + register: resource + + - name: assert that image stream is not created when using check_mode=yes + assert: + that: + - resource.resources == [] + + - name: Import image using tag (should import latest tag only) + community.okd.openshift_import_image: + namespace: "{{ test_ns }}" + name: "ansible/awx" + register: import_tag + + - name: Assert only latest was imported + assert: + that: + - import_tag is changed + + - name: check image stream + kubernetes.core.k8s_info: + kind: ImageStream + namespace: "{{ test_ns }}" + name: awx + register: resource + + - name: assert that image stream contains only tag latest + assert: + that: + - resource.resources | length == 1 + - resource.resources.0.status.tags.0.tag == 'latest' + + - name: Import once again the latest tag + community.okd.openshift_import_image: + namespace: "{{ test_ns }}" + name: "ansible/awx" + register: import_tag + + - name: assert change was performed + assert: + that: + - import_tag is changed + + - name: check image stream + kubernetes.core.k8s_info: + kind: ImageStream + version: image.openshift.io/v1 + namespace: "{{ test_ns }}" + name: awx + register: resource + + - name: assert that image stream still contains unique tag + assert: + that: + - resource.resources | length == 1 + - resource.resources.0.status.tags.0.tag == 'latest' + + - name: Import another tags + community.okd.openshift_import_image: + namespace: "{{ test_ns }}" + name: "ansible/awx:17.1.0" + register: import_another_tag + ignore_errors: yes + + - name: assert that another tag was imported + assert: + that: + - import_another_tag is failed + - '"the tag 17.1.0 does not exist on the image stream" in import_another_tag.msg' + + - name: Create simple ImageStream (without docker external container) + community.okd.k8s: + namespace: "{{ test_ns }}" + name: "local-is" + definition: + apiVersion: image.openshift.io/v1 + kind: ImageStream + spec: + lookupPolicy: + local: false + tags: [] + + - name: Import all tag for image stream not pointing on external container image should failed + community.okd.openshift_import_image: + namespace: "{{ test_ns }}" + name: "local-is" + all: true + register: error_tag + ignore_errors: true + check_mode: yes + + - name: Assert module cannot import from non-existing tag from ImageStream + assert: + that: + - error_tag is failed + - 'error_tag.msg == "image stream {{ test_ns }}/local-is does not have tags pointing to external container images"' + + - name: import all tags for container image ibmcom/pause and specific tag for redhat/ubi8-micro + community.okd.openshift_import_image: + namespace: "{{ test_ns }}" + name: + - "ibmcom/pause" + - "redhat/ubi8-micro:8.5-437" + all: true + register: multiple_import + + - name: Assert that import succeed + assert: + that: + - multiple_import is changed + - multiple_import.result | length == 2 + + - name: Read ibmcom/pause ImageStream + kubernetes.core.k8s_info: + version: image.openshift.io/v1 + kind: ImageStream + namespace: "{{ test_ns }}" + name: pause + register: pause + + - name: assert that ibmcom/pause has multiple tags + assert: + that: + - pause.resources | length == 1 + - pause.resources.0.status.tags | length > 1 + + - name: Read redhat/ubi8-micro ImageStream + kubernetes.core.k8s_info: + version: image.openshift.io/v1 + kind: ImageStream + namespace: "{{ test_ns }}" + name: ubi8-micro + register: resource + + - name: assert that redhat/ubi8-micro has only one tag + assert: + that: + - resource.resources | length == 1 + - resource.resources.0.status.tags | length == 1 + - 'resource.resources.0.status.tags.0.tag == "8.5-437"' + + always: + - name: Delete testing namespace + community.okd.k8s: + state: absent + kind: Namespace + name: "{{ test_ns }}" + ignore_errors: yes diff --git a/ansible_collections/community/okd/molecule/default/tasks/openshift_process.yml b/ansible_collections/community/okd/molecule/default/tasks/openshift_process.yml new file mode 100644 index 000000000..4341bf21c --- /dev/null +++ b/ansible_collections/community/okd/molecule/default/tasks/openshift_process.yml @@ -0,0 +1,183 @@ +--- + +- name: Process a template in the cluster + community.okd.openshift_process: + name: nginx-example + namespace: openshift # only needed if using a template already on the server + parameters: + NAMESPACE: openshift + NAME: test123 + register: result + +- name: Create the rendered resources + community.okd.k8s: + namespace: process-test + definition: '{{ item }}' + wait: yes + apply: yes + loop: '{{ result.resources }}' + +- name: Delete the rendered resources + community.okd.k8s: + namespace: process-test + definition: '{{ item }}' + wait: yes + state: absent + loop: '{{ result.resources }}' + +- name: Process a template and create the resources in the cluster + community.okd.openshift_process: + name: nginx-example + namespace: openshift # only needed if using a template already on the server + parameters: + NAMESPACE: openshift + NAME: test123 + state: present + namespace_target: process-test + register: result + +- name: Process a template and update the resources in the cluster + community.okd.openshift_process: + name: nginx-example + namespace: openshift # only needed if using a template already on the server + parameters: + NAMESPACE: openshift + NAME: test123 + MEMORY_LIMIT: 1Gi + state: present + namespace_target: process-test + register: result + +- name: Process a template and delete the resources in the cluster + community.okd.openshift_process: + name: nginx-example + namespace: openshift # only needed if using a template already on the server + parameters: + NAMESPACE: openshift + NAME: test123 + state: absent + namespace_target: process-test + register: result + +- name: Process a template with parameters from an env file and create the resources + community.okd.openshift_process: + name: nginx-example + namespace: openshift + namespace_target: process-test + parameter_file: '{{ files_dir }}/nginx.env' + state: present + wait: yes + +- name: Process a template with parameters from an env file and delete the resources + community.okd.openshift_process: + name: nginx-example + namespace: openshift + namespace_target: process-test + parameter_file: '{{ files_dir }}/nginx.env' + state: absent + wait: yes + + +- name: Process a template with duplicate values + community.okd.openshift_process: + name: nginx-example + namespace: openshift # only needed if using a template already on the server + parameters: + NAME: test123 + parameter_file: '{{ files_dir }}/nginx.env' + ignore_errors: yes + register: result + +- name: Assert the expected failure occurred + assert: + that: + - result.msg is defined + - result.msg == "Duplicate value for 'NAME' detected in parameter file" + +- name: Process a local template + community.okd.openshift_process: + src: '{{ files_dir }}/simple-template.yaml' + parameter_file: '{{ files_dir }}/example.env' + register: rendered + +- name: Process a local template and create the resources + community.okd.openshift_process: + src: '{{ files_dir }}/simple-template.yaml' + parameter_file: '{{ files_dir }}/example.env' + namespace_target: process-test + state: present + register: result + +- assert: + that: result is changed + +- name: Create the processed resources + community.okd.k8s: + namespace: process-test + definition: '{{ item }}' + loop: '{{ rendered.resources }}' + register: result + +- assert: + that: result is not changed + +- name: Process a local template and create the resources + community.okd.openshift_process: + definition: "{{ lookup('template', files_dir + '/simple-template.yaml') | from_yaml }}" + parameter_file: '{{ files_dir }}/example.env' + namespace_target: process-test + state: present + register: result + +- assert: + that: result is not changed + +- name: Get the created configmap + kubernetes.core.k8s_info: + api_version: v1 + kind: ConfigMap + name: example + namespace: process-test + register: templated_cm + +- assert: + that: + - (templated_cm.resources | length) == 1 + - templated_cm.resources.0.data.content is defined + - templated_cm.resources.0.data.content == "This is a long message that may take one or more lines to parse but should still work without issue" + +- name: Create the Template resource + community.okd.k8s: + src: '{{ files_dir }}/simple-template.yaml' + namespace: process-test + +- name: Process the template and create the resources + community.okd.openshift_process: + name: simple-example + namespace: process-test # only needed if using a template already on the server + namespace_target: process-test + parameter_file: '{{ files_dir }}/example.env' + state: present + register: result + +- assert: + that: result is not changed + +# Processing template without message +- name: create template with file {{ files_dir }}/pod-template.yaml + kubernetes.core.k8s: + namespace: process-test + src: "{{ files_dir }}/pod-template.yaml" + state: present + +- name: Process pod template + community.okd.openshift_process: + name: pod-template + namespace: process-test + state: rendered + parameters: + NAME: ansible + register: rendered_template + +- assert: + that: rendered_template.message == "" diff --git a/ansible_collections/community/okd/molecule/default/tasks/openshift_prune_images.yml b/ansible_collections/community/okd/molecule/default/tasks/openshift_prune_images.yml new file mode 100644 index 000000000..86630da69 --- /dev/null +++ b/ansible_collections/community/okd/molecule/default/tasks/openshift_prune_images.yml @@ -0,0 +1,217 @@ +--- +- name: Read registry information + community.okd.openshift_registry_info: + check: yes + register: registry + +- name: Display registry information + debug: var=registry + +- block: + - set_fact: + prune_ns: "prune-images" + prune_registry: "{{ registry.public_hostname }}" + container: + name: "httpd" + from: "centos/python-38-centos7:20210629-304c7c8" + pod_name: "test-pod" + + - name: Ensure namespace is created + community.okd.k8s: + kind: Namespace + name: "{{ prune_ns }}" + + - name: Import image into internal registry + community.okd.openshift_import_image: + namespace: "{{ prune_ns }}" + name: "{{ container.name }}" + source: "{{ container.from }}" + + - name: Create simple Pod + community.okd.k8s: + namespace: "{{ prune_ns }}" + wait: yes + definition: + apiVersion: v1 + kind: Pod + metadata: + name: "{{ pod_name }}" + spec: + containers: + - name: test-container + image: "{{ prune_registry }}/{{ prune_ns }}/{{ container.name }}:latest" + command: + - /bin/sh + - -c + - while true;do date;sleep 5; done + + - name: Create limit range for images size + community.okd.k8s: + namespace: "{{ prune_ns }}" + definition: + kind: "LimitRange" + metadata: + name: "image-resource-limits" + spec: + limits: + - type: openshift.io/Image + max: + storage: 1Gi + + - name: Prune images from namespace + community.okd.openshift_adm_prune_images: + registry_url: "{{ prune_registry }}" + namespace: "{{ prune_ns }}" + check_mode: yes + register: prune + + - name: Assert that nothing to prune as image is in used + assert: + that: + - prune is not changed + - prune is successful + - prune.deleted_images == [] + - prune.updated_image_streams == [] + + - name: Delete Pod created before + community.okd.k8s: + state: absent + name: "{{ pod_name }}" + kind: Pod + namespace: "{{ prune_ns }}" + wait: yes + + - name: Prune images from namespace + community.okd.openshift_adm_prune_images: + registry_url: "{{ prune_registry }}" + namespace: "{{ prune_ns }}" + check_mode: yes + register: prune + + - name: Read ImageStream + kubernetes.core.k8s_info: + version: image.openshift.io/v1 + kind: ImageStream + namespace: "{{ prune_ns }}" + name: "{{ container.name }}" + register: isinfo + + - set_fact: + is_image_name: "{{ isinfo.resources.0.status.tags[0]['items'].0.image }}" + + - name: Assert that corresponding Image and ImageStream were candidate for pruning + assert: + that: + - prune is changed + - prune.deleted_images | length == 1 + - prune.deleted_images.0.metadata.name == is_image_name + - prune.updated_image_streams | length == 1 + - prune.updated_image_streams.0.metadata.name == container.name + - prune.updated_image_streams.0.metadata.namespace == prune_ns + - prune.updated_image_streams.0.status.tags == [] + + - name: Prune images from namespace keeping images and referrer younger than 60minutes + community.okd.openshift_adm_prune_images: + registry_url: "{{ prune_registry }}" + namespace: "{{ prune_ns }}" + keep_younger_than: 60 + check_mode: yes + register: younger + + - assert: + that: + - younger is not changed + - younger is successful + - younger.deleted_images == [] + - younger.updated_image_streams == [] + + - name: Prune images over size limit + community.okd.openshift_adm_prune_images: + registry_url: "{{ prune_registry }}" + namespace: "{{ prune_ns }}" + prune_over_size_limit: yes + check_mode: yes + register: prune_over_size + + - assert: + that: + - prune_over_size is not changed + - prune_over_size is successful + - prune_over_size.deleted_images == [] + - prune_over_size.updated_image_streams == [] + + - name: Update limit range for images size + community.okd.k8s: + namespace: "{{ prune_ns }}" + definition: + kind: "LimitRange" + metadata: + name: "image-resource-limits" + spec: + limits: + - type: openshift.io/Image + max: + storage: 1Ki + + - name: Prune images over size limit (check_mode=yes) + community.okd.openshift_adm_prune_images: + registry_url: "{{ prune_registry }}" + namespace: "{{ prune_ns }}" + prune_over_size_limit: yes + check_mode: yes + register: prune + + - name: Assert Images and ImageStream were candidate for prune + assert: + that: + - prune is changed + - prune.deleted_images | length == 1 + - prune.deleted_images.0.metadata.name == is_image_name + - prune.updated_image_streams | length == 1 + - prune.updated_image_streams.0.metadata.name == container.name + - prune.updated_image_streams.0.metadata.namespace == prune_ns + - prune.updated_image_streams.0.status.tags == [] + + - name: Prune images over size limit + community.okd.openshift_adm_prune_images: + registry_url: "{{ prune_registry }}" + namespace: "{{ prune_ns }}" + prune_over_size_limit: yes + register: prune + + - name: Assert that Images and ImageStream were candidate for prune + assert: + that: + - prune is changed + - prune.deleted_images | length == 1 + - prune.deleted_images.0.details.name == is_image_name + - prune.updated_image_streams | length == 1 + - prune.updated_image_streams.0.metadata.name == container.name + - prune.updated_image_streams.0.metadata.namespace == prune_ns + - '"tags" not in prune.updated_image_streams.0.status' + + - name: Validate that ImageStream was updated + kubernetes.core.k8s_info: + version: image.openshift.io/v1 + kind: ImageStream + namespace: "{{ prune_ns }}" + name: "{{ container.name }}" + register: stream + + - name: Assert that ImageStream was updated + assert: + that: + - stream.resources | length == 1 + - '"tags" not in stream.resources.0.status' + + always: + - name: Delete namespace + community.okd.k8s: + name: "{{ prune_ns }}" + kind: Namespace + state: absent + ignore_errors: true + + when: + - registry.public_hostname + - registry.check.reached diff --git a/ansible_collections/community/okd/molecule/default/tasks/openshift_route.yml b/ansible_collections/community/okd/molecule/default/tasks/openshift_route.yml new file mode 100644 index 000000000..50056b7e4 --- /dev/null +++ b/ansible_collections/community/okd/molecule/default/tasks/openshift_route.yml @@ -0,0 +1,275 @@ +--- +- name: Create Deployment + community.okd.k8s: + wait: yes + definition: + apiVersion: apps/v1 + kind: Deployment + metadata: + name: hello-kubernetes + namespace: default + spec: + replicas: 3 + selector: + matchLabels: + app: hello-kubernetes + template: + metadata: + labels: + app: hello-kubernetes + spec: + containers: + - name: hello-kubernetes + image: docker.io/openshift/hello-openshift + ports: + - containerPort: 8080 + +- name: Create Service + community.okd.k8s: + wait: yes + definition: + apiVersion: v1 + kind: Service + metadata: + name: hello-kubernetes + namespace: default + spec: + ports: + - port: 80 + targetPort: 8080 + selector: + app: hello-kubernetes + +- name: Create Route with fewest possible arguments + community.okd.openshift_route: + service: hello-kubernetes + namespace: default + register: route + +- name: Attempt to hit http URL + uri: + url: 'http://{{ route.result.spec.host }}' + return_content: yes + until: result is successful + retries: 20 + register: result + +- name: Assert the page content is as expected + assert: + that: + - not result.redirected + - result.status == 200 + - result.content == 'Hello OpenShift!\n' + +- name: Delete route + community.okd.openshift_route: + name: '{{ route.result.metadata.name }}' + namespace: default + state: absent + wait: yes + +- name: Create Route with custom name and wait + community.okd.openshift_route: + service: hello-kubernetes + namespace: default + name: test1 + wait: yes + register: route + +- name: Assert that the condition is properly set + assert: + that: + - route.duration is defined + - route.result.status.ingress.0.conditions.0.type == 'Admitted' + - route.result.status.ingress.0.conditions.0.status == 'True' + +- name: Attempt to hit http URL + uri: + url: 'http://{{ route.result.spec.host }}' + return_content: yes + until: result is successful + retries: 20 + register: result + +- name: Assert the page content is as expected + assert: + that: + - not result.redirected + - result.status == 200 + - result.content == 'Hello OpenShift!\n' + +- name: Delete route + community.okd.openshift_route: + name: '{{ route.result.metadata.name }}' + namespace: default + state: absent + wait: yes + +- name: Create edge-terminated route that allows insecure traffic + community.okd.openshift_route: + service: hello-kubernetes + namespace: default + name: hello-kubernetes-https + tls: + insecure_policy: allow + termination: edge + register: route + +- name: Attempt to hit http URL + uri: + url: 'http://{{ route.result.spec.host }}' + return_content: yes + until: result is successful + retries: 20 + register: result + +- name: Assert the page content is as expected + assert: + that: + - not result.redirected + - result.status == 200 + - result.content == 'Hello OpenShift!\n' + +- name: Attempt to hit https URL + uri: + url: 'https://{{ route.result.spec.host }}' + validate_certs: no + return_content: yes + until: result is successful + retries: 10 + register: result + +- name: Assert the page content is as expected + assert: + that: + - not result.redirected + - result.status == 200 + - result.content == 'Hello OpenShift!\n' + +- name: Alter edge-terminated route to redirect insecure traffic + community.okd.openshift_route: + service: hello-kubernetes + namespace: default + name: hello-kubernetes-https + tls: + insecure_policy: redirect + termination: edge + register: route + +- name: Attempt to hit http URL + uri: + url: 'http://{{ route.result.spec.host }}' + return_content: yes + validate_certs: no + until: + - result is successful + - result.redirected + retries: 10 + register: result + +- name: Assert the page content is as expected + assert: + that: + - result.redirected + - result.status == 200 + - result.content == 'Hello OpenShift!\n' + +- name: Attempt to hit https URL + uri: + url: 'https://{{ route.result.spec.host }}' + validate_certs: no + return_content: yes + until: result is successful + retries: 20 + register: result + +- name: Assert the page content is as expected + assert: + that: + - not result.redirected + - result.status == 200 + - result.content == 'Hello OpenShift!\n' + +- name: Alter edge-terminated route with insecure traffic disabled + community.okd.openshift_route: + service: hello-kubernetes + namespace: default + name: hello-kubernetes-https + tls: + insecure_policy: disallow + termination: edge + register: route + +- debug: var=route + +- name: Attempt to hit https URL + uri: + url: 'https://{{ route.result.spec.host }}' + validate_certs: no + return_content: yes + until: result is successful + retries: 20 + register: result + +- name: Assert the page content is as expected + assert: + that: + - not result.redirected + - result.status == 200 + - result.content == 'Hello OpenShift!\n' + +- name: Attempt to hit http URL + uri: + url: 'http://{{ route.result.spec.host }}' + status_code: 503 + until: result is successful + retries: 20 + register: result + +- debug: var=result + +- name: Assert the page content is as expected + assert: + that: + - not result.redirected + - result.status == 503 + +- name: Delete route + community.okd.openshift_route: + name: '{{ route.result.metadata.name }}' + namespace: default + state: absent + wait: yes + +# Route with labels and annotations +- name: Create route with labels and annotations + community.okd.openshift_route: + service: hello-kubernetes + namespace: default + name: route-label-annotation + labels: + ansible: test + annotations: + haproxy.router.openshift.io/balance: roundrobin + +- name: Get route information + kubernetes.core.k8s_info: + api_version: route.openshift.io/v1 + kind: Route + name: route-label-annotation + namespace: default + register: route + +- assert: + that: + - route.resources[0].metadata.annotations is defined + - '"haproxy.router.openshift.io/balance" in route.resources[0].metadata.annotations' + - route.resources[0].metadata.labels is defined + - '"ansible" in route.resources[0].metadata.labels' + +- name: Delete route + community.okd.openshift_route: + name: route-label-annotation + namespace: default + state: absent + wait: yes diff --git a/ansible_collections/community/okd/molecule/default/tasks/validate_installed.yml b/ansible_collections/community/okd/molecule/default/tasks/validate_installed.yml new file mode 100644 index 000000000..4508efdd6 --- /dev/null +++ b/ansible_collections/community/okd/molecule/default/tasks/validate_installed.yml @@ -0,0 +1,122 @@ +--- +- block: + - name: Create a project + community.okd.k8s: + name: "{{ playbook_namespace }}" + kind: Project + api_version: project.openshift.io/v1 + + - name: incredibly simple ConfigMap + community.okd.k8s: + definition: + apiVersion: v1 + kind: ConfigMap + metadata: + name: hello + namespace: "{{ playbook_namespace }}" + validate: + fail_on_error: yes + register: k8s_with_validate + + - name: assert that k8s_with_validate succeeds + assert: + that: + - k8s_with_validate is successful + + - name: extra property does not fail without strict + community.okd.k8s: + src: "files/kuard-extra-property.yml" + namespace: "{{ playbook_namespace }}" + validate: + fail_on_error: yes + strict: no + + - name: extra property fails with strict + community.okd.k8s: + src: "files/kuard-extra-property.yml" + namespace: "{{ playbook_namespace }}" + validate: + fail_on_error: yes + strict: yes + ignore_errors: yes + register: extra_property + + - name: check that extra property fails with strict + assert: + that: + - extra_property is failed + + - name: invalid type fails at validation stage + community.okd.k8s: + src: "files/kuard-invalid-type.yml" + namespace: "{{ playbook_namespace }}" + validate: + fail_on_error: yes + strict: no + ignore_errors: yes + register: invalid_type + + - name: check that invalid type fails + assert: + that: + - invalid_type is failed + + - name: invalid type fails with warnings when fail_on_error is False + community.okd.k8s: + src: "files/kuard-invalid-type.yml" + namespace: "{{ playbook_namespace }}" + validate: + fail_on_error: no + strict: no + ignore_errors: yes + register: invalid_type_no_fail + + - name: check that invalid type fails + assert: + that: + - invalid_type_no_fail is failed + + - name: setup custom resource definition + community.okd.k8s: + src: "files/setup-crd.yml" + + - name: wait a few seconds + pause: + seconds: 5 + + - name: add custom resource definition + community.okd.k8s: + src: "files/crd-resource.yml" + namespace: "{{ playbook_namespace }}" + validate: + fail_on_error: yes + strict: yes + register: unknown_kind + + - name: check that unknown kind warns + assert: + that: + - unknown_kind is successful + + always: + - name: remove custom resource + community.okd.k8s: + definition: "{{ lookup('file', 'files/crd-resource.yml') }}" + namespace: "{{ playbook_namespace }}" + state: absent + ignore_errors: yes + + - name: remove custom resource definitions + community.okd.k8s: + definition: "{{ lookup('file', 'files/setup-crd.yml') }}" + state: absent + + - name: Delete namespace + community.okd.k8s: + state: absent + definition: + - kind: Project + apiVersion: project.openshift.io/v1 + metadata: + name: "{{ playbook_namespace }}" + ignore_errors: yes diff --git a/ansible_collections/community/okd/molecule/default/tasks/validate_not_installed.yml b/ansible_collections/community/okd/molecule/default/tasks/validate_not_installed.yml new file mode 100644 index 000000000..a64607ce0 --- /dev/null +++ b/ansible_collections/community/okd/molecule/default/tasks/validate_not_installed.yml @@ -0,0 +1,25 @@ +--- +# TODO: Not available in ansible-base +# - python_requirements_info: +# dependencies: +# - openshift +# - kubernetes +# - kubernetes-validate + +- community.okd.k8s: + definition: + apiVersion: v1 + kind: ConfigMap + metadata: + name: hello + namespace: default + validate: + fail_on_error: yes + ignore_errors: yes + register: k8s_no_validate + +- name: assert that k8s_no_validate fails gracefully + assert: + that: + - k8s_no_validate is failed + - k8s_no_validate.msg.startswith('Failed to import the required Python library (kubernetes-validate)') diff --git a/ansible_collections/community/okd/molecule/default/vars/main.yml b/ansible_collections/community/okd/molecule/default/vars/main.yml new file mode 100644 index 000000000..66fb0d33c --- /dev/null +++ b/ansible_collections/community/okd/molecule/default/vars/main.yml @@ -0,0 +1,94 @@ +--- +k8s_pod_annotations: {} + +k8s_pod_metadata: + labels: + app: '{{ k8s_pod_name }}' + annotations: '{{ k8s_pod_annotations }}' + +k8s_pod_spec: + serviceAccount: "{{ k8s_pod_service_account }}" + containers: + - image: "{{ k8s_pod_image }}" + imagePullPolicy: Always + name: "{{ k8s_pod_name }}" + command: "{{ k8s_pod_command }}" + readinessProbe: + initialDelaySeconds: 15 + exec: + command: + - /bin/true + resources: "{{ k8s_pod_resources }}" + ports: "{{ k8s_pod_ports }}" + env: "{{ k8s_pod_env }}" + +k8s_pod_service_account: default + +k8s_pod_resources: + limits: + cpu: "100m" + memory: "100Mi" + +k8s_pod_command: [] + +k8s_pod_ports: [] + +k8s_pod_env: [] + +k8s_pod_template: + metadata: "{{ k8s_pod_metadata }}" + spec: "{{ k8s_pod_spec }}" + +k8s_deployment_spec: + template: '{{ k8s_pod_template }}' + selector: + matchLabels: + app: '{{ k8s_pod_name }}' + replicas: 1 + +k8s_deployment_template: + apiVersion: apps/v1 + kind: Deployment + spec: '{{ k8s_deployment_spec }}' + +okd_dc_triggers: + - type: ConfigChange + - type: ImageChange + imageChangeParams: + automatic: true + containerNames: + - '{{ k8s_pod_name }}' + from: + kind: ImageStreamTag + name: '{{ image_name }}:{{ image_tag }}' + +okd_dc_spec: + template: '{{ k8s_pod_template }}' + triggers: '{{ okd_dc_triggers }}' + replicas: 1 + strategy: + type: Recreate + +okd_dc_template: + apiVersion: v1 + kind: DeploymentConfig + spec: '{{ okd_dc_spec }}' + +okd_imagestream_template: + apiVersion: image.openshift.io/v1 + kind: ImageStream + metadata: + name: '{{ image_name }}' + spec: + lookupPolicy: + local: true + tags: + - annotations: null + from: + kind: DockerImage + name: '{{ image }}' + name: '{{ image_tag }}' + referencePolicy: + type: Source + +image_tag: latest diff --git a/ansible_collections/community/okd/molecule/default/verify.yml b/ansible_collections/community/okd/molecule/default/verify.yml new file mode 100644 index 000000000..b787062aa --- /dev/null +++ b/ansible_collections/community/okd/molecule/default/verify.yml @@ -0,0 +1,89 @@ +--- +- name: Verify inventory and connection plugins + # This group is created by the openshift_inventory plugin + # It is automatically configured to use the `oc` connection plugin + hosts: namespace_testing_pods + gather_facts: no + vars: + file_content: | + Hello world + tasks: + - name: End play if host not running (TODO should we not add these to the inventory?) + meta: end_host + when: pod_phase != "Running" + + - setup: + + - debug: var=ansible_facts + + - name: Assert the TEST environment variable was retrieved + assert: + that: ansible_facts.env.TEST == 'test' + + - name: Copy a file into the host + copy: + content: '{{ file_content }}' + dest: /tmp/test_file + + - name: Retrieve the file from the host + slurp: + src: /tmp/test_file + register: slurped_file + + - name: Assert the file content matches expectations + assert: + that: (slurped_file.content|b64decode) == file_content + + +- name: Verify + hosts: localhost + connection: local + gather_facts: no + vars: + ansible_python_interpreter: '{{ virtualenv_interpreter }}' + + tasks: + - pip: + name: kubernetes-validate==1.12.0 + virtualenv: "{{ virtualenv }}" + virtualenv_command: "{{ virtualenv_command }}" + virtualenv_site_packages: no + + - import_tasks: tasks/validate_installed.yml + + - pip: + name: kubernetes-validate + state: absent + virtualenv: "{{ virtualenv }}" + virtualenv_command: "{{ virtualenv_command }}" + virtualenv_site_packages: no + + - import_tasks: tasks/validate_not_installed.yml + + - import_tasks: tasks/openshift_auth.yml + - import_tasks: tasks/openshift_adm_prune_auth_clusterroles.yml + - import_tasks: tasks/openshift_adm_prune_auth_roles.yml + - import_tasks: tasks/openshift_adm_prune_deployments.yml + - import_tasks: tasks/openshift_builds.yml + - import_tasks: tasks/openshift_route.yml + - import_tasks: tasks/openshift_import_images.yml + - import_tasks: tasks/openshift_prune_images.yml + - block: + - name: Create namespace + community.okd.k8s: + api_version: v1 + kind: Namespace + name: process-test + - import_tasks: tasks/openshift_process.yml + vars: + files_dir: '{{ playbook_dir }}/files' + always: + - name: Delete namespace + community.okd.k8s: + api_version: v1 + kind: Namespace + name: process-test + state: absent + + roles: + - role: openshift_adm_groups |