diff --git a/puppet-manifests/src/modules/platform/manifests/client.pp b/puppet-manifests/src/modules/platform/manifests/client.pp index 7590c0084f..6fb1fdfa55 100644 --- a/puppet-manifests/src/modules/platform/manifests/client.pp +++ b/puppet-manifests/src/modules/platform/manifests/client.pp @@ -6,6 +6,7 @@ class platform::client::params ( $admin_user_domain = 'Default', $admin_project_domain = 'Default', $admin_project_name = 'admin', + $admin_password = undef, $keystone_identity_region = 'RegionOne', ) { } diff --git a/puppet-manifests/src/modules/platform/manifests/docker.pp b/puppet-manifests/src/modules/platform/manifests/docker.pp index c3755b3315..1c18c3de23 100644 --- a/puppet-manifests/src/modules/platform/manifests/docker.pp +++ b/puppet-manifests/src/modules/platform/manifests/docker.pp @@ -7,6 +7,10 @@ class platform::docker::params ( $gcr_registry = undef, $quay_registry = undef, $docker_registry = undef, + $k8s_registry_secret = undef, + $gcr_registry_secret = undef, + $quay_registry_secret = undef, + $docker_registry_secret = undef, $insecure_registry = undef, ) { } @@ -85,3 +89,42 @@ class platform::docker::bootstrap include ::platform::docker::install include ::platform::docker::config::bootstrap } + +define platform::docker::login_registry ( + $registry_url, + $registry_secret, +) { + include ::platform::client::params + + $auth_url = $::platform::client::params::identity_auth_url + $username = $::platform::client::params::admin_username + $user_domain = $::platform::client::params::admin_user_domain + $project_name = $::platform::client::params::admin_project_name + $project_domain = $::platform::client::params::admin_project_domain + $region_name = $::platform::client::params::keystone_identity_region + $password = $::platform::client::params::admin_password + $interface = 'internal' + + # Registry credentials have been stored in Barbican secret at Ansible + # bootstrap time, retrieve Barbican secret to get the payload + notice("Get payload of Barbican secret ${registry_secret}") + $secret_payload = generate( + '/bin/sh', '-c', template('platform/get-secret-payload.erb')) + + if $secret_payload { + # Parse Barbican secret payload to get the registry username and password + $secret_payload_array = split($secret_payload, ' ') + $registry_username = split($secret_payload_array[0], 'username:')[1] + $registry_password = split($secret_payload_array[1], 'password:')[1] + + # Login to authenticated registry + if $registry_username and $registry_password { + exec { 'Login registry': + command => "docker login ${registry_url} -u ${registry_username} -p ${registry_password}", + logoutput => true, + } + } else { + notice('Registry username or/and password NOT FOUND') + } + } +} diff --git a/puppet-manifests/src/modules/platform/manifests/kubernetes.pp b/puppet-manifests/src/modules/platform/manifests/kubernetes.pp index 909d46a9df..2ed49b8550 100644 --- a/puppet-manifests/src/modules/platform/manifests/kubernetes.pp +++ b/puppet-manifests/src/modules/platform/manifests/kubernetes.pp @@ -109,12 +109,6 @@ class platform::kubernetes::kubeadm { $iptables_file = "net.bridge.bridge-nf-call-ip6tables = 1 net.bridge.bridge-nf-call-iptables = 1" - if $::platform::docker::params::k8s_registry { - $k8s_registry = $::platform::docker::params::k8s_registry - } else { - $k8s_registry = 'k8s.gcr.io' - } - # Configure kubelet cpumanager options if str2bool($::is_worker_subfunction) and !('openstack-compute-node' @@ -335,6 +329,27 @@ class platform::kubernetes::master::init # This flag is created by Ansible on controller-0; # - Ansible replay is not impacted by flag creation. + # If alternative k8s registry requires the authentication, + # kubeadm required images need to be pre-pulled on controller + if $k8s_registry != 'k8s.gcr.io' and $::platform::docker::params::k8s_registry_secret != undef { + File['/etc/kubernetes/kubeadm.yaml'] + -> platform::docker::login_registry { 'login k8s registry': + registry_url => $k8s_registry, + registry_secret => $::platform::docker::params::k8s_registry_secret + } + + -> exec { 'kubeadm to pre pull images': + command => 'kubeadm config images pull --config /etc/kubernetes/kubeadm.yaml', + logoutput => true, + before => Exec['configure master node'] + } + + -> exec { 'logout k8s registry': + command => "docker logout ${k8s_registry}", + logoutput => true, + } + } + # Create necessary certificate files file { '/etc/kubernetes/pki': ensure => directory, @@ -467,6 +482,44 @@ class platform::kubernetes::worker::init Class['::platform::docker::config'] -> Class[$name] + if str2bool($::is_initial_config) { + include ::platform::params + + if $::platform::docker::params::k8s_registry { + $k8s_registry = $::platform::docker::params::k8s_registry + } else { + $k8s_registry = 'k8s.gcr.io' + } + + # If alternative k8s registry requires the authentication, + # k8s pause image needs to be pre-pulled on worker nodes + if $k8s_registry != 'k8s.gcr.io' and $::platform::docker::params::k8s_registry_secret != undef { + # Get the pause image tag from kubeadm required images + # list and replace with alternative k8s registry + $get_k8s_pause_img = "kubeadm config images list 2>/dev/null |\ + awk '/^k8s.gcr.io\\/pause:/{print \$1}' | sed 's/k8s.gcr.io/${k8s_registry}/'" + $k8s_pause_img = generate('/bin/sh', '-c', $get_k8s_pause_img) + + if k8s_pause_img { + platform::docker::login_registry { 'login k8s registry': + registry_url => $k8s_registry, + registry_secret => $::platform::docker::params::k8s_registry_secret + } + + -> exec { 'load k8s pause image': + command => "docker image pull ${k8s_pause_img}", + logoutput => true, + before => Exec['configure worker node'] + } + + -> exec { 'logout k8s registry': + command => "docker logout ${k8s_registry}", + logoutput => true, + } + } + } + } + # Configure the worker node. Only do this once, so check whether the # kubelet.conf file has already been created (by the join). exec { 'configure worker node': diff --git a/puppet-manifests/src/modules/platform/templates/get-secret-payload.erb b/puppet-manifests/src/modules/platform/templates/get-secret-payload.erb new file mode 100644 index 0000000000..1b1eab67c3 --- /dev/null +++ b/puppet-manifests/src/modules/platform/templates/get-secret-payload.erb @@ -0,0 +1,11 @@ +# Retrieve barbican secret payload +openstack secret get <%=@registry_secret %> \ + --os-auth-url <%=@auth_url %> \ + --os-username <%=@username %> \ + --os-user-domain-name <%=@user_domain %> \ + --os-project-name <%=@project_name %> \ + --os-project-domain-name <%=@project_domain %> \ + --os-region-name <%=@region_name %> \ + --os-interface <%=@interface %> \ + --os-password <%=@password %> \ + -p -f value -c Payload diff --git a/sysinv/sysinv/sysinv/sysinv/common/service_parameter.py b/sysinv/sysinv/sysinv/sysinv/common/service_parameter.py index ac330053cc..73a54b16e4 100644 --- a/sysinv/sysinv/sysinv/sysinv/common/service_parameter.py +++ b/sysinv/sysinv/sysinv/sysinv/common/service_parameter.py @@ -291,6 +291,13 @@ def _validate_docker_registry_address(name, value): "Parameter '%s' must be a valid address." % name)) +def _validate_docker_registry_auth_secret(name, value): + """Check if registry auth secret is a valid UUID""" + if not cutils.is_uuid_like(value): + raise wsme.exc.ClientSideError(_( + "Parameter '%s' must be a valid UUID." % name)) + + def _validate_docker_insecure_registry_bool(name, value): """Check if insecure registry is a valid bool""" if not cutils.is_valid_boolstr(value): @@ -462,26 +469,35 @@ DOCKER_REGISTRIES_PARAMETER_OPTIONAL = [ DOCKER_REGISTRIES_PARAMETER_VALIDATOR = { constants.SERVICE_PARAM_NAME_DOCKER_URL: _validate_docker_registry_address, + constants.SERVICE_PARAM_NAME_DOCKER_AUTH_SECRET: _validate_docker_registry_auth_secret } DOCKER_DOCKER_REGISTRY_PARAMETER_RESOURCE = { constants.SERVICE_PARAM_NAME_DOCKER_URL: 'platform::docker::params::docker_registry', + constants.SERVICE_PARAM_NAME_DOCKER_AUTH_SECRET: + 'platform::docker::params::docker_registry_secret' } DOCKER_GCR_REGISTRY_PARAMETER_RESOURCE = { constants.SERVICE_PARAM_NAME_DOCKER_URL: - 'platform::docker::params::gcr_registry' + 'platform::docker::params::gcr_registry', + constants.SERVICE_PARAM_NAME_DOCKER_AUTH_SECRET: + 'platform::docker::params::gcr_registry_secret' } DOCKER_K8S_REGISTRY_PARAMETER_RESOURCE = { constants.SERVICE_PARAM_NAME_DOCKER_URL: - 'platform::docker::params::k8s_registry' + 'platform::docker::params::k8s_registry', + constants.SERVICE_PARAM_NAME_DOCKER_AUTH_SECRET: + 'platform::docker::params::k8s_registry_secret' } DOCKER_QUAY_REGISTRY_PARAMETER_RESOURCE = { constants.SERVICE_PARAM_NAME_DOCKER_URL: - 'platform::docker::params::quay_registry' + 'platform::docker::params::quay_registry', + constants.SERVICE_PARAM_NAME_DOCKER_AUTH_SECRET: + 'platform::docker::params::quay_registry_secret' } KUBERNETES_CERTIFICATES_PARAMETER_OPTIONAL = [ diff --git a/sysinv/sysinv/sysinv/sysinv/conductor/kube_app.py b/sysinv/sysinv/sysinv/sysinv/conductor/kube_app.py index 0728705cd6..fe87801191 100644 --- a/sysinv/sysinv/sysinv/sysinv/conductor/kube_app.py +++ b/sysinv/sysinv/sysinv/sysinv/conductor/kube_app.py @@ -2513,6 +2513,25 @@ class DockerHelper(object): overrides_dir: {'bind': '/overrides', 'mode': 'ro'}, logs_dir: {'bind': ARMADA_CONTAINER_LOG_LOCATION, 'mode': 'rw'}} + armada_image = client.images.list(CONF.armada_image_tag) + # Pull Armada image if it's not available + if not armada_image: + LOG.info("Downloading Armada image %s ..." % CONF.armada_image_tag) + + quay_registry_secret = self._dbapi.service_parameter_get_all( + service=constants.SERVICE_TYPE_DOCKER, + section=constants.SERVICE_PARAM_SECTION_DOCKER_QUAY_REGISTRY, + name=constants.SERVICE_PARAM_NAME_DOCKER_AUTH_SECRET) + if quay_registry_secret: + quay_registry_auth = self._parse_barbican_secret( + quay_registry_secret[0].value) + else: + quay_registry_auth = None + + client.images.pull(CONF.armada_image_tag, + auth_config=quay_registry_auth) + LOG.info("Armada image %s downloaded!" % CONF.armada_image_tag) + container = client.containers.run( CONF.armada_image_tag, name=ARMADA_CONTAINER_NAME, diff --git a/sysinv/sysinv/sysinv/sysinv/puppet/keystone.py b/sysinv/sysinv/sysinv/sysinv/puppet/keystone.py index f764d100cb..fca6cd683c 100644 --- a/sysinv/sysinv/sysinv/sysinv/puppet/keystone.py +++ b/sysinv/sysinv/sysinv/sysinv/puppet/keystone.py @@ -77,6 +77,7 @@ class KeystonePuppet(openstack.OpenstackBasePuppet): 'keystone::db::postgresql::password': dbpass, 'keystone::roles::admin::password': admin_password, + 'platform::client::params::admin_password': admin_password, } def get_system_config(self): @@ -145,6 +146,7 @@ class KeystonePuppet(openstack.OpenstackBasePuppet): 'keystone::admin_password': admin_password, 'keystone::roles::admin::password': admin_password, 'keystone::database_connection': db_connection, + 'platform::client::params::admin_password': admin_password, } return config