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.
- data/katello-foreman-engine.gemspec +1 -2
- data/lib/katello-foreman-engine.rb +0 -1
- data/lib/katello_foreman_engine/actions/changeset_promote.rb +31 -0
- data/lib/katello_foreman_engine/actions/content_view_promote.rb +4 -1
- data/lib/katello_foreman_engine/actions/distribution_publish.rb +104 -0
- data/lib/katello_foreman_engine/actions/distribution_unpublish.rb +26 -0
- data/lib/katello_foreman_engine/actions/repository_change.rb +50 -0
- data/lib/katello_foreman_engine/actions/user_destroy.rb +1 -1
- data/lib/katello_foreman_engine/bindings.rb +136 -8
- data/lib/katello_foreman_engine/engine.rb +1 -0
- data/lib/katello_foreman_engine/helpers.rb +15 -0
- data/lib/katello_foreman_engine/settings.rb +6 -1
- data/test/lib/actions/distribution_publish_test.rb +124 -0
- data/test/lib/actions/distribution_unpublish_test.rb +33 -0
- data/test/lib/actions/{env_create.rb → env_create_test.rb} +7 -9
- data/test/lib/actions/{env_destroy.rb → env_destroy_test.rb} +5 -8
- data/test/lib/actions/{org_create.rb → org_create_test.rb} +0 -0
- data/test/lib/actions/{org_destroy.rb → org_destroy_test.rb} +2 -4
- data/test/lib/actions/repository_change_test.rb +61 -0
- data/test/test_helper.rb +60 -3
- metadata +13 -21
@@ -1,6 +1,6 @@
|
|
1
1
|
Gem::Specification.new do |s|
|
2
2
|
s.name = "katello-foreman-engine"
|
3
|
-
s.version = "0.0.
|
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
|
@@ -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(
|
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
|
@@ -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
|
-
|
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
|
|
@@ -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
|
-
|
14
|
-
|
15
|
-
assert_equal
|
16
|
-
assert_equal step.input['
|
17
|
-
assert_equal step.input['
|
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
|
-
|
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
|
-
|
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
|
-
|
17
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
30
|
+
EnvironmentDestroy.new('foreman_id' => '123').run
|
34
31
|
end
|
35
32
|
|
36
33
|
end
|
File without changes
|
@@ -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
|
-
|
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
|
-
|
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
|
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
|
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.
|
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/
|
88
|
-
- test/lib/actions/
|
89
|
-
- test/lib/actions/
|
90
|
-
- test/lib/actions/
|
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
|