diff options
-rw-r--r-- | roles/docker/defaults/main.yml | 2 | ||||
-rw-r--r-- | roles/docker/meta/main.yml | 1 | ||||
-rw-r--r-- | roles/docker/tasks/registry_auth.yml | 16 | ||||
-rw-r--r-- | roles/docker/tasks/systemcontainer_crio.yml | 6 | ||||
-rw-r--r-- | roles/docker/tasks/systemcontainer_docker.yml | 8 | ||||
-rw-r--r-- | roles/lib_utils/library/docker_creds.py | 207 | ||||
-rw-r--r-- | roles/openshift_master/defaults/main.yml | 1 | ||||
-rw-r--r-- | roles/openshift_master/tasks/registry_auth.yml | 20 | ||||
-rw-r--r-- | roles/openshift_node/defaults/main.yml | 1 | ||||
-rw-r--r-- | roles/openshift_node/tasks/registry_auth.yml | 19 | ||||
-rw-r--r-- | roles/openshift_node_upgrade/defaults/main.yml | 1 | ||||
-rw-r--r-- | roles/openshift_node_upgrade/tasks/registry_auth.yml | 19 |
12 files changed, 299 insertions, 2 deletions
diff --git a/roles/docker/defaults/main.yml b/roles/docker/defaults/main.yml index c086c28df..224844a06 100644 --- a/roles/docker/defaults/main.yml +++ b/roles/docker/defaults/main.yml @@ -2,6 +2,8 @@ docker_cli_auth_config_path: '/root/.docker' openshift_docker_signature_verification: False +openshift_docker_alternative_creds: False + # oreg_url is defined by user input. oreg_host: "{{ oreg_url.split('/')[0] if (oreg_url is defined and '.' in oreg_url.split('/')[0]) else '' }}" oreg_auth_credentials_replace: False diff --git a/roles/docker/meta/main.yml b/roles/docker/meta/main.yml index 62b8a2eb5..d5faae8df 100644 --- a/roles/docker/meta/main.yml +++ b/roles/docker/meta/main.yml @@ -12,3 +12,4 @@ galaxy_info: dependencies: - role: lib_openshift - role: lib_os_firewall +- role: lib_utils diff --git a/roles/docker/tasks/registry_auth.yml b/roles/docker/tasks/registry_auth.yml index d05b7f2b8..2c7bc5711 100644 --- a/roles/docker/tasks/registry_auth.yml +++ b/roles/docker/tasks/registry_auth.yml @@ -12,5 +12,21 @@ delay: 5 until: openshift_docker_credentials_create_res.rc == 0 when: + - not openshift_docker_alternative_creds | bool + - oreg_auth_user is defined + - (not docker_cli_auth_credentials_stat.stat.exists or oreg_auth_credentials_replace) | bool + +# docker_creds is a custom module from lib_utils +# 'docker login' requires a docker.service running on the local host, this is an +# alternative implementation for non-docker hosts. This implementation does not +# check the registry to determine whether or not the credentials will work. +- name: Create credentials for docker cli registry auth (alternative) + docker_creds: + path: "{{ docker_cli_auth_config_path }}" + registry: "{{ oreg_host }}" + username: "{{ oreg_auth_user }}" + password: "{{ oreg_auth_password }}" + when: + - openshift_docker_alternative_creds | bool - oreg_auth_user is defined - (not docker_cli_auth_credentials_stat.stat.exists or oreg_auth_credentials_replace) | bool diff --git a/roles/docker/tasks/systemcontainer_crio.yml b/roles/docker/tasks/systemcontainer_crio.yml index 1e2d64293..3fe10454d 100644 --- a/roles/docker/tasks/systemcontainer_crio.yml +++ b/roles/docker/tasks/systemcontainer_crio.yml @@ -179,3 +179,9 @@ register: start_result - meta: flush_handlers + +# If we are using crio only, docker.service might not be available for +# 'docker login' +- include: registry_auth.yml + vars: + openshift_docker_alternative_creds: "{{ l_use_crio_only }}" diff --git a/roles/docker/tasks/systemcontainer_docker.yml b/roles/docker/tasks/systemcontainer_docker.yml index aa3b35ddd..84220fa66 100644 --- a/roles/docker/tasks/systemcontainer_docker.yml +++ b/roles/docker/tasks/systemcontainer_docker.yml @@ -173,6 +173,10 @@ - set_fact: docker_service_status_changed: "{{ r_docker_systemcontainer_docker_start_result | changed }}" -- include: registry_auth.yml - - meta: flush_handlers + +# Since docker is running as a system container, docker login will fail to create +# credentials. Use alternate method if requiring authenticated registries. +- include: registry_auth.yml + vars: + openshift_docker_alternative_creds: True diff --git a/roles/lib_utils/library/docker_creds.py b/roles/lib_utils/library/docker_creds.py new file mode 100644 index 000000000..d4674845e --- /dev/null +++ b/roles/lib_utils/library/docker_creds.py @@ -0,0 +1,207 @@ +#!/usr/bin/env python +# pylint: disable=missing-docstring +# +# Copyright 2017 Red Hat, Inc. and/or its affiliates +# and other contributors as indicated by the @author tags. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import base64 +import json +import os + +from ansible.module_utils.basic import AnsibleModule + + +DOCUMENTATION = ''' +--- +module: docker_creds + +short_description: Creates/updates a 'docker login' file in place of using 'docker login' + +version_added: "2.4" + +description: + - This module creates a docker config.json file in the directory provided by 'path' + on hosts that do not support 'docker login' but need the file present for + registry authentication purposes of various other services. + +options: + path: + description: + - This is the message to send to the sample module + required: true + registry: + description: + - This is the registry the credentials are for. + required: true + username: + description: + - This is the username to authenticate to the registry with. + required: true + password: + description: + - This is the password to authenticate to the registry with. + required: true + +author: + - "Michael Gugino <mgugino@redhat.com>" +''' + +EXAMPLES = ''' +# Pass in a message +- name: Place credentials in file + docker_creds: + path: /root/.docker + registry: registry.example.com:443 + username: myuser + password: mypassword +''' + + +def check_dest_dir_exists(module, dest): + '''Check if dest dir is present and is a directory''' + dir_exists = os.path.exists(dest) + if dir_exists: + if not os.path.isdir(dest): + msg = "{} exists but is not a directory".format(dest) + result = {'failed': True, + 'changed': False, + 'msg': msg, + 'state': 'unknown'} + module.fail_json(**result) + else: + return 1 + else: + return 0 + + +def create_dest_dir(module, dest): + try: + os.makedirs(dest, mode=0o700) + except OSError as oserror: + result = {'failed': True, + 'changed': False, + 'msg': str(oserror), + 'state': 'unknown'} + module.fail_json(**result) + + +def load_config_file(module, dest): + '''load the config.json in directory dest''' + conf_file_path = os.path.join(dest, 'config.json') + if os.path.exists(conf_file_path): + # Try to open the file and load json data + try: + with open(conf_file_path) as conf_file: + data = conf_file.read() + jdata = json.loads(data) + + except IOError as ioerror: + result = {'failed': True, + 'changed': False, + 'msg': str(ioerror), + 'state': 'unknown'} + module.fail_json(**result) + except ValueError as jsonerror: + result = {'failed': True, + 'changed': False, + 'msg': str(jsonerror), + 'state': 'unknown'} + module.fail_json(**result) + return jdata + else: + # File doesn't exist, we just return an empty dictionary. + return {} + + +def update_config(docker_config, registry, username, password): + '''Add our registry auth credentials into docker_config dict''' + + # Add anything that might be missing in our dictionary + if 'auths' not in docker_config: + docker_config['auths'] = {} + if registry not in docker_config['auths']: + docker_config['auths'][registry] = {} + + # base64 encode our username:password string + encoded_data = base64.b64encode('{}:{}'.format(username, password)) + + # check if the same value is already present for idempotency. + if 'auth' in docker_config['auths'][registry]: + if docker_config['auths'][registry]['auth'] == encoded_data: + # No need to go further, everything is already set in file. + return False + docker_config['auths'][registry]['auth'] = encoded_data + return True + + +def write_config(module, docker_config, dest): + '''Write updated credentials into dest/config.json''' + conf_file_path = os.path.join(dest, 'config.json') + try: + with open(conf_file_path, 'w') as conf_file: + json.dump(docker_config, conf_file, indent=8) + except IOError as ioerror: + result = {'failed': True, + 'changed': False, + 'msg': str(ioerror), + 'state': 'unknown'} + module.fail_json(**result) + + +def run_module(): + '''Run this module''' + module_args = dict( + path=dict(aliases=['dest', 'name'], required=True, type='path'), + registry=dict(type='str', required=True), + username=dict(type='str', required=True), + password=dict(type='str', required=True, no_log=True) + ) + + module = AnsibleModule( + argument_spec=module_args, + supports_check_mode=False + ) + + # First, create our dest dir if necessary + dest = module.params['path'] + registry = module.params['registry'] + username = module.params['username'] + password = module.params['password'] + + if not check_dest_dir_exists(module, dest): + create_dest_dir(module, dest) + docker_config = {} + else: + # We want to scrape the contents of dest/config.json + # in case there are other registries/settings already present. + docker_config = load_config_file(module, dest) + + # Put the registry auth info into the config dict. + changed = update_config(docker_config, registry, username, password) + + if changed: + write_config(module, docker_config, dest) + + result = {'changed': changed} + + module.exit_json(**result) + + +def main(): + run_module() + + +if __name__ == '__main__': + main() diff --git a/roles/openshift_master/defaults/main.yml b/roles/openshift_master/defaults/main.yml index a27fbae7e..97a8735ee 100644 --- a/roles/openshift_master/defaults/main.yml +++ b/roles/openshift_master/defaults/main.yml @@ -31,6 +31,7 @@ oreg_host: "{{ oreg_url.split('/')[0] if (oreg_url is defined and '.' in oreg_ur oreg_auth_credentials_path: "{{ r_openshift_master_data_dir }}/.docker" oreg_auth_credentials_replace: False l_bind_docker_reg_auth: False +openshift_docker_alternative_creds: "{{ (openshift_docker_use_system_container | default(False)) or (openshift_use_crio_only | default(False)) }}" containerized_svc_dir: "/usr/lib/systemd/system" ha_svc_template_path: "native-cluster" diff --git a/roles/openshift_master/tasks/registry_auth.yml b/roles/openshift_master/tasks/registry_auth.yml index cde01c49e..c95f562d0 100644 --- a/roles/openshift_master/tasks/registry_auth.yml +++ b/roles/openshift_master/tasks/registry_auth.yml @@ -8,6 +8,7 @@ - name: Create credentials for registry auth command: "docker --config={{ oreg_auth_credentials_path }} login -u {{ oreg_auth_user }} -p {{ oreg_auth_password }} {{ oreg_host }}" when: + - not (openshift_docker_alternative_creds | default(False)) - oreg_auth_user is defined - (not master_oreg_auth_credentials_stat.stat.exists or oreg_auth_credentials_replace) | bool register: master_oreg_auth_credentials_create @@ -18,6 +19,25 @@ - restart master api - restart master controllers +# docker_creds is a custom module from lib_utils +# 'docker login' requires a docker.service running on the local host, this is an +# alternative implementation for non-docker hosts. This implementation does not +# check the registry to determine whether or not the credentials will work. +- name: Create credentials for registry auth (alternative) + docker_creds: + path: "{{ oreg_auth_credentials_path }}" + registry: "{{ oreg_host }}" + username: "{{ oreg_auth_user }}" + password: "{{ oreg_auth_password }}" + when: + - openshift_docker_alternative_creds | default(False) | bool + - oreg_auth_user is defined + - (not docker_cli_auth_credentials_stat.stat.exists or oreg_auth_credentials_replace) | bool + register: master_oreg_auth_credentials_create + notify: + - restart master api + - restart master controllers + # Container images may need the registry credentials - name: Setup ro mount of /root/.docker for containerized hosts set_fact: diff --git a/roles/openshift_node/defaults/main.yml b/roles/openshift_node/defaults/main.yml index 85ad33ad3..89d154ad7 100644 --- a/roles/openshift_node/defaults/main.yml +++ b/roles/openshift_node/defaults/main.yml @@ -85,6 +85,7 @@ oreg_host: "{{ oreg_url.split('/')[0] if (oreg_url is defined and '.' in oreg_ur oreg_auth_credentials_path: "{{ openshift_node_data_dir }}/.docker" oreg_auth_credentials_replace: False l_bind_docker_reg_auth: False +openshift_docker_alternative_creds: "{{ (openshift_docker_use_system_container | default(False)) or (openshift_use_crio_only | default(False)) }}" # NOTE # r_openshift_node_*_default may be defined external to this role. diff --git a/roles/openshift_node/tasks/registry_auth.yml b/roles/openshift_node/tasks/registry_auth.yml index 5e5e4f94a..f5428867a 100644 --- a/roles/openshift_node/tasks/registry_auth.yml +++ b/roles/openshift_node/tasks/registry_auth.yml @@ -8,6 +8,7 @@ - name: Create credentials for registry auth command: "docker --config={{ oreg_auth_credentials_path }} login -u {{ oreg_auth_user }} -p {{ oreg_auth_password }} {{ oreg_host }}" when: + - not (openshift_docker_alternative_creds | default(False)) - oreg_auth_user is defined - (not node_oreg_auth_credentials_stat.stat.exists or oreg_auth_credentials_replace) | bool register: node_oreg_auth_credentials_create @@ -17,6 +18,24 @@ notify: - restart node +# docker_creds is a custom module from lib_utils +# 'docker login' requires a docker.service running on the local host, this is an +# alternative implementation for non-docker hosts. This implementation does not +# check the registry to determine whether or not the credentials will work. +- name: Create credentials for registry auth (alternative) + docker_creds: + path: "{{ oreg_auth_credentials_path }}" + registry: "{{ oreg_host }}" + username: "{{ oreg_auth_user }}" + password: "{{ oreg_auth_password }}" + when: + - openshift_docker_alternative_creds | bool + - oreg_auth_user is defined + - (not node_oreg_auth_credentials_stat.stat.exists or oreg_auth_credentials_replace) | bool + register: node_oreg_auth_credentials_create + notify: + - restart node + # Container images may need the registry credentials - name: Setup ro mount of /root/.docker for containerized hosts set_fact: diff --git a/roles/openshift_node_upgrade/defaults/main.yml b/roles/openshift_node_upgrade/defaults/main.yml index 10b4c6977..1da434e6f 100644 --- a/roles/openshift_node_upgrade/defaults/main.yml +++ b/roles/openshift_node_upgrade/defaults/main.yml @@ -12,3 +12,4 @@ oreg_host: "{{ oreg_url.split('/')[0] if (oreg_url is defined and '.' in oreg_ur oreg_auth_credentials_path: "{{ openshift_node_data_dir }}/.docker" oreg_auth_credentials_replace: False l_bind_docker_reg_auth: False +openshift_docker_alternative_creds: "{{ (openshift_docker_use_system_container | default(False)) or (openshift_use_crio_only | default(False)) }}" diff --git a/roles/openshift_node_upgrade/tasks/registry_auth.yml b/roles/openshift_node_upgrade/tasks/registry_auth.yml index 5e5e4f94a..f5428867a 100644 --- a/roles/openshift_node_upgrade/tasks/registry_auth.yml +++ b/roles/openshift_node_upgrade/tasks/registry_auth.yml @@ -8,6 +8,7 @@ - name: Create credentials for registry auth command: "docker --config={{ oreg_auth_credentials_path }} login -u {{ oreg_auth_user }} -p {{ oreg_auth_password }} {{ oreg_host }}" when: + - not (openshift_docker_alternative_creds | default(False)) - oreg_auth_user is defined - (not node_oreg_auth_credentials_stat.stat.exists or oreg_auth_credentials_replace) | bool register: node_oreg_auth_credentials_create @@ -17,6 +18,24 @@ notify: - restart node +# docker_creds is a custom module from lib_utils +# 'docker login' requires a docker.service running on the local host, this is an +# alternative implementation for non-docker hosts. This implementation does not +# check the registry to determine whether or not the credentials will work. +- name: Create credentials for registry auth (alternative) + docker_creds: + path: "{{ oreg_auth_credentials_path }}" + registry: "{{ oreg_host }}" + username: "{{ oreg_auth_user }}" + password: "{{ oreg_auth_password }}" + when: + - openshift_docker_alternative_creds | bool + - oreg_auth_user is defined + - (not node_oreg_auth_credentials_stat.stat.exists or oreg_auth_credentials_replace) | bool + register: node_oreg_auth_credentials_create + notify: + - restart node + # Container images may need the registry credentials - name: Setup ro mount of /root/.docker for containerized hosts set_fact: |