Beispiel #1
0
    def _load_manifest(self):
        digest = self._manifest_data[DOCKER_SCHEMA2_MANIFESTLIST_DIGEST_KEY]
        size = self._manifest_data[DOCKER_SCHEMA2_MANIFESTLIST_SIZE_KEY]
        manifest_bytes = self._content_retriever.get_manifest_bytes_with_digest(
            digest)
        if manifest_bytes is None:
            raise MalformedSchema2ManifestList(
                "Could not find child manifest with digest `%s`" % digest)

        if len(manifest_bytes) != size:
            raise MalformedSchema2ManifestList(
                "Size of manifest does not match that retrieved: %s vs %s",
                len(manifest_bytes),
                size,
            )

        content_type = self._manifest_data[
            DOCKER_SCHEMA2_MANIFESTLIST_MEDIATYPE_KEY]
        if content_type == DOCKER_SCHEMA2_MANIFEST_CONTENT_TYPE:
            return DockerSchema2Manifest(
                Bytes.for_string_or_unicode(manifest_bytes))

        if content_type == DOCKER_SCHEMA1_MANIFEST_CONTENT_TYPE:
            return DockerSchema1Manifest(
                Bytes.for_string_or_unicode(manifest_bytes), validate=False)

        raise MalformedSchema2ManifestList("Unknown manifest content type")
Beispiel #2
0
def parse_manifest_from_bytes(manifest_bytes, media_type, validate=True):
    """
    Parses and returns a manifest from the given bytes, for the given media type.

    Raises a ManifestException if the parse fails for some reason.
    """
    assert isinstance(manifest_bytes, Bytes)

    if media_type == DOCKER_SCHEMA2_MANIFEST_CONTENT_TYPE:
        return DockerSchema2Manifest(manifest_bytes)

    if media_type == DOCKER_SCHEMA2_MANIFESTLIST_CONTENT_TYPE:
        return DockerSchema2ManifestList(manifest_bytes)

    if media_type == OCI_IMAGE_MANIFEST_CONTENT_TYPE:
        return OCIManifest(manifest_bytes)

    if media_type == OCI_IMAGE_INDEX_CONTENT_TYPE:
        return OCIIndex(manifest_bytes)

    if media_type in DOCKER_SCHEMA1_CONTENT_TYPES:
        return DockerSchema1Manifest(manifest_bytes, validate=validate)

    raise ManifestException("Unknown or unsupported manifest media type `%s`" %
                            media_type)
Beispiel #3
0
def test_conversion(name, config_sha):
    cr = {}
    cr[config_sha] = _get_test_file_contents(name, 'config').as_encoded_str()
    retriever = ContentRetrieverForTesting(cr)

    schema2 = DockerSchema2Manifest(_get_test_file_contents(name, 'schema2'))
    schema1 = DockerSchema1Manifest(_get_test_file_contents(name, 'schema1'),
                                    validate=False)

    s2to2 = schema2.convert_manifest([schema2.media_type], 'devtable',
                                     'somerepo', 'latest', retriever)
    assert s2to2 == schema2

    s1to1 = schema1.convert_manifest([schema1.media_type], 'devtable',
                                     'somerepo', 'latest', retriever)
    assert s1to1 == schema1

    s2to1 = schema2.convert_manifest(DOCKER_SCHEMA1_CONTENT_TYPES, 'devtable',
                                     'somerepo', 'latest', retriever)
    assert s2to1.media_type in DOCKER_SCHEMA1_CONTENT_TYPES
    assert len(s2to1.layers) == len(schema1.layers)

    s2toempty = schema2.convert_manifest([], 'devtable', 'somerepo', 'latest',
                                         retriever)
    assert s2toempty is None
Beispiel #4
0
def test_get_schema1_manifest():
  retriever = ContentRetrieverForTesting.for_config({
    "config": {
      "Labels": {},
    },
    "rootfs": {"type": "layers", "diff_ids": []},
    "history": [
      {
        "created": "2018-04-03T18:37:09.284840891Z",
        "created_by": "foo"
      },
      {
        "created": "2018-04-12T18:37:09.284840891Z",
        "created_by": "bar"
      },
      {
        "created": "2018-04-03T18:37:09.284840891Z",
        "created_by": "foo"
      },
      {
        "created": "2018-04-12T18:37:09.284840891Z",
        "created_by": "bar"
      },
    ],
  }, 'sha256:b5b2b2c507a0944348e0303114d8d93aaaa081732b86451d9bce1f432a537bc7', 1885)

  manifest = DockerSchema2Manifest(Bytes.for_string_or_unicode(MANIFEST_BYTES))
  schema1 = manifest.get_schema1_manifest('somenamespace', 'somename', 'sometag', retriever)
  assert schema1 is not None
  assert schema1.media_type == DOCKER_SCHEMA1_MANIFEST_CONTENT_TYPE

  via_convert = manifest.convert_manifest([schema1.media_type], 'somenamespace', 'somename',
                                          'sometag', retriever)
  assert via_convert.digest == schema1.digest
Beispiel #5
0
def test_valid_remote_manifest():
  manifest = DockerSchema2Manifest(Bytes.for_string_or_unicode(REMOTE_MANIFEST_BYTES))
  assert manifest.config.size == 1885
  assert str(manifest.config.digest) == 'sha256:b5b2b2c507a0944348e0303114d8d93aaaa081732b86451d9bce1f432a537bc7'
  assert manifest.media_type == "application/vnd.docker.distribution.manifest.v2+json"
  assert manifest.has_remote_layer

  assert len(manifest.filesystem_layers) == 4
  assert manifest.filesystem_layers[0].compressed_size == 1234
  assert str(manifest.filesystem_layers[0].digest) == 'sha256:ec4b8955958665577945c89419d1af06b5f7636b4ac3da7f12184802ad867736'
  assert manifest.filesystem_layers[0].is_remote
  assert manifest.filesystem_layers[0].urls == ['http://some/url']

  assert manifest.leaf_filesystem_layer == manifest.filesystem_layers[3]
  assert not manifest.leaf_filesystem_layer.is_remote
  assert manifest.leaf_filesystem_layer.compressed_size == 73109

  expected = set([str(layer.digest) for layer in manifest.filesystem_layers] + 
                 [manifest.config.digest])

  blob_digests = set(manifest.blob_digests)
  local_digests = set(manifest.local_blob_digests)

  assert blob_digests == expected
  assert local_digests == (expected - {manifest.filesystem_layers[0].digest})

  assert manifest.has_remote_layer
  assert manifest.get_leaf_layer_v1_image_id(None) is None
  assert manifest.get_legacy_image_ids(None) is None

  retriever = ContentRetrieverForTesting.for_config({
    "config": {
      "Labels": {},
    },
    "rootfs": {"type": "layers", "diff_ids": []},
    "history": [
      {
        "created": "2018-04-03T18:37:09.284840891Z",
        "created_by": "foo"
      },
      {
        "created": "2018-04-12T18:37:09.284840891Z",
        "created_by": "bar"
      },
      {
        "created": "2018-04-03T18:37:09.284840891Z",
        "created_by": "foo"
      },
      {
        "created": "2018-04-12T18:37:09.284840891Z",
        "created_by": "bar"
      },
    ],
  }, 'sha256:b5b2b2c507a0944348e0303114d8d93aaaa081732b86451d9bce1f432a537bc7', 1885)

  manifest_image_layers = list(manifest.get_layers(retriever))
  assert len(manifest_image_layers) == len(list(manifest.filesystem_layers))
  for index in range(0, 4):
    assert manifest_image_layers[index].blob_digest == str(manifest.filesystem_layers[index].digest)
Beispiel #6
0
def test_get_manifest_labels():
  labels = dict(foo='bar', baz='meh')
  retriever = ContentRetrieverForTesting.for_config({
    "config": {
      "Labels": labels,
    },
    "rootfs": {"type": "layers", "diff_ids": []},
    "history": [],
  }, 'sha256:b5b2b2c507a0944348e0303114d8d93aaaa081732b86451d9bce1f432a537bc7', 1885)

  manifest = DockerSchema2Manifest(Bytes.for_string_or_unicode(MANIFEST_BYTES))
  assert manifest.get_manifest_labels(retriever) == labels
Beispiel #7
0
def test_schema2_builder():
  manifest = DockerSchema2Manifest(Bytes.for_string_or_unicode(MANIFEST_BYTES))

  builder = DockerSchema2ManifestBuilder()
  builder.set_config_digest(manifest.config.digest, manifest.config.size)

  for layer in manifest.filesystem_layers:
    builder.add_layer(layer.digest, layer.compressed_size, urls=layer.urls)

  built = builder.build()
  assert built.filesystem_layers == manifest.filesystem_layers
  assert built.config == manifest.config
Beispiel #8
0
def test_build_schema1():
  manifest = DockerSchema2Manifest(Bytes.for_string_or_unicode(MANIFEST_BYTES))
  assert not manifest.has_remote_layer

  retriever = ContentRetrieverForTesting({
    'sha256:b5b2b2c507a0944348e0303114d8d93aaaa081732b86451d9bce1f432a537bc7': CONFIG_BYTES,
  })

  builder = DockerSchema1ManifestBuilder('somenamespace', 'somename', 'sometag')
  manifest._populate_schema1_builder(builder, retriever)
  schema1 = builder.build(docker_v2_signing_key)

  assert schema1.media_type == DOCKER_SCHEMA1_SIGNED_MANIFEST_CONTENT_TYPE
Beispiel #9
0
def test_load_unicode_manifest():
  test_dir = os.path.dirname(os.path.abspath(__file__))
  with open(os.path.join(test_dir, 'unicode_manifest_config.json'), 'r') as f:
    retriever = ContentRetrieverForTesting()
    retriever.add_digest('sha256:5bdd65cdd055c7f3bbaecdc9fd6c75f155322520f85953aa0e2724cab006d407',
                         f.read())

  with open(os.path.join(test_dir, 'unicode_manifest.json'), 'r') as f:
    manifest_bytes = f.read()

  manifest = DockerSchema2Manifest(Bytes.for_string_or_unicode(manifest_bytes))
  assert manifest.digest == 'sha256:97556fa8c553395bd9d8e19a04acef4716ca287ffbf6bde14dd9966053912613'

  layers = list(manifest.get_layers(retriever))
  assert layers[-1].author == u"Sômé guy"
Beispiel #10
0
def test_legacy_layers(name, config_sha):
    cr = {}
    cr[config_sha] = _get_test_file_contents(name, 'config').as_encoded_str()
    retriever = ContentRetrieverForTesting(cr)

    schema2 = DockerSchema2Manifest(_get_test_file_contents(name, 'schema2'))
    schema1 = DockerSchema1Manifest(_get_test_file_contents(name, 'schema1'),
                                    validate=False)

    # Check legacy layers
    schema2_legacy_layers = list(schema2.generate_legacy_layers({}, retriever))
    schema1_legacy_layers = list(schema1.generate_legacy_layers({}, retriever))
    assert len(schema1_legacy_layers) == len(schema2_legacy_layers)

    for index in range(0, len(schema1_legacy_layers)):
        schema1_legacy_layer = schema1_legacy_layers[index]
        schema2_legacy_layer = schema2_legacy_layers[index]
        assert schema1_legacy_layer.content_checksum == schema2_legacy_layer.content_checksum
        assert schema1_legacy_layer.comment == schema2_legacy_layer.comment
        assert schema1_legacy_layer.command == schema2_legacy_layer.command
Beispiel #11
0
def test_2to1_conversion(name, config_sha):
    cr = {}
    cr[config_sha] = _get_test_file_contents(name, 'config').as_encoded_str()
    retriever = ContentRetrieverForTesting(cr)

    schema2 = DockerSchema2Manifest(_get_test_file_contents(name, 'schema2'))
    schema1 = DockerSchema1Manifest(_get_test_file_contents(name, 'schema1'),
                                    validate=False)

    converted = schema2.get_schema1_manifest('devtable', 'somerepo', 'latest',
                                             retriever)
    assert len(converted.layers) == len(schema1.layers)

    image_id_map = {}
    for index in range(0, len(converted.layers)):
        converted_layer = converted.layers[index]
        schema1_layer = schema1.layers[index]

        image_id_map[schema1_layer.v1_metadata.
                     image_id] = converted_layer.v1_metadata.image_id

        assert str(schema1_layer.digest) == str(converted_layer.digest)

        schema1_parent_id = schema1_layer.v1_metadata.parent_image_id
        converted_parent_id = converted_layer.v1_metadata.parent_image_id
        assert (schema1_parent_id is None) == (converted_parent_id is None)

        if schema1_parent_id is not None:
            assert image_id_map[schema1_parent_id] == converted_parent_id

        assert schema1_layer.v1_metadata.created == converted_layer.v1_metadata.created
        assert schema1_layer.v1_metadata.comment == converted_layer.v1_metadata.comment
        assert schema1_layer.v1_metadata.command == converted_layer.v1_metadata.command
        assert schema1_layer.v1_metadata.labels == converted_layer.v1_metadata.labels

        schema1_container_config = json.loads(
            schema1_layer.raw_v1_metadata)['container_config']
        converted_container_config = json.loads(
            converted_layer.raw_v1_metadata)['container_config']

        assert schema1_container_config == converted_container_config
Beispiel #12
0
def test_malformed_manifests(json_data):
    with pytest.raises(MalformedSchema2Manifest):
        DockerSchema2Manifest(Bytes.for_string_or_unicode(json_data))