예제 #1
0
def backfill_replication():
    encountered = set()
    query = (
        Image.select(Image, ImageStorage, Repository, User)
        .join(ImageStorage)
        .switch(Image)
        .join(Repository)
        .join(User)
    )

    for image in query:
        if image.storage.uuid in encountered:
            continue

        namespace = image.repository.namespace_user
        locations = model.user.get_region_locations(namespace)
        locations_required = locations | set(storage.default_locations)

        query = (
            ImageStoragePlacement.select(ImageStoragePlacement, ImageStorageLocation)
            .where(ImageStoragePlacement.storage == image.storage)
            .join(ImageStorageLocation)
        )

        existing_locations = set([p.location.name for p in query])
        locations_missing = locations_required - existing_locations
        if locations_missing:
            print("Enqueueing image storage %s to be replicated" % (image.storage.uuid))
            encountered.add(image.storage.uuid)

            if not image_replication_queue.alive([image.storage.uuid]):
                queue_storage_replication(image.repository.namespace_user.username, image.storage)
예제 #2
0
def put_image_layer(namespace, repository, image_id):
    logger.debug("Checking repo permissions")
    permission = ModifyRepositoryPermission(namespace, repository)
    if not permission.can():
        abort(403)

    repository_ref = registry_model.lookup_repository(namespace,
                                                      repository,
                                                      kind_filter="image")
    if repository_ref is None:
        abort(403)

    logger.debug("Checking for image in manifest builder")
    builder = lookup_manifest_builder(repository_ref,
                                      session.get("manifest_builder"), store,
                                      docker_v2_signing_key)
    if builder is None:
        abort(400)

    layer = builder.lookup_layer(image_id)
    if layer is None:
        abort(404)

    logger.debug("Storing layer data")
    input_stream = request.stream
    if request.headers.get("transfer-encoding") == "chunked":
        # Careful, might work only with WSGI servers supporting chunked
        # encoding (Gunicorn)
        input_stream = request.environ["wsgi.input"]

    expiration_sec = app.config["PUSH_TEMP_TAG_EXPIRATION_SEC"]
    settings = BlobUploadSettings(
        maximum_blob_size=app.config["MAXIMUM_LAYER_SIZE"],
        committed_blob_expiration=expiration_sec,
    )

    extra_handlers = []

    # Add a handler that copies the data into a temp file. This is used to calculate the tarsum,
    # which is only needed for older versions of Docker.
    requires_tarsum = bool(builder.get_layer_checksums(layer))
    if requires_tarsum:
        tmp, tmp_hndlr = store.temp_store_handler()
        extra_handlers.append(tmp_hndlr)

    # Add a handler which computes the simple Docker V1 checksum.
    h, sum_hndlr = checksums.simple_checksum_handler(layer.v1_metadata_string)
    extra_handlers.append(sum_hndlr)

    uploaded_blob = None
    try:
        with upload_blob(repository_ref,
                         store,
                         settings,
                         extra_blob_stream_handlers=extra_handlers) as manager:
            manager.upload_chunk(app.config, input_stream)
            uploaded_blob = manager.commit_to_blob(app.config)
    except BlobUploadException:
        logger.exception("Exception when writing image data")
        abort(520,
              "Image %(image_id)s could not be written. Please try again.",
              image_id=image_id)

    # Compute the final checksum
    csums = []
    csums.append("sha256:{0}".format(h.hexdigest()))

    try:
        if requires_tarsum:
            tmp.seek(0)
            csums.append(
                checksums.compute_tarsum(tmp, layer.v1_metadata_string))
            tmp.close()
    except (IOError, checksums.TarError) as exc:
        logger.debug("put_image_layer: Error when computing tarsum %s", exc)

    # If there was already a precomputed checksum, validate against it now.
    if builder.get_layer_checksums(layer):
        checksum = builder.get_layer_checksums(layer)[0]
        if not builder.validate_layer_checksum(layer, checksum):
            logger.debug(
                "put_image_checksum: Wrong checksum. Given: %s and expected: %s",
                checksum,
                builder.get_layer_checksums(layer),
            )
            abort(
                400,
                "Checksum mismatch for image: %(image_id)s",
                issue="checksum-mismatch",
                image_id=image_id,
            )

    # Assign the blob to the layer in the manifest.
    if not builder.assign_layer_blob(layer, uploaded_blob, csums):
        abort(500, "Something went wrong")

    # Send a job to the work queue to replicate the image layer.
    # TODO: move this into a better place.
    queue_storage_replication(namespace, uploaded_blob)

    return make_response("true", 200)