foreman_docker 3.0.0 → 3.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (79) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +22 -22
  3. data/app/assets/javascripts/foreman_docker/image_step.js +36 -6
  4. data/app/controllers/api/v2/containers_controller.rb +13 -11
  5. data/app/controllers/containers/steps_controller.rb +8 -2
  6. data/app/controllers/containers_controller.rb +4 -3
  7. data/app/controllers/image_search_controller.rb +36 -79
  8. data/app/helpers/container_steps_helper.rb +21 -0
  9. data/app/models/concerns/foreman_docker/parameter_validators.rb +27 -4
  10. data/app/models/container.rb +9 -10
  11. data/app/models/docker_container_wizard_state.rb +2 -0
  12. data/app/models/docker_container_wizard_states/dns.rb +2 -8
  13. data/app/models/docker_container_wizard_states/environment.rb +4 -14
  14. data/app/models/docker_container_wizard_states/environment_variable.rb +2 -2
  15. data/app/models/docker_container_wizard_states/exposed_port.rb +2 -8
  16. data/app/models/docker_container_wizard_states/image.rb +30 -0
  17. data/app/models/docker_container_wizard_states/preliminary.rb +1 -1
  18. data/app/models/docker_parameter.rb +20 -0
  19. data/app/models/docker_registry.rb +6 -4
  20. data/app/models/environment_variable.rb +3 -3
  21. data/app/models/exposed_port.rb +4 -10
  22. data/app/models/foreman_docker/compute_resource_extensions.rb +11 -0
  23. data/app/models/foreman_docker/dns.rb +3 -9
  24. data/app/models/foreman_docker/docker.rb +1 -5
  25. data/app/models/service/containers.rb +15 -11
  26. data/app/models/service/registry_api.rb +87 -15
  27. data/app/services/foreman_docker/image_search.rb +92 -0
  28. data/app/views/containers/index.html.erb +1 -3
  29. data/app/views/containers/show.html.erb +1 -1
  30. data/app/views/containers/steps/_image_hub_tab.html.erb +39 -29
  31. data/app/views/containers/steps/_title.html.erb +1 -1
  32. data/app/views/containers/steps/preliminary.html.erb +1 -1
  33. data/app/views/foreman_docker/common_parameters/_dns_entry.html.erb +1 -1
  34. data/app/views/foreman_docker/common_parameters/_environment_variable.html.erb +1 -1
  35. data/app/views/foreman_docker/common_parameters/_exposed_port.html.erb +1 -1
  36. data/app/views/image_search/_repository_search_results.html.erb +1 -1
  37. data/app/views/registries/index.html.erb +1 -3
  38. data/app/views/registries/new.html.erb +1 -1
  39. data/db/migrate/20160605133025_create_docker_parameters.rb +13 -0
  40. data/db/migrate/20160605134652_move_parameters_to_docker_parameters.rb +27 -0
  41. data/lib/foreman_docker/engine.rb +6 -7
  42. data/lib/foreman_docker/version.rb +1 -1
  43. data/lib/tasks/test.rake +35 -0
  44. data/test/functionals/api/v2/containers_controller_test.rb +21 -0
  45. data/test/functionals/api/v2/registries_controller_test.rb +4 -3
  46. data/test/functionals/containers_controller_test.rb +5 -0
  47. data/test/functionals/containers_steps_controller_test.rb +74 -36
  48. data/test/functionals/image_search_controller_test.rb +166 -12
  49. data/test/integration/container_test.rb +1 -1
  50. data/test/test_plugin_helper.rb +10 -0
  51. data/test/units/container_test.rb +1 -1
  52. data/test/units/containers_service_test.rb +31 -9
  53. data/test/units/docker_container_wizard_states/image_test.rb +84 -0
  54. data/test/units/docker_registry_test.rb +27 -10
  55. data/test/units/foreman_docker/compute_resource_extensions_test.rb +10 -0
  56. data/test/units/image_search_service_test.rb +188 -0
  57. data/test/units/registry_api_test.rb +206 -12
  58. metadata +55 -36
  59. data/lib/foreman_docker/tasks/test.rake +0 -45
  60. data/locale/de/foreman_docker.edit.po +0 -631
  61. data/locale/de/foreman_docker.po.time_stamp +0 -0
  62. data/locale/es/foreman_docker.edit.po +0 -631
  63. data/locale/es/foreman_docker.po.time_stamp +0 -0
  64. data/locale/fr/foreman_docker.edit.po +0 -632
  65. data/locale/fr/foreman_docker.po.time_stamp +0 -0
  66. data/locale/it/foreman_docker.edit.po +0 -630
  67. data/locale/it/foreman_docker.po.time_stamp +0 -0
  68. data/locale/ja/foreman_docker.edit.po +0 -634
  69. data/locale/ja/foreman_docker.po.time_stamp +0 -0
  70. data/locale/ko/foreman_docker.edit.po +0 -629
  71. data/locale/ko/foreman_docker.po.time_stamp +0 -0
  72. data/locale/pt_BR/foreman_docker.edit.po +0 -631
  73. data/locale/pt_BR/foreman_docker.po.time_stamp +0 -0
  74. data/locale/ru/foreman_docker.edit.po +0 -630
  75. data/locale/ru/foreman_docker.po.time_stamp +0 -0
  76. data/locale/zh_CN/foreman_docker.edit.po +0 -628
  77. data/locale/zh_CN/foreman_docker.po.time_stamp +0 -0
  78. data/locale/zh_TW/foreman_docker.edit.po +0 -628
  79. data/locale/zh_TW/foreman_docker.po.time_stamp +0 -0
@@ -0,0 +1,92 @@
1
+ module ForemanDocker
2
+ class ImageSearch
3
+ def initialize(*args)
4
+ @sources = {}
5
+ args.each do |source|
6
+ add_source(source)
7
+ end
8
+ end
9
+
10
+ def add_source(source)
11
+ case source
12
+ when ForemanDocker::Docker
13
+ @sources[:compute_resource] ||= []
14
+ @sources[:compute_resource] << source
15
+ when Service::RegistryApi
16
+ @sources[:registry] ||= []
17
+ @sources[:registry] << source
18
+ end
19
+ end
20
+
21
+ def remove_source(source)
22
+ @sources.each do |_, sources|
23
+ sources.delete(source)
24
+ end
25
+ end
26
+
27
+ def search(query)
28
+ return [] if query[:term].blank? || query[:term] == ':'
29
+
30
+ unless query[:tags] == 'true'
31
+ images(query[:term])
32
+ else
33
+ tags(query[:term])
34
+ end
35
+ end
36
+
37
+ def images(query)
38
+ sources_results_for(:search, query)
39
+ end
40
+
41
+ def tags(query)
42
+ image_name, tag = query.split(':')
43
+ sources_results_for(:tags, image_name, tag)
44
+ .map { |tag_name| { 'name' => tag_name } }
45
+ end
46
+
47
+ def available?(query)
48
+ tags(query).present?
49
+ end
50
+
51
+ private
52
+
53
+ def registry_search(registry, term)
54
+ registry.search(term)['results']
55
+ end
56
+
57
+ def compute_resource_search(compute_resource, query)
58
+ images = compute_resource.local_images(query)
59
+ images.flat_map do |image|
60
+ image.info['RepoTags'].map do |tag|
61
+ { 'name' => tag.split(':').first }
62
+ end
63
+ end.uniq
64
+ end
65
+
66
+ def compute_resource_image(compute_resource, image_name)
67
+ compute_resource.image(image_name)
68
+ rescue ::Docker::Error::NotFoundError
69
+ nil
70
+ end
71
+
72
+ def compute_resource_tags(compute_resource, image_name, tag)
73
+ image = compute_resource_image(compute_resource, image_name)
74
+ image ? compute_resource.tags_for_local_image(image, tag) : []
75
+ end
76
+
77
+ def registry_tags(registry, image_name, tag)
78
+ registry.tags(image_name, tag).map { |t| t['name'] }
79
+ end
80
+
81
+ def sources_results_for(search, *args)
82
+ result = []
83
+ @sources.each do |kind, sources|
84
+ sources.each do |source|
85
+ result << self.send("#{kind}_#{search}", source, *args)
86
+ end
87
+ end
88
+ result.flatten.compact
89
+ end
90
+ end
91
+ end
92
+
@@ -1,8 +1,6 @@
1
1
  <% title _("Containers") %>
2
2
 
3
- <%= title_actions(display_link_if_authorized(
4
- _('New container'),
5
- hash_for_new_container_path)) %>
3
+ <%= title_actions(new_link(_("Create container"))) %>
6
4
 
7
5
  <ul class="nav nav-tabs" data-tabs="tabs">
8
6
  <% @container_resources.each_with_index do |resource, i| %>
@@ -69,7 +69,7 @@
69
69
  <td><%= _('Environment Variables') %></td>
70
70
  <td>
71
71
  <table id="environment_variables" class="table table-bordered" style="table-layout:fixed; word-wrap: break-word">
72
- <% (@container.in_fog.attributes['config_env'] || []).each do |environment_variable| %>
72
+ <% (@container.in_fog.environment_variables || []).each do |environment_variable| %>
73
73
  <% pair = environment_variable.split("=") %>
74
74
  <tr>
75
75
  <td><b><%= pair.first %></b></td>
@@ -4,42 +4,52 @@
4
4
  :url => wizard_path,
5
5
  :method => :put,
6
6
  :html => {:data => {:registry => registry}} do |f| %>
7
+
8
+ <% model.errors.messages.each do |field, field_errors| %>
9
+ <div class="alert alert-danger">
10
+ <span class="pficon pficon-error-circle-o"></span>
11
+ <ul>
12
+ <% field_errors.each do |message| %>
13
+ <li><%= message %></li>
14
+ <% end %>
15
+ </ul>
16
+ </div>
17
+ <% end %>
18
+
7
19
  <% if registry == "registry" -%>
8
20
  <div class="input-group col-md-6">
9
21
  <%= select_registry f %>
10
22
  </div>
11
23
  <% end -%>
12
24
 
13
- <div class="form-group">
14
- <div class='row'>
15
- <% help_type = f.object.errors[:repository_name].present? ? :help_block : :help_inline %>
16
- <%= text_f(
17
- f,
18
- :repository_name,
19
- :label => _('Search'),
20
- :size => 'col-md-6',
21
- :'data-url' => auto_complete_repository_name_image_search_path(model.compute_resource_id),
22
- :value => f.object.repository_name.present? ? f.object.repository_name : '',
23
- :'data-registry' => registry,
24
- :'data-search' => true,
25
- :focus_on_load => true,
26
- :placeholder => _('Find your favorite container, e.g. centos'),
27
- help_type => link_to_function(
28
- icon_text('search', ''),
29
- 'searchRepo(this)',
30
- :class => 'btn btn-default',
31
- :id => "search_repository_#{registry}",
32
- :'data-registry' => registry,
33
- :'data-url' => search_repository_image_search_path(model.compute_resource_id)
34
- ) + content_tag(:span, '', :id => 'image-confirmation').html_safe) %>
35
- </div>
36
- <div class='row'>
37
- <%= text_f f, :tag,
25
+ <% help_type = f.object.errors[:repository_name].present? ? :help_block : :help_inline %>
26
+ <%= text_f(f, :repository_name,
27
+ :label => _('Search'),
28
+ :size => 'col-md-6',
29
+ :wrapper_class => (image_search_wrapper_class(model) if tab_active?(registry)),
30
+ :'data-url' => auto_complete_repository_name_image_search_path(model.compute_resource_id),
31
+ :value => f.object.repository_name.present? ? f.object.repository_name : '',
32
+ :'data-registry' => registry,
33
+ :'data-image' => true,
34
+ :'data-search' => true,
35
+ :'data-min-length' => 1,
36
+ :focus_on_load => true,
37
+ :placeholder => _('Find your favorite container, e.g. centos'),
38
+ :control_group_id => "#{registry}_image_search",
39
+ help_type => link_to_function(
40
+ icon_text('search', ''),
41
+ 'searchRepo(this)',
42
+ :class => 'btn btn-default',
43
+ :id => "search_repository_#{registry}",
38
44
  :'data-registry' => registry,
39
- :'data-tag' => true,
40
- :'data-url' => auto_complete_image_tag_image_search_path(model.compute_resource_id) %>
41
- </div>
42
- </div>
45
+ :'data-url' => search_repository_image_search_path(model.compute_resource_id)
46
+ ) + content_tag(:span, '', :id => 'image-confirmation').html_safe) %>
47
+
48
+ <%= text_f f, :tag,
49
+ :control_group_id => "#{registry}_tag_search",
50
+ :'data-registry' => registry,
51
+ :'data-tag' => true,
52
+ :'data-url' => auto_complete_image_tag_image_search_path(model.compute_resource_id) %>
43
53
 
44
54
  <div class="col-md-12">
45
55
  <div data-search-spinner=true class='col-md-offset-3 hide'>
@@ -1,3 +1,3 @@
1
- <% title _("New container") %>
1
+ <% title _("Create container") %>
2
2
  <%= container_wizard(step) %>
3
3
  <%= yield %>
@@ -23,7 +23,7 @@
23
23
  <% else %>
24
24
 
25
25
  <div class="alert alert-warning alert-dismissable">
26
- <%= 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', new_compute_resource_path)).html_safe %>
26
+ <%= (_("You need a Docker compute resource in order to create containers. Please %s and try again.") % link_to('add a new one', new_compute_resource_path)).html_safe %>
27
27
  </div>
28
28
  <% end %>
29
29
  </div>
@@ -1,5 +1,5 @@
1
1
  <tr class="fields form-group <%= 'has-error' if f.object.errors.any? %>">
2
- <td><%= f.text_field(:name, :class => "form-control",
2
+ <td><%= f.text_field(:key, :class => "form-control",
3
3
  :placeholder => _("DNS e.g. 8.8.8.8")) %></td>
4
4
  <td style='vertical-align: middle' class='text-center'>
5
5
  <span class="help-block">
@@ -1,5 +1,5 @@
1
1
  <tr class="fields form-group <%= 'error' if f.object.errors.any? %>">
2
- <td><%= f.text_field(:name, :class => "form-control",
2
+ <td><%= f.text_field(:key, :class => "form-control",
3
3
  :placeholder => _("Name, e.g. PING_HOST")) %></td>
4
4
  <td><%= f.text_field(:value, :class => "form-control",
5
5
  :placeholder => _("Value, e.g. example.org")) %></td>
@@ -1,5 +1,5 @@
1
1
  <tr class="fields form-group <%= 'has-error' if f.object.errors.any? %>">
2
- <td><%= f.text_field(:name, :class => "form-control",
2
+ <td><%= f.text_field(:key, :class => "form-control",
3
3
  :placeholder => _("Port number e.g. 22")) %></td>
4
4
  <td><%= f.select :value, [['TCP','tcp'],['UDP','udp']] %></td>
5
5
  <td style='vertical-align: middle' class='text-center'>
@@ -1,5 +1,5 @@
1
1
  <% repositories.each do |repository| %>
2
- <h3><%= link_to repository['name'], '#', :onclick => 'repoSelected(this)', "data-hub" => use_hub %></h3>
2
+ <h3><%= link_to cleanup_image_name(repository['name']), '#', :onclick => 'repoSelected(this)', "data-hub" => use_hub %></h3>
3
3
  <p>
4
4
  <%= '<span class="glyphicon glyphicon-certificate" title="Official"></span>'.html_safe if repository['is_official'] %>
5
5
  <%= '<span class="glyphicon glyphicon-thumbs-up" title="Trusted"></span>'.html_safe if repository['is_trusted'] %>
@@ -1,8 +1,6 @@
1
1
  <% title _("Registries") %>
2
2
 
3
- <%= title_actions(display_link_if_authorized(
4
- _('New registry'),
5
- hash_for_new_registry_path)) %>
3
+ <%= title_actions(new_link(_("Create Registry"))) %>
6
4
 
7
5
  <table class="table table-bordered table-striped table-condensed" data-table="inline">
8
6
  </thead>
@@ -1,3 +1,3 @@
1
- <% title _("New Registry") %>
1
+ <% title _("Create Registry") %>
2
2
 
3
3
  <%= render :partial => 'form' %>
@@ -0,0 +1,13 @@
1
+ class CreateDockerParameters < ActiveRecord::Migration
2
+ def change
3
+ create_table :docker_parameters do |t|
4
+ t.string :key, :limit => 255
5
+ t.text :value
6
+ t.string :type, :limit => 255
7
+ t.integer :reference_id
8
+ t.timestamps
9
+ end
10
+
11
+ add_index :docker_parameters, [:type, :reference_id, :key], :unique => true
12
+ end
13
+ end
@@ -0,0 +1,27 @@
1
+ class MoveParametersToDockerParameters < ActiveRecord::Migration
2
+ class FakeDockerParameter < ActiveRecord::Base
3
+ self.table_name = 'docker_parameters'
4
+ end
5
+
6
+ class FakeParameter < ActiveRecord::Base
7
+ self.table_name = 'parameters'
8
+ end
9
+
10
+ def up
11
+ # All the DockerContainerWizardStates::PARAMETER are temporary for the wizard step so no need to keep them
12
+ docker_params = FakeParameter.unscoped.where(:type => ['EnvironmentVariable', 'ForemanDocker::Dns', 'ExposedPort'])
13
+ docker_params.each do |param|
14
+ DockerParameter.create(:key => param['name'], :value => param['value'], :reference_id => param['reference_id'], :type => param['type'])
15
+ end
16
+ docker_params.delete_all
17
+ end
18
+
19
+ def down
20
+ docker_params = FakeDockerParameter.unscoped.where(:type => ['EnvironmentVariable', 'ForemanDocker::Dns', 'ExposedPort'])
21
+ docker_params.each do |param|
22
+ Parameter.create(:key => param['name'], :value => param['value'], :reference_id => param['reference_id'], :type => param['type'])
23
+ end
24
+
25
+ docker_params.delete_all
26
+ end
27
+ end
@@ -42,15 +42,15 @@ module ForemanDocker
42
42
 
43
43
  initializer 'foreman_docker.register_plugin', :before => :finisher_hook do
44
44
  Foreman::Plugin.register :foreman_docker do
45
- requires_foreman '>= 1.11'
45
+ requires_foreman '>= 1.15'
46
46
  compute_resource ForemanDocker::Docker
47
47
 
48
48
  sub_menu :top_menu, :containers_menu, :caption => N_('Containers'),
49
49
  :after => :monitor_menu do
50
- menu :top_menu, :containers, :caption => N_('All containers'),
50
+ menu :top_menu, :containers, :caption => N_('All Containers'),
51
51
  :url_hash => { :controller => :containers,
52
52
  :action => :index }
53
- menu :top_menu, :new_container, :caption => N_('New container'),
53
+ menu :top_menu, :new_container, :caption => N_('Create Container'),
54
54
  :url_hash => { :controller => :containers,
55
55
  :action => :new }
56
56
  menu :top_menu, :registries, :caption => N_('Registries'),
@@ -103,6 +103,8 @@ module ForemanDocker
103
103
  :resource_type => 'Docker/ImageSearch'
104
104
  end
105
105
 
106
+ add_all_permissions_to_default_roles
107
+
106
108
  parameter_filter ComputeResource, :email
107
109
 
108
110
  # apipie API documentation
@@ -127,10 +129,6 @@ module ForemanDocker
127
129
  end
128
130
  end
129
131
 
130
- rake_tasks do
131
- load "#{ForemanDocker::Engine.root}/lib/foreman_docker/tasks/test.rake"
132
- end
133
-
134
132
  require 'fog/fogdocker/models/compute/server'
135
133
  require 'fog/fogdocker/models/compute/image'
136
134
  require 'fog/fogdocker/models/compute/images'
@@ -146,6 +144,7 @@ module ForemanDocker
146
144
  # Compatibility fixes - to be removed once 1.7 compatibility is no longer required
147
145
  Fog::Compute::Fogdocker::Images.send(:include, ::FogExtensions::Fogdocker::Images)
148
146
  ::Taxonomy.send(:include, ForemanDocker::TaxonomyExtensions)
147
+ ComputeResource.send(:include, ForemanDocker::ComputeResourceExtensions)
149
148
  end
150
149
  end
151
150
  end
@@ -1,3 +1,3 @@
1
1
  module ForemanDocker
2
- VERSION = '3.0.0'
2
+ VERSION = '3.1.0'
3
3
  end
@@ -0,0 +1,35 @@
1
+ namespace :test do
2
+ desc "Test ForemanDocker"
3
+ Rake::TestTask.new(:docker) do |t|
4
+ test_dir = File.join(File.dirname(__FILE__), '../..', 'test')
5
+ t.libs << ['test', test_dir]
6
+ t.pattern = "#{test_dir}/**/*_test.rb"
7
+ t.verbose = false
8
+ t.warning = false
9
+ end
10
+ end
11
+
12
+ namespace :docker do
13
+ task :rubocop do
14
+ begin
15
+ require 'rubocop/rake_task'
16
+ RuboCop::RakeTask.new(:rubocop_docker) do |task|
17
+ task.patterns = ["#{ForemanDocker::Engine.root}/app/**/*.rb",
18
+ "#{ForemanDocker::Engine.root}/lib/**/*.rb",
19
+ "#{ForemanDocker::Engine.root}/test/**/*.rb"]
20
+ end
21
+ rescue
22
+ puts "Rubocop not loaded."
23
+ end
24
+
25
+ Rake::Task['rubocop_docker'].invoke
26
+ end
27
+ end
28
+
29
+ Rake::Task[:test].enhance ['test:docker']
30
+
31
+ load 'tasks/jenkins.rake'
32
+ if Rake::Task.task_defined?(:'jenkins:unit')
33
+ Rake::Task["jenkins:unit"].enhance ['test:docker',
34
+ 'docker:rubocop']
35
+ end
@@ -3,6 +3,11 @@ require 'test_plugin_helper'
3
3
  module Api
4
4
  module V2
5
5
  class ContainersControllerTest < ActionController::TestCase
6
+ setup do
7
+ stub_image_existance
8
+ stub_registry_api
9
+ end
10
+
6
11
  test 'index returns a list of all containers' do
7
12
  get :index, {}, set_session_user
8
13
  assert_response :success
@@ -109,6 +114,21 @@ module Api
109
114
  :tag => tag }
110
115
  assert_response :created
111
116
  end
117
+
118
+ test 'creates a container with correct params' do
119
+ repository_name = "centos"
120
+ tag = "8"
121
+ name = "foo2"
122
+ Service::Containers.any_instance.expects(:pull_image).returns(true)
123
+ Service::Containers.any_instance.expects(:start_container).returns(true)
124
+ post :create, :container => { :compute_resource_id => @compute_resource.id,
125
+ :name => name,
126
+ :registry_id => @registry.id,
127
+ :repository_name => repository_name,
128
+ :tag => tag,
129
+ :environment_variables => [{:key => 'ping_host', :value => 'example.com'}]}
130
+ assert_response :created
131
+ end
112
132
  end
113
133
 
114
134
  test 'creates a katello container with correct params' do
@@ -145,6 +165,7 @@ module Api
145
165
  :repository_name => 'centos',
146
166
  :tag => 'latest' }
147
167
  assert_response :unprocessable_entity
168
+ assert_match /Name has already been taken/, @response.body
148
169
  end
149
170
  end
150
171
  end
@@ -43,15 +43,16 @@ module Api
43
43
 
44
44
  test 'update a docker registry' do
45
45
  DockerRegistry.any_instance.stubs(:attempt_login)
46
- put :update, :id => @registry.id, :registry => { :name => 'hello_world' }
46
+ new_name = 'hello_world'
47
+ put :update, :id => @registry.id, :registry => { :name => new_name }
47
48
  assert_response :success
48
- assert DockerRegistry.exists?(:name => 'hello_world')
49
+ assert_equal new_name, @registry.reload.name
49
50
  end
50
51
 
51
52
  test 'deletes a docker registry' do
52
53
  delete :destroy, :id => @registry.id
53
54
  assert_response :success
54
- refute DockerRegistry.exists?(@registry.id)
55
+ assert DockerRegistry.where(:id => @registry.id).blank?
55
56
  end
56
57
  end
57
58
  end