Revision 6d101d7a
Added by Dmitri Dolguikh over 7 years ago
app/assets/javascripts/foreman_docker/image_step.js | ||
---|---|---|
18 | 18 |
}); |
19 | 19 |
|
20 | 20 |
$('#hub_tab').click( function() { |
21 |
$('#repository_registry_id').val('');
|
|
21 |
$('#wizard_states_image_registry_id').val('');
|
|
22 | 22 |
}); |
23 | 23 |
}); |
24 | 24 |
|
... | ... | |
26 | 26 |
$.ajax({ |
27 | 27 |
type:'get', |
28 | 28 |
url: $(item).attr('data-url'), |
29 |
data: { search: item.val(), registry_id: $('#registry_id').val() }, |
|
29 |
data: { search: item.val(), registry_id: $('#wizard_states_image_registry_id').val() },
|
|
30 | 30 |
//data:'search=' + item.val(), |
31 | 31 |
success:function (result) { |
32 | 32 |
if(result == 'true'){ |
... | ... | |
52 | 52 |
tag.addClass('tags-autocomplete-loading'); |
53 | 53 |
tag.val(''); |
54 | 54 |
var source = []; |
55 |
$.getJSON( tag.data("url"), { search: $('#search').val(), registry_id: $('#repository_registry_id').val() },
|
|
55 |
$.getJSON( tag.data("url"), { search: $('#search').val(), registry_id: $('#wizard_states_image_registry_id').val() },
|
|
56 | 56 |
function(data) { |
57 | 57 |
$('#searching_spinner').hide(); |
58 | 58 |
tag.removeClass('tags-autocomplete-loading'); |
... | ... | |
72 | 72 |
type:'get', |
73 | 73 |
dataType:'text', |
74 | 74 |
url: $(item).attr('data-url'), |
75 |
data: { search: $('#search').val(), registry_id: $('#repository_registry_id').val() },
|
|
75 |
data: { search: $('#search').val(), registry_id: $('#wizard_states_image_registry_id').val() },
|
|
76 | 76 |
success: function (result) { |
77 | 77 |
$('#repository_search_results').html(result); |
78 | 78 |
}, |
app/controllers/containers/steps_controller.rb | ||
---|---|---|
3 | 3 |
include Wicked::Wizard |
4 | 4 |
|
5 | 5 |
steps :preliminary, :image, :configuration, :environment |
6 |
before_filter :find_container
|
|
6 |
before_filter :find_state
|
|
7 | 7 |
|
8 |
# rubocop:disable Metrics/CyclomaticComplexity |
|
8 | 9 |
def show |
9 | 10 |
case step |
10 | 11 |
when :preliminary |
11 |
@container_resources = ComputeResource.select { |cr| cr.provider == 'Docker' } |
|
12 |
@container_resources = allowed_resources.select { |cr| cr.provider == 'Docker' } |
|
13 |
@preliminary = @state.preliminary || @state.build_preliminary |
|
14 |
when :image |
|
15 |
@image = @state.image || @state.build_image |
|
16 |
when :configuration |
|
17 |
@configuration = @state.configuration || @state.build_configuration |
|
18 |
when :environment |
|
19 |
@environment = @state.environment || @state.build_environment |
|
12 | 20 |
end |
13 | 21 |
render_wizard |
14 | 22 |
end |
... | ... | |
17 | 25 |
def update |
18 | 26 |
case step |
19 | 27 |
when :preliminary |
20 |
@container.update_attribute(:compute_resource_id, params[:container][:compute_resource_id])
|
|
28 |
@state.create_preliminary!(params[:docker_container_wizard_states_preliminary])
|
|
21 | 29 |
when :image |
22 |
@container.update_attributes!(params[:container])
|
|
30 |
@state.create_image!(params[:docker_container_wizard_states_image])
|
|
23 | 31 |
when :configuration |
24 |
@container.update_attributes(params[:container])
|
|
32 |
@state.create_configuration!(params[:docker_container_wizard_states_configuration])
|
|
25 | 33 |
when :environment |
26 |
@container.update_attributes(params[:container]) |
|
27 |
if (response = start_container) |
|
28 |
@container.uuid = response.id |
|
34 |
@state.create_environment!(params[:docker_container_wizard_states_environment]) |
|
35 |
container = Service::Containers.start_container!(@state) |
|
36 |
if container |
|
37 |
return redirect_to container_path(container) |
|
29 | 38 |
else |
30 |
process_error(:object => @container.compute_resource, :render => 'environment') |
|
39 |
@environment = @state.environment |
|
40 |
process_error(:object => @state.environment, :render => 'environment') |
|
31 | 41 |
return |
32 | 42 |
end |
33 | 43 |
end |
34 |
render_wizard @container
|
|
44 |
render_wizard @state
|
|
35 | 45 |
end |
36 | 46 |
|
37 | 47 |
private |
38 | 48 |
|
39 |
def finish_wizard_path |
|
40 |
container_path(:id => params[:container_id]) |
|
41 |
end |
|
42 |
|
|
43 | 49 |
def allowed_resources |
44 | 50 |
ComputeResource.authorized(:view_compute_resources) |
45 | 51 |
end |
46 | 52 |
|
47 |
def find_container
|
|
48 |
@container = Container.find(params[:container_id])
|
|
53 |
def find_state
|
|
54 |
@state = DockerContainerWizardState.find(params[:wizard_state_id])
|
|
49 | 55 |
rescue ActiveRecord::RecordNotFound |
50 | 56 |
not_found |
51 | 57 |
end |
52 |
|
|
53 |
def start_container |
|
54 |
@container.compute_resource.create_container(@container.parametrize) |
|
55 |
end |
|
56 | 58 |
end |
57 | 59 |
end |
app/controllers/containers_controller.rb | ||
---|---|---|
1 | 1 |
# rubocop:disable Metrics/ClassLength |
2 | 2 |
class ContainersController < ::ApplicationController |
3 |
before_filter :find_container, :only => [:show, :auto_complete_repository_name, |
|
4 |
:auto_complete_tag, |
|
5 |
:search_repository, :commit] |
|
6 |
before_filter :find_registry, :only => [:auto_complete_repository_name, |
|
7 |
:auto_complete_tag, |
|
8 |
:search_repository] |
|
3 |
before_filter :find_container, :only => [:show, :commit] |
|
9 | 4 |
|
10 | 5 |
def index |
11 | 6 |
@container_resources = allowed_resources |
... | ... | |
19 | 14 |
end |
20 | 15 |
|
21 | 16 |
def new |
22 |
@container = Container.create |
|
23 |
redirect_to container_step_path(:container_id => @container.id, :id => :preliminary) |
|
17 |
redirect_to wizard_state_step_path( |
|
18 |
:wizard_state_id => DockerContainerWizardState.create!.id, |
|
19 |
:id => :preliminary) |
|
24 | 20 |
end |
25 | 21 |
|
26 | 22 |
def destroy |
... | ... | |
38 | 34 |
def show |
39 | 35 |
end |
40 | 36 |
|
41 |
def auto_complete_repository_name |
|
42 |
exist = if @registry.nil? |
|
43 |
@container.compute_resource.exist?(params[:search]) |
|
44 |
else |
|
45 |
registry_auto_complete_repository(params[:search]) |
|
46 |
end |
|
47 |
render :text => exist.to_s |
|
48 |
end |
|
49 |
|
|
50 |
def registry_auto_complete_repository(term) |
|
51 |
result = ::Service::RegistryApi.new(:url => @registry.url).search(term) |
|
52 |
registry_name = term.split('/').size > 1 ? term : |
|
53 |
'library/' + term |
|
54 |
result['results'].any? { |r| r['name'] == registry_name } |
|
55 |
end |
|
56 |
|
|
57 |
def auto_complete_tag |
|
58 |
# This is the format jQuery UI autocomplete expects |
|
59 |
tags = if @registry.nil? |
|
60 |
@container.compute_resource.tags(params[:search]) |
|
61 |
else |
|
62 |
registry_auto_complete_tags(params[:search]) |
|
63 |
end |
|
64 |
respond_to do |format| |
|
65 |
format.js do |
|
66 |
tags.map! { |tag| { :label => CGI.escapeHTML(tag), :value => CGI.escapeHTML(tag) } } |
|
67 |
render :json => tags |
|
68 |
end |
|
69 |
end |
|
70 |
end |
|
71 |
|
|
72 |
def registry_auto_complete_tags(term) |
|
73 |
::Service::RegistryApi.new(:url => @registry.url).list_repository_tags(term).keys |
|
74 |
end |
|
75 |
|
|
76 | 37 |
def commit |
77 | 38 |
Docker::Container.get(@container.uuid).commit(:author => params[:commit][:author], |
78 | 39 |
:repo => params[:commit][:repo], |
... | ... | |
87 | 48 |
{ :container => @container, :e => e } |
88 | 49 |
end |
89 | 50 |
|
90 |
def search_repository |
|
91 |
repositories = if @registry.nil? |
|
92 |
@container.compute_resource.search(params[:search]) |
|
93 |
else |
|
94 |
r = ::Service::RegistryApi.new(:url => @registry.url) |
|
95 |
.search(params[:search]) |
|
96 |
r['results'] |
|
97 |
end |
|
98 |
respond_to do |format| |
|
99 |
format.js do |
|
100 |
render :partial => 'repository_search_results', :locals => { :repositories => repositories } |
|
101 |
end |
|
102 |
end |
|
103 |
end |
|
104 |
|
|
105 | 51 |
private |
106 | 52 |
|
107 | 53 |
def action_permission |
... | ... | |
151 | 97 |
@container = Container.authorized("#{action_permission}_#{controller_name}".to_sym) |
152 | 98 |
.find(params[:id]) |
153 | 99 |
end |
154 |
|
|
155 |
def find_registry |
|
156 |
return if params[:registry_id].empty? |
|
157 |
@registry = DockerRegistry.authorized("#{action_permission}_#{controller_name}".to_sym) |
|
158 |
.find(params[:registry_id]) |
|
159 |
end |
|
160 | 100 |
end |
app/controllers/image_search_controller.rb | ||
---|---|---|
1 |
class ImageSearchController < ::ApplicationController |
|
2 |
before_filter :find_resource |
|
3 |
|
|
4 |
def auto_complete_repository_name |
|
5 |
render :text => (use_hub? ? hub_image_exists?(params[:search]) : |
|
6 |
registry_image_exists?(params[:search])).to_s |
|
7 |
end |
|
8 |
|
|
9 |
def auto_complete_image_tag |
|
10 |
# This is the format jQuery UI autocomplete expects |
|
11 |
tags = use_hub? ? hub_auto_complete_image_tags(params[:search]) : |
|
12 |
registry_auto_complete_image_tags(params[:search]) |
|
13 |
respond_to do |format| |
|
14 |
format.js do |
|
15 |
tags.map! { |tag| { :label => CGI.escapeHTML(tag), :value => CGI.escapeHTML(tag) } } |
|
16 |
render :json => tags |
|
17 |
end |
|
18 |
end |
|
19 |
end |
|
20 |
|
|
21 |
def search_repository |
|
22 |
images = use_hub? ? hub_search_image(params[:search]) : registry_search_image(params[:search]) |
|
23 |
respond_to do |format| |
|
24 |
format.js { render :partial => 'repository_search_results', :locals => { :images => images } } |
|
25 |
end |
|
26 |
end |
|
27 |
|
|
28 |
def use_hub? |
|
29 |
@registry.nil? |
|
30 |
end |
|
31 |
|
|
32 |
def hub_image_exists?(terms) |
|
33 |
@cr.exist?(terms) |
|
34 |
end |
|
35 |
|
|
36 |
def hub_auto_complete_image_tags(terms) |
|
37 |
@cr.tags(terms) |
|
38 |
end |
|
39 |
|
|
40 |
def hub_search_image(terms) |
|
41 |
@cr.search(terms) |
|
42 |
end |
|
43 |
|
|
44 |
def registry_image_exists?(term) |
|
45 |
result = ::Service::RegistryApi.new(:url => @registry.url).search(term) |
|
46 |
registry_name = term.split('/').size > 1 ? term : |
|
47 |
'library/' + term |
|
48 |
result['results'].any? { |r| r['name'] == registry_name } |
|
49 |
end |
|
50 |
|
|
51 |
def registry_auto_complete_image_tags(terms) |
|
52 |
::Service::RegistryApi.new(:url => @registry.url).list_repository_tags(terms).keys |
|
53 |
end |
|
54 |
|
|
55 |
def registry_search_image(terms) |
|
56 |
r = ::Service::RegistryApi.new(:url => @registry.url).search(terms) |
|
57 |
r['results'] |
|
58 |
end |
|
59 |
|
|
60 |
def action_permission |
|
61 |
case params[:action] |
|
62 |
when 'auto_complete_repository_name', 'auto_complete_image_tag', 'search_repository' |
|
63 |
:search_repository |
|
64 |
else |
|
65 |
super |
|
66 |
end |
|
67 |
end |
|
68 |
|
|
69 |
def find_resource |
|
70 |
if !params[:registry_id].empty? |
|
71 |
@registry = DockerRegistry.authorized(:view_registries).find(params[:registry_id]) |
|
72 |
else |
|
73 |
@cr = ComputeResource.authorized(:view_compute_resources).find(params[:id]) |
|
74 |
end |
|
75 |
rescue ActiveRecord::RecordNotFound |
|
76 |
not_found |
|
77 |
end |
|
78 |
end |
app/helpers/container_steps_helper.rb | ||
---|---|---|
10 | 10 |
end |
11 | 11 |
|
12 | 12 |
def select_registry(f) |
13 |
field(f, 'container[registry_id]', :label => _("Registry")) do |
|
14 |
collection_select :container, :registry_id, |
|
15 |
DockerRegistry.with_taxonomy_scope_override(@location, @organization) |
|
16 |
.authorized(:view_registries), |
|
13 |
registries = DockerRegistry.with_taxonomy_scope_override(@location, @organization) |
|
14 |
.authorized(:view_registries) |
|
15 |
field(f, 'docker_container_wizard_states_image[registry_id]', :label => _("Registry")) do |
|
16 |
collection_select :wizard_states_image, :registry_id, |
|
17 |
registries, |
|
17 | 18 |
:id, :name, |
18 | 19 |
{ :prompt => _("Select a registry") }, |
19 |
:class => "form-control", :disabled => f.object.repository_name.present?
|
|
20 |
:class => "form-control", :disabled => registries.size == 0
|
|
20 | 21 |
end |
21 | 22 |
end |
22 | 23 |
end |
app/models/container.rb | ||
---|---|---|
5 | 5 |
belongs_to :registry, :class_name => "DockerRegistry", :foreign_key => :registry_id |
6 | 6 |
has_many :environment_variables, :dependent => :destroy, :foreign_key => :reference_id, |
7 | 7 |
:inverse_of => :container, |
8 |
:class_name => 'EnvironmentVariable' |
|
8 |
:class_name => 'EnvironmentVariable', |
|
9 |
:validate => false |
|
9 | 10 |
accepts_nested_attributes_for :environment_variables, :allow_destroy => true |
10 | 11 |
include ForemanDocker::ParameterValidators |
11 | 12 |
|
app/models/docker_container_wizard_state.rb | ||
---|---|---|
1 |
class DockerContainerWizardState < ActiveRecord::Base |
|
2 |
has_one :preliminary, :class_name => DockerContainerWizardStates::Preliminary, |
|
3 |
:dependent => :destroy, :validate => true, :autosave => true |
|
4 |
has_one :image, :class_name => DockerContainerWizardStates::Image, |
|
5 |
:dependent => :destroy, :validate => true, :autosave => true |
|
6 |
has_one :configuration, :class_name => DockerContainerWizardStates::Configuration, |
|
7 |
:dependent => :destroy, :validate => true, :autosave => true |
|
8 |
has_one :environment, :class_name => DockerContainerWizardStates::Environment, |
|
9 |
:dependent => :destroy, :validate => true, :autosave => true |
|
10 |
|
|
11 |
delegate :compute_resource_id, :to => :preliminary |
|
12 |
delegate :environment_variables, :to => :environment |
|
13 |
|
|
14 |
def container_attributes |
|
15 |
{ :repository_name => image.repository_name, |
|
16 |
:tag => image.tag, |
|
17 |
:registry_id => image.registry_id, |
|
18 |
:name => configuration.name, |
|
19 |
:compute_resource_id => preliminary.compute_resource_id, |
|
20 |
:tty => environment.tty, |
|
21 |
:memory => configuration.memory, |
|
22 |
:entrypoint => configuration.entrypoint, |
|
23 |
:command => configuration.command, |
|
24 |
:attach_stdout => environment.attach_stdout, |
|
25 |
:attach_stdin => environment.attach_stdin, |
|
26 |
:attach_stderr => environment.attach_stderr, |
|
27 |
:cpu_shares => configuration.cpu_shares, |
|
28 |
:cpu_set => configuration.cpu_set } |
|
29 |
end |
|
30 |
end |
app/models/docker_container_wizard_states/configuration.rb | ||
---|---|---|
1 |
module DockerContainerWizardStates |
|
2 |
class Configuration < ActiveRecord::Base |
|
3 |
self.table_name_prefix = 'docker_container_wizard_states_' |
|
4 |
belongs_to :wizard_state, :class_name => DockerContainerWizardState, |
|
5 |
:foreign_key => :docker_container_wizard_state_id |
|
6 |
end |
|
7 |
end |
app/models/docker_container_wizard_states/environment.rb | ||
---|---|---|
1 |
module DockerContainerWizardStates |
|
2 |
class Environment < ActiveRecord::Base |
|
3 |
self.table_name_prefix = 'docker_container_wizard_states_' |
|
4 |
belongs_to :wizard_state, :class_name => DockerContainerWizardState |
|
5 |
# Fix me: |
|
6 |
# Validations are off on this association as there's a bug in ::Parameter |
|
7 |
# that forces validation of reference_id. This will fail on new records as |
|
8 |
# validations are executed before parent and children records have been persisted. |
|
9 |
has_many :environment_variables, :dependent => :destroy, :foreign_key => :reference_id, |
|
10 |
:inverse_of => :environment, |
|
11 |
:class_name => 'DockerContainerWizardStates::EnvironmentVariable', |
|
12 |
:validate => false |
|
13 |
include ::ParameterValidators |
|
14 |
|
|
15 |
accepts_nested_attributes_for :environment_variables, :allow_destroy => true |
|
16 |
|
|
17 |
def parameters_symbol |
|
18 |
:environment_variables |
|
19 |
end |
|
20 |
end |
|
21 |
end |
app/models/docker_container_wizard_states/environment_variable.rb | ||
---|---|---|
1 |
module DockerContainerWizardStates |
|
2 |
class EnvironmentVariable < Parameter |
|
3 |
belongs_to :environment, :foreign_key => :reference_id, :inverse_of => :environment_variables, |
|
4 |
:class_name => 'DockerContainerWizardStates::Environment' |
|
5 |
validates :name, :uniqueness => { :scope => :reference_id } |
|
6 |
end |
|
7 |
end |
app/models/docker_container_wizard_states/image.rb | ||
---|---|---|
1 |
module DockerContainerWizardStates |
|
2 |
class Image < ActiveRecord::Base |
|
3 |
self.table_name_prefix = 'docker_container_wizard_states_' |
|
4 |
belongs_to :wizard_state, :class_name => DockerContainerWizardState, |
|
5 |
:foreign_key => :docker_container_wizard_state_id |
|
6 |
delegate :compute_resource_id, :to => :wizard_state |
|
7 |
|
|
8 |
validates :tag, :presence => true |
|
9 |
validates :repository_name, :presence => true |
|
10 |
end |
|
11 |
end |
app/models/docker_container_wizard_states/preliminary.rb | ||
---|---|---|
1 |
module DockerContainerWizardStates |
|
2 |
class Preliminary < ActiveRecord::Base |
|
3 |
self.table_name_prefix = 'docker_container_wizard_states_' |
|
4 |
belongs_to :wizard_state, :class_name => DockerContainerWizardState, |
|
5 |
:foreign_key => :docker_container_wizard_state_id |
|
6 |
|
|
7 |
validates :compute_resource_id, :presence => true |
|
8 |
end |
|
9 |
end |
app/models/service/containers.rb | ||
---|---|---|
1 |
module Service |
|
2 |
class Containers |
|
3 |
def self.start_container!(wizard_state) |
|
4 |
ActiveRecord::Base.transaction do |
|
5 |
container = Container.new(wizard_state.container_attributes) do |r| |
|
6 |
# eagerly load environment variables |
|
7 |
state = DockerContainerWizardState.includes(:environment => [:environment_variables]) |
|
8 |
.find(wizard_state.id) |
|
9 |
state.environment_variables.each do |e| |
|
10 |
r.environment_variables.build( |
|
11 |
:name => e.name, :value => e.value, :priority => e.priority) |
|
12 |
end |
|
13 |
end |
|
14 |
|
|
15 |
started = start_container(container) |
|
16 |
fail ActiveRecord::Rollback unless started |
|
17 |
|
|
18 |
container.save! |
|
19 |
destroy_wizard_state(wizard_state) |
|
20 |
|
|
21 |
container |
|
22 |
end |
|
23 |
end |
|
24 |
|
|
25 |
def self.start_container(container) |
|
26 |
started = container.compute_resource.create_container(container.parametrize) |
|
27 |
container.uuid = started.id if started |
|
28 |
started |
|
29 |
end |
|
30 |
|
|
31 |
def self.destroy_wizard_state(wizard_state) |
|
32 |
wizard_state.destroy |
|
33 |
DockerContainerWizardState.destroy_all(["updated_at < ?", (Time.now - 24.hours)]) |
|
34 |
end |
|
35 |
end |
|
36 |
end |
app/views/containers/_image_search_results.html.erb | ||
---|---|---|
1 |
<% repositories.each do |repository| %> |
|
2 |
<h3><%= link_to repository['name'], '#', :onclick => 'repoSelected(this)' %></h3> |
|
3 |
<p> |
|
4 |
<%= '<span class="glyphicon glyphicon-certificate" title="Official"></span>'.html_safe if repository['is_official'] %> |
|
5 |
<%= '<span class="glyphicon glyphicon-thumbs-up" title="Trusted"></span>'.html_safe if repository['is_trusted'] %> |
|
6 |
<span class="glyphicon glyphicon-star"></span> <%= repository['star_count'] %> |
|
7 |
</p> |
|
8 |
<p> |
|
9 |
<%= trunc(repository['description']) %> |
|
10 |
<%= link_to '<span class="glyphicon glyphicon-share"></span>'.html_safe, hub_url(repository), :target => '_blank' %> |
|
11 |
</p> |
|
12 |
<% end %> |
app/views/containers/steps/configuration.html.erb | ||
---|---|---|
1 | 1 |
<%= render :layout => 'title', :locals => { :step => 3 } do %> |
2 |
<%= form_for @container, :url => wizard_path, :method => :put do |f| %>
|
|
2 |
<%= form_for @configuration, :url => wizard_path, :method => :put do |f| %>
|
|
3 | 3 |
<h3><%= _("Basic options") %></h3> |
4 | 4 |
<%= text_f f, :name, :size => 'col-md-4' %> |
5 | 5 |
<%= text_f f, :command, :size => 'col-md-4' %> |
app/views/containers/steps/environment.html.erb | ||
---|---|---|
1 | 1 |
<%= render :layout => 'title', :locals => { :step => 4 } do %> |
2 |
<%= form_for @container, :url => wizard_path, :method => :put do |f| %>
|
|
2 |
<%= form_for @environment, :url => wizard_path, :method => :put do |f| %>
|
|
3 | 3 |
<div class='row'> |
4 | 4 |
<div class='col-md-6 col-md-push-7'> |
5 | 5 |
<h3><%= _("Shell") %></h3> |
... | ... | |
10 | 10 |
</div> |
11 | 11 |
<div class='col-md-6 col-md-pull-6'> |
12 | 12 |
<h3><%= _("Environment variables") %></h3> |
13 |
<%= f.fields_for :environment_variables do |builder| %> |
|
13 |
<%= f.fields_for :environment_variables, @environment.environment_variables do |builder| %>
|
|
14 | 14 |
<%= render 'foreman_docker/common_parameters/environment_variable', :f => builder %> |
15 | 15 |
<% end %> |
16 | 16 |
<%= link_to_add_fields(_("Add environment variable"), f, :environment_variables, |
app/views/containers/steps/image.html.erb | ||
---|---|---|
13 | 13 |
</a></li> |
14 | 14 |
</ul> |
15 | 15 |
|
16 |
<%= form_for @container, :class => 'form-horizontal', :url => wizard_path, :method => :put do |f| %>
|
|
16 |
<%= form_for @image, :class => 'form-horizontal', :url => wizard_path, :method => :put do |f| %>
|
|
17 | 17 |
<div class="tab-content"> |
18 | 18 |
<div class="tab-pane active" id="hub"> |
19 | 19 |
</div> |
... | ... | |
24 | 24 |
</div> |
25 | 25 |
<div> |
26 | 26 |
<div class="form-group col-md-6"> |
27 |
<%= label_tag "repository[search]", _('Search'), :class=>"col-sm-2 control-label" %>
|
|
27 |
<%= label_tag "image_id", _('Search'), :class=>"col-sm-2 control-label" %>
|
|
28 | 28 |
<div class="input-group"> |
29 |
<%= auto_complete_docker_search('container[repository_name]', '', |
|
30 |
:'data-url' => auto_complete_repository_name_container_path(@container), |
|
29 |
|
|
30 |
<%= auto_complete_docker_search('docker_container_wizard_states_image[repository_name]', '', |
|
31 |
:'data-url' => auto_complete_repository_name_image_search_path(@image.compute_resource_id), |
|
31 | 32 |
:value => f.object.repository_name.present? ? f.object.repository_name : '', |
32 | 33 |
:id => :search, |
33 | 34 |
:focus_on_load => true, |
... | ... | |
37 | 38 |
<%= button_tag(:class => 'btn btn-default', |
38 | 39 |
:type => 'button', |
39 | 40 |
:id => 'search_repository', |
40 |
:'data-url' => search_repository_container_path(@container),
|
|
41 |
:'data-url' => search_repository_image_search_path(@image.compute_resource_id),
|
|
41 | 42 |
:onclick => 'searchRepo(this)') do %> |
42 | 43 |
<span class="glyphicon glyphicon-search"></span> |
43 | 44 |
<% end %> |
... | ... | |
45 | 46 |
</div> |
46 | 47 |
</div> |
47 | 48 |
<%= text_f f, :tag, |
48 |
:value => f.object.tag.present? ? f.object.tag : '', |
|
49 | 49 |
:id => 'tag', |
50 |
:'data-url' => auto_complete_tag_container_path(@container) %>
|
|
50 |
:'data-url' => auto_complete_image_tag_image_search_path(@image.compute_resource_id) %>
|
|
51 | 51 |
<div class="col-md-12"> |
52 | 52 |
<div id='searching_spinner' class='col-md-offset-3 hide'> |
53 | 53 |
<span id='waiting_text'> |
app/views/containers/steps/preliminary.html.erb | ||
---|---|---|
1 | 1 |
<%= render :layout => 'title', :locals => { :step => 1 } do %> |
2 |
<%= form_for @container, :url => wizard_path, :method => :put do |f| %>
|
|
2 |
<%= form_for @preliminary, :url => wizard_path, :method => :put do |f| %>
|
|
3 | 3 |
<div> |
4 | 4 |
<% if @container_resources.present? %> |
5 | 5 |
<h3><%= _("Resource selection") %></h3> |
6 | 6 |
<%= _("Where do you want to deploy your container?:") %> |
7 | 7 |
<hr> |
8 |
<%= select_f f, :compute_resource_id, @container_resources, :id, :to_label, {}, { :label => _('Deploy on') } %>
|
|
8 |
<%= select_f f, 'compute_resource_id', @container_resources, :id, :to_label, {}, { :label => _('Deploy on') } %>
|
|
9 | 9 |
<% else %> |
10 | 10 |
<div class="alert alert-warning alert-dismissable"> |
11 | 11 |
<%= image_tag 'false.png' %> <%= (_("You need a Docker compute resource in order to create containers. Please %s and try again.") % link_to('add a new one', hash_for_new_compute_resource_path)).html_safe %> |
app/views/image_search/_repository_search_results.html.erb | ||
---|---|---|
1 |
<% repositories.each do |repository| %> |
|
2 |
<h3><%= link_to repository['name'], '#', :onclick => 'repoSelected(this)' %></h3> |
|
3 |
<p> |
|
4 |
<%= '<span class="glyphicon glyphicon-certificate" title="Official"></span>'.html_safe if repository['is_official'] %> |
|
5 |
<%= '<span class="glyphicon glyphicon-thumbs-up" title="Trusted"></span>'.html_safe if repository['is_trusted'] %> |
|
6 |
<span class="glyphicon glyphicon-star"></span> <%= repository['star_count'] %> |
|
7 |
</p> |
|
8 |
<p> |
|
9 |
<%= trunc(repository['description']) %> |
|
10 |
<%= link_to '<span class="glyphicon glyphicon-share"></span>'.html_safe, hub_url(repository), :target => '_blank' %> |
|
11 |
</p> |
|
12 |
<% end %> |
config/routes.rb | ||
---|---|---|
3 | 3 |
member do |
4 | 4 |
post :commit |
5 | 5 |
end |
6 |
end |
|
7 |
|
|
8 |
resources :wizard_states, :only => [] do |
|
6 | 9 |
resources :steps, :controller => 'containers/steps', :only => [:show, :update] |
10 |
end |
|
11 |
|
|
12 |
resources :image_search, :only => [] do |
|
7 | 13 |
get :auto_complete_repository_name, :on => :member |
8 |
get :auto_complete_tag, :on => :member |
|
14 |
get :auto_complete_image_tag, :on => :member
|
|
9 | 15 |
get :search_repository, :on => :member |
10 | 16 |
end |
17 |
|
|
11 | 18 |
resources :registries, :only => [:index, :new, :create, :update, :destroy, :edit] |
12 | 19 |
end |
db/migrate/20141209182008_remove_docker_tables.rb | ||
---|---|---|
66 | 66 |
when :sqlite |
67 | 67 |
execute "DROP TABLE #{table_name}" |
68 | 68 |
else |
69 |
raise NotImplementedError, "Unknown adapter type '#{connection.adapter_name.downcase.to_sym}'"
|
|
69 |
fail NotImplementedError, "Unknown adapter type '#{connection.adapter_name.downcase.to_sym}'"
|
|
70 | 70 |
end |
71 | 71 |
end |
72 | 72 |
end |
db/migrate/20141222113313_create_wizard_states.rb | ||
---|---|---|
1 |
class CreateWizardStates < ActiveRecord::Migration |
|
2 |
# rubocop:disable Metrics/MethodLength |
|
3 |
def change |
|
4 |
create_table :docker_container_wizard_states do |t| |
|
5 |
t.timestamps |
|
6 |
end |
|
7 |
|
|
8 |
create_table :docker_container_wizard_states_preliminaries do |t| |
|
9 |
t.integer :compute_resource_id, :null => false |
|
10 |
t.references :docker_container_wizard_state, :null => false |
|
11 |
t.timestamps |
|
12 |
end |
|
13 |
|
|
14 |
create_table :docker_container_wizard_states_images do |t| |
|
15 |
t.integer :registry_id |
|
16 |
t.string :repository_name, :null => false |
|
17 |
t.string :tag, :null => false |
|
18 |
t.references :docker_container_wizard_state, :null => false |
|
19 |
t.timestamps |
|
20 |
end |
|
21 |
|
|
22 |
create_table :docker_container_wizard_states_configurations do |t| |
|
23 |
t.string :name |
|
24 |
t.string :command |
|
25 |
t.string :entrypoint |
|
26 |
t.integer :cpu_set |
|
27 |
t.float :cpu_shares |
|
28 |
t.string :memory |
|
29 |
t.references :docker_container_wizard_state, :null => false |
|
30 |
t.timestamps |
|
31 |
end |
|
32 |
|
|
33 |
create_table :docker_container_wizard_states_environments do |t| |
|
34 |
t.boolean :tty |
|
35 |
t.boolean :attach_stdin, :default => true |
|
36 |
t.boolean :attach_stdout, :default => true |
|
37 |
t.boolean :attach_stderr, :default => true |
|
38 |
t.references :docker_container_wizard_state, :null => false |
|
39 |
t.timestamps |
|
40 |
end |
|
41 |
end |
|
42 |
end |
lib/foreman_docker/engine.rb | ||
---|---|---|
53 | 53 |
end |
54 | 54 |
|
55 | 55 |
security_block :containers do |
56 |
permission :view_containers, :containers => [:index, :show, |
|
57 |
:auto_complete_repository_name, |
|
58 |
:auto_complete_tag, |
|
59 |
:search_repository] |
|
56 |
permission :view_containers, :containers => [:index, :show] |
|
60 | 57 |
permission :commit_containers, :containers => [:commit] |
61 | 58 |
permission :create_containers, :'containers/steps' => [:show, :update], |
62 | 59 |
:containers => [:new] |
... | ... | |
68 | 65 |
permission :create_registries, :registries => [:new, :create, :update, :edit] |
69 | 66 |
permission :destroy_registries, :registries => [:destroy] |
70 | 67 |
end |
68 |
|
|
69 |
security_block :image_search do |
|
70 |
permission :search_repository_image_search, |
|
71 |
:image_search => [:auto_complete_repository_name, |
|
72 |
:auto_complete_image_tag, |
|
73 |
:search_repository] |
|
74 |
end |
|
71 | 75 |
end |
72 | 76 |
|
73 | 77 |
end |
test/functionals/containers_steps_controller_test.rb | ||
---|---|---|
6 | 6 |
@container = FactoryGirl.create(:container) |
7 | 7 |
end |
8 | 8 |
|
9 |
test 'sets a docker repo and tag for a new container' do |
|
10 |
container_attrs = { :repository_name => 'centos', |
|
11 |
:tag => 'latest', |
|
12 |
:registry_id => '' |
|
13 |
} |
|
14 |
put :update, { :id => :image, |
|
15 |
:container_id => @container.id, |
|
16 |
:container => container_attrs }, set_session_user |
|
17 |
assert_response :found |
|
18 |
assert_redirected_to container_step_path(:container_id => @container.id, |
|
19 |
:id => :configuration) |
|
20 |
assert_equal "centos", @container.reload.repository_name |
|
21 |
assert_equal "latest", @container.tag |
|
22 |
end |
|
23 |
|
|
24 |
context 'container creation' do |
|
25 |
setup do |
|
26 |
@container.update_attribute(:repository_name, "centos") |
|
27 |
@container.update_attribute(:tag, "latest") |
|
28 |
end |
|
29 |
|
|
30 |
test 'uuid of the created container is saved at the end of the wizard' do |
|
31 |
Fog.mock! |
|
32 |
fake_container = @container.compute_resource.send(:client).servers.first |
|
33 |
ForemanDocker::Docker.any_instance.expects(:create_container).returns(fake_container) |
|
34 |
put :update, { :id => :environment, |
|
35 |
:container_id => @container.id }, set_session_user |
|
36 |
assert_equal fake_container.id, Container.find(@container.id).uuid |
|
37 |
end |
|
38 |
|
|
39 |
test 'errors are displayed when container creation fails' do |
|
40 |
Docker::Container.expects(:create).raises(Docker::Error::DockerError, 'some error') |
|
41 |
put :update, { :id => :environment, |
|
42 |
:container_id => @container.id }, set_session_user |
|
43 |
assert_template 'environment' |
|
44 |
assert_match(/some error/, flash[:error]) |
|
45 |
end |
|
46 |
end |
|
47 |
|
|
48 | 9 |
test 'wizard finishes with a redirect to the managed container' do |
49 |
get :show, { :id => :wicked_finish, |
|
50 |
:container_id => @container.id }, set_session_user |
|
10 |
state = DockerContainerWizardState.create! |
|
11 |
Service::Containers.expects(:start_container!).with(equals(state)).returns(@container) |
|
12 |
put :update, { :wizard_state_id => state.id, |
|
13 |
:id => :environment, |
|
14 |
:docker_container_wizard_states_environment => { :tty => false } }, |
|
15 |
set_session_user |
|
16 |
|
|
51 | 17 |
assert_redirected_to container_path(:id => @container.id) |
52 | 18 |
end |
53 | 19 |
end |
test/units/containers_service_test.rb | ||
---|---|---|
1 |
require 'test_plugin_helper' |
|
2 |
|
|
3 |
class ContainersServiceTest < ActiveSupport::TestCase |
|
4 |
setup do |
|
5 |
@state = DockerContainerWizardState.create! do |s| |
|
6 |
s.build_preliminary(:compute_resource_id => FactoryGirl.create(:docker_cr).id) |
|
7 |
s.build_image(:repository_name => 'test', :tag => 'test') |
|
8 |
s.build_configuration(:name => 'test') |
|
9 |
s.build_environment(:tty => false) |
|
10 |
end |
|
11 |
end |
|
12 |
|
|
13 |
test 'removes current state after successful container creation' do |
|
14 |
ForemanDocker::Docker.any_instance |
|
15 |
.expects(:create_container) |
|
16 |
.returns(OpenStruct.new(:uuid => 1)) |
|
17 |
Service::Containers.start_container!(@state) |
|
18 |
assert DockerContainerWizardState.where(:id => @state.id).count == 0 |
|
19 |
end |
|
20 |
end |
Also available in: Unified diff
fixes #7867: container creation wizard now tracks state in dedicated objects