From 66cd9b712cba153227e68d013fa6291a15de96dc Mon Sep 17 00:00:00 2001 From: vsoch Date: Sat, 12 Feb 2022 14:22:40 -0700 Subject: [PATCH 1/3] start of work to extend example Signed-off-by: vsoch --- docs/_docs/getting-started.md | 111 +++++++++++++++++++ opencontainers/distribution/reggie/client.py | 12 +- 2 files changed, 122 insertions(+), 1 deletion(-) diff --git a/docs/_docs/getting-started.md b/docs/_docs/getting-started.md index 899ebc2..87653ca 100644 --- a/docs/_docs/getting-started.md +++ b/docs/_docs/getting-started.md @@ -421,6 +421,117 @@ response.json() 'layers': []} ``` +##### Get A Manifest + +As shown above, it's fairly simple to get a manifest. + +```python +req = src.NewRequest( + "GET", + "/v2//manifests/", + reggie.WithReference("0.1.2dev0"), +) + +response = src.Do(req) +manifest = resp.json() +print(manifest) + +# The layers, config, and its digest are found here: +layers = manifest["layers"] +config_digest = manifest["config"]["digest"] +``` + +##### Get A Blob + +Let's say that we just retrieved the image config digest via the interaction above, +and we want to further inspect or tweak it. You might do the following to retrieve +the config blob: + +```python +import reggie + +def GetBlob(digest): + req = src.NewRequest("GET", "/v2//blobs/", reggie.WithDigest(digest)) + req.stream = True + return src.Do(req) +``` + +And then running the function, you could check the status code, act on it, +and return json for the response. + +```python +response = GetBlob(digest) +config = response.json() +``` + +##### Add a Patch + +Let's say that you've retrieved the config blob from above, and we did that +so we can get the last working directory of the container. We want +to add a new layer that has a file in that directory. + +```python +# Here is the working directory from the config loaded above +working_dir = config["container_config"]["WorkingDir"] +``` + +Here we are going to write the file to an new .tar.gz. + +```python +import tarfile + +PATCH_FILE = "patch.tar.gz" +with tarfile.open(PATCH_FILE, mode="w:gz") as tf: + content = b"A new test file" + info = tarfile.TarInfo(os.path.join(working_dir, "test.txt")) + info.size = len(content) + tf.addfile(info, io.BytesIO(content)) +``` + +And again here is a quick function for calculating the digest and size of this new archive: + +```python +import hashlib + +def compute_digest(reader): + m = hashlib.sha256() + patch_size = 0 + while True: + data = f.read(64000) + if not data: + break + m.update(data) + patch_size += len(data) + patch_digest = "sha256:" + m.hexdigest() + return patch_digest, patch_size +``` + +And do the calculating: + +```python +with open(PATCH_FILE, "rb") as f: + patch_digest, patch_size = compute_digest(f) +``` + +We can now append the new information to our current manifest: + +```python +manifest["layers"].append( + { + "mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip", + "size": patch_size, + "digest": patch_digest, + } +) +``` + +And upload the new patch and manifest. + +**todo: need to have discussion about what should be added to reggie vs. shown here** + + +**Note** this example is provided from [this issue](https://github.com/vsoch/oci-python/issues/15#issuecomment-1035978143) +and thank you to [Tristan](https://github.com/d4l3k)! ##### List Tags diff --git a/opencontainers/distribution/reggie/client.py b/opencontainers/distribution/reggie/client.py index 9bfc987..90ac994 100644 --- a/opencontainers/distribution/reggie/client.py +++ b/opencontainers/distribution/reggie/client.py @@ -9,7 +9,7 @@ """ from .defaults import DEFAULT_USER_AGENT, URL_REGEX -from .request import RequestConfig, RequestClient +from .request import RequestConfig, RequestClient, WithDigest from .config import BaseConfig from copy import deepcopy @@ -182,6 +182,16 @@ def NewRequest(self, method, path, *opts): # Return the Client, which has Request and retryCallback return requestClient + def GetBlob(digest): + """ + Get Blob returns the request for a specific digest, + """ + req = self.NewRequest( + "GET", "/v2//blobs/", reggie.WithDigest(digest) + ) + req.stream = True + return src.Do(req) + def Do(self, req): """ Execut a request. From 3aca8902a36cc9aad0812b1f6ecdb7a174a89334 Mon Sep 17 00:00:00 2001 From: vsoch Date: Sat, 12 Feb 2022 14:24:31 -0700 Subject: [PATCH 2/3] remove getblob Signed-off-by: vsoch --- opencontainers/distribution/reggie/client.py | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/opencontainers/distribution/reggie/client.py b/opencontainers/distribution/reggie/client.py index 90ac994..9bfc987 100644 --- a/opencontainers/distribution/reggie/client.py +++ b/opencontainers/distribution/reggie/client.py @@ -9,7 +9,7 @@ """ from .defaults import DEFAULT_USER_AGENT, URL_REGEX -from .request import RequestConfig, RequestClient, WithDigest +from .request import RequestConfig, RequestClient from .config import BaseConfig from copy import deepcopy @@ -182,16 +182,6 @@ def NewRequest(self, method, path, *opts): # Return the Client, which has Request and retryCallback return requestClient - def GetBlob(digest): - """ - Get Blob returns the request for a specific digest, - """ - req = self.NewRequest( - "GET", "/v2//blobs/", reggie.WithDigest(digest) - ) - req.stream = True - return src.Do(req) - def Do(self, req): """ Execut a request. From 6495ccd942ff40f14cc5aade9215d6a3e96b136f Mon Sep 17 00:00:00 2001 From: vsoch Date: Mon, 14 Feb 2022 17:06:45 -0700 Subject: [PATCH 3/3] remove un-needed import and add detail about mediaType Signed-off-by: vsoch --- docs/_docs/getting-started.md | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/docs/_docs/getting-started.md b/docs/_docs/getting-started.md index 87653ca..ed6001c 100644 --- a/docs/_docs/getting-started.md +++ b/docs/_docs/getting-started.md @@ -448,8 +448,6 @@ and we want to further inspect or tweak it. You might do the following to retrie the config blob: ```python -import reggie - def GetBlob(digest): req = src.NewRequest("GET", "/v2//blobs/", reggie.WithDigest(digest)) req.stream = True @@ -524,8 +522,8 @@ manifest["layers"].append( } ) ``` - -And upload the new patch and manifest. +Note that the mediaType differs between Docker v2 and oci images. +Then upload the new patch and manifest. **todo: need to have discussion about what should be added to reggie vs. shown here**