foreman_omaha 0.0.3 → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (72) hide show
  1. checksums.yaml +5 -5
  2. data/README.md +5 -2
  3. data/app/assets/javascripts/foreman_omaha/application.js +1 -0
  4. data/app/assets/stylesheets/foreman_omaha/version_breakdown.scss +13 -0
  5. data/app/controllers/api/v2/omaha_groups_controller.rb +29 -0
  6. data/app/controllers/api/v2/omaha_reports_controller.rb +9 -7
  7. data/app/controllers/omaha_groups_controller.rb +28 -0
  8. data/app/controllers/omaha_hosts_controller.rb +42 -0
  9. data/app/controllers/omaha_reports_controller.rb +0 -11
  10. data/app/helpers/concerns/foreman_omaha/hosts_helper_extensions.rb +15 -6
  11. data/app/helpers/foreman_omaha/application_helper.rb +7 -0
  12. data/app/helpers/foreman_omaha/omaha_groups_helper.rb +52 -0
  13. data/app/helpers/omaha_hosts_helper.rb +43 -0
  14. data/app/models/concerns/foreman_omaha/host_extensions.rb +16 -2
  15. data/app/models/concerns/foreman_omaha/omaha_facet_host_extensions.rb +23 -0
  16. data/app/models/foreman_omaha/omaha_facet.rb +40 -0
  17. data/app/models/foreman_omaha/omaha_group.rb +34 -0
  18. data/app/models/foreman_omaha/omaha_report.rb +13 -21
  19. data/app/models/host_status/omaha_status.rb +6 -16
  20. data/app/services/foreman_omaha/charts/oem_distribution.rb +24 -0
  21. data/app/services/foreman_omaha/charts/status_distribution.rb +57 -0
  22. data/app/services/foreman_omaha/charts/version_distribution.rb +24 -0
  23. data/app/services/foreman_omaha/container_linux_config_transpiler.rb +33 -0
  24. data/app/services/foreman_omaha/fact_parser.rb +19 -3
  25. data/app/services/foreman_omaha/group_version_breakdown.rb +30 -0
  26. data/app/services/foreman_omaha/omaha_report_importer.rb +52 -3
  27. data/app/services/foreman_omaha/renderer_methods.rb +7 -0
  28. data/app/services/foreman_omaha/status_mapper.rb +53 -0
  29. data/app/views/api/v2/omaha_groups/base.json.rabl +3 -0
  30. data/app/views/api/v2/omaha_groups/index.json.rabl +3 -0
  31. data/app/views/api/v2/omaha_groups/main.json.rabl +5 -0
  32. data/app/views/api/v2/omaha_groups/show.json.rabl +3 -0
  33. data/app/views/application/foreman_omaha/_toolbar.html.erb +11 -0
  34. data/app/views/foreman_omaha/api/v2/omaha_facets/base.json.rabl +5 -0
  35. data/app/views/foreman_omaha/api/v2/omaha_facets/base_with_root.json.rabl +3 -0
  36. data/app/views/foreman_omaha/api/v2/omaha_facets/show.json.rabl +3 -0
  37. data/app/views/hosts/_omaha_tab.html.erb +29 -0
  38. data/app/views/omaha_groups/index.html.erb +34 -0
  39. data/app/views/omaha_groups/show.html.erb +196 -0
  40. data/app/views/omaha_hosts/index.html.erb +51 -0
  41. data/app/views/omaha_hosts/welcome.html.erb +12 -0
  42. data/app/views/omaha_reports/_details.html.erb +5 -3
  43. data/app/views/omaha_reports/_list.html.erb +2 -2
  44. data/app/views/omaha_reports/show.html.erb +1 -1
  45. data/app/views/omaha_reports/welcome.html.erb +1 -1
  46. data/config/routes.rb +14 -1
  47. data/db/migrate/20160812083100_add_omaha_fields_to_reports.foreman_omaha.rb +1 -1
  48. data/db/migrate/20171101204100_create_omaha_facets.foreman_omaha.rb +22 -0
  49. data/db/seeds.d/200_omaha_groups.rb +6 -0
  50. data/lib/foreman_omaha/engine.rb +74 -21
  51. data/lib/foreman_omaha/version.rb +1 -1
  52. data/lib/tasks/foreman_omaha_tasks.rake +2 -4
  53. data/test/factories/feature.rb +1 -1
  54. data/test/factories/foreman_omaha_factories.rb +16 -1
  55. data/test/factories/host.rb +21 -0
  56. data/test/factories/smart_proxy.rb +1 -1
  57. data/test/functional/api/v2/omaha_groups_controller_test.rb +32 -0
  58. data/test/functional/api/v2/omaha_reports_controller_test.rb +24 -24
  59. data/test/functional/omaha_groups_controller_test.rb +18 -0
  60. data/test/functional/omaha_hosts_controller_test.rb +11 -0
  61. data/test/functional/omaha_reports_controller_test.rb +13 -13
  62. data/test/test_plugin_helper.rb +3 -3
  63. data/test/unit/charts/oem_distribution_test.rb +26 -0
  64. data/test/unit/charts/status_distribution_test.rb +28 -0
  65. data/test/unit/charts/version_distribution_test.rb +28 -0
  66. data/test/unit/group_version_breakdown_test.rb +65 -0
  67. data/test/unit/host_status/omaha_status_test.rb +19 -0
  68. data/test/unit/host_test.rb +55 -0
  69. data/test/unit/omaha_fact_parser_test.rb +77 -0
  70. data/test/unit/omaha_report_test.rb +63 -17
  71. data/test/unit/renderer_test.rb +21 -0
  72. metadata +80 -9
@@ -0,0 +1,34 @@
1
+ module ForemanOmaha
2
+ class OmahaGroup < ApplicationRecord
3
+ include Authorizable
4
+
5
+ def self.humanize_class_name
6
+ N_('Omaha Channel')
7
+ end
8
+
9
+ has_many :omaha_facets, :class_name => 'ForemanOmaha::OmahaFacet', :foreign_key => :omaha_group_id,
10
+ :inverse_of => :omaha_group, :dependent => :restrict_with_exception
11
+ has_many :hosts, :class_name => '::Host::Managed', :through => :omaha_facets,
12
+ :inverse_of => :omaha_group
13
+
14
+ scoped_search :on => :name, :complete_value => :true, :default_order => true
15
+
16
+ validates_lengths_from_database
17
+
18
+ before_validation :ensure_uuid
19
+
20
+ def operatingsystems
21
+ Coreos.where(:release_name => name.downcase)
22
+ end
23
+
24
+ def latest_operatingsystem
25
+ operatingsystems.order(:major, :minor).last
26
+ end
27
+
28
+ private
29
+
30
+ def ensure_uuid
31
+ self.uuid ||= SecureRandom.uuid
32
+ end
33
+ end
34
+ end
@@ -1,7 +1,6 @@
1
1
  module ForemanOmaha
2
2
  class OmahaReport < ::Report
3
- enum :status => [:unknown, :complete, :downloading, :downloaded,
4
- :installed, :instance_hold, :error]
3
+ enum :status => OmahaFacet::VALID_OMAHA_STATUSES
5
4
 
6
5
  scoped_search :on => :omaha_version, :rename => :version, :complete_value => true
7
6
  scoped_search :on => :status, :complete_value => statuses
@@ -14,25 +13,12 @@ module ForemanOmaha
14
13
  'status'
15
14
  end
16
15
 
17
- def to_label
18
- case status.to_sym
19
- when :complete
20
- _('Complete')
21
- when :downloading
22
- _('Downloading')
23
- when :downloaded
24
- _('Downloaded')
25
- when :installed
26
- _('Installed')
27
- when :instance_hold
28
- _('Instance Hold')
29
- when :error
30
- _('Error')
31
- else
32
- _('unknown')
33
- end
16
+ def self.humanize_class_name
17
+ N_('Omaha Report')
34
18
  end
35
19
 
20
+ delegate :to_label, :to_description, :to => :status_mapper
21
+
36
22
  def operatingsystem
37
23
  return if omaha_version.blank?
38
24
  args = { :type => 'Coreos', :major => osmajor, :minor => osminor }
@@ -41,14 +27,20 @@ module ForemanOmaha
41
27
 
42
28
  def osmajor
43
29
  omaha_version.gsub(/^(\d+)\.\d\.\d$/, '\1')
44
- rescue
30
+ rescue StandardError
45
31
  nil
46
32
  end
47
33
 
48
34
  def osminor
49
35
  omaha_version.gsub(/^\d+\.(\d\.\d)$/, '\1')
50
- rescue
36
+ rescue StandardError
51
37
  nil
52
38
  end
39
+
40
+ private
41
+
42
+ def status_mapper
43
+ StatusMapper.new(status)
44
+ end
53
45
  end
54
46
  end
@@ -1,27 +1,17 @@
1
1
  module HostStatus
2
2
  class OmahaStatus < HostStatus::Status
3
- def last_report
4
- self.last_report = host.last_omaha_report_object unless @last_report_set
5
- @last_report
6
- end
7
-
8
- def last_report=(report)
9
- @last_report_set = true
10
- @last_report = report
11
- end
12
-
13
3
  def self.status_name
14
4
  N_('Omaha Status')
15
5
  end
16
6
 
17
7
  def to_status(_options = {})
18
- return ::ForemanOmaha::OmahaReport.statuses[:unknown] unless relevant?
19
- ::ForemanOmaha::OmahaReport.statuses[last_report.status]
8
+ return ::ForemanOmaha::OmahaFacet.statuses[:unknown] unless relevant?
9
+ ::ForemanOmaha::OmahaFacet.statuses[host.omaha_facet.status]
20
10
  end
21
11
 
22
12
  def to_global(_options = {})
23
- return ::ForemanOmaha::OmahaReport.statuses[:unknown] unless relevant?
24
- case last_report.status.to_sym
13
+ return ::ForemanOmaha::OmahaFacet.statuses[:unknown] unless relevant?
14
+ case host.omaha_facet.status.to_sym
25
15
  when :complete, :downloaded, :downloading, :installed
26
16
  HostStatus::Global::OK
27
17
  when :instance_hold
@@ -34,11 +24,11 @@ module HostStatus
34
24
  end
35
25
 
36
26
  def to_label(_options = {})
37
- last_report.to_label
27
+ host.omaha_facet.to_status_label
38
28
  end
39
29
 
40
30
  def relevant?(_options = {})
41
- host && last_report.present?
31
+ host && !!host.omaha_facet
42
32
  end
43
33
  end
44
34
  end
@@ -0,0 +1,24 @@
1
+ module ForemanOmaha
2
+ module Charts
3
+ class OemDistribution
4
+ attr_accessor :hosts
5
+
6
+ def initialize(hosts = nil)
7
+ @hosts = hosts || Host.authorized(:view_hosts, Host).joins(:omaha_facet)
8
+ end
9
+
10
+ def query
11
+ @query ||= hosts.group(:oem).count
12
+ end
13
+
14
+ def to_chart_data
15
+ query.map do |oem, count|
16
+ {
17
+ :label => oem,
18
+ :data => count
19
+ }
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,57 @@
1
+ module ForemanOmaha
2
+ module Charts
3
+ class StatusDistribution
4
+ attr_accessor :hosts
5
+
6
+ def initialize(hosts = nil)
7
+ @hosts = hosts || Host.authorized(:view_hosts, Host).joins(:omaha_facet)
8
+ end
9
+
10
+ def query
11
+ @query ||= hosts.group(:status).count.transform_keys { |k| ForemanOmaha::OmahaFacet.statuses.key(k).to_sym }
12
+ end
13
+
14
+ def to_chart_data
15
+ query.map do |status, count|
16
+ {
17
+ :label => status_label(status),
18
+ :data => count,
19
+ :color => status_color(status)
20
+ }
21
+ end
22
+ end
23
+
24
+ def to_a
25
+ query.map do |status, count|
26
+ {
27
+ :status => status,
28
+ :label => status_label(status),
29
+ :count => count
30
+ }
31
+ end
32
+ end
33
+
34
+ private
35
+
36
+ def color_map
37
+ {
38
+ :unknown => '#92A8CD',
39
+ :complete => '#89A54E',
40
+ :downloading => '#3D96AE',
41
+ :downloaded => '#4572A7',
42
+ :installed => '#DB843D',
43
+ :instance_hold => '#80699B',
44
+ :error => '#AA4643'
45
+ }
46
+ end
47
+
48
+ def status_color(status)
49
+ color_map[status]
50
+ end
51
+
52
+ def status_label(status)
53
+ ForemanOmaha::StatusMapper.new(status).to_label
54
+ end
55
+ end
56
+ end
57
+ end
@@ -0,0 +1,24 @@
1
+ module ForemanOmaha
2
+ module Charts
3
+ class VersionDistribution
4
+ attr_accessor :hosts
5
+
6
+ def initialize(hosts = nil)
7
+ @hosts = hosts || Host.authorized(:view_hosts, Host).joins(:omaha_facet)
8
+ end
9
+
10
+ def query
11
+ hosts.group(:version).count
12
+ end
13
+
14
+ def to_chart_data
15
+ query.map do |version, count|
16
+ {
17
+ :label => version,
18
+ :data => count
19
+ }
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,33 @@
1
+ require 'open3'
2
+
3
+ module ForemanOmaha
4
+ class ContainerLinuxConfigTranspiler
5
+ class TranspilerNotFound < StandardError; end
6
+ class TranspileError < StandardError; end
7
+
8
+ attr_accessor :input, :output, :errors, :status
9
+
10
+ def initialize(input)
11
+ self.input = input
12
+ end
13
+
14
+ def run!
15
+ check_transpiler
16
+ transpile
17
+ raise TranspileError, "Could not transpile container linux config to ignition: #{errors}" unless status.success?
18
+ output
19
+ end
20
+
21
+ def transpile
22
+ self.output, self.errors, self.status = Open3.capture3(cmd, :stdin_data => input)
23
+ end
24
+
25
+ def check_transpiler
26
+ raise TranspilerNotFound, 'The ct binary was not found in your PATH.' if cmd.blank?
27
+ end
28
+
29
+ def cmd
30
+ @cmd ||= Foreman::Util.which('ct')
31
+ end
32
+ end
33
+ end
@@ -3,9 +3,9 @@ module ForemanOmaha
3
3
  def operatingsystem
4
4
  args = { :name => facts['platform'], :major => facts['osmajor'], :minor => facts['osminor'] }
5
5
  description = "#{facts['platform']} #{facts['version']}"
6
- Operatingsystem.where(args).first ||
7
- Operatingsystem.create!(args.merge(:description => description,
8
- :release_name => facts['track']))
6
+ Coreos.where(args).first ||
7
+ create_coreos_version(args.merge(:description => description,
8
+ :release_name => facts['track']))
9
9
  end
10
10
 
11
11
  def architecture
@@ -28,5 +28,21 @@ module ForemanOmaha
28
28
  def support_interfaces_parsing?
29
29
  false
30
30
  end
31
+
32
+ private
33
+
34
+ def create_coreos_version(attrs)
35
+ previous_version = previous_coreos_version
36
+ return Coreos.create!(attrs) unless previous_coreos_version
37
+ os = previous_version.deep_clone(
38
+ :include => [:ptables, :media, :os_default_templates, :architectures]
39
+ )
40
+ os.update_attributes(attrs)
41
+ os
42
+ end
43
+
44
+ def previous_coreos_version
45
+ Coreos.all.sort_by { |os| Gem::Version.new(os.release) }.last
46
+ end
31
47
  end
32
48
  end
@@ -0,0 +1,30 @@
1
+ module ForemanOmaha
2
+ class GroupVersionBreakdown
3
+ attr_accessor :omaha_group
4
+
5
+ def initialize(opts = {})
6
+ self.omaha_group = opts.fetch(:omaha_group)
7
+ end
8
+
9
+ def version_breakdown
10
+ facets.group(:version).count.sort_by { |version, _| Gem::Version.new(version) }.reverse.map do |version, count|
11
+ {
12
+ :version => version,
13
+ :count => count,
14
+ :percentage => percentage(count)
15
+ }
16
+ end
17
+ end
18
+
19
+ def facets
20
+ ForemanOmaha::OmahaFacet.where(:omaha_group => omaha_group)
21
+ end
22
+
23
+ private
24
+
25
+ def percentage(count)
26
+ return 0 if count.zero? || facets.count.zero?
27
+ (count.to_f * 100 / facets.count).round(2)
28
+ end
29
+ end
30
+ end
@@ -10,19 +10,68 @@ module ForemanOmaha
10
10
 
11
11
  private
12
12
 
13
+ def host
14
+ @host ||= ForemanOmaha::OmahaFacet.find_by(:machineid => machineid).try(:host) if machineid.present?
15
+ @name ||= @host.try(:name)
16
+ @host || super
17
+ end
18
+
13
19
  def create_report_and_logs
14
20
  super
15
- @report.omaha_version = omaha_version
16
- @report.save
17
- @report
21
+ return report unless report.persisted?
22
+ report.omaha_version = omaha_version
23
+ report.save
24
+ update_omaha_facet!
25
+ report
26
+ end
27
+
28
+ def omaha_facet
29
+ host.omaha_facet || host.build_omaha_facet
30
+ end
31
+
32
+ def update_omaha_facet!
33
+ return unless omaha_facet.last_report.nil? || omaha_facet.last_report.utc < time
34
+ omaha_facet.update(
35
+ :last_report => time,
36
+ :status => report_status,
37
+ :machineid => machineid,
38
+ :oem => oem,
39
+ :version => omaha_version,
40
+ :omaha_group => omaha_group
41
+ )
18
42
  end
19
43
 
20
44
  def report_status
21
45
  raw['status']
22
46
  end
23
47
 
48
+ def machineid
49
+ raw['machineid']
50
+ end
51
+
52
+ def oem
53
+ raw['oem']
54
+ end
55
+
24
56
  def omaha_version
25
57
  raw['omaha_version'] || 'unknown'
26
58
  end
59
+
60
+ def omaha_group
61
+ ForemanOmaha::OmahaGroup.find_by(:uuid => raw['omaha_group']) || find_omaha_group_by_version
62
+ end
63
+
64
+ # If the Report does not contain information
65
+ # about the Omaha Group, we try to find
66
+ # the correct group by looking at the defined
67
+ # operating systems
68
+ def find_omaha_group_by_version
69
+ version = Gem::Version.new(omaha_version)
70
+ major = version.segments.first
71
+ minor = version.segments.last(2).join('.')
72
+ os = Coreos.find_by(:major => major, :minor => minor)
73
+ return unless os
74
+ ForemanOmaha::OmahaGroup.find_by(:uuid => os.release_name)
75
+ end
27
76
  end
28
77
  end
@@ -0,0 +1,7 @@
1
+ module ForemanOmaha
2
+ module RendererMethods
3
+ def transpile_container_linux_config(input)
4
+ ForemanOmaha::ContainerLinuxConfigTranspiler.new(input).run!
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,53 @@
1
+ module ForemanOmaha
2
+ class StatusMapper
3
+ attr_accessor :status
4
+
5
+ def initialize(status)
6
+ @status = status
7
+ end
8
+
9
+ def to_label
10
+ case status.to_sym
11
+ when :complete
12
+ N_('Complete')
13
+ when :downloading
14
+ N_('Downloading')
15
+ when :downloaded
16
+ N_('Downloaded')
17
+ when :installed
18
+ N_('Installed')
19
+ when :instance_hold
20
+ N_('Instance Hold')
21
+ when :error
22
+ N_('Error')
23
+ else
24
+ N_('unknown')
25
+ end
26
+ end
27
+
28
+ # rubocop:disable Metrics/CyclomaticComplexity
29
+ def to_description(version = nil)
30
+ case status.to_sym
31
+ when :complete
32
+ if version.present?
33
+ _('The host has been updated successfully and is now running version %s.') % version
34
+ else
35
+ _('The host has been updated successfully.')
36
+ end
37
+ when :downloading
38
+ _('The host has just started downloading the update package.')
39
+ when :downloaded
40
+ _('The host has downloaded the update package and will install it now.')
41
+ when :installed
42
+ _('The host has installed the update package but is not using it yet.')
43
+ when :instance_hold
44
+ _('An update for this host is pending but it was put on hold because of the rollout policy.')
45
+ when :error
46
+ _('The host reported an error while updating.')
47
+ else
48
+ _('The status of this host is unknown.')
49
+ end
50
+ end
51
+ # rubocop:enable Metrics/CyclomaticComplexity
52
+ end
53
+ end