Project

General

Profile

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

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

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 --export, otherwise required)'
16
    option %w(--prefix), 'PREFIX', 'Prefix for all name columns',
17
           :hidden => true
18
    option %w(--organization), 'ORGANIZATION', _('Only process organization matching this name')
19

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

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

    
30
    def self.supported?
31
      false
32
    end
33

    
34
    def supported?
35
      self.class.supported?
36
    end
37

    
38
    def help
39
      print_message _('**** This command is unsupported and is provided as tech preview. ****') unless supported?
40
      super
41
    end
42

    
43
    def execute
44
      @server = (HammerCLI::Settings.settings[:_params] &&
45
                 HammerCLI::Settings.settings[:_params][:host]) ||
46
        HammerCLI::Settings.get(:csv, :host) ||
47
        HammerCLI::Settings.get(:katello, :host) ||
48
        HammerCLI::Settings.get(:foreman, :host)
49
      @username = (HammerCLI::Settings.settings[:_params] &&
50
                   HammerCLI::Settings.settings[:_params][:username]) ||
51
        HammerCLI::Settings.get(:csv, :username) ||
52
        HammerCLI::Settings.get(:katello, :username) ||
53
        HammerCLI::Settings.get(:foreman, :username)
54
      @password = (HammerCLI::Settings.settings[:_params] &&
55
                   HammerCLI::Settings.settings[:_params][:password]) ||
56
        HammerCLI::Settings.get(:csv, :password) ||
57
        HammerCLI::Settings.get(:katello, :password) ||
58
        HammerCLI::Settings.get(:foreman, :password)
59

    
60
      @server_status = check_server_status(@server, @username, @password)
61

    
62
      if @server_status['release'] == 'Headpin'
63
        @headpin = HeadpinApi.new({
64
                                    :server => @server,
65
                                    :username => @username,
66
                                    :password => @password
67
                                  })
68
      else
69
        @api = ApipieBindings::API.new({
70
                                         :uri => @server,
71
                                         :username => @username,
72
                                         :password => @password,
73
                                         :api_version => 2
74
                                       })
75
      end
76

    
77
      if option_export?
78
        if option_file
79
          CSV.open(option_file, 'wb', {:force_quotes => false}) do |csv|
80
            export csv
81
          end
82
        else
83
          CSV do |csv|
84
            export csv
85
          end
86
        end
87
      else
88
        import
89
      end
90
      HammerCLI::EX_OK
91
    end
92

    
93
    def check_server_status(server, username, password)
94
      url = "#{server}/api/status"
95
      uri = URI(url)
96
      nethttp = Net::HTTP.new(uri.host, uri.port)
97
      nethttp.use_ssl = uri.scheme == 'https'
98
      nethttp.verify_mode = OpenSSL::SSL::VERIFY_NONE
99
      server_status = nethttp.start do |http|
100
        request = Net::HTTP::Get.new uri.request_uri
101
        request.basic_auth(username, password)
102
        response = http.request(request)
103
        JSON.parse(response.body)
104
      end
105

    
106
      url = "#{server}/api/v2/plugins"
107
      uri = URI(url)
108
      nethttp = Net::HTTP.new(uri.host, uri.port)
109
      nethttp.use_ssl = uri.scheme == 'https'
110
      nethttp.verify_mode = OpenSSL::SSL::VERIFY_NONE
111
      server_status['plugins'] = nethttp.start do |http|
112
        request = Net::HTTP::Get.new uri.request_uri
113
        request.basic_auth(username, password)
114
        response = http.request(request)
115
        JSON.parse(response.body)['results']
116
      end
117

    
118
      server_status
119
    end
120

    
121
    def namify(name_format, number = 0)
122
      return '' unless name_format
123
      if name_format.index('%')
124
        name = name_format % number
125
      else
126
        name = name_format
127
      end
128
      name = "#{option_prefix}#{name}" if option_prefix
129
      name
130
    end
131

    
132
    def labelize(name)
133
      name.gsub(/[^a-z0-9\-_]/i, '_')
134
    end
135

    
136
    def thread_import(return_headers = false, filename=nil, name_column=nil)
137
      filename ||= option_file || '/dev/stdin'
138
      csv = []
139
      CSV.new(open(filename), {
140
          :skip_blanks => true,
141
          :headers => :first_row,
142
          :return_headers => return_headers
143
      }).each do |line|
144
        csv << line
145
      end
146
      lines_per_thread = csv.length / option_threads.to_i + 1
147
      splits = []
148

    
149
      option_threads.to_i.times do |current_thread|
150
        start_index = ((current_thread) * lines_per_thread).to_i
151
        finish_index = ((current_thread + 1) * lines_per_thread).to_i
152
        finish_index = csv.length if finish_index > csv.length
153
        if start_index <= finish_index
154
          lines = csv[start_index...finish_index].clone
155
          splits << Thread.new do
156
            lines.each do |line|
157
              if line[name_column || NAME][0] != '#'
158
                yield line
159
              end
160
            end
161
          end
162
        end
163
      end
164

    
165
      splits.each do |thread|
166
        thread.join
167
      end
168
    end
169

    
170
    def hammer_context
171
      {
172
        :interactive => false,
173
        :username => 'admin', # TODO: this needs to come from config/settings
174
        :password => 'changeme' # TODO: this needs to come from config/settings
175
      }
176
    end
177

    
178
    def hammer(context = nil)
179
      HammerCLI::MainCommand.new('', context || hammer_context)
180
    end
181

    
182
    def foreman_organization(options = {})
183
      @organizations ||= {}
184

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

    
210
      result
211
    end
212

    
213
    def foreman_location(options = {})
214
      @locations ||= {}
215

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

    
241
      result
242
    end
243

    
244
    def foreman_role(options = {})
245
      @roles ||= {}
246

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

    
272
      result
273
    end
274

    
275
    def foreman_permission(options = {})
276
      @permissions ||= {}
277

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

    
303
      result
304
    end
305

    
306
    def foreman_filter(role, resource, search)
307
      search = nil if search && search.empty?
308
      filters = @api.resource(:filters).call(:index, {
309
                                               :per_page => 999999,
310
                                               'search' => "role=\"#{role}\""
311
                                             })['results']
312
      filters.each do |filter|
313
        resource_type = (filter['resource_type'] || '').split(':')[-1] # To remove "Katello::" when present
314
        return filter['id'] if resource_type == resource && filter['search'] == search
315
      end
316

    
317
      nil
318
    end
319

    
320
    def foreman_environment(options = {})
321
      @environments ||= {}
322

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

    
348
      result
349
    end
350

    
351
    def foreman_template_kind(options = {})
352
      @template_kinds ||= {}
353

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

    
379
      result
380
    end
381

    
382
    def foreman_operatingsystem(options = {})
383
      @operatingsystems ||= {}
384

    
385
      if options[:name]
386
        return nil if options[:name].nil? || options[:name].empty?
387
        options[:id] = @operatingsystems[options[:name]]
388
        if !options[:id]
389
          (osname, major, minor) = split_os_name(options[:name])
390
          search = "name=\"#{osname}\" and major=\"#{major}\" and minor=\"#{minor}\""
391
          operatingsystems = @api.resource(:operatingsystems).call(:index, {
392
                                                                     :per_page => 999999,
393
                                                                     'search' => search
394
                                                                   })['results']
395
          operatingsystem = operatingsystems[0]
396
          raise "Operating system '#{options[:name]}' not found" if !operatingsystem || operatingsystem.empty?
397
          options[:id] = operatingsystem['id']
398
          @operatingsystems[options[:name]] = options[:id]
399
        end
400
        result = options[:id]
401
      else
402
        return nil if options[:id].nil?
403
        options[:name] = @operatingsystems.key(options[:id])
404
        if !options[:name]
405
          operatingsystem = @api.resource(:operatingsystems).call(:show, {'id' => options[:id]})
406
          raise "Operating system 'id=#{options[:id]}' not found" if !operatingsystem || operatingsystem.empty?
407
          options[:name] = build_os_name(operatingsystem['name'],
408
                                         operatingsystem['major'],
409
                                         operatingsystem['minor'])
410
          @operatingsystems[options[:name]] = options[:id]
411
        end
412
        result = options[:name]
413
      end
414

    
415
      result
416
    end
417

    
418
    def foreman_architecture(options = {})
419
      @architectures ||= {}
420

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

    
446
      result
447
    end
448

    
449
    def foreman_domain(options = {})
450
      @domains ||= {}
451

    
452
      if options[:name]
453
        return nil if options[:name].nil? || options[:name].empty?
454
        options[:id] = @domains[options[:name]]
455
        if !options[:id]
456
          domain = @api.resource(:domains).call(:index, {
457
                                                  :per_page => 999999,
458
                                                  'search' => "name=\"#{options[:name]}\""
459
                                                })['results']
460
          raise "Domain '#{options[:name]}' not found" if !domain || domain.empty?
461
          options[:id] = domain[0]['id']
462
          @domains[options[:name]] = options[:id]
463
        end
464
        result = options[:id]
465
      else
466
        return nil if options[:id].nil?
467
        options[:name] = @domains.key(options[:id])
468
        if !options[:name]
469
          domain = @api.resource(:domains).call(:show, {'id' => options[:id]})
470
          raise "Domain 'id=#{options[:id]}' not found" if !domain || domain.empty?
471
          options[:name] = domain['name']
472
          @domains[options[:name]] = options[:id]
473
        end
474
        result = options[:name]
475
      end
476

    
477
      result
478
    end
479

    
480
    def foreman_partitiontable(options = {})
481
      @ptables ||= {}
482

    
483
      if options[:name]
484
        return nil if options[:name].nil? || options[:name].empty?
485
        options[:id] = @ptables[options[:name]]
486
        if !options[:id]
487
          ptable = @api.resource(:ptables).call(:index, {
488
                                                  :per_page => 999999,
489
                                                  'search' => "name=\"#{options[:name]}\""
490
                                                })['results']
491
          raise "Partition table '#{options[:name]}' not found" if !ptable || ptable.empty?
492
          options[:id] = ptable[0]['id']
493
          @ptables[options[:name]] = options[:id]
494
        end
495
        result = options[:id]
496
      elsif options[:id]
497
        return nil if options[:id].nil?
498
        options[:name] = @ptables.key(options[:id])
499
        if !options[:name]
500
          ptable = @api.resource(:ptables).call(:show, {'id' => options[:id]})
501
          options[:name] = ptable['name']
502
          @ptables[options[:name]] = options[:id]
503
        end
504
        result = options[:name]
505
      elsif !options[:name] && !options[:id]
506
        result = ''
507
      end
508

    
509
      result
510
    end
511

    
512
    def foreman_medium(options = {})
513
      @media ||= {}
514

    
515
      if options[:name]
516
        return nil if options[:name].nil? || options[:name].empty?
517
        options[:id] = @media[options[:name]]
518
        if !options[:id]
519
          ptable = @api.resource(:media).call(:index, {
520
                                                  :per_page => 999999,
521
                                                  'search' => "name=\"#{options[:name]}\""
522
                                                })['results']
523
          raise "Partition table '#{options[:name]}' not found" if !ptable || ptable.empty?
524
          options[:id] = ptable[0]['id']
525
          @media[options[:name]] = options[:id]
526
        end
527
        result = options[:id]
528
      elsif options[:id]
529
        return nil if options[:id].nil?
530
        options[:name] = @media.key(options[:id])
531
        if !options[:name]
532
          ptable = @api.resource(:media).call(:show, {'id' => options[:id]})
533
          options[:name] = ptable['name']
534
          @media[options[:name]] = options[:id]
535
        end
536
        result = options[:name]
537
      elsif !options[:name] && !options[:id]
538
        result = ''
539
      end
540

    
541
      result
542
    end
543

    
544
    def foreman_host(options = {})
545
      @query_hosts ||= {}
546

    
547
      if options[:name]
548
        return nil if options[:name].nil? || options[:name].empty?
549
        options[:id] = @query_hosts[options[:name]]
550
        if !options[:id]
551
          host = @api.resource(:hosts).call(:index, {
552
                                              :per_page => 999999,
553
                                              'search' => "name=\"#{options[:name]}\""
554
                                            })['results']
555
          raise "Host '#{options[:name]}' not found" if !host || host.empty?
556
          options[:id] = host[0]['id']
557
          @query_hosts[options[:name]] = options[:id]
558
        end
559
        result = options[:id]
560
      else
561
        return nil if options[:id].nil?
562
        options[:name] = @query_hosts.key(options[:id])
563
        if !options[:name]
564
          host = @api.resource(:hosts).call(:show, {'id' => options[:id]})
565
          raise "Host 'id=#{options[:id]}' not found" if !host || host.empty?
566
          options[:name] = host['name']
567
          @query_hosts[options[:name]] = options[:id]
568
        end
569
        result = options[:name]
570
      end
571

    
572
      result
573
    end
574

    
575
    def foreman_hostgroup(options = {})
576
      @query_hostgroups ||= {}
577

    
578
      if options[:name]
579
        return nil if options[:name].nil? || options[:name].empty?
580
        options[:id] = @query_hostgroups[options[:name]]
581
        if !options[:id]
582
          hostgroup = @api.resource(:hostgroups).call(:index, {
583
                                              :per_page => 999999,
584
                                              'search' => "name=\"#{options[:name]}\""
585
                                            })['results']
586
          raise "Host Group '#{options[:name]}' not found" if !hostgroup || hostgroup.empty?
587
          options[:id] = hostgroup[0]['id']
588
          @query_hostgroups[options[:name]] = options[:id]
589
        end
590
        result = options[:id]
591
      else
592
        return nil if options[:id].nil?
593
        options[:name] = @query_hostgroups.key(options[:id])
594
        if !options[:name]
595
          hostgroup = @api.resource(:hostgroups).call(:show, {'id' => options[:id]})
596
          raise "Host Group 'id=#{options[:id]}' not found" if !hostgroup || hostgroup.empty?
597
          options[:name] = hostgroup['name']
598
          @query_hostgroups[options[:name]] = options[:id]
599
        end
600
        result = options[:name]
601
      end
602

    
603
      result
604
    end
605

    
606
    def foreman_provisioning_template(options = {})
607
      @query_config_templates ||= {}
608

    
609
      if options[:name]
610
        return nil if options[:name].nil? || options[:name].empty?
611
        options[:id] = @query_config_templates[options[:name]]
612
        if !options[:id]
613
          config_template = @api.resource(:config_templates).call(:index, {
614
                                              :per_page => 999999,
615
                                              'search' => "name=\"#{options[:name]}\""
616
                                            })['results']
617
          raise "Provisioning template '#{options[:name]}' not found" if !config_template || config_template.empty?
618
          options[:id] = config_template[0]['id']
619
          @query_config_templates[options[:name]] = options[:id]
620
        end
621
        result = options[:id]
622
      else
623
        return nil if options[:id].nil?
624
        options[:name] = @query_config_templates.key(options[:id])
625
        if !options[:name]
626
          config_template = @api.resource(:config_templates).call(:show, {'id' => options[:id]})
627
          raise "Provisioning template 'id=#{options[:id]}' not found" if !config_template || config_template.empty?
628
          options[:name] = config_template['name']
629
          @query_config_templates[options[:name]] = options[:id]
630
        end
631
        result = options[:name]
632
      end
633

    
634
      result
635
    end
636

    
637
    def foreman_smart_proxy(options = {})
638
      @query_smart_proxies ||= {}
639

    
640
      if options[:name]
641
        return nil if options[:name].nil? || options[:name].empty?
642
        options[:id] = @query_smart_proxies[options[:name]]
643
        if !options[:id]
644
          smart_proxy = @api.resource(:smart_proxies).call(:index, {
645
                                              :per_page => 999999,
646
                                              'search' => "name=\"#{options[:name]}\""
647
                                            })['results']
648
          raise "Smart Proxy '#{options[:name]}' not found" if !smart_proxy || smart_proxy.empty?
649
          options[:id] = smart_proxy[0]['id']
650
          @query_smart_proxies[options[:name]] = options[:id]
651
        end
652
        result = options[:id]
653
      else
654
        return nil if options[:id].nil?
655
        options[:name] = @query_smart_proxies.key(options[:id])
656
        if !options[:name]
657
          smart_proxy = @api.resource(:smart_proxies).call(:show, {'id' => options[:id]})
658
          raise "Smart Proxy 'id=#{options[:id]}' not found" if !smart_proxy || smart_proxy.empty?
659
          options[:name] = smart_proxy['name']
660
          @query_smart_proxies[options[:name]] = options[:id]
661
        end
662
        result = options[:name]
663
      end
664

    
665
      result
666
    end
667

    
668
    def lifecycle_environment(organization, options = {})
669
      @lifecycle_environments ||= {}
670
      @lifecycle_environments[organization] ||= {
671
      }
672

    
673
      if options[:name]
674
        return nil if options[:name].nil? || options[:name].empty?
675
        options[:id] = @lifecycle_environments[organization][options[:name]]
676
        if !options[:id]
677
          @api.resource(:lifecycle_environments).call(:index, {
678
              :per_page => 999999,
679
              'organization_id' => foreman_organization(:name => organization)
680
          })['results'].each do |environment|
681
            @lifecycle_environments[organization][environment['name']] = environment['id']
682
          end
683
          options[:id] = @lifecycle_environments[organization][options[:name]]
684
          raise "Lifecycle environment '#{options[:name]}' not found" if !options[:id]
685
        end
686
        result = options[:id]
687
      else
688
        return nil if options[:id].nil?
689
        options[:name] = @lifecycle_environments.key(options[:id])
690
        if !options[:name]
691
          environment = @api.resource(:lifecycle_environments).call(:show, {'id' => options[:id]})
692
          raise "Lifecycle environment '#{options[:name]}' not found" if !environment || environment.empty?
693
          options[:name] = environment['name']
694
          @lifecycle_environments[options[:name]] = options[:id]
695
        end
696
        result = options[:name]
697
      end
698

    
699
      result
700
    end
701

    
702
    def katello_contentview(organization, options = {})
703
      @contentviews ||= {}
704
      @contentviews[organization] ||= {}
705

    
706
      if options[:name]
707
        return nil if options[:name].nil? || options[:name].empty?
708
        options[:id] = @contentviews[organization][options[:name]]
709
        if !options[:id]
710
          @api.resource(:content_views).call(:index, {
711
              :per_page => 999999,
712
              'organization_id' => foreman_organization(:name => organization)
713
          })['results'].each do |contentview|
714
            @contentviews[organization][contentview['name']] = contentview['id']
715
          end
716
          options[:id] = @contentviews[organization][options[:name]]
717
          raise "Content view '#{options[:name]}' not found" if !options[:id]
718
        end
719
        result = options[:id]
720
      else
721
        return nil if options[:id].nil?
722
        options[:name] = @contentviews.key(options[:id])
723
        if !options[:name]
724
          contentview = @api.resource(:content_views).call(:show, {'id' => options[:id]})
725
          raise "Puppet contentview '#{options[:name]}' not found" if !contentview || contentview.empty?
726
          options[:name] = contentview['name']
727
          @contentviews[options[:name]] = options[:id]
728
        end
729
        result = options[:name]
730
      end
731

    
732
      result
733
    end
734

    
735
    def katello_contentviewversion(organization, name, version='latest')
736
      @contentviewversions ||= {}
737
      @contentviewversions[organization] ||= {}
738
      versionname = "#{version}|#{name}"
739

    
740
      return nil if name.nil? || name.empty?
741
      id = @contentviewversions[organization][versionname]
742
      if !id
743
        contentview_id = katello_contentview(organization, :name => name)
744
        contentviewversions = @api.resource(:content_view_versions).call(:index, {
745
                                  :per_page => 999999,
746
                                  'content_view_id' => contentview_id
747
                              })['results'].sort { |a, b| a['created_at'] <=> b['created_at'] }
748
        if version == 'latest'
749
          @contentviewversions[organization][versionname] = contentviewversions[-1]['id']
750
        else
751
          contentviewversions.each do |contentviewversion|
752
            if contentviewversion['version'] == version.to_f
753
              @contentviewversions[organization][versionname] = contentviewversion['id']
754
            end
755
          end
756
        end
757
        id = @contentviewversions[organization][versionname]
758
        raise "Content view version '#{name}' with version '#{version}' not found" if !id
759
      end
760

    
761
      id
762
    end
763

    
764
    def katello_repository(organization, options = {})
765
      @repositories ||= {}
766
      @repositories[organization] ||= {}
767

    
768
      if options[:name]
769
        return nil if options[:name].nil? || options[:name].empty?
770
        options[:id] = @repositories[organization][options[:name]]
771
        if !options[:id]
772
          @api.resource(:repositories).call(:index, {
773
              :per_page => 999999,
774
              'organization_id' => foreman_organization(:name => organization)
775
          })['results'].each do |repository|
776
            @repositories[organization][repository['name']] = repository['id']
777
          end
778
          options[:id] = @repositories[organization][options[:name]]
779
          raise "Repository '#{options[:name]}' not found" if !options[:id]
780
        end
781
        result = options[:id]
782
      else
783
        return nil if options[:id].nil?
784
        options[:name] = @repositories.key(options[:id])
785
        if !options[:name]
786
          repository = @api.resource(:repositories).call(:show, {'id' => options[:id]})
787
          raise "Puppet repository '#{options[:name]}' not found" if !repository || repository.empty?
788
          options[:name] = repository['name']
789
          @repositoriesr[options[:name]] = options[:id]
790
        end
791
        result = options[:name]
792
      end
793

    
794
      result
795
    end
796

    
797
    def katello_subscription(organization, options = {})
798
      @subscriptions ||= {}
799
      @subscriptions[organization] ||= {}
800

    
801
      if options[:name]
802
        return nil if options[:name].nil? || options[:name].empty?
803
        options[:id] = @subscriptions[organization][options[:name]]
804
        if !options[:id]
805
          results = @api.resource(:subscriptions).call(:index, {
806
              :per_page => 999999,
807
              'organization_id' => foreman_organization(:name => organization),
808
              'search' => "name = \"#{options[:name]}\""
809
          })
810
          raise "No subscriptions match '#{options[:name]}'" if results['subtotal'] == 0
811
          raise "Too many subscriptions match '#{options[:name]}'" if results['subtotal'] > 1
812
          subscription = results['results'][0]
813
          @subscriptions[organization][options[:name]] = subscription['id']
814
          options[:id] = @subscriptions[organization][options[:name]]
815
          raise "Subscription '#{options[:name]}' not found" if !options[:id]
816
        end
817
        result = options[:id]
818
      else
819
        return nil if options[:id].nil?
820
        options[:name] = @subscriptions.key(options[:id])
821
        if !options[:name]
822
          subscription = @api.resource(:subscriptions).call(:show, {'id' => options[:id]})
823
          raise "Subscription '#{options[:name]}' not found" if !subscription || subscription.empty?
824
          options[:name] = subscription['name']
825
          @subscriptions[options[:name]] = options[:id]
826
        end
827
        result = options[:name]
828
      end
829

    
830
      result
831
    end
832

    
833
    def katello_hostcollection(organization, options = {})
834
      @hostcollections ||= {}
835
      @hostcollections[organization] ||= {}
836

    
837
      if options[:name]
838
        return nil if options[:name].nil? || options[:name].empty?
839
        options[:id] = @hostcollections[organization][options[:name]]
840
        if !options[:id]
841
          @api.resource(:host_collections).call(:index,
842
                  {
843
                    :per_page => 999999,
844
                    'organization_id' => foreman_organization(:name => organization),
845
                    'search' => search_string('host-collections',options[:name])
846
                  })['results'].each do |hostcollection|
847
            @hostcollections[organization][hostcollection['name']] = hostcollection['id'] if hostcollection
848
          end
849
          options[:id] = @hostcollections[organization][options[:name]]
850
          raise "Host collection '#{options[:name]}' not found" if !options[:id]
851
        end
852
        result = options[:id]
853
      else
854
        return nil if options[:id].nil?
855
        options[:name] = @hostcollections.key(options[:id])
856
        if !options[:name]
857
          hostcollection = @api.resource(:host_collections).call(:show, {'id' => options[:id]})
858
          raise "Host collection '#{options[:name]}' not found" if !hostcollection || hostcollection.empty?
859
          options[:name] = hostcollection['name']
860
          @hostcollections[options[:name]] = options[:id]
861
        end
862
        result = options[:name]
863
      end
864

    
865
      result
866
    end
867

    
868
    def katello_product(organization, options = {})
869
      @products ||= {}
870
      @products[organization] ||= {}
871

    
872
      if options[:name]
873
        return nil if options[:name].nil? || options[:name].empty?
874
        options[:id] = @products[organization][options[:name]]
875
        if !options[:id]
876
          @api.resource(:products).call(:index,
877
                  {
878
                    :per_page => 999999,
879
                    'organization_id' => foreman_organization(:name => organization),
880
                    'search' => search_string('host-collections',options[:name])
881
                  })['results'].each do |product|
882
            @products[organization][product['name']] = product['id'] if product
883
          end
884
          options[:id] = @products[organization][options[:name]]
885
          raise "Host collection '#{options[:name]}' not found" if !options[:id]
886
        end
887
        result = options[:id]
888
      else
889
        return nil if options[:id].nil?
890
        options[:name] = @products.key(options[:id])
891
        if !options[:name]
892
          product = @api.resource(:host_collections).call(:show, {'id' => options[:id]})
893
          raise "Host collection '#{options[:name]}' not found" if !product || product.empty?
894
          options[:name] = product['name']
895
          @products[options[:name]] = options[:id]
896
        end
897
        result = options[:name]
898
      end
899

    
900
      result
901
    end
902

    
903
    def foreman_container(options = {})
904
      @containers ||= {}
905

    
906
      if options[:name]
907
        return nil if options[:name].nil? || options[:name].empty?
908
        options[:id] = @containers[options[:name]]
909
        if !options[:id]
910
          container = @api.resource(:containers).call(:index, {
911
                                                       :per_page => 999999,
912
                                                       'search' => "name=\"#{options[:name]}\""
913
                                                     })['results']
914
          raise "Container '#{options[:name]}' not found" if !container || container.empty?
915
          options[:id] = container[0]['id']
916
          @containers[options[:name]] = options[:id]
917
        end
918
        result = options[:id]
919
      else
920
        return nil if options[:id].nil?
921
        options[:name] = @containers.key(options[:id])
922
        if !options[:name]
923
          container = @api.resource(:containers).call(:show, {'id' => options[:id]})
924
          raise "Container 'id=#{options[:id]}' not found" if !container || container.empty?
925
          options[:name] = container['name']
926
          @containers[options[:name]] = options[:id]
927
        end
928
        result = options[:name]
929
      end
930

    
931
      result
932
    end
933

    
934

    
935
    def build_os_name(name, major, minor)
936
      name += " #{major}" if major && major != ''
937
      name += ".#{minor}" if minor && minor != ''
938
      name
939
    end
940

    
941
    # "Red Hat 6.4" => "Red Hat", "6", "4"
942
    # "Red Hat 6"   => "Red Hat", "6", ''
943
    def split_os_name(name)
944
      tokens = name.split(' ')
945
      is_number = Float(tokens[-1]) rescue false
946
      if is_number
947
        (major, minor) = tokens[-1].split('.').flatten
948
        name = tokens[0...-1].join(' ')
949
      else
950
        name = tokens.join(' ')
951
      end
952
      [name, major || '', minor || '']
953
    end
954

    
955
    def export_column(object, name, field=nil)
956
      return '' unless object[name]
957
      values = CSV.generate do |column|
958
        column << object[name].collect do |fields|
959
          field.nil? ? yield(fields) : fields[field]
960
        end
961
      end
962
      values.delete!("\n")
963
    end
964

    
965
    def collect_column(column)
966
      return [] if column.nil? || column.empty?
967
      CSV.parse_line(column, {:skip_blanks => true}).collect do |value|
968
        yield value
969
      end
970
    end
971

    
972
    def pluralize(name)
973
      case name
974
      when /smart_proxy/
975
        'smart_proxies'
976
      else
977
        "#{name}s"
978
      end
979
    end
980

    
981
    def associate_organizations(id, organizations, name)
982
      return if organizations.nil?
983

    
984
      associations ||= {}
985
      CSV.parse_line(organizations).each do |organization|
986
        organization_id = foreman_organization(:name => organization)
987
        if associations[organization].nil?
988
          associations[organization] = @api.resource(:organizations).call(:show, {'id' => organization_id})[pluralize(name)].collect do |reference_object|
989
            reference_object['id']
990
          end
991
        end
992
        associations[organization] += [id] if !associations[organization].include? id
993
        @api.resource(:organizations).call(:update, {
994
            'id' => organization_id,
995
            'organization' => {
996
                "#{name}_ids" => associations[organization]
997
            }
998
        })
999
      end if organizations && !organizations.empty?
1000
    end
1001

    
1002
    def associate_locations(id, locations, name)
1003
      return if locations.nil?
1004

    
1005
      associations ||= {}
1006
      CSV.parse_line(locations).each do |location|
1007
        location_id = foreman_location(:name => location)
1008
        if associations[location].nil?
1009
          associations[location] = @api.resource(:locations).call(:show, {'id' => location_id})[pluralize(name)].collect do |reference_object|
1010
            reference_object['id']
1011
          end
1012
        end
1013
        associations[location] += [id] if !associations[location].include? id
1014

    
1015
        @api.resource(:locations).call(:update, {
1016
            'id' => location_id,
1017
            'location' => {
1018
                "#{name}_ids" => associations[location]
1019
            }
1020
        })
1021
      end if locations && !locations.empty?
1022
    end
1023

    
1024
    def apipie_check_param(resource, action, name)
1025
      method = @api.resource(pluralize(resource).to_sym).apidoc[:methods].detect do |api_method|
1026
        api_method[:name] == action.to_s
1027
      end
1028
      return false unless method
1029

    
1030
      found = method[:params].detect do |param|
1031
        param[:full_name] == name
1032
      end
1033
      if !found
1034
        nested =  method[:params].detect do |param|
1035
          param[:name] == resource.to_s
1036
        end
1037
        if nested
1038
          found = nested[:params].detect do |param|
1039
            param[:full_name] == name
1040
          end
1041
        end
1042
      end
1043
      found
1044
    end
1045

    
1046
    def count(value)
1047
      return 1 if value.nil? || value.empty?
1048
      value.to_i
1049
    end
1050

    
1051
    private
1052

    
1053
    def search_string(resource, name)
1054
      operator = case resource
1055
                 when "gpg-key", "sync-plan", "lifecycle-environment", "host-collections"
1056
                   @server_status['version'] && @server_status['version'].match(/\A1\.6/) ? ':' : '='
1057
                 else
1058
                   ':'
1059
                 end
1060
      "name#{operator}\"#{name}\""
1061
    end
1062
  end
1063
end