Project

General

Profile

Revision 6d101d7a

Added by Dmitri Dolguikh over 7 years ago

fixes #7867: container creation wizard now tracks state in dedicated objects

View differences:

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