foreman_docker 3.0.0 → 3.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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