From 3b7f3b44eecbc60e9c8c29f6c87129a28c518896 Mon Sep 17 00:00:00 2001 From: Jesus Bermudez Velazquez Date: Fri, 16 Feb 2024 11:56:27 +0000 Subject: [PATCH 01/18] Add registry entry in /etc/hosts --- lib/cloudregister/registerutils.py | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/lib/cloudregister/registerutils.py b/lib/cloudregister/registerutils.py index 163ec07d..c1597c84 100644 --- a/lib/cloudregister/registerutils.py +++ b/lib/cloudregister/registerutils.py @@ -45,7 +45,7 @@ REGISTRATION_DATA_DIR = '/var/cache/cloudregister/' REGISTERED_SMT_SERVER_DATA_FILE_NAME = 'currentSMTInfo.obj' RMT_AS_SCC_PROXY_MARKER = 'rmt_is_scc_proxy' - +REGISTRY_FQDN = 'registry.suse.com' # ---------------------------------------------------------------------------- def add_hosts_entry(smt_server): @@ -61,10 +61,16 @@ def add_hosts_entry(smt_server): smt_server.get_FQDN(), smt_server.get_name() ) + # add registry entry + registry_entry = '%s\t%s\n' % ( + smt_ip, + REGISTRY_FQDN + ) with open('/etc/hosts', 'a') as hosts_file: hosts_file.write(smt_hosts_entry_comment) hosts_file.write(entry) - logging.info('Modified /etc/hosts, added: %s' % entry) + hosts_file.write(registry_entry) + logging.info('Modified /etc/hosts, added: %s' % (entry + registry_entry)) # ---------------------------------------------------------------------------- From ec73fff5cc18a46bfd3c5f2b796b5d5f58c8c599 Mon Sep 17 00:00:00 2001 From: Jesus Bermudez Velazquez Date: Fri, 16 Feb 2024 11:56:44 +0000 Subject: [PATCH 02/18] Add registry credentials setting for docker --- usr/sbin/registercloudguest | 44 +++++++++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) diff --git a/usr/sbin/registercloudguest b/usr/sbin/registercloudguest index ac7e9417..732624f7 100755 --- a/usr/sbin/registercloudguest +++ b/usr/sbin/registercloudguest @@ -46,12 +46,53 @@ from cloudregister import smt from lxml import etree from requests.auth import HTTPBasicAuth +DOCKER_REGISTRY_CREDENTIALS_PATH = '.docker/.config.json' + # Disable the urllib warnings # We have server certs that have no subject alt names # We have to check the server state API without certificate validation urllib3.disable_warnings() registration_returncode = 0 +# ---------------------------------------------------------------------------- +def set_registry_credentials(): + username, password = utils.get_credentials( + utils.get_credentials_file( + utils.get_current_smt() + ) + ) + registry_credentials = {} + registry_credentials[utils.REGISTRY_FQDN] = { + 'username': username, + 'password': password + } + + docker_paths = [ + os.path.join( + os.path.expanduser('~'), DOCKER_REGISTRY_CREDENTIALS_PATH + ), + os.path.join(os.sep, 'root', DOCKER_REGISTRY_CREDENTIALS_PATH) + ] + for docker_path in docker_paths: + config_json = {} + try: + with open(docker_path, 'r') as cred_json: + config_json = json.load(cred_json) + # file exists + # set the new registry credentials, + # independently of what that content was + config_json['auths'].update(registry_credentials) + except (FileNotFoundError, KeyError): + # config file does not exist or "auths" key is not set + config_json.update({'auths': registry_credentials}) + + with open(docker_path, 'w') as cred_json_file: + json.dump(config_json, cred_json_file) + + logging.info( + 'Credentials for the registry added in %s' % ' '.join(docker_paths) + ) + # ---------------------------------------------------------------------------- def register_modules(extensions, products, registered=[], failed=[]): """Register modules obeying dependencies""" @@ -574,6 +615,9 @@ if failed_extensions: for failed_extension in failed_extensions: print(activate_prod_cmd.format(failed_extension)) +# add username and password credentials for registry +set_registry_credentials() + # Enable Nvidia repo if repo(s) are configured and destination can be reached if utils.has_nvidia_support(): nvidia_repo_names = utils.find_repos('nvidia') From b0c2496eca437e5b5868c04fdea4d5d98c546dcd Mon Sep 17 00:00:00 2001 From: Jesus Bermudez Velazquez Date: Fri, 16 Feb 2024 12:48:54 +0000 Subject: [PATCH 03/18] Create .docker directory --- usr/sbin/registercloudguest | 1 + 1 file changed, 1 insertion(+) diff --git a/usr/sbin/registercloudguest b/usr/sbin/registercloudguest index 732624f7..7ece6af8 100755 --- a/usr/sbin/registercloudguest +++ b/usr/sbin/registercloudguest @@ -84,6 +84,7 @@ def set_registry_credentials(): config_json['auths'].update(registry_credentials) except (FileNotFoundError, KeyError): # config file does not exist or "auths" key is not set + os.makedirs(os.path.dirname(docker_path), exist_ok=True) config_json.update({'auths': registry_credentials}) with open(docker_path, 'w') as cred_json_file: From a1aaeb6b2c003ef383aedbc0958eb90385e2cc4d Mon Sep 17 00:00:00 2001 From: Jesus Bermudez Velazquez Date: Fri, 16 Feb 2024 13:56:10 +0000 Subject: [PATCH 04/18] Add test for /etc/hosts entries --- tests/test_registerutils.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/tests/test_registerutils.py b/tests/test_registerutils.py index 8562bfd2..0392d71b 100644 --- a/tests/test_registerutils.py +++ b/tests/test_registerutils.py @@ -536,9 +536,14 @@ def test_add_hosts_entry(mock_has_ipv6_access): fqdn=smt_server.get_FQDN(), name=smt_server.get_name() ) + file_content_registry_entry = '{ip}\t{registry_fqdn}\n'.format( + ip=smt_server.get_ipv6(), + registry_fqdn='registry.suse.com' + ) assert file_handle.write.mock_calls == [ call(file_content_comment), - call(file_content_entry) + call(file_content_entry), + call(file_content_registry_entry) ] From f3cf6c0acbd76418d4166dea23996c8e8612026f Mon Sep 17 00:00:00 2001 From: Jesus Bermudez Velazquez Date: Thu, 29 Feb 2024 17:42:00 +0000 Subject: [PATCH 05/18] Add and clean hosts entry Set registry FQDN as registry-framework.susecloud.net in SMT Use SMT object to get registry FQDN Update tests --- lib/cloudregister/registerutils.py | 27 ++++++++++--------- lib/cloudregister/smt.py | 11 ++++++++ tests/test_registerutils.py | 43 ++++++++++++++++++------------ 3 files changed, 52 insertions(+), 29 deletions(-) diff --git a/lib/cloudregister/registerutils.py b/lib/cloudregister/registerutils.py index c1597c84..cdeea612 100644 --- a/lib/cloudregister/registerutils.py +++ b/lib/cloudregister/registerutils.py @@ -56,21 +56,17 @@ def add_hosts_entry(smt_server): smt_ip = smt_server.get_ipv4() if has_ipv6_access(smt_server): smt_ip = smt_server.get_ipv6() - entry = '%s\t%s\t%s\n' % ( + entry = '%s\t%s\t%s\n%s\t%s\n' % ( smt_ip, smt_server.get_FQDN(), - smt_server.get_name() - ) - # add registry entry - registry_entry = '%s\t%s\n' % ( + smt_server.get_name(), smt_ip, - REGISTRY_FQDN + smt_server.get_registry_FQDN(), ) with open('/etc/hosts', 'a') as hosts_file: hosts_file.write(smt_hosts_entry_comment) hosts_file.write(entry) - hosts_file.write(registry_entry) - logging.info('Modified /etc/hosts, added: %s' % (entry + registry_entry)) + logging.info('Modified /etc/hosts, added: %s' % entry) # ---------------------------------------------------------------------------- @@ -92,10 +88,12 @@ def add_region_server_args_to_URL(api, cfg): # ---------------------------------------------------------------------------- -def clean_hosts_file(domain_name): +def clean_hosts_file(domain_name, registry_name): """Remove the smt server entry from the /etc/hosts file""" if isinstance(domain_name, str): domain_name = domain_name.encode() + if isinstance(registry_name, str): + registry_name = registry_name.encode() new_hosts_content = [] # Handle entries as bytes, # Yes, users put non ascii characters into /etc/hosts @@ -103,12 +101,17 @@ def clean_hosts_file(domain_name): content = hosts_file.readlines() smt_announce_found = None + smt_domain_found = None for entry in content: if b'# Added by SMT' in entry: smt_announce_found = True continue if smt_announce_found and domain_name in entry: smt_announce_found = False + smt_domain_found = True + continue + if smt_domain_found and registry_name in entry: + smt_domain_found = False continue new_hosts_content.append(entry) @@ -779,7 +782,7 @@ def get_smt(cache_refreshed=None): '"%s"' % str((server.get_ipv4(), server.get_ipv6())) ) # Assume the new server is in the same domain - clean_hosts_file(server.get_FQDN()) + clean_hosts_file(server.get_FQDN(), server.get_registry_FQDN()) add_hosts_entry(server) set_as_current_smt(server) return server @@ -1267,7 +1270,7 @@ def remove_registration_data(): logging.warning('Unable to remove client registration from server') logging.warning(e) logging.info('Continue with local artifact removal') - clean_hosts_file(domain_name) + clean_hosts_file(domain_name, smt.get_registry_FQDN()) __remove_repo_artifacts(server_name) os.unlink(smt_data_file) if is_scc_connected(): @@ -1301,7 +1304,7 @@ def remove_registration_data(): # ---------------------------------------------------------------------------- def replace_hosts_entry(current_smt, new_smt): - clean_hosts_file(current_smt.get_FQDN()) + clean_hosts_file(current_smt.get_FQDN(), current_smt.get_registry_FQDN()) add_hosts_entry(new_smt) diff --git a/lib/cloudregister/smt.py b/lib/cloudregister/smt.py index 14bed546..76d468d3 100644 --- a/lib/cloudregister/smt.py +++ b/lib/cloudregister/smt.py @@ -40,6 +40,11 @@ def __init__(self, smtXMLNode, https_only=False): except KeyError: self._region = 'unknown' self._fqdn = smtXMLNode.attrib['SMTserverName'] + try: + self._registry_fqdn = 'registry-' + self._fqdn.split('-')[1] + except IndexError: + logging.error('Server name (FQDN) is malformed') + self._registry_fqdn = '' self._fingerprint = smtXMLNode.attrib['fingerprint'] self._cert = None self._cert_names = ('smt.crt', 'rmt.crt') @@ -56,6 +61,7 @@ def __eq__(self, other_smt): self.get_ipv4() == other_smt.get_ipv4() and self.get_ipv6() == other_smt.get_ipv6() and self.get_FQDN() == other_smt.get_FQDN() and + self.get_registry_FQDN() == other_smt.get_registry_FQDN() and self.get_fingerprint() == other_smt.get_fingerprint() and self.get_region() == other_smt.get_region() ): @@ -94,6 +100,11 @@ def get_FQDN(self): """Return the fully qualified domain name""" return self._fqdn + # -------------------------------------------------------------------- + def get_registry_FQDN(self): + """Return the fully qualified domain registry name""" + return self._registry_fqdn + # -------------------------------------------------------------------- def get_name(self): """Return the name""" diff --git a/tests/test_registerutils.py b/tests/test_registerutils.py index 0392d71b..61f0b3ce 100644 --- a/tests/test_registerutils.py +++ b/tests/test_registerutils.py @@ -284,6 +284,7 @@ def test_clean_host_file_no_empty_bottom_lines(): # Added by SMT, please, do NOT remove this line 2.3.4.5 smt-entry.susecloud.net smt-entry +2.3.4.5 registry-entry.susecloud.net 4.3.2.1 another_entry.whatever.com another_entry""" expected_cleaned_hosts = """ @@ -294,7 +295,7 @@ def test_clean_host_file_no_empty_bottom_lines(): 4.3.2.1 another_entry.whatever.com another_entry""" with mock.patch('builtins.open', mock.mock_open(read_data=hosts_content.encode())) as m: # noqa: E501 - utils.clean_hosts_file('smt-entry') + utils.clean_hosts_file('smt-entry', 'registry-entry') expected_write_calls = [] expected_lines = expected_cleaned_hosts.split('\n') @@ -317,6 +318,7 @@ def test_clean_host_file_one_empty_bottom_line(): # Added by SMT, please, do NOT remove this line 2.3.4.5 smt-entry.susecloud.net smt-entry +2.3.4.5 registry-entry.susecloud.net 4.3.2.1 another_entry.whatever.com another_entry """ @@ -329,7 +331,7 @@ def test_clean_host_file_one_empty_bottom_line(): 4.3.2.1 another_entry.whatever.com another_entry """ with mock.patch('builtins.open', mock.mock_open(read_data=hosts_content.encode())) as m: # noqa: E501 - utils.clean_hosts_file('smt-entry'.encode()) + utils.clean_hosts_file('smt-entry'.encode(), 'registry-entry'.encode()) expected_write_calls = [] expected_lines = expected_cleaned_hosts.split('\n') @@ -352,6 +354,7 @@ def test_clean_host_file_some_empty_bottom_lines(): # Added by SMT, please, do NOT remove this line 2.3.4.5 smt-entry.susecloud.net smt-entry +2.3.4.5 registry-entry.susecloud.net 4.3.2.1 another_entry.whatever.com another_entry @@ -367,7 +370,7 @@ def test_clean_host_file_some_empty_bottom_lines(): 4.3.2.1 another_entry.whatever.com another_entry """ with mock.patch('builtins.open', mock.mock_open(read_data=hosts_content.encode())) as m: # noqa: E501 - utils.clean_hosts_file('smt-entry'.encode()) + utils.clean_hosts_file('smt-entry'.encode(), 'registry-entry'.encode()) expected_write_calls = [] expected_lines = expected_cleaned_hosts.split('\n') @@ -393,6 +396,7 @@ def test_clean_host_file_some_empty_bottom_lines_smt_entry_is_last(): # Added by SMT, please, do NOT remove this line 2.3.4.5 smt-entry.susecloud.net smt-entry +2.3.4.5 registry-entry.susecloud.net @@ -407,7 +411,7 @@ def test_clean_host_file_some_empty_bottom_lines_smt_entry_is_last(): """ with mock.patch('builtins.open', mock.mock_open(read_data=hosts_content.encode())) as m: # noqa: E501 - utils.clean_hosts_file('smt-entry'.encode()) + utils.clean_hosts_file('smt-entry'.encode(), 'registry-entry'.encode()) expected_write_calls = [] expected_lines = expected_cleaned_hosts.split('\n') @@ -433,6 +437,7 @@ def test_clean_host_file_one_empty_bottom_lines_smt_entry_is_last(): # Added by SMT, please, do NOT remove this line 2.3.4.5 smt-entry.susecloud.net smt-entry +2.3.4.5 registry-entry.susecloud.net """ expected_cleaned_hosts = """ @@ -445,7 +450,7 @@ def test_clean_host_file_one_empty_bottom_lines_smt_entry_is_last(): """ with mock.patch('builtins.open', mock.mock_open(read_data=hosts_content.encode())) as m: # noqa: E501 - utils.clean_hosts_file('smt-entry'.encode()) + utils.clean_hosts_file('smt-entry'.encode(), 'registry-entry'.encode()) expected_write_calls = [] expected_lines = expected_cleaned_hosts.split('\n') @@ -470,7 +475,8 @@ def test_clean_host_file_no_empty_bottom_lines_smt_entry_is_last(): 4.3.2.1 another_entry.whatever.com another_entry # Added by SMT, please, do NOT remove this line -2.3.4.5 smt-entry.susecloud.net smt-entry""" +2.3.4.5 smt-entry.susecloud.net smt-entry +2.3.4.5 registry-entry.susecloud.net""" expected_cleaned_hosts = """ # simulates hosts file containing the ipv6 we are looking for in the test @@ -480,7 +486,7 @@ def test_clean_host_file_no_empty_bottom_lines_smt_entry_is_last(): 4.3.2.1 another_entry.whatever.com another_entry """ with mock.patch('builtins.open', mock.mock_open(read_data=hosts_content.encode())) as m: # noqa: E501 - utils.clean_hosts_file('smt-entry'.encode()) + utils.clean_hosts_file('smt-entry'.encode(), 'registry-entry'.encode()) expected_write_calls = [] expected_lines = expected_cleaned_hosts.split('\n') @@ -505,7 +511,7 @@ def test_clean_host_file_raised_exception(): 4.3.2.1 another_entry.whatever.com another_entry""" with mock.patch('builtins.open', mock.mock_open(read_data=hosts_content.encode())) as m: # noqa: E501 - utils.clean_hosts_file('smt-entry') + utils.clean_hosts_file('smt-entry', ''.encode()) assert m().write.mock_calls == [] @@ -531,19 +537,16 @@ def test_add_hosts_entry(mock_has_ipv6_access): '\n# Added by SMT registration do not remove, ' 'retain comment as well\n' ) - file_content_entry = '{ip}\t{fqdn}\t{name}\n'.format( + file_content_entry = '{ip}\t{fqdn}\t{name}\n{ip_reg}\t{reg_name}\n'.format( ip=smt_server.get_ipv6(), fqdn=smt_server.get_FQDN(), - name=smt_server.get_name() - ) - file_content_registry_entry = '{ip}\t{registry_fqdn}\n'.format( - ip=smt_server.get_ipv6(), - registry_fqdn='registry.suse.com' + name=smt_server.get_name(), + ip_reg=smt_server.get_ipv6(), + reg_name=smt_server.get_registry_FQDN() ) assert file_handle.write.mock_calls == [ call(file_content_comment), call(file_content_entry), - call(file_content_registry_entry) ] @@ -1737,7 +1740,10 @@ def test_get_smt_alternative_server( mock_add_hosts_entry.assert_called_once_with(alternative_smt_server) mock_set_as_current_smt.assert_called_once_with(alternative_smt_server) mock_set_as_current_smt.assert_called_once_with(alternative_smt_server) - mock_clean_hosts_file.assert_called_once_with('smt-foo.susecloud.net') + mock_clean_hosts_file.assert_called_once_with( + 'smt-foo.susecloud.net', + 'registry-foo.susecloud.net' + ) @patch('cloudregister.registerutils.__populate_srv_cache') @@ -2415,7 +2421,10 @@ def test_replace_hosts_entry(mock_clean_hosts_file, mock_add_hosts_entry): region="antarctica-1"/>''') smt_server = SMT(etree.fromstring(smt_data_ipv46)) utils.replace_hosts_entry(smt_server, 'new_smt') - mock_clean_hosts_file.assert_called_once_with('smt-foo.susecloud.net') + mock_clean_hosts_file.assert_called_once_with( + 'smt-foo.susecloud.net', + 'registry-foo.susecloud.net' + ) mock_add_hosts_entry.assert_called_once_with('new_smt') From 275b3e3004170beb0bb9ba7d89fdd9add7b15109 Mon Sep 17 00:00:00 2001 From: Jesus Bermudez Velazquez Date: Mon, 11 Mar 2024 15:37:58 +0000 Subject: [PATCH 06/18] Add auth token to config file When login with docker/podman, an auths token is written to the config file - Set that config file with the auth token without running login command --- lib/cloudregister/registerutils.py | 39 ++++++++++++++++++++++++- usr/sbin/registercloudguest | 47 ++++-------------------------- 2 files changed, 44 insertions(+), 42 deletions(-) diff --git a/lib/cloudregister/registerutils.py b/lib/cloudregister/registerutils.py index cdeea612..0d384cd2 100644 --- a/lib/cloudregister/registerutils.py +++ b/lib/cloudregister/registerutils.py @@ -45,7 +45,7 @@ REGISTRATION_DATA_DIR = '/var/cache/cloudregister/' REGISTERED_SMT_SERVER_DATA_FILE_NAME = 'currentSMTInfo.obj' RMT_AS_SCC_PROXY_MARKER = 'rmt_is_scc_proxy' -REGISTRY_FQDN = 'registry.suse.com' +DOCKER_REGISTRY_CREDENTIALS_PATH = '.docker/.config.json' # ---------------------------------------------------------------------------- def add_hosts_entry(smt_server): @@ -508,6 +508,43 @@ def get_credentials(credentials_file): return (username, password) +# ---------------------------------------------------------------------------- +def set_registry_credentials(registry_fqdn, username, password): + """Set the auth token to pull images from SUSE registry.""" + auth_token = base64.b64encode( + b'{username}:{passwowrd}'.format(username=username, password=password) + ) + registry_credentials = {} + registry_credentials[registry_fqdn] = {'auths': auth_token} + + docker_paths = [ + os.path.join( + os.path.expanduser('~'), DOCKER_REGISTRY_CREDENTIALS_PATH + ), + os.path.join(os.sep, 'root', DOCKER_REGISTRY_CREDENTIALS_PATH) + ] + for docker_path in docker_paths: + config_json = {} + try: + with open(docker_path, 'r') as cred_json: + config_json = json.load(cred_json) + # file exists + # set the new registry credentials, + # independently of what that content was + config_json['auths'].update(registry_credentials) + except (FileNotFoundError, KeyError): + # config file does not exist or "auths" key is not set + os.makedirs(os.path.dirname(docker_path), exist_ok=True) + config_json.update({'auths': registry_credentials}) + + with open(docker_path, 'w') as cred_json_file: + json.dump(config_json, cred_json_file) + + logging.info( + 'Credentials for the registry added in %s' % ' '.join(docker_paths) + ) + + # ---------------------------------------------------------------------------- def get_credentials_file(update_server, service_name=None): """Return the credentials filename. diff --git a/usr/sbin/registercloudguest b/usr/sbin/registercloudguest index 7ece6af8..6891c68c 100755 --- a/usr/sbin/registercloudguest +++ b/usr/sbin/registercloudguest @@ -54,45 +54,6 @@ DOCKER_REGISTRY_CREDENTIALS_PATH = '.docker/.config.json' urllib3.disable_warnings() registration_returncode = 0 -# ---------------------------------------------------------------------------- -def set_registry_credentials(): - username, password = utils.get_credentials( - utils.get_credentials_file( - utils.get_current_smt() - ) - ) - registry_credentials = {} - registry_credentials[utils.REGISTRY_FQDN] = { - 'username': username, - 'password': password - } - - docker_paths = [ - os.path.join( - os.path.expanduser('~'), DOCKER_REGISTRY_CREDENTIALS_PATH - ), - os.path.join(os.sep, 'root', DOCKER_REGISTRY_CREDENTIALS_PATH) - ] - for docker_path in docker_paths: - config_json = {} - try: - with open(docker_path, 'r') as cred_json: - config_json = json.load(cred_json) - # file exists - # set the new registry credentials, - # independently of what that content was - config_json['auths'].update(registry_credentials) - except (FileNotFoundError, KeyError): - # config file does not exist or "auths" key is not set - os.makedirs(os.path.dirname(docker_path), exist_ok=True) - config_json.update({'auths': registry_credentials}) - - with open(docker_path, 'w') as cred_json_file: - json.dump(config_json, cred_json_file) - - logging.info( - 'Credentials for the registry added in %s' % ' '.join(docker_paths) - ) # ---------------------------------------------------------------------------- def register_modules(extensions, products, registered=[], failed=[]): @@ -616,8 +577,12 @@ if failed_extensions: for failed_extension in failed_extensions: print(activate_prod_cmd.format(failed_extension)) -# add username and password credentials for registry -set_registry_credentials() +# add registry auth token credentials +utils.set_registry_credentials( + registration_target.get_registry_FQDN(), + user, + password +) # Enable Nvidia repo if repo(s) are configured and destination can be reached if utils.has_nvidia_support(): From 951492cb955905b432d3a6d2dcb2e3838b786fcf Mon Sep 17 00:00:00 2001 From: Jesus Bermudez Velazquez Date: Mon, 11 Mar 2024 17:17:36 +0000 Subject: [PATCH 07/18] Update tests --- lib/cloudregister/registerutils.py | 9 +-- tests/test_registerutils.py | 93 +++++++++++++++++++++++++++++- 2 files changed, 95 insertions(+), 7 deletions(-) diff --git a/lib/cloudregister/registerutils.py b/lib/cloudregister/registerutils.py index 0d384cd2..e6596393 100644 --- a/lib/cloudregister/registerutils.py +++ b/lib/cloudregister/registerutils.py @@ -45,7 +45,7 @@ REGISTRATION_DATA_DIR = '/var/cache/cloudregister/' REGISTERED_SMT_SERVER_DATA_FILE_NAME = 'currentSMTInfo.obj' RMT_AS_SCC_PROXY_MARKER = 'rmt_is_scc_proxy' -DOCKER_REGISTRY_CREDENTIALS_PATH = '.docker/.config.json' +DOCKER_REGISTRY_CREDENTIALS_PATH = '.docker/config.json' # ---------------------------------------------------------------------------- def add_hosts_entry(smt_server): @@ -511,9 +511,10 @@ def get_credentials(credentials_file): # ---------------------------------------------------------------------------- def set_registry_credentials(registry_fqdn, username, password): """Set the auth token to pull images from SUSE registry.""" - auth_token = base64.b64encode( - b'{username}:{passwowrd}'.format(username=username, password=password) - ) + auth_token = base64.b64encode('{username}:{password}'.format( + username=username, + password=password + ).encode()).decode() registry_credentials = {} registry_credentials[registry_fqdn] = {'auths': auth_token} diff --git a/tests/test_registerutils.py b/tests/test_registerutils.py index 61f0b3ce..ff4741cc 100644 --- a/tests/test_registerutils.py +++ b/tests/test_registerutils.py @@ -11,6 +11,7 @@ # You should have received a copy of the GNU Lesser General Public # License along with this library. +import base64 import configparser import inspect import io @@ -2289,7 +2290,6 @@ def test_remove_registration_data( mock_request_delete.return_value = response mock_is_scc_connected.return_value = True assert utils.remove_registration_data() == None - print(mock_logging.info.call_args_list) assert mock_logging.info.call_args_list == [ call("Clean current registration server: ('192.168.1.1', 'fc00::1')"), call('System successfully removed from update infrastructure'), @@ -2338,7 +2338,6 @@ def test_remove_registration_data_request_not_OK( mock_request_delete.return_value = response mock_is_scc_connected.return_value = True assert utils.remove_registration_data() == None - print(mock_logging.info.call_args_list) assert mock_logging.info.call_args_list == [ call("Clean current registration server: ('192.168.1.1', 'fc00::1')"), call( @@ -2395,7 +2394,7 @@ def test_remove_registration_data_request_exception( mock_request_delete.side_effect = exception mock_is_scc_connected.return_value = True assert utils.remove_registration_data() == None - print(mock_logging.error.call_args_list) + assert mock_logging.warning.call_args_list == [ call('Unable to remove client registration from server'), call(exception), @@ -3018,6 +3017,94 @@ def test_remove_service( mock_logging.info.not_called() +@patch('cloudregister.registerutils.os.path.join') +@patch('cloudregister.registerutils.json.dump') +@patch('cloudregister.registerutils.os.makedirs') +def test_set_registry_credentials_config_does_not_exist( + mock_makedirs, + mock_json_dump, + mock_os_join +): + username = 'SCC_dbe7a97570214719bb6a2dc5e9c5baab' + password = '1256447b616544fc' + expected_auth_token = base64.b64encode('{username}:{password}'.format( + username=username, + password=password + ).encode()).decode() + + mock_os_join.return_value = '/home/foo/non_file' + + # with patch('builtins.open', side_effect=FileExistsError()): + with patch('builtins.open', create=True) as mock_open: + mock_open_docker_config = MagicMock(spec=io.IOBase) + def open_file(filename, mode): + if mode == 'w': + return mock_open_docker_config.return_value + if mode == 'r': + raise FileNotFoundError() + + mock_open.side_effect = open_file + file_handle = mock_open_docker_config.return_value.__enter__.return_value + file_handle.read.return_value = '' + utils.set_registry_credentials('127.0.0.1', username, password) + assert mock_makedirs.call_args_list == [ + call('/home/foo', exist_ok=True), + call('/home/foo', exist_ok=True) + ] + assert mock_json_dump.call_args_list == [ + call({"auths": {"127.0.0.1": {"auths": expected_auth_token}}}, file_handle), + call({"auths": {"127.0.0.1": {"auths": expected_auth_token}}}, file_handle) + ] + + +# --------------------------------------------------------------------------- +@patch('cloudregister.registerutils.json.load') +@patch('cloudregister.registerutils.os.path.join') +@patch('cloudregister.registerutils.json.dump') +@patch('cloudregister.registerutils.os.makedirs') +def test_set_registry_credentials_config_does_exist( + mock_makedirs, + mock_json_dump, + mock_os_join, + mock_json_load +): + username = 'SCC_dbe7a97570214719bb6a2dc5e9c5baab' + password = '1256447b616544fc' + expected_auth_token = base64.b64encode('{username}:{password}'.format( + username=username, + password=password + ).encode()).decode() + + mock_os_join.return_value = '/home/foo/non_file' + + with patch('builtins.open', create=True) as mock_open: + mock_open_docker_config = MagicMock(spec=io.IOBase) + def open_file(filename, mode): + return mock_open_docker_config.return_value + + mock_open.side_effect = open_file + file_handle = \ + mock_open_docker_config.return_value.__enter__.return_value + file_handle.read.return_value = '' + mock_json_load.return_value = { + "auths": { + "127.0.0.1": { + "auths": 'foo' + } + } + } + utils.set_registry_credentials('127.0.0.1', username, password) + assert mock_makedirs.call_args_list == [] + assert mock_json_dump.call_args_list == [ + call({ + "auths": {"127.0.0.1": {"auths": expected_auth_token}} + }, file_handle), + call({ + "auths": {"127.0.0.1": {"auths": expected_auth_token}} + }, file_handle) + ] + + # --------------------------------------------------------------------------- # Helper functions class Response(): From a477089d8f200eb36f7ffcd2df24fa027e3ac08a Mon Sep 17 00:00:00 2001 From: Jesus Bermudez Velazquez Date: Wed, 13 Mar 2024 09:47:05 +0000 Subject: [PATCH 08/18] Fix key for credentials --- lib/cloudregister/registerutils.py | 2 +- tests/test_registerutils.py | 16 +++++++++++----- 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/lib/cloudregister/registerutils.py b/lib/cloudregister/registerutils.py index e6596393..b009da84 100644 --- a/lib/cloudregister/registerutils.py +++ b/lib/cloudregister/registerutils.py @@ -516,7 +516,7 @@ def set_registry_credentials(registry_fqdn, username, password): password=password ).encode()).decode() registry_credentials = {} - registry_credentials[registry_fqdn] = {'auths': auth_token} + registry_credentials[registry_fqdn] = {'auth': auth_token} docker_paths = [ os.path.join( diff --git a/tests/test_registerutils.py b/tests/test_registerutils.py index ff4741cc..323baaa2 100644 --- a/tests/test_registerutils.py +++ b/tests/test_registerutils.py @@ -3052,8 +3052,14 @@ def open_file(filename, mode): call('/home/foo', exist_ok=True) ] assert mock_json_dump.call_args_list == [ - call({"auths": {"127.0.0.1": {"auths": expected_auth_token}}}, file_handle), - call({"auths": {"127.0.0.1": {"auths": expected_auth_token}}}, file_handle) + call( + {"auths": {"127.0.0.1": {"auth": expected_auth_token}}}, + file_handle + ), + call( + {"auths": {"127.0.0.1": {"auth": expected_auth_token}}}, + file_handle + ) ] @@ -3089,7 +3095,7 @@ def open_file(filename, mode): mock_json_load.return_value = { "auths": { "127.0.0.1": { - "auths": 'foo' + "auth": 'foo' } } } @@ -3097,10 +3103,10 @@ def open_file(filename, mode): assert mock_makedirs.call_args_list == [] assert mock_json_dump.call_args_list == [ call({ - "auths": {"127.0.0.1": {"auths": expected_auth_token}} + "auths": {"127.0.0.1": {"auth": expected_auth_token}} }, file_handle), call({ - "auths": {"127.0.0.1": {"auths": expected_auth_token}} + "auths": {"127.0.0.1": {"auth": expected_auth_token}} }, file_handle) ] From 944feba5b6a5a1e10b23dccfbdf01a08122568db Mon Sep 17 00:00:00 2001 From: Jesus Bermudez Velazquez Date: Wed, 13 Mar 2024 10:53:41 +0000 Subject: [PATCH 09/18] Use registry info coming from region server --- lib/cloudregister/smt.py | 6 +----- usr/sbin/registercloudguest | 9 ++++++++- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/lib/cloudregister/smt.py b/lib/cloudregister/smt.py index 76d468d3..ea2e33f6 100644 --- a/lib/cloudregister/smt.py +++ b/lib/cloudregister/smt.py @@ -40,11 +40,7 @@ def __init__(self, smtXMLNode, https_only=False): except KeyError: self._region = 'unknown' self._fqdn = smtXMLNode.attrib['SMTserverName'] - try: - self._registry_fqdn = 'registry-' + self._fqdn.split('-')[1] - except IndexError: - logging.error('Server name (FQDN) is malformed') - self._registry_fqdn = '' + self._registry_fqdn = smtXMLNode.attrib['SMTregistryName'] self._fingerprint = smtXMLNode.attrib['fingerprint'] self._cert = None self._cert_names = ('smt.crt', 'rmt.crt') diff --git a/usr/sbin/registercloudguest b/usr/sbin/registercloudguest index 6891c68c..fc539eee 100755 --- a/usr/sbin/registercloudguest +++ b/usr/sbin/registercloudguest @@ -167,6 +167,12 @@ argparse.add_argument( dest='user_smt_fqdn', help=help_msg ) +help_msg='The target registry server FQDN. ' +argparse.add_argument( + '--smt-registry-fqdn', + dest='user_registry_fqdn', + help=help_msg +) help_msg='The target update server IP. ' help_msg+='Use in exceptional cases only' argparse.add_argument( @@ -300,7 +306,8 @@ if args.user_smt_ip: smt_xml += 'SMTserverIPv6="%s" ' % args.user_smt_ip elif isinstance(smt_ip, ipaddress.IPv4Address): smt_xml += 'SMTserverIP="%s" ' % args.user_smt_ip - smt_xml += 'SMTserverName="%s"' % args.user_smt_fqdn + smt_xml += 'SMTserverName="%s" ' % args.user_smt_fqdn + smt_xml += 'SMTregistryName="%s"' % args.user_registry_fqdn smt_xml += '/>' region_smt_data = etree.fromstring(smt_xml) else: From 31081800335c7c00d3a4b8eeb5ba8f533daf88ba Mon Sep 17 00:00:00 2001 From: Jesus Bermudez Velazquez Date: Wed, 13 Mar 2024 11:51:47 +0000 Subject: [PATCH 10/18] Update tests to use registry info from region server --- lib/cloudregister/registerutils.py | 4 +- tests/test_registerutils.py | 88 ++++++++++++++++++++---------- tests/test_smt.py | 6 +- 3 files changed, 68 insertions(+), 30 deletions(-) diff --git a/lib/cloudregister/registerutils.py b/lib/cloudregister/registerutils.py index b009da84..3002b5d7 100644 --- a/lib/cloudregister/registerutils.py +++ b/lib/cloudregister/registerutils.py @@ -237,7 +237,9 @@ def fetch_smt_data(cfg, proxies, quiet=False): logging.error('Unable to obtain SMT server information, exiting') sys.exit(1) smt_info = json.loads(response.text) - expected_entries = ('fingerprint', 'SMTserverIP', 'SMTserverName') + expected_entries = ( + 'fingerprint', 'SMTserverIP', 'SMTserverName', 'SMTregistryName' + ) smt_info_xml = '''') smt_server = SMT(etree.fromstring(smt_data_ipv46)) @@ -712,12 +714,14 @@ def test_fetch_smt_data_metadata_server( response = Response() response.status_code = 200 response.text = ( - '{"fingerprint":"foo","SMTserverIP":"bar","SMTserverName":"foobar"}' + '{"fingerprint":"foo","SMTserverIP":"bar","SMTserverName":"foobar",' + '"SMTregistryName":"registry-foobar"}' ) mock_request_get.return_value = response smt_data_fetched = dedent('''\ ''') + SMTserverName="foobar" \ + SMTregistryName="registry-foobar" />''') smt_server = etree.fromstring(smt_data_fetched) fetched_smt_data = utils.fetch_smt_data(cfg, None) assert etree.tostring(fetched_smt_data, encoding='utf-8') == \ @@ -788,7 +792,8 @@ def test_fetch_smt_data_api_answered( SMTserverIP="1.2.3.4" SMTserverIPv6="fc11::2" SMTserverName="foo.susecloud.net" - /> + SMTregistryName="registry-foo.susecloud.net" + /> ''') response.text = smt_xml mock_request_get.return_value = response @@ -819,14 +824,16 @@ def test_fetch_smt_data_api_no_valid_ip( response = Response() response.status_code = 200 response.text = ( - '{"fingerprint":"foo","SMTserverIP":"bar","SMTserverName":"foobar"}' + '{"fingerprint":"foo","SMTserverIP":"bar","SMTserverName":"foobar",' + '"SMTregistryName":"registry-foobar"}' ) response2 = Response() response2.status_code = 200 smt_xml = dedent( '''''' + '''SMTserverName="foo.susecloud.net" ''' + '''SMTregistryName="registry-foo.susecloud.net"/>''' ) response2.text = smt_xml mock_request_get.side_effect = [response2, response2] @@ -972,35 +979,14 @@ def test_find_equivalent_smt_server(mock_is_responsive): SMTserverIP="192.168.1.1" SMTserverIPv6="fc00::1" SMTserverName="fantasy.example.com" + SMTregistryName="registry-fantasy.example.com" region="antarctica-1"/>''') smt_data_ipv46_2 = dedent('''\ ''') - smt_a = SMT(etree.fromstring(smt_data_ipv46)) - smt_b = SMT(etree.fromstring(smt_data_ipv46_2)) - mock_is_responsive.return_value = True - - assert utils.find_equivalent_smt_server(smt_a, [smt_a, smt_b]) == smt_b - assert utils.find_equivalent_smt_server(smt_a, [smt_a]) == None - - -@patch.object(SMT, 'is_responsive') -def test_find_equivalent_smt_server(mock_is_responsive): - """Test hosts entry has a new entry added by us.""" - smt_data_ipv46 = dedent('''\ - ''') - smt_data_ipv46_2 = dedent('''\ - ''') smt_a = SMT(etree.fromstring(smt_data_ipv46)) smt_b = SMT(etree.fromstring(smt_data_ipv46_2)) @@ -1031,6 +1017,7 @@ def test_get_activations_no_user_pass( SMTserverIP="192.168.1.1" SMTserverIPv6="fc00::1" SMTserverName="fantasy.example.com" + SMTregistryName="registry-fantasy.example.com" region="antarctica-1"/>''') smt_server = SMT(etree.fromstring(smt_data_ipv46)) mock_get_smt.return_value = smt_server @@ -1064,6 +1051,7 @@ def test_get_activations_request_wrong( SMTserverIP="192.168.1.1" SMTserverIPv6="fc00::1" SMTserverName="fantasy.example.com" + SMTregistryName="registry-fantasy.example.com" region="antarctica-1"/>''') smt_server = SMT(etree.fromstring(smt_data_ipv46)) mock_get_smt.return_value = smt_server @@ -1113,6 +1101,7 @@ def test_get_activations_request_OK( SMTserverIP="192.168.1.1" SMTserverIPv6="fc00::1" SMTserverName="fantasy.example.com" + SMTregistryName="registry-fantasy.example.com" region="antarctica-1"/>''') smt_server = SMT(etree.fromstring(smt_data_ipv46)) mock_get_smt.return_value = smt_server @@ -1165,6 +1154,7 @@ def test_get_credentials_file_no_file(mock_logging, mock_glob): SMTserverIP="192.168.1.1" SMTserverIPv6="fc00::1" SMTserverName="fantasy.example.com" + SMTregistryName="registry-fantasy.example.com" region="antarctica-1"/>''') smt_server = SMT(etree.fromstring(smt_data_ipv46)) @@ -1190,6 +1180,7 @@ def test_get_credentials_two_files(mock_logging, mock_glob): SMTserverIP="192.168.1.1" SMTserverIPv6="fc00::1" SMTserverName="fantasy.example.com" + SMTregistryName="registry-fantasy.example.com" region="antarctica-1"/>''') smt_server = SMT(etree.fromstring(smt_data_ipv46)) @@ -1215,6 +1206,7 @@ def test_get_current_smt_no_match(mock_get_smt_from_store, mock_os_unlink): SMTserverIP="192.168.1.1" SMTserverIPv6="fc00::1" SMTserverName="fantasy.example.com" + SMTregistryName="registry-fantasy.example.com" region="antarctica-1"/>''') smt_server = SMT(etree.fromstring(smt_data_ipv46)) mock_get_smt_from_store.return_value = smt_server @@ -1228,6 +1220,7 @@ def test_get_current_smt_no_registered(mock_get_smt_from_store): SMTserverIP="192.168.1.1" SMTserverIPv6="fc00::1" SMTserverName="smt-foo.susecloud.net" + SMTregistryName="registry-foo.susecloud.net" region="antarctica-1"/>''') smt_server = SMT(etree.fromstring(smt_data_ipv46)) mock_get_smt_from_store.return_value = smt_server @@ -1250,6 +1243,7 @@ def test_get_current_smt(mock_get_smt_from_store, mock_is_registered): SMTserverIP="192.168.1.1" SMTserverIPv6="fc00::1" SMTserverName="smt-foo.susecloud.net" + SMTregistryName="registry-foo.susecloud.net" region="antarctica-1"/>''') smt_server = SMT(etree.fromstring(smt_data_ipv46)) mock_get_smt_from_store.return_value = smt_server @@ -1551,6 +1545,7 @@ def test_get_smt_network_issue( SMTserverIP="192.168.1.1" SMTserverIPv6="fc00::1" SMTserverName="smt-foo.susecloud.net" + SMTregistryName="registry-foo.susecloud.net" region="antarctica-1"/>''') smt_server = SMT(etree.fromstring(smt_data_ipv46)) mock_get_current_smt.return_value = smt_server @@ -1580,6 +1575,7 @@ def test_get_smt_registered_no_network( SMTserverIP="192.168.1.1" SMTserverIPv6="fc00::1" SMTserverName="smt-foo.susecloud.net" + SMTregistryName="registry-foo.susecloud.net" region="antarctica-1"/>''') smt_server = SMT(etree.fromstring(smt_data_ipv46)) mock_get_current_smt.return_value = smt_server @@ -1622,6 +1618,7 @@ def test_get_smt_find_equivalent( SMTserverIP="192.168.1.1" SMTserverIPv6="fc00::1" SMTserverName="smt-foo.susecloud.net" + SMTregistryName="registry-foo.susecloud.net" region="antarctica-1"/>''') smt_server = SMT(etree.fromstring(smt_data_ipv46)) smt_data_ipv46 = dedent('''\ @@ -1629,6 +1626,7 @@ def test_get_smt_find_equivalent( SMTserverIP="42.168.1.1" SMTserverIPv6="fc00::7" SMTserverName="smt-foo.susecloud.net" + SMTregistryName="registry-foo.susecloud.net" region="antarctica-1"/>''') equivalent_smt_server = SMT(etree.fromstring(smt_data_ipv46)) mock_get_current_smt.return_value = smt_server @@ -1677,6 +1675,7 @@ def test_get_smt_equivalent_smt_no_access( SMTserverIP="192.168.1.1" SMTserverIPv6="fc00::1" SMTserverName="smt-foo.susecloud.net" + SMTregistryName="registry-foo.susecloud.net" region="antarctica-1"/>''') smt_server = SMT(etree.fromstring(smt_data_ipv46)) smt_data_ipv46 = dedent('''\ @@ -1684,6 +1683,7 @@ def test_get_smt_equivalent_smt_no_access( SMTserverIP="42.168.1.1" SMTserverIPv6="fc00::7" SMTserverName="smt-foo.susecloud.net" + SMTregistryName="registry-foo.susecloud.net" region="antarctica-1"/>''') equivalent_smt_server = SMT(etree.fromstring(smt_data_ipv46)) mock_get_current_smt.return_value = smt_server @@ -1729,6 +1729,7 @@ def test_get_smt_alternative_server( SMTserverIP="192.168.1.1" SMTserverIPv6="fc00::1" SMTserverName="smt-foo.susecloud.net" + SMTregistryName="registry-foo.susecloud.net" region="antarctica-1"/>''') alternative_smt_server = SMT(etree.fromstring(smt_data_ipv46)) mock_get_available_smt_servers.return_value = [alternative_smt_server] @@ -1791,6 +1792,7 @@ def test_get_update_server_name_from_hosts(mock_get_available_smt_servers): SMTserverIP="192.168.1.1" SMTserverIPv6="fc00::1" SMTserverName="smt-foo.susecloud.net" + SMTregistryName="registry-foo.susecloud.net" region="antarctica-1"/>''') alternative_smt_server = SMT(etree.fromstring(smt_data_ipv46)) mock_get_available_smt_servers.return_value = [alternative_smt_server] @@ -1832,6 +1834,7 @@ def test_has_ipv6_access_no_ipv6_defined(): ''') smt_server = SMT(etree.fromstring(smt_data_ipv4)) assert utils.has_ipv6_access(smt_server) == False @@ -1846,6 +1849,7 @@ def test_has_ipv6_access_https(mock_https_only, mock_request, mock_get_config): SMTserverIP="192.168.1.1" SMTserverIPv6="fc00::1" SMTserverName="smt-foo.susecloud.net" + SMTregistryName="registry-foo.susecloud.net" region="antarctica-1"/>''') smt_server = SMT(etree.fromstring(smt_data_ipv46)) response = Response() @@ -1874,6 +1878,7 @@ def test_has_ipv6_access_exception( SMTserverIP="192.168.1.1" SMTserverIPv6="fc00::1" SMTserverName="smt-foo.susecloud.net" + SMTregistryName="registry-foo.susecloud.net" region="antarctica-1"/>''') smt_server = SMT(etree.fromstring(smt_data_ipv46)) mock_request.side_effect = Exception("Server's too far, cant be reached") @@ -1960,6 +1965,7 @@ def test_import_smtcert_12_no_write_cert(mock_smt_write_cert): SMTserverIP="192.168.1.1" SMTserverIPv6="fc00::1" SMTserverName="fantasy.example.com" + SMTregistryName="registry-fantasy.example.com" region="antarctica-1"/>''') smt_server = SMT(etree.fromstring(smt_data_ipv46)) @@ -1979,6 +1985,7 @@ def test_import_smtcert_12_no_update_ca_chain( SMTserverIP="192.168.1.1" SMTserverIPv6="fc00::1" SMTserverName="fantasy.example.com" + SMTregistryName="registry-fantasy.example.com" region="antarctica-1"/>''') smt_server = SMT(etree.fromstring(smt_data_ipv46)) @@ -1998,6 +2005,7 @@ def test_import_smtcert_12( SMTserverIP="192.168.1.1" SMTserverIPv6="fc00::1" SMTserverName="fantasy.example.com" + SMTregistryName="registry-fantasy.example.com" region="antarctica-1"/>''') smt_server = SMT(etree.fromstring(smt_data_ipv46)) @@ -2082,6 +2090,7 @@ def test_set_as_current_smt(mock_get_state_dir): SMTserverIP="192.168.1.1" SMTserverIPv6="fc00::1" SMTserverName="fantasy.example.com" + SMTregistryName="registry-fantasy.example.com" region="antarctica-1"/>''') smt_server = SMT(etree.fromstring(smt_data_ipv46)) @@ -2168,6 +2177,7 @@ def test_switch_services_to_plugin_config_parse_error( SMTserverIP="192.168.1.1" SMTserverIPv6="fc00::1" SMTserverName="smt-foo.susecloud.net" + SMTregistryName="registry-foo.susecloud.net" region="antarctica-1"/>''') smt_server = SMT(etree.fromstring(smt_data_ipv46)) mock_get_available_smt_servers.return_value = [smt_server] @@ -2198,6 +2208,7 @@ def test_switch_services_to_plugin_unlink_service( SMTserverIP="192.168.1.1" SMTserverIPv6="fc00::1" SMTserverName="smt-foo.susecloud.net" + SMTregistryName="registry-foo.susecloud.net" region="antarctica-1"/>''') smt_server = SMT(etree.fromstring(smt_data_ipv46)) mock_get_available_smt_servers.return_value = [smt_server] @@ -2280,6 +2291,7 @@ def test_remove_registration_data( SMTserverIP="192.168.1.1" SMTserverIPv6="fc00::1" SMTserverName="smt-foo.susecloud.net" + SMTregistryName="registry-foo.susecloud.net" region="antarctica-1"/>''') smt_server = SMT(etree.fromstring(smt_data_ipv46)) mock_get_smt_from_store.return_value = smt_server @@ -2328,6 +2340,7 @@ def test_remove_registration_data_request_not_OK( SMTserverIP="192.168.1.1" SMTserverIPv6="fc00::1" SMTserverName="smt-foo.susecloud.net" + SMTregistryName="registry-foo.susecloud.net" region="antarctica-1"/>''') smt_server = SMT(etree.fromstring(smt_data_ipv46)) mock_get_smt_from_store.return_value = smt_server @@ -2383,6 +2396,7 @@ def test_remove_registration_data_request_exception( SMTserverIP="192.168.1.1" SMTserverIPv6="fc00::1" SMTserverName="smt-foo.susecloud.net" + SMTregistryName="registry-foo.susecloud.net" region="antarctica-1"/>''') smt_server = SMT(etree.fromstring(smt_data_ipv46)) mock_get_smt_from_store.return_value = smt_server @@ -2417,6 +2431,7 @@ def test_replace_hosts_entry(mock_clean_hosts_file, mock_add_hosts_entry): SMTserverIP="192.168.1.1" SMTserverIPv6="fc00::1" SMTserverName="smt-foo.susecloud.net" + SMTregistryName="registry-foo.susecloud.net" region="antarctica-1"/>''') smt_server = SMT(etree.fromstring(smt_data_ipv46)) utils.replace_hosts_entry(smt_server, 'new_smt') @@ -2455,6 +2470,7 @@ def test_store_smt_data(mock_os_fchmod, mock_pickle, mock_dump): SMTserverIP="192.168.1.1" SMTserverIPv6="fc00::1" SMTserverName="smt-foo.susecloud.net" + SMTregistryName="registry-foo.susecloud.net" region="antarctica-1"/>''') smt_server = SMT(etree.fromstring(smt_data_ipv46)) with tempfile.TemporaryDirectory() as tmpdirname: @@ -2474,6 +2490,7 @@ def test_switch_smt_repos(mock_get_current_smt, mock_glob): SMTserverIP="111.168.1.1" SMTserverIPv6="fc00::1" SMTserverName="ANOTHER_NAME" + SMTregistryName="ANOTHER_REGISTRY_NAME" region="antarctica-1"/>''') new_smt_server = SMT(etree.fromstring(new_smt_data_ipv46)) smt_data_ipv46 = dedent('''\ @@ -2481,6 +2498,7 @@ def test_switch_smt_repos(mock_get_current_smt, mock_glob): SMTserverIP="111.168.1.1" SMTserverIPv6="fc00::1" SMTserverName="plugin:/susecloud" + SMTregistryName="registry-susecloud" region="antarctica-1"/>''') current_smt_server = SMT(etree.fromstring(smt_data_ipv46)) mock_get_current_smt.return_value = current_smt_server @@ -2516,6 +2534,7 @@ def test_switch_smt_service(mock_get_current_smt, mock_glob): SMTserverIP="111.168.1.1" SMTserverIPv6="fc00::1" SMTserverName="ANOTHER_NAME" + SMTregistryName="ANOTHER_REGISTRY_NAME" region="antarctica-1"/>''') new_smt_server = SMT(etree.fromstring(new_smt_data_ipv46)) smt_data_ipv46 = dedent('''\ @@ -2523,6 +2542,7 @@ def test_switch_smt_service(mock_get_current_smt, mock_glob): SMTserverIP="111.168.1.1" SMTserverIPv6="fc00::1" SMTserverName="plugin:/susecloud" + SMTregistryName="registry-susecloud" region="antarctica-1"/>''') current_smt_server = SMT(etree.fromstring(smt_data_ipv46)) mock_get_current_smt.return_value = current_smt_server @@ -2593,6 +2613,7 @@ def test_update_rmt_cert_no_cert_change( SMTserverIP="111.168.1.1" SMTserverIPv6="fc00::1" SMTserverName="ANOTHER_NAME" + SMTregistryName="ANOTHER_REGISTRY_NAME" region="antarctica-1"/>''') smt_server = SMT(etree.fromstring(smt_data_ipv46)) smt_xml = dedent('''\ @@ -2601,6 +2622,7 @@ def test_update_rmt_cert_no_cert_change( SMTserverIP="1.2.3.4" SMTserverIPv6="fc11::2" SMTserverName="foo.susecloud.net" + SMTregistryName="registry-foo.susecloud.net" /> ''') region_smt_data = etree.fromstring(smt_xml) @@ -2634,6 +2656,7 @@ def test_update_rmt_cert( SMTserverIP="111.168.1.1" SMTserverIPv6="fc00::1" SMTserverName="ANOTHER_NAME" + SMTregistryName="ANOTHER_REGISTRY_NAME" region="antarctica-1"/>''') smt_server = SMT(etree.fromstring(smt_data_ipv46)) smt_xml = dedent('''\ @@ -2642,6 +2665,7 @@ def test_update_rmt_cert( SMTserverIP="111.168.1.1" SMTserverIPv6="fc00::1" SMTserverName="foo.susecloud.net" + SMTregistryName="registry-foo.susecloud.net" /> ''') region_smt_data = etree.fromstring(smt_xml) @@ -2882,6 +2906,7 @@ def test_populate_srv_cache( SMTserverIP="1.2.3.4" SMTserverIPv6="fc11::2" SMTserverName="foo.susecloud.net" + SMTregistryName="registry-foo.susecloud.net" /> ''') region_smt_data = etree.fromstring(smt_xml) @@ -2893,6 +2918,7 @@ def test_populate_srv_cache( SMTserverIP="1.2.3.4" SMTserverIPv6="fc11::2" SMTserverName="foo.susecloud.net" + SMTregistryName="registry-foo.susecloud.net" />''') smt_server = SMT(etree.fromstring(smt_data_ipv46)) mock_store_smt_data.assert_called_once_with( @@ -3124,16 +3150,19 @@ def get_servers_data(): \n \n \n @@ -3148,16 +3177,19 @@ def get_modified_servers_data(): \n \n \n diff --git a/tests/test_smt.py b/tests/test_smt.py index d2a7c4ac..11d9c941 100644 --- a/tests/test_smt.py +++ b/tests/test_smt.py @@ -34,12 +34,14 @@ ''') smt_data_ipv6 = dedent('''\ ''') smt_data_ipv46 = dedent('''\ @@ -47,12 +49,14 @@ SMTserverIP="192.168.1.1" SMTserverIPv6="fc00::1" SMTserverName="fantasy.example.com" + SMTregistryName="registry-fantasy.example.com" region="antarctica-1"/>''') smt_data_no_region = dedent('''\ ''') + SMTserverName="fantasy.example.com" + SMTregistryName="registry-fantasy.example.com"/>''') # ---------------------------------------------------------------------------- From cf262d86ecf8ca095e6ee65c78e28307e15a1c24 Mon Sep 17 00:00:00 2001 From: Jesus Bermudez Velazquez Date: Wed, 13 Mar 2024 14:21:43 +0000 Subject: [PATCH 11/18] Handle registry order search - Add registry sidecar RMT and SUSE registry URLs to podmand and docker config files - Add toml to spec file --- cloud-regionsrv-client.spec | 2 + lib/cloudregister/registerutils.py | 90 ++++++++++++++++++++++++++++++ usr/sbin/registercloudguest | 2 +- 3 files changed, 93 insertions(+), 1 deletion(-) diff --git a/cloud-regionsrv-client.spec b/cloud-regionsrv-client.spec index 520e299b..9cbd8ebb 100644 --- a/cloud-regionsrv-client.spec +++ b/cloud-regionsrv-client.spec @@ -41,6 +41,7 @@ Requires: python3-lxml Requires: python3-requests Requires: python3-urllib3 Requires: python3-zypp-plugin +Requires: python3-toml Requires: regionsrv-certs Requires: zypper BuildRequires: systemd @@ -56,6 +57,7 @@ BuildRequires: python3-lxml BuildRequires: python3-requests BuildRequires: python3-setuptools BuildRequires: python3-zypp-plugin +BuildRequires: python3-toml BuildRequires: systemd-rpm-macros BuildRoot: %{_tmppath}/%{name}-%{version}-build diff --git a/lib/cloudregister/registerutils.py b/lib/cloudregister/registerutils.py index 3002b5d7..f306334d 100644 --- a/lib/cloudregister/registerutils.py +++ b/lib/cloudregister/registerutils.py @@ -30,6 +30,7 @@ import subprocess import sys import time +import toml from lxml import etree from pathlib import Path @@ -46,6 +47,8 @@ REGISTERED_SMT_SERVER_DATA_FILE_NAME = 'currentSMTInfo.obj' RMT_AS_SCC_PROXY_MARKER = 'rmt_is_scc_proxy' DOCKER_REGISTRY_CREDENTIALS_PATH = '.docker/config.json' +DOCKER_CONFIG_PATH = '/etc/docker/daemon.json' +REGISTRIES_CONF_PATH = '/etc/containers/registries.conf' # ---------------------------------------------------------------------------- def add_hosts_entry(smt_server): @@ -510,6 +513,12 @@ def get_credentials(credentials_file): return (username, password) +# ---------------------------------------------------------------------------- +def set_registry_config(registry_fqdn, username, password): + set_registry_credentials(registry_fqdn, username, password) + set_registry_order_search(registry_fqdn) + + # ---------------------------------------------------------------------------- def set_registry_credentials(registry_fqdn, username, password): """Set the auth token to pull images from SUSE registry.""" @@ -548,6 +557,87 @@ def set_registry_credentials(registry_fqdn, username, password): ) +# ---------------------------------------------------------------------------- +def set_registry_order_search(registry_fqdn): + registry_location_config = { + 'location': registry_fqdn, + 'insecure': True + } + suse_registry = { + 'location': 'registry.suse.com', + 'insecure': True + } + registries_conf = {} + try: + with open(REGISTRIES_CONF_PATH, 'r') as registries_conf_file: + registries_conf = toml.load(registries_conf_file) + + if registry_fqdn not in registries_conf['unqualified-search-registries']: #no-qa + registries_conf['unqualified-search-registries'] = \ + ["{}".format(registry_fqdn), 'registry.suse.com'] + \ + registries_conf['unqualified-search-registries'] + if suse_registry not in registries_conf['registry']: + registries_conf['registry'] = \ + [suse_registry] + registries_conf['registry'] + if registry_location_config not in registries_conf['registry']: + registries_conf['registry'] = \ + [registry_location_config] + registries_conf['registry'] + except (FileNotFoundError, KeyError): + # file does not exist, create the file + os.makedirs(os.path.dirname(REGISTRIES_CONF_PATH), exist_ok=True) + with open(REGISTRIES_CONF_PATH, 'r') as registries_conf_file: + registries_conf = toml.load(registries_conf_file) + + # one or both keys do not exist + if registries_conf.get('unqualified-search-registries') is None: + registries_conf['unqualified-search-registries'] = \ + ["{}".format(registry_fqdn), 'registry.suse.com'] + if registries_conf.get('registry') is None: + registries_conf['registry'] = \ + [registry_location_config] + [suse_registry] + + with open(REGISTRIES_CONF_PATH, 'w') as registries_conf_file: + toml.dump(registries_conf, registries_conf_file) + + + docker_registry_config = [ + "'{}'".format(registry_fqdn), + 'registry.suse.com' + ] + docker_config_json = {} + try: + with open(DOCKER_CONFIG_PATH, 'r') as docker_config_file_json: + docker_config_json = json.load(docker_config_file_json) + + docker_config_json['registry-mirrors'].update( + docker_registry_config + docker_config_json['registry-mirrors'] + ) + docker_config_json['insecure-registries'].update( + docker_registry_config + docker_config_json['insecure-registries'] + ) + except (FileNotFoundError, KeyError): + # config file does not exist, + # or either "registry-mirrors" key is not set or + # or"insecure-registries" key is not set + os.makedirs(os.path.dirname(DOCKER_CONFIG_PATH), exist_ok=True) + if docker_config_json.get('registry-mirrors') is None: + docker_config_json.update( + {'registry-mirrors': docker_registry_config} + ) + if docker_config_json.get('insecure-registries') is None: + docker_config_json.update( + {'insecure-registries': docker_registry_config} + ) + with open(DOCKER_CONFIG_PATH, 'w') as docker_config_file_json: + json.dump(docker_config_json, docker_config_file_json) + + logging.info( + 'Config for the registry added in %s' % ' and '.join( + [REGISTRIES_CONF_PATH, DOCKER_CONFIG_PATH] + ) + ) + + # ---------------------------------------------------------------------------- def get_credentials_file(update_server, service_name=None): """Return the credentials filename. diff --git a/usr/sbin/registercloudguest b/usr/sbin/registercloudguest index fc539eee..d0d6fa3b 100755 --- a/usr/sbin/registercloudguest +++ b/usr/sbin/registercloudguest @@ -585,7 +585,7 @@ if failed_extensions: print(activate_prod_cmd.format(failed_extension)) # add registry auth token credentials -utils.set_registry_credentials( +utils.set_registry_config( registration_target.get_registry_FQDN(), user, password From ab42bcdfadf2c79da8282c4c15ff4942049036d2 Mon Sep 17 00:00:00 2001 From: Jesus Bermudez Velazquez Date: Wed, 13 Mar 2024 18:46:23 +0000 Subject: [PATCH 12/18] Add podman XDG_RUNTIME_DIR path config settings - Update tests to reflect the change --- lib/cloudregister/registerutils.py | 209 +++++++++++++++-------------- tests/test_registerutils.py | 43 +++--- 2 files changed, 123 insertions(+), 129 deletions(-) diff --git a/lib/cloudregister/registerutils.py b/lib/cloudregister/registerutils.py index f306334d..0b1e6c12 100644 --- a/lib/cloudregister/registerutils.py +++ b/lib/cloudregister/registerutils.py @@ -515,12 +515,20 @@ def get_credentials(credentials_file): # ---------------------------------------------------------------------------- def set_registry_config(registry_fqdn, username, password): - set_registry_credentials(registry_fqdn, username, password) + registry_credentials_paths = [ + os.path.join( + os.path.expanduser('~'), DOCKER_REGISTRY_CREDENTIALS_PATH + ), + os.path.join(os.sep, 'root', DOCKER_REGISTRY_CREDENTIALS_PATH), + os.getenv('XDG_RUNTIME_DIR') # podman path + ] + for cfg_path in registry_credentials_paths: + set_registry_credentials(registry_fqdn, username, password, cfg_path) set_registry_order_search(registry_fqdn) # ---------------------------------------------------------------------------- -def set_registry_credentials(registry_fqdn, username, password): +def set_registry_credentials(registry_fqdn, username, password, cfg_path): """Set the auth token to pull images from SUSE registry.""" auth_token = base64.b64encode('{username}:{password}'.format( username=username, @@ -529,115 +537,33 @@ def set_registry_credentials(registry_fqdn, username, password): registry_credentials = {} registry_credentials[registry_fqdn] = {'auth': auth_token} - docker_paths = [ - os.path.join( - os.path.expanduser('~'), DOCKER_REGISTRY_CREDENTIALS_PATH - ), - os.path.join(os.sep, 'root', DOCKER_REGISTRY_CREDENTIALS_PATH) - ] - for docker_path in docker_paths: - config_json = {} - try: - with open(docker_path, 'r') as cred_json: - config_json = json.load(cred_json) - # file exists - # set the new registry credentials, - # independently of what that content was - config_json['auths'].update(registry_credentials) - except (FileNotFoundError, KeyError): - # config file does not exist or "auths" key is not set - os.makedirs(os.path.dirname(docker_path), exist_ok=True) - config_json.update({'auths': registry_credentials}) - - with open(docker_path, 'w') as cred_json_file: - json.dump(config_json, cred_json_file) - - logging.info( - 'Credentials for the registry added in %s' % ' '.join(docker_paths) - ) - - -# ---------------------------------------------------------------------------- -def set_registry_order_search(registry_fqdn): - registry_location_config = { - 'location': registry_fqdn, - 'insecure': True - } - suse_registry = { - 'location': 'registry.suse.com', - 'insecure': True - } - registries_conf = {} + config_json = {} try: - with open(REGISTRIES_CONF_PATH, 'r') as registries_conf_file: - registries_conf = toml.load(registries_conf_file) - - if registry_fqdn not in registries_conf['unqualified-search-registries']: #no-qa - registries_conf['unqualified-search-registries'] = \ - ["{}".format(registry_fqdn), 'registry.suse.com'] + \ - registries_conf['unqualified-search-registries'] - if suse_registry not in registries_conf['registry']: - registries_conf['registry'] = \ - [suse_registry] + registries_conf['registry'] - if registry_location_config not in registries_conf['registry']: - registries_conf['registry'] = \ - [registry_location_config] + registries_conf['registry'] + with open(cfg_path, 'r') as cred_json: + config_json = json.load(cred_json) + # file exists + # set the new registry credentials, + # independently of what that content was + config_json['auths'].update(registry_credentials) except (FileNotFoundError, KeyError): - # file does not exist, create the file - os.makedirs(os.path.dirname(REGISTRIES_CONF_PATH), exist_ok=True) - with open(REGISTRIES_CONF_PATH, 'r') as registries_conf_file: - registries_conf = toml.load(registries_conf_file) + # config file does not exist or "auths" key is not set + os.makedirs(os.path.dirname(cfg_path), exist_ok=True) + config_json.update({'auths': registry_credentials}) - # one or both keys do not exist - if registries_conf.get('unqualified-search-registries') is None: - registries_conf['unqualified-search-registries'] = \ - ["{}".format(registry_fqdn), 'registry.suse.com'] - if registries_conf.get('registry') is None: - registries_conf['registry'] = \ - [registry_location_config] + [suse_registry] - - with open(REGISTRIES_CONF_PATH, 'w') as registries_conf_file: - toml.dump(registries_conf, registries_conf_file) - - - docker_registry_config = [ - "'{}'".format(registry_fqdn), - 'registry.suse.com' - ] - docker_config_json = {} - try: - with open(DOCKER_CONFIG_PATH, 'r') as docker_config_file_json: - docker_config_json = json.load(docker_config_file_json) - - docker_config_json['registry-mirrors'].update( - docker_registry_config + docker_config_json['registry-mirrors'] - ) - docker_config_json['insecure-registries'].update( - docker_registry_config + docker_config_json['insecure-registries'] - ) - except (FileNotFoundError, KeyError): - # config file does not exist, - # or either "registry-mirrors" key is not set or - # or"insecure-registries" key is not set - os.makedirs(os.path.dirname(DOCKER_CONFIG_PATH), exist_ok=True) - if docker_config_json.get('registry-mirrors') is None: - docker_config_json.update( - {'registry-mirrors': docker_registry_config} - ) - if docker_config_json.get('insecure-registries') is None: - docker_config_json.update( - {'insecure-registries': docker_registry_config} - ) - with open(DOCKER_CONFIG_PATH, 'w') as docker_config_file_json: - json.dump(docker_config_json, docker_config_file_json) + with open(cfg_path, 'w') as cred_json_file: + json.dump(config_json, cred_json_file) logging.info( - 'Config for the registry added in %s' % ' and '.join( - [REGISTRIES_CONF_PATH, DOCKER_CONFIG_PATH] - ) + 'Credentials for the registry added in %s' % ' '.join(cfg_path) ) +# ---------------------------------------------------------------------------- +def set_registry_order_search(registry_fqdn): + _set_registry_order_search_podman(registry_fqdn) + _set_registry_order_search_docker(registry_fqdn) + + # ---------------------------------------------------------------------------- def get_credentials_file(update_server, service_name=None): """Return the credentials filename. @@ -1777,3 +1703,80 @@ def __replace_url_target(config_files, new_smt): current_service_server, new_smt.get_FQDN()) ) + + +# ---------------------------------------------------------------------------- +def _set_registry_order_search_podman(registry_fqdn): + registry_location_config = {'location': registry_fqdn, 'insecure': True} + suse_registry = {'location': 'registry.suse.com', 'insecure': True} + registries_conf = {} + try: + with open(REGISTRIES_CONF_PATH, 'r') as registries_conf_file: + registries_conf = toml.load(registries_conf_file) + + if registry_fqdn not in registries_conf['unqualified-search-registries']: # no-qa + registries_conf['unqualified-search-registries'] = \ + ["{}".format(registry_fqdn), 'registry.suse.com'] + \ + registries_conf['unqualified-search-registries'] + if suse_registry not in registries_conf['registry']: + registries_conf['registry'] = \ + [suse_registry] + registries_conf['registry'] + if registry_location_config not in registries_conf['registry']: + registries_conf['registry'] = \ + [registry_location_config] + registries_conf['registry'] + except (FileNotFoundError, KeyError): + # file does not exist, create the file + os.makedirs(os.path.dirname(REGISTRIES_CONF_PATH), exist_ok=True) + with open(REGISTRIES_CONF_PATH, 'r') as registries_conf_file: + registries_conf = toml.load(registries_conf_file) + + # one or both keys do not exist + if registries_conf.get('unqualified-search-registries') is None: + registries_conf['unqualified-search-registries'] = \ + ["{}".format(registry_fqdn), 'registry.suse.com'] + if registries_conf.get('registry') is None: + registries_conf['registry'] = \ + [registry_location_config] + [suse_registry] + + with open(REGISTRIES_CONF_PATH, 'w') as registries_conf_file: + toml.dump(registries_conf, registries_conf_file) + + +# ---------------------------------------------------------------------------- +def _set_registry_order_search_docker(registry_fqdn): + docker_registry_config = [ + "'{}'".format(registry_fqdn), + 'registry.suse.com' + ] + docker_config_json = {} + try: + with open(DOCKER_CONFIG_PATH, 'r') as docker_config_file_json: + docker_config_json = json.load(docker_config_file_json) + + docker_config_json['registry-mirrors'].update( + docker_registry_config + docker_config_json['registry-mirrors'] + ) + docker_config_json['insecure-registries'].update( + docker_registry_config + docker_config_json['insecure-registries'] + ) + except (FileNotFoundError, KeyError): + # config file does not exist, + # or either "registry-mirrors" key is not set or + # or"insecure-registries" key is not set + os.makedirs(os.path.dirname(DOCKER_CONFIG_PATH), exist_ok=True) + if docker_config_json.get('registry-mirrors') is None: + docker_config_json.update( + {'registry-mirrors': docker_registry_config} + ) + if docker_config_json.get('insecure-registries') is None: + docker_config_json.update( + {'insecure-registries': docker_registry_config} + ) + with open(DOCKER_CONFIG_PATH, 'w') as docker_config_file_json: + json.dump(docker_config_json, docker_config_file_json) + + logging.info( + 'Config for the registry added in %s' % ' and '.join( + [REGISTRIES_CONF_PATH, DOCKER_CONFIG_PATH] + ) + ) diff --git a/tests/test_registerutils.py b/tests/test_registerutils.py index b7ffe601..35358141 100644 --- a/tests/test_registerutils.py +++ b/tests/test_registerutils.py @@ -3058,9 +3058,6 @@ def test_set_registry_credentials_config_does_not_exist( password=password ).encode()).decode() - mock_os_join.return_value = '/home/foo/non_file' - - # with patch('builtins.open', side_effect=FileExistsError()): with patch('builtins.open', create=True) as mock_open: mock_open_docker_config = MagicMock(spec=io.IOBase) def open_file(filename, mode): @@ -3070,18 +3067,20 @@ def open_file(filename, mode): raise FileNotFoundError() mock_open.side_effect = open_file - file_handle = mock_open_docker_config.return_value.__enter__.return_value + file_handle = \ + mock_open_docker_config.return_value.__enter__.return_value file_handle.read.return_value = '' - utils.set_registry_credentials('127.0.0.1', username, password) + mock_os_join.return_value = '/home/foo/non_file' + utils.set_registry_credentials( + '127.0.0.1', + username, + password, + mock_os_join.return_value + ) assert mock_makedirs.call_args_list == [ - call('/home/foo', exist_ok=True), call('/home/foo', exist_ok=True) ] assert mock_json_dump.call_args_list == [ - call( - {"auths": {"127.0.0.1": {"auth": expected_auth_token}}}, - file_handle - ), call( {"auths": {"127.0.0.1": {"auth": expected_auth_token}}}, file_handle @@ -3107,8 +3106,6 @@ def test_set_registry_credentials_config_does_exist( password=password ).encode()).decode() - mock_os_join.return_value = '/home/foo/non_file' - with patch('builtins.open', create=True) as mock_open: mock_open_docker_config = MagicMock(spec=io.IOBase) def open_file(filename, mode): @@ -3118,22 +3115,16 @@ def open_file(filename, mode): file_handle = \ mock_open_docker_config.return_value.__enter__.return_value file_handle.read.return_value = '' - mock_json_load.return_value = { - "auths": { - "127.0.0.1": { - "auth": 'foo' - } - } - } - utils.set_registry_credentials('127.0.0.1', username, password) + mock_json_load.return_value = {"auths":{"127.0.0.1": {"auth": 'foo'}}} + + utils.set_registry_credentials('127.0.0.1', username, password, '') + assert mock_makedirs.call_args_list == [] assert mock_json_dump.call_args_list == [ - call({ - "auths": {"127.0.0.1": {"auth": expected_auth_token}} - }, file_handle), - call({ - "auths": {"127.0.0.1": {"auth": expected_auth_token}} - }, file_handle) + call( + {"auths": {"127.0.0.1": {"auth": expected_auth_token}}}, + file_handle + ) ] From 243d380698aa53daf8038ea51a25b530c3251124 Mon Sep 17 00:00:00 2001 From: Jesus Bermudez Velazquez Date: Thu, 14 Mar 2024 10:26:47 +0000 Subject: [PATCH 13/18] Update docker config urls setting --- lib/cloudregister/registerutils.py | 35 +++++++++++------------------- 1 file changed, 13 insertions(+), 22 deletions(-) diff --git a/lib/cloudregister/registerutils.py b/lib/cloudregister/registerutils.py index 0b1e6c12..f0b56f33 100644 --- a/lib/cloudregister/registerutils.py +++ b/lib/cloudregister/registerutils.py @@ -1744,36 +1744,27 @@ def _set_registry_order_search_podman(registry_fqdn): # ---------------------------------------------------------------------------- def _set_registry_order_search_docker(registry_fqdn): - docker_registry_config = [ - "'{}'".format(registry_fqdn), - 'registry.suse.com' + insecure_urls = mirrors_urls = [ + 'https://{}'.format(registry_fqdn), + 'https://registry.suse.com' ] - docker_config_json = {} + docker_cfg_json = {} try: with open(DOCKER_CONFIG_PATH, 'r') as docker_config_file_json: - docker_config_json = json.load(docker_config_file_json) + docker_cfg_json = json.load(docker_config_file_json) - docker_config_json['registry-mirrors'].update( - docker_registry_config + docker_config_json['registry-mirrors'] - ) - docker_config_json['insecure-registries'].update( - docker_registry_config + docker_config_json['insecure-registries'] - ) + mirrors_urls += docker_cfg_json['registry-mirrors'] + insecure_urls += docker_cfg_json['insecure-registries'] except (FileNotFoundError, KeyError): # config file does not exist, - # or either "registry-mirrors" key is not set or - # or"insecure-registries" key is not set + # "registry-mirrors" key is not set or + # "insecure-registries" key is not set os.makedirs(os.path.dirname(DOCKER_CONFIG_PATH), exist_ok=True) - if docker_config_json.get('registry-mirrors') is None: - docker_config_json.update( - {'registry-mirrors': docker_registry_config} - ) - if docker_config_json.get('insecure-registries') is None: - docker_config_json.update( - {'insecure-registries': docker_registry_config} - ) + + docker_cfg_json['registry-mirrors'] = mirrors_urls + docker_cfg_json['insecure-registries'] = insecure_urls with open(DOCKER_CONFIG_PATH, 'w') as docker_config_file_json: - json.dump(docker_config_json, docker_config_file_json) + json.dump(docker_cfg_json, docker_config_file_json) logging.info( 'Config for the registry added in %s' % ' and '.join( From 6c0eaf0f2dd13bd22ff243c3e1a137e81fc1f74c Mon Sep 17 00:00:00 2001 From: Jesus Bermudez Velazquez Date: Wed, 17 Apr 2024 19:05:04 +0100 Subject: [PATCH 14/18] Adjustments after merge master --- .virtualenv.requirements.txt | 1 + lib/cloudregister/registerutils.py | 5 ++++- tests/test_registerutils.py | 18 +++++++++++------- 3 files changed, 16 insertions(+), 8 deletions(-) diff --git a/.virtualenv.requirements.txt b/.virtualenv.requirements.txt index 38f3fb0d..1dfcf10f 100644 --- a/.virtualenv.requirements.txt +++ b/.virtualenv.requirements.txt @@ -2,3 +2,4 @@ lxml requests dnspython M2Crypto +toml diff --git a/lib/cloudregister/registerutils.py b/lib/cloudregister/registerutils.py index b3db666e..a5ec70b1 100644 --- a/lib/cloudregister/registerutils.py +++ b/lib/cloudregister/registerutils.py @@ -50,6 +50,7 @@ DOCKER_CONFIG_PATH = '/etc/docker/daemon.json' REGISTRIES_CONF_PATH = '/etc/containers/registries.conf' + # ---------------------------------------------------------------------------- def add_hosts_entry(smt_server): """Add an entry to the /etc/hosts file for the given SMT server""" @@ -1726,7 +1727,9 @@ def _set_registry_order_search_podman(registry_fqdn): with open(REGISTRIES_CONF_PATH, 'r') as registries_conf_file: registries_conf = toml.load(registries_conf_file) - if registry_fqdn not in registries_conf['unqualified-search-registries']: # no-qa + missing_registry_fqdn = registry_fqdn not in \ + registries_conf['unqualified-search-registries'] + if missing_registry_fqdn: registries_conf['unqualified-search-registries'] = \ ["{}".format(registry_fqdn), 'registry.suse.com'] + \ registries_conf['unqualified-search-registries'] diff --git a/tests/test_registerutils.py b/tests/test_registerutils.py index 6a606804..133cc7e6 100644 --- a/tests/test_registerutils.py +++ b/tests/test_registerutils.py @@ -533,12 +533,14 @@ def test_add_hosts_entry(mock_has_ipv6_access): '\n# Added by SMT registration do not remove, ' 'retain comment as well\n' ) - file_content_entry = '{ip}\t{fqdn}\t{name}\n{ip_reg}\t{reg_name}\n'.format( - ip=smt_server.get_ipv6(), - fqdn=smt_server.get_FQDN(), - name=smt_server.get_name(), - ip_reg=smt_server.get_ipv6(), - reg_name=smt_server.get_registry_FQDN() + file_content_entry = ( + '{ip}\t{fqdn}\t{name}\n{ip_reg}\t{reg_name}\n'.format( + ip=smt_server.get_ipv6(), + fqdn=smt_server.get_FQDN(), + name=smt_server.get_name(), + ip_reg=smt_server.get_ipv6(), + reg_name=smt_server.get_registry_FQDN() + ) ) assert file_handle.write.mock_calls == [ call(file_content_comment), @@ -3055,6 +3057,7 @@ def test_set_registry_credentials_config_does_not_exist( with patch('builtins.open', create=True) as mock_open: mock_open_docker_config = MagicMock(spec=io.IOBase) + def open_file(filename, mode): if mode == 'w': return mock_open_docker_config.return_value @@ -3103,6 +3106,7 @@ def test_set_registry_credentials_config_does_exist( with patch('builtins.open', create=True) as mock_open: mock_open_docker_config = MagicMock(spec=io.IOBase) + def open_file(filename, mode): return mock_open_docker_config.return_value @@ -3110,7 +3114,7 @@ def open_file(filename, mode): file_handle = \ mock_open_docker_config.return_value.__enter__.return_value file_handle.read.return_value = '' - mock_json_load.return_value = {"auths":{"127.0.0.1": {"auth": 'foo'}}} + mock_json_load.return_value = {"auths": {"127.0.0.1": {"auth": 'foo'}}} utils.set_registry_credentials('127.0.0.1', username, password, '') From a994cc4031010fa7ee24e6c875f80bb1ff832092 Mon Sep 17 00:00:00 2001 From: Jesus Bermudez Velazquez Date: Tue, 23 Apr 2024 17:00:08 +0100 Subject: [PATCH 15/18] Update config - For podman set registry outside the unqualified search registries in order to be able to inform the user when credentials expired and a reauth is needed - For docker do not add registry-.susecloud.net to the search docker does not suppoert auth search, and the registry will not show free repos - Update tests --- lib/cloudregister/registerutils.py | 70 ++++---- tests/data/registry_conf.conf | 5 + tests/data/unconfigured_registry.conf | 4 + tests/test_registerutils.py | 220 ++++++++++++++++++++++++++ 4 files changed, 268 insertions(+), 31 deletions(-) create mode 100644 tests/data/registry_conf.conf create mode 100644 tests/data/unconfigured_registry.conf diff --git a/lib/cloudregister/registerutils.py b/lib/cloudregister/registerutils.py index a5ec70b1..bfdf01d7 100644 --- a/lib/cloudregister/registerutils.py +++ b/lib/cloudregister/registerutils.py @@ -1720,64 +1720,72 @@ def __replace_url_target(config_files, new_smt): # ---------------------------------------------------------------------------- def _set_registry_order_search_podman(registry_fqdn): - registry_location_config = {'location': registry_fqdn, 'insecure': True} - suse_registry = {'location': 'registry.suse.com', 'insecure': True} + public_registry_fqdn = 'registry.suse.com' + private_registry = {'location': registry_fqdn, 'insecure': False} + public_registry = {'location': public_registry_fqdn, 'insecure': False} registries_conf = {} try: - with open(REGISTRIES_CONF_PATH, 'r') as registries_conf_file: - registries_conf = toml.load(registries_conf_file) - - missing_registry_fqdn = registry_fqdn not in \ + registries_conf = _get_registry_conf_file( + REGISTRIES_CONF_PATH, 'podman' + ) + missing_public_registry = public_registry_fqdn not in \ registries_conf['unqualified-search-registries'] - if missing_registry_fqdn: + if missing_public_registry: registries_conf['unqualified-search-registries'] = \ - ["{}".format(registry_fqdn), 'registry.suse.com'] + \ + [public_registry_fqdn] + \ registries_conf['unqualified-search-registries'] - if suse_registry not in registries_conf['registry']: + if public_registry not in registries_conf['registry']: registries_conf['registry'] = \ - [suse_registry] + registries_conf['registry'] - if registry_location_config not in registries_conf['registry']: + [public_registry] + registries_conf['registry'] + if private_registry not in registries_conf['registry']: registries_conf['registry'] = \ - [registry_location_config] + registries_conf['registry'] + [private_registry] + registries_conf['registry'] except (FileNotFoundError, KeyError): # file does not exist, create the file os.makedirs(os.path.dirname(REGISTRIES_CONF_PATH), exist_ok=True) - with open(REGISTRIES_CONF_PATH, 'r') as registries_conf_file: - registries_conf = toml.load(registries_conf_file) - + registries_conf = _get_registry_conf_file( + REGISTRIES_CONF_PATH, 'podman' + ) # one or both keys do not exist if registries_conf.get('unqualified-search-registries') is None: registries_conf['unqualified-search-registries'] = \ - ["{}".format(registry_fqdn), 'registry.suse.com'] + ["{}".format(public_registry_fqdn)] if registries_conf.get('registry') is None: registries_conf['registry'] = \ - [registry_location_config] + [suse_registry] + [private_registry] + [public_registry] with open(REGISTRIES_CONF_PATH, 'w') as registries_conf_file: toml.dump(registries_conf, registries_conf_file) # ---------------------------------------------------------------------------- -def _set_registry_order_search_docker(registry_fqdn): - insecure_urls = mirrors_urls = [ - 'https://{}'.format(registry_fqdn), - 'https://registry.suse.com' - ] +def _get_registry_conf_file(container_path, container): + if container in 'podman': + with open(container_path, 'r') as registries_conf_file: + registries_conf = toml.load(registries_conf_file) + if container in 'docker': + with open(container_path, 'r') as registries_conf_file: + registries_conf = json.load(registries_conf_file) + + return registries_conf + + +# ---------------------------------------------------------------------------- +def _set_registry_order_search_docker(): + # search is disabled for Docker server side for private registry + secure_urls = ['https://registry.suse.com'] + mirrors_urls = ['https://registry.suse.com'] docker_cfg_json = {} try: - with open(DOCKER_CONFIG_PATH, 'r') as docker_config_file_json: - docker_cfg_json = json.load(docker_config_file_json) - - mirrors_urls += docker_cfg_json['registry-mirrors'] - insecure_urls += docker_cfg_json['insecure-registries'] - except (FileNotFoundError, KeyError): + docker_cfg_json = _get_registry_conf_file(DOCKER_CONFIG_PATH, 'docker') + secure_urls += docker_cfg_json.get('secure-registries', []) + mirrors_urls += docker_cfg_json.get('registry-mirrors', []) + except (FileNotFoundError): # , KeyError): # config file does not exist, - # "registry-mirrors" key is not set or - # "insecure-registries" key is not set os.makedirs(os.path.dirname(DOCKER_CONFIG_PATH), exist_ok=True) docker_cfg_json['registry-mirrors'] = mirrors_urls - docker_cfg_json['insecure-registries'] = insecure_urls + docker_cfg_json['secure-registries'] = secure_urls with open(DOCKER_CONFIG_PATH, 'w') as docker_config_file_json: json.dump(docker_cfg_json, docker_config_file_json) diff --git a/tests/data/registry_conf.conf b/tests/data/registry_conf.conf new file mode 100644 index 00000000..12ce1809 --- /dev/null +++ b/tests/data/registry_conf.conf @@ -0,0 +1,5 @@ +unqualified-search-registries = ["foo.com", "bar.registry.com", "docker.io"] + +[[registry]] +location = "foo.com" +insecure = true diff --git a/tests/data/unconfigured_registry.conf b/tests/data/unconfigured_registry.conf new file mode 100644 index 00000000..e6ed5a25 --- /dev/null +++ b/tests/data/unconfigured_registry.conf @@ -0,0 +1,4 @@ +search-registries = ["docker.io"] + +[[no-registry]] +location = "foo" diff --git a/tests/test_registerutils.py b/tests/test_registerutils.py index 133cc7e6..b79b8f8f 100644 --- a/tests/test_registerutils.py +++ b/tests/test_registerutils.py @@ -20,6 +20,7 @@ import requests import sys import tempfile +import toml from pytest import raises from textwrap import dedent @@ -1920,6 +1921,27 @@ def test_has_services_service(mock_get_service_plugins): assert utils.has_services('foo') is True +@patch('cloudregister.registerutils.glob.glob') +@patch('cloudregister.registerutils.__get_service_plugins') +def test_has_no_services( + mock_get_service_plugins, mock_glob_glob +): + mock_glob_glob.return_value = [] + mock_get_service_plugins.return_value = None + assert utils.has_services('foo') is False + + +@patch('cloudregister.registerutils.glob.glob') +@patch('cloudregister.registerutils.__get_referenced_credentials') +@patch('cloudregister.registerutils.__get_service_plugins') +def test_is_registered(mock_service_plugin, mock_ref_creds, mock_glob_glob): + mock_glob_glob.return_value = [] + mock_service_plugin.return_value = None + mock_ref_creds.return_value = None + + assert utils.is_registered('foo') is False + + @patch('cloudregister.registerutils.requests.post') @patch('cloudregister.registerutils.HTTPBasicAuth') def test_has_smt_access_unauthorized(mock_http_basic_auth, mock_post): @@ -3127,6 +3149,204 @@ def open_file(filename, mode): ] +@patch('cloudregister.registerutils._set_registry_order_search_docker') +@patch('cloudregister.registerutils._set_registry_order_search_podman') +def test_set_registry_order_search(mock_podman_order, mock_docker_order): + utils.set_registry_order_search('foo') + mock_podman_order.assert_called_once_with('foo') + mock_docker_order.assert_called_once_with('foo') + + +@patch('cloudregister.registerutils.toml.dump') +@patch('cloudregister.registerutils._get_registry_conf_file') +@patch('cloudregister.registerutils.os.makedirs') +def test_set_registry_order_search_podman_no_configured( + mock_os_makedirs, mock_get_registry_file, mock_toml_dump +): + with open('tests/data/unconfigured_registry.conf') as f: + registry_conf = toml.load(f) + mock_get_registry_file.side_effect = [FileNotFoundError(), registry_conf] + with patch('builtins.open', create=True) as mock_open: + mock_open_podman_config = MagicMock(spec=io.IOBase) + def open_file(filename, mode): + return mock_open_podman_config.return_value + + mock_open.side_effect = open_file + file_handle = \ + mock_open_podman_config.return_value.__enter__.return_value + utils._set_registry_order_search_podman('rmt-registry.susecloud.net') + mock_os_makedirs.assert_called_once_with( + '/etc/containers', + exist_ok=True + ) + mock_toml_dump.assert_called_once_with( + { + 'search-registries': ['docker.io'], + 'no-registry': [{'location': 'foo'}], + 'unqualified-search-registries': ['registry.suse.com'], + 'registry': [ + { + 'location': 'rmt-registry.susecloud.net', + 'insecure': False + }, + {'location': 'registry.suse.com', 'insecure': False} + ] + }, + file_handle + ) + + +@patch('cloudregister.registerutils.toml.dump') +@patch('cloudregister.registerutils._get_registry_conf_file') +def test_set_registry_order_search_podman_conf_missing_suse_registry( + mock_get_registry_file, mock_toml_dump +): + with open('tests/data/registry_conf.conf') as f: + registry_conf = toml.load(f) + mock_get_registry_file.return_value = registry_conf + with patch('builtins.open', create=True) as mock_open: + mock_open_podman_config = MagicMock(spec=io.IOBase) + def open_file(filename, mode): + return mock_open_podman_config.return_value + + mock_open.side_effect = open_file + file_handle = \ + mock_open_podman_config.return_value.__enter__.return_value + utils._set_registry_order_search_podman('rmt-registry.susecloud.net') + mock_toml_dump.assert_called_once_with( + { + 'unqualified-search-registries': [ + 'registry.suse.com', + 'foo.com', + 'bar.registry.com', + 'docker.io', + ], + 'registry': [ + { + 'location': 'rmt-registry.susecloud.net', + 'insecure': False + }, + {'location': 'registry.suse.com', 'insecure': False}, + {'location': 'foo.com', 'insecure': True} + ] + }, + file_handle + ) + + +@patch('cloudregister.registerutils.toml.load') +def test_get_registry_config_file_podman(mock_toml_load): + with patch('builtins.open') as mock_open: + mock_open_podman_config = MagicMock(spec=io.IOBase) + + def open_file(filename, mode): + return mock_open_podman_config.return_value + + mock_open.side_effect = open_file + utils._get_registry_conf_file( + '/etc/containers/registries.conf', 'podman' + ) + mock_toml_load.assert_called_once() + + +@patch('cloudregister.registerutils.json.load') +def test_get_registry_config_file_docker(mock_json_load): + with patch('builtins.open') as mock_open: + mock_open_podman_config = MagicMock(spec=io.IOBase) + + def open_file(filename, mode): + return mock_open_podman_config.return_value + + mock_open.side_effect = open_file + utils._get_registry_conf_file( + '/etc/containers/registries.conf', 'docker' + ) + mock_json_load.assert_called_once() + + +@patch('cloudregister.registerutils._get_registry_conf_file') +@patch('cloudregister.registerutils.json.dump') +def test_set_registry_order_search_docker_not_key_secure( + mock_json_dump, mock_get_registry_conf_file +): + with patch('builtins.open', create=True) as mock_open: + mock_open_podman_config = MagicMock(spec=io.IOBase) + def open_file(filename, mode): + return mock_open_podman_config.return_value + + mock_open.side_effect = open_file + file_handle = \ + mock_open_podman_config.return_value.__enter__.return_value + mock_get_registry_conf_file.return_value = { + 'registry-mirrors': ['foo'], + 'bar': ['bar'], + } + utils._set_registry_order_search_docker() + mock_json_dump.assert_called_once_with( + { + 'registry-mirrors': ['https://registry.suse.com', 'foo'], + 'bar': ['bar'], + 'secure-registries': ['https://registry.suse.com'] + }, + file_handle + ) + + +@patch('cloudregister.registerutils._get_registry_conf_file') +@patch('cloudregister.registerutils.json.dump') +def test_set_registry_order_search_docker_not_key_mirror( + mock_json_dump, mock_get_registry_conf_file +): + with patch('builtins.open', create=True) as mock_open: + mock_open_podman_config = MagicMock(spec=io.IOBase) + def open_file(filename, mode): + return mock_open_podman_config.return_value + + mock_open.side_effect = open_file + file_handle = \ + mock_open_podman_config.return_value.__enter__.return_value + mock_get_registry_conf_file.return_value = { + 'foo': ['foo'], + 'secure-registries': ['bar'], + } + utils._set_registry_order_search_docker() + mock_json_dump.assert_called_once_with( + { + 'foo': ['foo'], + 'registry-mirrors': ['https://registry.suse.com'], + 'secure-registries': ['https://registry.suse.com', 'bar'] + }, + file_handle + ) + + +@patch('cloudregister.registerutils.os.makedirs') +@patch('cloudregister.registerutils._get_registry_conf_file') +@patch('cloudregister.registerutils.json.dump') +def test_set_registry_order_search_docker_not_file( + mock_json_dump, mock_get_registry_conf_file, + mock_os_makedirs +): + with patch('builtins.open', create=True) as mock_open: + mock_open_podman_config = MagicMock(spec=io.IOBase) + def open_file(filename, mode): + return mock_open_podman_config.return_value + + mock_open.side_effect = open_file + file_handle = \ + mock_open_podman_config.return_value.__enter__.return_value + mock_get_registry_conf_file.side_effect = [FileNotFoundError(), {}] + utils._set_registry_order_search_docker() + mock_json_dump.assert_called_once_with( + { + 'registry-mirrors': ['https://registry.suse.com'], + 'secure-registries': ['https://registry.suse.com'] + }, + file_handle + ) + mock_os_makedirs.assert_called_once() + + # --------------------------------------------------------------------------- # Helper functions class Response(): From 1046b56b19cb2c3ced4411165e9cf3f4996b3106 Mon Sep 17 00:00:00 2001 From: Jesus Bermudez Velazquez Date: Tue, 23 Apr 2024 17:18:55 +0100 Subject: [PATCH 16/18] Fix linter --- lib/cloudregister/registerutils.py | 2 +- tests/test_registerutils.py | 11 ++++++++--- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/lib/cloudregister/registerutils.py b/lib/cloudregister/registerutils.py index bfdf01d7..19f326b8 100644 --- a/lib/cloudregister/registerutils.py +++ b/lib/cloudregister/registerutils.py @@ -1780,7 +1780,7 @@ def _set_registry_order_search_docker(): docker_cfg_json = _get_registry_conf_file(DOCKER_CONFIG_PATH, 'docker') secure_urls += docker_cfg_json.get('secure-registries', []) mirrors_urls += docker_cfg_json.get('registry-mirrors', []) - except (FileNotFoundError): # , KeyError): + except (FileNotFoundError): # config file does not exist, os.makedirs(os.path.dirname(DOCKER_CONFIG_PATH), exist_ok=True) diff --git a/tests/test_registerutils.py b/tests/test_registerutils.py index b79b8f8f..c2a752c7 100644 --- a/tests/test_registerutils.py +++ b/tests/test_registerutils.py @@ -3168,6 +3168,7 @@ def test_set_registry_order_search_podman_no_configured( mock_get_registry_file.side_effect = [FileNotFoundError(), registry_conf] with patch('builtins.open', create=True) as mock_open: mock_open_podman_config = MagicMock(spec=io.IOBase) + def open_file(filename, mode): return mock_open_podman_config.return_value @@ -3206,6 +3207,7 @@ def test_set_registry_order_search_podman_conf_missing_suse_registry( mock_get_registry_file.return_value = registry_conf with patch('builtins.open', create=True) as mock_open: mock_open_podman_config = MagicMock(spec=io.IOBase) + def open_file(filename, mode): return mock_open_podman_config.return_value @@ -3269,8 +3271,9 @@ def open_file(filename, mode): def test_set_registry_order_search_docker_not_key_secure( mock_json_dump, mock_get_registry_conf_file ): - with patch('builtins.open', create=True) as mock_open: + with patch('builtins.open', create=True) as mock_open: mock_open_podman_config = MagicMock(spec=io.IOBase) + def open_file(filename, mode): return mock_open_podman_config.return_value @@ -3297,8 +3300,9 @@ def open_file(filename, mode): def test_set_registry_order_search_docker_not_key_mirror( mock_json_dump, mock_get_registry_conf_file ): - with patch('builtins.open', create=True) as mock_open: + with patch('builtins.open', create=True) as mock_open: mock_open_podman_config = MagicMock(spec=io.IOBase) + def open_file(filename, mode): return mock_open_podman_config.return_value @@ -3327,8 +3331,9 @@ def test_set_registry_order_search_docker_not_file( mock_json_dump, mock_get_registry_conf_file, mock_os_makedirs ): - with patch('builtins.open', create=True) as mock_open: + with patch('builtins.open', create=True) as mock_open: mock_open_podman_config = MagicMock(spec=io.IOBase) + def open_file(filename, mode): return mock_open_podman_config.return_value From 6df7b70b9ba0b7688e6230c209315ef92146da55 Mon Sep 17 00:00:00 2001 From: Jesus Bermudez Velazquez Date: Tue, 23 Apr 2024 17:44:30 +0100 Subject: [PATCH 17/18] Add tests for config --- lib/cloudregister/registerutils.py | 1 - tests/test_registerutils.py | 26 ++++++++++++++++++++++++++ 2 files changed, 26 insertions(+), 1 deletion(-) diff --git a/lib/cloudregister/registerutils.py b/lib/cloudregister/registerutils.py index 19f326b8..974b2eef 100644 --- a/lib/cloudregister/registerutils.py +++ b/lib/cloudregister/registerutils.py @@ -524,7 +524,6 @@ def set_registry_config(registry_fqdn, username, password): os.path.expanduser('~'), DOCKER_REGISTRY_CREDENTIALS_PATH ), os.path.join(os.sep, 'root', DOCKER_REGISTRY_CREDENTIALS_PATH), - os.getenv('XDG_RUNTIME_DIR') # podman path ] for cfg_path in registry_credentials_paths: set_registry_credentials(registry_fqdn, username, password, cfg_path) diff --git a/tests/test_registerutils.py b/tests/test_registerutils.py index c2a752c7..ac30b875 100644 --- a/tests/test_registerutils.py +++ b/tests/test_registerutils.py @@ -3149,6 +3149,32 @@ def open_file(filename, mode): ] +@patch('cloudregister.registerutils.os.path.expanduser') +@patch('cloudregister.registerutils.set_registry_order_search') +@patch('cloudregister.registerutils.set_registry_credentials') +def test_set_registry_config( + mock_set_registry_cred, mock_set_registry_search, mock_os_path_expanduser +): + mock_os_path_expanduser.return_value = 'regular_path' + utils.set_registry_config('registry_fqdn', 'username', 'pass') + assert mock_set_registry_cred.call_args_list == [ + call( + 'registry_fqdn', + 'username', + 'pass', + 'regular_path/.docker/config.json' + ), + call( + 'registry_fqdn', + 'username', + 'pass', + '/root/.docker/config.json' + ) + + ] + mock_set_registry_search.assert_called_once_with('registry_fqdn') + + @patch('cloudregister.registerutils._set_registry_order_search_docker') @patch('cloudregister.registerutils._set_registry_order_search_podman') def test_set_registry_order_search(mock_podman_order, mock_docker_order): From a216b08a36ca2bd7cebc7ffa27e307b7e1d57620 Mon Sep 17 00:00:00 2001 From: Jesus Bermudez Velazquez Date: Wed, 24 Apr 2024 10:54:43 +0100 Subject: [PATCH 18/18] Clearer check - Remove duplication - Add check for Docker - Log if configuration files not found --- lib/cloudregister/registerutils.py | 82 ++++++++++++++++-------------- tests/test_registerutils.py | 2 - 2 files changed, 44 insertions(+), 40 deletions(-) diff --git a/lib/cloudregister/registerutils.py b/lib/cloudregister/registerutils.py index 974b2eef..bdd8446c 100644 --- a/lib/cloudregister/registerutils.py +++ b/lib/cloudregister/registerutils.py @@ -1723,35 +1723,34 @@ def _set_registry_order_search_podman(registry_fqdn): private_registry = {'location': registry_fqdn, 'insecure': False} public_registry = {'location': public_registry_fqdn, 'insecure': False} registries_conf = {} + registries_search = [] + registries = [] try: registries_conf = _get_registry_conf_file( REGISTRIES_CONF_PATH, 'podman' ) - missing_public_registry = public_registry_fqdn not in \ - registries_conf['unqualified-search-registries'] - if missing_public_registry: - registries_conf['unqualified-search-registries'] = \ - [public_registry_fqdn] + \ - registries_conf['unqualified-search-registries'] - if public_registry not in registries_conf['registry']: - registries_conf['registry'] = \ - [public_registry] + registries_conf['registry'] - if private_registry not in registries_conf['registry']: - registries_conf['registry'] = \ - [private_registry] + registries_conf['registry'] - except (FileNotFoundError, KeyError): + registries_search = registries_conf.get( + 'unqualified-search-registries', [] + ) + registries = registries_conf.get('registry', []) + if public_registry_fqdn not in registries_search: + registries_search.insert(0, public_registry_fqdn) + if public_registry not in registries: + registries.insert(0, public_registry) + if private_registry not in registries: + registries.insert(0, private_registry) + except FileNotFoundError: # file does not exist, create the file - os.makedirs(os.path.dirname(REGISTRIES_CONF_PATH), exist_ok=True) - registries_conf = _get_registry_conf_file( - REGISTRIES_CONF_PATH, 'podman' + logging.info( + 'Configuration file for Podman not found in %s' % + REGISTRIES_CONF_PATH ) - # one or both keys do not exist - if registries_conf.get('unqualified-search-registries') is None: - registries_conf['unqualified-search-registries'] = \ - ["{}".format(public_registry_fqdn)] - if registries_conf.get('registry') is None: - registries_conf['registry'] = \ - [private_registry] + [public_registry] + os.makedirs(os.path.dirname(REGISTRIES_CONF_PATH), exist_ok=True) + registries_search.append(public_registry_fqdn) + registries = [private_registry, public_registry] + + registries_conf['unqualified-search-registries'] = registries_search + registries_conf['registry'] = registries with open(REGISTRIES_CONF_PATH, 'w') as registries_conf_file: toml.dump(registries_conf, registries_conf_file) @@ -1759,10 +1758,10 @@ def _set_registry_order_search_podman(registry_fqdn): # ---------------------------------------------------------------------------- def _get_registry_conf_file(container_path, container): - if container in 'podman': + if container == 'podman': with open(container_path, 'r') as registries_conf_file: registries_conf = toml.load(registries_conf_file) - if container in 'docker': + if container == 'docker': with open(container_path, 'r') as registries_conf_file: registries_conf = json.load(registries_conf_file) @@ -1772,24 +1771,31 @@ def _get_registry_conf_file(container_path, container): # ---------------------------------------------------------------------------- def _set_registry_order_search_docker(): # search is disabled for Docker server side for private registry - secure_urls = ['https://registry.suse.com'] - mirrors_urls = ['https://registry.suse.com'] + public_registry_fqdn = 'https://registry.suse.com' docker_cfg_json = {} + secure_registries = [] + registry_mirrors = [] try: docker_cfg_json = _get_registry_conf_file(DOCKER_CONFIG_PATH, 'docker') - secure_urls += docker_cfg_json.get('secure-registries', []) - mirrors_urls += docker_cfg_json.get('registry-mirrors', []) - except (FileNotFoundError): - # config file does not exist, + secure_registries = docker_cfg_json.get('secure-registries', []) + registry_mirrors = docker_cfg_json.get('registry-mirrors', []) + if public_registry_fqdn not in secure_registries: + secure_registries.insert(0, public_registry_fqdn) + if public_registry_fqdn not in registry_mirrors: + registry_mirrors.insert(0, public_registry_fqdn) + except FileNotFoundError: + # config file does not exist + logging.info( + 'Configuration file for Docker not found in %s' % + DOCKER_CONFIG_PATH + ) os.makedirs(os.path.dirname(DOCKER_CONFIG_PATH), exist_ok=True) + secure_registries.append(public_registry_fqdn) + registry_mirrors.append(public_registry_fqdn) - docker_cfg_json['registry-mirrors'] = mirrors_urls - docker_cfg_json['secure-registries'] = secure_urls + docker_cfg_json['registry-mirrors'] = registry_mirrors + docker_cfg_json['secure-registries'] = secure_registries with open(DOCKER_CONFIG_PATH, 'w') as docker_config_file_json: json.dump(docker_cfg_json, docker_config_file_json) - logging.info( - 'Config for the registry added in %s' % ' and '.join( - [REGISTRIES_CONF_PATH, DOCKER_CONFIG_PATH] - ) - ) + logging.info('Config for the registry added in %s' % DOCKER_CONFIG_PATH) diff --git a/tests/test_registerutils.py b/tests/test_registerutils.py index ac30b875..0eb39428 100644 --- a/tests/test_registerutils.py +++ b/tests/test_registerutils.py @@ -3208,8 +3208,6 @@ def open_file(filename, mode): ) mock_toml_dump.assert_called_once_with( { - 'search-registries': ['docker.io'], - 'no-registry': [{'location': 'foo'}], 'unqualified-search-registries': ['registry.suse.com'], 'registry': [ {