Added docker registry view
This commit is contained in:
parent
011a905a82
commit
b0ddbaa07c
12 changed files with 187 additions and 0 deletions
26
app/controllers/projects/images_controller.rb
Normal file
26
app/controllers/projects/images_controller.rb
Normal file
|
@ -0,0 +1,26 @@
|
|||
class Projects::ImagesController < Projects::ApplicationController
|
||||
before_action :authorize_read_image!
|
||||
before_action :authorize_update_image!, only: [:destroy]
|
||||
before_action :tag, except: [:index]
|
||||
layout 'project'
|
||||
|
||||
def index
|
||||
@tags = registry.tags
|
||||
end
|
||||
|
||||
def destroy
|
||||
# registry.destroy_tag(tag['fsLayers'].first['blobSum'])
|
||||
registry.destroy_tag(registry.tag_digest(params[:id]))
|
||||
redirect_to namespace_project_images_path(project.namespace, project)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def registry
|
||||
@registry ||= project.registry
|
||||
end
|
||||
|
||||
def tag
|
||||
@tag ||= registry.tag(params[:id])
|
||||
end
|
||||
end
|
|
@ -33,6 +33,10 @@ module GitlabRoutingHelper
|
|||
namespace_project_builds_path(project.namespace, project, *args)
|
||||
end
|
||||
|
||||
def project_images_path(project, *args)
|
||||
namespace_project_images_path(project.namespace, project, *args)
|
||||
end
|
||||
|
||||
def activity_project_path(project, *args)
|
||||
activity_namespace_project_path(project.namespace, project, *args)
|
||||
end
|
||||
|
|
|
@ -152,6 +152,10 @@ module ProjectsHelper
|
|||
nav_tabs << :builds
|
||||
end
|
||||
|
||||
if can?(current_user, :read_image, project)
|
||||
nav_tabs << :images
|
||||
end
|
||||
|
||||
if can?(current_user, :admin_project, project)
|
||||
nav_tabs << :settings
|
||||
end
|
||||
|
|
|
@ -370,6 +370,10 @@ class Project < ActiveRecord::Base
|
|||
@repository ||= Repository.new(path_with_namespace, self)
|
||||
end
|
||||
|
||||
def registry
|
||||
@registry ||= Registry.new(path_with_namespace, self)
|
||||
end
|
||||
|
||||
def registry_repository_url
|
||||
"#{Gitlab.config.registry.host_with_port}/#{path_with_namespace}" if images_enabled? && Gitlab.config.registry.enabled
|
||||
end
|
||||
|
|
42
app/models/registry.rb
Normal file
42
app/models/registry.rb
Normal file
|
@ -0,0 +1,42 @@
|
|||
require 'net/http'
|
||||
|
||||
class Registry
|
||||
attr_accessor :path_with_namespace, :project
|
||||
|
||||
def initialize(path_with_namespace, project)
|
||||
@path_with_namespace = path_with_namespace
|
||||
@project = project
|
||||
end
|
||||
|
||||
def tags
|
||||
@tags ||= client.tags(path_with_namespace)
|
||||
end
|
||||
|
||||
def tag(reference)
|
||||
return @tag[reference] if defined?(@tag[reference])
|
||||
@tag ||= {}
|
||||
@tag[reference] ||= client.tag(path_with_namespace, reference)
|
||||
end
|
||||
|
||||
def tag_digest(reference)
|
||||
return @tag_digest[reference] if defined?(@tag_digest[reference])
|
||||
@tag_digest ||= {}
|
||||
@tag_digest[reference] ||= client.tag_digest(path_with_namespace, reference)
|
||||
end
|
||||
|
||||
def destroy_tag(reference)
|
||||
client.delete_tag(path_with_namespace, reference)
|
||||
end
|
||||
|
||||
def blob_size(blob)
|
||||
return @blob_size[blob] if defined?(@blob_size[blob])
|
||||
@blob_size ||= {}
|
||||
@blob_size[blob] ||= client.blob_size(path_with_namespace, blob)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def client
|
||||
@client ||= RegistryClient.new(Gitlab.config.registry.api_url)
|
||||
end
|
||||
end
|
|
@ -46,6 +46,13 @@
|
|||
Builds
|
||||
%span.count.builds_counter= number_with_delimiter(@project.builds.running_or_pending.count(:all))
|
||||
|
||||
- if project_nav_tab? :images
|
||||
= nav_link(controller: %w(images)) do
|
||||
= link_to project_images_path(@project), title: 'Images', class: 'shortcuts-images' do
|
||||
= icon('image fw')
|
||||
%span
|
||||
Images
|
||||
|
||||
- if project_nav_tab? :graphs
|
||||
= nav_link(controller: %w(graphs)) do
|
||||
= link_to namespace_project_graph_path(@project.namespace, @project, current_ref), title: 'Graphs', class: 'shortcuts-graphs' do
|
||||
|
|
1
app/views/projects/images/_header_title.html.haml
Normal file
1
app/views/projects/images/_header_title.html.haml
Normal file
|
@ -0,0 +1 @@
|
|||
- header_title project_title(@project, "Images", project_images_path(@project))
|
48
app/views/projects/images/index.html.haml
Normal file
48
app/views/projects/images/index.html.haml
Normal file
|
@ -0,0 +1,48 @@
|
|||
- page_title "Images"
|
||||
= render "header_title"
|
||||
|
||||
.top-area
|
||||
.nav-controls
|
||||
|
||||
.gray-content-block
|
||||
A list of Docker Images for this project
|
||||
|
||||
%ul.content-list
|
||||
- if @tags.blank?
|
||||
%li
|
||||
.nothing-here-block No images to show
|
||||
- else
|
||||
.table-holder
|
||||
%table.table.builds
|
||||
%thead
|
||||
%tr
|
||||
%th Name
|
||||
%th Layers
|
||||
%th Size
|
||||
%th Created
|
||||
%th Docker
|
||||
%th
|
||||
|
||||
- @tags.sort.each do |tag|
|
||||
- details = @registry.tag(tag)
|
||||
- layer = details['history'].first
|
||||
- if layer && layer['v1Compatibility']
|
||||
- layer_data = JSON.parse(layer['v1Compatibility'])
|
||||
%tr
|
||||
%td
|
||||
= link_to namespace_project_image_path(@project.namespace, @project, tag) do
|
||||
#{details['name']}:#{details['tag']}
|
||||
%td
|
||||
= details['fsLayers'].length
|
||||
%td
|
||||
= number_to_human_size(details['fsLayers'].inject(0) { |sum, d| sum + @registry.blob_size(d['blobSum']) }.bytes)
|
||||
%td
|
||||
- if layer_data
|
||||
= time_ago_in_words(DateTime.rfc3339(layer_data['created']))
|
||||
%td
|
||||
- if layer_data
|
||||
= layer_data['docker_version']
|
||||
%td.content
|
||||
.controls.hidden-xs.pull-right
|
||||
= link_to namespace_project_image_path(@project.namespace, @project, tag), class: 'btn btn-remove has-tooltip', title: "Remove", data: { confirm: "Are you sure?" }, method: :delete do
|
||||
= icon("trash cred")
|
|
@ -8,3 +8,10 @@ Mime::Type.register_alias "text/plain", :diff
|
|||
Mime::Type.register_alias "text/plain", :patch
|
||||
Mime::Type.register_alias 'text/html', :markdown
|
||||
Mime::Type.register_alias 'text/html', :md
|
||||
#Mime::Type.unregister :json
|
||||
Mime::Type.register_alias 'application/vnd.docker.distribution.manifest.v1+prettyjws', :json
|
||||
#Mime::Type.register 'application/json', :json, %w( text/plain text/x-json application/jsonrequest )
|
||||
|
||||
ActionDispatch::ParamsParser::DEFAULT_PARSERS[Mime::Type.lookup('application/vnd.docker.distribution.manifest.v1+prettyjws')]=lambda do |body|
|
||||
JSON.parse(body)
|
||||
end
|
||||
|
|
|
@ -690,6 +690,8 @@ Rails.application.routes.draw do
|
|||
end
|
||||
end
|
||||
|
||||
resources :images, only: [:index, :destroy], constraints: { id: Gitlab::Regex.image_reference_regex }
|
||||
|
||||
resources :milestones, constraints: { id: /\d+/ } do
|
||||
member do
|
||||
put :sort_issues
|
||||
|
|
|
@ -96,5 +96,9 @@ module Gitlab
|
|||
(?<![\/.]) (?# rule #6-7)
|
||||
}x.freeze
|
||||
end
|
||||
|
||||
def image_reference_regex
|
||||
git_reference_regex
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
38
lib/registry_client.rb
Normal file
38
lib/registry_client.rb
Normal file
|
@ -0,0 +1,38 @@
|
|||
require 'HTTParty'
|
||||
|
||||
class RegistryClient
|
||||
attr_accessor :uri
|
||||
|
||||
def initialize(uri)
|
||||
@uri = uri
|
||||
end
|
||||
|
||||
def tags(name)
|
||||
response = HTTParty.get("#{uri}/v2/#{name}/tags/list")
|
||||
response.parsed_response['tags']
|
||||
end
|
||||
|
||||
def tag(name, reference)
|
||||
response = HTTParty.get("#{uri}/v2/#{name}/manifests/#{reference}")
|
||||
JSON.parse(response)
|
||||
end
|
||||
|
||||
def tag_digest(name, reference)
|
||||
response = HTTParty.head("#{uri}/v2/#{name}/manifests/#{reference}")
|
||||
response.headers['docker-content-digest'].split(':')
|
||||
end
|
||||
|
||||
def delete_tag(name, reference)
|
||||
response = HTTParty.delete("#{uri}/v2/#{name}/manifests/#{reference}")
|
||||
response.parsed_response
|
||||
end
|
||||
|
||||
def blob_size(name, digest)
|
||||
response = HTTParty.head("#{uri}/v2/#{name}/blobs/#{digest}")
|
||||
response.headers.content_length
|
||||
end
|
||||
|
||||
def delete_blob(name, digest)
|
||||
HTTParty.delete("#{uri}/v2/#{name}/blobs/#{digest}")
|
||||
end
|
||||
end
|
Loading…
Reference in a new issue