Project

General

Profile

Download (21.7 KB) Statistics
| Branch: | Tag: | Revision:

hammer-cli-csv / lib / hammer_cli_csv / base.rb @ f8ecc788

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
    NAME = 'Name'
21
    COUNT = 'Count'
22

    
23
    def request_help(help_command = 'hammer csv', help_options = '')
24
      puts "TODO: write some help!"
25
      exit(HammerCLI::EX_OK)
26
    end
27

    
28
    option %w(-v --verbose), :flag, 'be verbose'
29
    option %w(--threads), 'THREAD_COUNT', 'Number of threads to hammer with', :default => 1
30
    option %w(--csv-export), :flag, 'Export current data instead of importing'
31
    option %w(--csv-file), 'FILE_NAME', 'CSV file (default to /dev/stdout with --csv-export, otherwise required)'
32
    option %w(--prefix), 'PREFIX', 'Prefix for all name columns'
33
    option %w(--server), 'SERVER', 'Server URL'
34
    option %w(-u --username), 'USERNAME', 'Username to access server'
35
    option %w(-p --password), 'PASSWORD', 'Password to access server'
36

    
37
    def execute
38
      if !option_csv_file
39
        if option_csv_export?
40
          # rubocop:disable UselessAssignment
41
          option_csv_file = '/dev/stdout'
42
        else
43
          # rubocop:disable UselessAssignment
44
          option_csv_file = '/dev/stdin'
45
        end
46
      end
47

    
48
      @api = ApipieBindings::API.new({
49
                                       :uri => option_server || HammerCLI::Settings.get(:csv, :host),
50
                                       :username => option_username || HammerCLI::Settings.get(:csv, :username),
51
                                       :password => option_password || HammerCLI::Settings.get(:csv, :password),
52
                                       :api_version => 2
53
                                     })
54

    
55
      option_csv_export? ? export : import
56
      HammerCLI::EX_OK
57
    end
58

    
59
    def namify(name_format, number = 0)
60
      if name_format.index('%')
61
        name = name_format % number
62
      else
63
        name = name_format
64
      end
65
      name = "#{option_prefix}#{name}" if option_prefix
66
      name
67
    end
68

    
69
    def labelize(name)
70
      name.gsub(/[^a-z0-9\-_]/i, '_')
71
    end
72

    
73
    def thread_import(return_headers = false)
74
      csv = []
75
      CSV.foreach(option_csv_file || '/dev/stdin', {
76
                                                     :skip_blanks => true,
77
                                                     :headers => :first_row,
78
                                                     :return_headers => return_headers
79
                                                   }) do |line|
80
        csv << line
81
      end
82
      lines_per_thread = csv.length / option_threads.to_i + 1
83
      splits = []
84

    
85
      option_threads.to_i.times do |current_thread|
86
        start_index = ((current_thread) * lines_per_thread).to_i
87
        finish_index = ((current_thread + 1) * lines_per_thread).to_i
88
        lines = csv[start_index...finish_index].clone
89
        splits << Thread.new do
90
          lines.each do |line|
91
            if line[NAME][0] != '#'
92
              yield line
93
            end
94
          end
95
        end
96
      end
97

    
98
      splits.each do |thread|
99
        thread.join
100
      end
101
    end
102

    
103
    def foreman_organization(options = {})
104
      @organizations ||= {}
105

    
106
      if options[:name]
107
        return nil if options[:name].nil? || options[:name].empty?
108
        options[:id] = @organizations[options[:name]]
109
        if !options[:id]
110
          organization = @api.resource(:organizations).call(:index, {'search' => "name=\"#{options[:name]}\""})['results']
111
          raise "Organization '#{options[:name]}' not found" if !organization || organization.empty?
112
          options[:id] = organization[0]['id']
113
          @organizations[options[:name]] = options[:id]
114
        end
115
        result = options[:id]
116
      else
117
        return nil if options[:id].nil?
118
        options[:name] = @organizations.key(options[:id])
119
        if !options[:name]
120
          organization = @api.resource(:organizations).call(:show, {'id' => options[:id]})
121
          raise "Organization 'id=#{options[:id]}' not found" if !organization || organization.empty?
122
          options[:name] = organization['name']
123
          @organizations[options[:name]] = options[:id]
124
        end
125
        result = options[:name]
126
      end
127

    
128
      result
129
    end
130

    
131
    def katello_organization(options = {})
132
      @organizations ||= {}
133

    
134
      if options[:name]
135
        return nil if options[:name].nil? || options[:name].empty?
136
        options[:id] = @organizations[options[:name]]
137
        if !options[:id]
138
          organization = @api.resource(:organizations).call(:index, {'search' => "name=\"#{options[:name]}\""})['results']
139
          raise "Organization '#{options[:name]}' not found" if !organization || organization.empty?
140
          options[:id] = organization[0]['label']
141
          @organizations[options[:name]] = options[:id]
142
        end
143
        result = options[:id]
144
      else
145
        return nil if options[:id].nil?
146
        options[:name] = @organizations.key(options[:id])
147
        if !options[:name]
148
          organization = @api.resource(:organizations).call(:show, {'id' => options[:id]})
149
          raise "Organization 'id=#{options[:id]}' not found" if !organization || organization.empty?
150
          options[:name] = organization['name']
151
          @organizations[options[:name]] = options[:id]
152
        end
153
        result = options[:name]
154
      end
155

    
156
      result
157
    end
158

    
159
    def foreman_location(options = {})
160
      @locations ||= {}
161

    
162
      if options[:name]
163
        return nil if options[:name].nil? || options[:name].empty?
164
        options[:id] = @locations[options[:name]]
165
        if !options[:id]
166
          location = @api.resource(:locations).call(:index, {'search' => "name=\"#{options[:name]}\""})['results']
167
          raise "Location '#{options[:name]}' not found" if !location || location.empty?
168
          options[:id] = location[0]['id']
169
          @locations[options[:name]] = options[:id]
170
        end
171
        result = options[:id]
172
      else
173
        return nil if options[:id].nil?
174
        options[:name] = @locations.key(options[:id])
175
        if !options[:name]
176
          location = @api.resource(:locations).call(:show, {'id' => options[:id]})
177
          raise "Location 'id=#{options[:id]}' not found" if !location || location.empty?
178
          options[:name] = location['name']
179
          @locations[options[:name]] = options[:id]
180
        end
181
        result = options[:name]
182
      end
183

    
184
      result
185
    end
186

    
187
    def foreman_role(options = {})
188
      @roles ||= {}
189

    
190
      if options[:name]
191
        return nil if options[:name].nil? || options[:name].empty?
192
        options[:id] = @roles[options[:name]]
193
        if !options[:id]
194
          role = @api.resource(:roles).call(:index, {'search' => "name=\"#{options[:name]}\""})['results']
195
          raise "Role '#{options[:name]}' not found" if !role || role.empty?
196
          options[:id] = role[0]['id']
197
          @roles[options[:name]] = options[:id]
198
        end
199
        result = options[:id]
200
      else
201
        return nil if options[:id].nil?
202
        options[:name] = @roles.key(options[:id])
203
        if !options[:name]
204
          role = @api.resource(:roles).call(:show, {'id' => options[:id]})
205
          raise "Role 'id=#{options[:id]}' not found" if !role || role.empty?
206
          options[:name] = role['name']
207
          @roles[options[:name]] = options[:id]
208
        end
209
        result = options[:name]
210
      end
211

    
212
      result
213
    end
214

    
215
    def foreman_permission(options = {})
216
      @permissions ||= {}
217

    
218
      if options[:name]
219
        return nil if options[:name].nil? || options[:name].empty?
220
        options[:id] = @permissions[options[:name]]
221
        if !options[:id]
222
          permission = @api.resource(:permissions).call(:index, {'name' => options[:name]})['results']
223
          raise "Permission '#{options[:name]}' not found" if !permission || permission.empty?
224
          options[:id] = permission[0]['id']
225
          @permissions[options[:name]] = options[:id]
226
        end
227
        result = options[:id]
228
      else
229
        return nil if options[:id].nil?
230
        options[:name] = @permissions.key(options[:id])
231
        if !options[:name]
232
          permission = @api.resource(:permissions).call(:show, {'id' => options[:id]})
233
          raise "Permission 'id=#{options[:id]}' not found" if !permission || permission.empty?
234
          options[:name] = permission['name']
235
          @permissions[options[:name]] = options[:id]
236
        end
237
        result = options[:name]
238
      end
239

    
240
      result
241
    end
242

    
243
    def foreman_filter(role, options = {})
244
      @filters ||= {}
245

    
246
      if options[:name]
247
        return nil if options[:name].nil? || options[:name].empty?
248
        options[:id] = @filters[options[:name]]
249
        if !options[:id]
250
          filter = @api.resource(:filters).call(:index, {'search' => "role=\"#{role}\" and search=\"#{options[:name]}\""})['results']
251
          if !filter || filter.empty?
252
            options[:id] = nil
253
          else
254
            options[:id] = filter[0]['id']
255
            @filters[options[:name]] = options[:id]
256
          end
257
        end
258
        result = options[:id]
259
      else
260
        return nil if options[:id].nil?
261
        options[:name] = @filters.key(options[:id])
262
        if !options[:name]
263
          filter = @api.resource(:filters).call(:show, {'id' => options[:id]})
264
          raise "Filter 'id=#{options[:id]}' not found" if !filter || filter.empty?
265
          options[:name] = filter['name']
266
          @filters[options[:name]] = options[:id]
267
        end
268
        result = options[:name]
269
      end
270

    
271
      result
272
    end
273

    
274
    def foreman_environment(options = {})
275
      @environments ||= {}
276

    
277
      if options[:name]
278
        return nil if options[:name].nil? || options[:name].empty?
279
        options[:id] = @environments[options[:name]]
280
        if !options[:id]
281
          environment = @api.resource(:environments).call(:index, {'search' => "name=\"#{options[:name]}\""})['results']
282
          raise "Puppet environment '#{options[:name]}' not found" if !environment || environment.empty?
283
          options[:id] = environment[0]['id']
284
          @environments[options[:name]] = options[:id]
285
        end
286
        result = options[:id]
287
      else
288
        return nil if options[:id].nil?
289
        options[:name] = @environments.key(options[:id])
290
        if !options[:name]
291
          environment = @api.resource(:environments).call(:show, {'id' => options[:id]})
292
          raise "Puppet environment '#{options[:name]}' not found" if !environment || environment.empty?
293
          options[:name] = environment['name']
294
          @environments[options[:name]] = options[:id]
295
        end
296
        result = options[:name]
297
      end
298

    
299
      result
300
    end
301

    
302
    def foreman_operatingsystem(options = {})
303
      @operatingsystems ||= {}
304

    
305
      if options[:name]
306
        return nil if options[:name].nil? || options[:name].empty?
307
        options[:id] = @operatingsystems[options[:name]]
308
        if !options[:id]
309
          (osname, major, minor) = split_os_name(options[:name])
310
          search = "name=\"#{osname}\" and major=\"#{major}\" and minor=\"#{minor}\""
311
          operatingsystems = @api.resource(:operatingsystems).call(:index, {'search' => search})['results']
312
          operatingsystem = operatingsystems[0]
313
          raise "Operating system '#{options[:name]}' not found" if !operatingsystem || operatingsystem.empty?
314
          options[:id] = operatingsystem['id']
315
          @operatingsystems[options[:name]] = options[:id]
316
        end
317
        result = options[:id]
318
      else
319
        return nil if options[:id].nil?
320
        options[:name] = @operatingsystems.key(options[:id])
321
        if !options[:name]
322
          operatingsystem = @api.resource(:operatingsystems).call(:show, {'id' => options[:id]})
323
          raise "Operating system 'id=#{options[:id]}' not found" if !operatingsystem || operatingsystem.empty?
324
          options[:name] = build_os_name(operatingsystem['name'],
325
                                         operatingsystem['major'],
326
                                         operatingsystem['minor'])
327
          @operatingsystems[options[:name]] = options[:id]
328
        end
329
        result = options[:name]
330
      end
331

    
332
      result
333
    end
334

    
335
    def foreman_architecture(options = {})
336
      @architectures ||= {}
337

    
338
      if options[:name]
339
        return nil if options[:name].nil? || options[:name].empty?
340
        options[:id] = @architectures[options[:name]]
341
        if !options[:id]
342
          architecture = @api.resource(:architectures).call(:index, {'search' => "name=\"#{options[:name]}\""})['results']
343
          raise "Architecture '#{options[:name]}' not found" if !architecture || architecture.empty?
344
          options[:id] = architecture[0]['id']
345
          @architectures[options[:name]] = options[:id]
346
        end
347
        result = options[:id]
348
      else
349
        return nil if options[:id].nil?
350
        options[:name] = @architectures.key(options[:id])
351
        if !options[:name]
352
          architecture = @api.resource(:architectures).call(:show, {'id' => options[:id]})
353
          raise "Architecture 'id=#{options[:id]}' not found" if !architecture || architecture.empty?
354
          options[:name] = architecture['name']
355
          @architectures[options[:name]] = options[:id]
356
        end
357
        result = options[:name]
358
      end
359

    
360
      result
361
    end
362

    
363
    def foreman_domain(options = {})
364
      @domains ||= {}
365

    
366
      if options[:name]
367
        return nil if options[:name].nil? || options[:name].empty?
368
        options[:id] = @domains[options[:name]]
369
        if !options[:id]
370
          domain = @api.resource(:domains).call(:index, {'search' => "name=\"#{options[:name]}\""})['results']
371
          raise "Domain '#{options[:name]}' not found" if !domain || domain.empty?
372
          options[:id] = domain[0]['id']
373
          @domains[options[:name]] = options[:id]
374
        end
375
        result = options[:id]
376
      else
377
        return nil if options[:id].nil?
378
        options[:name] = @domains.key(options[:id])
379
        if !options[:name]
380
          domain = @api.resource(:domains).call(:show, {'id' => options[:id]})
381
          raise "Domain 'id=#{options[:id]}' not found" if !domain || domain.empty?
382
          options[:name] = domain['name']
383
          @domains[options[:name]] = options[:id]
384
        end
385
        result = options[:name]
386
      end
387

    
388
      result
389
    end
390

    
391
    def foreman_partitiontable(options = {})
392
      @ptables ||= {}
393

    
394
      if options[:name]
395
        return nil if options[:name].nil? || options[:name].empty?
396
        options[:id] = @ptables[options[:name]]
397
        if !options[:id]
398
          ptable = @api.resource(:ptables).call(:index, {'search' => "name=\"#{options[:name]}\""})['results']
399
          raise "Partition table '#{options[:name]}' not found" if !ptable || ptable.empty?
400
          options[:id] = ptable[0]['id']
401
          @ptables[options[:name]] = options[:id]
402
        end
403
        result = options[:id]
404
      elsif options[:id]
405
        return nil if options[:id].nil?
406
        options[:name] = @ptables.key(options[:id])
407
        if !options[:name]
408
          ptable = @api.resource(:ptables).call(:show, {'id' => options[:id]})
409
          options[:name] = ptable['name']
410
          @ptables[options[:name]] = options[:id]
411
        end
412
        result = options[:name]
413
      elsif !options[:name] && !options[:id]
414
        result = ''
415
      end
416

    
417
      result
418
    end
419

    
420
    def katello_environment(organization, options = {})
421
      @environments ||= {}
422
      @environments[organization] ||= {}
423

    
424
      if options[:name]
425
        return nil if options[:name].nil? || options[:name].empty?
426
        options[:id] = @environments[organization][options[:name]]
427
        if !options[:id]
428
          @api.resource(:lifecycle_environments).call(:index, {
429
                                                        'organization_id' => katello_organization(:name => organization),
430
                                                        'library' => true
431
                                                      })['results'].each do |environment|
432
            @environments[organization][environment['name']] = environment['id']
433
          end
434
          options[:id] = @environments[organization][options[:name]]
435
          raise "Lifecycle environment '#{options[:name]}' not found" if !options[:id]
436
        end
437
        result = options[:id]
438
      else
439
        return nil if options[:id].nil?
440
        options[:name] = @environments.key(options[:id])
441
        if !options[:name]
442
          environment = @api.resource(:lifecycle_environments).call(:show, {'id' => options[:id]})
443
          raise "Lifecycle environment '#{options[:name]}' not found" if !environment || environment.empty?
444
          options[:name] = environment['name']
445
          @environments[options[:name]] = options[:id]
446
        end
447
        result = options[:name]
448
      end
449

    
450
      result
451
    end
452

    
453
    def katello_contentview(organization, options = {})
454
      @contentviews ||= {}
455
      @contentviews[organization] ||= {}
456

    
457
      if options[:name]
458
        return nil if options[:name].nil? || options[:name].empty?
459
        options[:id] = @contentviews[organization][options[:name]]
460
        if !options[:id]
461
          @api.resource(:content_views).call(:index, {
462
                                               'organization_id' => katello_organization(:name => organization)
463
                                             })['results'].each do |contentview|
464
            @contentviews[organization][contentview['name']] = contentview['id']
465
          end
466
          options[:id] = @contentviews[organization][options[:name]]
467
          raise "Content view '#{options[:name]}' not found" if !options[:id]
468
        end
469
        result = options[:id]
470
      else
471
        return nil if options[:id].nil?
472
        options[:name] = @contentviews.key(options[:id])
473
        if !options[:name]
474
          contentview = @api.resource(:content_views).call(:show, {'id' => options[:id]})
475
          raise "Puppet contentview '#{options[:name]}' not found" if !contentview || contentview.empty?
476
          options[:name] = contentview['name']
477
          @contentviews[options[:name]] = options[:id]
478
        end
479
        result = options[:name]
480
      end
481

    
482
      result
483
    end
484

    
485
    def katello_subscription(organization, options = {})
486
      @subscriptions ||= {}
487
      @subscriptions[organization] ||= {}
488

    
489
      if options[:name]
490
        return nil if options[:name].nil? || options[:name].empty?
491
        options[:id] = @subscriptions[organization][options[:name]]
492
        if !options[:id]
493
          results = @api.resource(:subscriptions).call(:index, {
494
                                                'organization_id' => katello_organization(:name => organization),
495
                                                'search' => "name:\"#{options[:name]}\""
496
                                              })
497
          raise "No subscriptions match '#{options[:name]}'" if results['subtotal'] == 0
498
          raise "Too many subscriptions match '#{options[:name]}'" if results['subtotal'] > 1
499
          subscription = results['results'][0]
500
          @subscriptions[organization][options[:name]] = subscription['id']
501
          options[:id] = @subscriptions[organization][options[:name]]
502
          raise "Subscription '#{options[:name]}' not found" if !options[:id]
503
        end
504
        result = options[:id]
505
      else
506
        return nil if options[:id].nil?
507
        options[:name] = @subscriptions.key(options[:id])
508
        if !options[:name]
509
          subscription = @api.resource(:subscriptions).call(:show, {'id' => options[:id]})
510
          raise "Subscription '#{options[:name]}' not found" if !subscription || subscription.empty?
511
          options[:name] = subscription['name']
512
          @subscriptions[options[:name]] = options[:id]
513
        end
514
        result = options[:name]
515
      end
516

    
517
      result
518
    end
519

    
520
    def katello_systemgroup(organization, options = {})
521
      @systemgroups ||= {}
522
      @systemgroups[organization] ||= {}
523

    
524
      if options[:name]
525
        return nil if options[:name].nil? || options[:name].empty?
526
        options[:id] = @systemgroups[organization][options[:name]]
527
        if !options[:id]
528
          @api.resource(:system_groups).call(:index, {
529
                                     'organization_id' => katello_organization(:name => organization),
530
                                     'search' => "name:\"#{options[:name]}\""
531
                                   })['results'].each do |systemgroup|
532
            @systemgroups[organization][systemgroup['name']] = systemgroup['id'] if systemgroup
533
          end
534
          options[:id] = @systemgroups[organization][options[:name]]
535
          raise "System group '#{options[:name]}' not found" if !options[:id]
536
        end
537
        result = options[:id]
538
      else
539
        return nil if options[:id].nil?
540
        options[:name] = @systemgroups.key(options[:id])
541
        if !options[:name]
542
          systemgroup = @api.resource(:system_groups).call(:show, {'id' => options[:id]})
543
          raise "System group '#{options[:name]}' not found" if !systemgroup || systemgroup.empty?
544
          options[:name] = systemgroup['name']
545
          @systemgroups[options[:name]] = options[:id]
546
        end
547
        result = options[:name]
548
      end
549

    
550
      result
551
    end
552

    
553
    def build_os_name(name, major, minor)
554
      name += " #{major}" if major && major != ''
555
      name += ".#{minor}" if minor && minor != ''
556
      name
557
    end
558

    
559
    # "Red Hat 6.4" => "Red Hat", "6", "4"
560
    # "Red Hat 6"   => "Red Hat", "6", ''
561
    def split_os_name(name)
562
      tokens = name.split(' ')
563
      is_number = Float(tokens[-1]) rescue false
564
      if is_number
565
        (major, minor) = tokens[-1].split('.').flatten
566
        name = tokens[0...-1].join(' ')
567
      else
568
        name = tokens.join(' ')
569
      end
570
      [name, major || '', minor || '']
571
    end
572
  end
573
end