def test_dockerhub_v2_registry_without_namespace(self, http_threaded_downloader): name = 'test_image' registry_url = "https://registry-1.docker.io" download_config = mock.MagicMock() working_dir = '/a/working/dir' r = registry.V2Repository(name, download_config, registry_url, working_dir) self.assertEqual('library/test_image', r.name, "Non-name-spaced image not prepended")
def test_get_tags(self): """ Assert correct behavior from get_tags(). """ def download_one(request): """ Mock the download_one() method to manipulate the path. """ self.assertEqual(request.url, 'https://registry.example.com/v2/pulp/tags/list') self.assertEqual(type(request.destination), type(StringIO())) report = DownloadReport(request.url, request.destination) report.download_succeeded() report.headers = {} report.destination.write('{"name": "pulp", "tags": ["best_ever", "latest", "decent"]}') return report name = 'pulp' download_config = DownloaderConfig(max_concurrent=25) registry_url = 'https://registry.example.com' working_dir = '/a/working/dir' r = registry.V2Repository(name, download_config, registry_url, working_dir) r.downloader.download_one = mock.MagicMock(side_effect=download_one) tags = r.get_tags() self.assertEqual(tags, ["best_ever", "latest", "decent"])
def test__get_path_success(self): """ Test _get_path() for the case when the download is successful. """ def download_one(request): """ Mock the download_one() method. """ self.assertEqual(request.url, 'https://registry.example.com/some/path') self.assertEqual(type(request.destination), type(StringIO())) report = DownloadReport(request.url, request.destination) report.download_succeeded() report.headers = {'some': 'cool stuff'} report.destination.write("This is the stuff you've been waiting for.") return report name = 'pulp' download_config = DownloaderConfig(max_concurrent=25) registry_url = 'https://registry.example.com' working_dir = '/a/working/dir' r = registry.V2Repository(name, download_config, registry_url, working_dir) r.downloader.download_one = mock.MagicMock(side_effect=download_one) headers, body = r._get_path('/some/path') self.assertEqual(headers, {'some': 'cool stuff'}) self.assertEqual(body, "This is the stuff you've been waiting for.")
def test_api_version_check_missing_header(self): """ The the api_version_check() method when the response is missing the Docker-Distribution-API-Version header. Since we want to support servers that are just serving simple directories of files, it should be OK if the header is not present. """ def download_one(request): """ Mock the download_one() method to manipulate the path. """ self.assertEqual(request.url, 'https://registry.example.com/v2/') self.assertEqual(type(request.destination), type(StringIO())) report = DownloadReport(request.url, request.destination) report.download_succeeded() # The Version header is not present report.headers = {} report.destination.write("") return report name = 'pulp' download_config = DownloaderConfig(max_concurrent=25) registry_url = 'https://registry.example.com' working_dir = '/a/working/dir' r = registry.V2Repository(name, download_config, registry_url, working_dir) r.downloader.download_one = mock.MagicMock(side_effect=download_one) # This should not raise an Exception r.api_version_check()
def test_get_manifest(self): """ Assert correct behavior from get_manifest(). """ def download_one(request): """ Mock the download_one() method to manipulate the path. """ self.assertEqual(request.url, 'https://registry.example.com/v2/pulp/manifests/best_version_ever') self.assertEqual(type(request.destination), type(StringIO())) report = DownloadReport(request.url, request.destination) report.download_succeeded() schema2 = 'application/vnd.docker.distribution.manifest.v2+json' report.headers = {'Docker-Distribution-API-Version': 'registry/2.0', 'docker-content-digest': digest, 'content-type': schema2} report.destination.write(manifest) return report name = 'pulp' download_config = DownloaderConfig(max_concurrent=25) registry_url = 'https://registry.example.com' working_dir = '/a/working/dir' r = registry.V2Repository(name, download_config, registry_url, working_dir) r.downloader.download_one = mock.MagicMock(side_effect=download_one) digest = 'sha256:46356a7d9575b4cee21e7867b1b83a51788610b7719a616096d943b44737ad9a' with open(os.path.join(TEST_DATA_PATH, 'manifest_repeated_layers.json')) as manifest_file: manifest = manifest_file.read() schema2 = 'application/vnd.docker.distribution.manifest.v2+json' m = r.get_manifest('best_version_ever', None, None) self.assertEqual([(manifest, digest, schema2)], m)
def test_api_version_check_successful(self): """ The the api_version_check() method when the registry_url is indeed a Docker v2 registry. """ def download_one(request): """ Mock the download_one() method to manipulate the path. """ self.assertEqual(request.url, 'https://registry.example.com/v2/') self.assertEqual(type(request.destination), type(StringIO())) report = DownloadReport(request.url, request.destination) report.download_succeeded() report.headers = {'Docker-Distribution-API-Version': 'registry/2.0'} report.destination.write("") return report name = 'pulp' download_config = DownloaderConfig(max_concurrent=25) registry_url = 'https://registry.example.com' working_dir = '/a/working/dir' r = registry.V2Repository(name, download_config, registry_url, working_dir) r.downloader.download_one = mock.MagicMock(side_effect=download_one) # This should not raise an Exception r.api_version_check()
def test_api_version_check_incorrect_header(self): """ The the api_version_check() method when the response has the Docker-Distribution-API-Version header, but it is not the correct value for a Docker v2 registry. """ def download_one(request): """ Mock the download_one() method to manipulate the path. """ self.assertEqual(request.url, 'https://registry.example.com/v2/') self.assertEqual(type(request.destination), type(StringIO())) report = DownloadReport(request.url, request.destination) report.download_succeeded() report.headers = {'Docker-Distribution-API-Version': 'WRONG_VALUE!'} report.destination.write("") return report name = 'pulp' download_config = DownloaderConfig(max_concurrent=25) registry_url = 'https://registry.example.com' working_dir = '/a/working/dir' r = registry.V2Repository(name, download_config, registry_url, working_dir) r.downloader.download_one = mock.MagicMock(side_effect=download_one) self.assertFalse(r.api_version_check())
def test_non_dockerhub_v2_registry_without_namespace(self, http_threaded_downloader): name = 'test_image' registry_url = "https://somewhere.not-docker.io" download_config = mock.MagicMock() working_dir = '/a/working/dir' r = registry.V2Repository(name, download_config, registry_url, working_dir) self.assertNotEqual('library/test_image', r.name, "Non-docker hub image prepended with library")
def __init__(self, repo=None, conduit=None, config=None): """ This method initializes the SyncStep. It first validates the config to ensure that the required keys are present. It then constructs some needed items (such as a download config), and determines whether the feed URL is a Docker v2 registry or not. If it is, it instantiates child tasks that are appropriate for syncing a v2 registry, and if it is not it raises a NotImplementedError. :param repo: repository to sync :type repo: pulp.plugins.model.Repository :param conduit: sync conduit to use :type conduit: pulp.plugins.conduits.repo_sync.RepoSyncConduit :param config: config object for the sync :type config: pulp.plugins.config.PluginCallConfiguration """ super(SyncStep, self).__init__( step_type=constants.SYNC_STEP_MAIN, repo=repo, conduit=conduit, config=config, plugin_type=constants.IMPORTER_TYPE_ID) self.description = _('Syncing Docker Repository') self._validate(config) download_config = nectar_config.importer_config_to_nectar_config(config.flatten()) upstream_name = config.get(constants.CONFIG_KEY_UPSTREAM_NAME) url = config.get(importer_constants.KEY_FEED) # The DownloadMetadataSteps will set these to a list of Manifests and Blobs self.available_manifests = [] self.available_blobs = [] # Unit keys, populated by v1_sync.GetMetadataStep self.v1_available_units = [] # populated by v1_sync.GetMetadataStep self.v1_tags = {} # Create a Repository object to interact with. self.index_repository = registry.V2Repository( upstream_name, download_config, url, self.get_working_dir()) self.v1_index_repository = registry.V1Repository(upstream_name, download_config, url, self.get_working_dir()) # determine which API versions are supported and add corresponding steps v2_enabled = config.get(constants.CONFIG_KEY_ENABLE_V2, default=True) v1_enabled = config.get(constants.CONFIG_KEY_ENABLE_V1, default=False) if not v2_enabled: _logger.debug(_('v2 API skipped due to config')) if not v1_enabled: _logger.debug(_('v1 API skipped due to config')) v2_found = v2_enabled and self.index_repository.api_version_check() v1_found = v1_enabled and self.v1_index_repository.api_version_check() if v2_found: _logger.debug(_('v2 API found')) self.add_v2_steps(repo, conduit, config) if v1_found: _logger.debug(_('v1 API found')) self.add_v1_steps(repo, config) if not any((v1_found, v2_found)): raise PulpCodedException(error_code=error_codes.DKR1008, registry=url)
def test_api_version_check_ioerror(self, mock_get_path): """ The the api_version_check() method when _get_path() raises an IOError. """ name = 'pulp' download_config = DownloaderConfig(max_concurrent=25) registry_url = 'https://registry.example.com' working_dir = '/a/working/dir' r = registry.V2Repository(name, download_config, registry_url, working_dir) self.assertFalse(r.api_version_check())
def test__get_path_failed(self): """ Test _get_path() for the case when an IOError is raised by the downloader. """ name = 'pulp' download_config = DownloaderConfig(max_concurrent=25) registry_url = 'https://registry.example.com' working_dir = '/a/working/dir' r = registry.V2Repository(name, download_config, registry_url, working_dir) # The request will fail because the requested path does not exist self.assertRaises(IOError, r._get_path, '/some/path')
def test_get_tags_failed(self, mock_download_one): """ When get_tags fails, make sure the correct exception is raised. """ name = 'pulp' download_config = DownloaderConfig() registry_url = 'https://registry.example.com' working_dir = '/a/working/dir' r = registry.V2Repository(name, download_config, registry_url, working_dir) with self.assertRaises(PulpCodedException) as assertion: r.get_tags() self.assertEqual(assertion.exception.error_code, error_codes.DKR1007)
def test_create_blob_download_request(self): """ Assert correct behavior from create_blob_download_request(). """ name = 'pulp' download_config = DownloaderConfig(max_concurrent=25) registry_url = 'https://registry.example.com' working_dir = '/a/working/dir' r = registry.V2Repository(name, download_config, registry_url, working_dir) digest = 'sha256:5f70bf18a086007016e948b04aed3b82103a36bea41755b6cddfaf10ace3c6ef' request = r.create_blob_download_request(digest) self.assertEqual(request.url, 'https://registry.example.com/v2/pulp/blobs/{0}'.format(digest)) self.assertEqual(request.destination, os.path.join(working_dir, digest))
def test___init__(self): """ Assert that __init__() initializes all the correct attributes. """ name = 'pulp' download_config = DownloaderConfig(max_concurrent=25) registry_url = 'https://registry.example.com' working_dir = '/a/working/dir' r = registry.V2Repository(name, download_config, registry_url, working_dir) self.assertEqual(r.name, name) self.assertEqual(r.download_config, download_config) self.assertEqual(r.registry_url, registry_url) self.assertEqual(type(r.downloader), HTTPThreadedDownloader) self.assertEqual(r.downloader.config, download_config) self.assertEqual(r.working_dir, working_dir)
def test__get_path_failed(self, mock_download_one, mock_request_token): """ Test _get_path() for the case when an IOError is raised by the downloader. """ name = 'pulp' download_config = DownloaderConfig(max_concurrent=25) registry_url = 'https://registry.example.com' working_dir = '/a/working/dir' r = registry.V2Repository(name, download_config, registry_url, working_dir) report = DownloadReport(registry_url + '/some/path', StringIO()) report.error_report['response_code'] = httplib.UNAUTHORIZED report.state = DownloadReport.DOWNLOAD_FAILED report.headers = {} mock_download_one.return_value = report # The request will fail because the requested path does not exist self.assertRaises(IOError, r._get_path, '/some/path')