hammer_cli_csv 2.0.0 → 2.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (87) hide show
  1. checksums.yaml +5 -13
  2. data/config/cli_config.yml +9 -24
  3. data/lib/hammer_cli_csv/activation_keys.rb +220 -95
  4. data/lib/hammer_cli_csv/architectures.rb +7 -11
  5. data/lib/hammer_cli_csv/base.rb +67 -41
  6. data/lib/hammer_cli_csv/compute_profiles.rb +11 -15
  7. data/lib/hammer_cli_csv/compute_resources.rb +11 -15
  8. data/lib/hammer_cli_csv/containers.rb +10 -12
  9. data/lib/hammer_cli_csv/content_hosts.rb +285 -203
  10. data/lib/hammer_cli_csv/content_view_filters.rb +32 -36
  11. data/lib/hammer_cli_csv/content_views.rb +33 -37
  12. data/lib/hammer_cli_csv/csv.rb +17 -1
  13. data/lib/hammer_cli_csv/domains.rb +15 -19
  14. data/lib/hammer_cli_csv/export.rb +13 -5
  15. data/lib/hammer_cli_csv/host_collections.rb +20 -22
  16. data/lib/hammer_cli_csv/host_groups.rb +73 -65
  17. data/lib/hammer_cli_csv/hosts.rb +30 -34
  18. data/lib/hammer_cli_csv/import.rb +24 -10
  19. data/lib/hammer_cli_csv/installation_media.rb +74 -0
  20. data/lib/hammer_cli_csv/job_templates.rb +37 -41
  21. data/lib/hammer_cli_csv/lifecycle_environments.rb +15 -19
  22. data/lib/hammer_cli_csv/locations.rb +4 -6
  23. data/lib/hammer_cli_csv/operating_systems.rb +17 -21
  24. data/lib/hammer_cli_csv/organizations.rb +11 -13
  25. data/lib/hammer_cli_csv/partition_tables.rb +17 -21
  26. data/lib/hammer_cli_csv/products.rb +200 -92
  27. data/lib/hammer_cli_csv/provisioning_templates.rb +19 -23
  28. data/lib/hammer_cli_csv/puppet_environments.rb +8 -12
  29. data/lib/hammer_cli_csv/puppet_facts.rb +20 -24
  30. data/lib/hammer_cli_csv/puppet_reports.rb +47 -51
  31. data/lib/hammer_cli_csv/reports.rb +6 -10
  32. data/lib/hammer_cli_csv/roles.rb +12 -16
  33. data/lib/hammer_cli_csv/settings.rb +8 -6
  34. data/lib/hammer_cli_csv/smart_proxies.rb +9 -13
  35. data/lib/hammer_cli_csv/splice.rb +1 -3
  36. data/lib/hammer_cli_csv/subnets.rb +24 -28
  37. data/lib/hammer_cli_csv/subscriptions.rb +39 -91
  38. data/lib/hammer_cli_csv/sync_plans.rb +20 -24
  39. data/lib/hammer_cli_csv/users.rb +25 -29
  40. data/lib/hammer_cli_csv/utils/subscriptions.rb +130 -0
  41. data/lib/hammer_cli_csv/version.rb +1 -1
  42. data/lib/hammer_cli_csv.rb +2 -2
  43. data/test/csv_test.rb +32 -0
  44. data/test/csv_test_helper.rb +17 -2
  45. data/test/data/content-hosts.csv +3 -2
  46. data/test/data/hosts.csv +0 -11
  47. data/test/data/settings.csv +1 -0
  48. data/test/data/setup/content-hosts.csv +1 -0
  49. data/test/data/setup/content-views.csv +2 -0
  50. data/test/data/setup/lifecycle-environments.csv +5 -0
  51. data/test/data/setup/locations.csv +6 -0
  52. data/test/data/setup/organizations.csv +2 -0
  53. data/test/data/setup/subscriptions.csv +5 -0
  54. data/test/data/subscriptions.csv +15 -17
  55. data/test/export_test.rb +27 -0
  56. data/test/fixtures/vcr_cassettes/apipie.yml +18528 -0
  57. data/test/fixtures/vcr_cassettes/resources/activation_keys_import/create_and_update.yml +38033 -0
  58. data/test/fixtures/vcr_cassettes/resources/content_hosts_export/export.yml +18846 -0
  59. data/test/fixtures/vcr_cassettes/resources/content_hosts_export/export_subscriptions.yml +323 -0
  60. data/test/fixtures/vcr_cassettes/resources/content_hosts_import/create_and_update.yml +41884 -0
  61. data/test/fixtures/vcr_cassettes/resources/content_hosts_import/import_single_line.yml +38248 -0
  62. data/test/fixtures/vcr_cassettes/resources/settings_import/update_settings.yml +18832 -0
  63. data/test/fixtures/vcr_cassettes/resources/settings_import/update_settings_continue.yml +316 -0
  64. data/test/fixtures/vcr_cassettes/resources/subscriptions_import/manifest_does_not_exist.yml +18785 -0
  65. data/test/fixtures/vcr_cassettes/setup/setup_content_views/setup.yml +19090 -0
  66. data/test/fixtures/vcr_cassettes/setup/setup_lifecycle_environments/setup.yml +924 -0
  67. data/test/fixtures/vcr_cassettes/setup/setup_locations/setup.yml +21102 -0
  68. data/test/fixtures/vcr_cassettes/setup/setup_organizations/setup.yml +19278 -0
  69. data/test/fixtures/vcr_cassettes/setup/setup_subscriptions/setup.yml +419 -0
  70. data/test/import_test.rb +20 -25
  71. data/test/resources/activation_keys_test.rb +72 -0
  72. data/test/resources/content_hosts_test.rb +132 -0
  73. data/test/resources/settings_test.rb +81 -0
  74. data/test/resources/subscriptions_test.rb +56 -0
  75. data/test/setup/setup_content_views.rb +17 -0
  76. data/test/setup/setup_lifecycle_environments.rb +17 -0
  77. data/test/setup/setup_locations.rb +17 -0
  78. data/test/setup/setup_organizations.rb +17 -0
  79. data/test/setup/setup_subscriptions.rb +20 -0
  80. data/test/setup/setup_test.rb +10 -0
  81. data/test/test_runner.rb +175 -0
  82. data/test/vcr_setup.rb +54 -0
  83. metadata +77 -13
  84. data/lib/hammer_cli_csv/exception_handler.rb +0 -42
  85. data/lib/hammer_cli_csv/installation_medias.rb +0 -77
  86. data/test/content_hosts_test.rb +0 -61
  87. data/test/settings_test.rb +0 -30
checksums.yaml CHANGED
@@ -1,15 +1,7 @@
1
1
  ---
2
- !binary "U0hBMQ==":
3
- metadata.gz: !binary |-
4
- N2ExODdkOTg4YzFhYmNhZjIyNDdkNTZjMjFjOGVjYjliOWM0OTA0Mw==
5
- data.tar.gz: !binary |-
6
- Njg1YmE0ZTMzMzE0NjlkM2E2NWMxMDI2N2QwM2Q5NDdmODViYzU2YQ==
2
+ SHA1:
3
+ metadata.gz: e0f784cf2623ea6218aa82c967c03a4df23f5c79
4
+ data.tar.gz: 3ff43bcc04983f69ec6f72da581e8fbceb70feee
7
5
  SHA512:
8
- metadata.gz: !binary |-
9
- NzZlYzM4NWMxZGMzYzNlNzljYWZmNWQyZmE3NzQ2OWJjMWY0MjNjMGEzMzdi
10
- NTVlM2NhZmM1ZjE4M2YzZWMxYzQ5M2E1OTZjMWRlNDE2MGUyYmE5YWU0NjYy
11
- ODJmNDMyMWNiYzk4NTEzODk4MjkzMjZlNjE1MDNiOThhNDRkZGM=
12
- data.tar.gz: !binary |-
13
- ZDNhNzIwOWU1N2Y0NWVhYjI5Y2Y1MTgzMzY0NDM2MzZiNjVkNDY3MDk1YzQ1
14
- OWE4MDY2YjkzOGJjYTZlOWNlM2U3ZTE5MzdlMWU2ZTY4YTk2ZWEwNWNjY2Y2
15
- Mzc3MTMzZTEwNWU4NjcxMzBmOGJiMjA5M2VhYWYyNWRmY2RkNjA=
6
+ metadata.gz: c51c13c2d41f6c78f0ce02d68d921e10ae694617354fc3d80049404cdb9ef222fac36a00bd76ad7b06fc2649aa4b0065878bb0abfbf0522482d618539fe57e7a
7
+ data.tar.gz: 49761b76cf989b896339674f0046d676a06d74bf774c8a0d7c50192699d36ad565866137f6d3e603ddb42da5f0a8616ee65cae278c0b5c33ea1ad170e49c7e48
@@ -1,38 +1,23 @@
1
+ # User interface related settings
1
2
  :ui:
2
- :interactive: true
3
- :per_page: 20
4
- :history_file: './log/history'
3
+ :interactive: false
4
+ :history_file: 'log/history'
5
5
 
6
- :watch_plain: true # enable/disable color output of logger in Clamp commands
6
+ :watch_plain: true
7
7
 
8
- :log_dir: './log'
8
+ :reload_cache: false
9
+
10
+ :log_dir: 'log'
9
11
  :log_level: 'error'
10
- :log_api_calls: false
11
- :log_size: 5 # MB
12
12
 
13
- :request_timeout: 120
13
+ # Mark translated strings with X characters (for developers)
14
+ #:mark_translated: false
14
15
 
15
16
  :foreman:
16
17
  :enable_module: true
17
- :host: 'http://katello:3000'
18
- :username: 'admin'
19
- :password: 'changeme'
20
18
 
21
19
  :katello:
22
20
  :enable_module: true
23
21
 
24
22
  :csv:
25
23
  :enable_module: true
26
- :host: 'http://katello:3000'
27
- :username: 'admin'
28
- :password: 'changeme'
29
- :products_sync: false
30
-
31
- :gutterball:
32
- :enable_module: true
33
-
34
- :foreman_remote_execution:
35
- :enable_module: true
36
-
37
- :import:
38
- :enable_module: true
@@ -1,9 +1,17 @@
1
1
  module HammerCLICsv
2
2
  class CsvCommand
3
3
  class ActivationKeysCommand < BaseCommand
4
+ include ::HammerCLICsv::Utils::Subscriptions
5
+
4
6
  command_name 'activation-keys'
5
7
  desc _('import or export activation keys')
6
8
 
9
+ def self.supported?
10
+ true
11
+ end
12
+
13
+ option %w(--itemized-subscriptions), :flag, _('Export one subscription per row, only process update subscriptions on import')
14
+
7
15
  ORGANIZATION = 'Organization'
8
16
  DESCRIPTION = 'Description'
9
17
  LIMIT = 'Limit'
@@ -13,46 +21,71 @@ module HammerCLICsv
13
21
  SERVICELEVEL = "Service Level"
14
22
  RELEASEVER = "Release Version"
15
23
  AUTOATTACH = "Auto-Attach"
16
- SUBSCRIPTIONS = 'Subscriptions'
17
-
18
- def export
19
- CSV.open(option_file || '/dev/stdout', 'wb', {:force_quotes => false}) do |csv|
20
- csv << [NAME, ORGANIZATION, DESCRIPTION, LIMIT, ENVIRONMENT, CONTENTVIEW,
21
- HOSTCOLLECTIONS, AUTOATTACH, SERVICELEVEL, RELEASEVER, SUBSCRIPTIONS]
22
- @api.resource(:organizations).call(:index, {
23
- :per_page => 999999
24
- })['results'].each do |organization|
25
- next if option_organization && organization['name'] != option_organization
26
-
27
- @api.resource(:activation_keys).call(:index, {
28
- 'per_page' => 999999,
29
- 'organization_id' => organization['id']
30
- })['results'].each do |activationkey|
31
- name = namify(activationkey['name'])
32
- count = 1
33
- description = activationkey['description']
34
- limit = activationkey['unlimited_content_hosts'] ? 'Unlimited' : activationkey['max_content_hosts']
35
- environment = activationkey['environment']['label']
36
- contentview = activationkey['content_view']['name']
37
- hostcollections = export_column(activationkey, 'host_collections', 'name')
38
- autoattach = activationkey['auto_attach'] ? 'Yes' : 'No'
39
- servicelevel = activationkey['service_level']
40
- releasever = activationkey['release_version']
41
- subscriptions = CSV.generate do |column|
42
- column << @api.resource(:subscriptions).call(:index, {
43
- 'organization_id' => organization['id'],
44
- 'activation_key_id' => activationkey['id']
45
- })['results'].collect do |subscription|
46
- amount = subscription['amount'] == 0 ? 'Automatic' : subscription['amount']
47
- sku = subscription['product_id'].match(/\A[0-9]/) ? 'Custom' : subscription['product_id']
48
- "#{amount}|#{sku}|#{subscription['product_name']}"
49
- end
50
- end
51
- subscriptions.delete!("\n")
52
- csv << [name, count, organization['name'], description, limit, environment, contentview,
53
- hostcollections, servicelevel, releasever, autoattach, subscriptions]
24
+
25
+ def export(csv)
26
+ if option_itemized_subscriptions?
27
+ export_itemized_subscriptions csv
28
+ else
29
+ export_all csv
30
+ end
31
+ end
32
+
33
+ def export_itemized_subscriptions(csv)
34
+ csv << shared_headers + [Utils::Subscriptions::SUBS_NAME, Utils::Subscriptions::SUBS_TYPE,
35
+ Utils::Subscriptions::SUBS_QUANTITY, Utils::Subscriptions::SUBS_SKU,
36
+ Utils::Subscriptions::SUBS_CONTRACT, Utils::Subscriptions::SUBS_ACCOUNT,
37
+ Utils::Subscriptions::SUBS_START, Utils::Subscriptions::SUBS_END]
38
+ iterate_activationkeys(csv) do |activationkey|
39
+ columns = shared_columns(activationkey)
40
+ @api.resource(:subscriptions).call(:index, {
41
+ 'organization_id' => activationkey['organization']['id'],
42
+ 'activation_key_id' => activationkey['id']
43
+ })['results'].collect do |subscription|
44
+ subscription_type = subscription['product_id'].to_i == 0 ? 'Red Hat' : 'Custom'
45
+ subscription_type += ' Guest' if subscription['type'] == 'STACK_DERIVED'
46
+ subscription_type += ' Temporary' if subscription['type'] == 'UNMAPPED_GUEST'
47
+ amount = (subscription['quantity_attached'].nil? || subscription['quantity_attached'] < 1) ? 'Automatic' : subscription['quantity_attached']
48
+ csv << columns +
49
+ [subscription['product_name'], subscription_type, amount,
50
+ subscription['product_id'], subscription['contract_number'], subscription['account_number'],
51
+ DateTime.parse(subscription['start_date']),
52
+ DateTime.parse(subscription['end_date'])]
53
+ end
54
+ end
55
+ end
56
+
57
+ def export_all(csv)
58
+ csv << shared_headers + [SUBSCRIPTIONS]
59
+ iterate_activationkeys(csv) do |activationkey|
60
+ subscriptions = CSV.generate do |column|
61
+ column << @api.resource(:subscriptions).call(:index, {
62
+ 'organization_id' => activationkey['organization']['id'],
63
+ 'activation_key_id' => activationkey['id']
64
+ })['results'].collect do |subscription|
65
+ amount = (subscription['quantity_attached'].nil? || subscription['quantity_attached'] < 1) ? 'Automatic' : subscription['quantity_attached']
66
+ "#{amount}"\
67
+ "|#{subscription['product_id']}"\
68
+ "|#{subscription['product_name']}"\
69
+ "|#{subscription['contract_number']}|#{subscription['account_number']}"
54
70
  end
55
71
  end
72
+ subscriptions.delete!("\n")
73
+ csv << shared_columns(activationkey) + [subscriptions]
74
+ end
75
+ end
76
+
77
+ def iterate_activationkeys(csv)
78
+ @api.resource(:organizations).call(:index, {
79
+ :per_page => 999999
80
+ })['results'].each do |organization|
81
+ next if option_organization && organization['name'] != option_organization
82
+
83
+ @api.resource(:activation_keys).call(:index, {
84
+ 'per_page' => 999999,
85
+ 'organization_id' => organization['id']
86
+ })['results'].each do |activationkey|
87
+ yield activationkey
88
+ end
56
89
  end
57
90
  end
58
91
 
@@ -60,55 +93,64 @@ module HammerCLICsv
60
93
  @existing = {}
61
94
 
62
95
  thread_import do |line|
63
- create_activationkeys_from_csv(line)
96
+ create_from_csv(line)
64
97
  end
65
98
  end
66
99
 
67
- def create_activationkeys_from_csv(line)
100
+ def create_from_csv(line)
68
101
  return if option_organization && line[ORGANIZATION] != option_organization
69
102
 
70
- if !@existing[line[ORGANIZATION]]
71
- @existing[line[ORGANIZATION]] = {}
72
- @api.resource(:activation_keys).call(:index, {
73
- 'per_page' => 999999,
74
- 'organization_id' => foreman_organization(:name => line[ORGANIZATION])
75
- })['results'].each do |activationkey|
76
- @existing[line[ORGANIZATION]][activationkey['name']] = activationkey['id'] if activationkey
77
- end
78
- end
103
+ update_existing(line)
79
104
 
80
105
  count(line[COUNT]).times do |number|
81
106
  name = namify(line[NAME], number)
82
107
 
83
- params = {
84
- 'organization_id' => foreman_organization(:name => line[ORGANIZATION]),
85
- 'name' => name,
86
- 'environment_id' => lifecycle_environment(line[ORGANIZATION],
87
- :name => line[ENVIRONMENT]),
88
- 'content_view_id' => katello_contentview(line[ORGANIZATION],
89
- :name => line[CONTENTVIEW]),
90
- 'description' => line[DESCRIPTION],
91
- 'unlimited_content_hosts' => (line[LIMIT] == 'Unlimited') ? true : false,
92
- 'max_content_hosts' => (line[LIMIT] == 'Unlimited') ? nil : line[LIMIT].to_i
93
- }
94
- params['auto_attach'] = (line[AUTOATTACH] == 'Yes' ? true : false) if params['auto_attach']
95
- params['service_level'] = line[SERVICELEVEL].nil? || line[SERVICELEVEL].empty? ? nil : line[SERVICELEVEL]
96
- params['release_version'] = line[RELEASEVER].nil? || line[RELEASEVER].empty? ? nil : line[RELEASEVER]
97
- if !@existing[line[ORGANIZATION]].include? name
98
- print _("Creating activation key '%{name}'...") % {:name => name} if option_verbose?
99
- activationkey = @api.resource(:activation_keys).call(:create, params)
100
- @existing[line[ORGANIZATION]][activationkey['name']] = activationkey['id']
108
+ if option_itemized_subscriptions?
109
+ update_itemized_subscriptions(name, line)
101
110
  else
102
- print _("Updating activation key '%{name}'...") % {:name => name} if option_verbose?
103
- params['id'] = @existing[line[ORGANIZATION]][name]
104
- activationkey = @api.resource(:activation_keys).call(:update, params)
111
+ update_or_create(name, line)
105
112
  end
113
+ end
114
+ end
106
115
 
107
- update_subscriptions(activationkey, line)
108
- update_groups(activationkey, line)
116
+ def update_itemized_subscriptions(name, line)
117
+ raise _("Activation key '%{name}' must already exist with --itemized_subscriptions") % {:name => name} unless @existing[line[ORGANIZATION]].include? name
109
118
 
110
- puts _('done') if option_verbose?
119
+ print(_("Updating subscriptions for activation key '%{name}'...") % {:name => name}) if option_verbose?
120
+ activationkey = @api.resource(:activation_keys).call(:show, {:id => @existing[line[ORGANIZATION]][name]})
121
+ update_subscriptions(activationkey, line, false)
122
+ puts _('done') if option_verbose?
123
+ end
124
+
125
+ def update_or_create(name, line)
126
+ params = {
127
+ 'organization_id' => foreman_organization(:name => line[ORGANIZATION]),
128
+ 'name' => name,
129
+ 'environment_id' => lifecycle_environment(line[ORGANIZATION],
130
+ :name => line[ENVIRONMENT]),
131
+ 'content_view_id' => katello_contentview(line[ORGANIZATION],
132
+ :name => line[CONTENTVIEW]),
133
+ 'description' => line[DESCRIPTION],
134
+ 'unlimited_content_hosts' => (line[LIMIT] == 'Unlimited') ? true : false,
135
+ 'max_content_hosts' => (line[LIMIT] == 'Unlimited') ? nil : line[LIMIT].to_i
136
+ }
137
+ params['auto_attach'] = (line[AUTOATTACH] == 'Yes' ? true : false) if params['auto_attach']
138
+ params['service_level'] = line[SERVICELEVEL].nil? || line[SERVICELEVEL].empty? ? nil : line[SERVICELEVEL]
139
+ params['release_version'] = line[RELEASEVER].nil? || line[RELEASEVER].empty? ? nil : line[RELEASEVER]
140
+ if !@existing[line[ORGANIZATION]].include? name
141
+ print _("Creating activation key '%{name}'...") % {:name => name} if option_verbose?
142
+ activationkey = @api.resource(:activation_keys).call(:create, params)
143
+ @existing[line[ORGANIZATION]][activationkey['name']] = activationkey['id']
144
+ else
145
+ print _("Updating activation key '%{name}'...") % {:name => name} if option_verbose?
146
+ params['id'] = @existing[line[ORGANIZATION]][name]
147
+ activationkey = @api.resource(:activation_keys).call(:update, params)
111
148
  end
149
+
150
+ update_subscriptions(activationkey, line, true)
151
+ update_groups(activationkey, line)
152
+
153
+ puts _('done') if option_verbose?
112
154
  end
113
155
 
114
156
  def update_groups(activationkey, line)
@@ -123,38 +165,121 @@ module HammerCLICsv
123
165
  end
124
166
  end
125
167
 
126
- def update_subscriptions(activationkey, line)
127
- if line[SUBSCRIPTIONS] && line[SUBSCRIPTIONS] != ''
128
- subscriptions = CSV.parse_line(line[SUBSCRIPTIONS], {:skip_blanks => true}).collect do |subscription_details|
129
- (amount, sku, name) = subscription_details.split('|')
130
- {
131
- :id => katello_subscription(line[ORGANIZATION], :name => name),
132
- :quantity => (amount.nil? || amount == 'Automatic') ? 0 : amount
133
- }
168
+ def update_subscriptions(activationkey, line, remove_existing)
169
+ existing_subscriptions = @api.resource(:subscriptions).call(:index, {
170
+ 'organization_id' => foreman_organization(:name => line[ORGANIZATION]),
171
+ 'per_page' => 999999,
172
+ 'activation_key_id' => activationkey['id']
173
+ })['results']
174
+ if remove_existing && existing_subscriptions.length > 0
175
+ existing_subscriptions.map! do |existing_subscription|
176
+ {:id => existing_subscription['id'], :quantity => existing_subscription['quantity_consumed']}
134
177
  end
178
+ @api.resource(:activation_keys).call(:remove_subscriptions, {
179
+ 'id' => activationkey['id'],
180
+ 'subscriptions' => existing_subscriptions
181
+ })
182
+ existing_subscriptions = []
183
+ end
135
184
 
136
- existing_subscriptions = @api.resource(:subscriptions).call(:index, {
137
- 'organization_id' => foreman_organization(:name => line[ORGANIZATION]),
138
- 'per_page' => 999999,
139
- 'activation_key_id' => activationkey['id']
140
- })['results']
141
- if existing_subscriptions.length > 0
142
- @api.resource(:activation_keys).call(:remove_subscriptions, {
143
- 'id' => activationkey['id'],
144
- 'subscriptions' => existing_subscriptions
145
- })
185
+ if line[Utils::Subscriptions::SUBS_NAME].nil? && line[Utils::Subscriptions::SUBS_SKU].nil?
186
+ all_in_one_subscription(activationkey, existing_subscriptions, line)
187
+ else
188
+ single_subscription(activationkey, existing_subscriptions, line)
189
+ end
190
+ end
191
+
192
+ def single_subscription(activationkey, existing_subscriptions, line)
193
+ already_attached = false
194
+ if line[Utils::Subscriptions::SUBS_SKU]
195
+ already_attached = existing_subscriptions.detect do |subscription|
196
+ line[Utils::Subscriptions::SUBS_SKU] == subscription['product_id']
197
+ end
198
+ elsif line[Utils::Subscriptions::SUBS_NAME]
199
+ already_attached = existing_subscriptions.detect do |subscription|
200
+ line[Utils::Subscriptions::SUBS_NAME] == subscription['name']
146
201
  end
202
+ end
203
+ if already_attached
204
+ print _(" '%{name}' already attached...") % {:name => already_attached['name']}
205
+ return
206
+ end
147
207
 
148
- @api.resource(:activation_keys).call(:add_subscriptions, {
149
- 'id' => activationkey['id'],
150
- 'subscriptions' => subscriptions
151
- })
208
+ available_subscriptions = @api.resource(:subscriptions).call(:index, {
209
+ 'organization_id' => activationkey['organization']['id'],
210
+ 'activation_key_id' => activationkey['id'],
211
+ 'available_for' => 'activation_key'
212
+ })['results']
213
+
214
+ matches = matches_by_sku_and_name([], line, available_subscriptions)
215
+ matches = matches_by_type(matches, line)
216
+ matches = matches_by_account(matches, line)
217
+ matches = matches_by_contract(matches, line)
218
+ matches = matches_by_quantity(matches, line)
219
+
220
+ raise _("No matching subscriptions") if matches.empty?
221
+
222
+ match = matches[0]
223
+ print _(" attaching '%{name}'...") % {:name => match['name']} if option_verbose?
224
+
225
+ @api.resource(:activation_keys).call(:add_subscriptions, {
226
+ 'id' => activationkey['id'],
227
+ 'subscriptions' => [match]
228
+ })
229
+ end
230
+
231
+ def all_in_one_subscription(activationkey, existing_subscriptions, line)
232
+ return if line[SUBSCRIPTIONS].nil? || line[SUBSCRIPTIONS].empty?
233
+
234
+ subscriptions = CSV.parse_line(line[SUBSCRIPTIONS], {:skip_blanks => true}).collect do |details|
235
+ (amount, sku, name, contract, account) = split_subscription_details(details)
236
+ {
237
+ :id => get_subscription(line[ORGANIZATION], :name => name),
238
+ :quantity => (amount.nil? || amount == 'Automatic') ? 0 : amount.to_i
239
+ }
152
240
  end
241
+
242
+ @api.resource(:activation_keys).call(:add_subscriptions, {
243
+ 'id' => activationkey['id'],
244
+ 'subscriptions' => subscriptions
245
+ })
153
246
  end
154
247
 
155
248
  def usage_limit(limit)
156
249
  Integer(limit) rescue -1
157
250
  end
251
+
252
+ def shared_headers
253
+ [NAME, ORGANIZATION, DESCRIPTION, LIMIT, ENVIRONMENT, CONTENTVIEW,
254
+ HOSTCOLLECTIONS, AUTOATTACH, SERVICELEVEL, RELEASEVER]
255
+ end
256
+
257
+ def shared_columns(activationkey)
258
+ name = namify(activationkey['name'])
259
+ organization = activationkey['organization']['name']
260
+ description = activationkey['description']
261
+ limit = activationkey['unlimited_content_hosts'] ? 'Unlimited' : activationkey['max_content_hosts']
262
+ environment = activationkey['environment'].nil? ? nil : activationkey['environment']['label']
263
+ contentview = activationkey['content_view'].nil? ? nil : activationkey['content_view']['name']
264
+ hostcollections = export_column(activationkey, 'host_collections', 'name')
265
+ autoattach = activationkey['auto_attach'] ? 'Yes' : 'No'
266
+ servicelevel = activationkey['service_level']
267
+ releasever = activationkey['release_version']
268
+ [name, organization, description, limit, environment, contentview, hostcollections,
269
+ autoattach, servicelevel, releasever]
270
+ end
271
+
272
+ def update_existing(line)
273
+ if !@existing[line[ORGANIZATION]]
274
+ @existing[line[ORGANIZATION]] = {}
275
+ @api.resource(:activation_keys).call(:index, {
276
+ 'per_page' => 999999,
277
+ 'organization_id' => foreman_organization(:name => line[ORGANIZATION])
278
+ })['results'].each do |activationkey|
279
+ @existing[line[ORGANIZATION]][activationkey['name']] = activationkey['id'] if activationkey
280
+ end
281
+ end
282
+ end
158
283
  end
159
284
  end
160
285
  end
@@ -6,15 +6,13 @@ module HammerCLICsv
6
6
 
7
7
  OPERATINGSYSTEMS = 'Operating Systems'
8
8
 
9
- def export
10
- CSV.open(option_file || '/dev/stdout', 'wb', {:force_quotes => true}) do |csv|
11
- csv << [NAME, OPERATINGSYSTEMS]
12
- @api.resource(:architectures).call(:index, {:per_page => 999999})['results'].each do |architecture|
13
- architecture = @api.resource(:architectures).call(:show, {:id => architecture['id']})
14
- name = architecture['name']
15
- operatingsystems = export_column(architecture, 'operatingsystems', 'title')
16
- csv << [name, operatingsystems]
17
- end
9
+ def export(csv)
10
+ csv << [NAME, OPERATINGSYSTEMS]
11
+ @api.resource(:architectures).call(:index, {:per_page => 999999})['results'].each do |architecture|
12
+ architecture = @api.resource(:architectures).call(:show, {:id => architecture['id']})
13
+ name = architecture['name']
14
+ operatingsystems = export_column(architecture, 'operatingsystems', 'title')
15
+ csv << [name, operatingsystems]
18
16
  end
19
17
  end
20
18
 
@@ -56,8 +54,6 @@ module HammerCLICsv
56
54
  end
57
55
  print "done\n" if option_verbose?
58
56
  end
59
- rescue RuntimeError => e
60
- raise "#{e}\n #{line}"
61
57
  end
62
58
  end
63
59
  end
@@ -12,9 +12,11 @@ module HammerCLICsv
12
12
  option %w(--threads), 'THREAD_COUNT', 'Number of threads to hammer with',
13
13
  :default => 1, :hidden => true
14
14
  option %w(--export), :flag, 'Export current data instead of importing'
15
- option %w(--file), 'FILE_NAME', 'CSV file (default to /dev/stdout with --csv-export, otherwise required)'
16
- option %w(--prefix), 'PREFIX', 'Prefix for all name columns'
15
+ option %w(--file), 'FILE_NAME', 'CSV file (default to /dev/stdout with --export, otherwise required)'
16
+ option %w(--prefix), 'PREFIX', 'Prefix for all name columns',
17
+ :hidden => true
17
18
  option %w(--organization), 'ORGANIZATION', _('Only process organization matching this name')
19
+ option %w(--continue-on-error), :flag, _('Continue processing even if individual resource error')
18
20
 
19
21
  option %w(--csv-file), 'FILE_NAME', 'Option --csv-file is deprecated. Use --file',
20
22
  :deprecated => "Use --file", :hidden => true,
@@ -23,10 +25,22 @@ module HammerCLICsv
23
25
  :deprecated => "Use --export", :hidden => true,
24
26
  :attribute_name => :option_export
25
27
 
26
-
27
28
  NAME = 'Name'
28
29
  COUNT = 'Count'
29
30
 
31
+ def self.supported?
32
+ false
33
+ end
34
+
35
+ def supported?
36
+ self.class.supported?
37
+ end
38
+
39
+ def help
40
+ print_message _('**** This command is unsupported and is provided as tech preview. ****') unless supported?
41
+ super
42
+ end
43
+
30
44
  def execute
31
45
  @server = (HammerCLI::Settings.settings[:_params] &&
32
46
  HammerCLI::Settings.settings[:_params][:host]) ||
@@ -61,7 +75,19 @@ module HammerCLICsv
61
75
  })
62
76
  end
63
77
 
64
- option_export? ? export : import
78
+ if option_export?
79
+ if option_file
80
+ CSV.open(option_file, 'wb', {:force_quotes => false}) do |csv|
81
+ export csv
82
+ end
83
+ else
84
+ CSV do |csv|
85
+ export csv
86
+ end
87
+ end
88
+ else
89
+ import
90
+ end
65
91
  HammerCLI::EX_OK
66
92
  end
67
93
 
@@ -129,8 +155,12 @@ module HammerCLICsv
129
155
  lines = csv[start_index...finish_index].clone
130
156
  splits << Thread.new do
131
157
  lines.each do |line|
132
- if line[name_column || NAME][0] != '#'
158
+ next if line[name_column || NAME][0] == '#'
159
+ begin
133
160
  yield line
161
+ rescue RuntimeError => e
162
+ message = "#{e}\n#{line}"
163
+ option_continue_on_error? ? $stderr.puts("Error: #{message}") : raise(message)
134
164
  end
135
165
  end
136
166
  end
@@ -484,6 +514,38 @@ module HammerCLICsv
484
514
  result
485
515
  end
486
516
 
517
+ def foreman_medium(options = {})
518
+ @media ||= {}
519
+
520
+ if options[:name]
521
+ return nil if options[:name].nil? || options[:name].empty?
522
+ options[:id] = @media[options[:name]]
523
+ if !options[:id]
524
+ ptable = @api.resource(:media).call(:index, {
525
+ :per_page => 999999,
526
+ 'search' => "name=\"#{options[:name]}\""
527
+ })['results']
528
+ raise "Partition table '#{options[:name]}' not found" if !ptable || ptable.empty?
529
+ options[:id] = ptable[0]['id']
530
+ @media[options[:name]] = options[:id]
531
+ end
532
+ result = options[:id]
533
+ elsif options[:id]
534
+ return nil if options[:id].nil?
535
+ options[:name] = @media.key(options[:id])
536
+ if !options[:name]
537
+ ptable = @api.resource(:media).call(:show, {'id' => options[:id]})
538
+ options[:name] = ptable['name']
539
+ @media[options[:name]] = options[:id]
540
+ end
541
+ result = options[:name]
542
+ elsif !options[:name] && !options[:id]
543
+ result = ''
544
+ end
545
+
546
+ result
547
+ end
548
+
487
549
  def foreman_host(options = {})
488
550
  @query_hosts ||= {}
489
551
 
@@ -737,42 +799,6 @@ module HammerCLICsv
737
799
  result
738
800
  end
739
801
 
740
- def katello_subscription(organization, options = {})
741
- @subscriptions ||= {}
742
- @subscriptions[organization] ||= {}
743
-
744
- if options[:name]
745
- return nil if options[:name].nil? || options[:name].empty?
746
- options[:id] = @subscriptions[organization][options[:name]]
747
- if !options[:id]
748
- results = @api.resource(:subscriptions).call(:index, {
749
- :per_page => 999999,
750
- 'organization_id' => foreman_organization(:name => organization),
751
- 'search' => "name = \"#{options[:name]}\""
752
- })
753
- raise "No subscriptions match '#{options[:name]}'" if results['subtotal'] == 0
754
- raise "Too many subscriptions match '#{options[:name]}'" if results['subtotal'] > 1
755
- subscription = results['results'][0]
756
- @subscriptions[organization][options[:name]] = subscription['id']
757
- options[:id] = @subscriptions[organization][options[:name]]
758
- raise "Subscription '#{options[:name]}' not found" if !options[:id]
759
- end
760
- result = options[:id]
761
- else
762
- return nil if options[:id].nil?
763
- options[:name] = @subscriptions.key(options[:id])
764
- if !options[:name]
765
- subscription = @api.resource(:subscriptions).call(:show, {'id' => options[:id]})
766
- raise "Subscription '#{options[:name]}' not found" if !subscription || subscription.empty?
767
- options[:name] = subscription['name']
768
- @subscriptions[options[:name]] = options[:id]
769
- end
770
- result = options[:name]
771
- end
772
-
773
- result
774
- end
775
-
776
802
  def katello_hostcollection(organization, options = {})
777
803
  @hostcollections ||= {}
778
804
  @hostcollections[organization] ||= {}