hammer_cli_csv 0.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.
Files changed (69) hide show
  1. checksums.yaml +15 -0
  2. data/lib/hammer_cli_csv.rb +48 -0
  3. data/lib/hammer_cli_csv/activation_keys.rb +170 -0
  4. data/lib/hammer_cli_csv/architectures.rb +95 -0
  5. data/lib/hammer_cli_csv/base.rb +706 -0
  6. data/lib/hammer_cli_csv/compute_profiles.rb +94 -0
  7. data/lib/hammer_cli_csv/compute_resources.rb +92 -0
  8. data/lib/hammer_cli_csv/content_hosts.rb +357 -0
  9. data/lib/hammer_cli_csv/content_view_filters.rb +158 -0
  10. data/lib/hammer_cli_csv/content_views.rb +86 -0
  11. data/lib/hammer_cli_csv/csv.rb +23 -0
  12. data/lib/hammer_cli_csv/domains.rb +103 -0
  13. data/lib/hammer_cli_csv/exception_handler.rb +53 -0
  14. data/lib/hammer_cli_csv/host_collections.rb +108 -0
  15. data/lib/hammer_cli_csv/hosts.rb +118 -0
  16. data/lib/hammer_cli_csv/import.rb +82 -0
  17. data/lib/hammer_cli_csv/installation_medias.rb +88 -0
  18. data/lib/hammer_cli_csv/lifecycle_environments.rb +116 -0
  19. data/lib/hammer_cli_csv/locations.rb +84 -0
  20. data/lib/hammer_cli_csv/operating_systems.rb +95 -0
  21. data/lib/hammer_cli_csv/organizations.rb +107 -0
  22. data/lib/hammer_cli_csv/partition_tables.rb +98 -0
  23. data/lib/hammer_cli_csv/products.rb +179 -0
  24. data/lib/hammer_cli_csv/provisioning_templates.rb +96 -0
  25. data/lib/hammer_cli_csv/puppet_environments.rb +105 -0
  26. data/lib/hammer_cli_csv/puppet_facts.rb +99 -0
  27. data/lib/hammer_cli_csv/puppet_reports.rb +244 -0
  28. data/lib/hammer_cli_csv/reports.rb +91 -0
  29. data/lib/hammer_cli_csv/roles.rb +115 -0
  30. data/lib/hammer_cli_csv/smart_proxies.rb +88 -0
  31. data/lib/hammer_cli_csv/subnets.rb +121 -0
  32. data/lib/hammer_cli_csv/subscriptions.rb +135 -0
  33. data/lib/hammer_cli_csv/users.rb +133 -0
  34. data/lib/hammer_cli_csv/version.rb +16 -0
  35. data/test/activation_keys_test.rb +17 -0
  36. data/test/apipie_resource_mock.rb +77 -0
  37. data/test/config.template.yml +17 -0
  38. data/test/csv_test_helper.rb +65 -0
  39. data/test/data/activation-keys.csv +119 -0
  40. data/test/data/architectures.csv +5 -0
  41. data/test/data/content-hosts.csv +4 -0
  42. data/test/data/content-view-filters.csv +2 -0
  43. data/test/data/content-views.csv +6 -0
  44. data/test/data/domains.csv +8 -0
  45. data/test/data/host-collections.csv +16 -0
  46. data/test/data/hosts.csv +12 -0
  47. data/test/data/installation-medias.csv +7 -0
  48. data/test/data/lifecycle-environments.csv +6 -0
  49. data/test/data/locations.csv +10 -0
  50. data/test/data/operating-systems.csv +16 -0
  51. data/test/data/organizations.csv +5 -0
  52. data/test/data/partition-tables.csv +187 -0
  53. data/test/data/products.csv +19 -0
  54. data/test/data/puppet-environments.csv +6 -0
  55. data/test/data/puppet-facts.csv +9 -0
  56. data/test/data/reports.csv +4 -0
  57. data/test/data/roles.csv +159 -0
  58. data/test/data/smart-proxies.csv +2 -0
  59. data/test/data/subscriptions.csv +19 -0
  60. data/test/data/users.csv +119 -0
  61. data/test/helpers/command.rb +67 -0
  62. data/test/helpers/resource_disabled.rb +69 -0
  63. data/test/hosts_test.rb +47 -0
  64. data/test/organizations_test.rb +74 -0
  65. data/test/roles_test.rb +39 -0
  66. data/test/setup_test.rb +164 -0
  67. data/test/systems_test.rb +71 -0
  68. data/test/users_test.rb +35 -0
  69. metadata +174 -0
@@ -0,0 +1,15 @@
1
+ ---
2
+ !binary "U0hBMQ==":
3
+ metadata.gz: !binary |-
4
+ NzY3ZmEyZWZkYzk3MTA0NDAzMDNkNzIxYTRhNDc5ZmJhYWVjNDQ5MA==
5
+ data.tar.gz: !binary |-
6
+ MjBjNWJhOTBhOTE1YTU2MDI3YTAwYTRhMWI4OWJmNDQxMjY5ZmI0OQ==
7
+ SHA512:
8
+ metadata.gz: !binary |-
9
+ YWJjZDUxZDZiZjMwOTZiN2JlOWYwZmI0MTk0YTQwN2Y2OTYxMTdlYzc3Njlj
10
+ ZTkyNThkZjJiMzM0OTMzYTgzYWZkNjBhNDk1Y2MyMmY0M2U2MzZjYTYwMzY3
11
+ YjY0NzViZWZhNTAyNDY1NzBlNWUxYWZkMDA5MjgyMWFlZGRmYTE=
12
+ data.tar.gz: !binary |-
13
+ Njg1OTg0NWMxNzRiODNkYzM4NDdhMDcyMmIzMTE2YzliNzc5ZTE0YTE3MWU3
14
+ ZjNhZGUyYTk0YjBlZTkzMTg2MzhmYjMzMDQwNDY1MzhmNWYxOWU5NDBiZjBl
15
+ MWNlYWI0MjA0MzRjYmVkNmYxZWIxZTM4MjE3OWMyOGQ1ZDIwNmQ=
@@ -0,0 +1,48 @@
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 'hammer_cli'
13
+ require 'hammer_cli/exit_codes'
14
+
15
+ module HammerCLICsv
16
+ require 'hammer_cli_csv/base'
17
+ require 'hammer_cli_csv/exception_handler'
18
+
19
+ require 'hammer_cli_csv/csv'
20
+ require 'hammer_cli_csv/activation_keys'
21
+ require 'hammer_cli_csv/architectures'
22
+ require 'hammer_cli_csv/compute_profiles'
23
+ require 'hammer_cli_csv/compute_resources'
24
+ require 'hammer_cli_csv/content_hosts'
25
+ require 'hammer_cli_csv/content_views'
26
+ require 'hammer_cli_csv/content_view_filters'
27
+ require 'hammer_cli_csv/domains'
28
+ require 'hammer_cli_csv/host_collections'
29
+ require 'hammer_cli_csv/hosts'
30
+ require 'hammer_cli_csv/import'
31
+ require 'hammer_cli_csv/installation_medias'
32
+ require 'hammer_cli_csv/lifecycle_environments'
33
+ require 'hammer_cli_csv/locations'
34
+ require 'hammer_cli_csv/operating_systems'
35
+ require 'hammer_cli_csv/organizations'
36
+ require 'hammer_cli_csv/partition_tables'
37
+ require 'hammer_cli_csv/products'
38
+ require 'hammer_cli_csv/provisioning_templates'
39
+ require 'hammer_cli_csv/puppet_environments'
40
+ require 'hammer_cli_csv/puppet_facts'
41
+ require 'hammer_cli_csv/puppet_reports'
42
+ require 'hammer_cli_csv/reports'
43
+ require 'hammer_cli_csv/roles'
44
+ require 'hammer_cli_csv/smart_proxies'
45
+ require 'hammer_cli_csv/subnets'
46
+ require 'hammer_cli_csv/subscriptions'
47
+ require 'hammer_cli_csv/users'
48
+ end
@@ -0,0 +1,170 @@
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
+ module HammerCLICsv
13
+ class CsvCommand
14
+ class ActivationKeysCommand < BaseCommand
15
+ command_name 'activation-keys'
16
+ desc 'import or export activation keys'
17
+
18
+ ORGANIZATION = 'Organization'
19
+ DESCRIPTION = 'Description'
20
+ LIMIT = 'Limit'
21
+ ENVIRONMENT = 'Environment'
22
+ CONTENTVIEW = 'Content View'
23
+ SYSTEMGROUPS = 'System Groups'
24
+ SUBSCRIPTIONS = 'Subscriptions'
25
+
26
+ def export
27
+ CSV.open(option_csv_file || '/dev/stdout', 'wb', {:force_quotes => false}) do |csv|
28
+ csv << [NAME, COUNT, ORGANIZATION, DESCRIPTION, LIMIT, ENVIRONMENT, CONTENTVIEW,
29
+ SYSTEMGROUPS, SUBSCRIPTIONS]
30
+ @api.resource(:organizations)
31
+ .call(:index, {
32
+ :per_page => 999999
33
+ })['results'].each do |organization|
34
+ @api.resource(:activation_keys)
35
+ .call(:index, {
36
+ 'per_page' => 999999,
37
+ 'organization_id' => organization['id']
38
+ })['results'].each do |activationkey|
39
+ puts "Writing activation key '#{activationkey['name']}'" if option_verbose?
40
+ name = namify(activationkey['name'])
41
+ count = 1
42
+ description = activationkey['description']
43
+ limit = activationkey['usage_limit'].to_i < 0 ? 'Unlimited' : sytemgroup['usage_limit']
44
+ environment = activationkey['environment']['label']
45
+ contentview = activationkey['content_view']['name']
46
+ hostcollections = export_column(activationkey, 'systemGroups', 'name')
47
+ subscriptions = CSV.generate do |column|
48
+ column << @api.resource(:subscriptions).call(:index, {
49
+ 'activation_key_id' => activationkey['id']
50
+ })['results'].collect do |subscription|
51
+ amount = subscription['amount'] == 0 ? 'Automatic' : subscription['amount']
52
+ "#{amount}|#{subscription['product_name']}"
53
+ end
54
+ end
55
+ subscriptions.delete!("\n")
56
+ csv << [name, count, organization['label'], description, limit, environment, contentview,
57
+ hostcollections, subscriptions]
58
+ end
59
+ end
60
+ end
61
+ end
62
+
63
+ def import
64
+ @existing = {}
65
+
66
+ thread_import do |line|
67
+ create_activationkeys_from_csv(line)
68
+ end
69
+ end
70
+
71
+ def create_activationkeys_from_csv(line)
72
+ if !@existing[line[ORGANIZATION]]
73
+ @existing[line[ORGANIZATION]] = {}
74
+ @api.resource(:activation_keys)
75
+ .call(:index, {
76
+ 'per_page' => 999999,
77
+ 'organization_id' => foreman_organization(:name => line[ORGANIZATION])
78
+ })['results'].each do |activationkey|
79
+ @existing[line[ORGANIZATION]][activationkey['name']] = activationkey['id'] if activationkey
80
+ end
81
+ end
82
+
83
+ line[COUNT].to_i.times do |number|
84
+ name = namify(line[NAME], number)
85
+
86
+ if !@existing[line[ORGANIZATION]].include? name
87
+ print "Creating activation key '#{name}'..." if option_verbose?
88
+ activationkey = @api.resource(:activation_keys)
89
+ .call(:create, {
90
+ 'name' => name,
91
+ 'environment_id' => lifecycle_environment(line[ORGANIZATION],
92
+ :name => line[ENVIRONMENT]),
93
+ 'content_view_id' => katello_contentview(line[ORGANIZATION],
94
+ :name => line[CONTENTVIEW]),
95
+ 'description' => line[DESCRIPTION],
96
+ 'usage_limit' => usage_limit(line[LIMIT])
97
+ })
98
+ @existing[line[ORGANIZATION]][activationkey['name']] = activationkey['id']
99
+ else
100
+ print "Updating activation key '#{name}'..." if option_verbose?
101
+ activationkey = @api.resource(:activation_keys)
102
+ .call(:update, {
103
+ 'id' => @existing[line[ORGANIZATION]][name],
104
+ 'name' => name,
105
+ 'environment_id' => lifecycle_environment(line[ORGANIZATION],
106
+ :name => line[ENVIRONMENT]),
107
+ 'content_view_id' => katello_contentview(line[ORGANIZATION],
108
+ :name => line[CONTENTVIEW]),
109
+ 'description' => line[DESCRIPTION],
110
+ 'usage_limit' => usage_limit(line[LIMIT])
111
+ })
112
+ end
113
+
114
+ update_subscriptions(activationkey, line)
115
+ update_groups(activationkey, line)
116
+
117
+ puts 'done' if option_verbose?
118
+ end
119
+ end
120
+
121
+ def update_groups(activationkey, line)
122
+ if line[SYSTEMGROUPS] && line[SYSTEMGROUPS] != ''
123
+ # TODO: note that existing system groups are not removed
124
+ CSV.parse_line(line[SYSTEMGROUPS], {:skip_blanks => true}).each do |name|
125
+ @api.resource(:host_collections)
126
+ .call(:add_activation_keys, {
127
+ 'id' => katello_hostcollection(line[ORGANIZATION], :name => name),
128
+ 'activation_key_ids' => [activationkey['id']]
129
+ })
130
+ end
131
+ end
132
+ end
133
+
134
+ def update_subscriptions(activationkey, line)
135
+ if line[SUBSCRIPTIONS] && line[SUBSCRIPTIONS] != ''
136
+ subscriptions = CSV.parse_line(line[SUBSCRIPTIONS], {:skip_blanks => true}).collect do |subscription_details|
137
+ (amount, name) = subscription_details.split('|')
138
+ {
139
+ :id => katello_subscription(line[ORGANIZATION], :name => name),
140
+ :quantity => amount
141
+ }
142
+ end
143
+
144
+ # TODO: should there be a destroy_all similar to systems?
145
+ @api.resource(:subscriptions)
146
+ .call(:index, {
147
+ 'per_page' => 999999,
148
+ 'activation_key_id' => activationkey['id']
149
+ })['results'].each do |subscription|
150
+ @api.resource(:subscriptions)
151
+ .call(:destroy, {
152
+ 'id' => subscription['id'],
153
+ 'activation_key_id' => activationkey['id']
154
+ })
155
+ end
156
+
157
+ @api.resource(:subscriptions)
158
+ .call(:create, {
159
+ 'activation_key_id' => activationkey['id'],
160
+ 'subscriptions' => subscriptions
161
+ })
162
+ end
163
+ end
164
+
165
+ def usage_limit(limit)
166
+ Integer(limit) rescue -1
167
+ end
168
+ end
169
+ end
170
+ end
@@ -0,0 +1,95 @@
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
+ #
13
+ # -= Architectures CSV =-
14
+ #
15
+ # Columns
16
+ # Name
17
+ # - Architecture name
18
+ # - May contain '%d' which will be replaced with current iteration number of Count
19
+ # - eg. "os%d" -> "os1"
20
+ # Count
21
+ # - Number of times to iterate on this line of the CSV file
22
+ #
23
+
24
+ require 'hammer_cli'
25
+ require 'json'
26
+ require 'csv'
27
+
28
+ module HammerCLICsv
29
+ class CsvCommand
30
+ class ArchitecturesCommand < BaseCommand
31
+ command_name 'architectures'
32
+ desc 'import or export architectures'
33
+
34
+ OPERATINGSYSTEMS = 'Operating Systems'
35
+
36
+ def export
37
+ CSV.open(option_csv_file || '/dev/stdout', 'wb', {:force_quotes => true}) do |csv|
38
+ csv << [NAME, COUNT, ORGANIZATIONS, OPERATINGSYSTEMS]
39
+ @api.resource(:architectures).call(:index, {:per_page => 999999})['results'].each do |architecture|
40
+ name = architecture['name']
41
+ count = 1
42
+ # TODO: http://projects.theforeman.org/issues/4198
43
+ #operatingsystems = architecture['operatingsystem_ids'].collect do |operatingsystem_id|
44
+ # foreman_operatingsystem(:id => operatingsystem_id)
45
+ #end.join(',')
46
+ operatingsystems = ''
47
+ csv << [name, count, operatingsystems]
48
+ end
49
+ end
50
+ end
51
+
52
+ def import
53
+ @existing = {}
54
+ @api.resource(:architectures).call(:index, {:per_page => 999999})['results'].each do |architecture|
55
+ @existing[architecture['name']] = architecture['id'] if architecture
56
+ end
57
+
58
+ thread_import do |line|
59
+ create_architectures_from_csv(line)
60
+ end
61
+ end
62
+
63
+ def create_architectures_from_csv(line)
64
+ line[COUNT].to_i.times do |number|
65
+ name = namify(line[NAME], number)
66
+ architecture_id = @existing[name]
67
+ operatingsystem_ids = CSV.parse_line(line[OPERATINGSYSTEMS]).collect do |operatingsystem_name|
68
+ foreman_operatingsystem(:name => operatingsystem_name)
69
+ end
70
+ if !architecture_id
71
+ print "Creating architecture '#{name}'..." if option_verbose?
72
+ architecture_id = @api.resource(:architectures).call(:create, {
73
+ 'architecture' => {
74
+ 'name' => name,
75
+ 'operatingsystem_ids' => operatingsystem_ids
76
+ }
77
+ })
78
+ else
79
+ print "Updating architecture '#{name}'..." if option_verbose?
80
+ @api.resource(:architectures).call(:update, {
81
+ 'id' => architecture_id,
82
+ 'architecture' => {
83
+ 'name' => name,
84
+ 'operatingsystem_ids' => operatingsystem_ids
85
+ }
86
+ })
87
+ end
88
+ print "done\n" if option_verbose?
89
+ end
90
+ rescue RuntimeError => e
91
+ raise "#{e}\n #{line}"
92
+ end
93
+ end
94
+ end
95
+ end
@@ -0,0 +1,706 @@
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 'apipie-bindings'
13
+ require 'hammer_cli'
14
+ require 'json'
15
+ require 'csv'
16
+ require 'hammer_cli_csv/csv'
17
+
18
+ module HammerCLICsv
19
+ class BaseCommand < HammerCLI::Apipie::Command
20
+ option %w(-v --verbose), :flag, 'be verbose'
21
+ option %w(--threads), 'THREAD_COUNT', 'Number of threads to hammer with', :default => 1
22
+ option %w(--csv-export), :flag, 'Export current data instead of importing'
23
+ option %w(--csv-file), 'FILE_NAME', 'CSV file (default to /dev/stdout with --csv-export, otherwise required)'
24
+ option %w(--prefix), 'PREFIX', 'Prefix for all name columns'
25
+ option %w(--server), 'SERVER', 'Server URL'
26
+ option %w(-u --username), 'USERNAME', 'Username to access server'
27
+ option %w(-p --password), 'PASSWORD', 'Password to access server'
28
+
29
+ NAME = 'Name'
30
+ COUNT = 'Count'
31
+
32
+ def execute
33
+ if !option_csv_file
34
+ if option_csv_export?
35
+ # rubocop:disable UselessAssignment
36
+ option_csv_file = '/dev/stdout'
37
+ else
38
+ # rubocop:disable UselessAssignment
39
+ option_csv_file = '/dev/stdin'
40
+ end
41
+ end
42
+
43
+ @api = ApipieBindings::API.new({
44
+ :uri => option_server || HammerCLI::Settings.get(:csv, :host),
45
+ :username => option_username || HammerCLI::Settings.get(:csv, :username),
46
+ :password => option_password || HammerCLI::Settings.get(:csv, :password),
47
+ :api_version => 2
48
+ })
49
+
50
+ option_csv_export? ? export : import
51
+ HammerCLI::EX_OK
52
+ end
53
+
54
+ def namify(name_format, number = 0)
55
+ if name_format.index('%')
56
+ name = name_format % number
57
+ else
58
+ name = name_format
59
+ end
60
+ name = "#{option_prefix}#{name}" if option_prefix
61
+ name
62
+ end
63
+
64
+ def labelize(name)
65
+ name.gsub(/[^a-z0-9\-_]/i, '_')
66
+ end
67
+
68
+ def thread_import(return_headers = false)
69
+ csv = []
70
+ CSV.foreach(option_csv_file || '/dev/stdin', {
71
+ :skip_blanks => true,
72
+ :headers => :first_row,
73
+ :return_headers => return_headers
74
+ }) do |line|
75
+ csv << line
76
+ end
77
+ lines_per_thread = csv.length / option_threads.to_i + 1
78
+ splits = []
79
+
80
+ option_threads.to_i.times do |current_thread|
81
+ start_index = ((current_thread) * lines_per_thread).to_i
82
+ finish_index = ((current_thread + 1) * lines_per_thread).to_i
83
+ finish_index = csv.length if finish_index > csv.length
84
+ if start_index <= finish_index
85
+ lines = csv[start_index...finish_index].clone
86
+ splits << Thread.new do
87
+ lines.each do |line|
88
+ if line[NAME][0] != '#'
89
+ yield line
90
+ end
91
+ end
92
+ end
93
+ end
94
+ end
95
+
96
+ splits.each do |thread|
97
+ thread.join
98
+ end
99
+ end
100
+
101
+ def hammer_context
102
+ {
103
+ :interactive => false,
104
+ :username => 'admin', # TODO: this needs to come from config/settings
105
+ :password => 'changeme' # TODO: this needs to come from config/settings
106
+ }
107
+ end
108
+
109
+ def hammer(context = nil)
110
+ HammerCLI::MainCommand.new('', context || hammer_context)
111
+ end
112
+
113
+ def foreman_organization(options = {})
114
+ @organizations ||= {}
115
+
116
+ if options[:name]
117
+ return nil if options[:name].nil? || options[:name].empty?
118
+ options[:id] = @organizations[options[:name]]
119
+ if !options[:id]
120
+ organization = @api.resource(:organizations).call(:index, {
121
+ :per_page => 999999,
122
+ 'search' => "name=\"#{options[:name]}\""
123
+ })['results']
124
+ raise "Organization '#{options[:name]}' not found" if !organization || organization.empty?
125
+ options[:id] = organization[0]['id']
126
+ @organizations[options[:name]] = options[:id]
127
+ end
128
+ result = options[:id]
129
+ else
130
+ return nil if options[:id].nil?
131
+ options[:name] = @organizations.key(options[:id])
132
+ if !options[:name]
133
+ organization = @api.resource(:organizations).call(:show, {'id' => options[:id]})
134
+ raise "Organization 'id=#{options[:id]}' not found" if !organization || organization.empty?
135
+ options[:name] = organization['name']
136
+ @organizations[options[:name]] = options[:id]
137
+ end
138
+ result = options[:name]
139
+ end
140
+
141
+ result
142
+ end
143
+
144
+ def foreman_location(options = {})
145
+ @locations ||= {}
146
+
147
+ if options[:name]
148
+ return nil if options[:name].nil? || options[:name].empty?
149
+ options[:id] = @locations[options[:name]]
150
+ if !options[:id]
151
+ location = @api.resource(:locations).call(:index, {
152
+ :per_page => 999999,
153
+ 'search' => "name=\"#{options[:name]}\""
154
+ })['results']
155
+ raise "Location '#{options[:name]}' not found" if !location || location.empty?
156
+ options[:id] = location[0]['id']
157
+ @locations[options[:name]] = options[:id]
158
+ end
159
+ result = options[:id]
160
+ else
161
+ return nil if options[:id].nil?
162
+ options[:name] = @locations.key(options[:id])
163
+ if !options[:name]
164
+ location = @api.resource(:locations).call(:show, {'id' => options[:id]})
165
+ raise "Location 'id=#{options[:id]}' not found" if !location || location.empty?
166
+ options[:name] = location['name']
167
+ @locations[options[:name]] = options[:id]
168
+ end
169
+ result = options[:name]
170
+ end
171
+
172
+ result
173
+ end
174
+
175
+ def foreman_role(options = {})
176
+ @roles ||= {}
177
+
178
+ if options[:name]
179
+ return nil if options[:name].nil? || options[:name].empty?
180
+ options[:id] = @roles[options[:name]]
181
+ if !options[:id]
182
+ role = @api.resource(:roles).call(:index, {
183
+ :per_page => 999999,
184
+ 'search' => "name=\"#{options[:name]}\""
185
+ })['results']
186
+ raise "Role '#{options[:name]}' not found" if !role || role.empty?
187
+ options[:id] = role[0]['id']
188
+ @roles[options[:name]] = options[:id]
189
+ end
190
+ result = options[:id]
191
+ else
192
+ return nil if options[:id].nil?
193
+ options[:name] = @roles.key(options[:id])
194
+ if !options[:name]
195
+ role = @api.resource(:roles).call(:show, {'id' => options[:id]})
196
+ raise "Role 'id=#{options[:id]}' not found" if !role || role.empty?
197
+ options[:name] = role['name']
198
+ @roles[options[:name]] = options[:id]
199
+ end
200
+ result = options[:name]
201
+ end
202
+
203
+ result
204
+ end
205
+
206
+ def foreman_permission(options = {})
207
+ @permissions ||= {}
208
+
209
+ if options[:name]
210
+ return nil if options[:name].nil? || options[:name].empty?
211
+ options[:id] = @permissions[options[:name]]
212
+ if !options[:id]
213
+ permission = @api.resource(:permissions).call(:index, {
214
+ :per_page => 999999,
215
+ 'name' => options[:name]
216
+ })['results']
217
+ raise "Permission '#{options[:name]}' not found" if !permission || permission.empty?
218
+ options[:id] = permission[0]['id']
219
+ @permissions[options[:name]] = options[:id]
220
+ end
221
+ result = options[:id]
222
+ else
223
+ return nil if options[:id].nil?
224
+ options[:name] = @permissions.key(options[:id])
225
+ if !options[:name]
226
+ permission = @api.resource(:permissions).call(:show, {'id' => options[:id]})
227
+ raise "Permission 'id=#{options[:id]}' not found" if !permission || permission.empty?
228
+ options[:name] = permission['name']
229
+ @permissions[options[:name]] = options[:id]
230
+ end
231
+ result = options[:name]
232
+ end
233
+
234
+ result
235
+ end
236
+
237
+ def foreman_filter(role, resource, search)
238
+ search = nil if search && search.empty?
239
+ filters = @api.resource(:filters).call(:index, {
240
+ :per_page => 999999,
241
+ 'search' => "role=\"#{role}\""
242
+ })['results']
243
+ filters.each do |filter|
244
+ return filter['id'] if filter['resource_type'] == resource && filter['search'] == search
245
+ end
246
+
247
+ nil
248
+ end
249
+
250
+ def foreman_environment(options = {})
251
+ @environments ||= {}
252
+
253
+ if options[:name]
254
+ return nil if options[:name].nil? || options[:name].empty?
255
+ options[:id] = @environments[options[:name]]
256
+ if !options[:id]
257
+ environment = @api.resource(:environments).call(:index, {
258
+ :per_page => 999999,
259
+ 'search' => "name=\"#{ options[:name] }\""
260
+ })['results']
261
+ raise "Puppet environment '#{options[:name]}' not found" if !environment || environment.empty?
262
+ options[:id] = environment[0]['id']
263
+ @environments[options[:name]] = options[:id]
264
+ end
265
+ result = options[:id]
266
+ else
267
+ return nil if options[:id].nil?
268
+ options[:name] = @environments.key(options[:id])
269
+ if !options[:name]
270
+ environment = @api.resource(:environments).call(:show, {'id' => options[:id]})
271
+ raise "Puppet environment '#{options[:name]}' not found" if !environment || environment.empty?
272
+ options[:name] = environment['name']
273
+ @environments[options[:name]] = options[:id]
274
+ end
275
+ result = options[:name]
276
+ end
277
+
278
+ result
279
+ end
280
+
281
+ def foreman_template_kind(options = {})
282
+ @template_kinds ||= {}
283
+
284
+ if options[:name]
285
+ return nil if options[:name].nil? || options[:name].empty?
286
+ options[:id] = @template_kinds[options[:name]]
287
+ if !options[:id]
288
+ template_kind = @api.resource(:template_kinds).call(:index, {
289
+ :per_page => 999999,
290
+ 'search' => "name=\"#{options[:name]}\""
291
+ })['results']
292
+ raise "Template kind '#{options[:name]}' not found" if !template_kind || template_kind.empty?
293
+ options[:id] = template_kind[0]['id']
294
+ @template_kinds[options[:name]] = options[:id]
295
+ end
296
+ result = options[:id]
297
+ else
298
+ return nil if options[:id].nil?
299
+ options[:name] = @template_kinds.key(options[:id])
300
+ if !options[:name]
301
+ template_kind = @api.resource(:template_kinds).call(:show, {'id' => options[:id]})
302
+ raise "Template kind 'id=#{options[:id]}' not found" if !template_kind || template_kind.empty?
303
+ options[:name] = template_kind['name']
304
+ @template_kinds[options[:name]] = options[:id]
305
+ end
306
+ result = options[:name]
307
+ end
308
+
309
+ result
310
+ end
311
+
312
+ def foreman_operatingsystem(options = {})
313
+ @operatingsystems ||= {}
314
+
315
+ if options[:name]
316
+ return nil if options[:name].nil? || options[:name].empty?
317
+ options[:id] = @operatingsystems[options[:name]]
318
+ if !options[:id]
319
+ (osname, major, minor) = split_os_name(options[:name])
320
+ search = "name=\"#{osname}\" and major=\"#{major}\" and minor=\"#{minor}\""
321
+ operatingsystems = @api.resource(:operatingsystems).call(:index, {
322
+ :per_page => 999999,
323
+ 'search' => search
324
+ })['results']
325
+ operatingsystem = operatingsystems[0]
326
+ raise "Operating system '#{options[:name]}' not found" if !operatingsystem || operatingsystem.empty?
327
+ options[:id] = operatingsystem['id']
328
+ @operatingsystems[options[:name]] = options[:id]
329
+ end
330
+ result = options[:id]
331
+ else
332
+ return nil if options[:id].nil?
333
+ options[:name] = @operatingsystems.key(options[:id])
334
+ if !options[:name]
335
+ operatingsystem = @api.resource(:operatingsystems).call(:show, {'id' => options[:id]})
336
+ raise "Operating system 'id=#{options[:id]}' not found" if !operatingsystem || operatingsystem.empty?
337
+ options[:name] = build_os_name(operatingsystem['name'],
338
+ operatingsystem['major'],
339
+ operatingsystem['minor'])
340
+ @operatingsystems[options[:name]] = options[:id]
341
+ end
342
+ result = options[:name]
343
+ end
344
+
345
+ result
346
+ end
347
+
348
+ def foreman_architecture(options = {})
349
+ @architectures ||= {}
350
+
351
+ if options[:name]
352
+ return nil if options[:name].nil? || options[:name].empty?
353
+ options[:id] = @architectures[options[:name]]
354
+ if !options[:id]
355
+ architecture = @api.resource(:architectures).call(:index, {
356
+ :per_page => 999999,
357
+ 'search' => "name=\"#{options[:name]}\""
358
+ })['results']
359
+ raise "Architecture '#{options[:name]}' not found" if !architecture || architecture.empty?
360
+ options[:id] = architecture[0]['id']
361
+ @architectures[options[:name]] = options[:id]
362
+ end
363
+ result = options[:id]
364
+ else
365
+ return nil if options[:id].nil?
366
+ options[:name] = @architectures.key(options[:id])
367
+ if !options[:name]
368
+ architecture = @api.resource(:architectures).call(:show, {'id' => options[:id]})
369
+ raise "Architecture 'id=#{options[:id]}' not found" if !architecture || architecture.empty?
370
+ options[:name] = architecture['name']
371
+ @architectures[options[:name]] = options[:id]
372
+ end
373
+ result = options[:name]
374
+ end
375
+
376
+ result
377
+ end
378
+
379
+ def foreman_domain(options = {})
380
+ @domains ||= {}
381
+
382
+ if options[:name]
383
+ return nil if options[:name].nil? || options[:name].empty?
384
+ options[:id] = @domains[options[:name]]
385
+ if !options[:id]
386
+ domain = @api.resource(:domains).call(:index, {
387
+ :per_page => 999999,
388
+ 'search' => "name=\"#{options[:name]}\""
389
+ })['results']
390
+ raise "Domain '#{options[:name]}' not found" if !domain || domain.empty?
391
+ options[:id] = domain[0]['id']
392
+ @domains[options[:name]] = options[:id]
393
+ end
394
+ result = options[:id]
395
+ else
396
+ return nil if options[:id].nil?
397
+ options[:name] = @domains.key(options[:id])
398
+ if !options[:name]
399
+ domain = @api.resource(:domains).call(:show, {'id' => options[:id]})
400
+ raise "Domain 'id=#{options[:id]}' not found" if !domain || domain.empty?
401
+ options[:name] = domain['name']
402
+ @domains[options[:name]] = options[:id]
403
+ end
404
+ result = options[:name]
405
+ end
406
+
407
+ result
408
+ end
409
+
410
+ def foreman_partitiontable(options = {})
411
+ @ptables ||= {}
412
+
413
+ if options[:name]
414
+ return nil if options[:name].nil? || options[:name].empty?
415
+ options[:id] = @ptables[options[:name]]
416
+ if !options[:id]
417
+ ptable = @api.resource(:ptables).call(:index, {
418
+ :per_page => 999999,
419
+ 'search' => "name=\"#{options[:name]}\""
420
+ })['results']
421
+ raise "Partition table '#{options[:name]}' not found" if !ptable || ptable.empty?
422
+ options[:id] = ptable[0]['id']
423
+ @ptables[options[:name]] = options[:id]
424
+ end
425
+ result = options[:id]
426
+ elsif options[:id]
427
+ return nil if options[:id].nil?
428
+ options[:name] = @ptables.key(options[:id])
429
+ if !options[:name]
430
+ ptable = @api.resource(:ptables).call(:show, {'id' => options[:id]})
431
+ options[:name] = ptable['name']
432
+ @ptables[options[:name]] = options[:id]
433
+ end
434
+ result = options[:name]
435
+ elsif !options[:name] && !options[:id]
436
+ result = ''
437
+ end
438
+
439
+ result
440
+ end
441
+
442
+ def lifecycle_environment(organization, options = {})
443
+ @lifecycle_environments ||= {}
444
+ @lifecycle_environments[organization] ||= {
445
+ }
446
+
447
+ if options[:name]
448
+ return nil if options[:name].nil? || options[:name].empty?
449
+ options[:id] = @lifecycle_environments[organization][options[:name]]
450
+ if !options[:id]
451
+ @api.resource(:lifecycle_environments)
452
+ .call(:index, {
453
+ :per_page => 999999,
454
+ 'organization_id' => foreman_organization(:name => organization)
455
+ })['results'].each do |environment|
456
+ @lifecycle_environments[organization][environment['name']] = environment['id']
457
+ end
458
+ options[:id] = @lifecycle_environments[organization][options[:name]]
459
+ raise "Lifecycle environment '#{options[:name]}' not found" if !options[:id]
460
+ end
461
+ result = options[:id]
462
+ else
463
+ return nil if options[:id].nil?
464
+ options[:name] = @lifecycle_environments.key(options[:id])
465
+ if !options[:name]
466
+ environment = @api.resource(:lifecycle_environments).call(:show, {'id' => options[:id]})
467
+ raise "Lifecycle environment '#{options[:name]}' not found" if !environment || environment.empty?
468
+ options[:name] = environment['name']
469
+ @lifecycle_environments[options[:name]] = options[:id]
470
+ end
471
+ result = options[:name]
472
+ end
473
+
474
+ result
475
+ end
476
+
477
+ def katello_contentview(organization, options = {})
478
+ @contentviews ||= {}
479
+ @contentviews[organization] ||= {}
480
+
481
+ if options[:name]
482
+ return nil if options[:name].nil? || options[:name].empty?
483
+ options[:id] = @contentviews[organization][options[:name]]
484
+ if !options[:id]
485
+ @api.resource(:content_views).call(:index, {
486
+ :per_page => 999999,
487
+ 'organization_id' => foreman_organization(:name => organization)
488
+ })['results'].each do |contentview|
489
+ @contentviews[organization][contentview['name']] = contentview['id']
490
+ end
491
+ options[:id] = @contentviews[organization][options[:name]]
492
+ raise "Content view '#{options[:name]}' not found" if !options[:id]
493
+ end
494
+ result = options[:id]
495
+ else
496
+ return nil if options[:id].nil?
497
+ options[:name] = @contentviews.key(options[:id])
498
+ if !options[:name]
499
+ contentview = @api.resource(:content_views).call(:show, {'id' => options[:id]})
500
+ raise "Puppet contentview '#{options[:name]}' not found" if !contentview || contentview.empty?
501
+ options[:name] = contentview['name']
502
+ @contentviews[options[:name]] = options[:id]
503
+ end
504
+ result = options[:name]
505
+ end
506
+
507
+ result
508
+ end
509
+
510
+ def katello_repository(organization, options = {})
511
+ @repositories ||= {}
512
+ @repositories[organization] ||= {}
513
+
514
+ if options[:name]
515
+ return nil if options[:name].nil? || options[:name].empty?
516
+ options[:id] = @repositories[organization][options[:name]]
517
+ if !options[:id]
518
+ @api.resource(:repositories)
519
+ .call(:index, {
520
+ :per_page => 999999,
521
+ 'organization_id' => foreman_organization(:name => organization)
522
+ })['results'].each do |repository|
523
+ @repositories[organization][repository['name']] = repository['id']
524
+ end
525
+ options[:id] = @repositories[organization][options[:name]]
526
+ raise "Repository '#{options[:name]}' not found" if !options[:id]
527
+ end
528
+ result = options[:id]
529
+ else
530
+ return nil if options[:id].nil?
531
+ options[:name] = @repositories.key(options[:id])
532
+ if !options[:name]
533
+ repository = @api.resource(:repositories).call(:show, {'id' => options[:id]})
534
+ raise "Puppet repository '#{options[:name]}' not found" if !repository || repository.empty?
535
+ options[:name] = repository['name']
536
+ @repositoriesr[options[:name]] = options[:id]
537
+ end
538
+ result = options[:name]
539
+ end
540
+
541
+ result
542
+ end
543
+
544
+ def katello_subscription(organization, options = {})
545
+ @subscriptions ||= {}
546
+ @subscriptions[organization] ||= {}
547
+
548
+ if options[:name]
549
+ return nil if options[:name].nil? || options[:name].empty?
550
+ options[:id] = @subscriptions[organization][options[:name]]
551
+ if !options[:id]
552
+ results = @api.resource(:subscriptions).call(:index, {
553
+ :per_page => 999999,
554
+ 'organization_id' => foreman_organization(:name => organization),
555
+ 'search' => "name:\"#{options[:name]}\""
556
+ })
557
+ raise "No subscriptions match '#{options[:name]}'" if results['subtotal'] == 0
558
+ raise "Too many subscriptions match '#{options[:name]}'" if results['subtotal'] > 1
559
+ subscription = results['results'][0]
560
+ @subscriptions[organization][options[:name]] = subscription['id']
561
+ options[:id] = @subscriptions[organization][options[:name]]
562
+ raise "Subscription '#{options[:name]}' not found" if !options[:id]
563
+ end
564
+ result = options[:id]
565
+ else
566
+ return nil if options[:id].nil?
567
+ options[:name] = @subscriptions.key(options[:id])
568
+ if !options[:name]
569
+ subscription = @api.resource(:subscriptions).call(:show, {'id' => options[:id]})
570
+ raise "Subscription '#{options[:name]}' not found" if !subscription || subscription.empty?
571
+ options[:name] = subscription['name']
572
+ @subscriptions[options[:name]] = options[:id]
573
+ end
574
+ result = options[:name]
575
+ end
576
+
577
+ result
578
+ end
579
+
580
+ def katello_hostcollection(organization, options = {})
581
+ @hostcollections ||= {}
582
+ @hostcollections[organization] ||= {}
583
+
584
+ if options[:name]
585
+ return nil if options[:name].nil? || options[:name].empty?
586
+ options[:id] = @hostcollections[organization][options[:name]]
587
+ if !options[:id]
588
+ @api.resource(:host_collections).call(:index,
589
+ {
590
+ :per_page => 999999,
591
+ 'organization_id' => foreman_organization(:name => organization),
592
+ 'search' => "name:\"#{options[:name]}\""
593
+ })['results'].each do |hostcollection|
594
+ @hostcollections[organization][hostcollection['name']] = hostcollection['id'] if hostcollection
595
+ end
596
+ options[:id] = @hostcollections[organization][options[:name]]
597
+ raise "System group '#{options[:name]}' not found" if !options[:id]
598
+ end
599
+ result = options[:id]
600
+ else
601
+ return nil if options[:id].nil?
602
+ options[:name] = @hostcollections.key(options[:id])
603
+ if !options[:name]
604
+ hostcollection = @api.resource(:host_collections).call(:show, {'id' => options[:id]})
605
+ raise "System group '#{options[:name]}' not found" if !hostcollection || hostcollection.empty?
606
+ options[:name] = hostcollection['name']
607
+ @hostcollections[options[:name]] = options[:id]
608
+ end
609
+ result = options[:name]
610
+ end
611
+
612
+ result
613
+ end
614
+
615
+ def build_os_name(name, major, minor)
616
+ name += " #{major}" if major && major != ''
617
+ name += ".#{minor}" if minor && minor != ''
618
+ name
619
+ end
620
+
621
+ # "Red Hat 6.4" => "Red Hat", "6", "4"
622
+ # "Red Hat 6" => "Red Hat", "6", ''
623
+ def split_os_name(name)
624
+ tokens = name.split(' ')
625
+ is_number = Float(tokens[-1]) rescue false
626
+ if is_number
627
+ (major, minor) = tokens[-1].split('.').flatten
628
+ name = tokens[0...-1].join(' ')
629
+ else
630
+ name = tokens.join(' ')
631
+ end
632
+ [name, major || '', minor || '']
633
+ end
634
+
635
+ def export_column(object, name, field)
636
+ return '' unless object[name]
637
+ values = CSV.generate do |column|
638
+ column << object[name].collect do |fields|
639
+ fields[field]
640
+ end
641
+ end
642
+ values.delete!("\n")
643
+ end
644
+
645
+ def collect_column(column)
646
+ return [] if column.nil? || column.empty?
647
+ CSV.parse_line(column, {:skip_blanks => true}).collect do |value|
648
+ yield value
649
+ end
650
+ end
651
+
652
+ def pluralize(name)
653
+ case name
654
+ when /smart_proxy/
655
+ 'smart_proxies'
656
+ else
657
+ "#{name}s"
658
+ end
659
+ end
660
+
661
+ def associate_organizations(id, organizations, name)
662
+ return if organizations.nil?
663
+
664
+ associations ||= {}
665
+ CSV.parse_line(organizations).each do |organization|
666
+ organization_id = foreman_organization(:name => organization)
667
+ if associations[organization].nil?
668
+ associations[organization] = @api.resource(:organizations).call(:show, {'id' => organization_id})[pluralize(name)].collect do |reference_object|
669
+ reference_object['id']
670
+ end
671
+ end
672
+ associations[organization] += [id] if !associations[organization].include? id
673
+ @api.resource(:organizations)
674
+ .call(:update, {
675
+ 'id' => organization_id,
676
+ 'organization' => {
677
+ "#{name}_ids" => associations[organization]
678
+ }
679
+ })
680
+ end if organizations && !organizations.empty?
681
+ end
682
+
683
+ def associate_locations(id, locations, name)
684
+ return if locations.nil?
685
+
686
+ associations ||= {}
687
+ CSV.parse_line(locations).each do |location|
688
+ location_id = foreman_location(:name => location)
689
+ if associations[location].nil?
690
+ associations[location] = @api.resource(:locations).call(:show, {'id' => location_id})[pluralize(name)].collect do |reference_object|
691
+ reference_object['id']
692
+ end
693
+ end
694
+ associations[location] += [id] if !associations[location].include? id
695
+
696
+ @api.resource(:locations)
697
+ .call(:update, {
698
+ 'id' => location_id,
699
+ 'location' => {
700
+ "#{name}_ids" => associations[location]
701
+ }
702
+ })
703
+ end if locations && !locations.empty?
704
+ end
705
+ end
706
+ end