katello-foreman-engine 0.0.1 → 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,6 +1,6 @@
1
1
  Gem::Specification.new do |s|
2
2
  s.name = "katello-foreman-engine"
3
- s.version = "0.0.1"
3
+ s.version = "0.0.2"
4
4
 
5
5
  s.authors = ["Katello"]
6
6
  s.date = "2013-04-19"
@@ -11,7 +11,6 @@ Gem::Specification.new do |s|
11
11
  s.licenses = ["GPL-2"]
12
12
  s.require_paths = ["lib"]
13
13
  s.add_dependency "foreman_api"
14
- s.add_dependency "deface", "~> 0.7.2"
15
14
  s.add_dependency "dynflow"
16
15
  s.summary = "Foreman specific parts of Katello"
17
16
  end
@@ -1,2 +1 @@
1
- require 'deface'
2
1
  require 'katello_foreman_engine'
@@ -0,0 +1,31 @@
1
+ #
2
+ # Copyright 2013 Red Hat, Inc.
3
+ #
4
+ # This software is licensed to you under the GNU General Public
5
+ # License as published by the Free Software Foundation; either version
6
+ # 2 of the License (GPLv2) or (at your option) any later version.
7
+ # There is NO WARRANTY for this software, express or implied,
8
+ # including the implied warranties of MERCHANTABILITY,
9
+ # NON-INFRINGEMENT, or FITNESS FOR A PARTICULAR PURPOSE. You should
10
+ # have received a copy of GPLv2 along with this software; if not, see
11
+ # http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
12
+
13
+ module KatelloForemanEngine
14
+ module Actions
15
+
16
+ class ChangesetPromote < Dynflow::Action
17
+
18
+ def self.subscribe
19
+ Katello::Actions::ChangesetPromote
20
+ end
21
+
22
+ def plan(changeset)
23
+ changeset.affected_repos.each do |repo|
24
+ repo = repo.get_clone(changeset.environment)
25
+ plan_action(RepositoryChange, repo)
26
+ end
27
+ end
28
+
29
+ end
30
+ end
31
+ end
@@ -6,10 +6,13 @@ module KatelloForemanEngine
6
6
  Katello::Actions::ContentViewPromote
7
7
  end
8
8
 
9
- def plan(*args)
9
+ def plan(content_view, from_env, to_env)
10
10
  unless Bindings.environment_find(input['organization_label'], input['to_env_label'], input['label'])
11
11
  plan_self input
12
12
  end
13
+ content_view.repos(to_env) do |repo|
14
+ plan_action(RepositoryChange, repo)
15
+ end
13
16
  end
14
17
 
15
18
  input_format do
@@ -0,0 +1,104 @@
1
+ module KatelloForemanEngine
2
+ module Actions
3
+ class DistributionPublish < Dynflow::Action
4
+
5
+ input_format do
6
+ param :family, String, "Example: Red Hat Enterprise Linux"
7
+ param :variant, String, "Example: Server"
8
+ param :arch, String, "Example: x86_64"
9
+ param :version, String, "Example: 6.3"
10
+ param :repo, Hash do
11
+ param :pulp_id
12
+ param :uri, String, "Example: https://example.com/pulp/repos/org/env/pr/os/"
13
+ param :label
14
+ param :product_label
15
+ param :content_view_label
16
+ param :environment_label
17
+ param :organization_label
18
+ end
19
+ end
20
+
21
+ def run
22
+ medium_name = construct_medium_name
23
+ medium_path = Helpers.installation_media_path(input['repo']['uri'])
24
+ return if Bindings.medium_find(medium_path)
25
+
26
+ arch = find_or_create_arch
27
+ os = find_or_create_operating_system
28
+ assign_arch_to_os(os, arch)
29
+ medium = Bindings.medium_create(medium_name, medium_path)
30
+ assign_medium_to_os(os, medium)
31
+ end
32
+
33
+ private
34
+
35
+ def find_or_create_arch
36
+ arch = Bindings.architecture_find(input['arch']) ||
37
+ Bindings.architecture_create(input['arch'])
38
+ return arch
39
+ end
40
+
41
+ def find_or_create_operating_system
42
+ os_name = construct_operating_system_name
43
+ major, minor = input['version'].split('.')
44
+
45
+ os = Bindings.operating_system_find(os_name, major, minor)
46
+ unless os
47
+ os = Bindings.operating_system_create(os_name, major, minor)
48
+ end
49
+
50
+ return os
51
+ end
52
+
53
+ def assign_arch_to_os(os, arch)
54
+ if os['architectures']
55
+ arch_ids = os['architectures'].map { |a| a['architecture']['id'] }
56
+ else
57
+ arch_ids = []
58
+ end
59
+ unless arch_ids.include?(arch['id'])
60
+ arch_ids << arch['id']
61
+ data = {'architecture_ids' => arch_ids}
62
+ Bindings.operating_system_update(os['id'], data)
63
+ end
64
+ end
65
+
66
+ def assign_medium_to_os(os, medium)
67
+ if os['media']
68
+ medium_ids = os['media'].map { |a| a['medium']['id'] }
69
+ else
70
+ medium_ids = []
71
+ end
72
+ unless medium_ids.include?(medium['id'])
73
+ medium_ids << medium['id']
74
+ data = {'medium_ids' => medium_ids}
75
+ Bindings.operating_system_update(os['id'], data)
76
+ end
77
+ end
78
+
79
+
80
+ def construct_medium_name
81
+ parts = []
82
+ parts << [
83
+ input['repo']['organization_label'],
84
+ input['repo']['environment_label'],
85
+ input['repo']['content_view_label']
86
+ ].compact.join('/')
87
+ parts << input['family']
88
+ parts << input['variant']
89
+ parts << input['version']
90
+ parts << input['arch']
91
+ name = parts.join(' ')
92
+ # we need to make the name a bit shorter to get under 50
93
+ # charatcers for medium name
94
+ name.sub!('Red Hat Enterprise Linux','RHEL')
95
+ return name
96
+ end
97
+
98
+ def construct_operating_system_name
99
+ [input['family'], input['variant']].join(' ').gsub(' ', '_')
100
+ end
101
+
102
+ end
103
+ end
104
+ end
@@ -0,0 +1,26 @@
1
+ module KatelloForemanEngine
2
+ module Actions
3
+ class DistributionUnpublish < Dynflow::Action
4
+
5
+ def self.subscribe
6
+ Katello::Actions::RepositoryDestroy
7
+ end
8
+
9
+ input_format do
10
+ param :medium_id, String
11
+ end
12
+
13
+ def plan(repo)
14
+ path = Helpers.installation_media_path(repo.uri)
15
+ if medium = Bindings.medium_find(path)
16
+ plan_self('medium_id' => medium['id'])
17
+ end
18
+ end
19
+
20
+ def run
21
+ Bindings.medium_destroy(input['medium_id'])
22
+ end
23
+
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,50 @@
1
+ #
2
+ # Copyright 2013 Red Hat, Inc.
3
+ #
4
+ # This software is licensed to you under the GNU General Public
5
+ # License as published by the Free Software Foundation; either version
6
+ # 2 of the License (GPLv2) or (at your option) any later version.
7
+ # There is NO WARRANTY for this software, express or implied,
8
+ # including the implied warranties of MERCHANTABILITY,
9
+ # NON-INFRINGEMENT, or FITNESS FOR A PARTICULAR PURPOSE. You should
10
+ # have received a copy of GPLv2 along with this software; if not, see
11
+ # http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
12
+
13
+ module KatelloForemanEngine
14
+ module Actions
15
+
16
+ class RepositoryChange < Dynflow::Action
17
+
18
+ def plan(repo)
19
+ if repo.distributions.empty?
20
+ # no distributions, no instalation media
21
+ plan_action(DistributionUnpublish, repo)
22
+ elsif(repo.unprotected)
23
+ repo_info = {
24
+ 'pulp_id' => repo.pulp_id,
25
+ 'uri' => repo.uri,
26
+ 'label' => repo.label,
27
+ 'product_label' => repo.product.label,
28
+ 'environment_label' => repo.environment.label,
29
+ 'organization_label' => repo.organization.label
30
+ }
31
+
32
+ if repo.content_view && !repo.content_view.default?
33
+ repo_info['content_view_label'] = repo.content_view.label
34
+ end
35
+
36
+ # Foreman's installation media don't distinguish between
37
+ # different variants. Using just a first one.
38
+ distribution = repo.distributions.first
39
+ plan_action(DistributionPublish,
40
+ { 'repo' => repo_info,
41
+ 'family' => distribution.family,
42
+ 'variant' => distribution.variant,
43
+ 'arch' => distribution.arch,
44
+ 'version' => distribution.version })
45
+ end
46
+ end
47
+
48
+ end
49
+ end
50
+ end
@@ -8,7 +8,7 @@ module KatelloForemanEngine
8
8
 
9
9
  def plan(user)
10
10
  if foreman_user = Bindings.user_find(input['username'])
11
- plan_self 'foreman_user_id' => foreman_user['user']['id']
11
+ plan_self 'foreman_user_id' => foreman_user['id']
12
12
  end
13
13
  end
14
14
 
@@ -24,6 +24,26 @@ module KatelloForemanEngine
24
24
  resource(ForemanApi::Resources::Environment)
25
25
  end
26
26
 
27
+ def architecture
28
+ resource(ForemanApi::Resources::Architecture)
29
+ end
30
+
31
+ def ptable
32
+ resource(ForemanApi::Resources::Ptable)
33
+ end
34
+
35
+ def operating_system
36
+ resource(ForemanApi::Resources::OperatingSystem)
37
+ end
38
+
39
+ def config_template
40
+ resource(ForemanApi::Resources::ConfigTemplate)
41
+ end
42
+
43
+ def medium
44
+ resource(ForemanApi::Resources::Medium)
45
+ end
46
+
27
47
  def user(username = nil)
28
48
  user_resource = resource(ForemanApi::Resources::User)
29
49
  if username && User.current.username == username
@@ -34,12 +54,6 @@ module KatelloForemanEngine
34
54
  return user_resource
35
55
  end
36
56
 
37
- def resource(resource_class)
38
- client = resource_class.new(client_config)
39
- client.client.options[:headers][:foreman_user] = User.current.username
40
- return client
41
- end
42
-
43
57
  def organization_find(name)
44
58
  orgs, _ = base.http_call('get', '/api/organizations', 'search' => "name = #{name}")
45
59
  return orgs.first
@@ -77,8 +91,7 @@ module KatelloForemanEngine
77
91
  end
78
92
 
79
93
  def user_find(username)
80
- users, _ = user(username).index('search' => "login = #{username}")
81
- return users.first
94
+ find_resource(user(username), "login = #{username}")
82
95
  end
83
96
 
84
97
  def user_create(username, email)
@@ -93,6 +106,121 @@ module KatelloForemanEngine
93
106
  user.destroy('id' => id)
94
107
  end
95
108
 
109
+ def architecture_find(name)
110
+ find_resource(architecture, "name = #{name}")
111
+ end
112
+
113
+ def architecture_create(name)
114
+ without_root_key { architecture.create('architecture' => {'name' => name}) }
115
+ end
116
+
117
+ def operating_system_find(name, major, minor)
118
+ find_resource(operating_system, "name = #{name} AND major = #{major} AND minor = #{minor}")
119
+ end
120
+
121
+ def operating_system_create(name, major, minor)
122
+ data = {
123
+ 'name' => name,
124
+ 'major' => major.to_s,
125
+ 'minor' => minor.to_s,
126
+ 'family' => Settings['foreman_os_family']
127
+ }
128
+ templates_to_add = [template_find(Settings['foreman_os_provisioning_template']),
129
+ template_find(Settings['foreman_os_pxe_template'])].compact
130
+ data['os_default_templates_attributes'] = templates_to_add.map do |template|
131
+ {
132
+ "config_template_id" => template["id"],
133
+ "template_kind_id" => template["template_kind"]["id"],
134
+ }
135
+ end
136
+
137
+ if ptable = ptable_find(Settings['foreman_os_ptable'])
138
+ data['ptable_ids'] = [ptable['id']]
139
+ end
140
+
141
+ os = without_root_key { operating_system.create('operatingsystem' => data) }
142
+
143
+ oss, _ = operating_system.index
144
+ os_ids = oss.map { |o| o['operatingsystem']['id'] }
145
+ templates_to_add.each do |template|
146
+ # Because of http://projects.theforeman.org/issues/2500 we
147
+ # have not way to add only the created os to the template.
148
+ # As a workaround, we add all os to the template for now.
149
+ config_template.update("id" => template['id'],
150
+ 'config_template' => {
151
+ "operatingsystem_ids" => os_ids
152
+ })
153
+ end
154
+ return os
155
+ end
156
+
157
+ def operating_system_update(id, data)
158
+ without_root_key do
159
+ operating_system.update('id' => id, 'operatingsystem' => data)
160
+ end
161
+ end
162
+
163
+ def template_find(name)
164
+ find_resource(config_template, %{name = "#{name}"})
165
+ end
166
+
167
+ def medium_find(path)
168
+ find_resource(medium, %{path = "#{path}"})
169
+ end
170
+
171
+ def medium_create(name, path)
172
+ without_root_key do
173
+ self.medium.create('medium' => {
174
+ 'name' => name,
175
+ 'path' => path,
176
+ 'os_family' => Settings['foreman_os_family']})
177
+ end
178
+ end
179
+
180
+ def medium_destroy(id)
181
+ self.medium.destroy('id' => id)
182
+ end
183
+
184
+ def ptable_find(name)
185
+ find_resource(ptable, %{name = "#{name}"})
186
+ end
187
+
188
+ private
189
+
190
+ # configure resource client to be used to call Foreman.
191
+ # We need to do this for every resoruce right now.
192
+ # We might improve this on foreman_api side later.
193
+ def resource(resource_class)
194
+ client = resource_class.new(client_config)
195
+ client.client.options[:headers][:foreman_user] = User.current.username
196
+ return client
197
+ end
198
+
199
+ # From Foreman, the resource comes in form:
200
+ #
201
+ # { 'resource' => { 'attr1' => 'val1', 'attr2' => 'val2' } }
202
+ #
203
+ # this method returns only the body, i.e.:
204
+ #
205
+ # { 'attr1' => 'val1', 'attr2' => 'val2' }
206
+ #
207
+ # If block given, it expects the call to foreman_api from that
208
+ #
209
+ # We might improve this on foreman_api side later
210
+ def without_root_key(resource_hash = nil, &block)
211
+ if block
212
+ resource_hash, _ = yield
213
+ end
214
+ if resource_hash
215
+ resource_hash.values.first
216
+ end
217
+ end
218
+
219
+ def find_resource(resource, search_query)
220
+ results, _ = resource.index('search' => search_query)
221
+ return without_root_key(results.first)
222
+ end
223
+
96
224
  end
97
225
  end
98
226
 
@@ -4,6 +4,7 @@ module KatelloForemanEngine
4
4
  class Engine < ::Rails::Engine
5
5
 
6
6
  config.after_initialize do
7
+ require 'katello_foreman_engine/helpers'
7
8
  require 'katello_foreman_engine/settings'
8
9
  Settings.initialize_settings
9
10
  require 'katello_foreman_engine/bindings'
@@ -0,0 +1,15 @@
1
+ module KatelloForemanEngine
2
+ module Helpers
3
+ class << self
4
+
5
+ # takes repo uri from Katello and makes installation media url
6
+ # suitable for provisioning from it
7
+ def installation_media_path(repo_uri)
8
+ path = repo_uri.sub(/\Ahttps/, 'http')
9
+ path << "/" unless path.end_with?('/')
10
+ return path
11
+ end
12
+ end
13
+
14
+ end
15
+ end
@@ -5,7 +5,12 @@ module KatelloForemanEngine
5
5
  @settings = {
6
6
  'foreman_url' => Katello.config.foreman.url.sub(/\/+\Z/,''),
7
7
  'oauth_consumer_key' => Katello.config.foreman.oauth_key,
8
- 'oauth_consumer_secret' => Katello.config.foreman.oauth_secret
8
+ 'oauth_consumer_secret' => Katello.config.foreman.oauth_secret,
9
+ # TODO: make the following options configurable:
10
+ 'foreman_os_family' => 'Redhat',
11
+ 'foreman_os_provisioning_template' => 'Katello Kickstart Default',
12
+ 'foreman_os_pxe_template' => 'Kickstart default PXElinux',
13
+ 'foreman_os_ptable' => 'RedHat default',
9
14
  }
10
15
  end
11
16
 
@@ -0,0 +1,124 @@
1
+ require 'test_helper'
2
+
3
+ module KatelloForemanEngine
4
+ module Actions
5
+ class DistributionPublishTest < ActiveSupport::TestCase
6
+
7
+ def setup
8
+ @input = {
9
+ 'family' => 'Red Hat Enterprise Linux',
10
+ 'variant' => 'Server',
11
+ 'arch' => 'x86_64',
12
+ 'version' => '6.3',
13
+ 'repo' => {
14
+ 'pulp_id' => 'Org-Env-Prod-Repo',
15
+ 'uri' => 'http://example.com/pulp/repos/os/',
16
+ 'label' => 'Repo',
17
+ 'product_label' => 'Prod',
18
+ 'environment_label' => 'Env',
19
+ 'organization_label' => 'Org'
20
+ }
21
+ }
22
+
23
+ @arch = 'x86_64'
24
+ @os_name = 'Red_Hat_Enterprise_Linux_Server'
25
+ @os_major = '6'
26
+ @os_minor = '3'
27
+
28
+ @medium_name = 'Org/Env Red Hat Enterprise Linux Server 6.3 x86_64'
29
+ @medium_path = 'http://example.com/pulp/repos/os/'
30
+
31
+ @arch_output = {'architecture' => { 'id' => 1, 'name' => @arch }}
32
+ @ptable_output = {'ptable' => { 'id' => 1, 'name' => 'RedHat default' }}
33
+ @os_output = {
34
+ 'operatingsystem' => {
35
+ 'id' => 1,
36
+ 'name' => @os_name,
37
+ 'major' => @os_major,
38
+ 'minor' => @os_minor,
39
+ 'family' => 'RedHat',
40
+ 'architectures' => [@arch_output],
41
+ 'media' => [],
42
+ 'ptables' => [@ptable_output],
43
+ }
44
+ }
45
+ @medium_output = {
46
+ 'medium' => {
47
+ 'id' => 1,
48
+ 'name' => @medium_name,
49
+ 'path' => @medium_path
50
+ }
51
+ }
52
+
53
+ stub_foreman_search(:architecture, "name = #{@arch}", @arch_output)
54
+ stub_foreman_search(:ptable, %{name = "RedHat default"}, @ptable_output)
55
+ stub_foreman_call(:medium, :index, nil, [])
56
+ stub_foreman_call(:medium, :create, nil, @medium_output)
57
+ stub_foreman_call(:operating_system, :index, nil, [])
58
+ stub_foreman_call(:operating_system, :create, nil, @os_output)
59
+ stub_foreman_call(:operating_system, :update)
60
+ stub_foreman_search(:config_template, %{name = "Katello Kickstart Default"}, nil)
61
+ stub_foreman_search(:config_template, %{name = "Kickstart default PXElinux"}, nil)
62
+ stub_foreman_search(:ptable, %{name = "RedHat default"}, nil)
63
+ stub_foreman_call(:operating_system, :index, nil, [])
64
+ end
65
+
66
+ def run_action
67
+ action = DistributionPublish.new(@input)
68
+ action.run
69
+ return action
70
+ end
71
+
72
+ test "creates architecture in foreman if not created yet" do
73
+ stub_foreman_search(:architecture, "name = #{@arch}", nil)
74
+ expect_foreman_call(:architecture, :create, {'name' => @arch}, @arch_output)
75
+ run_action
76
+ end
77
+
78
+ test "creates operating system in foreman if not created yet" do
79
+ stub_foreman_search(:operating_system, "name = #{@os_name} AND major = #{@os_major} AND minor = #{@os_minor}", nil)
80
+ os_data = {
81
+ 'name' => @os_name,
82
+ 'major' => @os_major.to_s,
83
+ 'minor' => @os_minor.to_s,
84
+ 'family' => 'Redhat',
85
+ 'os_default_templates_attributes' => [],
86
+ }
87
+ expect_foreman_call(:operating_system, :create, os_data, @os_output)
88
+ run_action
89
+ end
90
+
91
+ test "creates sets minor version empty if missing" do
92
+ stub_foreman_search(:operating_system, "name = #{@os_name} AND major = #{@os_major} AND minor = ", nil)
93
+ os_data = {
94
+ 'name' => @os_name,
95
+ 'major' => @os_major.to_s,
96
+ 'minor' => '',
97
+ 'family' => 'Redhat',
98
+ 'os_default_templates_attributes' => [],
99
+ }
100
+ expect_foreman_call(:operating_system, :create, os_data, @os_output)
101
+ @input['version'] = '6'
102
+ run_action
103
+ end
104
+
105
+ test "assigns architecture to operating system if not assigned yet" do
106
+ os_without_arch = {
107
+ 'operatingsystem' => @os_output['operatingsystem'].merge('architectures' => [])
108
+ }
109
+ stub_foreman_search(:operating_system, "name = #{@os_name} AND major = #{@os_major} AND minor = #{@os_minor}", os_without_arch)
110
+ expected_data = {'id' => 1, 'architecture_ids' => [@arch_output['architecture']['id']]}
111
+ expect_foreman_call(:operating_system, :update, expected_data)
112
+ run_action
113
+ end
114
+
115
+ test "creates medium and assigns it to the os in not created yet" do
116
+ expect_foreman_call(:medium, :create, {'name' => @medium_name, 'path' => @medium_path, 'os_family' => 'Redhat'}, @medium_output)
117
+ expected_data = {'id' => 1, 'medium_ids' => [@medium_output['medium']['id']]}
118
+ expect_foreman_call(:operating_system, :update, expected_data)
119
+ run_action
120
+ end
121
+
122
+ end
123
+ end
124
+ end
@@ -0,0 +1,33 @@
1
+ require 'test_helper'
2
+
3
+ module KatelloForemanEngine
4
+ module Actions
5
+ class DistributionUnpublishTest < ActiveSupport::TestCase
6
+
7
+ def setup
8
+ @https_path = "https://example.com/my/repo"
9
+ @http_path = "http://example.com/my/repo/"
10
+ @medium_output = {'medium' => {'id' => '123'}}
11
+ @repo = stub(:uri => @https_path)
12
+ end
13
+
14
+ test "deletes the instalation media using the repo" do
15
+ stub_foreman_search(:medium, %{path = "#{@http_path}"}, @medium_output)
16
+ step = run_steps(DistributionUnpublish, {}, @repo).first
17
+ assert_equal DistributionUnpublish, step.action_class
18
+ assert_equal({'medium_id' => '123'}, step.input)
19
+ end
20
+
21
+ test "does nothing if the installation media is not present" do
22
+ stub_foreman_search(:medium, %{path = "#{@http_path}"}, [])
23
+ assert_equal [], run_steps(DistributionUnpublish, {}, @repo)
24
+ end
25
+
26
+ test 'calls bindings to destroy environment' do
27
+ expect_foreman_call(:medium, :destroy, {'id' => '123'})
28
+ DistributionUnpublish.new('medium_id' => '123').run
29
+ end
30
+
31
+ end
32
+ end
33
+ end
@@ -10,21 +10,19 @@ module KatelloForemanEngine
10
10
  env.organization = org
11
11
 
12
12
  env.library = false
13
- plan = prepare_plan(EnvCreate, {}, env)
14
- step = plan.run_steps.first
15
- assert_equal EnvCreate, step.action_class
16
- assert_equal step.input['org_label'], 'org'
17
- assert_equal step.input['label'], 'dev'
18
- assert_equal step.input['cv_id'], 'env'
13
+ step = run_steps(EnvironmentCreate, {}, env).first
14
+ assert_equal EnvironmentCreate, step.action_class
15
+ assert_equal 'org', step.input['org_label']
16
+ assert_equal 'dev', step.input['label']
17
+ assert_equal 'env', step.input['content_view_id']
19
18
 
20
19
  env.library = true
21
- plan = prepare_plan(EnvCreate, {}, env)
22
- assert_equal [], plan.run_steps
20
+ assert_equal [], run_steps(EnvironmentCreate, {}, env)
23
21
  end
24
22
 
25
23
  test 'calls bindings to create environment' do
26
24
  Bindings.expects(:environment_create).with('env', 'org', 'dev')
27
- EnvCreate.new('org_label' => 'org', 'label' => 'dev', 'cv_id' => 'env').run
25
+ EnvironmentCreate.new('org_label' => 'org', 'label' => 'dev', 'content_view_id' => 'env').run
28
26
  end
29
27
 
30
28
  end
@@ -13,24 +13,21 @@ module KatelloForemanEngine
13
13
  Bindings.expects(:environment_find).with('org', 'dev').returns(foreman_env)
14
14
 
15
15
  env.library = false
16
- plan = prepare_plan(EnvDestroy,{}, env)
17
- step = plan.run_steps.first
18
- assert_equal EnvDestroy, step.action_class
16
+ step = run_steps(EnvironmentDestroy,{}, env).first
17
+ assert_equal EnvironmentDestroy, step.action_class
19
18
  assert_equal step.input['foreman_id'], '123'
20
19
 
21
20
  env.library = true
22
- plan = prepare_plan(EnvDestroy, {}, env)
23
- assert_equal [], plan.run_steps
21
+ assert_equal [], run_steps(EnvironmentDestroy,{}, env)
24
22
 
25
23
  env.library = false
26
24
  Bindings.expects(:environment_find).returns(nil)
27
- plan = prepare_plan(EnvDestroy, {}, env)
28
- assert_equal [], plan.run_steps
25
+ assert_equal [], run_steps(EnvironmentDestroy,{}, env)
29
26
  end
30
27
 
31
28
  test 'calls bindings to destroy environment' do
32
29
  Bindings.expects(:environment_destroy).with('123')
33
- EnvDestroy.new('foreman_id' => '123').run
30
+ EnvironmentDestroy.new('foreman_id' => '123').run
34
31
  end
35
32
 
36
33
  end
@@ -7,14 +7,12 @@ module KatelloForemanEngine
7
7
  test "runs only when the org is present in Foreman" do
8
8
  foreman_org = { 'organization' => { 'id' => '123' } }
9
9
  Bindings.expects(:organization_find).with('KT-[test]').returns(foreman_org)
10
- plan = prepare_plan(OrgDestroy, {'label' => 'test'}, nil)
11
- step = plan.run_steps.first
10
+ step = run_steps(OrgDestroy, {'label' => 'test'}, nil).first
12
11
  assert_equal OrgDestroy, step.action_class
13
12
  assert_equal step.input['foreman_id'], '123'
14
13
 
15
14
  Bindings.expects(:organization_find).returns(nil)
16
- plan = prepare_plan(OrgDestroy, {'label' => 'test'}, nil)
17
- assert_equal [], plan.run_steps
15
+ assert_equal [], run_steps(OrgDestroy, {'label' => 'test'}, nil)
18
16
  end
19
17
 
20
18
  test 'calls bindings to destroy organization' do
@@ -0,0 +1,61 @@
1
+ require 'test_helper'
2
+
3
+ module KatelloForemanEngine
4
+ module Actions
5
+ class RepositoryChangeTest < ActiveSupport::TestCase
6
+
7
+ def setup
8
+ @repo_with_distros = stub(:unprotected => true,
9
+ :distributions => [stub('family' => 'Family',
10
+ 'variant' => 'Variant',
11
+ 'arch' => 'Arch',
12
+ 'version' => 'Version')],
13
+ :pulp_id => 'pulp_id',
14
+ :uri => 'https://example.com/repo/uri',
15
+ :label => 'label',
16
+ :product => stub(:label => 'product_label'),
17
+ :content_view => stub(:default? => true, :label => 'cv'),
18
+ :environment => stub(:label => 'environment_label'),
19
+ :organization => stub(:label => 'organization_label'))
20
+
21
+ @expected_publish_input = {
22
+ "repo"=>
23
+ {
24
+ "pulp_id"=>"pulp_id",
25
+ "uri"=>"https://example.com/repo/uri",
26
+ "label"=>"label",
27
+ "product_label"=>"product_label",
28
+ "environment_label"=>"environment_label",
29
+ "organization_label"=>"organization_label"
30
+ },
31
+ "family"=>"Family",
32
+ "variant"=>"Variant",
33
+ "arch"=>"Arch",
34
+ "version"=>"Version"
35
+ }
36
+ end
37
+
38
+ test "plans repository unpublish if no distros found for the repo" do
39
+ repo = stub(:distributions => [])
40
+ action_class, arg = planned_actions(RepositoryChange, {}, repo).first
41
+ assert_equal DistributionUnpublish, action_class
42
+ assert_equal repo, arg
43
+ end
44
+
45
+ test "plans distribution publish if repo is unprotected and has distirbutions" do
46
+ action_class, input = planned_actions(RepositoryChange, {}, @repo_with_distros).first
47
+ assert_equal DistributionPublish, action_class
48
+ assert_equal @expected_publish_input, input
49
+ end
50
+
51
+ test "passes the content view label unless repo in default content view" do
52
+ @repo_with_distros.content_view.stubs(:default? => false)
53
+ action_class, input = planned_actions(RepositoryChange, {}, @repo_with_distros).first
54
+ assert_equal DistributionPublish, action_class
55
+ @expected_publish_input['repo']['content_view_label'] = 'cv'
56
+ assert_equal input, @expected_publish_input
57
+ end
58
+
59
+ end
60
+ end
61
+ end
data/test/test_helper.rb CHANGED
@@ -11,10 +11,67 @@ require 'mocha/setup'
11
11
 
12
12
  Rails.backtrace_cleaner.remove_silencers!
13
13
 
14
- # returns the execution plan for given action, given
14
+ # returns the subactions being planned from the plan method of
15
+ # +action_class+. It prevents calling plan methods on the subactions,
16
+ # letting to test only the action_class in isolation.
17
+ def planned_actions(action_class, input, *args)
18
+ planned_actions = []
19
+ action = action_class.new(input)
20
+ action.stubs(:plan_action).with do |*args|
21
+ planned_actions << args
22
+ end
23
+ action.plan(*args)
24
+ return planned_actions
25
+ end
26
+
27
+ # returns the run steps planned for given action, given
15
28
  # input from parent action and *args for plan method
16
- def prepare_plan(action_class, input, *args)
29
+ def run_steps(action_class, input, *args)
17
30
  action = action_class.new(input)
18
31
  action.plan(*args)
19
- return action.execution_plan
32
+ return action.execution_plan.run_steps
33
+ end
34
+
35
+ def expect_foreman_search(*args)
36
+ args = args + [true]
37
+ stub_foreman_search(*args)
38
+ end
39
+
40
+ def stub_foreman_search(resource, search, response, expect = false)
41
+ response = case response
42
+ when nil
43
+ []
44
+ when Array
45
+ response
46
+ else
47
+ [response]
48
+ end
49
+ stub_foreman_call(resource, :index, {'search' => search}, response, expect)
50
+ end
51
+
52
+ def expect_foreman_call(*args)
53
+ args = args + [true]
54
+ stub_foreman_call(*args)
55
+ end
56
+
57
+ def stub_foreman_call(resource, action, request = nil, response = nil, expect = false)
58
+ setup_user
59
+ resource_key = resource.to_s
60
+ # difference between class name and resource key in the API
61
+ resource_key.gsub!('_','') if resource_key == 'operating_system'
62
+ if request && [:create, :update].include?(action) && !request.has_key?(resource_key)
63
+ request = {resource_key => request}
64
+ end
65
+ resource_class ="ForemanApi::Resources::#{resource.to_s.camelize}".constantize
66
+ stub = resource_class.any_instance.stubs(action)
67
+ if request
68
+ stub.with(request)
69
+ end
70
+ if response
71
+ stub.returns([response, response.to_json])
72
+ end
73
+ end
74
+
75
+ def setup_user
76
+ User.current ||= User.new(:username => 'admin')
20
77
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: katello-foreman-engine
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 0.0.2
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -27,22 +27,6 @@ dependencies:
27
27
  - - ! '>='
28
28
  - !ruby/object:Gem::Version
29
29
  version: '0'
30
- - !ruby/object:Gem::Dependency
31
- name: deface
32
- requirement: !ruby/object:Gem::Requirement
33
- none: false
34
- requirements:
35
- - - ~>
36
- - !ruby/object:Gem::Version
37
- version: 0.7.2
38
- type: :runtime
39
- prerelease: false
40
- version_requirements: !ruby/object:Gem::Requirement
41
- none: false
42
- requirements:
43
- - - ~>
44
- - !ruby/object:Gem::Version
45
- version: 0.7.2
46
30
  - !ruby/object:Gem::Dependency
47
31
  name: dynflow
48
32
  requirement: !ruby/object:Gem::Requirement
@@ -72,22 +56,30 @@ files:
72
56
  - katello-foreman-engine.gemspec
73
57
  - lib/katello-foreman-engine.rb
74
58
  - lib/katello_foreman_engine.rb
59
+ - lib/katello_foreman_engine/actions/changeset_promote.rb
75
60
  - lib/katello_foreman_engine/actions/content_view_demote.rb
76
61
  - lib/katello_foreman_engine/actions/content_view_promote.rb
62
+ - lib/katello_foreman_engine/actions/distribution_publish.rb
63
+ - lib/katello_foreman_engine/actions/distribution_unpublish.rb
77
64
  - lib/katello_foreman_engine/actions/environment_create.rb
78
65
  - lib/katello_foreman_engine/actions/environment_destroy.rb
79
66
  - lib/katello_foreman_engine/actions/org_create.rb
80
67
  - lib/katello_foreman_engine/actions/org_destroy.rb
68
+ - lib/katello_foreman_engine/actions/repository_change.rb
81
69
  - lib/katello_foreman_engine/actions/user_create.rb
82
70
  - lib/katello_foreman_engine/actions/user_destroy.rb
83
71
  - lib/katello_foreman_engine/bindings.rb
84
72
  - lib/katello_foreman_engine/engine.rb
73
+ - lib/katello_foreman_engine/helpers.rb
85
74
  - lib/katello_foreman_engine/settings.rb
86
75
  - script/rails
87
- - test/lib/actions/env_create.rb
88
- - test/lib/actions/env_destroy.rb
89
- - test/lib/actions/org_create.rb
90
- - test/lib/actions/org_destroy.rb
76
+ - test/lib/actions/distribution_publish_test.rb
77
+ - test/lib/actions/distribution_unpublish_test.rb
78
+ - test/lib/actions/env_create_test.rb
79
+ - test/lib/actions/env_destroy_test.rb
80
+ - test/lib/actions/org_create_test.rb
81
+ - test/lib/actions/org_destroy_test.rb
82
+ - test/lib/actions/repository_change_test.rb
91
83
  - test/lib/bindings_test.rb
92
84
  - test/lib/settings_test.rb
93
85
  - test/test_helper.rb