Skip to content

Commit 74f566c

Browse files
authored
Merge pull request #12 from ruby-no-kai/skopeo-copy
skopeo-copy
2 parents 8a02397 + a4e641f commit 74f566c

7 files changed

Lines changed: 330 additions & 0 deletions

File tree

.github/workflows/docker-dnsdist.yml

Lines changed: 2 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
(import './docker-build-simple.libsonnet')('skopeo-copy') {
2+
jobs+: {
3+
merge+: {
4+
steps+: [
5+
{
6+
name: 'Push arm64 tag for Lambda', // doesnt support manifest
7+
run: |||
8+
dgst="$(docker buildx imagetools inspect --raw "${REPO}:${SHA}" | jq -r '.manifests[] | select(.platform.architecture == "arm64" and .platform.os == "linux") | .digest')"
9+
docker pull "${REPO}@${dgst}"
10+
docker tag "${REPO}@${dgst}" "${REPO}:${SHA}-arm64"
11+
docker push "${REPO}:${SHA}-arm64"
12+
|||,
13+
env: {
14+
REPO: std.format('${{ steps.login-ecr.outputs.registry }}/%s', 'skopeo-copy'),
15+
SHA: '${{ github.sha }}',
16+
},
17+
},
18+
],
19+
},
20+
},
21+
}

.github/workflows/docker-skopeo-copy.yml

Lines changed: 135 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

skopeo-copy/Dockerfile

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
FROM public.ecr.aws/sorah/ruby:4.0-dev AS builder
2+
3+
RUN --mount=type=cache,target=/var/cache/apt --mount=type=cache,target=/var/lib/apt/lists,sharing=locked apt-get update \
4+
&& DEBIAN_FRONTEND=noninteractive apt-get install -y libssl-dev
5+
6+
WORKDIR /var/task
7+
COPY Gemfile* /var/task/
8+
9+
RUN bundle config set path '/var/task/vendor/bundle' \
10+
&& bundle config set deployment 'true' \
11+
&& bundle install --jobs 30
12+
RUN bundle config set bin /usr/local/bin \
13+
&& bundle binstubs aws_lambda_ric --force
14+
15+
FROM public.ecr.aws/sorah/ruby:4.0
16+
17+
RUN --mount=type=cache,target=/var/cache/apt --mount=type=cache,target=/var/lib/apt/lists,sharing=locked apt-get update \
18+
&& DEBIAN_FRONTEND=noninteractive apt-get install -y skopeo
19+
20+
WORKDIR /var/task
21+
COPY --from=builder /var/task/vendor /var/task/vendor
22+
COPY --from=builder /var/task/.bundle /var/task/.bundle
23+
COPY --from=builder /usr/local/bin/aws_lambda_ric /usr/local/bin/
24+
COPY . /var/task/
25+
26+
ENTRYPOINT ["/usr/local/bin/aws_lambda_ric"]
27+
CMD ["app.handler"]

skopeo-copy/Gemfile

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
source 'https://rubygems.org'
2+
3+
gem 'aws_lambda_ric'
4+
gem 'aws-sdk-ecr'
5+
gem 'aws-sdk-ecrpublic'
6+
gem 'openssl'

skopeo-copy/Gemfile.lock

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
GEM
2+
remote: https://rubygems.org/
3+
specs:
4+
aws-eventstream (1.4.0)
5+
aws-partitions (1.1213.0)
6+
aws-sdk-core (3.242.0)
7+
aws-eventstream (~> 1, >= 1.3.0)
8+
aws-partitions (~> 1, >= 1.992.0)
9+
aws-sigv4 (~> 1.9)
10+
base64
11+
bigdecimal
12+
jmespath (~> 1, >= 1.6.1)
13+
logger
14+
aws-sdk-ecr (1.119.0)
15+
aws-sdk-core (~> 3, >= 3.241.4)
16+
aws-sigv4 (~> 1.5)
17+
aws-sdk-ecrpublic (1.62.0)
18+
aws-sdk-core (~> 3, >= 3.241.4)
19+
aws-sigv4 (~> 1.5)
20+
aws-sigv4 (1.12.1)
21+
aws-eventstream (~> 1, >= 1.0.2)
22+
aws_lambda_ric (3.1.3)
23+
base64 (0.3.0)
24+
bigdecimal (4.0.1)
25+
jmespath (1.6.2)
26+
logger (1.7.0)
27+
openssl (4.0.0)
28+
29+
PLATFORMS
30+
ruby
31+
32+
DEPENDENCIES
33+
aws-sdk-ecr
34+
aws-sdk-ecrpublic
35+
aws_lambda_ric
36+
openssl
37+
38+
CHECKSUMS
39+
aws-eventstream (1.4.0) sha256=116bf85c436200d1060811e6f5d2d40c88f65448f2125bc77ffce5121e6e183b
40+
aws-partitions (1.1213.0) sha256=5ec132d91d44ef2702125b8f71f0e4fc2cd7de040e02c5d0aefb87219fd2e05e
41+
aws-sdk-core (3.242.0) sha256=c17b3003acc78d80c1a8437b285a1cfc5e4d7749ce7821cf3071e847535a29a0
42+
aws-sdk-ecr (1.119.0) sha256=4e2d47c6f0f02d8e15c8abe7e2d5c99aa03502820db6409ed1a0a6063ca20e86
43+
aws-sdk-ecrpublic (1.62.0) sha256=c8c0101a3e99105b750ed775fe13ac8256b58f2752a0a4b8f8992a5e7aef2c36
44+
aws-sigv4 (1.12.1) sha256=6973ff95cb0fd0dc58ba26e90e9510a2219525d07620c8babeb70ef831826c00
45+
aws_lambda_ric (3.1.3) sha256=7d7551c91d2070bb1427cd05d7b0b94076d42084f743b117522659a76935dfbc
46+
base64 (0.3.0) sha256=27337aeabad6ffae05c265c450490628ef3ebd4b67be58257393227588f5a97b
47+
bigdecimal (4.0.1) sha256=8b07d3d065a9f921c80ceaea7c9d4ae596697295b584c296fe599dd0ad01c4a7
48+
jmespath (1.6.2) sha256=238d774a58723d6c090494c8879b5e9918c19485f7e840f2c1c7532cf84ebcb1
49+
logger (1.7.0) sha256=196edec7cc44b66cfb40f9755ce11b392f21f7967696af15d274dde7edff0203
50+
openssl (4.0.0) sha256=185711ed93d4e9c9a9db6efea7edb202dfe04f7d3692fbab988e3d84e498ee91
51+
52+
BUNDLED WITH
53+
4.0.3

skopeo-copy/app.rb

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
$stdout.sync = true
2+
3+
require 'json'
4+
require 'base64'
5+
require 'logger'
6+
require 'open3'
7+
require 'aws-sdk-ecr'
8+
require 'aws-sdk-ecrpublic'
9+
10+
module SkopeoCopy
11+
ECR_PRIVATE_PATTERN = /\A(\d+)\.dkr\.ecr\.([^.]+)\.amazonaws\.com\z/
12+
ECR_PUBLIC_HOST = 'public.ecr.aws'
13+
AUTHFILE = '/tmp/containers-auth.json'
14+
15+
Registry = Data.define(:host, :kind, :account_id, :region)
16+
17+
def self.detect_registry(image_ref)
18+
host = image_ref.sub(%r{\A[a-z0-9+-]+://}, '').split('/').first
19+
case host
20+
when ECR_PRIVATE_PATTERN
21+
Registry.new(host:, kind: :ecr_private, account_id: $1, region: $2)
22+
when ECR_PUBLIC_HOST
23+
Registry.new(host:, kind: :ecr_public, account_id: nil, region: nil)
24+
end
25+
end
26+
27+
def self.ecr_login_password(account_id:, region:)
28+
client = Aws::ECR::Client.new(region:, logger:)
29+
resp = client.get_authorization_token(registry_ids: [account_id])
30+
token = Base64.decode64(resp.authorization_data[0].authorization_token)
31+
_user, password = token.split(':', 2)
32+
password
33+
end
34+
35+
# ECR Public endpoint is only available in us-east-1
36+
def self.ecr_public_login_password
37+
client = Aws::ECRPublic::Client.new(region: 'us-east-1', logger:)
38+
resp = client.get_authorization_token
39+
token = Base64.decode64(resp.authorization_data.authorization_token)
40+
_user, password = token.split(':', 2)
41+
password
42+
end
43+
44+
def self.skopeo_login(registry:, password:)
45+
out, status = Open3.capture2e('skopeo', 'login', '--authfile', AUTHFILE, '--username', 'AWS', '--password-stdin', registry, stdin_data: password)
46+
logger.info("skopeo login #{registry}: #{out}")
47+
raise "skopeo login #{registry} failed (status=#{status.exitstatus}): #{out}" unless status.success?
48+
end
49+
50+
def self.skopeo_copy(src:, dst:)
51+
logger.info("skopeo copy #{src} #{dst}")
52+
out, status = Open3.capture2e('skopeo', 'copy', '--authfile', AUTHFILE, src, dst)
53+
logger.info("skopeo copy: #{out}")
54+
raise "skopeo copy failed (status=#{status.exitstatus}): #{out}" unless status.success?
55+
end
56+
57+
def self.logger
58+
@logger ||= Logger.new($stdout)
59+
end
60+
61+
def self.perform(event)
62+
params = event.fetch('skopeo_copy')
63+
src = params.fetch('src')
64+
dst = params.fetch('dst')
65+
66+
registries = [detect_registry(src), detect_registry(dst)].compact.uniq
67+
registries.each do |reg|
68+
case reg.kind
69+
when :ecr_private
70+
password = ecr_login_password(account_id: reg.account_id, region: reg.region)
71+
skopeo_login(registry: reg.host, password:)
72+
when :ecr_public
73+
password = ecr_public_login_password
74+
skopeo_login(registry: reg.host, password:)
75+
end
76+
end
77+
78+
skopeo_copy(src:, dst:)
79+
80+
{status: 'ok', src:, dst:}
81+
end
82+
end
83+
84+
def handler(event:, context:)
85+
SkopeoCopy.perform(event)
86+
end

0 commit comments

Comments
 (0)