hammer_cli_import 0.10.21
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 +7 -0
- data/LICENSE +674 -0
- data/README.md +115 -0
- data/channel_data_pretty.json +10316 -0
- data/config/import/config_macros.yml +16 -0
- data/config/import/interview_answers.yml +13 -0
- data/config/import/role_map.yml +10 -0
- data/config/import.yml +2 -0
- data/lib/hammer_cli_import/activationkey.rb +156 -0
- data/lib/hammer_cli_import/all.rb +253 -0
- data/lib/hammer_cli_import/asynctasksreactor.rb +187 -0
- data/lib/hammer_cli_import/autoload.rb +27 -0
- data/lib/hammer_cli_import/base.rb +585 -0
- data/lib/hammer_cli_import/configfile.rb +392 -0
- data/lib/hammer_cli_import/contenthost.rb +243 -0
- data/lib/hammer_cli_import/contentview.rb +198 -0
- data/lib/hammer_cli_import/csvhelper.rb +68 -0
- data/lib/hammer_cli_import/deltahash.rb +86 -0
- data/lib/hammer_cli_import/fixtime.rb +27 -0
- data/lib/hammer_cli_import/hostcollection.rb +52 -0
- data/lib/hammer_cli_import/import.rb +31 -0
- data/lib/hammer_cli_import/importtools.rb +351 -0
- data/lib/hammer_cli_import/organization.rb +110 -0
- data/lib/hammer_cli_import/persistentmap.rb +225 -0
- data/lib/hammer_cli_import/repository.rb +91 -0
- data/lib/hammer_cli_import/repositoryenable.rb +250 -0
- data/lib/hammer_cli_import/templatesnippet.rb +67 -0
- data/lib/hammer_cli_import/user.rb +155 -0
- data/lib/hammer_cli_import/version.rb +25 -0
- data/lib/hammer_cli_import.rb +53 -0
- metadata +117 -0
@@ -0,0 +1,91 @@
|
|
1
|
+
#
|
2
|
+
# Copyright (c) 2014 Red Hat Inc.
|
3
|
+
#
|
4
|
+
# This file is part of hammer-cli-import.
|
5
|
+
#
|
6
|
+
# hammer-cli-import is free software: you can redistribute it and/or modify
|
7
|
+
# it under the terms of the GNU General Public License as published by
|
8
|
+
# the Free Software Foundation, either version 3 of the License, or
|
9
|
+
# (at your option) any later version.
|
10
|
+
#
|
11
|
+
# hammer-cli-import is distributed in the hope that it will be useful,
|
12
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
13
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
14
|
+
# GNU General Public License for more details.
|
15
|
+
#
|
16
|
+
# You should have received a copy of the GNU General Public License
|
17
|
+
# along with hammer-cli-import. If not, see <http://www.gnu.org/licenses/>.
|
18
|
+
#
|
19
|
+
|
20
|
+
require 'hammer_cli'
|
21
|
+
require 'uri'
|
22
|
+
|
23
|
+
module HammerCLIImport
|
24
|
+
class ImportCommand
|
25
|
+
class RepositoryImportCommand < BaseCommand
|
26
|
+
extend ImportTools::Repository::Extend
|
27
|
+
include ImportTools::Repository::Include
|
28
|
+
|
29
|
+
command_name 'repository'
|
30
|
+
reportname = 'repositories'
|
31
|
+
desc "Import repositories (from spacewalk-report #{reportname})."
|
32
|
+
|
33
|
+
csv_columns 'id', 'org_id', 'repo_label', 'source_url', 'repo_type'
|
34
|
+
|
35
|
+
persistent_maps :organizations, :repositories, :products
|
36
|
+
|
37
|
+
add_repo_options
|
38
|
+
|
39
|
+
def mk_product_hash(data, product_name)
|
40
|
+
{
|
41
|
+
:name => product_name,
|
42
|
+
:organization_id => get_translated_id(:organizations, data['org_id'].to_i)
|
43
|
+
}
|
44
|
+
end
|
45
|
+
|
46
|
+
def mk_repo_hash(data, product_id)
|
47
|
+
{
|
48
|
+
:name => data['repo_label'],
|
49
|
+
:product_id => product_id,
|
50
|
+
:url => data['source_url'],
|
51
|
+
:content_type => data['repo_type']
|
52
|
+
}
|
53
|
+
end
|
54
|
+
|
55
|
+
def import_single_row(data)
|
56
|
+
begin
|
57
|
+
product_name = URI.parse(data['source_url']).host.split('.').last(2).join('.').upcase
|
58
|
+
rescue
|
59
|
+
error 'Skipping ' + data['repo_label'] + ' ' + to_singular(:repositories) + ' import, invalid source_url.'
|
60
|
+
report_summary :skipped, :repositories
|
61
|
+
return
|
62
|
+
end
|
63
|
+
product_hash = mk_product_hash(data, product_name)
|
64
|
+
composite_id = [data['org_id'].to_i, product_name]
|
65
|
+
product_id = create_entity(:products, product_hash, composite_id)['id']
|
66
|
+
repo_hash = mk_repo_hash data, product_id
|
67
|
+
|
68
|
+
repo = create_entity(:repositories, repo_hash, data['id'].to_i)
|
69
|
+
with_synced_repo(repo)
|
70
|
+
end
|
71
|
+
|
72
|
+
def delete_single_row(data)
|
73
|
+
# check just becasue we're calling get_translated_id
|
74
|
+
unless @pm[:repositories][data['id'].to_i]
|
75
|
+
info to_singular(:repositories).capitalize + ' with id ' + data['id'] + " wasn't imported. Skipping deletion."
|
76
|
+
return
|
77
|
+
end
|
78
|
+
# find out product id
|
79
|
+
repo_id = get_translated_id(:repositories, data['id'].to_i)
|
80
|
+
product_id = lookup_entity(:repositories, repo_id)['product']['id']
|
81
|
+
# delete repo
|
82
|
+
delete_entity(:repositories, data['id'].to_i)
|
83
|
+
# delete its product, if it's not associated with any other repositories
|
84
|
+
product = lookup_entity(:products, product_id, true)
|
85
|
+
|
86
|
+
delete_entity_by_import_id(:products, product_id) if product['repository_count'] == 0
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
91
|
+
# vim: autoindent tabstop=2 shiftwidth=2 expandtab softtabstop=2 filetype=ruby
|
@@ -0,0 +1,250 @@
|
|
1
|
+
#
|
2
|
+
# Copyright (c) 2014 Red Hat Inc.
|
3
|
+
#
|
4
|
+
# This file is part of hammer-cli-import.
|
5
|
+
#
|
6
|
+
# hammer-cli-import is free software: you can redistribute it and/or modify
|
7
|
+
# it under the terms of the GNU General Public License as published by
|
8
|
+
# the Free Software Foundation, either version 3 of the License, or
|
9
|
+
# (at your option) any later version.
|
10
|
+
#
|
11
|
+
# hammer-cli-import is distributed in the hope that it will be useful,
|
12
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
13
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
14
|
+
# GNU General Public License for more details.
|
15
|
+
#
|
16
|
+
# You should have received a copy of the GNU General Public License
|
17
|
+
# along with hammer-cli-import. If not, see <http://www.gnu.org/licenses/>.
|
18
|
+
#
|
19
|
+
|
20
|
+
require 'hammer_cli'
|
21
|
+
require 'hammer_cli_import'
|
22
|
+
require 'json'
|
23
|
+
|
24
|
+
module HammerCLIImport
|
25
|
+
class ImportCommand
|
26
|
+
class RepositoryEnableCommand < BaseCommand
|
27
|
+
extend ImportTools::Repository::Extend
|
28
|
+
include ImportTools::Repository::Include
|
29
|
+
include ImportTools::ContentView::Include
|
30
|
+
|
31
|
+
command_name 'repository-enable'
|
32
|
+
reportname = 'channels'
|
33
|
+
desc "Enable any Red Hat repositories accessible to any Organization (from spacewalk-report #{reportname})."
|
34
|
+
|
35
|
+
option ['--repository-map'],
|
36
|
+
'FILE_NAME',
|
37
|
+
'JSON file mapping channel-labels to repository information',
|
38
|
+
:default => File.expand_path('../../channel_data_pretty.json', File.dirname(__FILE__)) do |filename|
|
39
|
+
raise ArgumentError, "Channel-to-repository-map file #{filename} does not exist" unless File.exist? filename
|
40
|
+
filename
|
41
|
+
end
|
42
|
+
|
43
|
+
option ['--dry-run'],
|
44
|
+
:flag,
|
45
|
+
'Only show the repositories that would be enabled',
|
46
|
+
:default => false
|
47
|
+
|
48
|
+
add_repo_options
|
49
|
+
|
50
|
+
# Required or BaseCommand gets angry at you
|
51
|
+
csv_columns 'channel_id', 'channel_label', 'channel_name', 'number_of_packages', 'org_id'
|
52
|
+
persistent_maps :organizations, :products,
|
53
|
+
:redhat_repositories, :redhat_content_views, :repositories
|
54
|
+
|
55
|
+
# BaseCommand will read our channel-csv for us
|
56
|
+
def import_single_row(row)
|
57
|
+
handle_row(row, true)
|
58
|
+
end
|
59
|
+
|
60
|
+
def delete_single_row(row)
|
61
|
+
handle_row(row, false)
|
62
|
+
end
|
63
|
+
|
64
|
+
def handle_row(row, enable)
|
65
|
+
if row['org_id'] # Not a Red Hat channel
|
66
|
+
info " Skipping #{row['channel_label']} in organization #{row['org_id']}"
|
67
|
+
return
|
68
|
+
end
|
69
|
+
|
70
|
+
# read_channel_mapping_data will be called only once per subcommand
|
71
|
+
@channel_to_repo ||= read_channel_mapping_data(option_repository_map)
|
72
|
+
channel_label = row['channel_label']
|
73
|
+
channel_id = row['channel_id'].to_i
|
74
|
+
repo_set_info = @channel_to_repo[channel_label]
|
75
|
+
|
76
|
+
if repo_set_info.nil? # not mapped channel (like proxy)
|
77
|
+
info " Skipping nontransferable #{row['channel_label']}"
|
78
|
+
return
|
79
|
+
end
|
80
|
+
|
81
|
+
# rely on we see only products in imported organizations
|
82
|
+
get_cache(:products).each do |product_id, product|
|
83
|
+
rsets = list_server_entities(:repository_sets, {:product_id => product_id}, true)
|
84
|
+
|
85
|
+
rsets.each do |rs|
|
86
|
+
next if repo_set_info['set-url'] != rs['contentUrl'] &&
|
87
|
+
repo_set_info['set-url'].gsub('$releasever', repo_set_info['version']) != rs['contentUrl']
|
88
|
+
|
89
|
+
product_org = lookup_entity_in_cache(:organizations, {'label' => product['organization']['label']})
|
90
|
+
composite_rhcv_id = [get_original_id(:organizations, product_org['id']), channel_id]
|
91
|
+
if enable
|
92
|
+
# Turn on the specific repository
|
93
|
+
rh_repo = enable_repos(product_org, product_id, rs['id'], repo_set_info, row)
|
94
|
+
next if rh_repo.nil? || option_dry_run?
|
95
|
+
|
96
|
+
# Finally, if requested, kick off a sync
|
97
|
+
with_synced_repo rh_repo do
|
98
|
+
cv = create_entity(
|
99
|
+
:redhat_content_views,
|
100
|
+
{
|
101
|
+
:organization_id => product_org['id'],
|
102
|
+
:name => row['channel_name'],
|
103
|
+
:description => 'Red Hat channel migrated from Satellite 5',
|
104
|
+
:repository_ids => [rh_repo['id']]
|
105
|
+
},
|
106
|
+
composite_rhcv_id)
|
107
|
+
begin
|
108
|
+
publish_content_view(cv['id'], :redhat_content_views)
|
109
|
+
rescue RestClient::Exception => e
|
110
|
+
msg = JSON.parse(e.response)['displayMessage']
|
111
|
+
error "#{e.http_code} trying to publish content-view #{row['channel_name']} :\n #{msg}\n"
|
112
|
+
next
|
113
|
+
end
|
114
|
+
end
|
115
|
+
else
|
116
|
+
if @pm[:redhat_content_views][composite_rhcv_id]
|
117
|
+
delete_content_view(get_translated_id(:redhat_content_views, composite_rhcv_id), :redhat_content_views)
|
118
|
+
end
|
119
|
+
disable_repos(product_org, product_id, rs['id'], repo_set_info, channel_label)
|
120
|
+
end
|
121
|
+
end
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
# Hydrate the channel-to-repository-data mapping struct
|
126
|
+
def read_channel_mapping_data(filename)
|
127
|
+
channel_map = {}
|
128
|
+
|
129
|
+
File.open(filename, 'r') do |f|
|
130
|
+
json = f.read
|
131
|
+
channel_map = JSON.parse(json)
|
132
|
+
end
|
133
|
+
return channel_map
|
134
|
+
end
|
135
|
+
|
136
|
+
# this way we're able to get from the server, what repositories within a repository-set are enabled
|
137
|
+
def find_repo_in_reposet(product_id, repo_set_id, info)
|
138
|
+
repos = api_call(
|
139
|
+
:repository_sets,
|
140
|
+
:available_repositories,
|
141
|
+
'product_id' => product_id,
|
142
|
+
'id' => repo_set_id)
|
143
|
+
|
144
|
+
if repos['results'][0] && repos['results'][0]['substitutions'].size == 1
|
145
|
+
return lookup_entity_in_array(repos['results'],
|
146
|
+
{'substitutions' => {'basearch' => info['arch']}})
|
147
|
+
end
|
148
|
+
return lookup_entity_in_array(repos['results'],
|
149
|
+
{'substitutions' => {'basearch' => info['arch'], 'releasever' => info['version']}})
|
150
|
+
end
|
151
|
+
|
152
|
+
# and this is quite a pain - to get real ids of the enabled repositories
|
153
|
+
# search according to the repository name
|
154
|
+
def find_enabled_repo(product_id, repo_set_id, repo_name)
|
155
|
+
reposet = api_call(
|
156
|
+
:repository_sets,
|
157
|
+
:show,
|
158
|
+
'product_id' => product_id,
|
159
|
+
'id' => repo_set_id)
|
160
|
+
|
161
|
+
enabled_repo = lookup_entity_in_array(reposet['repositories'], {'name' => repo_name})
|
162
|
+
info "Repository '#{repo_name}' already enabled as #{enabled_repo['id']}."
|
163
|
+
return lookup_entity(:redhat_repositories, enabled_repo['id'])
|
164
|
+
end
|
165
|
+
|
166
|
+
# Given a repository-set and a channel-to-repo info for that channel,
|
167
|
+
# enable the correct repository
|
168
|
+
def enable_repos(org, prod_id, repo_set_id, info, row)
|
169
|
+
channel_label = row['channel_label']
|
170
|
+
channel_id = row ['channel_id'].to_i
|
171
|
+
repo = find_repo_in_reposet(prod_id, repo_set_id, info)
|
172
|
+
if repo.nil?
|
173
|
+
warn "Repository #{info['url']} for (#{info['arch']} x #{info['version']}) not found!"
|
174
|
+
return
|
175
|
+
end
|
176
|
+
|
177
|
+
return find_enabled_repo(prod_id, repo_set_id, repo['repo_name']) if repo['enabled']
|
178
|
+
|
179
|
+
info "Enabling #{info['url']} for channel #{channel_label} in org #{org['id']}"
|
180
|
+
begin
|
181
|
+
unless option_dry_run?
|
182
|
+
rc = api_call(
|
183
|
+
:repository_sets,
|
184
|
+
:enable,
|
185
|
+
'product_id' => prod_id,
|
186
|
+
'id' => repo_set_id,
|
187
|
+
'basearch' => repo['substitutions'].key?('basearch') ? info['arch'] : '',
|
188
|
+
'releasever' => repo['substitutions'].key?('releasever') ? info['version'] : '')
|
189
|
+
|
190
|
+
original_org_id = get_original_id(:organizations, org['id'])
|
191
|
+
map_entity(:redhat_repositories, [original_org_id, channel_id], rc['input']['repository']['id'])
|
192
|
+
# store to cache (using lookup_entity, because :redhat_repositories api
|
193
|
+
# does not return full repository hash)
|
194
|
+
return lookup_entity(:redhat_repositories, rc['input']['repository']['id'], true)
|
195
|
+
end
|
196
|
+
rescue RestClient::Exception => e
|
197
|
+
if e.http_code == 409
|
198
|
+
info '...already enabled.'
|
199
|
+
return find_enabled_repo(prod_id, repo_set_id, repo['repo_name'])
|
200
|
+
else
|
201
|
+
error "...repository enablement failed with error '#{e.http_code}, #{e.message}' - skipping."
|
202
|
+
end
|
203
|
+
end
|
204
|
+
end
|
205
|
+
|
206
|
+
def disable_repos(org, prod_id, repo_set_id, info, channel_label)
|
207
|
+
repo = lookup_entity_in_cache(
|
208
|
+
:redhat_repositories,
|
209
|
+
{
|
210
|
+
'content_id' => repo_set_id,
|
211
|
+
'organization' => {'label' => org['label']}
|
212
|
+
})
|
213
|
+
# find the repo from reposet to get also the substitutions
|
214
|
+
# otherwise it's not possible to disable certain repositories
|
215
|
+
repo = find_repo_in_reposet(prod_id, repo_set_id, info) if repo
|
216
|
+
unless repo
|
217
|
+
error "Unknown repository (#{channel_label} equivalent) to disable."
|
218
|
+
return
|
219
|
+
end
|
220
|
+
info "Disabling #{info['url']} for channel #{channel_label} in org #{org['id']}"
|
221
|
+
begin
|
222
|
+
unless option_dry_run?
|
223
|
+
rc = api_call(
|
224
|
+
:repository_sets,
|
225
|
+
:disable,
|
226
|
+
'product_id' => prod_id,
|
227
|
+
'id' => repo_set_id,
|
228
|
+
'basearch' => repo['substitutions'].key?('basearch') ? info['arch'] : '',
|
229
|
+
'releasever' => repo['substitutions'].key?('releasever') ? info['version'] : '')
|
230
|
+
|
231
|
+
unmap_entity(:redhat_repositories, rc['input']['repository']['id'])
|
232
|
+
get_cache(:redhat_repositories).delete(rc['input']['repository']['id'])
|
233
|
+
return rc['input']['repository']
|
234
|
+
end
|
235
|
+
rescue RestClient::Exception => e
|
236
|
+
if e.http_code == 404
|
237
|
+
error '...no such repository to disable.'
|
238
|
+
else
|
239
|
+
error "...repository disable failed with error '#{e.http_code}, #{e.message}' - skipping."
|
240
|
+
end
|
241
|
+
end
|
242
|
+
end
|
243
|
+
|
244
|
+
def post_import(_file)
|
245
|
+
HammerCLI::EX_OK
|
246
|
+
end
|
247
|
+
end
|
248
|
+
end
|
249
|
+
end
|
250
|
+
# vim: autoindent tabstop=2 shiftwidth=2 expandtab softtabstop=2 filetype=ruby
|
@@ -0,0 +1,67 @@
|
|
1
|
+
#
|
2
|
+
# Copyright (c) 2014 Red Hat Inc.
|
3
|
+
#
|
4
|
+
# This file is part of hammer-cli-import.
|
5
|
+
#
|
6
|
+
# hammer-cli-import is free software: you can redistribute it and/or modify
|
7
|
+
# it under the terms of the GNU General Public License as published by
|
8
|
+
# the Free Software Foundation, either version 3 of the License, or
|
9
|
+
# (at your option) any later version.
|
10
|
+
#
|
11
|
+
# hammer-cli-import is distributed in the hope that it will be useful,
|
12
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
13
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
14
|
+
# GNU General Public License for more details.
|
15
|
+
#
|
16
|
+
# You should have received a copy of the GNU General Public License
|
17
|
+
# along with hammer-cli-import. If not, see <http://www.gnu.org/licenses/>.
|
18
|
+
#
|
19
|
+
|
20
|
+
require 'hammer_cli'
|
21
|
+
require 'apipie-bindings'
|
22
|
+
|
23
|
+
module HammerCLIImport
|
24
|
+
class ImportCommand
|
25
|
+
class TemplateSnippetImportCommand < BaseCommand
|
26
|
+
command_name 'template-snippet'
|
27
|
+
reportname = 'kickstart-scripts'
|
28
|
+
desc "Import template snippets (from spacewalk-report #{reportname})."
|
29
|
+
|
30
|
+
csv_columns \
|
31
|
+
'id', 'org_id', 'script_name', 'kickstart_label', 'position',
|
32
|
+
'script_type', 'chroot', 'interpreter', 'data'
|
33
|
+
|
34
|
+
persistent_maps :organizations, :template_snippets
|
35
|
+
|
36
|
+
def mk_snippet_hash(data)
|
37
|
+
template = "%#{data['script_type']}"
|
38
|
+
template += ' --nochroot' if data['chroot'] == 'N'
|
39
|
+
template += " --interpreter #{data['interpreter']}" if data['interpreter']
|
40
|
+
template += "\n"
|
41
|
+
template += data['data'] if data['data']
|
42
|
+
template += "\n" unless template.end_with? "\n"
|
43
|
+
template += "%end\n"
|
44
|
+
{
|
45
|
+
:name => "#{data['kickstart_label']}-#{data['org_id']}-" \
|
46
|
+
"#{data['position']}-#{data['script_name']}-#{data['script_type']}",
|
47
|
+
:template => template,
|
48
|
+
# nowadays templates do not get associated with an organization
|
49
|
+
# :organization_id => get_translated_id(:organizations, data['org_id'].to_i),
|
50
|
+
:snippet => true,
|
51
|
+
# audit_comment does not get stored anyway
|
52
|
+
:audit_comment => ''
|
53
|
+
}
|
54
|
+
end
|
55
|
+
|
56
|
+
def import_single_row(data)
|
57
|
+
snippet = mk_snippet_hash data
|
58
|
+
create_entity(:template_snippets, snippet, data['id'].to_i)
|
59
|
+
end
|
60
|
+
|
61
|
+
def delete_single_row(data)
|
62
|
+
delete_entity(:template_snippets, data['id'].to_i)
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
# vim: autoindent tabstop=2 shiftwidth=2 expandtab softtabstop=2 filetype=ruby
|
@@ -0,0 +1,155 @@
|
|
1
|
+
#
|
2
|
+
# Copyright (c) 2014 Red Hat Inc.
|
3
|
+
#
|
4
|
+
# This file is part of hammer-cli-import.
|
5
|
+
#
|
6
|
+
# hammer-cli-import is free software: you can redistribute it and/or modify
|
7
|
+
# it under the terms of the GNU General Public License as published by
|
8
|
+
# the Free Software Foundation, either version 3 of the License, or
|
9
|
+
# (at your option) any later version.
|
10
|
+
#
|
11
|
+
# hammer-cli-import is distributed in the hope that it will be useful,
|
12
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
13
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
14
|
+
# GNU General Public License for more details.
|
15
|
+
#
|
16
|
+
# You should have received a copy of the GNU General Public License
|
17
|
+
# along with hammer-cli-import. If not, see <http://www.gnu.org/licenses/>.
|
18
|
+
#
|
19
|
+
|
20
|
+
require 'hammer_cli'
|
21
|
+
require 'yaml'
|
22
|
+
|
23
|
+
module HammerCLIImport
|
24
|
+
class ImportCommand
|
25
|
+
class UserImportCommand < BaseCommand
|
26
|
+
command_name 'user'
|
27
|
+
reportname = 'users'
|
28
|
+
desc "Import Users (from spacewalk-report #{reportname})."
|
29
|
+
|
30
|
+
option ['--new-passwords'], 'FILE_NAME', 'Output for new passwords' do |filename|
|
31
|
+
raise ArgumentError, "File #{filename} already exists" if File.exist? filename
|
32
|
+
filename
|
33
|
+
end
|
34
|
+
|
35
|
+
option ['--merge-users'], :flag, 'Merge pre-created users (except admin)', :default => false
|
36
|
+
|
37
|
+
option ['--role-mapping'], 'FILE_NAME',
|
38
|
+
'Mapping of Satellite-5 role names to Satellite-6 defined roles',
|
39
|
+
:default => '/etc/hammer/cli.modules.d/import/role_map.yml'
|
40
|
+
|
41
|
+
validate_options do
|
42
|
+
any(:option_new_passwords, :option_delete).required
|
43
|
+
end
|
44
|
+
|
45
|
+
csv_columns 'organization_id', 'user_id', 'username',\
|
46
|
+
'last_name', 'first_name', 'email', 'role', 'active'
|
47
|
+
|
48
|
+
persistent_maps :organizations, :users
|
49
|
+
|
50
|
+
# Override so we can read the role-map *once*, not *once per user*
|
51
|
+
def first_time_only
|
52
|
+
if File.exist? option_role_mapping
|
53
|
+
@role_map = YAML.load_file(option_role_mapping)
|
54
|
+
else
|
55
|
+
warn "Role-mapping file #{option_role_mapping} not found, no roles will be assigned"
|
56
|
+
end
|
57
|
+
return 'loaded'
|
58
|
+
end
|
59
|
+
|
60
|
+
def genpw(username)
|
61
|
+
username + '_' + (0...8).collect { ('a'..'z').to_a[rand(26)] }.join
|
62
|
+
end
|
63
|
+
|
64
|
+
# Admin-flag should be set if any Sat5-role has '_admin_' in its map
|
65
|
+
def admin?(data)
|
66
|
+
return false if @role_map.nil?
|
67
|
+
|
68
|
+
roles = split_multival(data['role'], false)
|
69
|
+
is_admin = false
|
70
|
+
roles.each do |r|
|
71
|
+
is_admin ||= (@role_map[r.gsub(' ', '-')].include? '_admin_')
|
72
|
+
end
|
73
|
+
return is_admin
|
74
|
+
end
|
75
|
+
|
76
|
+
# Return list-of-role-ids that match any sat5-role associated with this user
|
77
|
+
# XXX: Role-api doesn't return what it needs to
|
78
|
+
# Until BZ 1102816 is fixed, this doesn't work
|
79
|
+
# It does serve to show the infrastructure/approach required
|
80
|
+
def role_ids_for(data)
|
81
|
+
role_list = []
|
82
|
+
return role_list if @role_map.nil?
|
83
|
+
|
84
|
+
users_roles = split_multival(data['role'], false)
|
85
|
+
fm_roles = api_call(:roles, :index, 'per_page' => 999999)['results']
|
86
|
+
debug fm_roles.inspect
|
87
|
+
users_roles.each do |s5r|
|
88
|
+
fm_roles.each do |fr|
|
89
|
+
role_list << fr['id'] if @role_map[s5r.gsub(' ', '-')].include? fr['name']
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
return role_list
|
94
|
+
end
|
95
|
+
|
96
|
+
def mk_user_hash(data)
|
97
|
+
username = data['username']
|
98
|
+
username = 'sat5_admin' if username == 'admin'
|
99
|
+
{
|
100
|
+
:login => username,
|
101
|
+
:firstname => data['first_name'],
|
102
|
+
:lastname => data['last_name'],
|
103
|
+
:mail => data['email'],
|
104
|
+
:auth_source_id => 1,
|
105
|
+
:password => genpw(username),
|
106
|
+
:organization_ids => [get_translated_id(:organizations, data['organization_id'].to_i)],
|
107
|
+
:location_ids => [],
|
108
|
+
:admin => admin?(data),
|
109
|
+
:role_ids => role_ids_for(data)
|
110
|
+
}
|
111
|
+
end
|
112
|
+
|
113
|
+
def post_import(_)
|
114
|
+
return if @new_passwords.nil? || @new_passwords.empty?
|
115
|
+
CSVHelper.csv_write_hashes option_new_passwords, [:mail, :login, :password], @new_passwords
|
116
|
+
end
|
117
|
+
|
118
|
+
def import_single_row(data)
|
119
|
+
@first_time ||= first_time_only
|
120
|
+
user = mk_user_hash data
|
121
|
+
new_user = true
|
122
|
+
|
123
|
+
user_id = data['user_id'].to_i
|
124
|
+
login = user[:login]
|
125
|
+
|
126
|
+
unless @pm[:users][user_id].nil?
|
127
|
+
info "User #{login} already imported."
|
128
|
+
return
|
129
|
+
end
|
130
|
+
|
131
|
+
if option_merge_users?
|
132
|
+
existing_user = lookup_entity_in_cache :users, 'login' => user[:login]
|
133
|
+
|
134
|
+
unless existing_user.nil?
|
135
|
+
info "User with login #{login} already exists. Associating..."
|
136
|
+
map_entity :users, user_id, existing_user['id']
|
137
|
+
new_user = false
|
138
|
+
end
|
139
|
+
end
|
140
|
+
|
141
|
+
return unless new_user
|
142
|
+
|
143
|
+
create_entity :users, user, user_id
|
144
|
+
|
145
|
+
@new_passwords ||= []
|
146
|
+
@new_passwords << {:login => user[:login], :password => user[:password], :mail => user[:mail]}
|
147
|
+
end
|
148
|
+
|
149
|
+
def delete_single_row(data)
|
150
|
+
delete_entity(:users, data['user_id'].to_i)
|
151
|
+
end
|
152
|
+
end
|
153
|
+
end
|
154
|
+
end
|
155
|
+
# vim: autoindent tabstop=2 shiftwidth=2 expandtab softtabstop=2 filetype=ruby
|
@@ -0,0 +1,25 @@
|
|
1
|
+
#
|
2
|
+
# Copyright (c) 2014 Red Hat Inc.
|
3
|
+
#
|
4
|
+
# This file is part of hammer-cli-import.
|
5
|
+
#
|
6
|
+
# hammer-cli-import is free software: you can redistribute it and/or modify
|
7
|
+
# it under the terms of the GNU General Public License as published by
|
8
|
+
# the Free Software Foundation, either version 3 of the License, or
|
9
|
+
# (at your option) any later version.
|
10
|
+
#
|
11
|
+
# hammer-cli-import is distributed in the hope that it will be useful,
|
12
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
13
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
14
|
+
# GNU General Public License for more details.
|
15
|
+
#
|
16
|
+
# You should have received a copy of the GNU General Public License
|
17
|
+
# along with hammer-cli-import. If not, see <http://www.gnu.org/licenses/>.
|
18
|
+
#
|
19
|
+
|
20
|
+
module HammerCLIImport
|
21
|
+
def self.version
|
22
|
+
@version ||= Gem::Version.new('0.10.21')
|
23
|
+
end
|
24
|
+
end
|
25
|
+
# vim: autoindent tabstop=2 shiftwidth=2 expandtab softtabstop=2 filetype=ruby
|
@@ -0,0 +1,53 @@
|
|
1
|
+
#
|
2
|
+
# Copyright (c) 2014 Red Hat Inc.
|
3
|
+
#
|
4
|
+
# This file is part of hammer-cli-import.
|
5
|
+
#
|
6
|
+
# hammer-cli-import is free software: you can redistribute it and/or modify
|
7
|
+
# it under the terms of the GNU General Public License as published by
|
8
|
+
# the Free Software Foundation, either version 3 of the License, or
|
9
|
+
# (at your option) any later version.
|
10
|
+
#
|
11
|
+
# hammer-cli-import is distributed in the hope that it will be useful,
|
12
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
13
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
14
|
+
# GNU General Public License for more details.
|
15
|
+
#
|
16
|
+
# You should have received a copy of the GNU General Public License
|
17
|
+
# along with hammer-cli-import. If not, see <http://www.gnu.org/licenses/>.
|
18
|
+
#
|
19
|
+
|
20
|
+
require 'hammer_cli'
|
21
|
+
|
22
|
+
module HammerCLIImport
|
23
|
+
# def self.exception_handler_class
|
24
|
+
# HammerCLIImport::ExceptionHandler
|
25
|
+
# end
|
26
|
+
|
27
|
+
require 'hammer_cli_import/asynctasksreactor'
|
28
|
+
require 'hammer_cli_import/csvhelper'
|
29
|
+
require 'hammer_cli_import/deltahash'
|
30
|
+
require 'hammer_cli_import/fixtime'
|
31
|
+
require 'hammer_cli_import/importtools'
|
32
|
+
require 'hammer_cli_import/persistentmap'
|
33
|
+
|
34
|
+
require 'hammer_cli_import/base'
|
35
|
+
require 'hammer_cli_import/import'
|
36
|
+
|
37
|
+
require 'hammer_cli_import/all'
|
38
|
+
require 'hammer_cli_import/activationkey'
|
39
|
+
require 'hammer_cli_import/configfile'
|
40
|
+
require 'hammer_cli_import/contentview'
|
41
|
+
require 'hammer_cli_import/contenthost'
|
42
|
+
require 'hammer_cli_import/hostcollection'
|
43
|
+
require 'hammer_cli_import/organization'
|
44
|
+
require 'hammer_cli_import/repository'
|
45
|
+
require 'hammer_cli_import/repositoryenable'
|
46
|
+
require 'hammer_cli_import/templatesnippet.rb'
|
47
|
+
require 'hammer_cli_import/user'
|
48
|
+
require 'hammer_cli_import/version'
|
49
|
+
|
50
|
+
# This has to be after all subcommands
|
51
|
+
require 'hammer_cli_import/autoload'
|
52
|
+
end
|
53
|
+
# vim: autoindent tabstop=2 shiftwidth=2 expandtab softtabstop=2 filetype=ruby
|