Project

General

Profile

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

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

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

    
17
module HammerCLICsv
18
  class BaseCommand < HammerCLI::Apipie::Command
19

    
20
    NAME = 'Name'
21
    COUNT = 'Count'
22

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

    
32
    def execute
33
      if !option_csv_file
34
        if option_csv_export?
35
          option_csv_file = '/dev/stdout'
36
        else
37
          option_csv_file = '/dev/stdin'
38
        end
39
      end
40

    
41
      @api = ApipieBindings::API.new({
42
                                       :uri => option_server || HammerCLI::Settings.get(:csv, :host),
43
                                       :username => option_username || HammerCLI::Settings.get(:csv, :username),
44
                                       :password => option_password || HammerCLI::Settings.get(:csv, :password),
45
                                       :api_version => 2
46
                                     })
47

    
48
      option_csv_export? ? export : import
49
      HammerCLI::EX_OK
50
    end
51

    
52
    def namify(name_format, number=0)
53
      if name_format.index('%')
54
        name = name_format % number
55
      else
56
        name = name_format
57
      end
58
      name = "#{option_prefix}#{name}" if option_prefix
59
      name
60
    end
61

    
62
    def labelize(name)
63
      name.gsub(/[^a-z0-9\-_]/i, "_")
64
    end
65

    
66
    def thread_import(return_headers=false)
67
      csv = []
68
      CSV.foreach(option_csv_file || '/dev/stdin', {:skip_blanks => true, :headers => :first_row, 
69
                    :return_headers => return_headers}) do |line|
70
        csv << line
71
      end
72
      lines_per_thread = csv.length/option_threads.to_i + 1
73
      splits = []
74

    
75
      option_threads.to_i.times do |current_thread|
76
        start_index = ((current_thread) * lines_per_thread).to_i
77
        finish_index = ((current_thread + 1) * lines_per_thread).to_i
78
        lines = csv[start_index...finish_index].clone
79
        splits << Thread.new do
80
          lines.each do |line|
81
            if line[NAME][0] != '#'
82
              yield line
83
            end
84
          end
85
        end
86
      end
87

    
88
      splits.each do |thread|
89
        thread.join
90
      end
91
    end
92

    
93
    def foreman_organization(options={})
94
      @organizations ||= {}
95

    
96
      if options[:name]
97
        return nil if options[:name].nil? || options[:name].empty?
98
        options[:id] = @organizations[options[:name]]
99
        if !options[:id]
100
          organization = @api.resource(:organizations).call(:index, {'search' => "name=\"#{options[:name]}\""})['results']
101
          raise RuntimeError, "Organization '#{options[:name]}' not found" if !organization || organization.empty?
102
          options[:id] = organization[0]['id']
103
          @organizations[options[:name]] = options[:id]
104
        end
105
        result = options[:id]
106
      else
107
        return nil if options[:id].nil?
108
        options[:name] = @organizations.key(options[:id])
109
        if !options[:name]
110
          organization = @api.resource(:organizations).call(:show, {'id' => options[:id]})
111
          raise "Organization 'id=#{options[:id]}' not found" if !organization || organization.empty?
112
          options[:name] = organization['name']
113
          @organizations[options[:name]] = options[:id]
114
        end
115
        result = options[:name]
116
      end
117

    
118
      result
119
    end
120

    
121
    def katello_organization(options={})
122
      @organizations ||= {}
123

    
124
      if options[:name]
125
        return nil if options[:name].nil? || options[:name].empty?
126
        options[:id] = @organizations[options[:name]]
127
        if !options[:id]
128
          organization = @api.resource(:organizations).call(:index, {'search' => "name=\"#{options[:name]}\""})['results']
129
          raise RuntimeError, "Organization '#{options[:name]}' not found" if !organization || organization.empty?
130
          options[:id] = organization[0]['label']
131
          @organizations[options[:name]] = options[:id]
132
        end
133
        result = options[:id]
134
      else
135
        return nil if options[:id].nil?
136
        options[:name] = @organizations.key(options[:id])
137
        if !options[:name]
138
          organization = @api.resource(:organizations).call(:show, {'id' => options[:id]})
139
          raise "Organization 'id=#{options[:id]}' not found" if !organization || organization.empty?
140
          options[:name] = organization['name']
141
          @organizations[options[:name]] = options[:id]
142
        end
143
        result = options[:name]
144
      end
145

    
146
      result
147
    end
148

    
149
    def foreman_location(options={})
150
      @locations ||= {}
151

    
152
      if options[:name]
153
        return nil if options[:name].nil? || options[:name].empty?
154
        options[:id] = @locations[options[:name]]
155
        if !options[:id]
156
          location = @api.resource(:locations).call(:index, {'search' => "name=\"#{options[:name]}\""})['results']
157
          raise RuntimeError, "Location '#{options[:name]}' not found" if !location || location.empty?
158
          options[:id] = location[0]['id']
159
          @locations[options[:name]] = options[:id]
160
        end
161
        result = options[:id]
162
      else
163
        return nil if options[:id].nil?
164
        options[:name] = @locations.key(options[:id])
165
        if !options[:name]
166
          location = @api.resource(:locations).call(:show, {'id' => options[:id]})
167
          raise "Location 'id=#{options[:id]}' not found" if !location || location.empty?
168
          options[:name] = location['name']
169
          @locations[options[:name]] = options[:id]
170
        end
171
        result = options[:name]
172
      end
173

    
174
      result
175
    end
176

    
177
    def foreman_role(options={})
178
      @roles ||= {}
179

    
180
      if options[:name]
181
        return nil if options[:name].nil? || options[:name].empty?
182
        options[:id] = @roles[options[:name]]
183
        if !options[:id]
184
          role = @api.resource(:roles).call(:index, {'search' => "name=\"#{options[:name]}\""})['results']
185
          raise RuntimeError, "Role '#{options[:name]}' not found" if !role || role.empty?
186
          options[:id] = role[0]['id']
187
          @roles[options[:name]] = options[:id]
188
        end
189
        result = options[:id]
190
      else
191
        return nil if options[:id].nil?
192
        options[:name] = @roles.key(options[:id])
193
        if !options[:name]
194
          role = @api.resource(:roles).call(:show, {'id' => options[:id]})
195
          raise "Role 'id=#{options[:id]}' not found" if !role || role.empty?
196
          options[:name] = role['name']
197
          @roles[options[:name]] = options[:id]
198
        end
199
        result = options[:name]
200
      end
201

    
202
      result
203
    end
204

    
205
    def foreman_permission(options={})
206
      @permissions ||= {}
207

    
208
      if options[:name]
209
        return nil if options[:name].nil? || options[:name].empty?
210
        options[:id] = @permissions[options[:name]]
211
        if !options[:id]
212
          permission = @api.resource(:permissions).call(:index, {'name' => options[:name]})['results']
213
          raise RuntimeError, "Permission '#{options[:name]}' not found" if !permission || permission.empty?
214
          options[:id] = permission[0]['id']
215
          @permissions[options[:name]] = options[:id]
216
        end
217
        result = options[:id]
218
      else
219
        return nil if options[:id].nil?
220
        options[:name] = @permissions.key(options[:id])
221
        if !options[:name]
222
          permission = @api.resource(:permissions).call(:show, {'id' => options[:id]})
223
          raise "Permission 'id=#{options[:id]}' not found" if !permission || permission.empty?
224
          options[:name] = permission['name']
225
          @permissions[options[:name]] = options[:id]
226
        end
227
        result = options[:name]
228
      end
229

    
230
      result
231
    end
232

    
233
    def foreman_filter(role, options={})
234
      @filters ||= {}
235

    
236
      if options[:name]
237
        return nil if options[:name].nil? || options[:name].empty?
238
        options[:id] = @filters[options[:name]]
239
        if !options[:id]
240
          filter = @api.resource(:filters).call(:index, {'search' => "role=\"#{role}\" and search=\"#{options[:name]}\""})['results']
241
          if !filter || filter.empty?
242
            options[:id] = nil
243
          else
244
            options[:id] = filter[0]['id']
245
            @filters[options[:name]] = options[:id]
246
          end
247
        end
248
        result = options[:id]
249
      else
250
        return nil if options[:id].nil?
251
        options[:name] = @filters.key(options[:id])
252
        if !options[:name]
253
          filter = @api.resource(:filters).call(:show, {'id' => options[:id]})
254
          raise "Filter 'id=#{options[:id]}' not found" if !filter || filter.empty?
255
          options[:name] = filter['name']
256
          @filters[options[:name]] = options[:id]
257
        end
258
        result = options[:name]
259
      end
260

    
261
      result
262
    end
263

    
264
    def foreman_environment(options={})
265
      @environments ||= {}
266

    
267
      if options[:name]
268
        return nil if options[:name].nil? || options[:name].empty?
269
        options[:id] = @environments[options[:name]]
270
        if !options[:id]
271
          environment = @api.resource(:environments).call(:index, {'search' => "name=\"#{options[:name]}\""})['results']
272
          raise "Puppet environment '#{options[:name]}' not found" if !environment || environment.empty?
273
          options[:id] = environment[0]['id']
274
          @environments[options[:name]] = options[:id]
275
        end
276
        result = options[:id]
277
      else
278
        return nil if options[:id].nil?
279
        options[:name] = @environments.key(options[:id])
280
        if !options[:name]
281
          environment = @api.resource(:environments).call(:show, {'id' => options[:id]})
282
          raise "Puppet environment '#{options[:name]}' not found" if !environment || environment.empty?
283
          options[:name] = environment['name']
284
          @environments[options[:name]] = options[:id]
285
        end
286
        result = options[:name]
287
      end
288

    
289
      result
290
    end
291

    
292
    def foreman_operatingsystem(options={})
293
      @operatingsystems ||= {}
294

    
295
      if options[:name]
296
        return nil if options[:name].nil? || options[:name].empty?
297
        options[:id] = @operatingsystems[options[:name]]
298
        if !options[:id]
299
          (osname, major, minor) = split_os_name(options[:name])
300
          search = "name=\"#{osname}\" and major=\"#{major}\" and minor=\"#{minor}\""
301
          operatingsystems = @api.resource(:operatingsystems).call(:index, {'search' => search})['results']
302
          operatingsystem = operatingsystems[0]
303
          raise "Operating system '#{options[:name]}' not found" if !operatingsystem || operatingsystem.empty?
304
          options[:id] = operatingsystem['id']
305
          @operatingsystems[options[:name]] = options[:id]
306
        end
307
        result = options[:id]
308
      else
309
        return nil if options[:id].nil?
310
        options[:name] = @operatingsystems.key(options[:id])
311
        if !options[:name]
312
          operatingsystem = @api.resource(:operatingsystems).call(:show, {'id' => options[:id]})
313
          raise "Operating system 'id=#{options[:id]}' not found" if !operatingsystem || operatingsystem.empty?
314
          options[:name] = build_os_name(operatingsystem['name'],
315
                                         operatingsystem['major'],
316
                                         operatingsystem['minor'])
317
          @operatingsystems[options[:name]] = options[:id]
318
        end
319
        result = options[:name]
320
      end
321

    
322
      result
323
    end
324

    
325
    def foreman_architecture(options={})
326
      @architectures ||= {}
327

    
328
      if options[:name]
329
        return nil if options[:name].nil? || options[:name].empty?
330
        options[:id] = @architectures[options[:name]]
331
        if !options[:id]
332
          architecture = @api.resource(:architectures).call(:index, {'search' => "name=\"#{options[:name]}\""})['results']
333
          raise "Architecture '#{options[:name]}' not found" if !architecture || architecture.empty?
334
          options[:id] = architecture[0]['id']
335
          @architectures[options[:name]] = options[:id]
336
        end
337
        result = options[:id]
338
      else
339
        return nil if options[:id].nil?
340
        options[:name] = @architectures.key(options[:id])
341
        if !options[:name]
342
          architecture = @api.resource(:architectures).call(:show, {'id' => options[:id]})
343
          raise "Architecture 'id=#{options[:id]}' not found" if !architecture || architecture.empty?
344
          options[:name] = architecture['name']
345
          @architectures[options[:name]] = options[:id]
346
        end
347
        result = options[:name]
348
      end
349

    
350
      result
351
    end
352

    
353
    def foreman_domain(options={})
354
      @domains ||= {}
355

    
356
      if options[:name]
357
        return nil if options[:name].nil? || options[:name].empty?
358
        options[:id] = @domains[options[:name]]
359
        if !options[:id]
360
          domain = @api.resource(:domains).call(:index, {'search' => "name=\"#{options[:name]}\""})['results']
361
          raise "Domain '#{options[:name]}' not found" if !domain || domain.empty?
362
          options[:id] = domain[0]['id']
363
          @domains[options[:name]] = options[:id]
364
        end
365
        result = options[:id]
366
      else
367
        return nil if options[:id].nil?
368
        options[:name] = @domains.key(options[:id])
369
        if !options[:name]
370
          domain = @api.resource(:domains).call(:show, {'id' => options[:id]})
371
          raise "Domain 'id=#{options[:id]}' not found" if !domain || domain.empty?
372
          options[:name] = domain['name']
373
          @domains[options[:name]] = options[:id]
374
        end
375
        result = options[:name]
376
      end
377

    
378
      result
379
    end
380

    
381
    def foreman_partitiontable(options={})
382
      @ptables ||= {}
383

    
384
      if options[:name]
385
        return nil if options[:name].nil? || options[:name].empty?
386
        options[:id] = @ptables[options[:name]]
387
        if !options[:id]
388
          ptable = @api.resource(:ptables).call(:index, {'search' => "name=\"#{options[:name]}\""})['results']
389
          raise "Partition table '#{options[:name]}' not found" if !ptable || ptable.empty?
390
          options[:id] = ptable[0]['id']
391
          @ptables[options[:name]] = options[:id]
392
        end
393
        result = options[:id]
394
      elsif options[:id]
395
        return nil if options[:id].nil?
396
        options[:name] = @ptables.key(options[:id])
397
        if !options[:name]
398
          ptable = @api.resource(:ptables).call(:show, {'id' => options[:id]})
399
          options[:name] = ptable['name']
400
          @ptables[options[:name]] = options[:id]
401
        end
402
        result = options[:name]
403
      elsif !options[:name] && !options[:id]
404
        result = ''
405
      end
406

    
407
      result
408
    end
409

    
410
    def katello_environment(organization, options={})
411
      @environments ||= {}
412
      @environments[organization] ||= {}
413

    
414
      if options[:name]
415
        return nil if options[:name].nil? || options[:name].empty?
416
        options[:id] = @environments[organization][options[:name]]
417
        if !options[:id]
418
          @api.resource(:lifecycle_environments).call(:index, {
419
                                                        'organization_id' => katello_organization(:name => organization),
420
                                                        'library' => true
421
                                                      })['results'].each do |environment|
422
            @environments[organization][environment['name']] = environment['id']
423
          end
424
          options[:id] = @environments[organization][options[:name]]
425
          raise "Lifecycle environment '#{options[:name]}' not found" if !options[:id]
426
        end
427
        result = options[:id]
428
      else
429
        return nil if options[:id].nil?
430
        options[:name] = @environments.key(options[:id])
431
        if !options[:name]
432
          environment = @api.resource(:lifecycle_environments).call(:show, {'id' => options[:id]})
433
          raise "Lifecycle environment '#{options[:name]}' not found" if !environment || environment.empty?
434
          options[:name] = environment['name']
435
          @environments[options[:name]] = options[:id]
436
        end
437
        result = options[:name]
438
      end
439

    
440
      result
441
    end
442

    
443
    def katello_contentview(organization, options={})
444
      @contentviews ||= {}
445
      @contentviews[organization] ||= {}
446

    
447
      if options[:name]
448
        return nil if options[:name].nil? || options[:name].empty?
449
        options[:id] = @contentviews[organization][options[:name]]
450
        if !options[:id]
451
          @api.resource(:content_views).call(:index, {'organization_id' => katello_organization(:name => organization)})['results'].each do |contentview|
452
            @contentviews[organization][contentview['name']] = contentview['id']
453
          end
454
          options[:id] = @contentviews[organization][options[:name]]
455
          raise "Content view '#{options[:name]}' not found" if !options[:id]
456
        end
457
        result = options[:id]
458
      else
459
        return nil if options[:id].nil?
460
        options[:name] = @contentviews.key(options[:id])
461
        if !options[:name]
462
          contentview = @api.resource(:content_views).call(:show, {'id' => options[:id]})
463
          raise "Puppet contentview '#{options[:name]}' not found" if !contentview || contentview.empty?
464
          options[:name] = contentview['name']
465
          @contentviews[options[:name]] = options[:id]
466
        end
467
        result = options[:name]
468
      end
469

    
470
      result
471
    end
472

    
473
    def katello_subscription(organization, options={})
474
      @subscriptions ||= {}
475
      @subscriptions[organization] ||= {}
476

    
477
      if options[:name]
478
        return nil if options[:name].nil? || options[:name].empty?
479
        options[:id] = @subscriptions[organization][options[:name]]
480
        if !options[:id]
481
          results = @api.resource(:subscriptions).call(:index, {
482
                                                'organization_id' => katello_organization(:name => organization),
483
                                                'search' => "name:\"#{options[:name]}\""
484
                                              })
485
          raise "No subscriptions match '#{options[:name]}'" if results['subtotal'] == 0
486
          raise "Too many subscriptions match '#{options[:name]}'" if results['subtotal'] > 1
487
          subscription = results['results'][0]
488
          @subscriptions[organization][options[:name]] = subscription['id']
489
          options[:id] = @subscriptions[organization][options[:name]]
490
          raise "Subscription '#{options[:name]}' not found" if !options[:id]
491
        end
492
        result = options[:id]
493
      else
494
        return nil if options[:id].nil?
495
        options[:name] = @subscriptions.key(options[:id])
496
        if !options[:name]
497
          subscription = @api.resource(:subscriptions).call(:show, {'id' => options[:id]})
498
          raise "Subscription '#{options[:name]}' not found" if !subscription || subscription.empty?
499
          options[:name] = subscription['name']
500
          @subscriptions[options[:name]] = options[:id]
501
        end
502
        result = options[:name]
503
      end
504

    
505
      result
506
    end
507

    
508
    def katello_systemgroup(organization, options={})
509
      @systemgroups ||= {}
510
      @systemgroups[organization] ||= {}
511

    
512
      if options[:name]
513
        return nil if options[:name].nil? || options[:name].empty?
514
        options[:id] = @systemgroups[organization][options[:name]]
515
        if !options[:id]
516
          @api.resource(:system_groups).call(:index, {
517
                                     'organization_id' => katello_organization(:name => organization),
518
                                     'search' => "name:\"#{options[:name]}\""
519
                                   })['results'].each do |systemgroup|
520
            @systemgroups[organization][systemgroup['name']] = systemgroup['id'] if systemgroup
521
          end
522
          options[:id] = @systemgroups[organization][options[:name]]
523
          raise "System group '#{options[:name]}' not found" if !options[:id]
524
        end
525
        result = options[:id]
526
      else
527
        return nil if options[:id].nil?
528
        options[:name] = @systemgroups.key(options[:id])
529
        if !options[:name]
530
          systemgroup = @api.resource(:system_groups).call(:show, {'id' => options[:id]})
531
          raise "System group '#{options[:name]}' not found" if !systemgroup || systemgroup.empty?
532
          options[:name] = systemgroup['name']
533
          @systemgroups[options[:name]] = options[:id]
534
        end
535
        result = options[:name]
536
      end
537

    
538
      result
539
    end
540

    
541
    def build_os_name(name, major, minor)
542
      name += " #{major}" if major && major != ""
543
      name += ".#{minor}" if minor && minor != ""
544
      name
545
    end
546

    
547
    # "Red Hat 6.4" => "Red Hat", "6", "4"
548
    # "Red Hat 6"   => "Red Hat", "6", ""
549
    def split_os_name(name)
550
      tokens = name.split(' ')
551
      is_number = Float(tokens[-1]) rescue false
552
      if is_number
553
        (major, minor) = tokens[-1].split('.').flatten
554
        name = tokens[0...-1].join(' ')
555
      else
556
        name = tokens.join(' ')
557
      end
558
      [name, major || "", minor || ""]
559
    end
560
  end
561
end