Project

General

Profile

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

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

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
    option %w(--continue-on-error), :flag, _('Continue processing even if individual resource error')
20

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

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

    
31
    def self.supported?
32
      false
33
    end
34

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

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

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

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

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

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

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

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

    
119
      server_status
120
    end
121

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

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

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

    
150
      option_threads.to_i.times do |current_thread|
151
        start_index = ((current_thread) * lines_per_thread).to_i
152
        finish_index = ((current_thread + 1) * lines_per_thread).to_i
153
        finish_index = csv.length if finish_index > csv.length
154
        if start_index <= finish_index
155
          lines = csv[start_index...finish_index].clone
156
          splits << Thread.new do
157
            lines.each do |line|
158
              next if line[name_column || NAME][0] == '#'
159
              begin
160
                yield line
161
              rescue RuntimeError => e
162
                message = "#{e}\n#{line}"
163
                option_continue_on_error? ? $stderr.puts(_("Error: %{message}") % {:message => message}) : raise(message)
164
              end
165
            end
166
          end
167
        end
168
      end
169

    
170
      splits.each do |thread|
171
        thread.join
172
      end
173
    end
174

    
175
    def hammer_context
176
      {
177
        :interactive => false,
178
        :username => 'admin', # TODO: this needs to come from config/settings
179
        :password => 'changeme' # TODO: this needs to come from config/settings
180
      }
181
    end
182

    
183
    def hammer(context = nil)
184
      HammerCLI::MainCommand.new('', context || hammer_context)
185
    end
186

    
187
    def foreman_organization(options = {})
188
      @organizations ||= {}
189

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

    
215
      result
216
    end
217

    
218
    def foreman_location(options = {})
219
      @locations ||= {}
220

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

    
246
      result
247
    end
248

    
249
    def foreman_role(options = {})
250
      @roles ||= {}
251

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

    
277
      result
278
    end
279

    
280
    def foreman_permission(options = {})
281
      @permissions ||= {}
282

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

    
308
      result
309
    end
310

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

    
322
      nil
323
    end
324

    
325
    def foreman_environment(options = {})
326
      @environments ||= {}
327

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

    
353
      result
354
    end
355

    
356
    def foreman_template_kind(options = {})
357
      @template_kinds ||= {}
358

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

    
384
      result
385
    end
386

    
387
    def foreman_operatingsystem(options = {})
388
      @operatingsystems ||= {}
389

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

    
420
      result
421
    end
422

    
423
    def foreman_architecture(options = {})
424
      @architectures ||= {}
425

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

    
451
      result
452
    end
453

    
454
    def foreman_domain(options = {})
455
      @domains ||= {}
456

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

    
482
      result
483
    end
484

    
485
    def foreman_partitiontable(options = {})
486
      @ptables ||= {}
487

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

    
514
      result
515
    end
516

    
517
    def foreman_medium(options = {})
518
      @media ||= {}
519

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

    
546
      result
547
    end
548

    
549
    def foreman_host(options = {})
550
      @query_hosts ||= {}
551

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

    
577
      result
578
    end
579

    
580
    def foreman_hostgroup(options = {})
581
      @query_hostgroups ||= {}
582

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

    
608
      result
609
    end
610

    
611
    def foreman_provisioning_template(options = {})
612
      @query_config_templates ||= {}
613

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

    
639
      result
640
    end
641

    
642
    def foreman_smart_proxy(options = {})
643
      @query_smart_proxies ||= {}
644

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

    
670
      result
671
    end
672

    
673
    def lifecycle_environment(organization, options = {})
674
      @lifecycle_environments ||= {}
675
      @lifecycle_environments[organization] ||= {
676
      }
677

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

    
704
      result
705
    end
706

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

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

    
737
      result
738
    end
739

    
740
    def katello_contentviewversion(organization, name, version='latest')
741
      @contentviewversions ||= {}
742
      @contentviewversions[organization] ||= {}
743
      versionname = "#{version}|#{name}"
744

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

    
766
      id
767
    end
768

    
769
    def katello_repository(organization, options = {})
770
      @repositories ||= {}
771
      @repositories[organization] ||= {}
772

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

    
799
      result
800
    end
801

    
802
    def katello_hostcollection(organization, options = {})
803
      @hostcollections ||= {}
804
      @hostcollections[organization] ||= {}
805

    
806
      if options[:name]
807
        return nil if options[:name].nil? || options[:name].empty?
808
        options[:id] = @hostcollections[organization][options[:name]]
809
        if !options[:id]
810
          @api.resource(:host_collections).call(:index,
811
                  {
812
                    :per_page => 999999,
813
                    'organization_id' => foreman_organization(:name => organization),
814
                    'search' => search_string('host-collections',options[:name])
815
                  })['results'].each do |hostcollection|
816
            @hostcollections[organization][hostcollection['name']] = hostcollection['id'] if hostcollection
817
          end
818
          options[:id] = @hostcollections[organization][options[:name]]
819
          raise _("Host collection '%{name}' not found") % {:name => options[:name]} if !options[:id]
820
        end
821
        result = options[:id]
822
      else
823
        return nil if options[:id].nil?
824
        options[:name] = @hostcollections.key(options[:id])
825
        if !options[:name]
826
          hostcollection = @api.resource(:host_collections).call(:show, {'id' => options[:id]})
827
          raise _("Host collection 'id=%{id}' not found") % {:id => options[:id]} if !hostcollection || hostcollection.empty?
828
          options[:name] = hostcollection['name']
829
          @hostcollections[options[:name]] = options[:id]
830
        end
831
        result = options[:name]
832
      end
833

    
834
      result
835
    end
836

    
837
    def katello_product(organization, options = {})
838
      @products ||= {}
839
      @products[organization] ||= {}
840

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

    
869
      result
870
    end
871

    
872
    def foreman_container(options = {})
873
      @containers ||= {}
874

    
875
      if options[:name]
876
        return nil if options[:name].nil? || options[:name].empty?
877
        options[:id] = @containers[options[:name]]
878
        if !options[:id]
879
          container = @api.resource(:containers).call(:index, {
880
                                                       :per_page => 999999,
881
                                                       'search' => "name=\"#{options[:name]}\""
882
                                                     })['results']
883
          raise _("Container '%{name}' not found") % {:name => options[:name]} if !container || container.empty?
884
          options[:id] = container[0]['id']
885
          @containers[options[:name]] = options[:id]
886
        end
887
        result = options[:id]
888
      else
889
        return nil if options[:id].nil?
890
        options[:name] = @containers.key(options[:id])
891
        if !options[:name]
892
          container = @api.resource(:containers).call(:show, {'id' => options[:id]})
893
          raise _("Container 'id=%{id}' not found") % {:id => options[:id]} if !container || container.empty?
894
          options[:name] = container['name']
895
          @containers[options[:name]] = options[:id]
896
        end
897
        result = options[:name]
898
      end
899

    
900
      result
901
    end
902

    
903

    
904
    def build_os_name(name, major, minor)
905
      name += " #{major}" if major && major != ''
906
      name += ".#{minor}" if minor && minor != ''
907
      name
908
    end
909

    
910
    # "Red Hat 6.4" => "Red Hat", "6", "4"
911
    # "Red Hat 6"   => "Red Hat", "6", ''
912
    def split_os_name(name)
913
      tokens = name.split(' ')
914
      is_number = Float(tokens[-1]) rescue false
915
      if is_number
916
        (major, minor) = tokens[-1].split('.').flatten
917
        name = tokens[0...-1].join(' ')
918
      else
919
        name = tokens.join(' ')
920
      end
921
      [name, major || '', minor || '']
922
    end
923

    
924
    def export_column(object, name, field=nil)
925
      return '' unless object[name]
926
      values = CSV.generate do |column|
927
        column << object[name].collect do |fields|
928
          field.nil? ? yield(fields) : fields[field]
929
        end
930
      end
931
      values.delete!("\n")
932
    end
933

    
934
    def collect_column(column)
935
      return [] if column.nil? || column.empty?
936
      CSV.parse_line(column, {:skip_blanks => true}).collect do |value|
937
        yield value
938
      end
939
    end
940

    
941
    def pluralize(name)
942
      case name
943
      when /smart_proxy/
944
        'smart_proxies'
945
      else
946
        "#{name}s"
947
      end
948
    end
949

    
950
    def associate_organizations(id, organizations, name)
951
      return if organizations.nil?
952

    
953
      associations ||= {}
954
      CSV.parse_line(organizations).each do |organization|
955
        organization_id = foreman_organization(:name => organization)
956
        if associations[organization].nil?
957
          associations[organization] = @api.resource(:organizations).call(:show, {'id' => organization_id})[pluralize(name)].collect do |reference_object|
958
            reference_object['id']
959
          end
960
        end
961
        associations[organization] += [id] if !associations[organization].include? id
962
        @api.resource(:organizations).call(:update, {
963
            'id' => organization_id,
964
            'organization' => {
965
                "#{name}_ids" => associations[organization]
966
            }
967
        })
968
      end if organizations && !organizations.empty?
969
    end
970

    
971
    def associate_locations(id, locations, name)
972
      return if locations.nil?
973

    
974
      associations ||= {}
975
      CSV.parse_line(locations).each do |location|
976
        location_id = foreman_location(:name => location)
977
        if associations[location].nil?
978
          associations[location] = @api.resource(:locations).call(:show, {'id' => location_id})[pluralize(name)].collect do |reference_object|
979
            reference_object['id']
980
          end
981
        end
982
        associations[location] += [id] if !associations[location].include? id
983

    
984
        @api.resource(:locations).call(:update, {
985
            'id' => location_id,
986
            'location' => {
987
                "#{name}_ids" => associations[location]
988
            }
989
        })
990
      end if locations && !locations.empty?
991
    end
992

    
993
    def apipie_check_param(resource, action, name)
994
      method = @api.resource(pluralize(resource).to_sym).apidoc[:methods].detect do |api_method|
995
        api_method[:name] == action.to_s
996
      end
997
      return false unless method
998

    
999
      found = method[:params].detect do |param|
1000
        param[:full_name] == name
1001
      end
1002
      if !found
1003
        nested =  method[:params].detect do |param|
1004
          param[:name] == resource.to_s
1005
        end
1006
        if nested
1007
          found = nested[:params].detect do |param|
1008
            param[:full_name] == name
1009
          end
1010
        end
1011
      end
1012
      found
1013
    end
1014

    
1015
    def count(value)
1016
      return 1 if value.nil? || value.empty?
1017
      value.to_i
1018
    end
1019

    
1020
    private
1021

    
1022
    def search_string(resource, name)
1023
      operator = case resource
1024
                 when "gpg-key", "sync-plan", "lifecycle-environment", "host-collections"
1025
                   @server_status['version'] && @server_status['version'].match(/\A1\.6/) ? ':' : '='
1026
                 else
1027
                   ':'
1028
                 end
1029
      "name#{operator}\"#{name}\""
1030
    end
1031
  end
1032
end