Beispiel #1
0
    def push(
        self,
        session,
        namespace,
        repo_name,
        tag_names,
        images,
        credentials=None,
        expected_failure=None,
        options=None,
    ):
        auth = self._auth_for_credentials(credentials)
        tag_names = [tag_names] if isinstance(tag_names, str) else tag_names

        # Ping!
        self.ping(session)

        # PUT /v1/repositories/{namespace}/{repository}/
        result = self.conduct(
            session,
            "PUT",
            "/v1/repositories/%s/" % self.repo_name(namespace, repo_name),
            expected_status=(201, expected_failure,
                             V1ProtocolSteps.PUT_IMAGES),
            json_data={},
            auth=auth,
        )
        if result.status_code != 201:
            return

        headers = {}
        headers[
            "Authorization"] = "token " + result.headers["www-authenticate"]

        for image in images:
            assert image.urls is None

            # PUT /v1/images/{imageID}/json
            image_json_data = {"id": image.id}
            if image.size is not None:
                image_json_data["Size"] = image.size

            if image.parent_id is not None:
                image_json_data["parent"] = image.parent_id

            if image.config is not None:
                image_json_data["config"] = image.config

            if image.created is not None:
                image_json_data["created"] = image.created

            image_json = json.dumps(image_json_data)

            response = self.conduct(
                session,
                "PUT",
                "/v1/images/%s/json" % image.id,
                data=image_json,
                headers=headers,
                expected_status=(200, expected_failure,
                                 V1ProtocolSteps.PUT_IMAGE_JSON),
            )
            if response.status_code != 200:
                return

            # PUT /v1/images/{imageID}/checksum (old style)
            old_checksum = compute_tarsum(BytesIO(image.bytes), image_json)
            checksum_headers = {"X-Docker-Checksum": old_checksum}
            checksum_headers.update(headers)

            self.conduct(session,
                         "PUT",
                         "/v1/images/%s/checksum" % image.id,
                         headers=checksum_headers)

            # PUT /v1/images/{imageID}/layer
            self.conduct(
                session,
                "PUT",
                "/v1/images/%s/layer" % image.id,
                data=BytesIO(image.bytes),
                headers=headers,
            )

            # PUT /v1/images/{imageID}/checksum (new style)
            checksum = compute_simple(BytesIO(image.bytes), image_json)
            checksum_headers = {"X-Docker-Checksum-Payload": checksum}
            checksum_headers.update(headers)

            self.conduct(session,
                         "PUT",
                         "/v1/images/%s/checksum" % image.id,
                         headers=checksum_headers)

        # PUT /v1/repositories/{namespace}/{repository}/tags/latest
        for tag_name in tag_names:
            self.conduct(
                session,
                "PUT",
                "/v1/repositories/%s/tags/%s" %
                (self.repo_name(namespace, repo_name), tag_name),
                data='"%s"' % images[-1].id,
                headers=headers,
                expected_status=(200, expected_failure,
                                 V1ProtocolSteps.PUT_TAG),
            )

        # PUT /v1/repositories/{namespace}/{repository}/images
        self.conduct(
            session,
            "PUT",
            "/v1/repositories/%s/images" %
            self.repo_name(namespace, repo_name),
            expected_status=204,
            headers=headers,
        )

        return PushResult(manifests=None, headers=headers)
Beispiel #2
0
    def push(
        self,
        session,
        namespace,
        repo_name,
        tag_names,
        images,
        credentials=None,
        expected_failure=None,
        options=None,
    ):
        options = options or ProtocolOptions()
        scopes = options.scopes or [
            "repository:%s:push,pull" % self.repo_name(namespace, repo_name)
        ]
        tag_names = [tag_names] if isinstance(tag_names, str) else tag_names

        # Ping!
        self.ping(session)

        # Perform auth and retrieve a token.
        token, _ = self.auth(
            session,
            credentials,
            namespace,
            repo_name,
            scopes=scopes,
            expected_failure=expected_failure,
        )
        if token is None:
            assert V2Protocol.FAILURE_CODES[V2ProtocolSteps.AUTH].get(expected_failure)
            return

        headers = {
            "Authorization": "Bearer " + token,
            "Accept": ",".join(options.accept_mimetypes)
            if options.accept_mimetypes is not None
            else "*/*",
        }

        # Build fake manifests.
        manifests = {}
        blobs = {}
        for tag_name in tag_names:
            if self.schema == "oci":
                manifests[tag_name] = self.build_oci(images, blobs, options)
            elif self.schema == "schema2":
                manifests[tag_name] = self.build_schema2(images, blobs, options)
            elif self.schema == "schema1":
                manifests[tag_name] = self.build_schema1(
                    namespace, repo_name, tag_name, images, blobs, options
                )
            else:
                raise NotImplementedError(self.schema)

        # Push the blob data.
        if not self._push_blobs(
            blobs, session, namespace, repo_name, headers, options, expected_failure
        ):
            return

        # Write a manifest for each tag.
        for tag_name in tag_names:
            manifest = manifests[tag_name]

            # Write the manifest. If we expect it to be invalid, we expect a 404 code. Otherwise, we
            # expect a 201 response for success.
            put_code = 404 if options.manifest_invalid_blob_references else 201
            manifest_headers = {"Content-Type": manifest.media_type}
            manifest_headers.update(headers)

            if options.manifest_content_type is not None:
                manifest_headers["Content-Type"] = options.manifest_content_type

            tag_or_digest = tag_name if not options.push_by_manifest_digest else manifest.digest
            self.conduct(
                session,
                "PUT",
                "/v2/%s/manifests/%s" % (self.repo_name(namespace, repo_name), tag_or_digest),
                data=manifest.bytes.as_encoded_str(),
                expected_status=(put_code, expected_failure, V2ProtocolSteps.PUT_MANIFEST),
                headers=manifest_headers,
            )

        return PushResult(manifests=manifests, headers=headers)
Beispiel #3
0
    def push(self,
             session,
             namespace,
             repo_name,
             tag_names,
             images,
             credentials=None,
             expected_failure=None,
             options=None):
        auth = self._auth_for_credentials(credentials)
        tag_names = [tag_names] if isinstance(tag_names, str) else tag_names

        # Ping!
        self.ping(session)

        # PUT /v1/repositories/{namespace}/{repository}/
        result = self.conduct(session,
                              'PUT',
                              '/v1/repositories/%s/' %
                              self.repo_name(namespace, repo_name),
                              expected_status=(201, expected_failure,
                                               V1ProtocolSteps.PUT_IMAGES),
                              json_data={},
                              auth=auth)
        if result.status_code != 201:
            return

        headers = {}
        headers[
            'Authorization'] = 'token ' + result.headers['www-authenticate']

        for image in images:
            assert image.urls is None

            # PUT /v1/images/{imageID}/json
            image_json_data = {'id': image.id}
            if image.size is not None:
                image_json_data['Size'] = image.size

            if image.parent_id is not None:
                image_json_data['parent'] = image.parent_id

            if image.config is not None:
                image_json_data['config'] = image.config

            if image.created is not None:
                image_json_data['created'] = image.created

            image_json = json.dumps(image_json_data)
            response = self.conduct(
                session,
                'PUT',
                '/v1/images/%s/json' % image.id,
                data=image_json,
                headers=headers,
                expected_status=(200, expected_failure,
                                 V1ProtocolSteps.PUT_IMAGE_JSON))
            if response.status_code != 200:
                return

            # PUT /v1/images/{imageID}/checksum (old style)
            old_checksum = compute_tarsum(StringIO(image.bytes), image_json)
            checksum_headers = {'X-Docker-Checksum': old_checksum}
            checksum_headers.update(headers)

            self.conduct(session,
                         'PUT',
                         '/v1/images/%s/checksum' % image.id,
                         headers=checksum_headers)

            # PUT /v1/images/{imageID}/layer
            self.conduct(session,
                         'PUT',
                         '/v1/images/%s/layer' % image.id,
                         data=StringIO(image.bytes),
                         headers=headers)

            # PUT /v1/images/{imageID}/checksum (new style)
            checksum = compute_simple(StringIO(image.bytes), image_json)
            checksum_headers = {'X-Docker-Checksum-Payload': checksum}
            checksum_headers.update(headers)

            self.conduct(session,
                         'PUT',
                         '/v1/images/%s/checksum' % image.id,
                         headers=checksum_headers)

        # PUT /v1/repositories/{namespace}/{repository}/tags/latest
        for tag_name in tag_names:
            self.conduct(session,
                         'PUT',
                         '/v1/repositories/%s/tags/%s' %
                         (self.repo_name(namespace, repo_name), tag_name),
                         data='"%s"' % images[-1].id,
                         headers=headers,
                         expected_status=(200, expected_failure,
                                          V1ProtocolSteps.PUT_TAG))

        # PUT /v1/repositories/{namespace}/{repository}/images
        self.conduct(session,
                     'PUT',
                     '/v1/repositories/%s/images' %
                     self.repo_name(namespace, repo_name),
                     expected_status=204,
                     headers=headers)

        return PushResult(manifests=None, headers=headers)
Beispiel #4
0
    def push_list(
        self,
        session,
        namespace,
        repo_name,
        tag_names,
        manifestlist,
        manifests,
        blobs,
        credentials=None,
        expected_failure=None,
        options=None,
    ):
        options = options or ProtocolOptions()
        scopes = options.scopes or [
            "repository:%s:push,pull" % self.repo_name(namespace, repo_name)
        ]
        tag_names = [tag_names] if isinstance(tag_names, str) else tag_names

        # Ping!
        self.ping(session)

        # Perform auth and retrieve a token.
        token, _ = self.auth(
            session,
            credentials,
            namespace,
            repo_name,
            scopes=scopes,
            expected_failure=expected_failure,
        )
        if token is None:
            assert V2Protocol.FAILURE_CODES[V2ProtocolSteps.AUTH].get(expected_failure)
            return

        headers = {
            "Authorization": "Bearer " + token,
            "Accept": ",".join(options.accept_mimetypes)
            if options.accept_mimetypes is not None
            else "*/*",
        }

        # Push all blobs.
        if not self._push_blobs(
            blobs, session, namespace, repo_name, headers, options, expected_failure
        ):
            return

        # Push the individual manifests.
        for manifest in manifests:
            manifest_headers = {"Content-Type": manifest.media_type}
            manifest_headers.update(headers)

            self.conduct(
                session,
                "PUT",
                "/v2/%s/manifests/%s" % (self.repo_name(namespace, repo_name), manifest.digest),
                data=manifest.bytes.as_encoded_str(),
                expected_status=(201, expected_failure, V2ProtocolSteps.PUT_MANIFEST),
                headers=manifest_headers,
            )

        # Push the manifest list.
        for tag_name in tag_names:
            manifest_headers = {"Content-Type": manifestlist.media_type}
            manifest_headers.update(headers)

            if options.manifest_content_type is not None:
                manifest_headers["Content-Type"] = options.manifest_content_type

            self.conduct(
                session,
                "PUT",
                "/v2/%s/manifests/%s" % (self.repo_name(namespace, repo_name), tag_name),
                data=manifestlist.bytes.as_encoded_str(),
                expected_status=(201, expected_failure, V2ProtocolSteps.PUT_MANIFEST_LIST),
                headers=manifest_headers,
            )

        return PushResult(manifests=None, headers=headers)