Project

General

Profile

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

hammer-cli-csv / lib / hammer_cli_csv / base.rb @ 5146ac68

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',
13
           :default => 1, :hidden => true
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'
17
    option %w(--organization), 'ORGANIZATION', _('Only process organization matching this name')
18

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

    
26

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

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

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

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

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

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

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

    
93
      server_status
94
    end
95

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

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

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

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

    
140
      splits.each do |thread|
141
        thread.join
142
      end
143
    end
144

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

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

    
157
    def foreman_organization(options = {})
158
      @organizations ||= {}
159

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

    
185
      result
186
    end
187

    
188
    def foreman_location(options = {})
189
      @locations ||= {}
190

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

    
216
      result
217
    end
218

    
219
    def foreman_role(options = {})
220
      @roles ||= {}
221

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

    
247
      result
248
    end
249

    
250
    def foreman_permission(options = {})
251
      @permissions ||= {}
252

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

    
278
      result
279
    end
280

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

    
292
      nil
293
    end
294

    
295
    def foreman_environment(options = {})
296
      @environments ||= {}
297

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

    
323
      result
324
    end
325

    
326
    def foreman_template_kind(options = {})
327
      @template_kinds ||= {}
328

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

    
354
      result
355
    end
356

    
357
    def foreman_operatingsystem(options = {})
358
      @operatingsystems ||= {}
359

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

    
390
      result
391
    end
392

    
393
    def foreman_architecture(options = {})
394
      @architectures ||= {}
395

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

    
421
      result
422
    end
423

    
424
    def foreman_domain(options = {})
425
      @domains ||= {}
426

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

    
452
      result
453
    end
454

    
455
    def foreman_partitiontable(options = {})
456
      @ptables ||= {}
457

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

    
484
      result
485
    end
486

    
487
    def foreman_host(options = {})
488
      @query_hosts ||= {}
489

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

    
515
      result
516
    end
517

    
518
    def foreman_hostgroup(options = {})
519
      @query_hostgroups ||= {}
520

    
521
      if options[:name]
522
        return nil if options[:name].nil? || options[:name].empty?
523
        options[:id] = @query_hostgroups[options[:name]]
524
        if !options[:id]
525
          hostgroup = @api.resource(:hostgroups).call(:index, {
526
                                              :per_page => 999999,
527
                                              'search' => "name=\"#{options[:name]}\""
528
                                            })['results']
529
          raise "Host Group '#{options[:name]}' not found" if !hostgroup || hostgroup.empty?
530
          options[:id] = hostgroup[0]['id']
531
          @query_hostgroups[options[:name]] = options[:id]
532
        end
533
        result = options[:id]
534
      else
535
        return nil if options[:id].nil?
536
        options[:name] = @query_hostgroups.key(options[:id])
537
        if !options[:name]
538
          hostgroup = @api.resource(:hostgroups).call(:show, {'id' => options[:id]})
539
          raise "Host Group 'id=#{options[:id]}' not found" if !hostgroup || hostgroup.empty?
540
          options[:name] = hostgroup['name']
541
          @query_hostgroups[options[:name]] = options[:id]
542
        end
543
        result = options[:name]
544
      end
545

    
546
      result
547
    end
548

    
549
    def foreman_provisioning_template(options = {})
550
      @query_config_templates ||= {}
551

    
552
      if options[:name]
553
        return nil if options[:name].nil? || options[:name].empty?
554
        options[:id] = @query_config_templates[options[:name]]
555
        if !options[:id]
556
          config_template = @api.resource(:config_templates).call(:index, {
557
                                              :per_page => 999999,
558
                                              'search' => "name=\"#{options[:name]}\""
559
                                            })['results']
560
          raise "Provisioning template '#{options[:name]}' not found" if !config_template || config_template.empty?
561
          options[:id] = config_template[0]['id']
562
          @query_config_templates[options[:name]] = options[:id]
563
        end
564
        result = options[:id]
565
      else
566
        return nil if options[:id].nil?
567
        options[:name] = @query_config_templates.key(options[:id])
568
        if !options[:name]
569
          config_template = @api.resource(:config_templates).call(:show, {'id' => options[:id]})
570
          raise "Provisioning template 'id=#{options[:id]}' not found" if !config_template || config_template.empty?
571
          options[:name] = config_template['name']
572
          @query_config_templates[options[:name]] = options[:id]
573
        end
574
        result = options[:name]
575
      end
576

    
577
      result
578
    end
579

    
580
    def foreman_smart_proxy(options = {})
581
      @query_smart_proxies ||= {}
582

    
583
      if options[:name]
584
        return nil if options[:name].nil? || options[:name].empty?
585
        options[:id] = @query_smart_proxies[options[:name]]
586
        if !options[:id]
587
          smart_proxy = @api.resource(:smart_proxies).call(:index, {
588
                                              :per_page => 999999,
589
                                              'search' => "name=\"#{options[:name]}\""
590
                                            })['results']
591
          raise "Smart Proxy '#{options[:name]}' not found" if !smart_proxy || smart_proxy.empty?
592
          options[:id] = smart_proxy[0]['id']
593
          @query_smart_proxies[options[:name]] = options[:id]
594
        end
595
        result = options[:id]
596
      else
597
        return nil if options[:id].nil?
598
        options[:name] = @query_smart_proxies.key(options[:id])
599
        if !options[:name]
600
          smart_proxy = @api.resource(:smart_proxies).call(:show, {'id' => options[:id]})
601
          raise "Smart Proxy 'id=#{options[:id]}' not found" if !smart_proxy || smart_proxy.empty?
602
          options[:name] = smart_proxy['name']
603
          @query_smart_proxies[options[:name]] = options[:id]
604
        end
605
        result = options[:name]
606
      end
607

    
608
      result
609
    end
610

    
611
    def lifecycle_environment(organization, options = {})
612
      @lifecycle_environments ||= {}
613
      @lifecycle_environments[organization] ||= {
614
      }
615

    
616
      if options[:name]
617
        return nil if options[:name].nil? || options[:name].empty?
618
        options[:id] = @lifecycle_environments[organization][options[:name]]
619
        if !options[:id]
620
          @api.resource(:lifecycle_environments).call(:index, {
621
              :per_page => 999999,
622
              'organization_id' => foreman_organization(:name => organization)
623
          })['results'].each do |environment|
624
            @lifecycle_environments[organization][environment['name']] = environment['id']
625
          end
626
          options[:id] = @lifecycle_environments[organization][options[:name]]
627
          raise "Lifecycle environment '#{options[:name]}' not found" if !options[:id]
628
        end
629
        result = options[:id]
630
      else
631
        return nil if options[:id].nil?
632
        options[:name] = @lifecycle_environments.key(options[:id])
633
        if !options[:name]
634
          environment = @api.resource(:lifecycle_environments).call(:show, {'id' => options[:id]})
635
          raise "Lifecycle environment '#{options[:name]}' not found" if !environment || environment.empty?
636
          options[:name] = environment['name']
637
          @lifecycle_environments[options[:name]] = options[:id]
638
        end
639
        result = options[:name]
640
      end
641

    
642
      result
643
    end
644

    
645
    def katello_contentview(organization, options = {})
646
      @contentviews ||= {}
647
      @contentviews[organization] ||= {}
648

    
649
      if options[:name]
650
        return nil if options[:name].nil? || options[:name].empty?
651
        options[:id] = @contentviews[organization][options[:name]]
652
        if !options[:id]
653
          @api.resource(:content_views).call(:index, {
654
              :per_page => 999999,
655
              'organization_id' => foreman_organization(:name => organization)
656
          })['results'].each do |contentview|
657
            @contentviews[organization][contentview['name']] = contentview['id']
658
          end
659
          options[:id] = @contentviews[organization][options[:name]]
660
          raise "Content view '#{options[:name]}' not found" if !options[:id]
661
        end
662
        result = options[:id]
663
      else
664
        return nil if options[:id].nil?
665
        options[:name] = @contentviews.key(options[:id])
666
        if !options[:name]
667
          contentview = @api.resource(:content_views).call(:show, {'id' => options[:id]})
668
          raise "Puppet contentview '#{options[:name]}' not found" if !contentview || contentview.empty?
669
          options[:name] = contentview['name']
670
          @contentviews[options[:name]] = options[:id]
671
        end
672
        result = options[:name]
673
      end
674

    
675
      result
676
    end
677

    
678
    def katello_contentviewversion(organization, name, version='latest')
679
      @contentviewversions ||= {}
680
      @contentviewversions[organization] ||= {}
681
      versionname = "#{version}|#{name}"
682

    
683
      return nil if name.nil? || name.empty?
684
      id = @contentviewversions[organization][versionname]
685
      if !id
686
        contentview_id = katello_contentview(organization, :name => name)
687
        contentviewversions = @api.resource(:content_view_versions).call(:index, {
688
                                  :per_page => 999999,
689
                                  'content_view_id' => contentview_id
690
                              })['results'].sort { |a, b| a['created_at'] <=> b['created_at'] }
691
        if version == 'latest'
692
          @contentviewversions[organization][versionname] = contentviewversions[-1]['id']
693
        else
694
          contentviewversions.each do |contentviewversion|
695
            if contentviewversion['version'] == version.to_f
696
              @contentviewversions[organization][versionname] = contentviewversion['id']
697
            end
698
          end
699
        end
700
        id = @contentviewversions[organization][versionname]
701
        raise "Content view version '#{name}' with version '#{version}' not found" if !id
702
      end
703

    
704
      id
705
    end
706

    
707
    def katello_repository(organization, options = {})
708
      @repositories ||= {}
709
      @repositories[organization] ||= {}
710

    
711
      if options[:name]
712
        return nil if options[:name].nil? || options[:name].empty?
713
        options[:id] = @repositories[organization][options[:name]]
714
        if !options[:id]
715
          @api.resource(:repositories).call(:index, {
716
              :per_page => 999999,
717
              'organization_id' => foreman_organization(:name => organization)
718
          })['results'].each do |repository|
719
            @repositories[organization][repository['name']] = repository['id']
720
          end
721
          options[:id] = @repositories[organization][options[:name]]
722
          raise "Repository '#{options[:name]}' not found" if !options[:id]
723
        end
724
        result = options[:id]
725
      else
726
        return nil if options[:id].nil?
727
        options[:name] = @repositories.key(options[:id])
728
        if !options[:name]
729
          repository = @api.resource(:repositories).call(:show, {'id' => options[:id]})
730
          raise "Puppet repository '#{options[:name]}' not found" if !repository || repository.empty?
731
          options[:name] = repository['name']
732
          @repositoriesr[options[:name]] = options[:id]
733
        end
734
        result = options[:name]
735
      end
736

    
737
      result
738
    end
739

    
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
    def katello_hostcollection(organization, options = {})
777
      @hostcollections ||= {}
778
      @hostcollections[organization] ||= {}
779

    
780
      if options[:name]
781
        return nil if options[:name].nil? || options[:name].empty?
782
        options[:id] = @hostcollections[organization][options[:name]]
783
        if !options[:id]
784
          @api.resource(:host_collections).call(:index,
785
                  {
786
                    :per_page => 999999,
787
                    'organization_id' => foreman_organization(:name => organization),
788
                    'search' => search_string('host-collections',options[:name])
789
                  })['results'].each do |hostcollection|
790
            @hostcollections[organization][hostcollection['name']] = hostcollection['id'] if hostcollection
791
          end
792
          options[:id] = @hostcollections[organization][options[:name]]
793
          raise "Host collection '#{options[:name]}' not found" if !options[:id]
794
        end
795
        result = options[:id]
796
      else
797
        return nil if options[:id].nil?
798
        options[:name] = @hostcollections.key(options[:id])
799
        if !options[:name]
800
          hostcollection = @api.resource(:host_collections).call(:show, {'id' => options[:id]})
801
          raise "Host collection '#{options[:name]}' not found" if !hostcollection || hostcollection.empty?
802
          options[:name] = hostcollection['name']
803
          @hostcollections[options[:name]] = options[:id]
804
        end
805
        result = options[:name]
806
      end
807

    
808
      result
809
    end
810

    
811
    def katello_product(organization, options = {})
812
      @products ||= {}
813
      @products[organization] ||= {}
814

    
815
      if options[:name]
816
        return nil if options[:name].nil? || options[:name].empty?
817
        options[:id] = @products[organization][options[:name]]
818
        if !options[:id]
819
          @api.resource(:products).call(:index,
820
                  {
821
                    :per_page => 999999,
822
                    'organization_id' => foreman_organization(:name => organization),
823
                    'search' => search_string('host-collections',options[:name])
824
                  })['results'].each do |product|
825
            @products[organization][product['name']] = product['id'] if product
826
          end
827
          options[:id] = @products[organization][options[:name]]
828
          raise "Host collection '#{options[:name]}' not found" if !options[:id]
829
        end
830
        result = options[:id]
831
      else
832
        return nil if options[:id].nil?
833
        options[:name] = @products.key(options[:id])
834
        if !options[:name]
835
          product = @api.resource(:host_collections).call(:show, {'id' => options[:id]})
836
          raise "Host collection '#{options[:name]}' not found" if !product || product.empty?
837
          options[:name] = product['name']
838
          @products[options[:name]] = options[:id]
839
        end
840
        result = options[:name]
841
      end
842

    
843
      result
844
    end
845

    
846
    def foreman_container(options = {})
847
      @containers ||= {}
848

    
849
      if options[:name]
850
        return nil if options[:name].nil? || options[:name].empty?
851
        options[:id] = @containers[options[:name]]
852
        if !options[:id]
853
          container = @api.resource(:containers).call(:index, {
854
                                                       :per_page => 999999,
855
                                                       'search' => "name=\"#{options[:name]}\""
856
                                                     })['results']
857
          raise "Container '#{options[:name]}' not found" if !container || container.empty?
858
          options[:id] = container[0]['id']
859
          @containers[options[:name]] = options[:id]
860
        end
861
        result = options[:id]
862
      else
863
        return nil if options[:id].nil?
864
        options[:name] = @containers.key(options[:id])
865
        if !options[:name]
866
          container = @api.resource(:containers).call(:show, {'id' => options[:id]})
867
          raise "Container 'id=#{options[:id]}' not found" if !container || container.empty?
868
          options[:name] = container['name']
869
          @containers[options[:name]] = options[:id]
870
        end
871
        result = options[:name]
872
      end
873

    
874
      result
875
    end
876

    
877

    
878
    def build_os_name(name, major, minor)
879
      name += " #{major}" if major && major != ''
880
      name += ".#{minor}" if minor && minor != ''
881
      name
882
    end
883

    
884
    # "Red Hat 6.4" => "Red Hat", "6", "4"
885
    # "Red Hat 6"   => "Red Hat", "6", ''
886
    def split_os_name(name)
887
      tokens = name.split(' ')
888
      is_number = Float(tokens[-1]) rescue false
889
      if is_number
890
        (major, minor) = tokens[-1].split('.').flatten
891
        name = tokens[0...-1].join(' ')
892
      else
893
        name = tokens.join(' ')
894
      end
895
      [name, major || '', minor || '']
896
    end
897

    
898
    def export_column(object, name, field=nil)
899
      return '' unless object[name]
900
      values = CSV.generate do |column|
901
        column << object[name].collect do |fields|
902
          field.nil? ? yield(fields) : fields[field]
903
        end
904
      end
905
      values.delete!("\n")
906
    end
907

    
908
    def collect_column(column)
909
      return [] if column.nil? || column.empty?
910
      CSV.parse_line(column, {:skip_blanks => true}).collect do |value|
911
        yield value
912
      end
913
    end
914

    
915
    def pluralize(name)
916
      case name
917
      when /smart_proxy/
918
        'smart_proxies'
919
      else
920
        "#{name}s"
921
      end
922
    end
923

    
924
    def associate_organizations(id, organizations, name)
925
      return if organizations.nil?
926

    
927
      associations ||= {}
928
      CSV.parse_line(organizations).each do |organization|
929
        organization_id = foreman_organization(:name => organization)
930
        if associations[organization].nil?
931
          associations[organization] = @api.resource(:organizations).call(:show, {'id' => organization_id})[pluralize(name)].collect do |reference_object|
932
            reference_object['id']
933
          end
934
        end
935
        associations[organization] += [id] if !associations[organization].include? id
936
        @api.resource(:organizations).call(:update, {
937
            'id' => organization_id,
938
            'organization' => {
939
                "#{name}_ids" => associations[organization]
940
            }
941
        })
942
      end if organizations && !organizations.empty?
943
    end
944

    
945
    def associate_locations(id, locations, name)
946
      return if locations.nil?
947

    
948
      associations ||= {}
949
      CSV.parse_line(locations).each do |location|
950
        location_id = foreman_location(:name => location)
951
        if associations[location].nil?
952
          associations[location] = @api.resource(:locations).call(:show, {'id' => location_id})[pluralize(name)].collect do |reference_object|
953
            reference_object['id']
954
          end
955
        end
956
        associations[location] += [id] if !associations[location].include? id
957

    
958
        @api.resource(:locations).call(:update, {
959
            'id' => location_id,
960
            'location' => {
961
                "#{name}_ids" => associations[location]
962
            }
963
        })
964
      end if locations && !locations.empty?
965
    end
966

    
967
    def apipie_check_param(resource, action, name)
968
      method = @api.resource(pluralize(resource).to_sym).apidoc[:methods].detect do |api_method|
969
        api_method[:name] == action.to_s
970
      end
971
      return false unless method
972

    
973
      found = method[:params].detect do |param|
974
        param[:full_name] == name
975
      end
976
      if !found
977
        nested =  method[:params].detect do |param|
978
          param[:name] == resource.to_s
979
        end
980
        if nested
981
          found = nested[:params].detect do |param|
982
            param[:full_name] == name
983
          end
984
        end
985
      end
986
      found
987
    end
988

    
989
    def count(value)
990
      return 1 if value.nil? || value.empty?
991
      value.to_i
992
    end
993

    
994
    private
995

    
996
    def search_string(resource, name)
997
      operator = case resource
998
                 when "gpg-key", "sync-plan", "lifecycle-environment", "host-collections"
999
                   @server_status['version'] && @server_status['version'].match(/\A1\.6/) ? ':' : '='
1000
                 else
1001
                   ':'
1002
                 end
1003
      "name#{operator}\"#{name}\""
1004
    end
1005
  end
1006
end