diff options
40 files changed, 991 insertions, 138 deletions
diff --git a/.tito/packages/openshift-ansible b/.tito/packages/openshift-ansible index 49ecde422..13ff44567 100644 --- a/.tito/packages/openshift-ansible +++ b/.tito/packages/openshift-ansible @@ -1 +1 @@ -3.6.21-1 ./ +3.6.22-1 ./ diff --git a/openshift-ansible.spec b/openshift-ansible.spec index 4a69537fe..166d21918 100644 --- a/openshift-ansible.spec +++ b/openshift-ansible.spec @@ -9,7 +9,7 @@  %global __requires_exclude ^/usr/bin/ansible-playbook$  Name:           openshift-ansible -Version:        3.6.21 +Version:        3.6.22  Release:        1%{?dist}  Summary:        Openshift and Atomic Enterprise Ansible  License:        ASL 2.0 @@ -270,6 +270,17 @@ Atomic OpenShift Utilities includes  %changelog +* Wed Apr 12 2017 Jenkins CD Merge Bot <tdawson@redhat.com> 3.6.22-1 +- Fixed spelling mistake. (kwoodson@redhat.com) +- Remove unnecessary folder refs (rteague@redhat.com) +- Switching commands for modules during upgrade of router and registry. +  (kwoodson@redhat.com) +- Fixing a compatibility issue with python 2.7 to 3.5 when reading from +  subprocess. (kwoodson@redhat.com) +- Refactor use of initialize_oo_option_facts.yml (rteague@redhat.com) +- preflight checks: refactor and fix aos_version (lmeyer@redhat.com) +- Add external provisioners playbook starting with aws efs (mawong@redhat.com) +  * Tue Apr 11 2017 Jenkins CD Merge Bot <tdawson@redhat.com> 3.6.21-1  - Adding a query for the existing docker-registry route. (kwoodson@redhat.com)  - Removing docker-registry route from cockpit-ui. (kwoodson@redhat.com) diff --git a/playbooks/common/openshift-cluster/config.yml b/playbooks/common/openshift-cluster/config.yml index 1b967b7f1..3c70db6a9 100644 --- a/playbooks/common/openshift-cluster/config.yml +++ b/playbooks/common/openshift-cluster/config.yml @@ -1,30 +1,7 @@  --- -- name: Set oo_option facts -  hosts: oo_all_hosts +- include: initialize_oo_option_facts.yml    tags:    - always -  tasks: -  - set_fact: -      openshift_docker_additional_registries: "{{ lookup('oo_option', 'docker_additional_registries') }}" -    when: openshift_docker_additional_registries is not defined -  - set_fact: -      openshift_docker_insecure_registries: "{{ lookup('oo_option',  'docker_insecure_registries') }}" -    when: openshift_docker_insecure_registries is not defined -  - set_fact: -      openshift_docker_blocked_registries: "{{ lookup('oo_option', 'docker_blocked_registries') }}" -    when: openshift_docker_blocked_registries is not defined -  - set_fact: -      openshift_docker_options: "{{ lookup('oo_option', 'docker_options') }}" -    when: openshift_docker_options is not defined -  - set_fact: -      openshift_docker_log_driver: "{{ lookup('oo_option', 'docker_log_driver') }}" -    when: openshift_docker_log_driver is not defined -  - set_fact: -      openshift_docker_log_options: "{{ lookup('oo_option', 'docker_log_options') }}" -    when: openshift_docker_log_options is not defined -  - set_fact: -      openshift_docker_selinux_enabled: "{{ lookup('oo_option', 'docker_selinux_enabled') }}" -    when: openshift_docker_selinux_enabled is not defined  - include: disable_excluder.yml    tags: diff --git a/playbooks/common/openshift-cluster/initialize_oo_option_facts.yml b/playbooks/common/openshift-cluster/initialize_oo_option_facts.yml new file mode 100644 index 000000000..ac3c702a0 --- /dev/null +++ b/playbooks/common/openshift-cluster/initialize_oo_option_facts.yml @@ -0,0 +1,27 @@ +--- +- name: Set oo_option facts +  hosts: oo_all_hosts +  tags: +  - always +  tasks: +  - set_fact: +      openshift_docker_additional_registries: "{{ lookup('oo_option', 'docker_additional_registries') }}" +    when: openshift_docker_additional_registries is not defined +  - set_fact: +      openshift_docker_insecure_registries: "{{ lookup('oo_option',  'docker_insecure_registries') }}" +    when: openshift_docker_insecure_registries is not defined +  - set_fact: +      openshift_docker_blocked_registries: "{{ lookup('oo_option', 'docker_blocked_registries') }}" +    when: openshift_docker_blocked_registries is not defined +  - set_fact: +      openshift_docker_options: "{{ lookup('oo_option', 'docker_options') }}" +    when: openshift_docker_options is not defined +  - set_fact: +      openshift_docker_log_driver: "{{ lookup('oo_option', 'docker_log_driver') }}" +    when: openshift_docker_log_driver is not defined +  - set_fact: +      openshift_docker_log_options: "{{ lookup('oo_option', 'docker_log_options') }}" +    when: openshift_docker_log_options is not defined +  - set_fact: +      openshift_docker_selinux_enabled: "{{ lookup('oo_option', 'docker_selinux_enabled') }}" +    when: openshift_docker_selinux_enabled is not defined diff --git a/playbooks/common/openshift-cluster/openshift_provisioners.yml b/playbooks/common/openshift-cluster/openshift_provisioners.yml new file mode 100644 index 000000000..b1ca6f606 --- /dev/null +++ b/playbooks/common/openshift-cluster/openshift_provisioners.yml @@ -0,0 +1,5 @@ +--- +- name: OpenShift Provisioners +  hosts: oo_first_master +  roles: +  - openshift_provisioners diff --git a/playbooks/common/openshift-cluster/redeploy-certificates/ca.yml b/playbooks/common/openshift-cluster/redeploy-certificates/ca.yml index cbb4a2434..3b26abcc7 100644 --- a/playbooks/common/openshift-cluster/redeploy-certificates/ca.yml +++ b/playbooks/common/openshift-cluster/redeploy-certificates/ca.yml @@ -130,7 +130,7 @@        state: absent      changed_when: false -- include: ../../../common/openshift-etcd/restart.yml +- include: ../openshift-etcd/restart.yml  # Update master config when ca-bundle not referenced. Services will be  # restarted below after new CA certificate has been distributed. @@ -322,7 +322,7 @@        group: "{{ 'root' if item == 'root' else _ansible_ssh_user_gid.stdout  }}"      with_items: "{{ client_users }}" -- include: ../../../common/openshift-master/restart.yml +- include: ../openshift-master/restart.yml  - name: Distribute OpenShift CA certificate to nodes    hosts: oo_nodes_to_config @@ -371,4 +371,4 @@        state: absent      changed_when: false -- include: ../../../common/openshift-node/restart.yml +- include: ../openshift-node/restart.yml diff --git a/playbooks/common/openshift-cluster/upgrades/init.yml b/playbooks/common/openshift-cluster/upgrades/init.yml index 01d151eb9..cc1fa5a0a 100644 --- a/playbooks/common/openshift-cluster/upgrades/init.yml +++ b/playbooks/common/openshift-cluster/upgrades/init.yml @@ -30,27 +30,7 @@      g_new_node_hosts: []      openshift_cluster_id: "{{ cluster_id | default('default') }}" -- name: Set oo_options -  hosts: oo_all_hosts -  tasks: -  - set_fact: -      openshift_docker_additional_registries: "{{ lookup('oo_option', 'docker_additional_registries') }}" -    when: openshift_docker_additional_registries is not defined -  - set_fact: -      openshift_docker_insecure_registries: "{{ lookup('oo_option',  'docker_insecure_registries') }}" -    when: openshift_docker_insecure_registries is not defined -  - set_fact: -      openshift_docker_blocked_registries: "{{ lookup('oo_option', 'docker_blocked_registries') }}" -    when: openshift_docker_blocked_registries is not defined -  - set_fact: -      openshift_docker_options: "{{ lookup('oo_option', 'docker_options') }}" -    when: openshift_docker_options is not defined -  - set_fact: -      openshift_docker_log_driver: "{{ lookup('oo_option', 'docker_log_driver') }}" -    when: openshift_docker_log_driver is not defined -  - set_fact: -      openshift_docker_log_options: "{{ lookup('oo_option', 'docker_log_options') }}" -    when: openshift_docker_log_options is not defined +- include: ../initialize_oo_option_facts.yml  - include: ../initialize_facts.yml diff --git a/playbooks/common/openshift-cluster/upgrades/post_control_plane.yml b/playbooks/common/openshift-cluster/upgrades/post_control_plane.yml index c00795a8d..0d7cdb227 100644 --- a/playbooks/common/openshift-cluster/upgrades/post_control_plane.yml +++ b/playbooks/common/openshift-cluster/upgrades/post_control_plane.yml @@ -5,9 +5,10 @@  - name: Upgrade default router and default registry    hosts: oo_first_master    vars: -    registry_image: "{{  openshift.master.registry_url | replace( '${component}', 'docker-registry' )  | replace ( '${version}', openshift_image_tag ) }}" -    router_image: "{{ openshift.master.registry_url | replace( '${component}', 'haproxy-router' ) | replace ( '${version}', openshift_image_tag ) }}" -    oc_cmd: "{{ openshift.common.client_binary }} --config={{ openshift.common.config_base }}/master/admin.kubeconfig" +    registry_image: "{{  openshift.master.registry_url | replace( '${component}', 'docker-registry' )  | +                         replace ( '${version}', openshift_image_tag ) }}" +    router_image: "{{ openshift.master.registry_url | replace( '${component}', 'haproxy-router' ) | +                      replace ( '${version}', openshift_image_tag ) }}"    pre_tasks:    - name: Load lib_openshift modules @@ -21,7 +22,10 @@        selector: 'router'      register: all_routers -  - set_fact: haproxy_routers="{{ all_routers.results.results[0]['items'] | oo_pods_match_component(openshift_deployment_type, 'haproxy-router') | oo_select_keys_from_list(['metadata']) }}" +  - set_fact: +      haproxy_routers: "{{ all_routers.results.results[0]['items'] | +                           oo_pods_match_component(openshift_deployment_type, 'haproxy-router') | +                           oo_select_keys_from_list(['metadata']) }}"      when:      - all_routers.results.returncode == 0 @@ -30,16 +34,15 @@      - all_routers.results.returncode != 0    - name: Update router image to current version +    oc_edit: +      kind: dc +      name: "{{ item['labels']['deploymentconfig'] }}" +      namespace: "{{ item['namespace'] }}" +      content: +        spec.template.spec.containers[0].image: "{{ router_image }}" +    with_items: "{{ haproxy_routers }}"      when:      - all_routers.results.returncode == 0 -    command: > -      {{ oc_cmd }} patch dc/{{ item['labels']['deploymentconfig'] }} -n {{ item['namespace'] }} -p -      '{"spec":{"template":{"spec":{"containers":[{"name":"router","image":"{{ router_image }}","livenessProbe":{"tcpSocket":null,"httpGet":{"path": "/healthz", "port": 1936, "host": "localhost", "scheme": "HTTP"},"initialDelaySeconds":10,"timeoutSeconds":1}}]}}}}' -      --api-version=v1 -    with_items: "{{ haproxy_routers }}" -    # AUDIT:changed_when_note: `false` not being set here. What we -    # need to do is check the current router image version and see if -    # this task needs to be ran.    - name: Check for default registry      oc_obj: @@ -49,15 +52,14 @@      register: _default_registry    - name: Update registry image to current version +    oc_edit: +      kind: dc +      name: docker-registry +      namespace: default +      content: +        spec.template.spec.containers[0].image: "{{ registry_image }}"      when:      - _default_registry.results.results[0] != {} -    command: > -      {{ oc_cmd }} patch dc/docker-registry -n default -p -      '{"spec":{"template":{"spec":{"containers":[{"name":"registry","image":"{{ registry_image }}"}]}}}}' -      --api-version=v1 -    # AUDIT:changed_when_note: `false` not being set here. What we -    # need to do is check the current registry image version and see -    # if this task needs to be ran.    roles:    - openshift_manageiq diff --git a/playbooks/common/openshift-master/restart.yml b/playbooks/common/openshift-master/restart.yml index b35368bf1..6fec346c3 100644 --- a/playbooks/common/openshift-master/restart.yml +++ b/playbooks/common/openshift-master/restart.yml @@ -1,5 +1,5 @@  --- -- include: ../../common/openshift-master/validate_restart.yml +- include: validate_restart.yml  - name: Restart masters    hosts: oo_masters_to_config @@ -12,8 +12,8 @@    roles:    - openshift_facts    post_tasks: -  - include: ../../common/openshift-master/restart_hosts.yml +  - include: restart_hosts.yml      when: openshift_rolling_restart_mode | default('services') == 'system' -  - include: ../../common/openshift-master/restart_services.yml +  - include: restart_services.yml      when: openshift_rolling_restart_mode | default('services') == 'services' diff --git a/roles/lib_openshift/library/oc_adm_ca_server_cert.py b/roles/lib_openshift/library/oc_adm_ca_server_cert.py index c69f5deda..4d083c4d5 100644 --- a/roles/lib_openshift/library/oc_adm_ca_server_cert.py +++ b/roles/lib_openshift/library/oc_adm_ca_server_cert.py @@ -1508,7 +1508,7 @@ class CAServerCert(OpenShiftCLI):          x509output, _ = proc.communicate()          if proc.returncode == 0:              regex = re.compile(r"^\s*X509v3 Subject Alternative Name:\s*?\n\s*(.*)\s*\n", re.MULTILINE) -            match = regex.search(x509output)  # E501 +            match = regex.search(x509output.decode())  # E501              if not match:                  return False diff --git a/roles/lib_openshift/src/class/oc_adm_ca_server_cert.py b/roles/lib_openshift/src/class/oc_adm_ca_server_cert.py index f954f40ef..cf99a6584 100644 --- a/roles/lib_openshift/src/class/oc_adm_ca_server_cert.py +++ b/roles/lib_openshift/src/class/oc_adm_ca_server_cert.py @@ -77,7 +77,7 @@ class CAServerCert(OpenShiftCLI):          x509output, _ = proc.communicate()          if proc.returncode == 0:              regex = re.compile(r"^\s*X509v3 Subject Alternative Name:\s*?\n\s*(.*)\s*\n", re.MULTILINE) -            match = regex.search(x509output)  # E501 +            match = regex.search(x509output.decode())  # E501              if not match:                  return False diff --git a/roles/openshift_health_checker/library/aos_version.py b/roles/openshift_health_checker/library/aos_version.py index 191a4b107..a46589443 100755 --- a/roles/openshift_health_checker/library/aos_version.py +++ b/roles/openshift_health_checker/library/aos_version.py @@ -1,91 +1,199 @@  #!/usr/bin/python  # vim: expandtab:tabstop=4:shiftwidth=4  ''' -Ansible module for determining if multiple versions of an OpenShift package are -available, and if the version requested is available down to the given -precision. - -Multiple versions available suggest that multiple repos are enabled for the -different versions, which may cause installation problems. +Ansible module for yum-based systems determining if multiple releases +of an OpenShift package are available, and if the release requested +(if any) is available down to the given precision. + +For Enterprise, multiple releases available suggest that multiple repos +are enabled for the different releases, which may cause installation +problems. With Origin, however, this is a normal state of affairs as +all the releases are provided in a single repo with the expectation that +only the latest can be installed. + +Code in the openshift_version role contains a lot of logic to pin down +the exact package and image version to use and so does some validation +of release availability already. Without duplicating all that, we would +like the user to have a helpful error message if we detect things will +not work out right. Note that if openshift_release is not specified in +the inventory, the version comparison checks just pass. + +TODO: fail gracefully on non-yum systems (dnf in Fedora)  ''' -import yum  # pylint: disable=import-error -  from ansible.module_utils.basic import AnsibleModule +IMPORT_EXCEPTION = None +try: +    import yum  # pylint: disable=import-error +except ImportError as err: +    IMPORT_EXCEPTION = err  # in tox test env, yum import fails + -def main():  # pylint: disable=missing-docstring,too-many-branches +class AosVersionException(Exception): +    '''Base exception class for package version problems''' +    def __init__(self, message, problem_pkgs=None): +        Exception.__init__(self, message) +        self.problem_pkgs = problem_pkgs + + +def main(): +    '''Entrypoint for this Ansible module'''      module = AnsibleModule(          argument_spec=dict( -            prefix=dict(required=True),  # atomic-openshift, origin, ... -            version=dict(required=True), +            requested_openshift_release=dict(type="str", default=''), +            openshift_deployment_type=dict(required=True), +            rpm_prefix=dict(required=True),  # atomic-openshift, origin, ...?          ),          supports_check_mode=True      ) -    def bail(error):  # pylint: disable=missing-docstring -        module.fail_json(msg=error) - -    rpm_prefix = module.params['prefix'] +    if IMPORT_EXCEPTION: +        module.fail_json(msg="aos_version module could not import yum: %s" % IMPORT_EXCEPTION) +    # determine the packages we will look for +    rpm_prefix = module.params['rpm_prefix']      if not rpm_prefix: -        bail("prefix must not be empty") - -    yb = yum.YumBase()  # pylint: disable=invalid-name -    yb.conf.disable_excludes = ["all"]  # assume the openshift excluder will be managed, ignore current state - -    # search for package versions available for aos pkgs -    expected_pkgs = [ +        module.fail_json(msg="rpm_prefix must not be empty") +    expected_pkgs = set([          rpm_prefix,          rpm_prefix + '-master',          rpm_prefix + '-node', -    ] +    ]) + +    # determine what level of precision the user specified for the openshift version. +    # should look like a version string with possibly many segments e.g. "3.4.1": +    requested_openshift_release = module.params['requested_openshift_release'] + +    # get the list of packages available and complain if anything is wrong +    try: +        pkgs = _retrieve_available_packages(expected_pkgs) +        if requested_openshift_release: +            _check_precise_version_found(pkgs, expected_pkgs, requested_openshift_release) +            _check_higher_version_found(pkgs, expected_pkgs, requested_openshift_release) +        if module.params['openshift_deployment_type'] in ['openshift-enterprise']: +            _check_multi_minor_release(pkgs, expected_pkgs) +    except AosVersionException as excinfo: +        module.fail_json(msg=str(excinfo)) +    module.exit_json(changed=False) + + +def _retrieve_available_packages(expected_pkgs): +    # search for package versions available for openshift pkgs +    yb = yum.YumBase()  # pylint: disable=invalid-name + +    # The openshift excluder prevents unintended updates to openshift +    # packages by setting yum excludes on those packages. See: +    # https://wiki.centos.org/SpecialInterestGroup/PaaS/OpenShift-Origin-Control-Updates +    # Excludes are then disabled during an install or upgrade, but +    # this check will most likely be running outside either. When we +    # attempt to determine what packages are available via yum they may +    # be excluded. So, for our purposes here, disable excludes to see +    # what will really be available during an install or upgrade. +    yb.conf.disable_excludes = ['all'] +      try:          pkgs = yb.pkgSack.returnPackages(patterns=expected_pkgs) -    except yum.Errors.PackageSackError as e:  # pylint: disable=invalid-name +    except yum.Errors.PackageSackError as excinfo:          # you only hit this if *none* of the packages are available -        bail('Unable to find any OpenShift packages.\nCheck your subscription and repo settings.\n%s' % e) +        raise AosVersionException('\n'.join([ +            'Unable to find any OpenShift packages.', +            'Check your subscription and repo settings.', +            str(excinfo), +        ])) +    return pkgs -    # determine what level of precision we're expecting for the version -    expected_version = module.params['version'] -    if expected_version.startswith('v'):  # v3.3 => 3.3 -        expected_version = expected_version[1:] -    num_dots = expected_version.count('.') -    pkgs_by_name_version = {} +class PreciseVersionNotFound(AosVersionException): +    '''Exception for reporting packages not available at given release''' +    def __init__(self, requested_release, not_found): +        msg = ['Not all of the required packages are available at requested version %s:' % requested_release] +        msg += ['  ' + name for name in not_found] +        msg += ['Please check your subscriptions and enabled repositories.'] +        AosVersionException.__init__(self, '\n'.join(msg), not_found) + + +def _check_precise_version_found(pkgs, expected_pkgs, requested_openshift_release): +    # see if any packages couldn't be found at requested release version +    # we would like to verify that the latest available pkgs have however specific a version is given. +    # so e.g. if there is a package version 3.4.1.5 the check passes; if only 3.4.0, it fails. +      pkgs_precise_version_found = {}      for pkg in pkgs: -        # get expected version precision -        match_version = '.'.join(pkg.version.split('.')[:num_dots + 1]) -        if match_version == expected_version: +        if pkg.name not in expected_pkgs: +            continue +        # does the version match, to the precision requested? +        # and, is it strictly greater, at the precision requested? +        match_version = '.'.join(pkg.version.split('.')[:requested_openshift_release.count('.') + 1]) +        if match_version == requested_openshift_release:              pkgs_precise_version_found[pkg.name] = True -        # get x.y version precision -        minor_version = '.'.join(pkg.version.split('.')[:2]) -        if pkg.name not in pkgs_by_name_version: -            pkgs_by_name_version[pkg.name] = {} -        pkgs_by_name_version[pkg.name][minor_version] = True -    # see if any packages couldn't be found at requested version -    # see if any packages are available in more than one minor version      not_found = [] -    multi_found = []      for name in expected_pkgs:          if name not in pkgs_precise_version_found:              not_found.append(name) + +    if not_found: +        raise PreciseVersionNotFound(requested_openshift_release, not_found) + + +class FoundHigherVersion(AosVersionException): +    '''Exception for reporting that a higher version than requested is available''' +    def __init__(self, requested_release, higher_found): +        msg = ['Some required package(s) are available at a version', +               'that is higher than requested %s:' % requested_release] +        msg += ['  ' + name for name in higher_found] +        msg += ['This will prevent installing the version you requested.'] +        msg += ['Please check your enabled repositories or adjust openshift_release.'] +        AosVersionException.__init__(self, '\n'.join(msg), higher_found) + + +def _check_higher_version_found(pkgs, expected_pkgs, requested_openshift_release): +    req_release_arr = [int(segment) for segment in requested_openshift_release.split(".")] +    # see if any packages are available in a version higher than requested +    higher_version_for_pkg = {} +    for pkg in pkgs: +        if pkg.name not in expected_pkgs: +            continue +        version = [int(segment) for segment in pkg.version.split(".")] +        too_high = version[:len(req_release_arr)] > req_release_arr +        higher_than_seen = version > higher_version_for_pkg.get(pkg.name, []) +        if too_high and higher_than_seen: +            higher_version_for_pkg[pkg.name] = version + +    if higher_version_for_pkg: +        higher_found = [] +        for name, version in higher_version_for_pkg.items(): +            higher_found.append(name + '-' + '.'.join(str(segment) for segment in version)) +        raise FoundHigherVersion(requested_openshift_release, higher_found) + + +class FoundMultiRelease(AosVersionException): +    '''Exception for reporting multiple minor releases found for same package''' +    def __init__(self, multi_found): +        msg = ['Multiple minor versions of these packages are available'] +        msg += ['  ' + name for name in multi_found] +        msg += ["There should only be one OpenShift release repository enabled at a time."] +        AosVersionException.__init__(self, '\n'.join(msg), multi_found) + + +def _check_multi_minor_release(pkgs, expected_pkgs): +    # see if any packages are available in more than one minor version +    pkgs_by_name_version = {} +    for pkg in pkgs: +        # keep track of x.y (minor release) versions seen +        minor_release = '.'.join(pkg.version.split('.')[:2]) +        if pkg.name not in pkgs_by_name_version: +            pkgs_by_name_version[pkg.name] = {} +        pkgs_by_name_version[pkg.name][minor_release] = True + +    multi_found = [] +    for name in expected_pkgs:          if name in pkgs_by_name_version and len(pkgs_by_name_version[name]) > 1:              multi_found.append(name) -    if not_found: -        msg = 'Not all of the required packages are available at requested version %s:\n' % expected_version -        for name in not_found: -            msg += '  %s\n' % name -        bail(msg + 'Please check your subscriptions and enabled repositories.') -    if multi_found: -        msg = 'Multiple minor versions of these packages are available\n' -        for name in multi_found: -            msg += '  %s\n' % name -        bail(msg + "There should only be one OpenShift version's repository enabled at a time.") -    module.exit_json(changed=False) +    if multi_found: +        raise FoundMultiRelease(multi_found)  if __name__ == '__main__': diff --git a/roles/openshift_health_checker/meta/main.yml b/roles/openshift_health_checker/meta/main.yml index 0bbeadd34..cd9b55902 100644 --- a/roles/openshift_health_checker/meta/main.yml +++ b/roles/openshift_health_checker/meta/main.yml @@ -1,3 +1,4 @@  ---  dependencies:    - role: openshift_facts +  - role: openshift_repos diff --git a/roles/openshift_health_checker/openshift_checks/package_availability.py b/roles/openshift_health_checker/openshift_checks/package_availability.py index 9891972a6..a7eb720fd 100644 --- a/roles/openshift_health_checker/openshift_checks/package_availability.py +++ b/roles/openshift_health_checker/openshift_checks/package_availability.py @@ -9,6 +9,10 @@ class PackageAvailability(NotContainerizedMixin, OpenShiftCheck):      name = "package_availability"      tags = ["preflight"] +    @classmethod +    def is_active(cls, task_vars): +        return super(PackageAvailability, cls).is_active(task_vars) and task_vars["ansible_pkg_mgr"] == "yum" +      def run(self, tmp, task_vars):          rpm_prefix = get_var(task_vars, "openshift", "common", "service_type")          group_names = get_var(task_vars, "group_names", default=[]) diff --git a/roles/openshift_health_checker/openshift_checks/package_version.py b/roles/openshift_health_checker/openshift_checks/package_version.py index 42193a1c6..cca2d8b75 100644 --- a/roles/openshift_health_checker/openshift_checks/package_version.py +++ b/roles/openshift_health_checker/openshift_checks/package_version.py @@ -10,11 +10,9 @@ class PackageVersion(NotContainerizedMixin, OpenShiftCheck):      tags = ["preflight"]      def run(self, tmp, task_vars): -        rpm_prefix = get_var(task_vars, "openshift", "common", "service_type") -        openshift_release = get_var(task_vars, "openshift_release") -          args = { -            "prefix": rpm_prefix, -            "version": openshift_release, +            "requested_openshift_release": get_var(task_vars, "openshift_release", default=''), +            "openshift_deployment_type": get_var(task_vars, "openshift_deployment_type"), +            "rpm_prefix": get_var(task_vars, "openshift", "common", "service_type"),          }          return self.execute_module("aos_version", args, tmp, task_vars) diff --git a/roles/openshift_health_checker/test/aos_version_test.py b/roles/openshift_health_checker/test/aos_version_test.py new file mode 100644 index 000000000..39c86067a --- /dev/null +++ b/roles/openshift_health_checker/test/aos_version_test.py @@ -0,0 +1,120 @@ +import pytest +import aos_version + +from collections import namedtuple +Package = namedtuple('Package', ['name', 'version']) + +expected_pkgs = set(['spam', 'eggs']) + + +@pytest.mark.parametrize('pkgs, requested_release, expect_not_found', [ +    ( +        [], +        '3.2.1', +        expected_pkgs,  # none found +    ), +    ( +        [Package('spam', '3.2.1')], +        '3.2', +        ['eggs'],  # completely missing +    ), +    ( +        [Package('spam', '3.2.1'), Package('eggs', '3.3.2')], +        '3.2', +        ['eggs'],  # not the right version +    ), +    ( +        [Package('spam', '3.2.1'), Package('eggs', '3.2.1')], +        '3.2', +        [],  # all found +    ), +    ( +        [Package('spam', '3.2.1'), Package('eggs', '3.2.1.5')], +        '3.2.1', +        [],  # found with more specific version +    ), +    ( +        [Package('eggs', '1.2.3'), Package('eggs', '3.2.1.5')], +        '3.2.1', +        ['spam'],  # eggs found with multiple versions +    ), +]) +def test_check_pkgs_for_precise_version(pkgs, requested_release, expect_not_found): +    if expect_not_found: +        with pytest.raises(aos_version.PreciseVersionNotFound) as e: +            aos_version._check_precise_version_found(pkgs, expected_pkgs, requested_release) +        assert set(expect_not_found) == set(e.value.problem_pkgs) +    else: +        aos_version._check_precise_version_found(pkgs, expected_pkgs, requested_release) + + +@pytest.mark.parametrize('pkgs, requested_release, expect_higher', [ +    ( +        [], +        '3.2.1', +        [], +    ), +    ( +        [Package('spam', '3.2.1')], +        '3.2', +        [],  # more precise but not strictly higher +    ), +    ( +        [Package('spam', '3.3')], +        '3.2.1', +        ['spam-3.3'],  # lower precision, but higher +    ), +    ( +        [Package('spam', '3.2.1'), Package('eggs', '3.3.2')], +        '3.2', +        ['eggs-3.3.2'],  # one too high +    ), +    ( +        [Package('eggs', '1.2.3'), Package('eggs', '3.2.1.5'), Package('eggs', '3.4')], +        '3.2.1', +        ['eggs-3.4'],  # multiple versions, one is higher +    ), +    ( +        [Package('eggs', '3.2.1'), Package('eggs', '3.4'), Package('eggs', '3.3')], +        '3.2.1', +        ['eggs-3.4'],  # multiple versions, two are higher +    ), +]) +def test_check_pkgs_for_greater_version(pkgs, requested_release, expect_higher): +    if expect_higher: +        with pytest.raises(aos_version.FoundHigherVersion) as e: +            aos_version._check_higher_version_found(pkgs, expected_pkgs, requested_release) +        assert set(expect_higher) == set(e.value.problem_pkgs) +    else: +        aos_version._check_higher_version_found(pkgs, expected_pkgs, requested_release) + + +@pytest.mark.parametrize('pkgs, expect_to_flag_pkgs', [ +    ( +        [], +        [], +    ), +    ( +        [Package('spam', '3.2.1')], +        [], +    ), +    ( +        [Package('spam', '3.2.1'), Package('eggs', '3.2.2')], +        [], +    ), +    ( +        [Package('spam', '3.2.1'), Package('spam', '3.3.2')], +        ['spam'], +    ), +    ( +        [Package('eggs', '1.2.3'), Package('eggs', '3.2.1.5'), Package('eggs', '3.4')], +        ['eggs'], +    ), +]) +def test_check_pkgs_for_multi_release(pkgs, expect_to_flag_pkgs): +    if expect_to_flag_pkgs: +        with pytest.raises(aos_version.FoundMultiRelease) as e: +            aos_version._check_multi_minor_release(pkgs, expected_pkgs) +        assert set(expect_to_flag_pkgs) == set(e.value.problem_pkgs) +    else: +        aos_version._check_multi_minor_release(pkgs, expected_pkgs) diff --git a/roles/openshift_health_checker/test/conftest.py b/roles/openshift_health_checker/test/conftest.py index d16401260..3cbd65507 100644 --- a/roles/openshift_health_checker/test/conftest.py +++ b/roles/openshift_health_checker/test/conftest.py @@ -6,5 +6,6 @@ import sys  openshift_health_checker_path = os.path.dirname(os.path.dirname(__file__))  sys.path[1:1] = [      openshift_health_checker_path, -    os.path.join(openshift_health_checker_path, 'action_plugins') +    os.path.join(openshift_health_checker_path, 'action_plugins'), +    os.path.join(openshift_health_checker_path, 'library'),  ] diff --git a/roles/openshift_health_checker/test/package_availability_test.py b/roles/openshift_health_checker/test/package_availability_test.py index 25385339a..f7e916a46 100644 --- a/roles/openshift_health_checker/test/package_availability_test.py +++ b/roles/openshift_health_checker/test/package_availability_test.py @@ -3,6 +3,20 @@ import pytest  from openshift_checks.package_availability import PackageAvailability +@pytest.mark.parametrize('pkg_mgr,is_containerized,is_active', [ +    ('yum', False, True), +    ('yum', True, False), +    ('dnf', True, False), +    ('dnf', False, False), +]) +def test_is_active(pkg_mgr, is_containerized, is_active): +    task_vars = dict( +        ansible_pkg_mgr=pkg_mgr, +        openshift=dict(common=dict(is_containerized=is_containerized)), +    ) +    assert PackageAvailability.is_active(task_vars=task_vars) == is_active + +  @pytest.mark.parametrize('task_vars,must_have_packages,must_not_have_packages', [      (          dict(openshift=dict(common=dict(service_type='openshift'))), diff --git a/roles/openshift_health_checker/test/package_version_test.py b/roles/openshift_health_checker/test/package_version_test.py index cc1d263bc..c6889ee9b 100644 --- a/roles/openshift_health_checker/test/package_version_test.py +++ b/roles/openshift_health_checker/test/package_version_test.py @@ -4,16 +4,19 @@ from openshift_checks.package_version import PackageVersion  def test_package_version():      task_vars = dict(          openshift=dict(common=dict(service_type='origin')), -        openshift_release='v3.5', +        openshift_release='3.5', +        openshift_deployment_type='origin',      )      return_value = object()      def execute_module(module_name=None, module_args=None, tmp=None, task_vars=None):          assert module_name == 'aos_version' -        assert 'prefix' in module_args -        assert 'version' in module_args -        assert module_args['prefix'] == task_vars['openshift']['common']['service_type'] -        assert module_args['version'] == task_vars['openshift_release'] +        assert 'requested_openshift_release' in module_args +        assert 'openshift_deployment_type' in module_args +        assert 'rpm_prefix' in module_args +        assert module_args['requested_openshift_release'] == task_vars['openshift_release'] +        assert module_args['openshift_deployment_type'] == task_vars['openshift_deployment_type'] +        assert module_args['rpm_prefix'] == task_vars['openshift']['common']['service_type']          return return_value      check = PackageVersion(execute_module=execute_module) diff --git a/roles/openshift_provisioners/README.md b/roles/openshift_provisioners/README.md new file mode 100644 index 000000000..7449073e6 --- /dev/null +++ b/roles/openshift_provisioners/README.md @@ -0,0 +1,29 @@ +# OpenShift External Dynamic Provisioners + +## Required Vars +* `openshift_provisioners_install_provisioners`: When `True` the openshift_provisioners role will install provisioners that have their "master" var (e.g. `openshift_provisioners_efs`) set `True`. When `False` will uninstall provisioners that have their var set `True`. + +## Optional Vars +* `openshift_provisioners_image_prefix`: The prefix for the provisioner images to use. Defaults to 'docker.io/openshift/origin-'. +* `openshift_provisioners_image_version`: The image version for the provisioner images to use. Defaults to 'latest'. +* `openshift_provisioners_project`: The namespace that provisioners will be installed in. Defaults to 'openshift-infra'. + +## AWS EFS + +### Prerequisites +* An IAM user assigned the AmazonElasticFileSystemReadOnlyAccess policy (or better) +* An EFS file system in your cluster's region +* [Mount targets](http://docs.aws.amazon.com/efs/latest/ug/accessing-fs.html) and [security groups](http://docs.aws.amazon.com/efs/latest/ug/accessing-fs-create-security-groups.html) such that any node (in any zone in the cluster's region) can mount the EFS file system by its [File system DNS name](http://docs.aws.amazon.com/efs/latest/ug/mounting-fs-mount-cmd-dns-name.html) + +### Required Vars +* `openshift_provisioners_efs_fsid`: The [File system ID](http://docs.aws.amazon.com/efs/latest/ug/gs-step-two-create-efs-resources.html) of the EFS file system, e.g. fs-47a2c22e. +* `openshift_provisioners_efs_region`: The Amazon EC2 region of the EFS file system. +* `openshift_provisioners_efs_aws_access_key_id`: The AWS access key of the IAM user, used to check that the EFS file system specified actually exists. +* `openshift_provisioners_efs_aws_secret_access_key`: The AWS secret access key of the IAM user, used to check that the EFS file system specified actually exists. + +### Optional Vars +* `openshift_provisioners_efs`: When `True` the AWS EFS provisioner will be installed or uninstalled according to whether `openshift_provisioners_install_provisioners` is `True` or `False`, respectively. Defaults to `False`. +* `openshift_provisioners_efs_path`: The path of the directory in the EFS file system in which the EFS provisioner will create a directory to back each PV it creates. It must exist and be mountable by the EFS provisioner. Defaults to '/persistentvolumes'. +* `openshift_provisioners_efs_name`: The `provisioner` name that `StorageClasses` specify. Defaults to 'openshift.org/aws-efs'. +* `openshift_provisioners_efs_nodeselector`: A map of labels (e.g. {"node":"infra","region":"west"} to select the nodes where the pod will land. +* `openshift_provisioners_efs_supplementalgroup`: The supplemental group to give the pod in case it is needed for permission to write to the EFS file system. Defaults to '65534'. diff --git a/roles/openshift_provisioners/defaults/main.yaml b/roles/openshift_provisioners/defaults/main.yaml new file mode 100644 index 000000000..a6f040831 --- /dev/null +++ b/roles/openshift_provisioners/defaults/main.yaml @@ -0,0 +1,12 @@ +--- +openshift_provisioners_install_provisioners: True +openshift_provisioners_image_prefix: docker.io/openshift/origin- +openshift_provisioners_image_version: latest + +openshift_provisioners_efs: False +openshift_provisioners_efs_path: /persistentvolumes +openshift_provisioners_efs_name: openshift.org/aws-efs +openshift_provisioners_efs_nodeselector: "" +openshift_provisioners_efs_supplementalgroup: '65534' + +openshift_provisioners_project: openshift-infra diff --git a/roles/openshift_provisioners/meta/main.yaml b/roles/openshift_provisioners/meta/main.yaml new file mode 100644 index 000000000..cb9278eb7 --- /dev/null +++ b/roles/openshift_provisioners/meta/main.yaml @@ -0,0 +1,16 @@ +--- +galaxy_info: +  author: OpenShift Red Hat +  description: OpenShift Provisioners +  company: Red Hat, Inc. +  license: Apache License, Version 2.0 +  min_ansible_version: 2.2 +  platforms: +  - name: EL +    versions: +    - 7 +  categories: +  - cloud +dependencies: +- role: lib_openshift +- role: openshift_facts diff --git a/roles/openshift_provisioners/tasks/generate_clusterrolebindings.yaml b/roles/openshift_provisioners/tasks/generate_clusterrolebindings.yaml new file mode 100644 index 000000000..ac21a5e37 --- /dev/null +++ b/roles/openshift_provisioners/tasks/generate_clusterrolebindings.yaml @@ -0,0 +1,19 @@ +--- +- name: Generate ClusterRoleBindings +  template: src=clusterrolebinding.j2 dest={{mktemp.stdout}}/templates/{{obj_name}}-clusterrolebinding.yaml +  vars: +    acct_name: provisioners-{{item}} +    obj_name: run-provisioners-{{item}} +    labels: +      provisioners-infra: support +    crb_usernames: ["system:serviceaccount:{{openshift_provisioners_project}}:{{acct_name}}"] +    subjects: +      - kind: ServiceAccount +        name: "{{acct_name}}" +        namespace: "{{openshift_provisioners_project}}" +    cr_name: "system:persistent-volume-provisioner" +  with_items: +    # TODO +    - efs +  check_mode: no +  changed_when: no diff --git a/roles/openshift_provisioners/tasks/generate_secrets.yaml b/roles/openshift_provisioners/tasks/generate_secrets.yaml new file mode 100644 index 000000000..e6cbb1bbf --- /dev/null +++ b/roles/openshift_provisioners/tasks/generate_secrets.yaml @@ -0,0 +1,14 @@ +--- +- name: Generate secret for efs +  template: src=secret.j2 dest={{mktemp.stdout}}/templates/{{obj_name}}-secret.yaml +  vars: +    name: efs +    obj_name: "provisioners-efs" +    labels: +      provisioners-infra: support +    secrets: +      - {key: aws-access-key-id, value: "{{openshift_provisioners_efs_aws_access_key_id}}"} +      - {key: aws-secret-access-key, value: "{{openshift_provisioners_efs_aws_secret_access_key}}"} +  check_mode: no +  changed_when: no +  when: openshift_provisioners_efs | bool diff --git a/roles/openshift_provisioners/tasks/generate_serviceaccounts.yaml b/roles/openshift_provisioners/tasks/generate_serviceaccounts.yaml new file mode 100644 index 000000000..4fe0583ee --- /dev/null +++ b/roles/openshift_provisioners/tasks/generate_serviceaccounts.yaml @@ -0,0 +1,12 @@ +--- +- name: Generating serviceaccounts +  template: src=serviceaccount.j2 dest={{mktemp.stdout}}/templates/{{obj_name}}-sa.yaml +  vars: +    obj_name: provisioners-{{item}} +    labels: +      provisioners-infra: support +  with_items: +  # TODO +  - efs +  check_mode: no +  changed_when: no diff --git a/roles/openshift_provisioners/tasks/install_efs.yaml b/roles/openshift_provisioners/tasks/install_efs.yaml new file mode 100644 index 000000000..57279c665 --- /dev/null +++ b/roles/openshift_provisioners/tasks/install_efs.yaml @@ -0,0 +1,70 @@ +--- +- name: Check efs current replica count +  command: > +    {{ openshift.common.client_binary }} --config={{ mktemp.stdout }}/admin.kubeconfig get dc provisioners-efs +    -o jsonpath='{.spec.replicas}' -n {{openshift_provisioners_project}} +  register: efs_replica_count +  when: not ansible_check_mode +  ignore_errors: yes +  changed_when: no + +- name: Generate efs PersistentVolumeClaim +  template: src=pvc.j2 dest={{mktemp.stdout}}/templates/{{obj_name}}-pvc.yaml +  vars: +    obj_name: "provisioners-efs" +    size: "1Mi" +    access_modes: +      - "ReadWriteMany" +    pv_selector: +      provisioners-efs: efs +  check_mode: no +  changed_when: no + +- name: Generate efs PersistentVolume +  template: src=pv.j2 dest={{mktemp.stdout}}/templates/{{obj_name}}-pv.yaml +  vars: +    obj_name: "provisioners-efs" +    size: "1Mi" +    access_modes: +      - "ReadWriteMany" +    labels: +      provisioners-efs: efs +    volume_plugin: "nfs" +    volume_source: +      - {key: "server", value: "{{openshift_provisioners_efs_fsid}}.efs.{{openshift_provisioners_efs_region}}.amazonaws.com"} +      - {key: "path", value: "{{openshift_provisioners_efs_path}}"} +    claim_name: "provisioners-efs" +  check_mode: no +  changed_when: no + +- name: Generate efs DeploymentConfig +  template: +    src: efs.j2 +    dest: "{{ mktemp.stdout }}/templates/{{deploy_name}}-dc.yaml" +  vars: +    name: efs +    deploy_name: "provisioners-efs" +    deploy_serviceAccount: "provisioners-efs" +    replica_count: "{{efs_replica_count.stdout | default(0)}}" +    node_selector: "{{openshift_provisioners_efs_nodeselector | default('') }}" +    claim_name: "provisioners-efs" +  check_mode: no +  changed_when: false + +# anyuid in order to run as root & chgrp shares with allocated gids +- name: "Check efs anyuid permissions" +  command: > +    {{ openshift.common.client_binary }} --config={{ mktemp.stdout }}/admin.kubeconfig +    get scc/anyuid -o jsonpath='{.users}' +  register: efs_anyuid +  check_mode: no +  changed_when: no + +- name: "Set anyuid permissions for efs" +  command: > +    {{ openshift.common.admin_binary}} --config={{ mktemp.stdout }}/admin.kubeconfig policy +    add-scc-to-user anyuid system:serviceaccount:{{openshift_provisioners_project}}:provisioners-efs +  register: efs_output +  failed_when: "efs_output.rc == 1 and 'exists' not in efs_output.stderr" +  check_mode: no +  when: efs_anyuid.stdout.find("system:serviceaccount:{{openshift_provisioners_project}}:provisioners-efs") == -1 diff --git a/roles/openshift_provisioners/tasks/install_provisioners.yaml b/roles/openshift_provisioners/tasks/install_provisioners.yaml new file mode 100644 index 000000000..324fdcc82 --- /dev/null +++ b/roles/openshift_provisioners/tasks/install_provisioners.yaml @@ -0,0 +1,55 @@ +--- +- name: Check that EFS File System ID is set +  fail: msg='the openshift_provisioners_efs_fsid variable is required' +  when: (openshift_provisioners_efs | bool) and openshift_provisioners_efs_fsid is not defined + +- name: Check that EFS region is set +  fail: msg='the openshift_provisioners_efs_region variable is required' +  when: (openshift_provisioners_efs | bool) and openshift_provisioners_efs_region is not defined + +- name: Check that EFS AWS access key id is set +  fail: msg='the openshift_provisioners_efs_aws_access_key_id variable is required' +  when: (openshift_provisioners_efs | bool) and openshift_provisioners_efs_aws_access_key_id is not defined + +- name: Check that EFS AWS secret access key is set +  fail: msg='the openshift_provisioners_efs_aws_secret_access_key variable is required' +  when: (openshift_provisioners_efs | bool) and openshift_provisioners_efs_aws_secret_access_key is not defined + +- name: Install support +  include: install_support.yaml + +- name: Install EFS +  include: install_efs.yaml +  when: openshift_provisioners_efs | bool + +- find: paths={{ mktemp.stdout }}/templates patterns=*.yaml +  register: object_def_files +  changed_when: no + +- slurp: src={{item}} +  register: object_defs +  with_items: "{{object_def_files.files | map(attribute='path') | list | sort}}" +  changed_when: no + +- name: Create objects +  include: oc_apply.yaml +  vars: +    - kubeconfig: "{{ mktemp.stdout }}/admin.kubeconfig" +    - namespace: "{{ openshift_provisioners_project }}" +    - file_name: "{{ file.source }}" +    - file_content: "{{ file.content | b64decode | from_yaml }}" +  with_items: "{{ object_defs.results }}" +  loop_control: +    loop_var: file +  when: not ansible_check_mode + +- name: Printing out objects to create +  debug: msg={{file.content | b64decode }} +  with_items: "{{ object_defs.results }}" +  loop_control: +    loop_var: file +  when: ansible_check_mode + +- name: Scaling up cluster +  include: start_cluster.yaml +  when: start_cluster | default(true) | bool diff --git a/roles/openshift_provisioners/tasks/install_support.yaml b/roles/openshift_provisioners/tasks/install_support.yaml new file mode 100644 index 000000000..ba472f1c9 --- /dev/null +++ b/roles/openshift_provisioners/tasks/install_support.yaml @@ -0,0 +1,24 @@ +--- +- name: Check for provisioners project already exists +  command: > +    {{ openshift.common.client_binary }} --config={{ mktemp.stdout }}/admin.kubeconfig get project {{openshift_provisioners_project}} --no-headers +  register: provisioners_project_result +  ignore_errors: yes +  when: not ansible_check_mode +  changed_when: no + +- name: Create provisioners project +  command: > +    {{ openshift.common.admin_binary }} --config={{ mktemp.stdout }}/admin.kubeconfig new-project {{openshift_provisioners_project}} +  when: not ansible_check_mode and "not found" in provisioners_project_result.stderr + +- name: Create temp directory for all our templates +  file: path={{mktemp.stdout}}/templates state=directory mode=0755 +  changed_when: False +  check_mode: no + +- include: generate_secrets.yaml + +- include: generate_clusterrolebindings.yaml + +- include: generate_serviceaccounts.yaml diff --git a/roles/openshift_provisioners/tasks/main.yaml b/roles/openshift_provisioners/tasks/main.yaml new file mode 100644 index 000000000..a50c78c97 --- /dev/null +++ b/roles/openshift_provisioners/tasks/main.yaml @@ -0,0 +1,27 @@ +--- +- name: Create temp directory for doing work in +  command: mktemp -td openshift-provisioners-ansible-XXXXXX +  register: mktemp +  changed_when: False +  check_mode: no + +- name: Copy the admin client config(s) +  command: > +    cp {{ openshift.common.config_base}}/master/admin.kubeconfig {{ mktemp.stdout }}/admin.kubeconfig +  changed_when: False +  check_mode: no +  tags: provisioners_init + +- include: "{{ role_path }}/tasks/install_provisioners.yaml" +  when: openshift_provisioners_install_provisioners | default(false) | bool + +- include: "{{ role_path }}/tasks/uninstall_provisioners.yaml" +  when: not openshift_provisioners_install_provisioners | default(false) | bool + +- name: Delete temp directory +  file: +    name: "{{ mktemp.stdout }}" +    state: absent +  tags: provisioners_cleanup +  changed_when: False +  check_mode: no diff --git a/roles/openshift_provisioners/tasks/oc_apply.yaml b/roles/openshift_provisioners/tasks/oc_apply.yaml new file mode 100644 index 000000000..49d03f203 --- /dev/null +++ b/roles/openshift_provisioners/tasks/oc_apply.yaml @@ -0,0 +1,51 @@ +--- +- name: Checking generation of {{file_content.kind}} {{file_content.metadata.name}} +  command: > +    {{ openshift.common.client_binary }} --config={{ kubeconfig }} +    get {{file_content.kind}} {{file_content.metadata.name}} +    -o jsonpath='{.metadata.resourceVersion}' +    -n {{namespace}} +  register: generation_init +  failed_when: "'not found' not in generation_init.stderr and generation_init.stdout == ''" +  changed_when: no + +- name: Applying {{file_name}} +  command: > +    {{ openshift.common.client_binary }} --config={{ kubeconfig }} +    apply -f {{ file_name }} +    -n {{ namespace }} +  register: generation_apply +  failed_when: "'error' in generation_apply.stderr" +  changed_when: no + +- name: Determine change status of {{file_content.kind}} {{file_content.metadata.name}} +  command: > +    {{ openshift.common.client_binary }} --config={{ kubeconfig }} +    get {{file_content.kind}} {{file_content.metadata.name}} +    -o jsonpath='{.metadata.resourceVersion}' +    -n {{namespace}} +  register: generation_changed +  failed_when: "'not found' not in generation_changed.stderr and generation_changed.stdout == ''" +  changed_when: generation_changed.stdout | default (0) | int  > generation_init.stdout | default(0) | int +  when: +    - "'field is immutable' not in generation_apply.stderr" + +- name: Removing previous {{file_name}} +  command: > +    {{ openshift.common.client_binary }} --config={{ kubeconfig }} +    delete -f {{ file_name }} +    -n {{ namespace }} +  register: generation_delete +  failed_when: "'error' in generation_delete.stderr" +  changed_when: generation_delete.rc == 0 +  when: generation_apply.rc != 0 + +- name: Recreating {{file_name}} +  command: > +    {{ openshift.common.client_binary }} --config={{ kubeconfig }} +    apply -f {{ file_name }} +    -n {{ namespace }} +  register: generation_apply +  failed_when: "'error' in generation_apply.stderr" +  changed_when: generation_apply.rc == 0 +  when: generation_apply.rc != 0 diff --git a/roles/openshift_provisioners/tasks/start_cluster.yaml b/roles/openshift_provisioners/tasks/start_cluster.yaml new file mode 100644 index 000000000..ee7f545a9 --- /dev/null +++ b/roles/openshift_provisioners/tasks/start_cluster.yaml @@ -0,0 +1,20 @@ +--- +- name: Retrieve efs +  oc_obj: +    state: list +    kind: dc +    selector: "provisioners-infra=efs" +    namespace: "{{openshift_provisioners_project}}" +  register: efs_dc +  when: openshift_provisioners_efs | bool + +- name: start efs +  oc_scale: +    kind: dc +    name: "{{ object }}" +    namespace: "{{openshift_provisioners_project}}" +    replicas: 1 +  with_items: "{{ efs_dc.results.results[0]['items'] | map(attribute='metadata.name') | list }}" +  loop_control: +    loop_var: object +  when: openshift_provisioners_efs | bool diff --git a/roles/openshift_provisioners/tasks/stop_cluster.yaml b/roles/openshift_provisioners/tasks/stop_cluster.yaml new file mode 100644 index 000000000..30b6b12c8 --- /dev/null +++ b/roles/openshift_provisioners/tasks/stop_cluster.yaml @@ -0,0 +1,20 @@ +--- +- name: Retrieve efs +  oc_obj: +    state: list +    kind: dc +    selector: "provisioners-infra=efs" +    namespace: "{{openshift_provisioners_project}}" +  register: efs_dc +  when: openshift_provisioners_efs | bool + +- name: stop efs +  oc_scale: +    kind: dc +    name: "{{ object }}" +    namespace: "{{openshift_provisioners_project}}" +    replicas: 0 +  with_items: "{{ efs_dc.results.results[0]['items'] | map(attribute='metadata.name') | list }}" +  loop_control: +    loop_var: object +  when: openshift_provisioners_efs | bool diff --git a/roles/openshift_provisioners/tasks/uninstall_provisioners.yaml b/roles/openshift_provisioners/tasks/uninstall_provisioners.yaml new file mode 100644 index 000000000..0be4bc7d2 --- /dev/null +++ b/roles/openshift_provisioners/tasks/uninstall_provisioners.yaml @@ -0,0 +1,43 @@ +--- +- name: stop provisioners +  include: stop_cluster.yaml + +# delete the deployment objects that we had created +- name: delete provisioner api objects +  command: > +    {{ openshift.common.client_binary }} --config={{ mktemp.stdout }}/admin.kubeconfig +    delete {{ item }} --selector provisioners-infra -n {{ openshift_provisioners_project }} --ignore-not-found=true +  with_items: +    - dc +  register: delete_result +  changed_when: delete_result.stdout.find("deleted") != -1 and delete_result.rc == 0 + +# delete our old secrets +- name: delete provisioner secrets +  command: > +    {{ openshift.common.client_binary }} --config={{ mktemp.stdout }}/admin.kubeconfig +    delete secret {{ item }} -n {{ openshift_provisioners_project }} --ignore-not-found=true +  with_items: +    - provisioners-efs +  ignore_errors: yes +  register: delete_result +  changed_when: delete_result.stdout.find("deleted") != -1 and delete_result.rc == 0 + +# delete cluster role bindings +- name: delete cluster role bindings +  command: > +    {{ openshift.common.client_binary }} --config={{ mktemp.stdout }}/admin.kubeconfig +    delete clusterrolebindings {{ item }} -n {{ openshift_provisioners_project }} --ignore-not-found=true +  with_items: +    - run-provisioners-efs +  register: delete_result +  changed_when: delete_result.stdout.find("deleted") != -1 and delete_result.rc == 0 + +# delete our service accounts +- name: delete service accounts +  oc_serviceaccount: +    name: "{{ item }}" +    namespace: "{{ openshift_provisioners_project }}" +    state: absent +  with_items: +    - provisioners-efs diff --git a/roles/openshift_provisioners/templates/clusterrolebinding.j2 b/roles/openshift_provisioners/templates/clusterrolebinding.j2 new file mode 100644 index 000000000..994afa32d --- /dev/null +++ b/roles/openshift_provisioners/templates/clusterrolebinding.j2 @@ -0,0 +1,30 @@ +apiVersion: v1 +kind: ClusterRoleBinding +metadata: +  name: {{obj_name}} +{% if labels is defined%} +  labels: +{% for key, value in labels.iteritems() %} +    {{key}}: {{value}} +{% endfor %} +{% endif %} +{% if crb_usernames is defined %} +userNames: +{% for name in crb_usernames %} +  - {{ name }} +{% endfor %} +{% endif %} +{% if crb_groupnames is defined %} +groupNames: +{% for name in crb_groupnames %} +  - {{ name }} +{% endfor %} +{% endif %} +subjects: +{% for sub in subjects %} +  - kind: {{ sub.kind }} +    name: {{ sub.name }} +    namespace: {{sub.namespace}} +{% endfor %} +roleRef: +  name: {{cr_name}} diff --git a/roles/openshift_provisioners/templates/efs.j2 b/roles/openshift_provisioners/templates/efs.j2 new file mode 100644 index 000000000..81b9ccca5 --- /dev/null +++ b/roles/openshift_provisioners/templates/efs.j2 @@ -0,0 +1,58 @@ +kind: DeploymentConfig +apiVersion: v1 +metadata: +  name: "{{deploy_name}}" +  labels: +    provisioners-infra: "{{name}}" +    name: "{{name}}" +spec: +  replicas: {{replica_count}} +  selector: +    provisioners-infra: "{{name}}" +    name: "{{name}}" +  strategy: +    type: Recreate  +  template: +    metadata: +      name: "{{deploy_name}}" +      labels: +        provisioners-infra: "{{name}}" +        name: "{{name}}" +    spec: +      serviceAccountName: "{{deploy_serviceAccount}}" +{% if node_selector is iterable and node_selector | length > 0 %} +      nodeSelector: +{% for key, value in node_selector.iteritems() %} +        {{key}}: "{{value}}" +{% endfor %} +{% endif %} +      containers: +        - name: efs-provisioner +          image: {{openshift_provisioners_image_prefix}}efs-provisioner:{{openshift_provisioners_image_version}} +          env: +            - name: AWS_ACCESS_KEY_ID +              valueFrom: +                secretKeyRef: +                  name: provisioners-efs +                  key: aws-access-key-id +            - name: AWS_SECRET_ACCESS_KEY +              valueFrom: +                secretKeyRef: +                  name: provisioners-efs +                  key: aws-secret-access-key +            - name: FILE_SYSTEM_ID +              value: "{{openshift_provisioners_efs_fsid}}" +            - name: AWS_REGION +              value: "{{openshift_provisioners_efs_region}}" +            - name: PROVISIONER_NAME +              value: "{{openshift_provisioners_efs_name}}" +          volumeMounts: +            - name: pv-volume +              mountPath: /persistentvolumes +      securityContext: +        supplementalGroups: +          - {{openshift_provisioners_efs_supplementalgroup}} +      volumes: +        - name: pv-volume +          persistentVolumeClaim: +            claimName: "{{claim_name}}" diff --git a/roles/openshift_provisioners/templates/pv.j2 b/roles/openshift_provisioners/templates/pv.j2 new file mode 100644 index 000000000..f4128f9f0 --- /dev/null +++ b/roles/openshift_provisioners/templates/pv.j2 @@ -0,0 +1,32 @@ +apiVersion: v1 +kind: PersistentVolume +metadata: +  name: {{obj_name}} +{% if annotations is defined %} +  annotations: +{% for key,value in annotations.iteritems() %} +    {{key}}: {{value}} +{% endfor %} +{% endif %} +{% if labels is defined%} +  labels: +{% for key, value in labels.iteritems() %} +    {{key}}: {{value}} +{% endfor %} +{% endif %} +spec: +  capacity: +    storage: {{size}} +  accessModes: +{% for mode in access_modes %} +    - {{mode}} +{% endfor %} +  {{volume_plugin}}: +{% for s in volume_source %} +    {{s.key}}: {{s.value}} +{% endfor %} +{% if claim_name is defined%} +  claimRef: +    name: {{claim_name}} +    namespace: {{openshift_provisioners_project}} +{% endif %} diff --git a/roles/openshift_provisioners/templates/pvc.j2 b/roles/openshift_provisioners/templates/pvc.j2 new file mode 100644 index 000000000..83d503056 --- /dev/null +++ b/roles/openshift_provisioners/templates/pvc.j2 @@ -0,0 +1,26 @@ +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: +  name: {{obj_name}} +{% if annotations is defined %} +  annotations: +{% for key,value in annotations.iteritems() %} +    {{key}}: {{value}} +{% endfor %} +{% endif %} +spec: +{% if pv_selector is defined and pv_selector is mapping %} +  selector: +    matchLabels: +{% for key,value in pv_selector.iteritems() %} +      {{key}}: {{value}} +{% endfor %} +{% endif %} +  accessModes: +{% for mode in access_modes %} +    - {{mode}} +{% endfor %} +  resources: +    requests: +      storage: {{size}} + diff --git a/roles/openshift_provisioners/templates/secret.j2 b/roles/openshift_provisioners/templates/secret.j2 new file mode 100644 index 000000000..78824095b --- /dev/null +++ b/roles/openshift_provisioners/templates/secret.j2 @@ -0,0 +1,15 @@ +apiVersion: v1 +kind: Secret +metadata: +  name: {{obj_name}} +{% if labels is defined%} +  labels: +{% for key, value in labels.iteritems() %} +    {{key}}: {{value}} +{% endfor %} +{% endif %} +type: Opaque +data: +{% for s in secrets %} +  "{{s.key}}" : "{{s.value | b64encode}}" +{% endfor %} diff --git a/roles/openshift_provisioners/templates/serviceaccount.j2 b/roles/openshift_provisioners/templates/serviceaccount.j2 new file mode 100644 index 000000000..b22acc594 --- /dev/null +++ b/roles/openshift_provisioners/templates/serviceaccount.j2 @@ -0,0 +1,16 @@ +apiVersion: v1 +kind: ServiceAccount +metadata: +  name: {{obj_name}} +{% if labels is defined%} +  labels: +{% for key, value in labels.iteritems() %} +    {{key}}: {{value}} +{% endfor %} +{% endif %} +{% if secrets is defined %} +secrets: +{% for name in secrets %} +- name: {{ name }} +{% endfor %} +{% endif %} diff --git a/roles/openshift_sanitize_inventory/tasks/main.yml b/roles/openshift_sanitize_inventory/tasks/main.yml index b944c8991..f15dc16d1 100644 --- a/roles/openshift_sanitize_inventory/tasks/main.yml +++ b/roles/openshift_sanitize_inventory/tasks/main.yml @@ -1,4 +1,17 @@  --- +- name: Abort when conflicting deployment type variables are set +  when: +    - deployment_type is defined +    - openshift_deployment_type is defined +    - openshift_deployment_type != deployment_type +  fail: +    msg: |- +      openshift_deployment_type is set to "{{ openshift_deployment_type }}". +      deployment_type is set to "{{ deployment_type }}". +      To avoid unexpected results, this conflict is not allowed. +      deployment_type is deprecated in favor of openshift_deployment_type. +      Please specify only openshift_deployment_type, or make both the same. +  - name: Standardize on latest variable names    set_fact:      # goal is to deprecate deployment_type in favor of openshift_deployment_type.  | 
