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