hammer_cli_import 0.10.21

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,198 @@
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 'set'
21
+
22
+ module HammerCLIImport
23
+ class ImportCommand
24
+ class LocalRepositoryImportCommand < BaseCommand
25
+ extend ImportTools::Repository::Extend
26
+ include ImportTools::Repository::Include
27
+ include ImportTools::ContentView::Include
28
+
29
+ command_name 'content-view'
30
+ desc 'Create Content Views based on local/cloned Channels (from spacewalk-export-channels).'
31
+
32
+ csv_columns 'org_id', 'channel_id', 'channel_label', 'channel_name'
33
+
34
+ persistent_maps :organizations, :repositories, :local_repositories, :content_views,
35
+ :products, :redhat_repositories, :redhat_content_views, :system_content_views
36
+
37
+ option ['--dir'], 'DIR', 'Export directory'
38
+ option ['--filter'], :flag, 'Filter content-views for package names present in Sat5 channel', :default => false
39
+ add_repo_options
40
+
41
+ def directory
42
+ File.expand_path(option_dir || File.dirname(option_csv_file))
43
+ end
44
+
45
+ def mk_product_hash(data, product_name)
46
+ {
47
+ :name => product_name,
48
+ :organization_id => get_translated_id(:organizations, data['org_id'].to_i)
49
+ }
50
+ end
51
+
52
+ def mk_repo_hash(data, product_id)
53
+ {
54
+ :name => "Local repository for #{data['channel_label']}",
55
+ :product_id => product_id,
56
+ :url => 'file://' + File.join(directory, data['org_id'], data['channel_id']),
57
+ :content_type => 'yum'
58
+ }
59
+ end
60
+
61
+ def mk_content_view_hash(data, repo_ids)
62
+ {
63
+ :name => data['channel_name'],
64
+
65
+ :description => 'Channel migrated from Satellite 5',
66
+
67
+ :organization_id => get_translated_id(:organizations, data['org_id'].to_i),
68
+ :repository_ids => repo_ids
69
+ }
70
+ end
71
+
72
+ def newer_repositories(cw)
73
+ last = cw['last_published']
74
+ return true unless last
75
+ last = Time.parse(last)
76
+ cw['repositories'].any? do |repo|
77
+ repo['last_sync'].nil? || last < Time.parse(repo['last_sync'])
78
+ end
79
+ end
80
+
81
+ def push_unless_nil(col, obj)
82
+ col << obj unless obj.nil?
83
+ end
84
+
85
+ def load_custom_channel_info(org_id, channel_id)
86
+ headers = %w(org_id channel_id package_nevra package_rpm_name in_repo in_parent_channel)
87
+ file = File.join directory, org_id.to_s, channel_id.to_s + '.csv'
88
+
89
+ packages_in_channel = Set[]
90
+ repo_ids = Set[]
91
+ parent_channel_ids = Set[]
92
+ has_local_packages = false
93
+
94
+ CSVHelper.csv_each file, headers do |data|
95
+ packages_in_channel << data['package_nevra']
96
+ push_unless_nil parent_channel_ids, data['in_parent_channel']
97
+ push_unless_nil repo_ids, data['in_repo']
98
+ has_local_packages ||= data['in_repo'].nil? && data['in_parent_channel'].nil?
99
+ end
100
+
101
+ raise "Multiple parents for channel #{channel_id}?" unless parent_channel_ids.size.between? 0, 1
102
+
103
+ [repo_ids.to_a, parent_channel_ids.to_a, packages_in_channel.to_a, has_local_packages]
104
+ end
105
+
106
+ def add_local_repo(data)
107
+ product_name = 'Local-repositories'
108
+ composite_id = [data['org_id'].to_i, product_name]
109
+ product_hash = mk_product_hash data, product_name
110
+ product_id = create_entity(:products, product_hash, composite_id)['id'].to_i
111
+
112
+ repo_hash = mk_repo_hash data, product_id
113
+ local_repo = create_entity :local_repositories, repo_hash, [data['org_id'].to_i, data['channel_id'].to_i]
114
+ local_repo
115
+ end
116
+
117
+ def add_repo_filters(content_view_id, nevras)
118
+ cw_filter = api_call :content_view_filters,
119
+ :create,
120
+ { :content_view_id => content_view_id,
121
+ :name => 'Satellite 5 channel equivalence filter',
122
+ :type => 'rpm',
123
+ :inclusion => true}
124
+
125
+ packages = nevras.collect do |package_nevra|
126
+ match = /^([^:]+)-(\d+):([^-]+)-(.*)\.([^.]*)$/.match(package_nevra)
127
+ raise "Bad nevra: #{package_nevra}" unless match
128
+
129
+ { :name => match[1],
130
+ :epoch => match[2],
131
+ :version => match[3],
132
+ :release => match[4],
133
+ :architecture => match[5]
134
+ }
135
+ end
136
+ packages.group_by { |package| package[:name] } .each do |name, _packages|
137
+ api_call :content_view_filter_rules,
138
+ :create,
139
+ { :content_view_filter_id => cw_filter['id'],
140
+ :name => name}
141
+ end
142
+ end
143
+
144
+ def import_single_row(data)
145
+ org_id = data['org_id'].to_i
146
+
147
+ repo_ids, clone_parents, packages, has_local = load_custom_channel_info org_id, data['channel_id'].to_i
148
+
149
+ repo_ids.map! { |id| get_translated_id :repositories, id.to_i }
150
+
151
+ if has_local
152
+ local_repo = add_local_repo data
153
+ sync_repo local_repo unless repo_synced? local_repo
154
+ repo_ids.push local_repo['id'].to_i
155
+ end
156
+
157
+ clone_parents.collect { |x| Integer(x) } .each do |parent_id|
158
+ begin
159
+ begin
160
+ parent_cv = get_cache(:redhat_content_views)[get_translated_id :redhat_content_views, [org_id, parent_id]]
161
+ rescue
162
+ parent_cv = get_cache(:content_views)[get_translated_id :content_views, parent_id]
163
+ end
164
+ repo_ids += parent_cv['repositories'].collect { |x| x['id'] }
165
+ rescue HammerCLIImport::MissingObjectError
166
+ error "No such {redhat_,}content_view: #{parent_id}"
167
+ end
168
+ end
169
+
170
+ repo_ids.collect { |id| lookup_entity :repositories, id } .each do |repo|
171
+ unless repo_synced? repo
172
+ warn "Repository #{repo['label']} is not (fully) synchronized. Retry once synchronization has completed."
173
+ report_summary :skipped, :content_views
174
+ return nil
175
+ end
176
+ end
177
+ content_view = mk_content_view_hash data, repo_ids
178
+
179
+ cw = create_entity :content_views, content_view, data['channel_id'].to_i
180
+ add_repo_filters cw['id'], packages if option_filter?
181
+ publish_content_view cw['id'] if newer_repositories cw
182
+ end
183
+
184
+ def delete_single_row(data)
185
+ cv_id = data['channel_id'].to_i
186
+ unless @pm[:content_views][cv_id] || @pm[:redhat_content_views][cv_id] || @pm[:system_content_views][cv_id]
187
+ info "#{to_singular(:content_views).capitalize} with id #{cv_id} wasn't imported. Skipping deletion."
188
+ return
189
+ end
190
+ translated = get_translated_id :content_views, cv_id
191
+
192
+ # delete_entity :content_views, cv_id
193
+ delete_content_view translated
194
+ end
195
+ end
196
+ end
197
+ end
198
+ # vim: autoindent tabstop=2 shiftwidth=2 expandtab softtabstop=2 filetype=ruby
@@ -0,0 +1,68 @@
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 'csv'
21
+
22
+ module CSVHelper
23
+ class CSVHelperError < RuntimeError
24
+ end
25
+
26
+ # Returns missing columns
27
+ def self.csv_missing_columns(filename, headers)
28
+ reader = CSV.open(filename, 'r')
29
+ real_header = reader.shift
30
+ reader.close
31
+ headers - real_header
32
+ end
33
+
34
+ def self.csv_each(filename, headers)
35
+ raise CSVHelperError, 'Expecting block' unless block_given?
36
+ reader = CSV.open(filename, 'r')
37
+ real_header = reader.shift
38
+ raise CSVHelperError, "No header in #{filename}" if real_header.nil?
39
+ real_header_length = real_header.length
40
+ to_discard = real_header - headers
41
+ headers.each do |col|
42
+ raise CSVHelperError, "Column #{col} expected in #{filename}" unless real_header.include? col
43
+ end
44
+ reader.each do |row|
45
+ raise CSVHelperError, "Broken CSV in #{filename}: #{real_header_length} columns expected but found #{row.length}" \
46
+ unless row.length == real_header_length
47
+ data = Hash[real_header.zip row]
48
+ to_discard.each { |key| data.delete key }
49
+ class << data
50
+ def[](key)
51
+ raise CSVHelperError, "Referencing undeclared key: #{key}" unless key? key
52
+ super
53
+ end
54
+ end
55
+ yield data
56
+ end
57
+ end
58
+
59
+ def self.csv_write_hashes(filename, headers, hashes)
60
+ CSV.open(filename, 'wb') do |csv|
61
+ csv << headers
62
+ hashes.each do |hash|
63
+ csv << headers.collect { |key| hash[key] }
64
+ end
65
+ end
66
+ end
67
+ end
68
+ # vim: autoindent tabstop=2 shiftwidth=2 expandtab softtabstop=2 filetype=ruby
@@ -0,0 +1,86 @@
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 'set'
21
+
22
+ class DeltaHashError < RuntimeError
23
+ end
24
+
25
+ class DeltaHash
26
+ attr_reader :new
27
+ attr_reader :del
28
+
29
+ def self.[](hash)
30
+ new(hash)
31
+ end
32
+
33
+ def initialize(hash)
34
+ @old = hash
35
+ @new = {}
36
+ @del = Set.new
37
+ end
38
+
39
+ def [](key)
40
+ return nil if @del.include? key
41
+ @new[key] || @old[key]
42
+ end
43
+
44
+ def []=(key, val)
45
+ raise DeltaHashError, 'Key exists' if self[key]
46
+ @del.delete key
47
+ @new[key] = val unless @old[key] == val
48
+ end
49
+
50
+ def to_hash
51
+ ret = (@old.merge @new)
52
+ @del.each do |key|
53
+ ret.delete key
54
+ end
55
+ ret
56
+ end
57
+
58
+ def delete(key)
59
+ raise DeltaHashError, "Key #{key} does not exist" unless self[key]
60
+ @del << key if @old[key]
61
+ @new.delete(key)
62
+ end
63
+
64
+ def delete_value(value)
65
+ deleted = 0
66
+ to_hash.each do |k, v|
67
+ next unless v == value
68
+ delete(k)
69
+ deleted += 1
70
+ end
71
+ return deleted
72
+ end
73
+
74
+ def to_s
75
+ to_hash.to_s
76
+ end
77
+
78
+ def inspect
79
+ to_hash.inspect
80
+ end
81
+
82
+ def changed?
83
+ ! (@new.empty? && del.empty?)
84
+ end
85
+ end
86
+ # vim: autoindent tabstop=2 shiftwidth=2 expandtab softtabstop=2 filetype=ruby
@@ -0,0 +1,27 @@
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 'time'
21
+
22
+ class Time
23
+ def iso8601
24
+ strftime '%Y-%m-%dT%H:%M:%S%z'
25
+ end
26
+ end
27
+ # vim: autoindent tabstop=2 shiftwidth=2 expandtab softtabstop=2 filetype=ruby
@@ -0,0 +1,52 @@
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 SystemGroupImportCommand < BaseCommand
26
+ command_name 'host-collection'
27
+ reportname = 'system-groups'
28
+ desc "Import Host Collections (from spacewalk-report #{reportname})."
29
+
30
+ csv_columns 'group_id', 'name', 'org_id'
31
+
32
+ persistent_maps :organizations, :host_collections
33
+
34
+ def mk_sg_hash(data)
35
+ {
36
+ :name => data['name'],
37
+ :organization_id => get_translated_id(:organizations, data['org_id'].to_i)
38
+ }
39
+ end
40
+
41
+ def import_single_row(data)
42
+ sg = mk_sg_hash data
43
+ create_entity(:host_collections, sg, data['group_id'].to_i)
44
+ end
45
+
46
+ def delete_single_row(data)
47
+ delete_entity(:host_collections, data['group_id'].to_i)
48
+ end
49
+ end
50
+ end
51
+ end
52
+ # vim: autoindent tabstop=2 shiftwidth=2 expandtab softtabstop=2 filetype=ruby
@@ -0,0 +1,31 @@
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/exit_codes'
22
+
23
+ module HammerCLIImport
24
+ class ImportCommand < HammerCLI::AbstractCommand
25
+ end
26
+
27
+ HammerCLI::MainCommand.subcommand('import',
28
+ 'Import data exported from a Red Hat Satellite 5 instance',
29
+ HammerCLIImport::ImportCommand)
30
+ end
31
+ # vim: autoindent tabstop=2 shiftwidth=2 expandtab softtabstop=2 filetype=ruby