Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
G
gitlab-ce
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
1
Merge Requests
1
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
nexedi
gitlab-ce
Commits
716154cb
Commit
716154cb
authored
Aug 25, 2021
by
Ian Baum
Committed by
Michael Kozono
Aug 25, 2021
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Geo: Replicate multi-arch containers
parent
cea3caef
Changes
5
Hide whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
103 additions
and
26 deletions
+103
-26
ee/app/services/geo/container_repository_sync.rb
ee/app/services/geo/container_repository_sync.rb
+23
-8
ee/lib/ee/container_registry/client.rb
ee/lib/ee/container_registry/client.rb
+1
-1
ee/spec/lib/container_registry/client_spec.rb
ee/spec/lib/container_registry/client_spec.rb
+9
-1
ee/spec/services/geo/container_repository_sync_spec.rb
ee/spec/services/geo/container_repository_sync_spec.rb
+67
-16
lib/container_registry/client.rb
lib/container_registry/client.rb
+3
-0
No files found.
ee/app/services/geo/container_repository_sync.rb
View file @
716154cb
...
@@ -25,21 +25,36 @@ module Geo
...
@@ -25,21 +25,36 @@ module Geo
private
private
def
sync_tag
(
tag
)
def
sync_tag
(
tag
)
file
=
nil
manifest
=
client
.
repository_raw_manifest
(
repository_path
,
tag
[
:name
])
manifest
=
client
.
repository_raw_manifest
(
repository_path
,
tag
[
:name
])
manifest_parsed
=
Gitlab
::
Json
.
parse
(
manifest
)
manifest_parsed
=
Gitlab
::
Json
.
parse
(
manifest
)
list_blobs
(
manifest_parsed
).
each
do
|
digest
|
case
manifest_parsed
[
'mediaType'
]
when
ContainerRegistry
::
Client
::
DOCKER_DISTRIBUTION_MANIFEST_V2_TYPE
push_manifest_blobs
(
manifest_parsed
)
when
ContainerRegistry
::
Client
::
DOCKER_DISTRIBUTION_MANIFEST_LIST_V2_TYPE
manifest_parsed
[
'manifests'
].
each
do
|
submanifest
|
image_info_raw
=
client
.
repository_raw_manifest
(
repository_path
,
submanifest
[
'digest'
])
image_info
=
Gitlab
::
Json
.
parse
(
image_info_raw
)
push_manifest_blobs
(
image_info
)
container_repository
.
push_manifest
(
submanifest
[
'digest'
],
image_info_raw
,
image_info
[
'mediaType'
])
end
else
raise
"Unexpected mediaType:
#{
manifest_parsed
[
'mediaType'
]
}
"
end
container_repository
.
push_manifest
(
tag
[
:name
],
manifest
,
manifest_parsed
[
'mediaType'
])
end
def
push_manifest_blobs
(
manifest
)
list_blobs
(
manifest
).
each
do
|
digest
|
next
if
container_repository
.
blob_exists?
(
digest
)
next
if
container_repository
.
blob_exists?
(
digest
)
file
=
client
.
pull_blob
(
repository_path
,
digest
)
file
=
client
.
pull_blob
(
repository_path
,
digest
)
container_repository
.
push_blob
(
digest
,
file
.
path
)
begin
file
.
unlink
container_repository
.
push_blob
(
digest
,
file
.
path
)
ensure
file
.
unlink
end
end
end
container_repository
.
push_manifest
(
tag
[
:name
],
manifest
,
manifest_parsed
[
'mediaType'
])
ensure
file
.
try
(
:unlink
)
end
end
def
remove_tag
(
tag
)
def
remove_tag
(
tag
)
...
...
ee/lib/ee/container_registry/client.rb
View file @
716154cb
...
@@ -94,7 +94,7 @@ module EE
...
@@ -94,7 +94,7 @@ module EE
# rubocop:enable Gitlab/ModuleWithInstanceVariables
# rubocop:enable Gitlab/ModuleWithInstanceVariables
def
accept_raw_manifest
(
conn
)
def
accept_raw_manifest
(
conn
)
conn
.
headers
[
'Accept'
]
=
::
ContainerRegistry
::
Client
::
ACCEPTED_TYPES
conn
.
headers
[
'Accept'
]
=
::
ContainerRegistry
::
Client
::
ACCEPTED_TYPES
_RAW
end
end
end
end
end
end
...
...
ee/spec/lib/container_registry/client_spec.rb
View file @
716154cb
...
@@ -24,6 +24,14 @@ RSpec.describe ContainerRegistry::Client do
...
@@ -24,6 +24,14 @@ RSpec.describe ContainerRegistry::Client do
}
}
end
end
let
(
:headers_with_accept_types_with_list
)
do
{
'Accept'
=>
'application/vnd.docker.distribution.manifest.v2+json, application/vnd.oci.image.manifest.v1+json, application/vnd.docker.distribution.manifest.list.v2+json'
,
'Authorization'
=>
'bearer 12345'
,
'User-Agent'
=>
"GitLab/
#{
Gitlab
::
VERSION
}
"
}
end
describe
'#push_blob'
do
describe
'#push_blob'
do
let
(
:file
)
do
let
(
:file
)
do
file
=
Tempfile
.
new
(
'test1'
)
file
=
Tempfile
.
new
(
'test1'
)
...
@@ -119,7 +127,7 @@ RSpec.describe ContainerRegistry::Client do
...
@@ -119,7 +127,7 @@ RSpec.describe ContainerRegistry::Client do
it
'GET "/v2/:name/manifests/:reference'
do
it
'GET "/v2/:name/manifests/:reference'
do
stub_request
(
:get
,
'http://registry/v2/group/test/manifests/my-tag'
)
stub_request
(
:get
,
'http://registry/v2/group/test/manifests/my-tag'
)
.
with
(
headers:
headers_with_accept_types
)
.
with
(
headers:
headers_with_accept_types
_with_list
)
.
to_return
(
status:
200
,
body:
manifest
,
headers:
{})
.
to_return
(
status:
200
,
body:
manifest
,
headers:
{})
expect
(
client
.
repository_raw_manifest
(
'group/test'
,
'my-tag'
)).
to
eq
(
manifest
)
expect
(
client
.
repository_raw_manifest
(
'group/test'
,
'my-tag'
)).
to
eq
(
manifest
)
...
...
ee/spec/services/geo/container_repository_sync_spec.rb
View file @
716154cb
...
@@ -17,6 +17,7 @@ RSpec.describe Geo::ContainerRepositorySync, :geo do
...
@@ -17,6 +17,7 @@ RSpec.describe Geo::ContainerRepositorySync, :geo do
let
(
:manifest
)
do
let
(
:manifest
)
do
"{"
\
"{"
\
"
\n\"
schemaVersion
\"
:2,"
\
"
\n\"
schemaVersion
\"
:2,"
\
"
\n\"
mediaType
\"
:
\"
application/vnd.docker.distribution.manifest.v2+json
\"
,"
\
"
\n\"
layers
\"
:["
\
"
\n\"
layers
\"
:["
\
"{
\n\"
mediaType
\"
:
\"
application/vnd.docker.distribution.manifest.v2+json
\"
,
\n\"
size
\"
:3333,
\n\"
digest
\"
:
\"
sha256:3333
\"
},"
\
"{
\n\"
mediaType
\"
:
\"
application/vnd.docker.distribution.manifest.v2+json
\"
,
\n\"
size
\"
:3333,
\n\"
digest
\"
:
\"
sha256:3333
\"
},"
\
"{
\n\"
mediaType
\"
:
\"
application/vnd.docker.distribution.manifest.v2+json
\"
,
\n\"
size
\"
:4444,
\n\"
digest
\"
:
\"
sha256:4444
\"
},"
\
"{
\n\"
mediaType
\"
:
\"
application/vnd.docker.distribution.manifest.v2+json
\"
,
\n\"
size
\"
:4444,
\n\"
digest
\"
:
\"
sha256:4444
\"
},"
\
...
@@ -25,6 +26,26 @@ RSpec.describe Geo::ContainerRepositorySync, :geo do
...
@@ -25,6 +26,26 @@ RSpec.describe Geo::ContainerRepositorySync, :geo do
"}"
"}"
end
end
let
(
:manifest_list
)
do
%Q(
{
"schemaVersion":2,
"mediaType":"application/vnd.docker.distribution.manifest.list.v2+json",
"manifests":[
{
"mediaType":"application/vnd.docker.distribution.manifest.v2+json",
"size":6666,
"digest":"sha256:6666",
"platform":
{
"architecture":"arm64","os":"linux"
}
}
]
}
)
end
before
do
before
do
stub_container_registry_config
(
enabled:
true
,
api_url:
secondary_api_url
)
stub_container_registry_config
(
enabled:
true
,
api_url:
secondary_api_url
)
stub_registry_replication_config
(
enabled:
true
,
primary_api_url:
primary_api_url
)
stub_registry_replication_config
(
enabled:
true
,
primary_api_url:
primary_api_url
)
...
@@ -61,6 +82,16 @@ RSpec.describe Geo::ContainerRepositorySync, :geo do
...
@@ -61,6 +82,16 @@ RSpec.describe Geo::ContainerRepositorySync, :geo do
.
to_return
(
status:
200
,
body:
manifest
,
headers:
{})
.
to_return
(
status:
200
,
body:
manifest
,
headers:
{})
end
end
def
stub_secondary_raw_manifest_request
(
repository_url
,
tag
,
manifest
)
stub_request
(
:get
,
"
#{
repository_url
}
/manifests/
#{
tag
}
"
)
.
to_return
(
status:
200
,
body:
manifest
,
headers:
{})
end
def
stub_primary_raw_manifest_list_request
(
repository_url
,
tag
,
manifest
)
stub_request
(
:get
,
"
#{
repository_url
}
/manifests/
#{
tag
}
"
)
.
to_return
(
status:
200
,
body:
manifest_list
,
headers:
{})
end
def
stub_secondary_push_manifest_request
(
repository_url
,
tag
,
manifest
)
def
stub_secondary_push_manifest_request
(
repository_url
,
tag
,
manifest
)
stub_request
(
:put
,
"
#{
repository_url
}
/manifests/
#{
tag
}
"
)
stub_request
(
:put
,
"
#{
repository_url
}
/manifests/
#{
tag
}
"
)
.
with
(
body:
manifest
)
.
with
(
body:
manifest
)
...
@@ -82,26 +113,46 @@ RSpec.describe Geo::ContainerRepositorySync, :geo do
...
@@ -82,26 +113,46 @@ RSpec.describe Geo::ContainerRepositorySync, :geo do
describe
'#execute'
do
describe
'#execute'
do
subject
{
described_class
.
new
(
container_repository
)
}
subject
{
described_class
.
new
(
container_repository
)
}
it
'determines list of tags to sync and to remove correctly'
do
context
'single manifest'
do
stub_primary_repository_tags_requests
(
primary_repository_url
,
{
'tag-to-sync'
=>
'sha256:1111'
})
it
'determines list of tags to sync and to remove correctly'
do
stub_secondary_repository_tags_requests
(
secondary_repository_url
,
{
'tag-to-remove'
=>
'sha256:2222'
})
stub_primary_repository_tags_requests
(
primary_repository_url
,
{
'tag-to-sync'
=>
'sha256:1111'
})
stub_primary_raw_manifest_request
(
primary_repository_url
,
'tag-to-sync'
,
manifest
)
stub_secondary_repository_tags_requests
(
secondary_repository_url
,
{
'tag-to-remove'
=>
'sha256:2222'
})
stub_missing_blobs_requests
(
primary_repository_url
,
secondary_repository_url
,
{
'sha256:3333'
=>
true
,
'sha256:4444'
=>
false
})
stub_primary_raw_manifest_request
(
primary_repository_url
,
'tag-to-sync'
,
manifest
)
stub_secondary_push_manifest_request
(
secondary_repository_url
,
'tag-to-sync'
,
manifest
)
stub_missing_blobs_requests
(
primary_repository_url
,
secondary_repository_url
,
{
'sha256:3333'
=>
true
,
'sha256:4444'
=>
false
})
stub_secondary_push_manifest_request
(
secondary_repository_url
,
'tag-to-sync'
,
manifest
)
expect
(
container_repository
).
to
receive
(
:push_blob
).
with
(
'sha256:3333'
,
anything
)
expect
(
container_repository
).
to
receive
(
:push_blob
).
with
(
'sha256:3333'
,
anything
)
expect
(
container_repository
).
not_to
receive
(
:push_blob
).
with
(
'sha256:4444'
,
anything
)
expect
(
container_repository
).
not_to
receive
(
:push_blob
).
with
(
'sha256:4444'
,
anything
)
expect
(
container_repository
).
not_to
receive
(
:push_blob
).
with
(
'sha256:5555'
,
anything
)
expect
(
container_repository
).
not_to
receive
(
:push_blob
).
with
(
'sha256:5555'
,
anything
)
expect
(
container_repository
).
to
receive
(
:delete_tag_by_digest
).
with
(
'sha256:2222'
)
expect
(
container_repository
).
to
receive
(
:delete_tag_by_digest
).
with
(
'sha256:2222'
)
subject
.
execute
subject
.
execute
end
end
context
'when primary repository has no tags'
do
context
'when primary repository has no tags'
do
it
'removes secondary tags and does not fail'
do
it
'removes secondary tags and does not fail'
do
stub_primary_repository_tags_requests
(
primary_repository_url
,
{})
stub_primary_repository_tags_requests
(
primary_repository_url
,
{})
stub_secondary_repository_tags_requests
(
secondary_repository_url
,
{
'tag-to-remove'
=>
'sha256:2222'
})
stub_secondary_repository_tags_requests
(
secondary_repository_url
,
{
'tag-to-remove'
=>
'sha256:2222'
})
expect
(
container_repository
).
to
receive
(
:delete_tag_by_digest
).
with
(
'sha256:2222'
)
subject
.
execute
end
end
end
context
'manifest list'
do
it
'pushes the correct blobs and manifests'
do
stub_primary_repository_tags_requests
(
primary_repository_url
,
{
'tag-to-sync'
=>
'sha256:1111'
})
stub_secondary_repository_tags_requests
(
secondary_repository_url
,
{})
stub_primary_raw_manifest_list_request
(
primary_repository_url
,
'tag-to-sync'
,
manifest_list
)
stub_primary_raw_manifest_request
(
primary_repository_url
,
'sha256:6666'
,
manifest
)
stub_secondary_raw_manifest_request
(
secondary_repository_url
,
'sha256:6666'
,
manifest
)
stub_missing_blobs_requests
(
primary_repository_url
,
secondary_repository_url
,
{
'sha256:3333'
=>
true
,
'sha256:4444'
=>
false
})
expect
(
container_repository
).
to
receive
(
:push_blob
).
with
(
'sha256:3333'
,
anything
)
expect
(
container_repository
).
to
receive
(
:push_manifest
).
with
(
'sha256:6666'
,
anything
,
anything
)
expect
(
container_repository
).
to
receive
(
:push_manifest
).
with
(
'tag-to-sync'
,
anything
,
anything
)
expect
(
container_repository
).
to
receive
(
:delete_tag_by_digest
).
with
(
'sha256:2222'
)
expect
(
container_repository
).
to
receive
(
:delete_tag_by_digest
).
with
(
'sha256:2222'
)
subject
.
execute
subject
.
execute
...
...
lib/container_registry/client.rb
View file @
716154cb
...
@@ -11,6 +11,7 @@ module ContainerRegistry
...
@@ -11,6 +11,7 @@ module ContainerRegistry
attr_accessor
:uri
attr_accessor
:uri
DOCKER_DISTRIBUTION_MANIFEST_V2_TYPE
=
'application/vnd.docker.distribution.manifest.v2+json'
DOCKER_DISTRIBUTION_MANIFEST_V2_TYPE
=
'application/vnd.docker.distribution.manifest.v2+json'
DOCKER_DISTRIBUTION_MANIFEST_LIST_V2_TYPE
=
'application/vnd.docker.distribution.manifest.list.v2+json'
OCI_MANIFEST_V1_TYPE
=
'application/vnd.oci.image.manifest.v1+json'
OCI_MANIFEST_V1_TYPE
=
'application/vnd.oci.image.manifest.v1+json'
CONTAINER_IMAGE_V1_TYPE
=
'application/vnd.docker.container.image.v1+json'
CONTAINER_IMAGE_V1_TYPE
=
'application/vnd.docker.container.image.v1+json'
REGISTRY_VERSION_HEADER
=
'gitlab-container-registry-version'
REGISTRY_VERSION_HEADER
=
'gitlab-container-registry-version'
...
@@ -19,6 +20,8 @@ module ContainerRegistry
...
@@ -19,6 +20,8 @@ module ContainerRegistry
ACCEPTED_TYPES
=
[
DOCKER_DISTRIBUTION_MANIFEST_V2_TYPE
,
OCI_MANIFEST_V1_TYPE
].
freeze
ACCEPTED_TYPES
=
[
DOCKER_DISTRIBUTION_MANIFEST_V2_TYPE
,
OCI_MANIFEST_V1_TYPE
].
freeze
ACCEPTED_TYPES_RAW
=
[
DOCKER_DISTRIBUTION_MANIFEST_V2_TYPE
,
OCI_MANIFEST_V1_TYPE
,
DOCKER_DISTRIBUTION_MANIFEST_LIST_V2_TYPE
].
freeze
# Taken from: FaradayMiddleware::FollowRedirects
# Taken from: FaradayMiddleware::FollowRedirects
REDIRECT_CODES
=
Set
.
new
[
301
,
302
,
303
,
307
]
REDIRECT_CODES
=
Set
.
new
[
301
,
302
,
303
,
307
]
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment