Commit b0ddbaa0 authored by Kamil Trzcinski's avatar Kamil Trzcinski

Added docker registry view

parent 011a905a
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
......
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
......
- header_title project_title(@project, "Images", project_images_path(@project))
- 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
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
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment