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
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Kirill Smelkov
gitlab-ce
Commits
a410c7af
Commit
a410c7af
authored
May 18, 2016
by
Fatih Acet
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'master' of gitlab.com:gitlab-org/gitlab-ce into awardables
parents
bb883387
08fddae7
Changes
41
Hide whitespace changes
Inline
Side-by-side
Showing
41 changed files
with
954 additions
and
22 deletions
+954
-22
app/controllers/projects/container_registry_controller.rb
app/controllers/projects/container_registry_controller.rb
+34
-0
app/helpers/gitlab_routing_helper.rb
app/helpers/gitlab_routing_helper.rb
+4
-0
app/helpers/projects_helper.rb
app/helpers/projects_helper.rb
+4
-0
app/models/namespace.rb
app/models/namespace.rb
+8
-0
app/models/project.rb
app/models/project.rb
+26
-3
app/services/auth/container_registry_authentication_service.rb
...ervices/auth/container_registry_authentication_service.rb
+12
-1
app/services/projects/destroy_service.rb
app/services/projects/destroy_service.rb
+10
-0
app/services/projects/transfer_service.rb
app/services/projects/transfer_service.rb
+5
-0
app/views/layouts/nav/_project.html.haml
app/views/layouts/nav/_project.html.haml
+7
-0
app/views/projects/container_registry/_header_title.html.haml
...views/projects/container_registry/_header_title.html.haml
+1
-0
app/views/projects/container_registry/_tag.html.haml
app/views/projects/container_registry/_tag.html.haml
+21
-0
app/views/projects/container_registry/index.html.haml
app/views/projects/container_registry/index.html.haml
+40
-0
config/gitlab.yml.example
config/gitlab.yml.example
+1
-0
config/initializers/1_settings.rb
config/initializers/1_settings.rb
+3
-0
config/routes.rb
config/routes.rb
+2
-0
doc/permissions/permissions.md
doc/permissions/permissions.md
+1
-0
lib/backup/manager.rb
lib/backup/manager.rb
+1
-1
lib/backup/registry.rb
lib/backup/registry.rb
+13
-0
lib/container_registry/blob.rb
lib/container_registry/blob.rb
+48
-0
lib/container_registry/client.rb
lib/container_registry/client.rb
+61
-0
lib/container_registry/config.rb
lib/container_registry/config.rb
+16
-0
lib/container_registry/registry.rb
lib/container_registry/registry.rb
+21
-0
lib/container_registry/repository.rb
lib/container_registry/repository.rb
+48
-0
lib/container_registry/tag.rb
lib/container_registry/tag.rb
+77
-0
lib/gitlab/regex.rb
lib/gitlab/regex.rb
+4
-0
lib/tasks/gitlab/backup.rake
lib/tasks/gitlab/backup.rake
+21
-0
shared/registry/.gitkeep
shared/registry/.gitkeep
+0
-0
spec/features/container_registry_spec.rb
spec/features/container_registry_spec.rb
+44
-0
spec/fixtures/container_registry/config_blob.json
spec/fixtures/container_registry/config_blob.json
+1
-0
spec/fixtures/container_registry/tag_manifest.json
spec/fixtures/container_registry/tag_manifest.json
+1
-0
spec/lib/container_registry/blob_spec.rb
spec/lib/container_registry/blob_spec.rb
+61
-0
spec/lib/container_registry/registry_spec.rb
spec/lib/container_registry/registry_spec.rb
+28
-0
spec/lib/container_registry/repository_spec.rb
spec/lib/container_registry/repository_spec.rb
+65
-0
spec/lib/container_registry/tag_spec.rb
spec/lib/container_registry/tag_spec.rb
+89
-0
spec/models/namespace_spec.rb
spec/models/namespace_spec.rb
+14
-0
spec/models/project_spec.rb
spec/models/project_spec.rb
+80
-2
spec/services/auth/container_registry_authentication_service_spec.rb
...es/auth/container_registry_authentication_service_spec.rb
+22
-10
spec/services/projects/destroy_service_spec.rb
spec/services/projects/destroy_service_spec.rb
+23
-0
spec/services/projects/transfer_service_spec.rb
spec/services/projects/transfer_service_spec.rb
+11
-0
spec/support/stub_gitlab_calls.rb
spec/support/stub_gitlab_calls.rb
+17
-0
spec/tasks/gitlab/backup_rake_spec.rb
spec/tasks/gitlab/backup_rake_spec.rb
+9
-5
No files found.
app/controllers/projects/container_registry_controller.rb
0 → 100644
View file @
a410c7af
class
Projects::ContainerRegistryController
<
Projects
::
ApplicationController
before_action
:verify_registry_enabled
before_action
:authorize_read_container_image!
before_action
:authorize_update_container_image!
,
only:
[
:destroy
]
layout
'project'
def
index
@tags
=
container_registry_repository
.
tags
end
def
destroy
url
=
namespace_project_container_registry_index_path
(
project
.
namespace
,
project
)
if
tag
.
delete
redirect_to
url
else
redirect_to
url
,
alert:
'Failed to remove tag'
end
end
private
def
verify_registry_enabled
render_404
unless
Gitlab
.
config
.
registry
.
enabled
end
def
container_registry_repository
@container_registry_repository
||=
project
.
container_registry_repository
end
def
tag
@tag
||=
container_registry_repository
.
tag
(
params
[
:id
])
end
end
app/helpers/gitlab_routing_helper.rb
View file @
a410c7af
...
@@ -33,6 +33,10 @@ module GitlabRoutingHelper
...
@@ -33,6 +33,10 @@ module GitlabRoutingHelper
namespace_project_builds_path
(
project
.
namespace
,
project
,
*
args
)
namespace_project_builds_path
(
project
.
namespace
,
project
,
*
args
)
end
end
def
project_container_registry_path
(
project
,
*
args
)
namespace_project_container_registry_index_path
(
project
.
namespace
,
project
,
*
args
)
end
def
activity_project_path
(
project
,
*
args
)
def
activity_project_path
(
project
,
*
args
)
activity_namespace_project_path
(
project
.
namespace
,
project
,
*
args
)
activity_namespace_project_path
(
project
.
namespace
,
project
,
*
args
)
end
end
...
...
app/helpers/projects_helper.rb
View file @
a410c7af
...
@@ -152,6 +152,10 @@ module ProjectsHelper
...
@@ -152,6 +152,10 @@ module ProjectsHelper
nav_tabs
<<
:builds
nav_tabs
<<
:builds
end
end
if
Gitlab
.
config
.
registry
.
enabled
&&
can?
(
current_user
,
:read_container_image
,
project
)
nav_tabs
<<
:container_registry
end
if
can?
(
current_user
,
:admin_project
,
project
)
if
can?
(
current_user
,
:admin_project
,
project
)
nav_tabs
<<
:settings
nav_tabs
<<
:settings
end
end
...
...
app/models/namespace.rb
View file @
a410c7af
...
@@ -110,6 +110,10 @@ class Namespace < ActiveRecord::Base
...
@@ -110,6 +110,10 @@ class Namespace < ActiveRecord::Base
# Ensure old directory exists before moving it
# Ensure old directory exists before moving it
gitlab_shell
.
add_namespace
(
path_was
)
gitlab_shell
.
add_namespace
(
path_was
)
if
any_project_has_container_registry_tags?
raise
Exception
.
new
(
'Namespace cannot be moved, because at least one project has tags in container registry'
)
end
if
gitlab_shell
.
mv_namespace
(
path_was
,
path
)
if
gitlab_shell
.
mv_namespace
(
path_was
,
path
)
Gitlab
::
UploadsTransfer
.
new
.
rename_namespace
(
path_was
,
path
)
Gitlab
::
UploadsTransfer
.
new
.
rename_namespace
(
path_was
,
path
)
...
@@ -131,6 +135,10 @@ class Namespace < ActiveRecord::Base
...
@@ -131,6 +135,10 @@ class Namespace < ActiveRecord::Base
end
end
end
end
def
any_project_has_container_registry_tags?
projects
.
any?
(
&
:has_container_registry_tags?
)
end
def
send_update_instructions
def
send_update_instructions
projects
.
each
do
|
project
|
projects
.
each
do
|
project
|
project
.
send_move_instructions
(
"
#{
path_was
}
/
#{
project
.
path
}
"
)
project
.
send_move_instructions
(
"
#{
path_was
}
/
#{
project
.
path
}
"
)
...
...
app/models/project.rb
View file @
a410c7af
...
@@ -329,12 +329,30 @@ class Project < ActiveRecord::Base
...
@@ -329,12 +329,30 @@ class Project < ActiveRecord::Base
@repository
||=
Repository
.
new
(
path_with_namespace
,
self
)
@repository
||=
Repository
.
new
(
path_with_namespace
,
self
)
end
end
def
container_registry_url
def
container_registry_repository
if
container_registry_enabled?
&&
Gitlab
.
config
.
registry
.
enabled
return
unless
Gitlab
.
config
.
registry
.
enabled
"
#{
Gitlab
.
config
.
registry
.
host_with_port
}
/
#{
path_with_namespace
}
"
@container_registry_repository
||=
begin
token
=
Auth
::
ContainerRegistryAuthenticationService
.
full_access_token
(
path_with_namespace
)
url
=
Gitlab
.
config
.
registry
.
api_url
host_port
=
Gitlab
.
config
.
registry
.
host_port
registry
=
ContainerRegistry
::
Registry
.
new
(
url
,
token:
token
,
path:
host_port
)
registry
.
repository
(
path_with_namespace
)
end
end
end
end
def
container_registry_repository_url
if
Gitlab
.
config
.
registry
.
enabled
"
#{
Gitlab
.
config
.
registry
.
host_port
}
/
#{
path_with_namespace
}
"
end
end
def
has_container_registry_tags?
return
unless
container_registry_repository
container_registry_repository
.
tags
.
any?
end
def
commit
(
id
=
'HEAD'
)
def
commit
(
id
=
'HEAD'
)
repository
.
commit
(
id
)
repository
.
commit
(
id
)
end
end
...
@@ -746,6 +764,11 @@ class Project < ActiveRecord::Base
...
@@ -746,6 +764,11 @@ class Project < ActiveRecord::Base
expire_caches_before_rename
(
old_path_with_namespace
)
expire_caches_before_rename
(
old_path_with_namespace
)
if
has_container_registry_tags?
# we currently doesn't support renaming repository if it contains tags in container registry
raise
Exception
.
new
(
'Project cannot be renamed, because tags are present in its container registry'
)
end
if
gitlab_shell
.
mv_repository
(
old_path_with_namespace
,
new_path_with_namespace
)
if
gitlab_shell
.
mv_repository
(
old_path_with_namespace
,
new_path_with_namespace
)
# If repository moved successfully we need to send update instructions to users.
# If repository moved successfully we need to send update instructions to users.
# However we cannot allow rollback since we moved repository
# However we cannot allow rollback since we moved repository
...
...
app/services/auth/container_registry_authentication_service.rb
View file @
a410c7af
...
@@ -6,7 +6,7 @@ module Auth
...
@@ -6,7 +6,7 @@ module Auth
return
error
(
'not found'
,
404
)
unless
registry
.
enabled
return
error
(
'not found'
,
404
)
unless
registry
.
enabled
if
params
[
:offline_token
]
if
params
[
:offline_token
]
return
error
(
'
forbidden'
,
403
)
unless
current_user
return
error
(
'
unauthorized'
,
401
)
unless
current_user
else
else
return
error
(
'forbidden'
,
403
)
unless
scope
return
error
(
'forbidden'
,
403
)
unless
scope
end
end
...
@@ -14,6 +14,17 @@ module Auth
...
@@ -14,6 +14,17 @@ module Auth
{
token:
authorized_token
(
scope
).
encoded
}
{
token:
authorized_token
(
scope
).
encoded
}
end
end
def
self
.
full_access_token
(
*
names
)
registry
=
Gitlab
.
config
.
registry
token
=
JSONWebToken
::
RSAToken
.
new
(
registry
.
key
)
token
.
issuer
=
registry
.
issuer
token
.
audience
=
AUDIENCE
token
[
:access
]
=
names
.
map
do
|
name
|
{
type:
'repository'
,
name:
name
,
actions:
%w(pull push)
}
end
token
.
encoded
end
private
private
def
authorized_token
(
*
accesses
)
def
authorized_token
(
*
accesses
)
...
...
app/services/projects/destroy_service.rb
View file @
a410c7af
...
@@ -26,6 +26,10 @@ module Projects
...
@@ -26,6 +26,10 @@ module Projects
Project
.
transaction
do
Project
.
transaction
do
project
.
destroy!
project
.
destroy!
unless
remove_registry_tags
raise_error
(
'Failed to remove project container registry. Please try again or contact administrator'
)
end
unless
remove_repository
(
repo_path
)
unless
remove_repository
(
repo_path
)
raise_error
(
'Failed to remove project repository. Please try again or contact administrator'
)
raise_error
(
'Failed to remove project repository. Please try again or contact administrator'
)
end
end
...
@@ -59,6 +63,12 @@ module Projects
...
@@ -59,6 +63,12 @@ module Projects
end
end
end
end
def
remove_registry_tags
return
true
unless
Gitlab
.
config
.
registry
.
enabled
project
.
container_registry_repository
.
delete_tags
end
def
raise_error
(
message
)
def
raise_error
(
message
)
raise
DestroyError
.
new
(
message
)
raise
DestroyError
.
new
(
message
)
end
end
...
...
app/services/projects/transfer_service.rb
View file @
a410c7af
...
@@ -34,6 +34,11 @@ module Projects
...
@@ -34,6 +34,11 @@ module Projects
raise
TransferError
.
new
(
"Project with same path in target namespace already exists"
)
raise
TransferError
.
new
(
"Project with same path in target namespace already exists"
)
end
end
if
project
.
has_container_registry_tags?
# we currently doesn't support renaming repository if it contains tags in container registry
raise
TransferError
.
new
(
'Project cannot be transferred, because tags are present in its container registry'
)
end
project
.
expire_caches_before_rename
(
old_path
)
project
.
expire_caches_before_rename
(
old_path
)
# Apply new namespace id and visibility level
# Apply new namespace id and visibility level
...
...
app/views/layouts/nav/_project.html.haml
View file @
a410c7af
...
@@ -46,6 +46,13 @@
...
@@ -46,6 +46,13 @@
Builds
Builds
%span
.count.builds_counter
=
number_with_delimiter
(
@project
.
builds
.
running_or_pending
.
count
(
:all
))
%span
.count.builds_counter
=
number_with_delimiter
(
@project
.
builds
.
running_or_pending
.
count
(
:all
))
-
if
project_nav_tab?
:container_registry
=
nav_link
(
controller:
%w(container_registry)
)
do
=
link_to
project_container_registry_path
(
@project
),
title:
'Container Registry'
,
class:
'shortcuts-container-registry'
do
=
icon
(
'hdd-o fw'
)
%span
Container Registry
-
if
project_nav_tab?
:graphs
-
if
project_nav_tab?
:graphs
=
nav_link
(
controller:
%w(graphs)
)
do
=
nav_link
(
controller:
%w(graphs)
)
do
=
link_to
namespace_project_graph_path
(
@project
.
namespace
,
@project
,
current_ref
),
title:
'Graphs'
,
class:
'shortcuts-graphs'
do
=
link_to
namespace_project_graph_path
(
@project
.
namespace
,
@project
,
current_ref
),
title:
'Graphs'
,
class:
'shortcuts-graphs'
do
...
...
app/views/projects/container_registry/_header_title.html.haml
0 → 100644
View file @
a410c7af
-
header_title
project_title
(
@project
,
"Container Registry"
,
project_container_registry_path
(
@project
))
app/views/projects/container_registry/_tag.html.haml
0 → 100644
View file @
a410c7af
%tr
.tag
%td
=
escape_once
(
tag
.
name
)
=
clipboard_button
(
clipboard_text:
"docker pull
#{
tag
.
path
}
"
)
%td
-
if
layer
=
tag
.
layers
.
first
%span
.has-tooltip
{
title:
"#{layer.revision}"
}
=
layer
.
short_revision
-
else
\-
%td
=
number_to_human_size
(
tag
.
total_size
)
·
=
pluralize
(
tag
.
layers
.
size
,
"layer"
)
%td
=
time_ago_in_words
(
tag
.
created_at
)
-
if
can?
(
current_user
,
:update_container_image
,
@project
)
%td
.content
.controls.hidden-xs.pull-right
=
link_to
namespace_project_container_registry_path
(
@project
.
namespace
,
@project
,
tag
.
name
),
class:
'btn btn-remove has-tooltip'
,
title:
"Remove"
,
data:
{
confirm:
"Are you sure?"
},
method: :delete
do
=
icon
(
"trash cred"
)
app/views/projects/container_registry/index.html.haml
0 → 100644
View file @
a410c7af
-
page_title
"Container Registry"
=
render
"header_title"
%hr
%ul
.content-list
.light.prepend-top-default
%p
A 'container image' is a snapshot of a container.
You can host your container images with GitLab.
%br
To start using container images hosted on GitLab you first need to login:
%pre
%code
docker login
#{
Gitlab
.
config
.
registry
.
host_port
}
%br
Then you are free to create and upload a container image with build and push commands:
%pre
docker build -t
#{
escape_once
(
@project
.
container_registry_repository_url
)
}
.
%br
docker push
#{
escape_once
(
@project
.
container_registry_repository_url
)
}
-
if
@tags
.
blank?
%li
.nothing-here-block
No images in Container Registry for this project.
-
else
.table-holder
%table
.table.tags
%thead
%tr
%th
Name
%th
Image ID
%th
Size
%th
Created
-
if
can?
(
current_user
,
:update_container_image
,
@project
)
%th
-
@tags
.
each
do
|
tag
|
=
render
'tag'
,
tag:
tag
\ No newline at end of file
config/gitlab.yml.example
View file @
a410c7af
...
@@ -183,6 +183,7 @@ production: &base
...
@@ -183,6 +183,7 @@ production: &base
# api_url: http://localhost:5000/
# api_url: http://localhost:5000/
# key: config/registry.key
# key: config/registry.key
# issuer: omnibus-certificate
# issuer: omnibus-certificate
# path: shared/registry
#
#
# 2. GitLab CI settings
# 2. GitLab CI settings
...
...
config/initializers/1_settings.rb
View file @
a410c7af
...
@@ -249,9 +249,12 @@ Settings.artifacts['max_size'] ||= 100 # in megabytes
...
@@ -249,9 +249,12 @@ Settings.artifacts['max_size'] ||= 100 # in megabytes
Settings
[
'registry'
]
||=
Settingslogic
.
new
({})
Settings
[
'registry'
]
||=
Settingslogic
.
new
({})
Settings
.
registry
[
'enabled'
]
||=
false
Settings
.
registry
[
'enabled'
]
||=
false
Settings
.
registry
[
'host'
]
||=
"example.com"
Settings
.
registry
[
'host'
]
||=
"example.com"
Settings
.
registry
[
'port'
]
||=
nil
Settings
.
registry
[
'api_url'
]
||=
"http://localhost:5000/"
Settings
.
registry
[
'api_url'
]
||=
"http://localhost:5000/"
Settings
.
registry
[
'key'
]
||=
nil
Settings
.
registry
[
'key'
]
||=
nil
Settings
.
registry
[
'issuer'
]
||=
nil
Settings
.
registry
[
'issuer'
]
||=
nil
Settings
.
registry
[
'host_port'
]
||=
[
Settings
.
registry
[
'host'
],
Settings
.
registry
[
'port'
]].
compact
.
join
(
':'
)
Settings
.
registry
[
'path'
]
=
File
.
expand_path
(
Settings
.
registry
[
'path'
]
||
File
.
join
(
Settings
.
shared
[
'path'
],
'registry'
),
Rails
.
root
)
#
#
# Git LFS
# Git LFS
...
...
config/routes.rb
View file @
a410c7af
...
@@ -694,6 +694,8 @@ Rails.application.routes.draw do
...
@@ -694,6 +694,8 @@ Rails.application.routes.draw do
end
end
end
end
resources
:container_registry
,
only:
[
:index
,
:destroy
],
constraints:
{
id:
Gitlab
::
Regex
.
container_registry_reference_regex
}
resources
:milestones
,
constraints:
{
id:
/\d+/
}
do
resources
:milestones
,
constraints:
{
id:
/\d+/
}
do
member
do
member
do
put
:sort_issues
put
:sort_issues
...
...
doc/permissions/permissions.md
View file @
a410c7af
...
@@ -39,6 +39,7 @@ documentation](../workflow/add-user/add-user.md).
...
@@ -39,6 +39,7 @@ documentation](../workflow/add-user/add-user.md).
| Cancel and retry builds | | | ✓ | ✓ | ✓ |
| Cancel and retry builds | | | ✓ | ✓ | ✓ |
| Create or update commit status | | | ✓ | ✓ | ✓ |
| Create or update commit status | | | ✓ | ✓ | ✓ |
| Update a container registry | | | ✓ | ✓ | ✓ |
| Update a container registry | | | ✓ | ✓ | ✓ |
| Remove a container registry image | | | ✓ | ✓ | ✓ |
| Create new milestones | | | | ✓ | ✓ |
| Create new milestones | | | | ✓ | ✓ |
| Add new team members | | | | ✓ | ✓ |
| Add new team members | | | | ✓ | ✓ |
| Push to protected branches | | | | ✓ | ✓ |
| Push to protected branches | | | | ✓ | ✓ |
...
...
lib/backup/manager.rb
View file @
a410c7af
...
@@ -157,7 +157,7 @@ module Backup
...
@@ -157,7 +157,7 @@ module Backup
end
end
def
archives_to_backup
def
archives_to_backup
%w{uploads builds artifacts lfs}
.
map
{
|
name
|
(
name
+
".tar.gz"
)
unless
skipped?
(
name
)
}.
compact
%w{uploads builds artifacts lfs
registry
}
.
map
{
|
name
|
(
name
+
".tar.gz"
)
unless
skipped?
(
name
)
}.
compact
end
end
def
folders_to_backup
def
folders_to_backup
...
...
lib/backup/registry.rb
0 → 100644
View file @
a410c7af
require
'backup/files'
module
Backup
class
Registry
<
Files
def
initialize
super
(
'registry'
,
Settings
.
registry
.
path
)
end
def
create_files_dir
Dir
.
mkdir
(
app_files_dir
,
0700
)
end
end
end
lib/container_registry/blob.rb
0 → 100644
View file @
a410c7af
module
ContainerRegistry
class
Blob
attr_reader
:repository
,
:config
delegate
:registry
,
:client
,
to: :repository
def
initialize
(
repository
,
config
)
@repository
=
repository
@config
=
config
||
{}
end
def
valid?
digest
.
present?
end
def
path
"
#{
repository
.
path
}
@
#{
digest
}
"
end
def
digest
config
[
'digest'
]
end
def
type
config
[
'mediaType'
]
end
def
size
config
[
'size'
]
end
def
revision
digest
.
split
(
':'
)[
1
]
end
def
short_revision
revision
[
0
..
8
]
end
def
delete
client
.
delete_blob
(
repository
.
name
,
digest
)
end
def
data
@data
||=
client
.
blob
(
repository
.
name
,
digest
,
type
)
end
end
end
lib/container_registry/client.rb
0 → 100644
View file @
a410c7af
require
'faraday'
require
'faraday_middleware'
module
ContainerRegistry
class
Client
attr_accessor
:uri
MANIFEST_VERSION
=
'application/vnd.docker.distribution.manifest.v2+json'
def
initialize
(
base_uri
,
options
=
{})
@base_uri
=
base_uri
@faraday
=
Faraday
.
new
(
@base_uri
)
do
|
conn
|
initialize_connection
(
conn
,
options
)
end
end
def
repository_tags
(
name
)
@faraday
.
get
(
"/v2/
#{
name
}
/tags/list"
).
body
end
def
repository_manifest
(
name
,
reference
)
@faraday
.
get
(
"/v2/
#{
name
}
/manifests/
#{
reference
}
"
).
body
end
def
repository_tag_digest
(
name
,
reference
)
response
=
@faraday
.
head
(
"/v2/
#{
name
}
/manifests/
#{
reference
}
"
)
response
.
headers
[
'docker-content-digest'
]
if
response
.
success?
end
def
delete_repository_tag
(
name
,
reference
)
@faraday
.
delete
(
"/v2/
#{
name
}
/manifests/
#{
reference
}
"
).
success?
end
def
blob
(
name
,
digest
,
type
=
nil
)
headers
=
{}
headers
[
'Accept'
]
=
type
if
type
@faraday
.
get
(
"/v2/
#{
name
}
/blobs/
#{
digest
}
"
,
nil
,
headers
).
body
end
def
delete_blob
(
name
,
digest
)
@faraday
.
delete
(
"/v2/
#{
name
}
/blobs/
#{
digest
}
"
).
success?
end
private
def
initialize_connection
(
conn
,
options
)
conn
.
request
:json
conn
.
headers
[
'Accept'
]
=
MANIFEST_VERSION
conn
.
response
:json
,
content_type:
/\bjson$/
if
options
[
:user
]
&&
options
[
:password
]
conn
.
request
(
:basic_auth
,
options
[
:user
].
to_s
,
options
[
:password
].
to_s
)
elsif
options
[
:token
]
conn
.
request
(
:authorization
,
:bearer
,
options
[
:token
].
to_s
)
end
conn
.
adapter
:net_http
end
end
end
lib/container_registry/config.rb
0 → 100644
View file @
a410c7af
module
ContainerRegistry
class
Config
attr_reader
:tag
,
:blob
,
:data
def
initialize
(
tag
,
blob
)
@tag
,
@blob
=
tag
,
blob
@data
=
JSON
.
parse
(
blob
.
data
)
end
def
[]
(
key
)
return
unless
data
data
[
key
]
end
end
end
lib/container_registry/registry.rb
0 → 100644
View file @
a410c7af
module
ContainerRegistry
class
Registry
attr_reader
:uri
,
:client
,
:path
def
initialize
(
uri
,
options
=
{})
@uri
=
uri
@path
=
options
[
:path
]
||
default_path
@client
=
ContainerRegistry
::
Client
.
new
(
uri
,
options
)
end
def
repository
(
name
)
ContainerRegistry
::
Repository
.
new
(
self
,
name
)
end
private
def
default_path
@uri
.
sub
(
/^https?:\/\//
,
''
)
end
end
end
lib/container_registry/repository.rb
0 → 100644
View file @
a410c7af
module
ContainerRegistry
class
Repository
attr_reader
:registry
,
:name
delegate
:client
,
to: :registry
def
initialize
(
registry
,
name
)
@registry
,
@name
=
registry
,
name
end
def
path
[
registry
.
path
,
name
].
compact
.
join
(
'/'
)
end
def
tag
(
tag
)
ContainerRegistry
::
Tag
.
new
(
self
,
tag
)
end
def
manifest
return
@manifest
if
defined?
(
@manifest
)
@manifest
=
client
.
repository_tags
(
name
)
end
def
valid?
manifest
.
present?
end
def
tags
return
@tags
if
defined?
(
@tags
)
return
[]
unless
manifest
&&
manifest
[
'tags'
]
@tags
=
manifest
[
'tags'
].
map
do
|
tag
|
ContainerRegistry
::
Tag
.
new
(
self
,
tag
)
end
end
def
blob
(
config
)
ContainerRegistry
::
Blob
.
new
(
self
,
config
)
end
def
delete_tags
return
unless
tags
tags
.
all?
(
&
:delete
)
end
end
end
lib/container_registry/tag.rb
0 → 100644
View file @
a410c7af
module
ContainerRegistry
class
Tag
attr_reader
:repository
,
:name
delegate
:registry
,
:client
,
to: :repository
def
initialize
(
repository
,
name
)
@repository
,
@name
=
repository
,
name
end
def
valid?
manifest
.
present?
end
def
manifest
return
@manifest
if
defined?
(
@manifest
)
@manifest
=
client
.
repository_manifest
(
repository
.
name
,
name
)
end
def
path
"
#{
repository
.
path
}
:
#{
name
}
"
end
def
[]
(
key
)
return
unless
manifest
manifest
[
key
]
end
def
digest
return
@digest
if
defined?
(
@digest
)
@digest
=
client
.
repository_tag_digest
(
repository
.
name
,
name
)
end
def
config_blob
return
@config_blob
if
defined?
(
@config_blob
)
return
unless
manifest
&&
manifest
[
'config'
]
@config_blob
=
repository
.
blob
(
manifest
[
'config'
])
end
def
config
return
unless
config_blob
@config
||=
ContainerRegistry
::
Config
.
new
(
self
,
config_blob
)
end
def
created_at
return
unless
config
@created_at
||=
DateTime
.
rfc3339
(
config
[
'created'
])
end
def
layers
return
@layers
if
defined?
(
@layers
)
return
unless
manifest
@layers
=
manifest
[
'layers'
].
map
do
|
layer
|
repository
.
blob
(
layer
)
end
end
def
total_size
return
unless
layers
layers
.
map
(
&
:size
).
sum
end
def
delete
return
unless
digest
client
.
delete_repository_tag
(
repository
.
name
,
digest
)
end
end
end
lib/gitlab/regex.rb
View file @
a410c7af
...
@@ -96,5 +96,9 @@ module Gitlab
...
@@ -96,5 +96,9 @@ module Gitlab
(?<![
\/
.]) (?# rule #6-7)
(?<![
\/
.]) (?# rule #6-7)
}x
.
freeze
}x
.
freeze
end
end
def
container_registry_reference_regex
git_reference_regex
end
end
end
end
end
lib/tasks/gitlab/backup.rake
View file @
a410c7af
...
@@ -14,6 +14,7 @@ namespace :gitlab do
...
@@ -14,6 +14,7 @@ namespace :gitlab do
Rake
::
Task
[
"gitlab:backup:builds:create"
].
invoke
Rake
::
Task
[
"gitlab:backup:builds:create"
].
invoke
Rake
::
Task
[
"gitlab:backup:artifacts:create"
].
invoke
Rake
::
Task
[
"gitlab:backup:artifacts:create"
].
invoke
Rake
::
Task
[
"gitlab:backup:lfs:create"
].
invoke
Rake
::
Task
[
"gitlab:backup:lfs:create"
].
invoke
Rake
::
Task
[
"gitlab:backup:registry:create"
].
invoke
backup
=
Backup
::
Manager
.
new
backup
=
Backup
::
Manager
.
new
backup
.
pack
backup
.
pack
...
@@ -54,6 +55,7 @@ namespace :gitlab do
...
@@ -54,6 +55,7 @@ namespace :gitlab do
Rake
::
Task
[
'gitlab:backup:builds:restore'
].
invoke
unless
backup
.
skipped?
(
'builds'
)
Rake
::
Task
[
'gitlab:backup:builds:restore'
].
invoke
unless
backup
.
skipped?
(
'builds'
)
Rake
::
Task
[
'gitlab:backup:artifacts:restore'
].
invoke
unless
backup
.
skipped?
(
'artifacts'
)
Rake
::
Task
[
'gitlab:backup:artifacts:restore'
].
invoke
unless
backup
.
skipped?
(
'artifacts'
)
Rake
::
Task
[
'gitlab:backup:lfs:restore'
].
invoke
unless
backup
.
skipped?
(
'lfs'
)
Rake
::
Task
[
'gitlab:backup:lfs:restore'
].
invoke
unless
backup
.
skipped?
(
'lfs'
)
Rake
::
Task
[
'gitlab:backup:registry:restore'
].
invoke
unless
backup
.
skipped?
(
'registry'
)
Rake
::
Task
[
'gitlab:shell:setup'
].
invoke
Rake
::
Task
[
'gitlab:shell:setup'
].
invoke
backup
.
cleanup
backup
.
cleanup
...
@@ -173,6 +175,25 @@ namespace :gitlab do
...
@@ -173,6 +175,25 @@ namespace :gitlab do
end
end
end
end
namespace
:registry
do
task
create: :environment
do
$progress
.
puts
"Dumping container registry images ... "
.
blue
if
ENV
[
"SKIP"
]
&&
ENV
[
"SKIP"
].
include?
(
"registry"
)
$progress
.
puts
"[SKIPPED]"
.
cyan
else
Backup
::
Registry
.
new
.
dump
$progress
.
puts
"done"
.
green
end
end
task
restore: :environment
do
$progress
.
puts
"Restoring container registry images ... "
.
blue
Backup
::
Registry
.
new
.
restore
$progress
.
puts
"done"
.
green
end
end
def
configure_cron_mode
def
configure_cron_mode
if
ENV
[
'CRON'
]
if
ENV
[
'CRON'
]
# We need an object we can say 'puts' and 'print' to; let's use a
# We need an object we can say 'puts' and 'print' to; let's use a
...
...
shared/registry/.gitkeep
0 → 100644
View file @
a410c7af
spec/features/container_registry_spec.rb
0 → 100644
View file @
a410c7af
require
'spec_helper'
describe
"Container Registry"
do
let
(
:project
)
{
create
(
:empty_project
)
}
let
(
:repository
)
{
project
.
container_registry_repository
}
let
(
:tag_name
)
{
'latest'
}
let
(
:tags
)
{
[
tag_name
]
}
before
do
login_as
(
:user
)
project
.
team
<<
[
@user
,
:developer
]
stub_container_registry_tags
(
*
tags
)
stub_container_registry_config
(
enabled:
true
)
allow
(
Auth
::
ContainerRegistryAuthenticationService
).
to
receive
(
:full_access_token
).
and_return
(
'token'
)
end
describe
'GET /:project/container_registry'
do
before
do
visit
namespace_project_container_registry_index_path
(
project
.
namespace
,
project
)
end
context
'when no tags'
do
let
(
:tags
)
{
[]
}
it
{
expect
(
page
).
to
have_content
(
'No images in Container Registry for this project'
)
}
end
context
'when there are tags'
do
it
{
expect
(
page
).
to
have_content
(
tag_name
)}
end
end
describe
'DELETE /:project/container_registry/tag'
do
before
do
visit
namespace_project_container_registry_index_path
(
project
.
namespace
,
project
)
end
it
do
expect_any_instance_of
(
::
ContainerRegistry
::
Tag
).
to
receive
(
:delete
).
and_return
(
true
)
click_on
'Remove'
end
end
end
spec/fixtures/container_registry/config_blob.json
0 → 100644
View file @
a410c7af
{
"architecture"
:
"amd64"
,
"config"
:{
"Hostname"
:
"b14cd8298755"
,
"Domainname"
:
""
,
"User"
:
""
,
"AttachStdin"
:
false
,
"AttachStdout"
:
false
,
"AttachStderr"
:
false
,
"Tty"
:
false
,
"OpenStdin"
:
false
,
"StdinOnce"
:
false
,
"Env"
:
null
,
"Cmd"
:
null
,
"Image"
:
""
,
"Volumes"
:
null
,
"WorkingDir"
:
""
,
"Entrypoint"
:
null
,
"OnBuild"
:
null
,
"Labels"
:
null
},
"container"
:
"b14cd82987550b01af9a666a2f4c996280a6152e66873134fae5a0f223dc5976"
,
"container_config"
:{
"Hostname"
:
"b14cd8298755"
,
"Domainname"
:
""
,
"User"
:
""
,
"AttachStdin"
:
false
,
"AttachStdout"
:
false
,
"AttachStderr"
:
false
,
"Tty"
:
false
,
"OpenStdin"
:
false
,
"StdinOnce"
:
false
,
"Env"
:
null
,
"Cmd"
:[
"/bin/sh"
,
"-c"
,
"#(nop) ADD file:033ab063740d9ff4dcfb1c69eccf25f91d88729f57cd5a73050e014e3e094aa0 in /"
],
"Image"
:
""
,
"Volumes"
:
null
,
"WorkingDir"
:
""
,
"Entrypoint"
:
null
,
"OnBuild"
:
null
,
"Labels"
:
null
},
"created"
:
"2016-04-01T20:53:00.160300546Z"
,
"docker_version"
:
"1.9.1"
,
"history"
:[{
"created"
:
"2016-04-01T20:53:00.160300546Z"
,
"created_by"
:
"/bin/sh -c #(nop) ADD file:033ab063740d9ff4dcfb1c69eccf25f91d88729f57cd5a73050e014e3e094aa0 in /"
}],
"os"
:
"linux"
,
"rootfs"
:{
"type"
:
"layers"
,
"diff_ids"
:[
"sha256:c56b7dabbc7aa730eeab07668bdcbd7e3d40855047ca9a0cc1bfed23a2486111"
]}}
spec/fixtures/container_registry/tag_manifest.json
0 → 100644
View file @
a410c7af
{
"schemaVersion"
:
2
,
"mediaType"
:
"application/vnd.docker.distribution.manifest.v2+json"
,
"config"
:{
"mediaType"
:
"application/octet-stream"
,
"size"
:
1145
,
"digest"
:
"sha256:d7a513a663c1a6dcdba9ed832ca53c02ac2af0c333322cd6ca92936d1d9917ac"
},
"layers"
:[{
"mediaType"
:
"application/vnd.docker.image.rootfs.diff.tar.gzip"
,
"size"
:
2319870
,
"digest"
:
"sha256:420890c9e918b6668faaedd9000e220190f2493b0693ee563ebd7b4cc754a57d"
}]}
spec/lib/container_registry/blob_spec.rb
0 → 100644
View file @
a410c7af
require
'spec_helper'
describe
ContainerRegistry
::
Blob
do
let
(
:digest
)
{
'sha256:0123456789012345'
}
let
(
:config
)
do
{
'digest'
=>
digest
,
'mediaType'
=>
'binary'
,
'size'
=>
1000
}
end
let
(
:registry
)
{
ContainerRegistry
::
Registry
.
new
(
'http://example.com'
)
}
let
(
:repository
)
{
registry
.
repository
(
'group/test'
)
}
let
(
:blob
)
{
repository
.
blob
(
config
)
}
it
{
expect
(
blob
).
to
respond_to
(
:repository
)
}
it
{
expect
(
blob
).
to
delegate_method
(
:registry
).
to
(
:repository
)
}
it
{
expect
(
blob
).
to
delegate_method
(
:client
).
to
(
:repository
)
}
context
'#path'
do
subject
{
blob
.
path
}
it
{
is_expected
.
to
eq
(
'example.com/group/test@sha256:0123456789012345'
)
}
end
context
'#digest'
do
subject
{
blob
.
digest
}
it
{
is_expected
.
to
eq
(
digest
)
}
end
context
'#type'
do
subject
{
blob
.
type
}
it
{
is_expected
.
to
eq
(
'binary'
)
}
end
context
'#revision'
do
subject
{
blob
.
revision
}
it
{
is_expected
.
to
eq
(
'0123456789012345'
)
}
end
context
'#short_revision'
do
subject
{
blob
.
short_revision
}
it
{
is_expected
.
to
eq
(
'012345678'
)
}
end
context
'#delete'
do
before
do
stub_request
(
:delete
,
'http://example.com/v2/group/test/blobs/sha256:0123456789012345'
).
to_return
(
status:
200
)
end
subject
{
blob
.
delete
}
it
{
is_expected
.
to
be_truthy
}
end
end
spec/lib/container_registry/registry_spec.rb
0 → 100644
View file @
a410c7af
require
'spec_helper'
describe
ContainerRegistry
::
Registry
do
let
(
:path
)
{
nil
}
let
(
:registry
)
{
described_class
.
new
(
'http://example.com'
,
path:
path
)
}
subject
{
registry
}
it
{
is_expected
.
to
respond_to
(
:client
)
}
it
{
is_expected
.
to
respond_to
(
:uri
)
}
it
{
is_expected
.
to
respond_to
(
:path
)
}
it
{
expect
(
subject
.
repository
(
'test'
)).
to_not
be_nil
}
context
'#path'
do
subject
{
registry
.
path
}
context
'path from URL'
do
it
{
is_expected
.
to
eq
(
'example.com'
)
}
end
context
'custom path'
do
let
(
:path
)
{
'registry.example.com'
}
it
{
is_expected
.
to
eq
(
path
)
}
end
end
end
spec/lib/container_registry/repository_spec.rb
0 → 100644
View file @
a410c7af
require
'spec_helper'
describe
ContainerRegistry
::
Repository
do
let
(
:registry
)
{
ContainerRegistry
::
Registry
.
new
(
'http://example.com'
)
}
let
(
:repository
)
{
registry
.
repository
(
'group/test'
)
}
it
{
expect
(
repository
).
to
respond_to
(
:registry
)
}
it
{
expect
(
repository
).
to
delegate_method
(
:client
).
to
(
:registry
)
}
it
{
expect
(
repository
.
tag
(
'test'
)).
to_not
be_nil
}
context
'#path'
do
subject
{
repository
.
path
}
it
{
is_expected
.
to
eq
(
'example.com/group/test'
)
}
end
context
'manifest processing'
do
before
do
stub_request
(
:get
,
'http://example.com/v2/group/test/tags/list'
).
with
(
headers:
{
'Accept'
=>
'application/vnd.docker.distribution.manifest.v2+json'
}).
to_return
(
status:
200
,
body:
JSON
.
dump
(
tags:
[
'test'
]),
headers:
{
'Content-Type'
=>
'application/vnd.docker.distribution.manifest.v2+json'
})
end
context
'#manifest'
do
subject
{
repository
.
manifest
}
it
{
is_expected
.
to_not
be_nil
}
end
context
'#valid?'
do
subject
{
repository
.
valid?
}
it
{
is_expected
.
to
be_truthy
}
end
context
'#tags'
do
subject
{
repository
.
tags
}
it
{
is_expected
.
to_not
be_empty
}
end
end
context
'#delete_tags'
do
let
(
:tag
)
{
ContainerRegistry
::
Tag
.
new
(
repository
,
'tag'
)
}
before
{
expect
(
repository
).
to
receive
(
:tags
).
twice
.
and_return
([
tag
])
}
subject
{
repository
.
delete_tags
}
context
'succeeds'
do
before
{
expect
(
tag
).
to
receive
(
:delete
).
and_return
(
true
)
}
it
{
is_expected
.
to
be_truthy
}
end
context
'any fails'
do
before
{
expect
(
tag
).
to
receive
(
:delete
).
and_return
(
false
)
}
it
{
is_expected
.
to
be_falsey
}
end
end
end
spec/lib/container_registry/tag_spec.rb
0 → 100644
View file @
a410c7af
require
'spec_helper'
describe
ContainerRegistry
::
Tag
do
let
(
:registry
)
{
ContainerRegistry
::
Registry
.
new
(
'http://example.com'
)
}
let
(
:repository
)
{
registry
.
repository
(
'group/test'
)
}
let
(
:tag
)
{
repository
.
tag
(
'tag'
)
}
let
(
:headers
)
{
{
'Accept'
=>
'application/vnd.docker.distribution.manifest.v2+json'
}
}
it
{
expect
(
tag
).
to
respond_to
(
:repository
)
}
it
{
expect
(
tag
).
to
delegate_method
(
:registry
).
to
(
:repository
)
}
it
{
expect
(
tag
).
to
delegate_method
(
:client
).
to
(
:repository
)
}
context
'#path'
do
subject
{
tag
.
path
}
it
{
is_expected
.
to
eq
(
'example.com/group/test:tag'
)
}
end
context
'manifest processing'
do
before
do
stub_request
(
:get
,
'http://example.com/v2/group/test/manifests/tag'
).
with
(
headers:
headers
).
to_return
(
status:
200
,
body:
File
.
read
(
Rails
.
root
+
'spec/fixtures/container_registry/tag_manifest.json'
),
headers:
{
'Content-Type'
=>
'application/vnd.docker.distribution.manifest.v2+json'
})
end
context
'#layers'
do
subject
{
tag
.
layers
}
it
{
expect
(
subject
.
length
).
to
eq
(
1
)
}
end
context
'#total_size'
do
subject
{
tag
.
total_size
}
it
{
is_expected
.
to
eq
(
2319870
)
}
end
context
'config processing'
do
before
do
stub_request
(
:get
,
'http://example.com/v2/group/test/blobs/sha256:d7a513a663c1a6dcdba9ed832ca53c02ac2af0c333322cd6ca92936d1d9917ac'
).
with
(
headers:
{
'Accept'
=>
'application/octet-stream'
}).
to_return
(
status:
200
,
body:
File
.
read
(
Rails
.
root
+
'spec/fixtures/container_registry/config_blob.json'
))
end
context
'#config'
do
subject
{
tag
.
config
}
it
{
is_expected
.
to_not
be_nil
}
end
context
'#created_at'
do
subject
{
tag
.
created_at
}
it
{
is_expected
.
to_not
be_nil
}
end
end
end
context
'manifest digest'
do
before
do
stub_request
(
:head
,
'http://example.com/v2/group/test/manifests/tag'
).
with
(
headers:
headers
).
to_return
(
status:
200
,
headers:
{
'Docker-Content-Digest'
=>
'sha256:digest'
})
end
context
'#digest'
do
subject
{
tag
.
digest
}
it
{
is_expected
.
to
eq
(
'sha256:digest'
)
}
end
context
'#delete'
do
before
do
stub_request
(
:delete
,
'http://example.com/v2/group/test/manifests/sha256:digest'
).
with
(
headers:
headers
).
to_return
(
status:
200
)
end
subject
{
tag
.
delete
}
it
{
is_expected
.
to
be_truthy
}
end
end
end
spec/models/namespace_spec.rb
View file @
a410c7af
...
@@ -70,6 +70,20 @@ describe Namespace, models: true do
...
@@ -70,6 +70,20 @@ describe Namespace, models: true do
allow
(
@namespace
).
to
receive
(
:path
).
and_return
(
new_path
)
allow
(
@namespace
).
to
receive
(
:path
).
and_return
(
new_path
)
expect
(
@namespace
.
move_dir
).
to
be_truthy
expect
(
@namespace
.
move_dir
).
to
be_truthy
end
end
context
"when any project has container tags"
do
before
do
stub_container_registry_config
(
enabled:
true
)
stub_container_registry_tags
(
'tag'
)
create
(
:empty_project
,
namespace:
@namespace
)
allow
(
@namespace
).
to
receive
(
:path_was
).
and_return
(
@namespace
.
path
)
allow
(
@namespace
).
to
receive
(
:path
).
and_return
(
'new_path'
)
end
it
{
expect
{
@namespace
.
move_dir
}.
to
raise_error
(
'Namespace cannot be moved, because at least one project has tags in container registry'
)
}
end
end
end
describe
:rm_dir
do
describe
:rm_dir
do
...
...
spec/models/project_spec.rb
View file @
a410c7af
...
@@ -634,11 +634,11 @@ describe Project, models: true do
...
@@ -634,11 +634,11 @@ describe Project, models: true do
# Project#gitlab_shell returns a new instance of Gitlab::Shell on every
# Project#gitlab_shell returns a new instance of Gitlab::Shell on every
# call. This makes testing a bit easier.
# call. This makes testing a bit easier.
allow
(
project
).
to
receive
(
:gitlab_shell
).
and_return
(
gitlab_shell
)
allow
(
project
).
to
receive
(
:gitlab_shell
).
and_return
(
gitlab_shell
)
end
it
'renames a repository'
do
allow
(
project
).
to
receive
(
:previous_changes
).
and_return
(
'path'
=>
[
'foo'
])
allow
(
project
).
to
receive
(
:previous_changes
).
and_return
(
'path'
=>
[
'foo'
])
end
it
'renames a repository'
do
ns
=
project
.
namespace_dir
ns
=
project
.
namespace_dir
expect
(
gitlab_shell
).
to
receive
(
:mv_repository
).
expect
(
gitlab_shell
).
to
receive
(
:mv_repository
).
...
@@ -663,6 +663,17 @@ describe Project, models: true do
...
@@ -663,6 +663,17 @@ describe Project, models: true do
project
.
rename_repo
project
.
rename_repo
end
end
context
'container registry with tags'
do
before
do
stub_container_registry_config
(
enabled:
true
)
stub_container_registry_tags
(
'tag'
)
end
subject
{
project
.
rename_repo
}
it
{
expect
{
subject
}.
to
raise_error
(
Exception
)
}
end
end
end
describe
'#expire_caches_before_rename'
do
describe
'#expire_caches_before_rename'
do
...
@@ -772,4 +783,71 @@ describe Project, models: true do
...
@@ -772,4 +783,71 @@ describe Project, models: true do
expect
(
project
.
protected_branch?
(
'foo'
)).
to
eq
(
false
)
expect
(
project
.
protected_branch?
(
'foo'
)).
to
eq
(
false
)
end
end
end
end
describe
'#container_registry_repository'
do
let
(
:project
)
{
create
(
:empty_project
)
}
before
{
stub_container_registry_config
(
enabled:
true
)
}
subject
{
project
.
container_registry_repository
}
it
{
is_expected
.
to_not
be_nil
}
end
describe
'#container_registry_repository_url'
do
let
(
:project
)
{
create
(
:empty_project
)
}
subject
{
project
.
container_registry_repository_url
}
before
{
stub_container_registry_config
(
**
registry_settings
)
}
context
'for enabled registry'
do
let
(
:registry_settings
)
do
{
enabled:
true
,
host_port:
'example.com'
,
}
end
it
{
is_expected
.
to_not
be_nil
}
end
context
'for disabled registry'
do
let
(
:registry_settings
)
do
{
enabled:
false
}
end
it
{
is_expected
.
to
be_nil
}
end
end
describe
'#has_container_registry_tags?'
do
let
(
:project
)
{
create
(
:empty_project
)
}
subject
{
project
.
has_container_registry_tags?
}
context
'for enabled registry'
do
before
{
stub_container_registry_config
(
enabled:
true
)
}
context
'with tags'
do
before
{
stub_container_registry_tags
(
'test'
,
'test2'
)
}
it
{
is_expected
.
to
be_truthy
}
end
context
'when no tags'
do
before
{
stub_container_registry_tags
}
it
{
is_expected
.
to
be_falsey
}
end
end
context
'for disabled registry'
do
before
{
stub_container_registry_config
(
enabled:
false
)
}
it
{
is_expected
.
to
be_falsey
}
end
end
end
end
spec/services/auth/container_registry_authentication_service_spec.rb
View file @
a410c7af
...
@@ -5,19 +5,12 @@ describe Auth::ContainerRegistryAuthenticationService, services: true do
...
@@ -5,19 +5,12 @@ describe Auth::ContainerRegistryAuthenticationService, services: true do
let
(
:current_user
)
{
nil
}
let
(
:current_user
)
{
nil
}
let
(
:current_params
)
{
{}
}
let
(
:current_params
)
{
{}
}
let
(
:rsa_key
)
{
OpenSSL
::
PKey
::
RSA
.
generate
(
512
)
}
let
(
:rsa_key
)
{
OpenSSL
::
PKey
::
RSA
.
generate
(
512
)
}
let
(
:registry_settings
)
do
{
enabled:
true
,
issuer:
'rspec'
,
key:
nil
}
end
let
(
:payload
)
{
JWT
.
decode
(
subject
[
:token
],
rsa_key
).
first
}
let
(
:payload
)
{
JWT
.
decode
(
subject
[
:token
],
rsa_key
).
first
}
subject
{
described_class
.
new
(
current_project
,
current_user
,
current_params
).
execute
}
subject
{
described_class
.
new
(
current_project
,
current_user
,
current_params
).
execute
}
before
do
before
do
allow
(
Gitlab
.
config
.
registry
).
to
receive_messages
(
registry_settings
)
stub_container_registry_config
(
enabled:
true
,
issuer:
'rspec'
,
key:
nil
)
allow_any_instance_of
(
JSONWebToken
::
RSAToken
).
to
receive
(
:key
).
and_return
(
rsa_key
)
allow_any_instance_of
(
JSONWebToken
::
RSAToken
).
to
receive
(
:key
).
and_return
(
rsa_key
)
end
end
...
@@ -57,6 +50,11 @@ describe Auth::ContainerRegistryAuthenticationService, services: true do
...
@@ -57,6 +50,11 @@ describe Auth::ContainerRegistryAuthenticationService, services: true do
end
end
end
end
shared_examples
'an unauthorized'
do
it
{
is_expected
.
to
include
(
http_status:
401
)
}
it
{
is_expected
.
to_not
include
(
:token
)
}
end
shared_examples
'a forbidden'
do
shared_examples
'a forbidden'
do
it
{
is_expected
.
to
include
(
http_status:
403
)
}
it
{
is_expected
.
to
include
(
http_status:
403
)
}
it
{
is_expected
.
to_not
include
(
:token
)
}
it
{
is_expected
.
to_not
include
(
:token
)
}
...
@@ -123,7 +121,7 @@ describe Auth::ContainerRegistryAuthenticationService, services: true do
...
@@ -123,7 +121,7 @@ describe Auth::ContainerRegistryAuthenticationService, services: true do
{
offline_token:
true
}
{
offline_token:
true
}
end
end
it_behaves_like
'a
forbidden
'
it_behaves_like
'a
n unauthorized
'
end
end
context
'allow to pull and push images'
do
context
'allow to pull and push images'
do
...
@@ -164,6 +162,20 @@ describe Auth::ContainerRegistryAuthenticationService, services: true do
...
@@ -164,6 +162,20 @@ describe Auth::ContainerRegistryAuthenticationService, services: true do
end
end
end
end
end
end
context
'for project without container registry'
do
let
(
:project
)
{
create
(
:empty_project
,
:public
,
container_registry_enabled:
false
)
}
before
{
project
.
update
(
container_registry_enabled:
false
)
}
context
'disallow when pulling'
do
let
(
:current_params
)
do
{
scope:
"repository:
#{
project
.
path_with_namespace
}
:pull"
}
end
it_behaves_like
'a forbidden'
end
end
end
end
context
'unauthorized'
do
context
'unauthorized'
do
...
@@ -172,7 +184,7 @@ describe Auth::ContainerRegistryAuthenticationService, services: true do
...
@@ -172,7 +184,7 @@ describe Auth::ContainerRegistryAuthenticationService, services: true do
{
offline_token:
true
}
{
offline_token:
true
}
end
end
it_behaves_like
'a
forbidden
'
it_behaves_like
'a
n unauthorized
'
end
end
context
'for invalid scope'
do
context
'for invalid scope'
do
...
...
spec/services/projects/destroy_service_spec.rb
View file @
a410c7af
...
@@ -28,6 +28,29 @@ describe Projects::DestroyService, services: true do
...
@@ -28,6 +28,29 @@ describe Projects::DestroyService, services: true do
it
{
expect
(
Dir
.
exist?
(
remove_path
)).
to
be_truthy
}
it
{
expect
(
Dir
.
exist?
(
remove_path
)).
to
be_truthy
}
end
end
context
'container registry'
do
before
do
stub_container_registry_config
(
enabled:
true
)
stub_container_registry_tags
(
'tag'
)
end
context
'tags deletion succeeds'
do
it
do
expect_any_instance_of
(
ContainerRegistry
::
Tag
).
to
receive
(
:delete
).
and_return
(
true
)
destroy_project
(
project
,
user
,
{})
end
end
context
'tags deletion fails'
do
before
{
expect_any_instance_of
(
ContainerRegistry
::
Tag
).
to
receive
(
:delete
).
and_return
(
false
)
}
subject
{
destroy_project
(
project
,
user
,
{})
}
it
{
expect
{
subject
}.
to
raise_error
(
Projects
::
DestroyService
::
DestroyError
)
}
end
end
def
destroy_project
(
project
,
user
,
params
)
def
destroy_project
(
project
,
user
,
params
)
Projects
::
DestroyService
.
new
(
project
,
user
,
params
).
execute
Projects
::
DestroyService
.
new
(
project
,
user
,
params
).
execute
end
end
...
...
spec/services/projects/transfer_service_spec.rb
View file @
a410c7af
...
@@ -26,6 +26,17 @@ describe Projects::TransferService, services: true do
...
@@ -26,6 +26,17 @@ describe Projects::TransferService, services: true do
it
{
expect
(
project
.
namespace
).
to
eq
(
user
.
namespace
)
}
it
{
expect
(
project
.
namespace
).
to
eq
(
user
.
namespace
)
}
end
end
context
'disallow transfering of project with tags'
do
before
do
stub_container_registry_config
(
enabled:
true
)
stub_container_registry_tags
(
'tag'
)
end
subject
{
transfer_project
(
project
,
user
,
group
)
}
it
{
is_expected
.
to
be_falsey
}
end
context
'namespace -> not allowed namespace'
do
context
'namespace -> not allowed namespace'
do
before
do
before
do
@result
=
transfer_project
(
project
,
user
,
group
)
@result
=
transfer_project
(
project
,
user
,
group
)
...
...
spec/support/stub_gitlab_calls.rb
View file @
a410c7af
...
@@ -25,6 +25,23 @@ module StubGitlabCalls
...
@@ -25,6 +25,23 @@ module StubGitlabCalls
allow_any_instance_of
(
Project
).
to
receive
(
:builds_enabled?
).
and_return
(
false
)
allow_any_instance_of
(
Project
).
to
receive
(
:builds_enabled?
).
and_return
(
false
)
end
end
def
stub_container_registry_config
(
registry_settings
)
allow
(
Gitlab
.
config
.
registry
).
to
receive_messages
(
registry_settings
)
allow
(
Auth
::
ContainerRegistryAuthenticationService
).
to
receive
(
:full_access_token
).
and_return
(
'token'
)
end
def
stub_container_registry_tags
(
*
tags
)
allow_any_instance_of
(
ContainerRegistry
::
Client
).
to
receive
(
:repository_tags
).
and_return
(
{
"tags"
=>
tags
}
)
allow_any_instance_of
(
ContainerRegistry
::
Client
).
to
receive
(
:repository_manifest
).
and_return
(
JSON
.
load
(
File
.
read
(
Rails
.
root
+
'spec/fixtures/container_registry/tag_manifest.json'
))
)
allow_any_instance_of
(
ContainerRegistry
::
Client
).
to
receive
(
:blob
).
and_return
(
File
.
read
(
Rails
.
root
+
'spec/fixtures/container_registry/config_blob.json'
)
)
end
private
private
def
gitlab_url
def
gitlab_url
...
...
spec/tasks/gitlab/backup_rake_spec.rb
View file @
a410c7af
...
@@ -21,7 +21,7 @@ describe 'gitlab:app namespace rake task' do
...
@@ -21,7 +21,7 @@ describe 'gitlab:app namespace rake task' do
end
end
def
reenable_backup_sub_tasks
def
reenable_backup_sub_tasks
%w{db repo uploads builds artifacts lfs}
.
each
do
|
subtask
|
%w{db repo uploads builds artifacts lfs
registry
}
.
each
do
|
subtask
|
Rake
::
Task
[
"gitlab:backup:
#{
subtask
}
:create"
].
reenable
Rake
::
Task
[
"gitlab:backup:
#{
subtask
}
:create"
].
reenable
end
end
end
end
...
@@ -65,6 +65,7 @@ describe 'gitlab:app namespace rake task' do
...
@@ -65,6 +65,7 @@ describe 'gitlab:app namespace rake task' do
expect
(
Rake
::
Task
[
'gitlab:backup:uploads:restore'
]).
to
receive
(
:invoke
)
expect
(
Rake
::
Task
[
'gitlab:backup:uploads:restore'
]).
to
receive
(
:invoke
)
expect
(
Rake
::
Task
[
'gitlab:backup:artifacts:restore'
]).
to
receive
(
:invoke
)
expect
(
Rake
::
Task
[
'gitlab:backup:artifacts:restore'
]).
to
receive
(
:invoke
)
expect
(
Rake
::
Task
[
'gitlab:backup:lfs:restore'
]).
to
receive
(
:invoke
)
expect
(
Rake
::
Task
[
'gitlab:backup:lfs:restore'
]).
to
receive
(
:invoke
)
expect
(
Rake
::
Task
[
'gitlab:backup:registry:restore'
]).
to
receive
(
:invoke
)
expect
(
Rake
::
Task
[
'gitlab:shell:setup'
]).
to
receive
(
:invoke
)
expect
(
Rake
::
Task
[
'gitlab:shell:setup'
]).
to
receive
(
:invoke
)
expect
{
run_rake_task
(
'gitlab:backup:restore'
)
}.
not_to
raise_error
expect
{
run_rake_task
(
'gitlab:backup:restore'
)
}.
not_to
raise_error
end
end
...
@@ -122,7 +123,7 @@ describe 'gitlab:app namespace rake task' do
...
@@ -122,7 +123,7 @@ describe 'gitlab:app namespace rake task' do
it
'should set correct permissions on the tar contents'
do
it
'should set correct permissions on the tar contents'
do
tar_contents
,
exit_status
=
Gitlab
::
Popen
.
popen
(
tar_contents
,
exit_status
=
Gitlab
::
Popen
.
popen
(
%W{tar -tvf
#{
@backup_tar
}
db uploads.tar.gz repositories builds.tar.gz artifacts.tar.gz lfs.tar.gz}
%W{tar -tvf
#{
@backup_tar
}
db uploads.tar.gz repositories builds.tar.gz artifacts.tar.gz lfs.tar.gz
registry.tar.gz
}
)
)
expect
(
exit_status
).
to
eq
(
0
)
expect
(
exit_status
).
to
eq
(
0
)
expect
(
tar_contents
).
to
match
(
'db/'
)
expect
(
tar_contents
).
to
match
(
'db/'
)
...
@@ -131,12 +132,13 @@ describe 'gitlab:app namespace rake task' do
...
@@ -131,12 +132,13 @@ describe 'gitlab:app namespace rake task' do
expect
(
tar_contents
).
to
match
(
'builds.tar.gz'
)
expect
(
tar_contents
).
to
match
(
'builds.tar.gz'
)
expect
(
tar_contents
).
to
match
(
'artifacts.tar.gz'
)
expect
(
tar_contents
).
to
match
(
'artifacts.tar.gz'
)
expect
(
tar_contents
).
to
match
(
'lfs.tar.gz'
)
expect
(
tar_contents
).
to
match
(
'lfs.tar.gz'
)
expect
(
tar_contents
).
not_to
match
(
/^.{4,9}[rwx].* (database.sql.gz|uploads.tar.gz|repositories|builds.tar.gz|artifacts.tar.gz)\/$/
)
expect
(
tar_contents
).
to
match
(
'registry.tar.gz'
)
expect
(
tar_contents
).
not_to
match
(
/^.{4,9}[rwx].* (database.sql.gz|uploads.tar.gz|repositories|builds.tar.gz|artifacts.tar.gz|registry.tar.gz)\/$/
)
end
end
it
'should delete temp directories'
do
it
'should delete temp directories'
do
temp_dirs
=
Dir
.
glob
(
temp_dirs
=
Dir
.
glob
(
File
.
join
(
Gitlab
.
config
.
backup
.
path
,
'{db,repositories,uploads,builds,artifacts,lfs}'
)
File
.
join
(
Gitlab
.
config
.
backup
.
path
,
'{db,repositories,uploads,builds,artifacts,lfs
,registry
}'
)
)
)
expect
(
temp_dirs
).
to
be_empty
expect
(
temp_dirs
).
to
be_empty
...
@@ -172,7 +174,7 @@ describe 'gitlab:app namespace rake task' do
...
@@ -172,7 +174,7 @@ describe 'gitlab:app namespace rake task' do
it
"does not contain skipped item"
do
it
"does not contain skipped item"
do
tar_contents
,
_exit_status
=
Gitlab
::
Popen
.
popen
(
tar_contents
,
_exit_status
=
Gitlab
::
Popen
.
popen
(
%W{tar -tvf
#{
@backup_tar
}
db uploads.tar.gz repositories builds.tar.gz artifacts.tar.gz lfs.tar.gz}
%W{tar -tvf
#{
@backup_tar
}
db uploads.tar.gz repositories builds.tar.gz artifacts.tar.gz lfs.tar.gz
registry.tar.gz
}
)
)
expect
(
tar_contents
).
to
match
(
'db/'
)
expect
(
tar_contents
).
to
match
(
'db/'
)
...
@@ -180,6 +182,7 @@ describe 'gitlab:app namespace rake task' do
...
@@ -180,6 +182,7 @@ describe 'gitlab:app namespace rake task' do
expect
(
tar_contents
).
to
match
(
'builds.tar.gz'
)
expect
(
tar_contents
).
to
match
(
'builds.tar.gz'
)
expect
(
tar_contents
).
to
match
(
'artifacts.tar.gz'
)
expect
(
tar_contents
).
to
match
(
'artifacts.tar.gz'
)
expect
(
tar_contents
).
to
match
(
'lfs.tar.gz'
)
expect
(
tar_contents
).
to
match
(
'lfs.tar.gz'
)
expect
(
tar_contents
).
to
match
(
'registry.tar.gz'
)
expect
(
tar_contents
).
not_to
match
(
'repositories/'
)
expect
(
tar_contents
).
not_to
match
(
'repositories/'
)
end
end
...
@@ -195,6 +198,7 @@ describe 'gitlab:app namespace rake task' do
...
@@ -195,6 +198,7 @@ describe 'gitlab:app namespace rake task' do
expect
(
Rake
::
Task
[
'gitlab:backup:builds:restore'
]).
to
receive
:invoke
expect
(
Rake
::
Task
[
'gitlab:backup:builds:restore'
]).
to
receive
:invoke
expect
(
Rake
::
Task
[
'gitlab:backup:artifacts:restore'
]).
to
receive
:invoke
expect
(
Rake
::
Task
[
'gitlab:backup:artifacts:restore'
]).
to
receive
:invoke
expect
(
Rake
::
Task
[
'gitlab:backup:lfs:restore'
]).
to
receive
:invoke
expect
(
Rake
::
Task
[
'gitlab:backup:lfs:restore'
]).
to
receive
:invoke
expect
(
Rake
::
Task
[
'gitlab:backup:registry:restore'
]).
to
receive
:invoke
expect
(
Rake
::
Task
[
'gitlab:shell:setup'
]).
to
receive
:invoke
expect
(
Rake
::
Task
[
'gitlab:shell:setup'
]).
to
receive
:invoke
expect
{
run_rake_task
(
'gitlab:backup:restore'
)
}.
not_to
raise_error
expect
{
run_rake_task
(
'gitlab:backup:restore'
)
}.
not_to
raise_error
end
end
...
...
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