Unable to push a manifest using Registry v2 API - docker

Update
Answered in the comments. I missed the sha256 prefix for digests in the manifest.json!
I am experimenting with the Registry v2 API using shell scripts and cannot seem to finalize the image push.
I followed the API docs and pushed the layers (one tar.gz and config.json). Both uploads were completed with status code 201.
< HTTP/1.1 201 Created
< content-length: 0
< docker-content-digest: sha256:e251e682f7e64cff127020015be3254313b3a7900f54d82ecf34653192be4c21
< docker-distribution-api-version: registry/2.0
< location: https://registry.hub.docker.com/v2/ravikanth/cnc2/blobs/sha256:e251e682f7e64cff127020015be3254313b3a7900f54d82ecf34653192be4c21
< date: Mon, 28 Nov 2022 13:43:31 GMT
< strict-transport-security: max-age=31536000
< HTTP/1.1 201 Created
< content-length: 0
< docker-content-digest: sha256:4500bf72b8876e180985cb9d30dcbfb4b37c6212af4a1e66f6a59e9c44e4430e
< docker-distribution-api-version: registry/2.0
< location: https://registry.hub.docker.com/v2/ravikanth/cnc2/blobs/sha256:4500bf72b8876e180985cb9d30dcbfb4b37c6212af4a1e66f6a59e9c44e4430e
< date: Mon, 28 Nov 2022 14:03:00 GMT
< strict-transport-security: max-age=31536000
I could verify that these layers exist.
date: Mon, 28 Nov 2022 14:03:50 GMT
content-type: application/octet-stream
content-length: 277
cf-ray: 7713a639ae0326b9-BLR
accept-ranges: bytes
cache-control: public, max-age=14400
etag: "6ff6ee3576fbb38ded464213e5119f93"
expires: Mon, 28 Nov 2022 18:03:50 GMT
last-modified: Mon, 28 Nov 2022 09:38:20 GMT
vary: Accept-Encoding
cf-cache-status: MISS
x-amz-id-2: BKOqrxyDQlWoyu/lv9AiyoCUMqImMVJROkFCpvHrtNdU1YDdjGJSQLoR+E+J7sYlyo9AwQd27Ao=
x-amz-request-id: D9F9EP13RA3VY9TJ
x-amz-version-id: y1TMXGkb8nPxCq1Ojxp7P0FbwmfurXTs
server: cloudflare
HTTP/2 200
date: Mon, 28 Nov 2022 14:02:00 GMT
content-type: application/octet-stream
content-length: 1074934
cf-ray: 7713a3862b8f1d89-BLR
accept-ranges: bytes
cache-control: public, max-age=14400
etag: "bb6070a00aab579e87f54126c0147bf6"
expires: Mon, 28 Nov 2022 18:02:00 GMT
last-modified: Mon, 28 Nov 2022 08:57:53 GMT
vary: Accept-Encoding
cf-cache-status: MISS
x-amz-id-2: ZIwf+5xaaHuHdQhCtErlXXXxfKZA3GPFSP2CTm1TbYS8caRh53bjxJ2yj/jGRTUPXQ0fHdTXIDs=
x-amz-request-id: FZH3XXP4VP2C354S
x-amz-version-id: 0ZKPRYiiGUKn5dc_rISx4jHKcKTH3rfR
server: cloudflare
Now, when I finally try to push the manifest, I am getting the following response.
{"errors":[{"code":"DIGEST_INVALID","message":"provided digest did not match uploaded content"},{"code":"MANIFEST_BLOB_UNKNOWN","message":"blob unknown to registry","detail":"4500bf72b8876e180985cb9d30dcbfb4b37c6212af4a1e66f6a59e9c44e4430e"},{"code":"DIGEST_INVALID","message":"provided digest did not match uploaded content"},{"code":"MANIFEST_BLOB_UNKNOWN","message":"blob unknown to registry","detail":"e251e682f7e64cff127020015be3254313b3a7900f54d82ecf34653192be4c21"}]}
What is wrong?
This is how I derived the digests/diff.
LAYERDIGEST=$(sha256sum < hello-cloud.tar.gz | cut -d' ' -f1)
LAYERDIFF=$(gunzip < hello-cloud.tar.gz | sha256sum | cut -d' ' -f1)
LAYERSIZE=$(ls -l hello-cloud.tar.gz | awk '{print $5}')
CONFIGDIGEST=$(sha256sum < configuration.json | cut -d' ' -f1)
CONFIGSIZE=$(ls -l configuration.json | awk '{print $5}')
And, here is the manifest.json
{
"schemaVersion": 2,
"mediaType": "application/vnd.oci.image.manifest.v1+json",
"config": {
"mediaType": "application/vnd.oci.image.config.v1+json",
"size": 277,
"digest": "4500bf72b8876e180985cb9d30dcbfb4b37c6212af4a1e66f6a59e9c44e4430e"
},
"layers": [
{
"mediaType": "application/vnd.oci.image.layer.v1.tar+gzip",
"size": 1074934,
"digest": "e251e682f7e64cff127020015be3254313b3a7900f54d82ecf34653192be4c21"
}
]
}
And, configuration.json
{
"architecture": "amd64",
"os": "linux",
"config": {
},
"rootfs": {
"type": "layers",
"diff_ids": [
"sha256:690fa2812df903a4cee676e28389e154fe022f2a26fb29c4c97e9c6583fa5bc6"
]
},
"history": [
{
"created_by": "Ravikanth C"
}
]
}

Your config and layer digests in the manifest are missing the sha256: prefix. Modify the manifest like this:
{
"schemaVersion": 2,
"mediaType": "application/vnd.oci.image.manifest.v1+json",
"config": {
"mediaType": "application/vnd.oci.image.config.v1+json",
"size": 277,
"digest": "sha256:4500bf72b8876e180985cb9d30dcbfb4b37c6212af4a1e66f6a59e9c44e4430e"
},
"layers": [
{
"mediaType": "application/vnd.oci.image.layer.v1.tar+gzip",
"size": 1074934,
"digest": "sha256:e251e682f7e64cff127020015be3254313b3a7900f54d82ecf34653192be4c21"
}
]
}

Related

Rails: Calculate days between date range given in string format

How could I calculate days from a given date range in Rails Controller.
Example:
daterange = "August 24 - Sept 11, 2016"
Desired output: 19
Also we have to keep in mind that the date range string may also change to something:
"December 24 2016 - Jan 11, 2017"
Try this:
(daterange.split("-")[1].to_date - daterange.split("-")[0].to_date).to_i + 1
# daterange = "August 24 - Sept 11, 2016"
# => 19
# daterange = "December 24 2016 - Jan 11, 2017"
# => 19
This should work:
def day_difference(daterange)
daterange.split('-').map(&:to_date).inject { |r,e| (e-r).to_i + 1 }
end
With your given examples:
day_difference("August 24 - Sept 11, 2016")
# => 19
day_difference("December 24 2016 - Jan 11, 2017")
# => 19

Ruby - How to sum values of a hash based on a given date (=key)?

I have these values in a hash:
{nil=>0,
Thu, 03 Dec 2015=>#<BigDecimal:7ff496381db8,'0.151875E2',18(27)>,
Fri, 04 Dec 2015=>#<BigDecimal:7ff496381cf0,'0.214375E2',18(27)>,
Wed, 09 Dec 2015=>#<BigDecimal:7ff496381c28,'0.6229E2',18(27)>,
Thu, 10 Dec 2015=>#<BigDecimal:7ff496381b60,'0.1243E2',18(27)>,
Fri, 11 Dec 2015=>#<BigDecimal:7ff496381a98,'0.1243E2',18(27)>,
Mon, 14 Dec 2015=>#<BigDecimal:7ff4963819d0,'0.6611E2',18(27)>,
Tue, 15 Dec 2015=>#<BigDecimal:7ff496381908,'0.625E1',18(18)>,
Wed, 16 Dec 2015=>#<BigDecimal:7ff496381840,'0.73345E2',18(27)>,
Thu, 17 Dec 2015=>#<BigDecimal:7ff496381778,'0.31845E2',18(27)>,
Fri, 18 Dec 2015=>#<BigDecimal:7ff4963816b0,'0.409225E2',18(27)>,
Mon, 21 Dec 2015=>#<BigDecimal:7ff4963815e8,'0.8019E2',18(27)>,
Mon, 28 Dec 2015=>#<BigDecimal:7ff496381520,'0.3125E2',18(27)>,
Mon, 04 Jan 2016=>#<BigDecimal:7ff496381458,'0.125E2',18(27)>,
Wed, 06 Jan 2016=>#<BigDecimal:7ff496381390,'0.625E2',18(27)>,
Thu, 07 Jan 2016=>#<BigDecimal:7ff4963812c8,'0.9111E2',18(27)>,
Fri, 08 Jan 2016=>#<BigDecimal:7ff4963811d8,'0.11972E3',18(27)>,
Mon, 11 Jan 2016=>#<BigDecimal:7ff4963810e8,'0.5022E2',18(27)>,
Wed, 13 Jan 2016=>0, Thu, 14 Jan 2016=>0, Fri, 15 Jan 2016=>0,
Wed, 09 Mar 2016=>#<BigDecimal:7ff496380eb8,'0.258125E2',18(27)>,
Tue, 15 Mar 2016=>#<BigDecimal:7ff496380da0,'0.631825E2',18(27)>,
Wed, 16 Mar 2016=>#<BigDecimal:7ff496380cd8,'0.504225E2',18(27)>,
Thu, 17 Mar 2016=>#<BigDecimal:7ff496380c10,'0.125E2',18(27)>,
Fri, 18 Mar 2016=>#<BigDecimal:7ff496380b48,'0.631825E2',18(27)>,
Mon, 21 Mar 2016=>#<BigDecimal:7ff496380a80,'0.167925E2',18(27)>,
Tue, 22 Mar 2016=>0}
I am looping through some calendar data (#dates) and from here I get two variables containing a specific year and month:
#dates.each do |d|
current_yer = d.strftime('%Y') #2016
current_month = d.strftime('%m') # 01 - january
Now, I have variables containing the dates, I would like to print out a sum of all data in the hash; so in this case, I would like to get something like this as output:
2016 01: SUM of all January items in the hash
specifically, SUM of these:
Mon, 04 Jan 2016=>#<BigDecimal:7ff496381458,'0.125E2',18(27)>,
Wed, 06 Jan 2016=>#<BigDecimal:7ff496381390,'0.625E2',18(27)>,
Thu, 07 Jan 2016=>#<BigDecimal:7ff4963812c8,'0.9111E2',18(27)>,
Fri, 08 Jan 2016=>#<BigDecimal:7ff4963811d8,'0.11972E3',18(27)>,
Mon, 11 Jan 2016=>#<BigDecimal:7ff4963810e8,'0.5022E2',18(27)>,
Wed, 13 Jan 2016=>0, Thu, 14 Jan 2016=>0, Fri, 15 Jan 2016=>0,
How to do this?
Thank you in advance.
You can try with select and sum:
#dates.select{|d, _| d.strftime('%Y %m') == '2016 01'}.values.sum
Construct example hash
First let's construct a hash (h) that is similar to yours, but a bit smaller:
g = {
"Thu, 03 Dec 2015"=> 1,
"Fri, 11 Dec 2015"=> 2,
"Mon, 14 Dec 2015"=> 3,
"Tue, 15 Dec 2015"=> 4,
"Wed, 16 Dec 2015"=> 5,
"Fri, 18 Dec 2015"=> 6,
"Mon, 21 Dec 2015"=> 7,
"Mon, 04 Jan 2016"=> 8,
"Fri, 08 Jan 2016"=> 9,
"Wed, 13 Jan 2016"=> 0,
"Thu, 14 Jan 2016"=> 0,
"Wed, 09 Mar 2016"=>10,
"Tue, 15 Mar 2016"=>11,
"Wed, 16 Mar 2016"=>12,
"Mon, 21 Mar 2016"=>13,
"Tue, 22 Mar 2016"=> 0 }
require 'date'
require 'bigdecimal'
h = { nil=>0 }.tap { |h| g.each { |k,v|
h[Date.strptime(k, "%a, %d %b %Y")] = v.zero? ? 0 : BigDecimal.new(v) } }
#=> {nil=>0,
# #<Date: 2015-12-03 ((2457360j,0s,0n),+0s,2299161j)> =>
# #<BigDecimal:7faef915c8e0,'0.1E1',9(27)>,
# #<Date: 2015-12-11 ((2457368j,0s,0n),+0s,2299161j)> =>
# #<BigDecimal:7faef914ff28,'0.2E1',9(27)>,
# #<Date: 2015-12-14 ((2457371j,0s,0n),+0s,2299161j) >=>
# #<BigDecimal:7faef914f938,'0.3E1',9(27)>,
# #<Date: 2015-12-15 ((2457372j,0s,0n),+0s,2299161j)> =>
# #<BigDecimal:7faef914f7a8,'0.4E1',9(27)>,
# #<Date: 2015-12-16 ((2457373j,0s,0n),+0s,2299161j)> =>
# #<BigDecimal:7faef914f320,'0.5E1',9(27)>,
# #<Date: 2015-12-18 ((2457375j,0s,0n),+0s,2299161j)> =>
# #<BigDecimal:7faef914e8d0,'0.6E1',9(27)>,
# #<Date: 2015-12-21 ((2457378j,0s,0n),+0s,2299161j)> =>
# #<BigDecimal:7faef914dde0,'0.7E1',9(27)>,
# #<Date: 2016-01-04 ((2457392j,0s,0n),+0s,2299161j)> =>
# #<BigDecimal:7faef914dca0,'0.8E1',9(27)>,
# #<Date: 2016-01-08 ((2457396j,0s,0n),+0s,2299161j)> =>
# #<BigDecimal:7faef914d390,'0.9E1',9(27)>,
# #<Date: 2016-01-13 ((2457401j,0s,0n),+0s,2299161j)> =>
# 0,
# #<Date: 2016-01-14 ((2457402j,0s,0n),+0s,2299161j)> =>
# 0,
# #<Date: 2016-03-09 ((2457457j,0s,0n),+0s,2299161j)> =>
# #<BigDecimal:7faef914cd28,'0.1E2',9(27)>,
# #<Date: 2016-03-15 ((2457463j,0s,0n),+0s,2299161j)> =>
# #<BigDecimal:7faef913ff60,'0.11E2',9(27)>,
# #<Date: 2016-03-16 ((2457464j,0s,0n),+0s,2299161j)> =>
# #<BigDecimal:7faef913f8d0,'0.12E2',9(27)>,
# #<Date: 2016-03-21 ((2457469j,0s,0n),+0s,2299161j)> =>
# #<BigDecimal:7faef913f560,'0.13E2',9(27)>,
# #<Date: 2016-03-22 ((2457470j,0s,0n),+0s,2299161j)> =>
# 0
}
Here I've used the class methods Date::strptime and BigDecimal::new.
Sum BigDecimal values by month
We can now use Hash#reject, Enumerable#group_by, Enumerable#map, Enumerable#reduce (aka inject) and Array#to_h to obtain the results you require:
sums =
h.reject { |k,_| k.nil? }.
group_by { |k,_| [k.year, k.month] }.
map { |yr_and_mon, arr| [yr_and_mon, arr.reduce(0) { |t,(_,bd)| t+bd }] }.
to_h
#=> {[2015, 12]=>#<BigDecimal:7faef9197eb8,'0.28E2',9(18)>,
# [2016, 1]=>#<BigDecimal:7faef9197b70,'0.17E2',9(18)>,
# [2016, 3]=>#<BigDecimal:7faef9197760,'0.46E2',9(18)>}
We see that the BigDecimal values more easily by converting them to integers:
sums.merge(sums) { |*,v| v.to_i }
#=> {[2015, 12]=>28, [2016, 1]=>17, [2016, 3]=>46}
Compare these results with the hash g at the beginning of this answer.
I used the form of Hash#merge that employs a block to determine the values of keys that are present in both hashes being merged. As I am merging sums with itself, the block is used to determine the values of all keys.
Once you have the hash sums it's an easy task to print the totals by month and year in any format you want.
The steps
h1 = h.reject { |k,_| k.nil? }.group_by { |k,_| [k.year, k.month] }
#=> {[2015, 12]=>[[#<Date: 2015-12-03 ((2457360j,0s,0n),+0s,2299161j)>,
# #<BigDecimal:7faef915c8e0,'0.1E1',9(27)>],
# [#<Date: 2015-12-11 ((2457368j,0s,0n),+0s,2299161j)>,
# #<BigDecimal:7faef914ff28,'0.2E1',9(27)>],
...
# #<BigDecimal:7faef9093850,'0.46E2',9(18)>]]
a1 = h1.map { |yr_and_mon, arr| [yr_and_mon, arr.reduce(0) { |t,(_,bd)| t+bd }] }
#=> [[[2015, 12], #<BigDecimal:7faef9029dd8,'0.28E2',9(18)>],
# [[2016, 1], #<BigDecimal:7faef90296a8,'0.17E2',9(18)>],
# [[2016, 3], #<BigDecimal:7faef9028dc0,'0.46E2',9(18)>]]
a1.to_h
#=> {[2015, 12]=>#<BigDecimal:7faef9098710,'0.28E2',9(18)>,
# [2016, 1]=>#<BigDecimal:7faef9093da0,'0.17E2',9(18)>,
# [2016, 3]=>#<BigDecimal:7faef9093850,'0.46E2',9(18)>}

Merge hash with another hash

I have two hash like
h1 = {
DateTime.new(2015, 7, 1),in_time_zone => 0,
DateTime.new(2015, 7, 2).in_time_zone => 10,
DateTime.new(2015, 7, 4).in_time_zone => 20,
DateTime.new(2015, 7, 5).in_time_zone => 5
}
h2 = {
DateTime.new(2015, 7, 1).in_time_zone => 0,
DateTime.new(2015, 7, 2).in_time_zone => 0,
DateTime.new(2015, 7, 3).in_time_zone => 0
}
I want to merge h1 and h2, don't merge if key already exist, so that will result look like (datetime format with time zone shortened for readability)
result
#=> {
# Wed, 01 Jul 2015 01:00:00 EST +01:00 => 0,
# Thu, 02 Jul 2015 01:00:00 EST +01:00 => 10,
# Fri, 03 Jul 2015 01:00:00 EST +01:00 => 0,
# Sat, 04 Jul 2015 01:00:00 EST +01:00 => 20,
# Sun, 05 Jul 2015 01:00:00 EST +01:00 => 5
# }
I have tried with h1.merge(h2) and h2.merge(h1) but it can be put key and value of h2 to h1.
arr = []
h = h1.merge(h2)
h.each{|k, v| arr.include?(v) ? h.delete(k) : arr << v }
#=> {#<DateTime: 2015-07-01T00:00:00+00:00 ((2457205j,0s,0n),+0s,2299161j)>=>0,
#<DateTime: 2015-07-04T00:00:00+00:00 ((2457208j,0s,0n),+0s,2299161j)>=>20,
#<DateTime: 2015-07-05T00:00:00+00:00 ((2457209j,0s,0n),+0s,2299161j)>=>5}
You will have only three key-value pairs, not 5 as you expect, because hash in Ruby is collection of unique keys and their values.

Remove duplicates from Ruby arrays and sum

I have the following array of arrays [date, value]:
array = [[12 Mar 2015, 0], [12 Mar 2015, 5], [13 Mar 2015, 0], [14 Mar 2015, 49], [15 Mar 2015, 51], [15 Mar 2015, 10], [16 Mar 2015, 110], [17 Mar 2015, 0], [18 Mar 2015, 31], [19 Mar 2015, 47], [20 Mar 2015, 0], [21 Mar 2015, 0], [22 Mar 2015, 138], [22 Mar 2015, 10], [23 Mar 2015, 0]]
You can see that there are arrays with duplicate dates. How would one sum the values while grouping by the dates? This is what I am looking for:
array = [[12 Mar 2015, 5], [13 Mar 2015, 0], [14 Mar 2015, 49], [15 Mar 2015, 61], [16 Mar 2015, 110], [17 Mar 2015, 0], [18 Mar 2015, 31], [19 Mar 2015, 47], [20 Mar 2015, 0], [21 Mar 2015, 0], [22 Mar 2015, 148], [23 Mar 2015, 0]]
Your array of days should look like
array = [["12 Mar 2015", 0], ["12 Mar 2015", 5], ["13 Mar 2015", 0], ["14 Mar 2015", 49], ["15 Mar 2015", 51], ["15 Mar 2015", 10], ["16 Mar 2015", 110], ["17 Mar 2015", 0], ["18 Mar 2015", 31], ["19 Mar 2015", 47], ["20 Mar 2015", 0], ["21 Mar 2015", 0], ["22 Mar 2015", 138], ["22 Mar 2015", 10], ["23 Mar 2015", 0]]
grouped = array.inject(Hash.new(0)) do |result, itm|
result[itm.first] += itm.last
result
end.to_a
UPDATED
Many thanks to #nathanvda, inject({}) do |hash, [time, index]| was my mistake. In any case his solution is clearer.
array.inject({}) do |hash, item|
time, index = item.to_a
hash[time] = hash.fetch(time, 0) + index
hash
end.to_a

How to output a date range for each quarter of a year in Ruby?

Thanks to some people on this board I was able to come up with a function that returns a number of date ranges:
years = [2013, 2012, 2011, 2010, 2009]
def month_ranges
years.flat_map { |y|
12.downto(1).map { |m| Date.new(y,m,1)..Date.new(y,m,-1) }
}
end
# =>
[
01 Dec 2013..31 Dec 2013,
01 Nov 2013..31 Nov 2013,
01 Oct 2013..31 Oct 2013,
01 Sep 2013..31 Sep 2013,
01 Aug 2013..31 Aug 2013,
....
]
Now, is there a way to return the four quarters of a year as well?
So the output will be something like:
# =>
[
01 Oct 2013..31 Dec 2013,
01 Jul 2013..31 Sep 2013,
01 Apr 2013..31 Jun 2013,
01 Jan 2013..31 Mar 2013
]
(Note: If a month has 30 or 31 days doesn't really matter in this case.)
Thanks to anyone who can help.
This should work (based on month_ranges, i.e. last quarter comes first):
def quarter_ranges
years.flat_map { |y|
3.downto(0).map { |q|
Date.new(y, q * 3 + 1, 1)..Date.new(y, q * 3 + 3, -1)
}
}
end
Or a bit more verbose and maybe easier to understand:
def quarter_ranges
years.flat_map { |y|
[
Date.new(y, 10, 1)..Date.new(y, 12, -1),
Date.new(y, 7, 1)..Date.new(y, 9, -1),
Date.new(y, 4, 1)..Date.new(y, 6, -1),
Date.new(y, 1, 1)..Date.new(y, 3, -1)
]
}
end
You can use beginning_of_quarter and end_of_quarter to define quarters.
For example, if I want to group a date_range according to quarters I could do the following:
((Date.today - 1.year)..Date.today).group_by(&:beginning_of_quarter)
The keys in this case are the beginning of each quarter:
((Date.today - 1.year)..Date.today).group_by(&:beginning_of_quarter).keys
=> [Sun, 01 Jul 2012, Mon, 01 Oct 2012, Tue, 01 Jan 2013, Mon, 01 Apr 2013, Mon, 01 Jul 2013]
What about something like this:
> now = Time.now.beginning_of_month
=> 2013-09-01 00:00:00 +0200
> now..(now + 3.months)
=> 2013-09-01 00:00:00 +0200..2013-12-01 00:00:00 +0100
I'd do something like:
require 'date'
def quarters(y)
q = []
(1..4).each do |s|
q << (Date.new(y, s * 3 - 1, 1)..Date.new(y, s * 3, -1))
end
return q
end

Resources