def put_image_layer(image_id): try: json_data = store.get_content(store.image_json_path(image_id)) except IOError: return api_error('Image not found', 404) layer_path = store.image_layer_path(image_id) mark_path = store.image_mark_path(image_id) if store.exists(layer_path) and not store.exists(mark_path): return api_error('Image already exists', 409) 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'] store.stream_write(layer_path, input_stream) # FIXME(sam): Compute the checksum while uploading the image to save time try: checksum = store.get_content(store.image_checksum_path(image_id)) except IOError: # We don't have a checksum stored yet, that's fine skipping the check. # Not removing the mark though, image is not downloadable yet. return response() if check_image_checksum(image_id, checksum, json_data) is False: logger.debug('put_image_layer: Wrong checksum') return api_error('Checksum mismatch, ignoring the layer') # Checksum is ok, we remove the marker store.remove(mark_path) return response()
def get_post_users(): if flask.request.method == 'GET': return toolkit.response('OK', 200) try: json.loads(flask.request.data) except json.JSONDecodeError: return toolkit.api_error('Error Decoding JSON', 400) return toolkit.response('User Created', 201)
def get_post_users(): if flask.request.method == "GET": return toolkit.response("OK", 200) try: json.loads(flask.request.data) except json.JSONDecodeError: return toolkit.api_error("Error Decoding JSON", 400) return toolkit.response("User Created", 201)
def put_image_layer(image_id): try: json_data = store.get_content(store.image_json_path(image_id)) except IOError: return toolkit.api_error('Image not found', 404) layer_path = store.image_layer_path(image_id) mark_path = store.image_mark_path(image_id) if store.exists(layer_path) and not store.exists(mark_path): return toolkit.api_error('Image already exists', 409) input_stream = flask.request.stream if flask.request.headers.get('transfer-encoding') == 'chunked': # Careful, might work only with WSGI servers supporting chunked # encoding (Gunicorn) input_stream = flask.request.environ['wsgi.input'] # compute checksums csums = [] sr = toolkit.SocketReader(input_stream) tmp, store_hndlr = storage.temp_store_handler() sr.add_handler(store_hndlr) h, sum_hndlr = checksums.simple_checksum_handler(json_data) sr.add_handler(sum_hndlr) store.stream_write(layer_path, sr) # read layer files and cache them try: files_json = json.dumps(layers.get_image_files_from_fobj(tmp)) layers.set_image_files_cache(image_id, files_json) except Exception as e: logger.debug('put_image_layer: Error when caching layer file-tree:' '{0}'.format(e)) csums.append('sha256:{0}'.format(h.hexdigest())) try: tmp.seek(0) csums.append(checksums.compute_tarsum(tmp, json_data)) except (IOError, checksums.TarError) as e: logger.debug('put_image_layer: Error when computing tarsum ' '{0}'.format(e)) try: checksum = store.get_content(store.image_checksum_path(image_id)) except IOError: # We don't have a checksum stored yet, that's fine skipping the check. # Not removing the mark though, image is not downloadable yet. flask.session['checksum'] = csums return toolkit.response() # We check if the checksums provided matches one the one we computed if checksum not in csums: logger.debug('put_image_layer: Wrong checksum') return toolkit.api_error('Checksum mismatch, ignoring the layer') tmp.close() # Checksum is ok, we remove the marker store.remove(mark_path) return toolkit.response()
def put_image_json(image_id): try: data = json.loads(request.data) except json.JSONDecodeError: pass if not data or not isinstance(data, dict): return api_error('Invalid JSON') for key in ['id']: if key not in data: return api_error('Missing key `{0}\' in JSON'.format(key)) # Read the checksum checksum = request.headers.get('x-docker-checksum', '') if checksum: # Storing the checksum is optional at this stage err = store_checksum(image_id, checksum) if err: return api_error(err) if image_id != data['id']: return api_error('JSON data contains invalid id') if check_images_list(image_id) is False: return api_error('This image does not belong to the repository') parent_id = data.get('parent') if parent_id and not store.exists(store.image_json_path(data['parent'])): return api_error('Image depends on a non existing parent') json_path = store.image_json_path(image_id) mark_path = store.image_mark_path(image_id) if store.exists(json_path) and not store.exists(mark_path): return api_error('Image already exists', 409) # If we reach that point, it means that this is a new image or a retry # on a failed push store.put_content(mark_path, 'true') store.put_content(json_path, request.data) generate_ancestry(image_id, parent_id) return response()
def put_image_layer(image_id): try: json_data = store.get_content(store.image_json_path(image_id)) checksum = store.get_content(store.image_checksum_path(image_id)) except IOError: return api_error('JSON\'s image not found', 404) layer_path = store.image_layer_path(image_id) mark_path = store.image_mark_path(image_id) if store.exists(layer_path) and not store.exists(mark_path): return api_error('Image already exists', 409) 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'] store.stream_write(layer_path, input_stream) # FIXME(sam): Compute the checksum while uploading the image to save time checksum_parts = checksum.split(':') computed_checksum = compute_image_checksum(checksum_parts[0], image_id, json_data) if computed_checksum != checksum_parts[1].lower(): logger.debug('put_image_layer: Wrong checksum') return api_error('Checksum mismatch, ignoring the layer') # Checksum is ok, we remove the marker store.remove(mark_path) return response()
def put_tag(namespace, repository, tag): logger.debug("[put_tag] namespace={0}; repository={1}; tag={2}".format( namespace, repository, tag)) data = None try: data = json.loads(flask.request.data) except json.JSONDecodeError: pass if not data or not isinstance(data, basestring): return toolkit.api_error('Invalid data') if not store.exists(store.image_json_path(data)): return toolkit.api_error('Image not found', 404) store.put_content(store.tag_path(namespace, repository, tag), data) sender = flask.current_app._get_current_object() signals.tag_created.send(sender, namespace=namespace, repository=repository, tag=tag, value=data) # Write some meta-data about the repos ua = flask.request.headers.get('user-agent', '') data = create_tag_json(user_agent=ua) json_path = store.repository_tag_json_path(namespace, repository, tag) store.put_content(json_path, data) if tag == "latest": # TODO(dustinlacewell) : deprecate this for v2 json_path = store.repository_json_path(namespace, repository) store.put_content(json_path, data) return toolkit.response()
def get_tag(namespace, repository, tag): data = None try: data = store.get_content(store.tag_path(namespace, repository, tag)) except IOError: return api_error('Tag not found', 404) return response(data)
def get_repositories(): tags = [] for namespace_path in store.list_directory(store.images): for repos_path in store.list_directory(namespace_path): for tag in store.list_directory(repos_path): tags.append(tag) return toolkit.response(tags, 200)
def delete_tag(namespace, repository, tag): logger.debug("[delete_tag] namespace={0}; repository={1}; tag={2}".format(namespace, repository, tag)) try: store.remove(store.tag_path(namespace, repository, tag)) except OSError: return api_error("Tag not found", 404) return response()
def delete_repository(namespace, repository): """Remove a repository from storage This endpoint exists in both the registry API [1] and the indexer API [2], but has the same semantics in each instance. It's in the tags module (instead of the index module which handles most repository tasks) because it should be available regardless of whether the rest of the index-module endpoints are enabled via the 'standalone' config setting. [1]: http://docs.docker.io/en/latest/reference/api/registry_api/#delete--v1-repositories-%28namespace%29-%28repository%29- # nopep8 [2]: http://docs.docker.io/en/latest/reference/api/index_api/#delete--v1-repositories-%28namespace%29-%28repo_name%29- # nopep8 """ logger.debug("[delete_repository] namespace={0}; repository={1}".format( namespace, repository)) try: for tag_name, tag_content in get_tags( namespace=namespace, repository=repository): delete_tag( namespace=namespace, repository=repository, tag=tag_name) # TODO(wking): remove images, but may need refcounting store.remove(store.repository_path( namespace=namespace, repository=repository)) except OSError: return toolkit.api_error('Repository not found', 404) else: sender = flask.current_app._get_current_object() signals.repository_deleted.send( sender, namespace=namespace, repository=repository) return toolkit.response()
def get_properties(namespace, repo): logger.debug("[get_access] namespace={0}; repository={1}".format(namespace, repo)) is_private = store.is_private(namespace, repo) return toolkit.response({ 'access': 'private' if is_private else 'public' })
def put_image_checksum(image_id): if toolkit.DockerVersion() < '0.10': checksum = flask.request.headers.get('X-Docker-Checksum') else: checksum = flask.request.headers.get('X-Docker-Checksum-Payload') if not checksum: return toolkit.api_error('Missing Image\'s checksum') if not flask.session.get('checksum'): return toolkit.api_error('Checksum not found in Cookie') if not store.exists(store.image_json_path(image_id)): return toolkit.api_error('Image not found', 404) mark_path = store.image_mark_path(image_id) if not store.exists(mark_path): return toolkit.api_error('Cannot set this image checksum', 409) err = store_checksum(image_id, checksum) if err: return toolkit.api_error(err) if checksum not in flask.session.get('checksum', []): logger.debug('put_image_checksum: Wrong checksum. ' 'Provided: {0}; Expected: {1}'.format( checksum, flask.session.get('checksum'))) return toolkit.api_error('Checksum mismatch') # Checksum is ok, we remove the marker store.remove(mark_path) # We trigger a task on the diff worker if it's running if cache.redis_conn: layers.diff_queue.push(image_id) return toolkit.response()
def get_image_ancestry(image_id, headers): ancestry_path = store.image_ancestry_path(image_id) try: data = store.get_content(ancestry_path) except IOError: return toolkit.api_error('Image not found', 404) return toolkit.response(json.loads(data), headers=headers)
def delete_repository(namespace, repository): logger.debug("[delete_repository] namespace={0}; repository={1}".format(namespace, repository)) try: store.remove(store.tag_path(namespace, repository)) except OSError: return api_error("Repository not found", 404) return response()
def get_tag(namespace, repository, tag): logger.debug("[get_tag] namespace={0}; repository={1}; tag={2}".format(namespace, repository, tag)) data = None try: data = store.get_content(store.tag_path(namespace, repository, tag)) except IOError: return api_error("Tag not found", 404) return response(data)
def get_repository_images(namespace, repository): data = None try: path = store.index_images_path(namespace, repository) data = store.get_content(path) except IOError: return toolkit.api_error('images not found', 404) headers = generate_headers(namespace, repository, 'read') return toolkit.response(data, 200, headers, True)
def delete_repository(namespace, repository): logger.debug("[delete_repository] namespace={0}; repository={1}".format( namespace, repository)) try: store.remove(store.tag_path(namespace, repository)) #TODO(samalba): Trigger tags_deleted signals except OSError: return toolkit.api_error('Repository not found', 404) return toolkit.response()
def get_post_users(): if flask.request.method == 'GET': return toolkit.response('OK', 200) try: data = json.loads(flask.request.data) if Auth.signin(data): return toolkit.response('OK', 200) else: cfg = config.load() if not cfg.allow_signup: return toolkit.api_error('Signup is not allowed', 400) else: if Auth.signup(data): return toolkit.response('User Created', 201) else: return toolkit.response('User Not Created', 400) except json.JSONDecodeError: return toolkit.api_error('Error Decoding JSON', 400)
def get_image_json(image_id): try: data = store.get_content(store.image_json_path(image_id)) except IOError: return api_error('Image not found', 404) checksum_path = store.image_checksum_path(image_id) headers = None if store.exists(checksum_path): headers = {'X-Docker-Checksum': store.get_content(checksum_path)} return response(data, headers=headers, raw=True)
def get_repository_json(namespace, repository): json_path = store.repository_json_path(namespace, repository) headers = {} data = {'last_update': None, 'docker_version': None, 'docker_go_version': None, 'arch': 'amd64', 'os': 'linux', 'kernel': None} try: data = json.loads(store.get_content(json_path)) except IOError: if mirroring.is_mirror(): # use code 404 to trigger the source_lookup decorator. # TODO(joffrey): make sure this doesn't break anything or have the # decorator rewrite the status code before sending return toolkit.response(data, code=404, headers=headers) # else we ignore the error, we'll serve the default json declared above return toolkit.response(data, headers=headers)
def put_image_layer(image_id): try: json_data = store.get_content(store.image_json_path(image_id)) except IOError: return toolkit.api_error("Image not found", 404) layer_path = store.image_layer_path(image_id) mark_path = store.image_mark_path(image_id) if store.exists(layer_path) and not store.exists(mark_path): return toolkit.api_error("Image already exists", 409) input_stream = flask.request.stream if flask.request.headers.get("transfer-encoding") == "chunked": # Careful, might work only with WSGI servers supporting chunked # encoding (Gunicorn) input_stream = flask.request.environ["wsgi.input"] # compute checksums csums = [] sr = toolkit.SocketReader(input_stream) tmp, store_hndlr = storage.temp_store_handler() sr.add_handler(store_hndlr) h, sum_hndlr = checksums.simple_checksum_handler(json_data) sr.add_handler(sum_hndlr) store.stream_write(layer_path, sr) csums.append("sha256:{0}".format(h.hexdigest())) try: tmp.seek(0) csums.append(checksums.compute_tarsum(tmp, json_data)) tmp.close() except (IOError, checksums.TarError) as e: logger.debug("put_image_layer: Error when computing tarsum " "{0}".format(e)) try: checksum = store.get_content(store.image_checksum_path(image_id)) except IOError: # We don't have a checksum stored yet, that's fine skipping the check. # Not removing the mark though, image is not downloadable yet. flask.session["checksum"] = csums return toolkit.response() # We check if the checksums provided matches one the one we computed if checksum not in csums: logger.debug("put_image_layer: Wrong checksum") return toolkit.api_error("Checksum mismatch, ignoring the layer") # Checksum is ok, we remove the marker store.remove(mark_path) return toolkit.response()
def _get_tags(namespace, repository): logger.debug("[get_tags] namespace={0}; repository={1}".format(namespace, repository)) try: data = {tag_name: tag_content for tag_name, tag_content in get_tags(namespace=namespace, repository=repository)} except OSError: return toolkit.api_error('Repository not found', 404) return toolkit.response(data)
def get_tags(namespace, repository): data = {} try: for fname in store.list_directory(store.tag_path(namespace, repository)): tag_name = fname.split('/').pop() if not tag_name.startswith('tag_'): continue data[tag_name[4:]] = store.get_content(fname) except OSError: return api_error('Repository not found', 404) return response(data)
def delete_tag(namespace, repository, tag): logger.debug("[delete_tag] namespace={0}; repository={1}; tag={2}".format( namespace, repository, tag)) try: store.remove(store.tag_path(namespace, repository, tag)) sender = flask.current_app._get_current_object() signals.tag_deleted.send(sender, namespace=namespace, repository=repository, tag=tag) except OSError: return toolkit.api_error('Tag not found', 404) return toolkit.response()
def put_repository(namespace, repository, images=False): data = None try: data = json.loads(request.data) except json.JSONDecodeError: return api_error('Error Decoding JSON', 400) if not data or not isinstance(data, list): return api_error('Invalid data') update_index_images(namespace, repository, request.data) headers = generate_headers(namespace, repository, 'write') code = 204 if images is True else 200 return response('', code, headers)
def get_tags(namespace, repository): logger.debug("[get_tags] namespace={0}; repository={1}".format(namespace, repository)) data = {} try: for fname in store.list_directory(store.tag_path(namespace, repository)): tag_name = fname.split("/").pop() if not tag_name.startswith("tag_"): continue data[tag_name[4:]] = store.get_content(fname) except OSError: return api_error("Repository not found", 404) return response(data)
def put_repository(namespace, repository, images=False): data = None try: data = json.loads(flask.request.data) except json.JSONDecodeError: return toolkit.api_error('Error Decoding JSON', 400) if not isinstance(data, list): return toolkit.api_error('Invalid data') update_index_images(namespace, repository, flask.request.data) headers = generate_headers(namespace, repository, 'write') code = 204 if images is True else 200 return toolkit.response('', code, headers)
def put_tag(namespace, repository, tag): data = None try: data = json.loads(request.data) except json.JSONDecodeError: pass if not data or not isinstance(data, basestring): return api_error('Invalid data') if not store.exists(store.image_json_path(data)): return api_error('Image not found', 404) store.put_content(store.tag_path(namespace, repository, tag), data) return response()
def put_image_layer(image_id): try: json_data = store.get_content(store.image_json_path(image_id)) except IOError: return api_error('Image not found', 404) layer_path = store.image_layer_path(image_id) mark_path = store.image_mark_path(image_id) if store.exists(layer_path) and not store.exists(mark_path): return api_error('Image already exists', 409) 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'] # compute checksums csums = [] with storage.store_stream(input_stream) as f: try: csums.append(checksums.compute_simple(f, json_data)) f.seek(0) csums.append(checksums.compute_tarsum(f, json_data)) except (IOError, checksums.TarError) as e: logger.debug('put_image_layer: Error when computing checksum ' '{0}'.format(e)) f.seek(0) store.stream_write(layer_path, f) try: checksum = store.get_content(store.image_checksum_path(image_id)) except IOError: # We don't have a checksum stored yet, that's fine skipping the check. # Not removing the mark though, image is not downloadable yet. session['checksum'] = csums return response() # We check if the checksums provided matches one the one we computed if checksum not in csums: logger.debug('put_image_layer: Wrong checksum') return api_error('Checksum mismatch, ignoring the layer') # Checksum is ok, we remove the marker store.remove(mark_path) return response()
def get_image_files(image_id, headers): try: repository = toolkit.get_repository() if repository and store.is_private(*repository): return toolkit.api_error('Image not found', 404) # If no auth token found, either standalone registry or privileged # access. In both cases, access is always "public". data = layers.get_image_files_json(image_id) return toolkit.response(data, headers=headers, raw=True) except IOError: return toolkit.api_error('Image not found', 404) except tarfile.TarError: return toolkit.api_error('Layer format not supported', 400)
def _get_image_json(image_id, headers=None): if headers is None: headers = {} data = store.get_content(store.image_json_path(image_id)) try: size = store.get_size(store.image_layer_path(image_id)) headers['X-Docker-Size'] = str(size) except OSError: pass checksum_path = store.image_checksum_path(image_id) if store.exists(checksum_path): headers['X-Docker-Checksum'] = store.get_content(checksum_path) return toolkit.response(data, headers=headers, raw=True)
def delete_tag(namespace, repository, tag): logger.debug("[delete_tag] namespace={0}; repository={1}; tag={2}".format( namespace, repository, tag)) try: store.remove(store.tag_path(namespace, repository, tag)) sender = current_app._get_current_object() tag_deleted.send(sender, namespace=namespace, repository=repository, tag=tag) except OSError: return api_error('Tag not found', 404) return response()
def get_repository_json(namespace, repository): json_path = store.repository_json_path(namespace, repository) data = {'last_update': None, 'docker_version': None, 'docker_go_version': None, 'arch': 'amd64', 'os': 'linux', 'kernel': None} try: data = json.loads(store.get_content(json_path)) except IOError: # We ignore the error, we'll serve the default json declared above pass return toolkit.response(data)
def get_image_json(image_id, headers): try: data = store.get_content(store.image_json_path(image_id)) except IOError: return toolkit.api_error('Image not found', 404) try: size = store.get_size(store.image_layer_path(image_id)) headers['X-Docker-Size'] = str(size) except OSError: pass checksum_path = store.image_checksum_path(image_id) if store.exists(checksum_path): headers['X-Docker-Checksum'] = store.get_content(checksum_path) return toolkit.response(data, headers=headers, raw=True)
def get_tags(namespace, repository): logger.debug("[get_tags] namespace={0}; repository={1}".format(namespace, repository)) data = {} try: for fname in store.list_directory(store.tag_path(namespace, repository)): tag_name = fname.split('/').pop() if not tag_name.startswith('tag_'): continue data[tag_name[4:]] = store.get_content(fname) except OSError: return api_error('Repository not found', 404) return response(data)
def get_private_image_files(image_id, headers): repository = toolkit.get_repository() if not repository: # No auth token found, either standalone registry or privileged access # In both cases, private images are "disabled" return toolkit.api_error('Image not found', 404) try: if not store.is_private(*repository): return toolkit.api_error('Image not found', 404) data = layers.get_image_files_json(image_id) return toolkit.response(data, headers=headers, raw=True) except IOError: return toolkit.api_error('Image not found', 404) except tarfile.TarError: return toolkit.api_error('Layer format not supported', 400)
def registry_status(): retval = {'services': ['redis', 'storage'], 'failures': {}} retval['host'] = socket.gethostname() code = 200 jobs = [gevent.spawn(job) for job in [redis_status, storage_status]] gevent.joinall(jobs, timeout=10) for job, service in zip(jobs, retval['services']): try: value = job.get() if value[service] != '': retval['failures'].update({service: value[service]}) code = 503 except Exception as e: retval['failures'].update({service: str(e)}) code = 503 return toolkit.response(retval, code=code)
def set_properties(namespace, repo): logger.debug("[set_access] namespace={0}; repository={1}".format( namespace, repo)) data = None try: data = json.loads(flask.request.data) except json.JSONDecodeError: pass if not data or not isinstance(data, dict): return toolkit.api_error('Invalid data') private_flag_path = store.private_flag_path(namespace, repo) if data['access'] == 'private' and not store.is_private(namespace, repo): store.put_content(private_flag_path, '') elif data['access'] == 'public' and store.is_private(namespace, repo): store.remove(private_flag_path) return toolkit.response()
def put_tag(namespace, repository, tag): logger.debug("[put_tag] namespace={0}; repository={1}; tag={2}".format( namespace, repository, tag)) data = None try: data = json.loads(flask.request.data) except json.JSONDecodeError: pass if not data or not isinstance(data, basestring): return toolkit.api_error('Invalid data') if not store.exists(store.image_json_path(data)): return toolkit.api_error('Image not found', 404) store.put_content(store.tag_path(namespace, repository, tag), data) sender = flask.current_app._get_current_object() signals.tag_created.send(sender, namespace=namespace, repository=repository, tag=tag, value=data) return toolkit.response()
def get_image_diff(image_id, headers): try: repository = toolkit.get_repository() if repository and store.is_private(*repository): return toolkit.api_error('Image not found', 404) # first try the cache diff_json = layers.get_image_diff_cache(image_id) # it the cache misses, request a diff from a worker if not diff_json: layers.diff_queue.push(image_id) # empty response diff_json = "" return toolkit.response(diff_json, headers=headers, raw=True) except IOError: return toolkit.api_error('Image not found', 404) except tarfile.TarError: return toolkit.api_error('Layer format not supported', 400)
def put_image_checksum(image_id): checksum = flask.request.headers.get('X-Docker-Checksum') if not checksum: return toolkit.api_error('Missing Image\'s checksum') if not flask.session.get('checksum'): return toolkit.api_error('Checksum not found in Cookie') if not store.exists(store.image_json_path(image_id)): return toolkit.api_error('Image not found', 404) mark_path = store.image_mark_path(image_id) if not store.exists(mark_path): return toolkit.api_error('Cannot set this image checksum', 409) err = store_checksum(image_id, checksum) if err: return toolkit.api_error(err) if checksum not in flask.session.get('checksum', []): logger.debug('put_image_layer: Wrong checksum') return toolkit.api_error('Checksum mismatch') # Checksum is ok, we remove the marker store.remove(mark_path) return toolkit.response()
def put_image_json(image_id): try: data = json.loads(request.data) except json.JSONDecodeError: pass if not data or not isinstance(data, dict): return api_error('Invalid JSON') for key in ['id']: if key not in data: return api_error('Missing key `{0}\' in JSON'.format(key)) # Read the checksum checksum = request.headers.get('x-docker-checksum', '') if not checksum: return api_error('Missing Image\'s checksum') checksum_parts = checksum.split(':') if len(checksum_parts) != 2: return api_error('Invalid checksum format') if checksum_parts[0] not in hashlib.algorithms: return api_error('Checksum algorithm not supported') # We store the checksum checksum_path = store.image_checksum_path(image_id) store.put_content(checksum_path, checksum) if image_id != data['id']: return api_error('JSON data contains invalid id') if check_images_list(image_id) is False: return api_error('This image does not belong to the repository') parent_id = data.get('parent') if parent_id and not store.exists(store.image_json_path(data['parent'])): return api_error('Image depends on a non existing parent') json_path = store.image_json_path(image_id) mark_path = store.image_mark_path(image_id) if store.exists(json_path) and not store.exists(mark_path): return api_error('Image already exists', 409) # If we reach that point, it means that this is a new image or a retry # on a failed push store.put_content(mark_path, 'true') store.put_content(json_path, request.data) generate_ancestry(image_id, parent_id) return response()
def put_image_json(image_id): try: data = json.loads(flask.request.data) except json.JSONDecodeError: pass if not data or not isinstance(data, dict): return toolkit.api_error('Invalid JSON') if 'id' not in data: return toolkit.api_error('Missing key `id\' in JSON') # Read the checksum checksum = flask.request.headers.get('X-Docker-Checksum') if checksum: # Storing the checksum is optional at this stage err = store_checksum(image_id, checksum) if err: return toolkit.api_error(err) else: # We cleanup any old checksum in case it's a retry after a fail store.remove(store.image_checksum_path(image_id)) if image_id != data['id']: return toolkit.api_error('JSON data contains invalid id') if check_images_list(image_id) is False: return toolkit.api_error('This image does not belong to the ' 'repository') parent_id = data.get('parent') if parent_id and not store.exists(store.image_json_path(data['parent'])): return toolkit.api_error('Image depends on a non existing parent') json_path = store.image_json_path(image_id) mark_path = store.image_mark_path(image_id) if store.exists(json_path) and not store.exists(mark_path): return toolkit.api_error('Image already exists', 409) # If we reach that point, it means that this is a new image or a retry # on a failed push store.put_content(mark_path, 'true') store.put_content(json_path, flask.request.data) generate_ancestry(image_id, parent_id) return toolkit.response()
def get_search(): return toolkit.response({})
def put_username(username): return toolkit.response('', 204)
def put_image_layer(image_id): try: json_data = store.get_content(store.image_json_path(image_id)) except IOError: return toolkit.api_error('Image not found', 404) layer_path = store.image_layer_path(image_id) mark_path = store.image_mark_path(image_id) if store.exists(layer_path) and not store.exists(mark_path): return toolkit.api_error('Image already exists', 409) input_stream = flask.request.stream if flask.request.headers.get('transfer-encoding') == 'chunked': # Careful, might work only with WSGI servers supporting chunked # encoding (Gunicorn) input_stream = flask.request.environ['wsgi.input'] # compute checksums sr = toolkit.SocketReader(input_stream) tmp, store_hndlr = storage.temp_store_handler() sr.add_handler(store_hndlr) h, sum_hndlr = checksums.simple_checksum_handler(json_data) sr.add_handler(sum_hndlr) store.stream_write(layer_path, sr) # Read tar data from the tempfile csums = [] tar = None tarsum = checksums.TarSum(json_data) try: tmp.seek(0) tar = tarfile.open(mode='r|*', fileobj=tmp) tarfilesinfo = layers.TarFilesInfo() for member in tar: tarsum.append(member, tar) tarfilesinfo.append(member) layers.set_image_files_cache(image_id, tarfilesinfo.json()) except (IOError, tarfile.TarError) as e: logger.debug('put_image_layer: Error when reading Tar stream tarsum. ' 'Disabling TarSum, TarFilesInfo. Error: {0}'.format(e)) finally: if tar: tar.close() tmp.close() # All data have been consumed from the tempfile csums.append('sha256:{0}'.format(h.hexdigest())) csums.append(tarsum.compute()) try: checksum = store.get_content(store.image_checksum_path(image_id)) except IOError: # We don't have a checksum stored yet, that's fine skipping the check. # Not removing the mark though, image is not downloadable yet. flask.session['checksum'] = csums return toolkit.response() # We check if the checksums provided matches one the one we computed if checksum not in csums: logger.debug('put_image_layer: Wrong checksum') return toolkit.api_error('Checksum mismatch, ignoring the layer') # Checksum is ok, we remove the marker store.remove(mark_path) return toolkit.response()
def put_repository_auth(namespace, repository): return response('OK')
def get_properties(namespace, repo): logger.debug("[get_access] namespace={0}; repository={1}".format( namespace, repo)) is_private = store.is_private(namespace, repo) return toolkit.response({'access': 'private' if is_private else 'public'})
def get_image_ancestry(image_id): try: data = store.get_content(store.image_ancestry_path(image_id)) except IOError: return api_error('Image not found', 404) return response(json.loads(data))
def ping(): return toolkit.response( headers={'X-Docker-Registry-Standalone': cfg.standalone is not False})
def root(): return toolkit.response('docker-registry server ({0})'.format(cfg.flavor))
def put_username(username): return response('', 204)
def get_search(): return response({})
def get_image_ancestry(image_id, headers): try: data = store.get_content(store.image_ancestry_path(image_id)) except IOError: return toolkit.api_error('Image not found', 404) return toolkit.response(json.loads(data), headers=headers)
def _delete_tag(namespace, repository, tag): try: delete_tag(namespace=namespace, repository=repository, tag=tag) except OSError: return toolkit.api_error('Tag not found', 404) return toolkit.response()
def delete_repository_images(namespace, repository): # Does nothing, this file will be removed when DELETE on repos headers = generate_headers(namespace, repository, 'delete') return response('', 204, headers)