Project

General

Profile

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

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

1
require 'apipie-bindings'
2
require 'hammer_cli'
3
require 'json'
4
require 'open-uri'
5
require 'csv'
6
require 'hammer_cli_csv/csv'
7

    
8
# rubocop:disable ClassLength
9
module HammerCLICsv
10
  class BaseCommand < HammerCLI::Apipie::Command
11
    option %w(-v --verbose), :flag, 'be verbose'
12
    option %w(--threads), 'THREAD_COUNT', 'Number of threads to hammer with', :default => 1
13
    option %w(--export), :flag, 'Export current data instead of importing'
14
    option %w(--file), 'FILE_NAME', 'CSV file (default to /dev/stdout with --csv-export, otherwise required)'
15
    option %w(--prefix), 'PREFIX', 'Prefix for all name columns'
16
    option %w(--organization), 'ORGANIZATION', _('Only process organization matching this name')
17

    
18
    option %w(--csv-file), 'FILE_NAME', 'Option --csv-file is deprecated. Use --file',
19
           :deprecated => "Use --file", :hidden => true,
20
           :attribute_name => :option_file
21
    option %w(--csv-export), :flag, 'Option --csv-export is deprecated. Use --export',
22
           :deprecated => "Use --export", :hidden => true,
23
           :attribute_name => :option_export
24

    
25

    
26
    NAME = 'Name'
27
    COUNT = 'Count'
28

    
29
    def execute
30
      @server = (HammerCLI::Settings.settings[:_params] &&
31
                 HammerCLI::Settings.settings[:_params][:host]) ||
32
        HammerCLI::Settings.get(:csv, :host) ||
33
        HammerCLI::Settings.get(:katello, :host) ||
34
        HammerCLI::Settings.get(:foreman, :host)
35
      @username = (HammerCLI::Settings.settings[:_params] &&
36
                   HammerCLI::Settings.settings[:_params][:username]) ||
37
        HammerCLI::Settings.get(:csv, :username) ||
38
        HammerCLI::Settings.get(:katello, :username) ||
39
        HammerCLI::Settings.get(:foreman, :username)
40
      @password = (HammerCLI::Settings.settings[:_params] &&
41
                   HammerCLI::Settings.settings[:_params][:password]) ||
42
        HammerCLI::Settings.get(:csv, :password) ||
43
        HammerCLI::Settings.get(:katello, :password) ||
44
        HammerCLI::Settings.get(:foreman, :password)
45

    
46
      @server_status = check_server_status(@server, @username, @password)
47

    
48
      if @server_status['release'] == 'Headpin'
49
        @headpin = HeadpinApi.new({
50
                                    :server => @server,
51
                                    :username => @username,
52
                                    :password => @password
53
                                  })
54
      else
55
        @api = ApipieBindings::API.new({
56
                                         :uri => @server,
57
                                         :username => @username,
58
                                         :password => @password,
59
                                         :api_version => 2
60
                                       })
61
      end
62

    
63
      option_export? ? export : import
64
      HammerCLI::EX_OK
65
    end
66

    
67
    def check_server_status(server, username, password)
68
      url = "#{server}/api/status"
69
      uri = URI(url)
70
      nethttp = Net::HTTP.new(uri.host, uri.port)
71
      nethttp.use_ssl = uri.scheme == 'https'
72
      nethttp.verify_mode = OpenSSL::SSL::VERIFY_NONE
73
      server_status = nethttp.start do |http|
74
        request = Net::HTTP::Get.new uri.request_uri
75
        request.basic_auth(username, password)
76
        response = http.request(request)
77
        JSON.parse(response.body)
78
      end
79

    
80
      url = "#{server}/api/v2/plugins"
81
      uri = URI(url)
82
      nethttp = Net::HTTP.new(uri.host, uri.port)
83
      nethttp.use_ssl = uri.scheme == 'https'
84
      nethttp.verify_mode = OpenSSL::SSL::VERIFY_NONE
85
      server_status['plugins'] = nethttp.start do |http|
86
        request = Net::HTTP::Get.new uri.request_uri
87
        request.basic_auth(username, password)
88
        response = http.request(request)
89
        JSON.parse(response.body)['results']
90
      end
91

    
92
      server_status
93
    end
94

    
95
    def namify(name_format, number = 0)
96
      if name_format.index('%')
97
        name = name_format % number
98
      else
99
        name = name_format
100
      end
101
      name = "#{option_prefix}#{name}" if option_prefix
102
      name
103
    end
104

    
105
    def labelize(name)
106
      name.gsub(/[^a-z0-9\-_]/i, '_')
107
    end
108

    
109
    def thread_import(return_headers = false, filename=nil, name_column=nil)
110
      filename ||= option_file || '/dev/stdin'
111
      csv = []
112
      CSV.new(open(filename), {
113
          :skip_blanks => true,
114
          :headers => :first_row,
115
          :return_headers => return_headers
116
      }).each do |line|
117
        csv << line
118
      end
119
      lines_per_thread = csv.length / option_threads.to_i + 1
120
      splits = []
121

    
122
      option_threads.to_i.times do |current_thread|
123
        start_index = ((current_thread) * lines_per_thread).to_i
124
        finish_index = ((current_thread + 1) * lines_per_thread).to_i
125
        finish_index = csv.length if finish_index > csv.length
126
        if start_index <= finish_index
127
          lines = csv[start_index...finish_index].clone
128
          splits << Thread.new do
129
            lines.each do |line|
130
              if line[name_column || NAME][0] != '#'
131
                yield line
132
              end
133
            end
134
          end
135
        end
136
      end
137

    
138
      splits.each do |thread|
139
        thread.join
140
      end
141
    end
142

    
143
    def hammer_context
144
      {
145
        :interactive => false,
146
        :username => 'admin', # TODO: this needs to come from config/settings
147
        :password => 'changeme' # TODO: this needs to come from config/settings
148
      }
149
    end
150

    
151
    def hammer(context = nil)
152
      HammerCLI::MainCommand.new('', context || hammer_context)
153
    end
154

    
155
    def foreman_organization(options = {})
156
      @organizations ||= {}
157

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

    
183
      result
184
    end
185

    
186
    def foreman_location(options = {})
187
      @locations ||= {}
188

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

    
214
      result
215
    end
216

    
217
    def foreman_role(options = {})
218
      @roles ||= {}
219

    
220
      if options[:name]
221
        return nil if options[:name].nil? || options[:name].empty?
222
        options[:id] = @roles[options[:name]]
223
        if !options[:id]
224
          role = @api.resource(:roles).call(:index, {
225
                                              :per_page => 999999,
226
                                              'search' => "name=\"#{options[:name]}\""
227
                                            })['results']
228
          raise "Role '#{options[:name]}' not found" if !role || role.empty?
229
          options[:id] = role[0]['id']
230
          @roles[options[:name]] = options[:id]
231
        end
232
        result = options[:id]
233
      else
234
        return nil if options[:id].nil?
235
        options[:name] = @roles.key(options[:id])
236
        if !options[:name]
237
          role = @api.resource(:roles).call(:show, {'id' => options[:id]})
238
          raise "Role 'id=#{options[:id]}' not found" if !role || role.empty?
239
          options[:name] = role['name']
240
          @roles[options[:name]] = options[:id]
241
        end
242
        result = options[:name]
243
      end
244

    
245
      result
246
    end
247

    
248
    def foreman_permission(options = {})
249
      @permissions ||= {}
250

    
251
      if options[:name]
252
        return nil if options[:name].nil? || options[:name].empty?
253
        options[:id] = @permissions[options[:name]]
254
        if !options[:id]
255
          permission = @api.resource(:permissions).call(:index, {
256
                                                          :per_page => 999999,
257
                                                          'name' => options[:name]
258
                                                        })['results']
259
          raise "Permission '#{options[:name]}' not found" if !permission || permission.empty?
260
          options[:id] = permission[0]['id']
261
          @permissions[options[:name]] = options[:id]
262
        end
263
        result = options[:id]
264
      else
265
        return nil if options[:id].nil?
266
        options[:name] = @permissions.key(options[:id])
267
        if !options[:name]
268
          permission = @api.resource(:permissions).call(:show, {'id' => options[:id]})
269
          raise "Permission 'id=#{options[:id]}' not found" if !permission || permission.empty?
270
          options[:name] = permission['name']
271
          @permissions[options[:name]] = options[:id]
272
        end
273
        result = options[:name]
274
      end
275

    
276
      result
277
    end
278

    
279
    def foreman_filter(role, resource, search)
280
      search = nil if search && search.empty?
281
      filters = @api.resource(:filters).call(:index, {
282
                                               :per_page => 999999,
283
                                               'search' => "role=\"#{role}\""
284
                                             })['results']
285
      filters.each do |filter|
286
        resource_type = (filter['resource_type'] || '').split(':')[-1] # To remove "Katello::" when present
287
        return filter['id'] if resource_type == resource && filter['search'] == search
288
      end
289

    
290
      nil
291
    end
292

    
293
    def foreman_environment(options = {})
294
      @environments ||= {}
295

    
296
      if options[:name]
297
        return nil if options[:name].nil? || options[:name].empty?
298
        options[:id] = @environments[options[:name]]
299
        if !options[:id]
300
          environment = @api.resource(:environments).call(:index, {
301
                                                            :per_page => 999999,
302
                                                            'search' => "name=\"#{ options[:name] }\""
303
                                                          })['results']
304
          raise "Puppet environment '#{options[:name]}' not found" if !environment || environment.empty?
305
          options[:id] = environment[0]['id']
306
          @environments[options[:name]] = options[:id]
307
        end
308
        result = options[:id]
309
      else
310
        return nil if options[:id].nil?
311
        options[:name] = @environments.key(options[:id])
312
        if !options[:name]
313
          environment = @api.resource(:environments).call(:show, {'id' => options[:id]})
314
          raise "Puppet environment '#{options[:name]}' not found" if !environment || environment.empty?
315
          options[:name] = environment['name']
316
          @environments[options[:name]] = options[:id]
317
        end
318
        result = options[:name]
319
      end
320

    
321
      result
322
    end
323

    
324
    def foreman_template_kind(options = {})
325
      @template_kinds ||= {}
326

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

    
352
      result
353
    end
354

    
355
    def foreman_operatingsystem(options = {})
356
      @operatingsystems ||= {}
357

    
358
      if options[:name]
359
        return nil if options[:name].nil? || options[:name].empty?
360
        options[:id] = @operatingsystems[options[:name]]
361
        if !options[:id]
362
          (osname, major, minor) = split_os_name(options[:name])
363
          search = "name=\"#{osname}\" and major=\"#{major}\" and minor=\"#{minor}\""
364
          operatingsystems = @api.resource(:operatingsystems).call(:index, {
365
                                                                     :per_page => 999999,
366
                                                                     'search' => search
367
                                                                   })['results']
368
          operatingsystem = operatingsystems[0]
369
          raise "Operating system '#{options[:name]}' not found" if !operatingsystem || operatingsystem.empty?
370
          options[:id] = operatingsystem['id']
371
          @operatingsystems[options[:name]] = options[:id]
372
        end
373
        result = options[:id]
374
      else
375
        return nil if options[:id].nil?
376
        options[:name] = @operatingsystems.key(options[:id])
377
        if !options[:name]
378
          operatingsystem = @api.resource(:operatingsystems).call(:show, {'id' => options[:id]})
379
          raise "Operating system 'id=#{options[:id]}' not found" if !operatingsystem || operatingsystem.empty?
380
          options[:name] = build_os_name(operatingsystem['name'],
381
                                         operatingsystem['major'],
382
                                         operatingsystem['minor'])
383
          @operatingsystems[options[:name]] = options[:id]
384
        end
385
        result = options[:name]
386
      end
387

    
388
      result
389
    end
390

    
391
    def foreman_architecture(options = {})
392
      @architectures ||= {}
393

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

    
419
      result
420
    end
421

    
422
    def foreman_domain(options = {})
423
      @domains ||= {}
424

    
425
      if options[:name]
426
        return nil if options[:name].nil? || options[:name].empty?
427
        options[:id] = @domains[options[:name]]
428
        if !options[:id]
429
          domain = @api.resource(:domains).call(:index, {
430
                                                  :per_page => 999999,
431
                                                  'search' => "name=\"#{options[:name]}\""
432
                                                })['results']
433
          raise "Domain '#{options[:name]}' not found" if !domain || domain.empty?
434
          options[:id] = domain[0]['id']
435
          @domains[options[:name]] = options[:id]
436
        end
437
        result = options[:id]
438
      else
439
        return nil if options[:id].nil?
440
        options[:name] = @domains.key(options[:id])
441
        if !options[:name]
442
          domain = @api.resource(:domains).call(:show, {'id' => options[:id]})
443
          raise "Domain 'id=#{options[:id]}' not found" if !domain || domain.empty?
444
          options[:name] = domain['name']
445
          @domains[options[:name]] = options[:id]
446
        end
447
        result = options[:name]
448
      end
449

    
450
      result
451
    end
452

    
453
    def foreman_partitiontable(options = {})
454
      @ptables ||= {}
455

    
456
      if options[:name]
457
        return nil if options[:name].nil? || options[:name].empty?
458
        options[:id] = @ptables[options[:name]]
459
        if !options[:id]
460
          ptable = @api.resource(:ptables).call(:index, {
461
                                                  :per_page => 999999,
462
                                                  'search' => "name=\"#{options[:name]}\""
463
                                                })['results']
464
          raise "Partition table '#{options[:name]}' not found" if !ptable || ptable.empty?
465
          options[:id] = ptable[0]['id']
466
          @ptables[options[:name]] = options[:id]
467
        end
468
        result = options[:id]
469
      elsif options[:id]
470
        return nil if options[:id].nil?
471
        options[:name] = @ptables.key(options[:id])
472
        if !options[:name]
473
          ptable = @api.resource(:ptables).call(:show, {'id' => options[:id]})
474
          options[:name] = ptable['name']
475
          @ptables[options[:name]] = options[:id]
476
        end
477
        result = options[:name]
478
      elsif !options[:name] && !options[:id]
479
        result = ''
480
      end
481

    
482
      result
483
    end
484

    
485
    def lifecycle_environment(organization, options = {})
486
      @lifecycle_environments ||= {}
487
      @lifecycle_environments[organization] ||= {
488
      }
489

    
490
      if options[:name]
491
        return nil if options[:name].nil? || options[:name].empty?
492
        options[:id] = @lifecycle_environments[organization][options[:name]]
493
        if !options[:id]
494
          @api.resource(:lifecycle_environments).call(:index, {
495
              :per_page => 999999,
496
              'organization_id' => foreman_organization(:name => organization)
497
          })['results'].each do |environment|
498
            @lifecycle_environments[organization][environment['name']] = environment['id']
499
          end
500
          options[:id] = @lifecycle_environments[organization][options[:name]]
501
          raise "Lifecycle environment '#{options[:name]}' not found" if !options[:id]
502
        end
503
        result = options[:id]
504
      else
505
        return nil if options[:id].nil?
506
        options[:name] = @lifecycle_environments.key(options[:id])
507
        if !options[:name]
508
          environment = @api.resource(:lifecycle_environments).call(:show, {'id' => options[:id]})
509
          raise "Lifecycle environment '#{options[:name]}' not found" if !environment || environment.empty?
510
          options[:name] = environment['name']
511
          @lifecycle_environments[options[:name]] = options[:id]
512
        end
513
        result = options[:name]
514
      end
515

    
516
      result
517
    end
518

    
519
    def katello_contentview(organization, options = {})
520
      @contentviews ||= {}
521
      @contentviews[organization] ||= {}
522

    
523
      if options[:name]
524
        return nil if options[:name].nil? || options[:name].empty?
525
        options[:id] = @contentviews[organization][options[:name]]
526
        if !options[:id]
527
          @api.resource(:content_views).call(:index, {
528
              :per_page => 999999,
529
              'organization_id' => foreman_organization(:name => organization)
530
          })['results'].each do |contentview|
531
            @contentviews[organization][contentview['name']] = contentview['id']
532
          end
533
          options[:id] = @contentviews[organization][options[:name]]
534
          raise "Content view '#{options[:name]}' not found" if !options[:id]
535
        end
536
        result = options[:id]
537
      else
538
        return nil if options[:id].nil?
539
        options[:name] = @contentviews.key(options[:id])
540
        if !options[:name]
541
          contentview = @api.resource(:content_views).call(:show, {'id' => options[:id]})
542
          raise "Puppet contentview '#{options[:name]}' not found" if !contentview || contentview.empty?
543
          options[:name] = contentview['name']
544
          @contentviews[options[:name]] = options[:id]
545
        end
546
        result = options[:name]
547
      end
548

    
549
      result
550
    end
551

    
552
    def katello_contentviewversion(organization, name, version='latest')
553
      @contentviewversions ||= {}
554
      @contentviewversions[organization] ||= {}
555
      versionname = "#{version}|#{name}"
556

    
557
      return nil if name.nil? || name.empty?
558
      id = @contentviewversions[organization][versionname]
559
      if !id
560
        contentview_id = katello_contentview(organization, :name => name)
561
        contentviewversions = @api.resource(:content_view_versions).call(:index, {
562
                                  :per_page => 999999,
563
                                  'content_view_id' => contentview_id
564
                              })['results'].sort { |a, b| a['created_at'] <=> b['created_at'] }
565
        if version == 'latest'
566
          @contentviewversions[organization][versionname] = contentviewversions[-1]['id']
567
        else
568
          contentviewversions.each do |contentviewversion|
569
            if contentviewversion['version'] == version.to_f
570
              @contentviewversions[organization][versionname] = contentviewversion['id']
571
            end
572
          end
573
        end
574
        id = @contentviewversions[organization][versionname]
575
        raise "Content view version '#{name}' with version '#{version}' not found" if !id
576
      end
577

    
578
      id
579
    end
580

    
581
    def katello_repository(organization, options = {})
582
      @repositories ||= {}
583
      @repositories[organization] ||= {}
584

    
585
      if options[:name]
586
        return nil if options[:name].nil? || options[:name].empty?
587
        options[:id] = @repositories[organization][options[:name]]
588
        if !options[:id]
589
          @api.resource(:repositories).call(:index, {
590
              :per_page => 999999,
591
              'organization_id' => foreman_organization(:name => organization)
592
          })['results'].each do |repository|
593
            @repositories[organization][repository['name']] = repository['id']
594
          end
595
          options[:id] = @repositories[organization][options[:name]]
596
          raise "Repository '#{options[:name]}' not found" if !options[:id]
597
        end
598
        result = options[:id]
599
      else
600
        return nil if options[:id].nil?
601
        options[:name] = @repositories.key(options[:id])
602
        if !options[:name]
603
          repository = @api.resource(:repositories).call(:show, {'id' => options[:id]})
604
          raise "Puppet repository '#{options[:name]}' not found" if !repository || repository.empty?
605
          options[:name] = repository['name']
606
          @repositoriesr[options[:name]] = options[:id]
607
        end
608
        result = options[:name]
609
      end
610

    
611
      result
612
    end
613

    
614
    def katello_subscription(organization, options = {})
615
      @subscriptions ||= {}
616
      @subscriptions[organization] ||= {}
617

    
618
      if options[:name]
619
        return nil if options[:name].nil? || options[:name].empty?
620
        options[:id] = @subscriptions[organization][options[:name]]
621
        if !options[:id]
622
          results = @api.resource(:subscriptions).call(:index, {
623
              :per_page => 999999,
624
              'organization_id' => foreman_organization(:name => organization),
625
              'search' => "name:\"#{options[:name]}\""
626
          })
627
          raise "No subscriptions match '#{options[:name]}'" if results['subtotal'] == 0
628
          raise "Too many subscriptions match '#{options[:name]}'" if results['subtotal'] > 1
629
          subscription = results['results'][0]
630
          @subscriptions[organization][options[:name]] = subscription['id']
631
          options[:id] = @subscriptions[organization][options[:name]]
632
          raise "Subscription '#{options[:name]}' not found" if !options[:id]
633
        end
634
        result = options[:id]
635
      else
636
        return nil if options[:id].nil?
637
        options[:name] = @subscriptions.key(options[:id])
638
        if !options[:name]
639
          subscription = @api.resource(:subscriptions).call(:show, {'id' => options[:id]})
640
          raise "Subscription '#{options[:name]}' not found" if !subscription || subscription.empty?
641
          options[:name] = subscription['name']
642
          @subscriptions[options[:name]] = options[:id]
643
        end
644
        result = options[:name]
645
      end
646

    
647
      result
648
    end
649

    
650
    def katello_hostcollection(organization, options = {})
651
      @hostcollections ||= {}
652
      @hostcollections[organization] ||= {}
653

    
654
      if options[:name]
655
        return nil if options[:name].nil? || options[:name].empty?
656
        options[:id] = @hostcollections[organization][options[:name]]
657
        if !options[:id]
658
          @api.resource(:host_collections).call(:index,
659
                  {
660
                    :per_page => 999999,
661
                    'organization_id' => foreman_organization(:name => organization),
662
                    'search' => search_string('host-collections',options[:name])
663
                  })['results'].each do |hostcollection|
664
            @hostcollections[organization][hostcollection['name']] = hostcollection['id'] if hostcollection
665
          end
666
          options[:id] = @hostcollections[organization][options[:name]]
667
          raise "Host collection '#{options[:name]}' not found" if !options[:id]
668
        end
669
        result = options[:id]
670
      else
671
        return nil if options[:id].nil?
672
        options[:name] = @hostcollections.key(options[:id])
673
        if !options[:name]
674
          hostcollection = @api.resource(:host_collections).call(:show, {'id' => options[:id]})
675
          raise "Host collection '#{options[:name]}' not found" if !hostcollection || hostcollection.empty?
676
          options[:name] = hostcollection['name']
677
          @hostcollections[options[:name]] = options[:id]
678
        end
679
        result = options[:name]
680
      end
681

    
682
      result
683
    end
684

    
685
    def katello_product(organization, options = {})
686
      @products ||= {}
687
      @products[organization] ||= {}
688

    
689
      if options[:name]
690
        return nil if options[:name].nil? || options[:name].empty?
691
        options[:id] = @products[organization][options[:name]]
692
        if !options[:id]
693
          @api.resource(:products).call(:index,
694
                  {
695
                    :per_page => 999999,
696
                    'organization_id' => foreman_organization(:name => organization),
697
                    'search' => search_string('host-collections',options[:name])
698
                  })['results'].each do |product|
699
            @products[organization][product['name']] = product['id'] if product
700
          end
701
          options[:id] = @products[organization][options[:name]]
702
          raise "Host collection '#{options[:name]}' not found" if !options[:id]
703
        end
704
        result = options[:id]
705
      else
706
        return nil if options[:id].nil?
707
        options[:name] = @products.key(options[:id])
708
        if !options[:name]
709
          product = @api.resource(:host_collections).call(:show, {'id' => options[:id]})
710
          raise "Host collection '#{options[:name]}' not found" if !product || product.empty?
711
          options[:name] = product['name']
712
          @products[options[:name]] = options[:id]
713
        end
714
        result = options[:name]
715
      end
716

    
717
      result
718
    end
719

    
720
    def foreman_container(options = {})
721
      @containers ||= {}
722

    
723
      if options[:name]
724
        return nil if options[:name].nil? || options[:name].empty?
725
        options[:id] = @containers[options[:name]]
726
        if !options[:id]
727
          container = @api.resource(:containers).call(:index, {
728
                                                       :per_page => 999999,
729
                                                       'search' => "name=\"#{options[:name]}\""
730
                                                     })['results']
731
          raise "Container '#{options[:name]}' not found" if !container || container.empty?
732
          options[:id] = container[0]['id']
733
          @containers[options[:name]] = options[:id]
734
        end
735
        result = options[:id]
736
      else
737
        return nil if options[:id].nil?
738
        options[:name] = @containers.key(options[:id])
739
        if !options[:name]
740
          container = @api.resource(:containers).call(:show, {'id' => options[:id]})
741
          raise "Container 'id=#{options[:id]}' not found" if !container || container.empty?
742
          options[:name] = container['name']
743
          @containers[options[:name]] = options[:id]
744
        end
745
        result = options[:name]
746
      end
747

    
748
      result
749
    end
750

    
751

    
752
    def build_os_name(name, major, minor)
753
      name += " #{major}" if major && major != ''
754
      name += ".#{minor}" if minor && minor != ''
755
      name
756
    end
757

    
758
    # "Red Hat 6.4" => "Red Hat", "6", "4"
759
    # "Red Hat 6"   => "Red Hat", "6", ''
760
    def split_os_name(name)
761
      tokens = name.split(' ')
762
      is_number = Float(tokens[-1]) rescue false
763
      if is_number
764
        (major, minor) = tokens[-1].split('.').flatten
765
        name = tokens[0...-1].join(' ')
766
      else
767
        name = tokens.join(' ')
768
      end
769
      [name, major || '', minor || '']
770
    end
771

    
772
    def export_column(object, name, field)
773
      return '' unless object[name]
774
      values = CSV.generate do |column|
775
        column << object[name].collect do |fields|
776
          fields[field]
777
        end
778
      end
779
      values.delete!("\n")
780
    end
781

    
782
    def collect_column(column)
783
      return [] if column.nil? || column.empty?
784
      CSV.parse_line(column, {:skip_blanks => true}).collect do |value|
785
        yield value
786
      end
787
    end
788

    
789
    def pluralize(name)
790
      case name
791
      when /smart_proxy/
792
        'smart_proxies'
793
      else
794
        "#{name}s"
795
      end
796
    end
797

    
798
    def associate_organizations(id, organizations, name)
799
      return if organizations.nil?
800

    
801
      associations ||= {}
802
      CSV.parse_line(organizations).each do |organization|
803
        organization_id = foreman_organization(:name => organization)
804
        if associations[organization].nil?
805
          associations[organization] = @api.resource(:organizations).call(:show, {'id' => organization_id})[pluralize(name)].collect do |reference_object|
806
            reference_object['id']
807
          end
808
        end
809
        associations[organization] += [id] if !associations[organization].include? id
810
        @api.resource(:organizations).call(:update, {
811
            'id' => organization_id,
812
            'organization' => {
813
                "#{name}_ids" => associations[organization]
814
            }
815
        })
816
      end if organizations && !organizations.empty?
817
    end
818

    
819
    def associate_locations(id, locations, name)
820
      return if locations.nil?
821

    
822
      associations ||= {}
823
      CSV.parse_line(locations).each do |location|
824
        location_id = foreman_location(:name => location)
825
        if associations[location].nil?
826
          associations[location] = @api.resource(:locations).call(:show, {'id' => location_id})[pluralize(name)].collect do |reference_object|
827
            reference_object['id']
828
          end
829
        end
830
        associations[location] += [id] if !associations[location].include? id
831

    
832
        @api.resource(:locations).call(:update, {
833
            'id' => location_id,
834
            'location' => {
835
                "#{name}_ids" => associations[location]
836
            }
837
        })
838
      end if locations && !locations.empty?
839
    end
840

    
841
    def apipie_check_param(resource, action, name)
842
      method = @api.resource(pluralize(resource).to_sym).apidoc[:methods].detect do |api_method|
843
        api_method[:name] == action.to_s
844
      end
845
      return false unless method
846

    
847
      found = method[:params].detect do |param|
848
        param[:full_name] == name
849
      end
850
      if !found
851
        nested =  method[:params].detect do |param|
852
          param[:name] == resource.to_s
853
        end
854
        if nested
855
          found = nested[:params].detect do |param|
856
            param[:full_name] == name
857
          end
858
        end
859
      end
860
      found
861
    end
862

    
863
    private
864

    
865
    def search_string(resource, name)
866
      operator = case resource
867
                 when "gpg-key", "sync-plan", "lifecycle-environment", "host-collections"
868
                   @server_status['version'] && @server_status['version'].match(/\A1\.6/) ? ':' : '='
869
                 else
870
                   ':'
871
                 end
872
      "name#{operator}\"#{name}\""
873
    end
874
  end
875
end