katello-foreman-engine 0.0.1 → 0.0.2

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.
@@ -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