foreman_omaha 0.0.1

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 (46) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE +619 -0
  3. data/README.md +51 -0
  4. data/Rakefile +47 -0
  5. data/app/assets/images/Omaha.png +0 -0
  6. data/app/controllers/api/v2/omaha_reports_controller.rb +86 -0
  7. data/app/controllers/omaha_reports_controller.rb +57 -0
  8. data/app/helpers/concerns/foreman_omaha/hosts_helper_extensions.rb +15 -0
  9. data/app/helpers/omaha_reports_helper.rb +28 -0
  10. data/app/models/concerns/foreman_omaha/host_extensions.rb +11 -0
  11. data/app/models/foreman_omaha/fact_name.rb +7 -0
  12. data/app/models/foreman_omaha/omaha_report.rb +54 -0
  13. data/app/models/host_status/omaha_status.rb +44 -0
  14. data/app/services/foreman_omaha/fact_importer.rb +11 -0
  15. data/app/services/foreman_omaha/fact_parser.rb +32 -0
  16. data/app/services/foreman_omaha/omaha_report_importer.rb +28 -0
  17. data/app/views/api/v2/omaha_reports/base.json.rabl +3 -0
  18. data/app/views/api/v2/omaha_reports/create.json.rabl +3 -0
  19. data/app/views/api/v2/omaha_reports/index.json.rabl +3 -0
  20. data/app/views/api/v2/omaha_reports/main.json.rabl +5 -0
  21. data/app/views/api/v2/omaha_reports/show.json.rabl +3 -0
  22. data/app/views/api/v2/omaha_reports/update.json.rabl +3 -0
  23. data/app/views/omaha_reports/_details.html.erb +28 -0
  24. data/app/views/omaha_reports/_list.html.erb +34 -0
  25. data/app/views/omaha_reports/index.html.erb +2 -0
  26. data/app/views/omaha_reports/show.html.erb +21 -0
  27. data/app/views/omaha_reports/welcome.html.erb +14 -0
  28. data/config/routes.rb +29 -0
  29. data/db/migrate/20160812083100_add_omaha_fields_to_reports.foreman_omaha.rb +5 -0
  30. data/db/seeds.d/60_omaha_proxy_feature.rb +2 -0
  31. data/lib/foreman_omaha/engine.rb +78 -0
  32. data/lib/foreman_omaha/version.rb +3 -0
  33. data/lib/foreman_omaha.rb +4 -0
  34. data/lib/tasks/foreman_omaha_tasks.rake +45 -0
  35. data/locale/Makefile +60 -0
  36. data/locale/en/foreman_omaha.po +19 -0
  37. data/locale/foreman_omaha.pot +19 -0
  38. data/locale/gemspec.rb +2 -0
  39. data/test/factories/feature.rb +7 -0
  40. data/test/factories/foreman_omaha_factories.rb +9 -0
  41. data/test/factories/smart_proxy.rb +7 -0
  42. data/test/functional/api/v2/omaha_reports_controller_test.rb +122 -0
  43. data/test/functional/omaha_reports_controller_test.rb +54 -0
  44. data/test/test_plugin_helper.rb +22 -0
  45. data/test/unit/omaha_report_test.rb +86 -0
  46. metadata +125 -0
data/Rakefile ADDED
@@ -0,0 +1,47 @@
1
+ #!/usr/bin/env rake
2
+ begin
3
+ require 'bundler/setup'
4
+ rescue LoadError
5
+ puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
6
+ end
7
+ begin
8
+ require 'rdoc/task'
9
+ rescue LoadError
10
+ require 'rdoc/rdoc'
11
+ require 'rake/rdoctask'
12
+ RDoc::Task = Rake::RDocTask
13
+ end
14
+
15
+ RDoc::Task.new(:rdoc) do |rdoc|
16
+ rdoc.rdoc_dir = 'rdoc'
17
+ rdoc.title = 'ForemanOmaha'
18
+ rdoc.options << '--line-numbers'
19
+ rdoc.rdoc_files.include('README.rdoc')
20
+ rdoc.rdoc_files.include('lib/**/*.rb')
21
+ end
22
+
23
+ APP_RAKEFILE = File.expand_path('../test/dummy/Rakefile', __FILE__)
24
+
25
+ Bundler::GemHelper.install_tasks
26
+
27
+ require 'rake/testtask'
28
+
29
+ Rake::TestTask.new(:test) do |t|
30
+ t.libs << 'lib'
31
+ t.libs << 'test'
32
+ t.pattern = 'test/**/*_test.rb'
33
+ t.verbose = false
34
+ end
35
+
36
+ task default: :test
37
+
38
+ begin
39
+ require 'rubocop/rake_task'
40
+ RuboCop::RakeTask.new
41
+ rescue => _
42
+ puts 'Rubocop not loaded.'
43
+ end
44
+
45
+ task :default do
46
+ Rake::Task['rubocop'].execute
47
+ end
Binary file
@@ -0,0 +1,86 @@
1
+ module Api
2
+ module V2
3
+ class OmahaReportsController < V2::BaseController
4
+ include Api::Version2
5
+ include Foreman::Controller::SmartProxyAuth
6
+
7
+ before_action :find_resource, :only => [:show, :destroy]
8
+ before_action :setup_search_options, :only => [:index, :last]
9
+
10
+ add_smart_proxy_filters :create,
11
+ :features => proc { ::ForemanOmaha::OmahaReportImporter.authorized_smart_proxy_features }
12
+
13
+ def_param_group :omaha_report do
14
+ param :report, Hash, :required => true, :action_aware => true do
15
+ param :host, String, :required => true, :desc => N_('Hostname or certname')
16
+ param :status, String,
17
+ :required => true,
18
+ :desc => N_('Omaha status, can be one of %s') % ::ForemanOmaha::OmahaReport.statuses.keys.to_sentence
19
+ param :omaha_version, String, :required => true, :desc => N_('Omaha OS version')
20
+ end
21
+ end
22
+
23
+ api :GET, '/omaha_reports/', N_('List all omaha reports')
24
+ param_group :search_and_pagination, ::Api::V2::BaseController
25
+
26
+ def index
27
+ @omaha_reports = resource_scope_for_index.my_reports
28
+ @total = resource_scope_for_index.my_reports.count
29
+ end
30
+
31
+ api :GET, '/omaha_reports/:id/', N_('Show a omaha report')
32
+ param :id, :identifier, :required => true
33
+
34
+ def show
35
+ end
36
+
37
+ api :POST, '/omaha_reports', N_('Create a omaha report')
38
+ param_group :omaha_report, :as => :create
39
+
40
+ def create
41
+ @omaha_report = resource_class.import(params[:omaha_report], detected_proxy.try(:id))
42
+ process_response @omaha_report.errors.empty?
43
+ rescue ::Foreman::Exception => e
44
+ render_message(e.to_s, :status => :unprocessable_entity)
45
+ end
46
+
47
+ api :DELETE, '/omaha_reports/:id/', N_('Delete a omaha report')
48
+ param :id, String, :required => true
49
+
50
+ def destroy
51
+ process_response @omaha_report.destroy
52
+ end
53
+
54
+ api :GET, '/hosts/:host_id/omaha_reports/last', N_('Show the last report for a host')
55
+ param :id, :identifier, :required => true
56
+
57
+ def last
58
+ if params[:host_id].present?
59
+ conditions = { :host_id => resource_finder(Host.authorized(:view_hosts), params[:host_id]).try(:id) }
60
+ end
61
+ max_id = resource_scope.where(conditions).maximum(:id)
62
+ @omaha_report = resource_scope.find(max_id)
63
+ render :show
64
+ end
65
+
66
+ private
67
+
68
+ def resource_class
69
+ ::ForemanOmaha::OmahaReport
70
+ end
71
+
72
+ def resource_scope(options = {})
73
+ super(options.merge(:permission => :view_omaha_reports)).my_reports
74
+ end
75
+
76
+ def action_permission
77
+ case params[:action]
78
+ when 'last'
79
+ 'view'
80
+ else
81
+ super
82
+ end
83
+ end
84
+ end
85
+ end
86
+ end
@@ -0,0 +1,57 @@
1
+ class OmahaReportsController < ApplicationController
2
+ include Foreman::Controller::AutoCompleteSearch
3
+
4
+ before_action :setup_search_options, :only => :index
5
+
6
+ def model_of_controller
7
+ ::ForemanOmaha::OmahaReport
8
+ end
9
+
10
+ def index
11
+ @omaha_reports = resource_base_search_and_page(:host)
12
+ end
13
+
14
+ def show
15
+ # are we searching for the last report?
16
+ if params[:id] == 'last'
17
+ conditions = {
18
+ :host_id => resource_finder(Host.authorized(:view_hosts), params[:host_id]).try(:id)
19
+ } if params[:host_id].present?
20
+ params[:id] = resource_base.where(conditions).maximum(:id)
21
+ end
22
+
23
+ return not_found if params[:id].blank?
24
+
25
+ @omaha_report = resource_base.includes(:logs => [:message, :source]).find(params[:id])
26
+ @offset = @omaha_report.reported_at - @omaha_report.created_at
27
+ end
28
+
29
+ def destroy
30
+ @omaha_report = resource_base.find(params[:id])
31
+ if @omaha_report.destroy
32
+ process_success(
33
+ :success_msg => _('Successfully deleted report.'),
34
+ :success_redirect => omaha_reports_path
35
+ )
36
+ else
37
+ process_error
38
+ end
39
+ end
40
+
41
+ # TODO: Remove for Foreman 1.14+
42
+ def resource_base_with_search
43
+ resource_base.search_for(params[:search], :order => params[:order])
44
+ end
45
+
46
+ # TODO: Remove for Foreman 1.14+
47
+ def resource_base_search_and_page(tables = [])
48
+ base = tables.empty? ? resource_base_with_search : resource_base_with_search.eager_load(*tables)
49
+ base.paginate(:page => params[:page], :per_page => params[:per_page])
50
+ end
51
+
52
+ private
53
+
54
+ def resource_base
55
+ super.my_reports
56
+ end
57
+ end
@@ -0,0 +1,15 @@
1
+ module ForemanOmaha
2
+ module HostsHelperExtensions
3
+ extend ActiveSupport::Concern
4
+
5
+ included do
6
+ alias_method_chain :show_appropriate_host_buttons, :foreman_omaha
7
+ end
8
+
9
+ def show_appropriate_host_buttons_with_foreman_omaha(host)
10
+ buttons = show_appropriate_host_buttons_without_foreman_omaha(host)
11
+ buttons << (link_to_if_authorized(_('Omaha'), hash_for_host_omaha_reports_path(:host_id => host), :title => _('Browse host omaha reports'), :class => 'btn btn-default') if host.omaha_reports.any?)
12
+ buttons.compact
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,28 @@
1
+ module OmahaReportsHelper
2
+ def iconclass_for_omaha_status(status)
3
+ case status.to_sym
4
+ when :complete
5
+ 'pficon pficon-ok'
6
+ when :downloading
7
+ 'fa fa-download text-info'
8
+ when :downloaded
9
+ 'fa fa-download text-success'
10
+ when :installed
11
+ 'fa fa-sign-in text-success'
12
+ when :instance_hold
13
+ 'fa fa-pause-circle-o text-warning'
14
+ when :error
15
+ 'pficon pficon-error-circle-o'
16
+ else
17
+ 'th'
18
+ end
19
+ end
20
+
21
+ def operatingsystem_link(operatingsystem)
22
+ link_to_if_authorized(os_name(operatingsystem),
23
+ hash_for_edit_operatingsystem_path(
24
+ :id => operatingsystem
25
+ ).merge(:auth_object => operatingsystem,
26
+ :authorizer => authorizer))
27
+ end
28
+ end
@@ -0,0 +1,11 @@
1
+ module ForemanOmaha
2
+ module HostExtensions
3
+ extend ActiveSupport::Concern
4
+ included do
5
+ has_many :omaha_reports, :class_name => '::ForemanOmaha::OmahaReport',
6
+ :foreign_key => :host_id
7
+ has_one :last_omaha_report_object, -> { order("#{Report.table_name}.id DESC") },
8
+ :foreign_key => :host_id, :class_name => '::ForemanOmaha::OmahaReport'
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,7 @@
1
+ module ForemanOmaha
2
+ class FactName < ::FactName
3
+ def origin
4
+ 'Omaha'
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,54 @@
1
+ module ForemanOmaha
2
+ class OmahaReport < ::Report
3
+ enum :status => [:unknown, :complete, :downloading, :downloaded,
4
+ :installed, :instance_hold, :error]
5
+
6
+ scoped_search :on => :omaha_version, :rename => :version, :complete_value => true
7
+ scoped_search :on => :status, :complete_value => statuses
8
+
9
+ def self.import(report, proxy_id = nil)
10
+ OmahaReportImporter.import(report, proxy_id)
11
+ end
12
+
13
+ def self.report_status_column
14
+ 'status'
15
+ end
16
+
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
34
+ end
35
+
36
+ def operatingsystem
37
+ return unless omaha_version.present?
38
+ args = { :type => 'Coreos', :major => osmajor, :minor => osminor }
39
+ Operatingsystem.find_by(args)
40
+ end
41
+
42
+ def osmajor
43
+ omaha_version.gsub(/^(\d+)\.\d\.\d$/, '\1')
44
+ rescue
45
+ nil
46
+ end
47
+
48
+ def osminor
49
+ omaha_version.gsub(/^\d+\.(\d\.\d)$/, '\1')
50
+ rescue
51
+ nil
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,44 @@
1
+ module HostStatus
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
+ def self.status_name
14
+ N_('Omaha Status')
15
+ end
16
+
17
+ def to_status(_options = {})
18
+ return ::ForemanOmaha::OmahaReport.statuses[:unknown] unless relevant?
19
+ ::ForemanOmaha::OmahaReport.statuses[last_report.status]
20
+ end
21
+
22
+ def to_global(_options = {})
23
+ return ::ForemanOmaha::OmahaReport.statuses[:unknown] unless relevant?
24
+ case last_report.status.to_sym
25
+ when :complete, :downloaded, :downloading, :installed
26
+ HostStatus::Global::OK
27
+ when :instance_hold
28
+ HostStatus::Global::WARN
29
+ when :error
30
+ HostStatus::Global::ERROR
31
+ else
32
+ HostStatus::Global::OK
33
+ end
34
+ end
35
+
36
+ def to_label(_options = {})
37
+ last_report.to_label
38
+ end
39
+
40
+ def relevant?(_options = {})
41
+ host && last_report.present?
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,11 @@
1
+ module ForemanOmaha
2
+ class FactImporter < ::FactImporter
3
+ def self.authorized_smart_proxy_features
4
+ 'Omaha'
5
+ end
6
+
7
+ def fact_name_class
8
+ ForemanOmaha::FactName
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,32 @@
1
+ module ForemanOmaha
2
+ class FactParser < ::FactParser
3
+ def operatingsystem
4
+ args = { :name => facts['platform'], :major => facts['osmajor'], :minor => facts['osminor'] }
5
+ description = "#{facts['platform']} #{facts['version']}"
6
+ Operatingsystem.where(args).first ||
7
+ Operatingsystem.create!(args.merge(:description => description,
8
+ :release_name => facts['track']))
9
+ end
10
+
11
+ def architecture
12
+ name = nil
13
+ name = 'x86_64' if facts['board'] == 'amd64-usr'
14
+ name = 'arm64' if facts['board'] == 'arm64-usr'
15
+ Architecture.where(:name => name).first_or_create unless name.nil?
16
+ end
17
+
18
+ def environment; end
19
+
20
+ def model; end
21
+
22
+ def domain; end
23
+
24
+ def ipmi_interface; end
25
+
26
+ def certname; end
27
+
28
+ def support_interfaces_parsing?
29
+ false
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,28 @@
1
+ module ForemanOmaha
2
+ class OmahaReportImporter < ::ReportImporter
3
+ def report_name_class
4
+ OmahaReport
5
+ end
6
+
7
+ def self.authorized_smart_proxy_features
8
+ @authorized_smart_proxy_features ||= super + ['Omaha']
9
+ end
10
+
11
+ private
12
+
13
+ def create_report_and_logs
14
+ super
15
+ @report.omaha_version = omaha_version
16
+ @report.save
17
+ @report
18
+ end
19
+
20
+ def report_status
21
+ raw['status']
22
+ end
23
+
24
+ def omaha_version
25
+ raw['omaha_version'] || 'unknown'
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,3 @@
1
+ object @omaha_report
2
+
3
+ attributes :id, :host_id, :host_name, :reported_at, :status
@@ -0,0 +1,3 @@
1
+ object @omaha_report
2
+
3
+ extends "api/v2/omaha_reports/show"
@@ -0,0 +1,3 @@
1
+ collection @omaha_reports
2
+
3
+ extends "api/v2/omaha_reports/main"
@@ -0,0 +1,5 @@
1
+ object @omaha_report
2
+
3
+ extends "api/v2/omaha_reports/base"
4
+
5
+ attributes :omaha_version, :created_at, :updated_at
@@ -0,0 +1,3 @@
1
+ object @omaha_report
2
+
3
+ extends "api/v2/omaha_reports/main"
@@ -0,0 +1,3 @@
1
+ object @omaha_report
2
+
3
+ extends "api/v2/omaha_reports/show"
@@ -0,0 +1,28 @@
1
+ <div class="container-fluid container-cards-pf">
2
+ <div class="row row-cards-pf">
3
+ <div class="col-xs-6 col-sm-4 col-md-4">
4
+ <div class="card-pf card-pf-accented card-pf-aggregate-status">
5
+ <h2 class="card-pf-title">
6
+ <span class="fa fa-cube"></span>Version
7
+ </h2>
8
+ <div class="card-pf-body">
9
+ <p class="card-pf-aggregate-status-notifications">
10
+ <span class="card-pf-aggregate-status-notification"><%= version %></span>
11
+ </p>
12
+ </div>
13
+ </div>
14
+ </div>
15
+ <div class="col-xs-6 col-sm-4 col-md-4">
16
+ <div class="card-pf card-pf-accented card-pf-aggregate-status">
17
+ <h2 class="card-pf-title">
18
+ <span class="fa fa-download"></span>Status
19
+ </h2>
20
+ <div class="card-pf-body">
21
+ <p class="card-pf-aggregate-status-notifications">
22
+ <span class="card-pf-aggregate-status-notification"><span class="<%= iconclass_for_omaha_status(status) %>"></span> <%= label %></span>
23
+ </p>
24
+ </div>
25
+ </div>
26
+ </div>
27
+ </div>
28
+ </div>
@@ -0,0 +1,34 @@
1
+ <table class="<%= table_css_classes('table-fixed') %>">
2
+ <thead>
3
+ <tr>
4
+ <% unless params[:host_id] %>
5
+ <th><%= sort :host, :as => _("Host") %></th>
6
+ <% end %>
7
+ <th class="col-md-2"><%= sort :reported, :as => _("Last report") %></th>
8
+ <th class="col-md-2"><%= sort :version, :as => _("Version") %></th>
9
+ <th class="col-md-2"><%= _("Status") %></th>
10
+ <th class="col-md-2"><%= _('Actions') %></th>
11
+ </tr>
12
+ </thead>
13
+ <tbody>
14
+ <% for report in @omaha_reports %>
15
+ <tr>
16
+ <% if params[:host_id].nil? %>
17
+ <% if report.host.nil? %>
18
+ <td></td>
19
+ <% else %>
20
+ <td class="ellipsis"><%= link_to report.host, host_omaha_reports_path(report.host) %></td>
21
+ <% end %>
22
+ <% end %>
23
+ <td><%= display_link_if_authorized(_("%s ago") % time_ago_in_words(report.reported_at), hash_for_omaha_report_path(:id => report.id)) %></td>
24
+ <td><%= report.operatingsystem.present? ? operatingsystem_link(report.operatingsystem) : _('unknown') %></td>
25
+ <td><span class="<%= iconclass_for_omaha_status(report.status) %>"></span> <%= report.to_label %></td>
26
+ <td>
27
+ <%= action_buttons(display_delete_if_authorized hash_for_omaha_report_path(:id => report).merge(:auth_object => report, :authorizer => authorizer),
28
+ :confirm => _("Delete report for %s?") % report.host.try(:name)) %>
29
+ </td>
30
+ </tr>
31
+ <% end %>
32
+ </tbody>
33
+ </table>
34
+ <%= will_paginate_with_info @omaha_reports %>
@@ -0,0 +1,2 @@
1
+ <% title _("Omaha Reports") %>
2
+ <%= render :partial => 'list' %>
@@ -0,0 +1,21 @@
1
+ <%= javascript 'reports' %>
2
+ <% title "#{@omaha_report.host}"%>
3
+
4
+ <p class='ra'> <%= _("Reported at %s ") % @omaha_report.reported_at %> </p>
5
+ <% if @offset > 10 %>
6
+ <div class="alert alert-block alert-danger alert-dismissable">
7
+ <%= alert_close %>
8
+ <h3><%= _("Host times seems to be adrift!") %></h3>
9
+ <%= (_("Host reported time is <em>%s</em>") % @omaha_report.reported_at).html_safe %> <br/>
10
+ <%= (_("Foreman report creation time is <em>%s</em>") % @omaha_report.created_at).html_safe %> <br/>
11
+ <%= (_("Which is an offset of <b>%s</b>") % distance_of_time_in_words(@omaha_report.reported_at, @omaha_report.created_at, :include_seconds => true)).html_safe %>
12
+ </div>
13
+ <% end %>
14
+
15
+ <%= render 'details', :label => @omaha_report.to_label, :status => @omaha_report.status, :version => @omaha_report.omaha_version %>
16
+
17
+ <%= title_actions link_to(_('Back'), :back, :class => 'btn btn-default'),
18
+ display_delete_if_authorized(hash_for_omaha_report_path(:id => @omaha_report), :class=> "btn btn-danger"),
19
+ link_to(_("Host details"), @omaha_report.host, :class => 'btn btn-default'),
20
+ link_to(_("Other reports for this host"), host_omaha_reports_path(@omaha_report.host), :class => 'btn btn-default')
21
+ %>
@@ -0,0 +1,14 @@
1
+ <div class="blank-slate-pf">
2
+ <div class="blank-slate-pf-icon">
3
+ <%= icon_text("book", "", :kind => "fa") %>
4
+ </div>
5
+ <h1><%= _('Omaha Reports') %></h1>
6
+ <p>
7
+ <%= _("You don't seem to have any omaha reports.") %></br>
8
+ <%= _('If you wish to configure CoreOS to forward reports to Foreman, please follow') %>
9
+ <%= link_to _("the documentation"), 'https://github.com/timogoebel/foreman_omaha', :rel => "external" %>.
10
+ </p>
11
+ <div class="blank-slate-pf-main-action">
12
+ <%= link_to _('Documentation'), 'https://github.com/timogoebel/foreman_omaha', :rel => 'external', :class => 'btn btn-primary btn-lg' %>
13
+ </div>
14
+ </div>
data/config/routes.rb ADDED
@@ -0,0 +1,29 @@
1
+ Rails.application.routes.draw do
2
+ namespace :api, :defaults => { :format => 'json' } do
3
+ scope '(:apiv)', :module => :v2,
4
+ :defaults => { :apiv => 'v2' },
5
+ :apiv => /v1|v2/,
6
+ :constraints => ApiConstraints.new(:version => 2) do
7
+ constraints(:id => /[^\/]+/) do
8
+ resources :omaha_reports, :only => [:index, :show, :destroy] do
9
+ get :last, :on => :collection
10
+ end
11
+ end
12
+ resources :omaha_reports, :only => [:create]
13
+ end
14
+ end
15
+
16
+ resources :omaha_reports, :only => [:index, :show, :destroy] do
17
+ collection do
18
+ get 'auto_complete_search'
19
+ end
20
+ end
21
+
22
+ constraints(:id => /[^\/]+/) do
23
+ resources :hosts do
24
+ constraints(:host_id => /[^\/]+/) do
25
+ resources :omaha_reports, :only => [:index, :show]
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,5 @@
1
+ class AddOmahaFieldsToReports < ActiveRecord::Migration
2
+ def change
3
+ add_column :reports, :omaha_version, :string
4
+ end
5
+ end
@@ -0,0 +1,2 @@
1
+ f = Feature.where(:name => 'Omaha').first_or_create
2
+ raise "Unable to create proxy feature: #{format_errors f}" if f.nil? || f.errors.any?