Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update headers in do_request method, provider.py #129

Merged
merged 8 commits into from
Apr 5, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,4 @@ oras.egg-info/
.env
env
__pycache__
.python-version
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ and **Merged pull requests**. Critical items to know are:
The versions coincide with releases on pip. Only major versions will be released as tags on Github.

## [0.0.x](https://github.com/oras-project/oras-py/tree/main) (0.0.x)
- add option to not refresh headers during the pushing flow, useful for push with basic auth (0.1.29)
- enable additionalProperties in schema validation (0.1.28)
- Introduce the option to not refresh headers when fetching manifests when pulling artifacts (0.1.27)
- To make it available for more OCI registries, the value of config used when `manifest_config` is not specified in `client.push()` has been changed from a pure empty string to `{}` (0.1.26)
Expand Down
63 changes: 55 additions & 8 deletions oras/provider.py
Original file line number Diff line number Diff line change
Expand Up @@ -226,6 +226,7 @@ def upload_blob(
container: container_type,
layer: dict,
do_chunked: bool = False,
refresh_headers: bool = True,
) -> requests.Response:
"""
Prepare and upload a blob.
Expand All @@ -239,6 +240,8 @@ def upload_blob(
:type container: oras.container.Container or str
:param layer: dict from oras.oci.NewLayer
:type layer: dict
:param refresh_headers: if true, headers are refreshed
:type refresh_headers: bool
"""
blob = os.path.abspath(blob)
container = self.get_container(container)
Expand All @@ -250,9 +253,13 @@ def upload_blob(
# This is currently disabled unless the user asks for it, as
# it doesn't seem to work for all registries
if not do_chunked:
response = self.put_upload(blob, container, layer)
response = self.put_upload(
blob, container, layer, refresh_headers=refresh_headers
)
else:
response = self.chunked_upload(blob, container, layer)
response = self.chunked_upload(
blob, container, layer, refresh_headers=refresh_headers
)

# If we have an empty layer digest and the registry didn't accept, just return dummy successful response
if (
Expand Down Expand Up @@ -474,7 +481,11 @@ def download_blob(
return outfile

def put_upload(
self, blob: str, container: oras.container.Container, layer: dict
self,
blob: str,
container: oras.container.Container,
layer: dict,
refresh_headers: bool = True,
) -> requests.Response:
"""
Upload to a registry via put.
Expand All @@ -485,9 +496,15 @@ def put_upload(
:type container: oras.container.Container or str
:param layer: dict from oras.oci.NewLayer
:type layer: dict
:param refresh_headers: if true, headers are refreshed
:type refresh_headers: bool
"""
# Start an upload session
headers = {"Content-Type": "application/octet-stream"}

if not refresh_headers:
headers.update(self.headers)

upload_url = f"{self.prefix}://{container.upload_blob_url()}"
r = self.do_request(upload_url, "POST", headers=headers)

Expand Down Expand Up @@ -541,7 +558,11 @@ def _get_location(
return session_url

def chunked_upload(
self, blob: str, container: oras.container.Container, layer: dict
self,
blob: str,
container: oras.container.Container,
layer: dict,
refresh_headers: bool = True,
) -> requests.Response:
"""
Upload via a chunked upload.
Expand All @@ -552,9 +573,14 @@ def chunked_upload(
:type container: oras.container.Container or str
:param layer: dict from oras.oci.NewLayer
:type layer: dict
:param refresh_headers: if true, headers are refreshed
:type refresh_headers: bool
"""
# Start an upload session
headers = {"Content-Type": "application/octet-stream", "Content-Length": "0"}
if not refresh_headers:
headers.update(self.headers)

upload_url = f"{self.prefix}://{container.upload_blob_url()}"
r = self.do_request(upload_url, "POST", headers=headers)

Expand Down Expand Up @@ -618,7 +644,10 @@ def _parse_response_errors(self, response: requests.Response):
pass

def upload_manifest(
self, manifest: dict, container: oras.container.Container
self,
manifest: dict,
container: oras.container.Container,
refresh_headers: bool = True,
) -> requests.Response:
"""
Read a manifest file and upload it.
Expand All @@ -627,13 +656,19 @@ def upload_manifest(
:type manifest: dict
:param container: parsed container URI
:type container: oras.container.Container or str
:param refresh_headers: if true, headers are refreshed
:type refresh_headers: bool
"""
self.reset_basic_auth()
jsonschema.validate(manifest, schema=oras.schemas.manifest)
headers = {
"Content-Type": oras.defaults.default_manifest_media_type,
"Content-Length": str(len(manifest)),
}

if not refresh_headers:
headers.update(self.headers)

return self.do_request(
f"{self.prefix}://{container.manifest_url()}", # noqa
"PUT",
Expand All @@ -659,6 +694,8 @@ def push(self, *args, **kwargs) -> requests.Response:
:type manifest_annotations: dict
:param target: target location to push to
:type target: str
:param refresh_headers: if true or None, headers are refreshed
:type refresh_headers: bool
:param subject: optional subject reference
:type subject: Subject
"""
Expand All @@ -675,6 +712,10 @@ def push(self, *args, **kwargs) -> requests.Response:
annotset = oras.oci.Annotations(kwargs.get("annotation_file"))
media_type = None

refresh_headers = kwargs.get("refresh_headers")
if refresh_headers is None:
refresh_headers = True

# Upload files as blobs
for blob in kwargs.get("files", []):
# You can provide a blob + content type
Expand Down Expand Up @@ -720,7 +761,9 @@ def push(self, *args, **kwargs) -> requests.Response:
logger.debug(f"Preparing layer {layer}")

# Upload the blob layer
response = self.upload_blob(blob, container, layer)
response = self.upload_blob(
blob, container, layer, refresh_headers=refresh_headers
)
self._check_200_response(response)

# Do we need to cleanup a temporary targz?
Expand Down Expand Up @@ -762,13 +805,17 @@ def push(self, *args, **kwargs) -> requests.Response:
if config_file is None
else nullcontext(config_file)
) as config_file:
response = self.upload_blob(config_file, container, conf)
response = self.upload_blob(
config_file, container, conf, refresh_headers=refresh_headers
)

self._check_200_response(response)

# Final upload of the manifest
manifest["config"] = conf
self._check_200_response(self.upload_manifest(manifest, container))
self._check_200_response(
self.upload_manifest(manifest, container, refresh_headers=refresh_headers)
)
print(f"Successfully pushed {container}")
return response

Expand Down
2 changes: 1 addition & 1 deletion oras/version.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
__copyright__ = "Copyright The ORAS Authors."
__license__ = "Apache-2.0"

__version__ = "0.1.28"
__version__ = "0.1.29"
AUTHOR = "Vanessa Sochat"
EMAIL = "[email protected]"
NAME = "oras"
Expand Down
Loading