Project

General

Profile

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

hammer-cli-csv / lib / hammer_cli_csv / base.rb @ 502df2e4

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_smart_proxy(options = {})
550
      @query_smart_proxies ||= {}
551

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

    
577
      result
578
    end
579

    
580
    def lifecycle_environment(organization, options = {})
581
      @lifecycle_environments ||= {}
582
      @lifecycle_environments[organization] ||= {
583
      }
584

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

    
611
      result
612
    end
613

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

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

    
644
      result
645
    end
646

    
647
    def katello_contentviewversion(organization, name, version='latest')
648
      @contentviewversions ||= {}
649
      @contentviewversions[organization] ||= {}
650
      versionname = "#{version}|#{name}"
651

    
652
      return nil if name.nil? || name.empty?
653
      id = @contentviewversions[organization][versionname]
654
      if !id
655
        contentview_id = katello_contentview(organization, :name => name)
656
        contentviewversions = @api.resource(:content_view_versions).call(:index, {
657
                                  :per_page => 999999,
658
                                  'content_view_id' => contentview_id
659
                              })['results'].sort { |a, b| a['created_at'] <=> b['created_at'] }
660
        if version == 'latest'
661
          @contentviewversions[organization][versionname] = contentviewversions[-1]['id']
662
        else
663
          contentviewversions.each do |contentviewversion|
664
            if contentviewversion['version'] == version.to_f
665
              @contentviewversions[organization][versionname] = contentviewversion['id']
666
            end
667
          end
668
        end
669
        id = @contentviewversions[organization][versionname]
670
        raise "Content view version '#{name}' with version '#{version}' not found" if !id
671
      end
672

    
673
      id
674
    end
675

    
676
    def katello_repository(organization, options = {})
677
      @repositories ||= {}
678
      @repositories[organization] ||= {}
679

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

    
706
      result
707
    end
708

    
709
    def katello_subscription(organization, options = {})
710
      @subscriptions ||= {}
711
      @subscriptions[organization] ||= {}
712

    
713
      if options[:name]
714
        return nil if options[:name].nil? || options[:name].empty?
715
        options[:id] = @subscriptions[organization][options[:name]]
716
        if !options[:id]
717
          results = @api.resource(:subscriptions).call(:index, {
718
              :per_page => 999999,
719
              'organization_id' => foreman_organization(:name => organization),
720
              'search' => "name:\"#{options[:name]}\""
721
          })
722
          raise "No subscriptions match '#{options[:name]}'" if results['subtotal'] == 0
723
          raise "Too many subscriptions match '#{options[:name]}'" if results['subtotal'] > 1
724
          subscription = results['results'][0]
725
          @subscriptions[organization][options[:name]] = subscription['id']
726
          options[:id] = @subscriptions[organization][options[:name]]
727
          raise "Subscription '#{options[:name]}' not found" if !options[:id]
728
        end
729
        result = options[:id]
730
      else
731
        return nil if options[:id].nil?
732
        options[:name] = @subscriptions.key(options[:id])
733
        if !options[:name]
734
          subscription = @api.resource(:subscriptions).call(:show, {'id' => options[:id]})
735
          raise "Subscription '#{options[:name]}' not found" if !subscription || subscription.empty?
736
          options[:name] = subscription['name']
737
          @subscriptions[options[:name]] = options[:id]
738
        end
739
        result = options[:name]
740
      end
741

    
742
      result
743
    end
744

    
745
    def katello_hostcollection(organization, options = {})
746
      @hostcollections ||= {}
747
      @hostcollections[organization] ||= {}
748

    
749
      if options[:name]
750
        return nil if options[:name].nil? || options[:name].empty?
751
        options[:id] = @hostcollections[organization][options[:name]]
752
        if !options[:id]
753
          @api.resource(:host_collections).call(:index,
754
                  {
755
                    :per_page => 999999,
756
                    'organization_id' => foreman_organization(:name => organization),
757
                    'search' => search_string('host-collections',options[:name])
758
                  })['results'].each do |hostcollection|
759
            @hostcollections[organization][hostcollection['name']] = hostcollection['id'] if hostcollection
760
          end
761
          options[:id] = @hostcollections[organization][options[:name]]
762
          raise "Host collection '#{options[:name]}' not found" if !options[:id]
763
        end
764
        result = options[:id]
765
      else
766
        return nil if options[:id].nil?
767
        options[:name] = @hostcollections.key(options[:id])
768
        if !options[:name]
769
          hostcollection = @api.resource(:host_collections).call(:show, {'id' => options[:id]})
770
          raise "Host collection '#{options[:name]}' not found" if !hostcollection || hostcollection.empty?
771
          options[:name] = hostcollection['name']
772
          @hostcollections[options[:name]] = options[:id]
773
        end
774
        result = options[:name]
775
      end
776

    
777
      result
778
    end
779

    
780
    def katello_product(organization, options = {})
781
      @products ||= {}
782
      @products[organization] ||= {}
783

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

    
812
      result
813
    end
814

    
815
    def foreman_container(options = {})
816
      @containers ||= {}
817

    
818
      if options[:name]
819
        return nil if options[:name].nil? || options[:name].empty?
820
        options[:id] = @containers[options[:name]]
821
        if !options[:id]
822
          container = @api.resource(:containers).call(:index, {
823
                                                       :per_page => 999999,
824
                                                       'search' => "name=\"#{options[:name]}\""
825
                                                     })['results']
826
          raise "Container '#{options[:name]}' not found" if !container || container.empty?
827
          options[:id] = container[0]['id']
828
          @containers[options[:name]] = options[:id]
829
        end
830
        result = options[:id]
831
      else
832
        return nil if options[:id].nil?
833
        options[:name] = @containers.key(options[:id])
834
        if !options[:name]
835
          container = @api.resource(:containers).call(:show, {'id' => options[:id]})
836
          raise "Container 'id=#{options[:id]}' not found" if !container || container.empty?
837
          options[:name] = container['name']
838
          @containers[options[:name]] = options[:id]
839
        end
840
        result = options[:name]
841
      end
842

    
843
      result
844
    end
845

    
846

    
847
    def build_os_name(name, major, minor)
848
      name += " #{major}" if major && major != ''
849
      name += ".#{minor}" if minor && minor != ''
850
      name
851
    end
852

    
853
    # "Red Hat 6.4" => "Red Hat", "6", "4"
854
    # "Red Hat 6"   => "Red Hat", "6", ''
855
    def split_os_name(name)
856
      tokens = name.split(' ')
857
      is_number = Float(tokens[-1]) rescue false
858
      if is_number
859
        (major, minor) = tokens[-1].split('.').flatten
860
        name = tokens[0...-1].join(' ')
861
      else
862
        name = tokens.join(' ')
863
      end
864
      [name, major || '', minor || '']
865
    end
866

    
867
    def export_column(object, name, field)
868
      return '' unless object[name]
869
      values = CSV.generate do |column|
870
        column << object[name].collect do |fields|
871
          fields[field]
872
        end
873
      end
874
      values.delete!("\n")
875
    end
876

    
877
    def collect_column(column)
878
      return [] if column.nil? || column.empty?
879
      CSV.parse_line(column, {:skip_blanks => true}).collect do |value|
880
        yield value
881
      end
882
    end
883

    
884
    def pluralize(name)
885
      case name
886
      when /smart_proxy/
887
        'smart_proxies'
888
      else
889
        "#{name}s"
890
      end
891
    end
892

    
893
    def associate_organizations(id, organizations, name)
894
      return if organizations.nil?
895

    
896
      associations ||= {}
897
      CSV.parse_line(organizations).each do |organization|
898
        organization_id = foreman_organization(:name => organization)
899
        if associations[organization].nil?
900
          associations[organization] = @api.resource(:organizations).call(:show, {'id' => organization_id})[pluralize(name)].collect do |reference_object|
901
            reference_object['id']
902
          end
903
        end
904
        associations[organization] += [id] if !associations[organization].include? id
905
        @api.resource(:organizations).call(:update, {
906
            'id' => organization_id,
907
            'organization' => {
908
                "#{name}_ids" => associations[organization]
909
            }
910
        })
911
      end if organizations && !organizations.empty?
912
    end
913

    
914
    def associate_locations(id, locations, name)
915
      return if locations.nil?
916

    
917
      associations ||= {}
918
      CSV.parse_line(locations).each do |location|
919
        location_id = foreman_location(:name => location)
920
        if associations[location].nil?
921
          associations[location] = @api.resource(:locations).call(:show, {'id' => location_id})[pluralize(name)].collect do |reference_object|
922
            reference_object['id']
923
          end
924
        end
925
        associations[location] += [id] if !associations[location].include? id
926

    
927
        @api.resource(:locations).call(:update, {
928
            'id' => location_id,
929
            'location' => {
930
                "#{name}_ids" => associations[location]
931
            }
932
        })
933
      end if locations && !locations.empty?
934
    end
935

    
936
    def apipie_check_param(resource, action, name)
937
      method = @api.resource(pluralize(resource).to_sym).apidoc[:methods].detect do |api_method|
938
        api_method[:name] == action.to_s
939
      end
940
      return false unless method
941

    
942
      found = method[:params].detect do |param|
943
        param[:full_name] == name
944
      end
945
      if !found
946
        nested =  method[:params].detect do |param|
947
          param[:name] == resource.to_s
948
        end
949
        if nested
950
          found = nested[:params].detect do |param|
951
            param[:full_name] == name
952
          end
953
        end
954
      end
955
      found
956
    end
957

    
958
    def count(value)
959
      return 1 if value.nil? || value.empty?
960
      value.to_i
961
    end
962

    
963
    private
964

    
965
    def search_string(resource, name)
966
      operator = case resource
967
                 when "gpg-key", "sync-plan", "lifecycle-environment", "host-collections"
968
                   @server_status['version'] && @server_status['version'].match(/\A1\.6/) ? ':' : '='
969
                 else
970
                   ':'
971
                 end
972
      "name#{operator}\"#{name}\""
973
    end
974
  end
975
end