hammer_cli_csv 1.0.0 → 1.0.1
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.
- checksums.yaml +8 -8
- data/config/cli_config.yml +30 -0
- data/config/csv.yml +2 -0
- data/lib/hammer_cli_csv.rb +5 -0
- data/lib/hammer_cli_csv/activation_keys.rb +36 -33
- data/lib/hammer_cli_csv/base.rb +82 -17
- data/lib/hammer_cli_csv/content_hosts.rb +100 -98
- data/lib/hammer_cli_csv/content_view_filters.rb +6 -0
- data/lib/hammer_cli_csv/content_views.rb +58 -37
- data/lib/hammer_cli_csv/export.rb +1 -1
- data/lib/hammer_cli_csv/host_collections.rb +21 -31
- data/lib/hammer_cli_csv/import.rb +13 -10
- data/lib/hammer_cli_csv/lifecycle_environments.rb +9 -3
- data/lib/hammer_cli_csv/products.rb +44 -23
- data/lib/hammer_cli_csv/provisioning_templates.rb +61 -29
- data/lib/hammer_cli_csv/roles.rb +8 -8
- data/lib/hammer_cli_csv/splice.rb +376 -0
- data/lib/hammer_cli_csv/subscriptions.rb +6 -16
- data/lib/hammer_cli_csv/sync_plans.rb +122 -0
- data/lib/hammer_cli_csv/users.rb +6 -2
- data/lib/hammer_cli_csv/version.rb +1 -1
- data/test/data/content-hosts.csv +3 -3
- data/test/data/content-view-filters.csv +1 -1
- data/test/data/organizations.csv +0 -1
- data/test/data/roles.csv +0 -1
- data/test/data/subscriptions.csv +0 -2
- metadata +6 -2
@@ -15,25 +15,35 @@ module HammerCLICsv
|
|
15
15
|
command_name 'provisioning-templates'
|
16
16
|
desc 'import or export provisioning templates'
|
17
17
|
|
18
|
+
option %w(--organization), 'ORGANIZATION', 'Only process organization matching this name'
|
19
|
+
|
18
20
|
ORGANIZATIONS = 'Organizations'
|
19
21
|
LOCATIONS = 'Locations'
|
22
|
+
OPERATINGSYSTEMS = 'Operating Systems'
|
23
|
+
ASSOCIATIONS = 'Host Group / Puppet Environment Combinations'
|
20
24
|
KIND = 'Kind'
|
21
25
|
TEMPLATE = 'Template'
|
22
26
|
|
23
27
|
def export
|
24
28
|
CSV.open(option_csv_file || '/dev/stdout', 'wb', {:force_quotes => true}) do |csv|
|
25
|
-
csv << [NAME, COUNT, ORGANIZATIONS, LOCATIONS, KIND, TEMPLATE]
|
29
|
+
csv << [NAME, COUNT, ORGANIZATIONS, LOCATIONS, OPERATINGSYSTEMS, ASSOCIATIONS, KIND, TEMPLATE]
|
26
30
|
@api.resource(:config_templates).call(:index, {
|
27
31
|
:per_page => 999999
|
28
32
|
})['results'].each do |template_id|
|
29
33
|
template = @api.resource(:config_templates).call(:show, {:id => template_id['id']})
|
34
|
+
next if template['locked']
|
35
|
+
next unless option_organization.nil? || template['organizations'].detect { |org| org['name'] == option_organization }
|
30
36
|
name = template['name']
|
31
37
|
count = 1
|
32
38
|
kind = template['snippet'] ? 'snippet' : template['template_kind_name']
|
33
39
|
organizations = export_column(template, 'organizations', 'name')
|
34
40
|
locations = export_column(template, 'locations', 'name')
|
41
|
+
operatingsystems = export_column(template, 'operatingsystems', 'fullname')
|
42
|
+
# TODO: puppet environments for content views are not present in api
|
43
|
+
# http://projects.theforeman.org/issues/10293
|
44
|
+
associations = export_associations(template)
|
35
45
|
unless name == 'Boot disk iPXE - generic host' || name == 'Boot disk iPXE - host'
|
36
|
-
csv << [name, count, organizations, locations, kind, template['template']]
|
46
|
+
csv << [name, count, organizations, locations, operatingsystems, associations, kind, template['template']]
|
37
47
|
end
|
38
48
|
end
|
39
49
|
end
|
@@ -56,81 +66,103 @@ module HammerCLICsv
|
|
56
66
|
organizations = collect_column(line[ORGANIZATIONS]) do |organization|
|
57
67
|
foreman_organization(:name => organization)
|
58
68
|
end
|
69
|
+
if option_organization
|
70
|
+
org_id = foreman_organization(:name => option_organization)
|
71
|
+
return if org_id.nil? || !organizations.include?(org_id)
|
72
|
+
organizations = [org_id]
|
73
|
+
end
|
59
74
|
locations = collect_column(line[LOCATIONS]) do |location|
|
60
75
|
foreman_location(:name => location)
|
61
76
|
end
|
77
|
+
operatingsystems = collect_column(line[OPERATINGSYSTEMS]) do |operatingsystem|
|
78
|
+
foreman_operatingsystem(:name => operatingsystem)
|
79
|
+
end
|
62
80
|
|
63
81
|
line[COUNT].to_i.times do |number|
|
64
82
|
name = namify(line[NAME], number)
|
65
83
|
if !@existing.include? name
|
66
|
-
print "Creating provisioning template '
|
84
|
+
print _("Creating provisioning template '%{name}'...") % {:name => name } if option_verbose?
|
67
85
|
template_id = @api.resource(:config_templates).call(:create, {
|
68
|
-
'
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
86
|
+
'config_template' => {
|
87
|
+
'name' => name,
|
88
|
+
'snippet' => line[KIND] == 'snippet',
|
89
|
+
'template_kind_id' => line[KIND] == 'snippet' ? nil : foreman_template_kind(:name => line[KIND]),
|
90
|
+
'operatingsystem_ids' => operatingsystems,
|
91
|
+
'location_ids' => locations,
|
92
|
+
'template' => line[TEMPLATE]
|
93
|
+
}
|
74
94
|
})['id']
|
75
95
|
else
|
76
|
-
print "Updating provisioning template '
|
96
|
+
print _("Updating provisioning template '%{name}'...") % {:name => name} if option_verbose?
|
77
97
|
template_id = @api.resource(:config_templates).call(:update, {
|
78
98
|
'id' => @existing[name],
|
79
|
-
'
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
99
|
+
'config_template' => {
|
100
|
+
'name' => name,
|
101
|
+
'snippet' => line[KIND] == 'snippet',
|
102
|
+
'template_kind_id' => line[KIND] == 'snippet' ? nil : foreman_template_kind(:name => line[KIND]),
|
103
|
+
'operatingsystem_ids' => operatingsystems,
|
104
|
+
'location_ids' => locations,
|
105
|
+
'template' => line[TEMPLATE]
|
106
|
+
}
|
85
107
|
})['id']
|
86
108
|
end
|
87
109
|
@existing[name] = template_id
|
88
110
|
|
89
111
|
# Update associated resources
|
90
|
-
template_organizations ||= {}
|
112
|
+
@template_organizations ||= {}
|
91
113
|
organizations.each do |organization_id|
|
92
|
-
if template_organizations[organization_id].nil?
|
93
|
-
template_organizations[organization_id] = @api.resource(:organizations).call(:show, {
|
114
|
+
if @template_organizations[organization_id].nil?
|
115
|
+
@template_organizations[organization_id] = @api.resource(:organizations).call(:show, {
|
94
116
|
'id' => organization_id
|
95
117
|
})['config_templates'].collect do |template|
|
96
118
|
template['id']
|
97
119
|
end
|
98
120
|
end
|
99
|
-
if
|
100
|
-
template_organizations[organization_id]
|
121
|
+
if !@template_organizations[organization_id].include? template_id
|
122
|
+
@template_organizations[organization_id] << template_id
|
101
123
|
@api.resource(:organizations).call(:update, {
|
102
124
|
'id' => organization_id,
|
103
125
|
'organization' => {
|
104
|
-
'config_template_ids' => template_organizations[organization_id]
|
126
|
+
'config_template_ids' => @template_organizations[organization_id]
|
105
127
|
}
|
106
128
|
})
|
107
129
|
end
|
108
130
|
end
|
109
|
-
template_locations ||= {}
|
131
|
+
@template_locations ||= {}
|
110
132
|
locations.each do |location_id|
|
111
|
-
if template_locations[location_id].nil?
|
112
|
-
template_locations[location_id] = @api.resource(:locations).call(:show, {
|
133
|
+
if @template_locations[location_id].nil?
|
134
|
+
@template_locations[location_id] = @api.resource(:locations).call(:show, {
|
113
135
|
'id' => location_id
|
114
136
|
})['config_templates'].collect do |template|
|
115
137
|
template['id']
|
116
138
|
end
|
117
139
|
end
|
118
|
-
if
|
119
|
-
template_locations[location_id] += [template_id]
|
140
|
+
if !@template_locations[location_id].include? template_id
|
141
|
+
@template_locations[location_id] += [template_id]
|
120
142
|
@api.resource(:locations).call(:update, {
|
121
143
|
'id' => location_id,
|
122
144
|
'location' => {
|
123
|
-
'config_template_ids' => template_locations[location_id]
|
145
|
+
'config_template_ids' => @template_locations[location_id]
|
124
146
|
}
|
125
147
|
})
|
126
148
|
end
|
127
149
|
end
|
128
150
|
|
129
|
-
|
151
|
+
puts _('done') if option_verbose?
|
130
152
|
end
|
131
153
|
rescue RuntimeError => e
|
132
154
|
raise "#{e}\n #{line[NAME]}"
|
133
155
|
end
|
156
|
+
|
157
|
+
def export_associations(template)
|
158
|
+
return '' unless template['template_combinations']
|
159
|
+
values = CSV.generate do |column|
|
160
|
+
column << template['template_combinations'].collect do |combo|
|
161
|
+
"#{combo['hostgroup_name']}|#{combo['environment_name']}"
|
162
|
+
end
|
163
|
+
end
|
164
|
+
values.delete!("\n")
|
165
|
+
end
|
134
166
|
end
|
135
167
|
end
|
136
168
|
end
|
data/lib/hammer_cli_csv/roles.rb
CHANGED
@@ -84,9 +84,7 @@ module HammerCLICsv
|
|
84
84
|
@existing_roles[name] = role['id']
|
85
85
|
else
|
86
86
|
print "Updating role '#{name}'..." if option_verbose?
|
87
|
-
|
88
|
-
'id' => @existing_roles[name]
|
89
|
-
})
|
87
|
+
# Nothing to update on the role object itself, just filters below
|
90
88
|
end
|
91
89
|
|
92
90
|
filter_id = foreman_filter(name, line[RESOURCE], search)
|
@@ -104,11 +102,13 @@ module HammerCLICsv
|
|
104
102
|
print " updating filter #{line[RESOURCE]}..."
|
105
103
|
@api.resource(:filters).call(:update, {
|
106
104
|
'id' => filter_id,
|
107
|
-
'
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
105
|
+
'filter' => {
|
106
|
+
'search' => search,
|
107
|
+
'unlimited' => search.nil? || search.empty?,
|
108
|
+
'organization_ids' => organizations,
|
109
|
+
'location_ids' => locations,
|
110
|
+
'permission_ids' => permissions
|
111
|
+
}
|
112
112
|
})
|
113
113
|
end
|
114
114
|
|
@@ -0,0 +1,376 @@
|
|
1
|
+
# Copyright 2013-2014 Red Hat, Inc.
|
2
|
+
#
|
3
|
+
# This software is licensed to you under the GNU General Public
|
4
|
+
# License as published by the Free Software Foundation; either version
|
5
|
+
# 2 of the License (GPLv2) or (at your option) any later version.
|
6
|
+
# There is NO WARRANTY for this software, express or implied,
|
7
|
+
# including the implied warranties of MERCHANTABILITY,
|
8
|
+
# NON-INFRINGEMENT, or FITNESS FOR A PARTICULAR PURPOSE. You should
|
9
|
+
# have received a copy of GPLv2 along with this software; if not, see
|
10
|
+
# http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
|
11
|
+
|
12
|
+
require 'openssl'
|
13
|
+
require 'date'
|
14
|
+
|
15
|
+
module HammerCLICsv
|
16
|
+
class CsvCommand
|
17
|
+
class SpliceCommand < BaseCommand
|
18
|
+
command_name 'splice'
|
19
|
+
desc 'import Satellite-5 splice data'
|
20
|
+
|
21
|
+
option %w(--organization), 'ORGANIZATION', 'Only process organization matching this name'
|
22
|
+
option %w(--dir), 'DIR',
|
23
|
+
'Directory of Splice exported CSV files (default pwd)'
|
24
|
+
option %w(--mapping-dir), 'DIR',
|
25
|
+
'Directory of Splice product mapping files (default /usr/share/rhsm/product/RHEL-6)'
|
26
|
+
|
27
|
+
UUID = 'server_id'
|
28
|
+
ORGANIZATION = 'organization'
|
29
|
+
ORGANIZATION_ID = 'org_id'
|
30
|
+
NAME = 'name'
|
31
|
+
HOSTNAME = 'hostname'
|
32
|
+
IP_ADDRESS = 'ip_address'
|
33
|
+
IPV6_ADDRESS = 'ipv6_address'
|
34
|
+
REGISTERED_BY = 'registered_by'
|
35
|
+
REGISTRATION_TIME = 'registration_time'
|
36
|
+
LAST_CHECKIN_TIME = 'last_checkin_time'
|
37
|
+
PRODUCTS = 'software_channel'
|
38
|
+
ENTITLEMENTS = 'entitlements'
|
39
|
+
HOSTCOLLECTIONS = 'system_group'
|
40
|
+
VIRTUAL_HOST = 'virtual_host'
|
41
|
+
ARCHITECTURE = 'architecture'
|
42
|
+
HARDWARE = 'hardware'
|
43
|
+
MEMORY = 'memory'
|
44
|
+
SOCKETS = 'sockets'
|
45
|
+
IS_VIRTUALIZED = 'is_virtualized'
|
46
|
+
|
47
|
+
def import
|
48
|
+
@existing = {}
|
49
|
+
load_product_mapping
|
50
|
+
preload_host_guests
|
51
|
+
|
52
|
+
filename = option_dir + '/splice-export'
|
53
|
+
thread_import(false, filename, NAME) do |line|
|
54
|
+
create_content_hosts_from_csv(line) unless line[UUID][0] == '#'
|
55
|
+
end
|
56
|
+
|
57
|
+
update_host_guests
|
58
|
+
delete_unfound_hosts(@existing)
|
59
|
+
end
|
60
|
+
|
61
|
+
def create_content_hosts_from_csv(line)
|
62
|
+
return if option_organization && line[ORGANIZATION] != option_organization
|
63
|
+
|
64
|
+
if !@existing[line[ORGANIZATION]]
|
65
|
+
create_organization(line)
|
66
|
+
@existing[line[ORGANIZATION]] = {}
|
67
|
+
|
68
|
+
# Fetching all content hosts is too slow and times out due to the complexity of the data
|
69
|
+
# rendered in the json.
|
70
|
+
# http://projects.theforeman.org/issues/6307
|
71
|
+
total = @api.resource(:systems).call(:index, {
|
72
|
+
'organization_id' => foreman_organization(:name => line[ORGANIZATION]),
|
73
|
+
'per_page' => 1
|
74
|
+
})['total'].to_i
|
75
|
+
(total / 20 + 2).to_i.times do |page|
|
76
|
+
@api.resource(:systems).call(:index, {
|
77
|
+
'organization_id' => foreman_organization(:name => line[ORGANIZATION]),
|
78
|
+
'page' => page,
|
79
|
+
'per_page' => 20
|
80
|
+
})['results'].each do |host|
|
81
|
+
@existing[line[ORGANIZATION]][host['name']] = host['uuid'] if host
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
name = "#{line[NAME]}-#{line[UUID]}"
|
87
|
+
#checkin_time = Time.parse(line[LAST_CHECKIN_TIME]).strftime("%a, %d %b %Y %H:%M:%S %z")
|
88
|
+
checkin_time = if line[LAST_CHECKIN_TIME].casecmp('now').zero?
|
89
|
+
DateTime.now.strftime("%a, %d %b %Y %H:%M:%S %z")
|
90
|
+
else
|
91
|
+
DateTime.parse(line[LAST_CHECKIN_TIME]).strftime("%a, %d %b %Y %H:%M:%S %z")
|
92
|
+
end
|
93
|
+
|
94
|
+
if !@existing[line[ORGANIZATION]].include? name
|
95
|
+
print(_("Creating content host '%{name}'...") % {:name => name}) if option_verbose?
|
96
|
+
host_id = @api.resource(:systems).call(:create, {
|
97
|
+
'name' => name,
|
98
|
+
'organization_id' => foreman_organization(:name => line[ORGANIZATION]),
|
99
|
+
'environment_id' => lifecycle_environment(line[ORGANIZATION], :name => 'Library'),
|
100
|
+
'content_view_id' => katello_contentview(line[ORGANIZATION], :name => 'Default Organization View'),
|
101
|
+
'last_checkin' => checkin_time,
|
102
|
+
'facts' => facts(name, line),
|
103
|
+
'installed_products' => products(line),
|
104
|
+
'type' => 'system'
|
105
|
+
})['uuid']
|
106
|
+
|
107
|
+
# last_checkin is not updated in candlepin on creation
|
108
|
+
# https://bugzilla.redhat.com/show_bug.cgi?id=1212122
|
109
|
+
@api.resource(:systems).call(:update, {
|
110
|
+
'id' => host_id,
|
111
|
+
'system' => {
|
112
|
+
'last_checkin' => checkin_time
|
113
|
+
},
|
114
|
+
'last_checkin' => checkin_time
|
115
|
+
})
|
116
|
+
|
117
|
+
else
|
118
|
+
print(_("Updating content host '%{name}'...") % {:name => name}) if option_verbose?
|
119
|
+
host_id = @api.resource(:systems).call(:update, {
|
120
|
+
'id' => @existing[line[ORGANIZATION]][name],
|
121
|
+
'system' => {
|
122
|
+
'name' => name,
|
123
|
+
'environment_id' => lifecycle_environment(line[ORGANIZATION], :name => 'Library'),
|
124
|
+
'content_view_id' => katello_contentview(line[ORGANIZATION], :name => 'Default Organization View'),
|
125
|
+
'last_checkin' => checkin_time,
|
126
|
+
'facts' => facts(name, line),
|
127
|
+
'installed_products' => products(line)
|
128
|
+
},
|
129
|
+
'installed_products' => products(line), # TODO: http://projects.theforeman.org/issues/9191
|
130
|
+
'last_checkin' => checkin_time
|
131
|
+
})['uuid']
|
132
|
+
|
133
|
+
@existing[line[ORGANIZATION]].delete(name) # Remove to indicate found
|
134
|
+
end
|
135
|
+
|
136
|
+
if @hosts.include? line[UUID]
|
137
|
+
@hosts[line[UUID]] = host_id
|
138
|
+
elsif @guests.include? line[UUID]
|
139
|
+
@guests[line[UUID]] = "#{line[ORGANIZATION]}/#{name}"
|
140
|
+
end
|
141
|
+
|
142
|
+
update_host_collections(host_id, line)
|
143
|
+
|
144
|
+
puts _('done') if option_verbose?
|
145
|
+
rescue RuntimeError => e
|
146
|
+
raise "#{e}\n #{line}"
|
147
|
+
end
|
148
|
+
|
149
|
+
private
|
150
|
+
|
151
|
+
def facts(name, line)
|
152
|
+
facts = {}
|
153
|
+
facts['system.certificate_version'] = '3.2' # Required for auto-attach to work
|
154
|
+
facts['network.hostname'] = line[NAME]
|
155
|
+
facts['network.ipv4_address'] = line[IP_ADDRESS]
|
156
|
+
facts['network.ipv6_address'] = line[IPV6_ADDRESS]
|
157
|
+
facts['memory.memtotal'] = line[MEMORY]
|
158
|
+
facts['uname.machine'] = line[ARCHITECTURE]
|
159
|
+
facts['virt.is_guest'] = line[IS_VIRTUALIZED] == 'Yes' ? true : false
|
160
|
+
facts['virt.uuid'] = "#{line[ORGANIZATION]}/#{name}" if facts['virt.is_guest']
|
161
|
+
|
162
|
+
# 1 CPUs 1 Sockets; eth0 10.11....
|
163
|
+
hardware = line[HARDWARE].split(' ')
|
164
|
+
if hardware[1] == 'CPUs'
|
165
|
+
facts['cpu.cpu(s)'] = hardware[0] unless hardware[0] == 'unknown'
|
166
|
+
facts['cpu.cpu_socket(s)'] = hardware[2] unless hardware[0] == 'unknown'
|
167
|
+
# facts['cpu.core(s)_per_socket'] Not present in data
|
168
|
+
end
|
169
|
+
|
170
|
+
facts
|
171
|
+
end
|
172
|
+
|
173
|
+
def update_host_collections(host_id, line)
|
174
|
+
return nil if !line[HOSTCOLLECTIONS]
|
175
|
+
|
176
|
+
@existing_hostcollections ||= {}
|
177
|
+
if @existing_hostcollections[line[ORGANIZATION]].nil?
|
178
|
+
@existing_hostcollections[line[ORGANIZATION]] = {}
|
179
|
+
@api.resource(:host_collections).call(:index, {
|
180
|
+
:per_page => 999999,
|
181
|
+
'organization_id' => foreman_organization(:name => line[ORGANIZATION])
|
182
|
+
})['results'].each do |hostcollection|
|
183
|
+
@existing_hostcollections[line[ORGANIZATION]][hostcollection['name']] = hostcollection['id']
|
184
|
+
end
|
185
|
+
end
|
186
|
+
|
187
|
+
CSV.parse_line(line[HOSTCOLLECTIONS], {:col_sep => ';'}).each do |hostcollection_name|
|
188
|
+
if @existing_hostcollections[line[ORGANIZATION]][hostcollection_name].nil?
|
189
|
+
hostcollection_id = @api.resource(:host_collections).call(:create, {
|
190
|
+
'organization_id' => foreman_organization(:name => line[ORGANIZATION]),
|
191
|
+
'name' => hostcollection_name,
|
192
|
+
'unlimited_content_hosts' => true,
|
193
|
+
'max_content_hosts' => nil
|
194
|
+
})['id']
|
195
|
+
@existing_hostcollections[line[ORGANIZATION]][hostcollection_name] = hostcollection_id
|
196
|
+
end
|
197
|
+
|
198
|
+
@api.resource(:host_collections).call(:add_systems, {
|
199
|
+
'id' => @existing_hostcollections[line[ORGANIZATION]][hostcollection_name],
|
200
|
+
'system_ids' => [host_id]
|
201
|
+
})
|
202
|
+
end
|
203
|
+
end
|
204
|
+
|
205
|
+
def products(line)
|
206
|
+
return nil if !line[PRODUCTS]
|
207
|
+
products = CSV.parse_line(line[PRODUCTS], {:col_sep => ';'}).collect do |channel|
|
208
|
+
product = @product_mapping[channel]
|
209
|
+
if product.nil?
|
210
|
+
# puts _("WARNING: No product found for channel '%{name}'") % {:name => channel}
|
211
|
+
next
|
212
|
+
end
|
213
|
+
product
|
214
|
+
end
|
215
|
+
products.compact
|
216
|
+
end
|
217
|
+
|
218
|
+
def preload_host_guests
|
219
|
+
@hosts = {}
|
220
|
+
@guests = {}
|
221
|
+
return unless option_dir && File.exists?(option_dir + "/host-guests")
|
222
|
+
host_guest_file = option_dir + "/host-guests"
|
223
|
+
|
224
|
+
CSV.foreach(host_guest_file, {
|
225
|
+
:skip_blanks => true,
|
226
|
+
:headers => :first_row,
|
227
|
+
:return_headers => false
|
228
|
+
}) do |line|
|
229
|
+
@hosts[line['server_id']] = nil
|
230
|
+
CSV.parse_line(line['guests'], {:col_sep => ';'}).each do |guest|
|
231
|
+
@guests[guest] = nil
|
232
|
+
end
|
233
|
+
end
|
234
|
+
end
|
235
|
+
|
236
|
+
def update_host_guests
|
237
|
+
return unless option_dir && File.exists?(option_dir + "/host-guests")
|
238
|
+
return if @hosts.empty?
|
239
|
+
host_guest_file = option_dir + "/host-guests"
|
240
|
+
|
241
|
+
print _('Updating hypervisor and guest associations...') if option_verbose?
|
242
|
+
|
243
|
+
CSV.foreach(host_guest_file, {
|
244
|
+
:skip_blanks => true,
|
245
|
+
:headers => :first_row,
|
246
|
+
:return_headers => false
|
247
|
+
}) do |line|
|
248
|
+
host_id = @hosts[line['server_id']]
|
249
|
+
next if host_id.nil?
|
250
|
+
guest_ids = CSV.parse_line(line['guests'], {:col_sep => ';'}).collect do |guest|
|
251
|
+
@guests[guest]
|
252
|
+
end
|
253
|
+
|
254
|
+
@api.resource(:systems).call(:update, {
|
255
|
+
'id' => host_id,
|
256
|
+
'guest_ids' => guest_ids
|
257
|
+
})
|
258
|
+
end
|
259
|
+
|
260
|
+
puts _("done") if option_verbose?
|
261
|
+
end
|
262
|
+
|
263
|
+
def update_subscriptions(host_id, line)
|
264
|
+
existing_subscriptions = @api.resource(:subscriptions).call(:index, {
|
265
|
+
'organization_id' => foreman_organization(:name => line[ORGANIZATION]),
|
266
|
+
'per_page' => 999999,
|
267
|
+
'system_id' => host_id
|
268
|
+
})['results']
|
269
|
+
if existing_subscriptions.length > 0
|
270
|
+
@api.resource(:subscriptions).call(:destroy, {
|
271
|
+
'system_id' => host_id,
|
272
|
+
'id' => existing_subscriptions[0]['id']
|
273
|
+
})
|
274
|
+
end
|
275
|
+
|
276
|
+
return if line[SUBSCRIPTIONS].nil? || line[SUBSCRIPTIONS].empty?
|
277
|
+
|
278
|
+
subscriptions = CSV.parse_line(line[SUBSCRIPTIONS], {:skip_blanks => true}).collect do |details|
|
279
|
+
(amount, sku, name) = details.split('|')
|
280
|
+
{
|
281
|
+
:id => katello_subscription(line[ORGANIZATION], :name => name),
|
282
|
+
:quantity => (amount.nil? || amount.empty? || amount == 'Automatic') ? 0 : amount.to_i
|
283
|
+
}
|
284
|
+
end
|
285
|
+
|
286
|
+
@api.resource(:subscriptions).call(:create, {
|
287
|
+
'system_id' => host_id,
|
288
|
+
'subscriptions' => subscriptions
|
289
|
+
})
|
290
|
+
end
|
291
|
+
|
292
|
+
def create_organization(line)
|
293
|
+
if !@existing_organizations
|
294
|
+
@existing_organizations = {}
|
295
|
+
@api.resource(:organizations).call(:index, {
|
296
|
+
:per_page => 999999
|
297
|
+
})['results'].each do |organization|
|
298
|
+
@existing_organizations[organization['name']] = organization['id'] if organization
|
299
|
+
end
|
300
|
+
end
|
301
|
+
|
302
|
+
if !@existing_organizations[line[ORGANIZATION]]
|
303
|
+
print _("Creating organization '%{name}'... ") % {:name => line[ORGANIZATION]} if option_verbose?
|
304
|
+
@api.resource(:organizations).call(:create, {
|
305
|
+
'name' => line[ORGANIZATION],
|
306
|
+
'organization' => {
|
307
|
+
'name' => line[ORGANIZATION],
|
308
|
+
'label' => "splice-#{line[ORGANIZATION_ID]}",
|
309
|
+
'description' => _('Satellite-5 Splice')
|
310
|
+
}
|
311
|
+
})
|
312
|
+
puts _('done')
|
313
|
+
end
|
314
|
+
end
|
315
|
+
|
316
|
+
def delete_unfound_hosts(hosts)
|
317
|
+
hosts.keys.each do |organization|
|
318
|
+
hosts[organization].values.each do |host_id|
|
319
|
+
print _("Deleting content host with id '%{id}'...") % {:id => host_id}
|
320
|
+
@api.resource(:systems).call(:destroy, {:id => host_id})
|
321
|
+
puts _('done')
|
322
|
+
end
|
323
|
+
end
|
324
|
+
end
|
325
|
+
|
326
|
+
|
327
|
+
def load_product_mapping
|
328
|
+
@product_mapping = {}
|
329
|
+
|
330
|
+
mapping_dir = (option_mapping_dir || '/usr/share/rhsm/product/RHEL-6')
|
331
|
+
File.open(mapping_dir + '/channel-cert-mapping.txt', 'r') do |file|
|
332
|
+
file.each_line do |line|
|
333
|
+
# '<product name>: <file name>\n'
|
334
|
+
(product_name, file_name) = line.split(':')
|
335
|
+
@product_mapping[product_name] = {:file => "#{mapping_dir}/#{file_name[1..-2]}"}
|
336
|
+
OpenSSL::X509::Certificate.new(File.read(@product_mapping[product_name][:file])).extensions.each do |extension|
|
337
|
+
if extension.oid.start_with?("1.3.6.1.4.1.2312.9.1.")
|
338
|
+
oid_parts = extension.oid.split('.')
|
339
|
+
@product_mapping[product_name][:productId] = oid_parts[-2].to_i
|
340
|
+
case oid_parts[-1]
|
341
|
+
when /1/
|
342
|
+
@product_mapping[product_name][:productName] = extension.value[2..-1] #.sub(/\A\.+/,'')
|
343
|
+
when /2/
|
344
|
+
@product_mapping[product_name][:version] = extension.value[2..-1] #.sub(/\A\.+/,'')
|
345
|
+
when /3/
|
346
|
+
@product_mapping[product_name][:arch] = extension.value[2..-1] #.sub(/\A\.+/,'')
|
347
|
+
end
|
348
|
+
end
|
349
|
+
end
|
350
|
+
end
|
351
|
+
end
|
352
|
+
|
353
|
+
channel_file = option_dir + '/cloned-channels'
|
354
|
+
return unless File.exists? channel_file
|
355
|
+
unmatched_channels = []
|
356
|
+
CSV.foreach(channel_file, {
|
357
|
+
:skip_blanks => true,
|
358
|
+
:headers => :first_row,
|
359
|
+
:return_headers => false
|
360
|
+
}) do |line|
|
361
|
+
if @product_mapping[line['original_channel_label']]
|
362
|
+
@product_mapping[line['new_channel_label']] = @product_mapping[line['original_channel_label']]
|
363
|
+
else
|
364
|
+
unmatched_channels << line
|
365
|
+
end
|
366
|
+
end
|
367
|
+
|
368
|
+
# Second pass through
|
369
|
+
unmatched_channels.each do |line|
|
370
|
+
next if @product_mapping[line['original_channel_label']].nil?
|
371
|
+
@product_mapping[line['new_channel_label']] = @product_mapping[line['original_channel_label']]
|
372
|
+
end
|
373
|
+
end
|
374
|
+
end
|
375
|
+
end
|
376
|
+
end
|