foreman_content 0.2 → 0.3

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 (85) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +40 -1
  3. data/app/controllers/content/api/repositories_controller.rb +3 -5
  4. data/app/controllers/content/content_views_controller.rb +48 -0
  5. data/app/controllers/content/products_controller.rb +1 -1
  6. data/app/controllers/content/repositories_controller.rb +9 -6
  7. data/app/helpers/content/content_views_helper.rb +21 -0
  8. data/app/helpers/content/products_helper.rb +9 -0
  9. data/app/helpers/content/repositories_helper.rb +3 -49
  10. data/app/models/concerns/content/environment_extensions.rb +2 -2
  11. data/app/models/concerns/content/home_helper.rb +1 -0
  12. data/app/models/concerns/content/host_extensions.rb +17 -1
  13. data/app/models/concerns/content/hostgroup_extensions.rb +14 -0
  14. data/app/models/concerns/content/operatingsystem_extensions.rb +6 -5
  15. data/app/models/concerns/content/orchestration/pulp/clone.rb +77 -0
  16. data/app/models/concerns/content/orchestration/pulp/sync.rb +70 -0
  17. data/app/models/concerns/content/orchestration/pulp.rb +25 -0
  18. data/app/models/content/available_content_view.rb +12 -0
  19. data/app/models/content/content_view.rb +66 -0
  20. data/app/models/content/content_view_host.rb +9 -0
  21. data/app/models/content/content_view_repository_clone.rb +5 -0
  22. data/app/models/content/host_product.rb +0 -11
  23. data/app/models/content/hostgroup_product.rb +0 -11
  24. data/app/models/content/operatingsystem_repository.rb +0 -11
  25. data/app/models/content/product.rb +6 -5
  26. data/app/models/content/repository/operating_system.rb +14 -0
  27. data/app/models/content/repository/product.rb +21 -0
  28. data/app/models/content/repository.rb +28 -39
  29. data/app/models/content/repository_clone.rb +29 -0
  30. data/app/models/content/validators/content_validator.rb +0 -12
  31. data/app/models/content/validators/description_format.rb +0 -12
  32. data/app/models/content/validators/no_trailing_space.rb +0 -12
  33. data/app/models/setting/content.rb +0 -18
  34. data/app/overrides/{add_host_conent_tab.rb → add_host_content_tab.rb} +2 -2
  35. data/app/overrides/{add_hostgroup_conent_tab.rb → add_hostgroup_content_tab.rb} +1 -1
  36. data/app/services/content/content_view_factory.rb +41 -0
  37. data/app/services/content/{pulp_configuration.rb → pulp/configuration.rb} +1 -1
  38. data/app/services/content/pulp/event_handler.rb +61 -0
  39. data/app/services/content/pulp/repository.rb +200 -0
  40. data/app/services/content/pulp/repository_clone.rb +24 -0
  41. data/app/services/content/pulp/repository_sync_history.rb +35 -0
  42. data/app/services/content/pulp/repository_sync_status.rb +30 -0
  43. data/app/views/content/content_views/_form.html.erb +49 -0
  44. data/app/views/content/content_views/_form_tab.html.erb +3 -0
  45. data/app/views/content/content_views/_host_tab_pane.html.erb +5 -0
  46. data/app/views/content/content_views/_step1.html.erb +18 -0
  47. data/app/views/content/content_views/_step2.html.erb +16 -0
  48. data/app/views/content/content_views/edit.html.erb +5 -0
  49. data/app/views/content/content_views/index.html.erb +27 -0
  50. data/app/views/content/content_views/new.html.erb +11 -0
  51. data/app/views/content/products/_form.html.erb +2 -13
  52. data/app/views/content/products/_form_tab.html.erb +3 -3
  53. data/app/views/content/products/_hostgroup_tab_pane.html.erb +2 -2
  54. data/app/views/content/products/index.html.erb +6 -1
  55. data/app/views/content/repositories/_os_form.html.erb +22 -0
  56. data/app/views/content/repositories/{_form.html.erb → _product_form.html.erb} +4 -6
  57. data/app/views/content/repositories/edit.html.erb +5 -2
  58. data/app/views/content/repositories/index.html.erb +12 -9
  59. data/app/views/content/repositories/new.html.erb +5 -2
  60. data/app/views/content/repositories/show.html.erb +9 -16
  61. data/config/environment.rb +0 -0
  62. data/config/routes.rb +6 -0
  63. data/db/migrate/20130702140034_create_content_repositories.rb +6 -2
  64. data/db/migrate/20130722084911_create_content_operatingsystem_repositories.rb +1 -1
  65. data/db/migrate/20130807121629_create_content_content_views.rb +15 -0
  66. data/db/migrate/20130807123220_create_content_available_content_views.rb +11 -0
  67. data/db/migrate/20130812154754_create_content_content_view_hosts.rb +9 -0
  68. data/db/migrate/20130813110455_create_content_repository_clones.rb +17 -0
  69. data/db/migrate/20130825145431_create_content_content_view_repository_clones.rb +12 -0
  70. data/lib/content/engine.rb +2 -0
  71. data/lib/content/version.rb +1 -1
  72. data/test/fixtures/content/repository_clones.yml +21 -0
  73. data/test/unit/content/repository_clone_test.rb +7 -0
  74. metadata +44 -17
  75. data/app/models/concerns/content/custom_repository_paths.rb +0 -29
  76. data/app/models/content/environment_product.rb +0 -19
  77. data/app/models/content/orchestration/pulp.rb +0 -93
  78. data/app/models/content/product_operatingsystem.rb +0 -19
  79. data/app/models/content/remote/pulp/repository.rb +0 -48
  80. data/app/overrides/add_os_conent_tab.rb +0 -9
  81. data/app/services/content/pulp_event_handler.rb +0 -25
  82. data/app/views/content/products/_host_tab_pane.html.erb +0 -5
  83. data/app/views/content/products/_operatingsystem_tab_pane.html.erb +0 -5
  84. data/db/migrate/20130717032320_create_content_environments_products.rb +0 -9
  85. data/db/migrate/20130729032320_create_content_product_operatingsystems.rb +0 -9
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 76fd79ca9fac589c6e62a1a0ec2ba6c9df2ac608
4
- data.tar.gz: 34734b08623ad025a96fa107974143e5678c80e2
3
+ metadata.gz: 81d2b11da956bb0d25160db53a69e130cd4d6d93
4
+ data.tar.gz: b7ea75653438011efd63b158822f68f6769f6965
5
5
  SHA512:
6
- metadata.gz: 1bb2945c7a124cc7ebd769ff32f2181f9f617f44efc283b5536b8e409feb738afe3defc05ae2a4d8de6aedbf778695ee5dd71707c6b00914b173f0206db1bb44
7
- data.tar.gz: 86d1ef1b4b71b460f5af210bac3523e6d61323ab7b3a41a34263abc1de637081c020866386e39c4cc15681bf46451654bc1627a8965325fab680931ba21cf96d
6
+ metadata.gz: 651ee332a371f5aab119b72c3d684372e028815fc91ed6fc407e39eda537a525771ec8b84e82b8ffd49ac8d3eb67d256b44d9070f8c80f5b8d1e3c988c8ee4a6
7
+ data.tar.gz: dce982b68ab1038d275a3ded98acca1763611805999aecff410a8f9312a6f4879802520ab99e44c8c565600791374cfc02583e2f55bb32fa42eab79adee01f3c
data/README.md CHANGED
@@ -68,7 +68,28 @@ of an Installation media.
68
68
  * Product - the product from above.
69
69
  * GPG key - not implemented
70
70
 
71
- Once created, the repo would automatically be synced and published.
71
+ Once created, the repo would automatically be synced but not yet visible for
72
+ end users, for that you would need to create a Content View.
73
+
74
+ ## Creating Content Views
75
+
76
+ Content Views, are a collection of immutibal repositories, these repositories
77
+ are cloned from the synced repository and allow you to have multiple
78
+ repositories definitions per Operation Systems, Custom yum repos, and
79
+ Hostgroups.
80
+
81
+ You would first need to create a content view per Product / Operation system.
82
+
83
+ ## Configuring Hostgroups (and hosts) to consume content views
84
+
85
+ In your hostgroup definiton, you can select the operation system and the custom
86
+ products you are interested in.
87
+
88
+ next under the content view, you can create a new hostgroup content view, and
89
+ select the releavnt content view you would like to consume within your hostgroup.
90
+
91
+ You could also define the puppet environment(s) in which the content view is
92
+ used.
72
93
 
73
94
  ## Consuming Repos within your Kickstart
74
95
 
@@ -111,3 +132,21 @@ pulp-admin event listener http create --event-type '*' --url https://foreman.exa
111
132
 
112
133
  * https://trello.com/b/NtzVcPkD/foreman-backlog
113
134
  filter engine spike
135
+
136
+ # License
137
+
138
+ foreman_content plugin
139
+ Copyright (c) 2013 Red Hat Inc.
140
+
141
+ This program is free software: you can redistribute it and/or modify
142
+ it under the terms of the GNU General Public License as published by
143
+ the Free Software Foundation, either version 3 of the License, or
144
+ (at your option) any later version.
145
+
146
+ This program is distributed in the hope that it will be useful,
147
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
148
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
149
+ GNU General Public License for more details.
150
+
151
+ You should have received a copy of the GNU General Public License
152
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
@@ -7,11 +7,9 @@ module Content
7
7
 
8
8
  # callback event from pulp upon tasks/events finished up
9
9
  def events
10
- if (repo_id = params['payload'] && params['payload']['repo_id'])
11
- repo = Content::Repository.where(:pulp_id => repo_id).first
12
- end
13
- render_error 'not_found', :status => :not_found and return false if repo.nil?
14
- PulpEventHandler.new(repo_id, params)
10
+ repo_id = params['payload']['repo_id'] if params['payload']
11
+ render_error 'not_found', :status => :not_found and return false if repo_id.blank?
12
+ Content::Pulp::EventHandler.new(repo_id, params)
15
13
  head :status => 202
16
14
  end
17
15
 
@@ -0,0 +1,48 @@
1
+ module Content
2
+ class ContentViewsController < ::ApplicationController
3
+ include Foreman::Controller::AutoCompleteSearch
4
+ before_filter :find_by_name, :only => %w{show edit update destroy}
5
+
6
+ def index
7
+ @content_views = ContentView.search_for(params[:search], :order => params[:order]).
8
+ paginate(:page => params[:page])
9
+ @counter = RepositoryClone.joins(:content_view_repository_clones).group(:content_view_id).count
10
+
11
+ end
12
+
13
+ def new
14
+ @hostgroup = Hostgroup.find_by_id(params[:hostgroup]) if params[:hostgroup]
15
+ @content_view = ContentViewFactory.create_product_content_view(params[:product]) if params[:product]
16
+ @content_view ||= ContentViewFactory.create_os_content_view(params[:operatingsystem]) if params[:operatingsystem]
17
+ @content_view ||= ContentViewFactory.create_composite_content_view(params[:content_content_view_factory]) if params[:content_content_view_factory]
18
+ end
19
+
20
+ def create
21
+ @content_view = ContentView.new(params[:content_content_view])
22
+ if @content_view.save
23
+ process_success
24
+ else
25
+ process_error
26
+ end
27
+ end
28
+
29
+ def edit
30
+ end
31
+
32
+ def update
33
+ if @content_view.update_attributes(params[:content_content_view])
34
+ process_success
35
+ else
36
+ process_error
37
+ end
38
+ end
39
+
40
+ def destroy
41
+ if @content_view.destroy
42
+ process_success
43
+ else
44
+ process_error
45
+ end
46
+ end
47
+ end
48
+ end
@@ -6,7 +6,7 @@ module Content
6
6
  def index
7
7
  @products = Product.search_for(params[:search], :order => params[:order]).
8
8
  paginate(:page => params[:page])
9
- @counter = Repository.group(:product_id).where(:product_id => @products.map(&:id)).count
9
+ @counter = Repository::Product.group(:product_id).where(:product_id => @products.map(&:id)).count
10
10
  end
11
11
 
12
12
  def new
@@ -5,11 +5,18 @@ module Content
5
5
 
6
6
  def index
7
7
  @repositories = Repository.search_for(params[:search], :order => params[:order]).
8
- paginate(:page => params[:page]).includes(:product, :operatingsystems)
8
+ paginate(:page => params[:page]).includes(:product, :operatingsystem)
9
9
  end
10
10
 
11
11
  def new
12
- @repository = Repository.new(:unprotected => true)
12
+ @repository = case params[:type]
13
+ when "operatingsystem"
14
+ Repository::OperatingSystem.new(:unprotected => true)
15
+ when "product"
16
+ Repository::Product.new(:product_id => params[:product_id])
17
+ else
18
+ not_found
19
+ end
13
20
  end
14
21
 
15
22
  def create
@@ -33,10 +40,6 @@ module Content
33
40
  end
34
41
 
35
42
  def show
36
- @details = @repository.retrieve_with_details
37
- @sync_history = @repository.sync_history
38
- rescue
39
- redirect_back_or_to(edit_repository_path)
40
43
  end
41
44
 
42
45
  def destroy
@@ -0,0 +1,21 @@
1
+ module Content
2
+ module ContentViewsHelper
3
+
4
+ def repositories(view)
5
+ if view.new_record?
6
+ view.source_repositories + view.repository_clones
7
+ else
8
+ view.repository_clones
9
+ end
10
+ end
11
+
12
+ def next_or_cancel path, args={}
13
+ args[:cancel_path] ||= send("#{controller_name}_path")
14
+ content_tag(:div, :class => "form-actions") do
15
+ link_to(_("Cancel"), args[:cancel_path], :class => "btn") + " " +
16
+ submit_tag( _("Next"), :class => "btn btn-primary")
17
+ end
18
+ end
19
+
20
+ end
21
+ end
@@ -0,0 +1,9 @@
1
+ module Content
2
+ module ProductsHelper
3
+
4
+ def visible? product_id
5
+ @counter[product_id].to_i == 0
6
+ end
7
+
8
+ end
9
+ end
@@ -1,55 +1,9 @@
1
1
  module Content
2
2
  module RepositoriesHelper
3
3
 
4
- def sync_status repo
5
- status = repo.sync_status
6
- status = if status && status.first
7
- status.first[:state]
8
- else
9
- details = repo.retrieve_with_details
10
- details[:importers][0][:last_sync] if details && details[:importers] && details[:importers][0]
11
- end
12
- "#{time_ago_in_words(status)} ago" rescue status
13
- rescue
14
- '-'
15
- end
16
-
17
- def last_publish details
18
- return '' unless details[:distributors] && details[:distributors].first && published = details[:distributors].first[:last_publish]
19
- "#{time_ago_in_words published} ago" rescue ''
20
- end
21
-
22
- def last_sync details
23
- return '' unless details[:importers] && details[:importers].first && synced = details[:importers].first[:last_sync]
24
- "#{time_ago_in_words synced} ago" rescue ''
25
- end
26
-
27
- def sync_history_times history
28
- return {} unless history && history.first && summary = history.first['summary']
29
- return {} unless summary[:comps]
30
- {
31
- :comps => summary[:comps][:time_total_sec],
32
- :errata => summary[:errata][:errata_time_total_sec],
33
- :packages => summary[:packages][:time_total_sec]
34
- }
35
- end
36
-
37
- def sync_history_metrics history
38
- return {} unless history && last = history.first
39
- {
40
- :updated => last[:updated_count],
41
- :removed => last[:removed_count],
42
- :added => last[:added_count]
43
- }
44
- end
45
-
46
- def sync_history_status history
47
- return {} unless history && last = history.first
48
- {
49
- 'result' => last[:result],
50
- 'message' => last[:error_message] || last['summary']['error'],
51
- 'completed' => ("#{time_ago_in_words(last[:completed])} ago" rescue '')
52
- }
4
+ def last_time(time)
5
+ return if time.blank?
6
+ time_ago_in_words(time) + ' ago'
53
7
  end
54
8
 
55
9
  end
@@ -2,8 +2,8 @@ module Content::EnvironmentExtensions
2
2
  extend ActiveSupport::Concern
3
3
 
4
4
  included do
5
- has_many :environment_products, :dependent => :destroy, :uniq => true, :class_name => 'Content::EnvironmentProduct'
6
- has_many :products, :through => :environment_products, :class_name => 'Content::Product'
5
+ has_many :available_content_views, :dependent => :destroy, :class_name => 'Content::AvailableContentView'
6
+ has_many :content_views, :through => :available_content_views, :class_name => 'Content::ContentView'
7
7
  end
8
8
 
9
9
  end
@@ -11,6 +11,7 @@ module Content::HomeHelper
11
11
  [
12
12
  [_('Products'), :"content/products"],
13
13
  [_('Repositories'), :"content/repositories"],
14
+ [_('Content Views'), :"content/content_views"],
14
15
  [_('Gpg keys'), :"content/gpg_keys"]
15
16
  ]
16
17
  choices.insert(3, [:divider], [:group, _("Content"), content_group])
@@ -5,6 +5,9 @@ module Content::HostExtensions
5
5
  has_many :host_products, :dependent => :destroy, :uniq => true, :foreign_key => :host_id, :class_name => 'Content::HostProduct'
6
6
  has_many :products, :through => :host_products, :class_name => 'Content::Product'
7
7
 
8
+ has_many :content_view_hosts, :dependent => :destroy, :uniq => true, :foreign_key => :host_id, :class_name => 'Content::ContentViewHost'
9
+ has_many :content_views, :through => :content_view_hosts, :class_name => 'Content::ContentView'
10
+
8
11
  scoped_search :in => :products, :on => :name, :complete_value => true, :rename => :product
9
12
 
10
13
  alias_method_chain :params, :repositories
@@ -30,8 +33,21 @@ module Content::HostExtensions
30
33
  (inherited_product_ids + product_ids).uniq
31
34
  end
32
35
 
36
+ def inherited_content_view_ids
37
+ return [] if hostgroup_id.nil? or environment_id.nil?
38
+
39
+ Content::ContentView.joins(:available_content_views).
40
+ where(:content_available_content_views => {:environment_id => environment_id}).
41
+ where(:originator_type => 'Hostgroup', :originator_id => hostgroup_id).pluck(:id)
42
+ end
43
+
44
+ def all_content_view_ids
45
+ (inherited_content_view_ids + content_view_ids).uniq
46
+ end
47
+
33
48
  def attached_repositories
34
- Content::Repository.attached_to_host(self)
49
+ return [] if all_content_view_ids.empty?
50
+ Content::RepositoryClone.for_content_views(all_content_view_ids)
35
51
  end
36
52
 
37
53
  private
@@ -4,15 +4,29 @@ module Content::HostgroupExtensions
4
4
  included do
5
5
  has_many :hostgroup_products, :dependent => :destroy, :uniq => true, :class_name => 'Content::HostgroupProduct'
6
6
  has_many :products, :through => :hostgroup_products, :class_name => 'Content::Product'
7
+ has_many :content_views, :as => :originator, :class_name => 'Content::ContentView'
8
+
9
+ scope :has_content_views, joins(:content_views)
7
10
 
8
11
  scoped_search :in => :products, :on => :name, :complete_value => true, :rename => :product
12
+ scoped_search :in => :content_views, :on => :name, :complete_value => true, :rename => :content_view
9
13
  end
10
14
 
11
15
  def inherited_product_ids
16
+ return [] if hostgroup.ancestor_ids.empty?
12
17
  Content::HostgroupProduct.where(:hostgroup_id => hostgroup.ancestor_ids).pluck(:product_id)
13
18
  end
14
19
 
15
20
  def all_product_ids
16
21
  (inherited_product_ids + product_ids).uniq
17
22
  end
23
+
24
+ def inherited_content_view_ids
25
+ return [] if hostgroup.ancestor_ids.empty?
26
+ Content::ContentView.where(:originator_id => hostgroup.ancestor_ids, :originator_type => 'Hostgroup').pluck(:id)
27
+ end
28
+
29
+ def all_content_views_ids
30
+ (inherited_content_view_ids + content_view_ids).uniq
31
+ end
18
32
  end
@@ -2,11 +2,12 @@ module Content::OperatingsystemExtensions
2
2
  extend ActiveSupport::Concern
3
3
 
4
4
  included do
5
- has_many :operatingsystem_repositories, :dependent => :destroy, :uniq => true, :class_name => 'Content::OperatingsystemRepository'
6
- has_many :repositories, :through => :operatingsystem_repositories, :class_name => 'Content::Repository'
7
- has_many :product_operatingsystems, :dependent => :destroy, :uniq => true, :class_name => 'Content::ProductOperatingsystem'
8
- has_many :products, :through => :product_operatingsystems, :class_name => 'Content::Product'
9
- has_many :default_repositories, :through => :products, :source => :repositories, :class_name => 'Content::Repository'
5
+ has_many :repositories, :class_name => 'Content::Repository'
6
+
7
+ has_many :available_content_views, :dependent => :destroy, :class_name => 'Content::AvailableContentView'
8
+ has_many :content_views, :as => :originator, :class_name => 'Content::ContentView'
9
+
10
+ scope :has_repos, joins(:repositories).uniq
10
11
  end
11
12
 
12
13
  end
@@ -0,0 +1,77 @@
1
+ module Content::Orchestration::Pulp::Clone
2
+ extend ActiveSupport::Concern
3
+ include Content::Orchestration::Pulp
4
+
5
+ included do
6
+ after_validation :repository_clone_save unless Rails.env.test?
7
+ before_destroy :repository_clone_destroy unless Rails.env.test?
8
+ end
9
+
10
+ def last_published
11
+ read_attribute(:last_published) || repo.last_publish
12
+ end
13
+
14
+ private
15
+
16
+ def repository_clone_save
17
+ return unless (pulp? and errors.empty? and new_record?)
18
+ queue_pulp_create
19
+ end
20
+
21
+ def queue_pulp_create
22
+ logger.debug "Scheduling new Pulp Repository"
23
+ queue.create(:name => _("Create Pulp Repository for %s") % self, :priority => 10,
24
+ :action => [self, :set_pulp_repo])
25
+ queue.create(:name => _("Copy Pulp Repository %s") % self, :priority => 20,
26
+ :action => [self, :set_copy_pulp_repo])
27
+ queue.create(:name => _("Create Event Notifier") % self, :priority => 30,
28
+ :action => [self, :set_create_event_notifier])
29
+ queue.create(:name => _("Publish Pulp Repository %s") % self, :priority => 40,
30
+ :action => [self, :set_publish_pulp_repo])
31
+ end
32
+
33
+ def repository_clone_destroy
34
+ return unless pulp? and errors.empty?
35
+ logger.debug _("Scheduling removal of Pulp Repository %s") % name
36
+ queue.create(:name => _("Delete Pulp repository for %s") % name, :priority => 50,
37
+ :action => [self, :del_pulp_repo])
38
+ end
39
+
40
+ def set_pulp_repo
41
+ repo.create_with_distributor
42
+ end
43
+
44
+ def set_copy_pulp_repo
45
+ repo.copy_from(repository.pulp_id)
46
+ end
47
+
48
+ def set_publish_pulp_repo
49
+ repo.publish
50
+ end
51
+
52
+ def set_create_event_notifier
53
+ repo.create_event_notifier
54
+ end
55
+
56
+ def del_create_event_notifier; end
57
+
58
+ def del_copy_pulp_repo; end
59
+
60
+ def del_pulp_repo
61
+ repo.delete
62
+ end
63
+
64
+ def repo_options
65
+ {
66
+ :pulp_id => pulp_repo_id,
67
+ :name => "#{to_label}_clone",
68
+ :relative_path => relative_path,
69
+ :content_type => content_type,
70
+ :protected => false,
71
+ }
72
+ end
73
+
74
+ def repo
75
+ @repo ||= Content::Pulp::RepositoryClone.new(repo_options)
76
+ end
77
+ end
@@ -0,0 +1,70 @@
1
+ module Content::Orchestration::Pulp::Sync
2
+ extend ActiveSupport::Concern
3
+ include Content::Orchestration::Pulp
4
+
5
+ included do
6
+ after_validation :queue_pulp
7
+ before_destroy :queue_pulp_destroy unless Rails.env.test?
8
+ end
9
+
10
+ def last_sync
11
+ read_attribute(:last_sync) || repo.last_sync
12
+ end
13
+
14
+ private
15
+
16
+ def queue_pulp
17
+ return unless pulp? and errors.empty?
18
+ new_record? ? queue_pulp_create : queue_pulp_update
19
+ end
20
+
21
+ def queue_pulp_create
22
+ logger.debug "Scheduling new Pulp Repository"
23
+ queue.create(:name => _("Create Pulp Repository for %s") % self, :priority => 10,
24
+ :action => [self, :set_pulp_repo])
25
+ queue.create(:name => _("Sync Pulp Repository %s") % self, :priority => 20,
26
+ :action => [self, :set_sync_pulp_repo])
27
+ end
28
+
29
+ def queue_pulp_update
30
+ # TODO: handle repo updates.
31
+ end
32
+
33
+ def queue_pulp_destroy
34
+ return unless pulp? and errors.empty?
35
+ logger.debug _("Scheduling removal of Pulp Repository %s") % name
36
+ queue.create(:name => _("Delete Pulp repository for %s") % name, :priority => 50,
37
+ :action => [self, :del_pulp_repo])
38
+ end
39
+
40
+ def set_pulp_repo
41
+ repo.create
42
+ end
43
+
44
+ def del_pulp_repo
45
+ repo.delete
46
+ end
47
+
48
+ def set_sync_pulp_repo
49
+ repo.sync
50
+ end
51
+
52
+ def del_sync_pulp_repo
53
+ repo.cancel_running_sync!
54
+ end
55
+
56
+ def repo_options
57
+ {
58
+ :pulp_id => pulp_repo_id,
59
+ :name => to_label,
60
+ :description => description,
61
+ :feed => feed,
62
+ :content_type => content_type,
63
+ :protected => unprotected,
64
+ }
65
+ end
66
+
67
+ def repo
68
+ @repo ||= Content::Pulp::Repository.new(repo_options)
69
+ end
70
+ end
@@ -0,0 +1,25 @@
1
+ module Content::Orchestration::Pulp
2
+ extend ActiveSupport::Concern
3
+ include ::Orchestration
4
+
5
+ included do
6
+ delegate :sync_status, :sync, :counters, :sync_history, :state, :to => :repo
7
+ end
8
+
9
+ def orchestration_errors?
10
+ errors.empty?
11
+ end
12
+
13
+ def pulp?
14
+ @use_pulp ||= Setting.use_pulp
15
+ end
16
+
17
+ def update_cache; nil; end
18
+ def progress_report_id
19
+ @progress_report_id ||= Foreman.uuid
20
+ end
21
+
22
+ def pulp_repo_id
23
+ self.pulp_id ||= Foreman.uuid.gsub("-", '')
24
+ end
25
+ end
@@ -0,0 +1,12 @@
1
+ module Content
2
+ class AvailableContentView < ActiveRecord::Base
3
+ belongs_to :environment
4
+ belongs_to :operatingsystem
5
+ belongs_to :content_view
6
+
7
+ validates_presence_of :content_view_id, :environment_id
8
+
9
+ #todo needs to validate that default can't be archived and vice-versa
10
+
11
+ end
12
+ end
@@ -0,0 +1,66 @@
1
+ module Content
2
+ class ContentView < ActiveRecord::Base
3
+ has_ancestry :orphan_strategy => :rootify
4
+
5
+ belongs_to :originator, :polymorphic => true
6
+ has_many :available_content_views, :dependent => :destroy
7
+ has_many :environments, :through => :available_content_views
8
+ delegate :operatingsystems, :to => :available_content_views, :allow_nil => true
9
+
10
+ has_many :content_view_hosts, :dependent => :destroy, :uniq => true, :foreign_key => :content_view_id, :class_name => 'Content::ContentViewHost'
11
+ has_many :hosts, :through => :content_view_hosts
12
+
13
+ has_many :content_view_repository_clones, :dependent => :destroy
14
+ has_many :repository_clones, :through => :content_view_repository_clones, :class_name => 'Content::RepositoryClone'
15
+ has_many :repositories, :through => :repository_clones
16
+
17
+ scope :hostgroups, where(:originator_type => 'Hostgroup')
18
+ scope :products, where(:originator_type => 'Content::Product')
19
+ scope :operatingsystem, where(:originator_type => 'Operatingsystem')
20
+
21
+ after_save :clone_repos
22
+ before_destroy :clean_unused_clone_repos
23
+
24
+ validates_presence_of :name
25
+
26
+ # special relationships needed for search with polymorphic associations
27
+ belongs_to :search_hostgroups, :class_name => 'Hostgroup', :foreign_key => :originator_id,
28
+ :conditions => '"content_content_views"."originator_type" = "Hostgroup"'
29
+ belongs_to :search_operatingsystems, :class_name => 'Operatingsystem', :foreign_key => :originator_id,
30
+ :conditions => '"content_content_views"."originator_type" = "Operatingsystem"'
31
+ belongs_to :search_products, :class_name => 'Content::Product', :foreign_key => :originator_id,
32
+ :conditions => '"content_content_views"."originator_type" = "Content::Product"'
33
+ scoped_search :on => [:name, :created_at], :complete_value => :true
34
+ scoped_search :in => :search_products, :on => :name, :rename => :product,
35
+ :complete_value => :true, :only_explicit => true
36
+ scoped_search :in => :search_operatingsystems, :on => :name, :rename => :operatingsystem,
37
+ :complete_value => :true, :only_explicit => true
38
+ scoped_search :in => :search_hostgroups, :on => :label, :complete_value => true,
39
+ :rename => :hostgroup, :only_explicit => true
40
+
41
+ attr_accessor :source_repositories
42
+
43
+ def to_label
44
+ name || "#{originator.to_label} - #{DateTime.now.strftime("%m/%d/%Y")}".parameterize
45
+ end
46
+
47
+ def clone_repos
48
+ return unless @source_repositories
49
+ Repository.where(:id => @source_repositories).each do |repository|
50
+ repository.publish self
51
+ end
52
+ end
53
+
54
+ private
55
+
56
+ def clean_unused_clone_repos
57
+ current_repos = Content::ContentViewRepositoryClone.where(:content_view_id => id).pluck(:repository_clone_id)
58
+ used_repos = Content::ContentViewRepositoryClone.
59
+ where(:repository_clone_id => current_repos).
60
+ where(['content_view_id IS NOT ?', id]).pluck(:repository_clone_id)
61
+
62
+ repos_to_delete = current_repos - used_repos
63
+ Content::RepositoryClone.destroy(repos_to_delete) if repos_to_delete.any?
64
+ end
65
+ end
66
+ end
@@ -0,0 +1,9 @@
1
+ module Content
2
+ class ContentViewHost < ActiveRecord::Base
3
+ belongs_to :host
4
+ belongs_to :content_view
5
+
6
+ validates_presence_of :content_view_id, :host_id
7
+ validates_uniqueness_of :content_view_id, :scope => :host_id
8
+ end
9
+ end
@@ -0,0 +1,5 @@
1
+ class Content::ContentViewRepositoryClone < ActiveRecord::Base
2
+ belongs_to :content_view
3
+ belongs_to :repository_clone
4
+ validate :content_view_id, :repository_clone_id, :presence => true
5
+ end
@@ -1,14 +1,3 @@
1
- #
2
- # Copyright 2013 Red Hat, Inc.
3
- #
4
- # This software is licensed to you under the GNU General Public
5
- # License as published by the Free Software Foundation; either version
6
- # 2 of the License (GPLv2) or (at your option) any later version.
7
- # There is NO WARRANTY for this software, express or implied,
8
- # including the implied warranties of MERCHANTABILITY,
9
- # NON-INFRINGEMENT, or FITNESS FOR A PARTICULAR PURPOSE. You should
10
- # have received a copy of GPLv2 along with this software; if not, see
11
- # http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
12
1
  module Content
13
2
  class HostProduct < ActiveRecord::Base
14
3
  belongs_to :product
@@ -1,14 +1,3 @@
1
- #
2
- # Copyright 2013 Red Hat, Inc.
3
- #
4
- # This software is licensed to you under the GNU General Public
5
- # License as published by the Free Software Foundation; either version
6
- # 2 of the License (GPLv2) or (at your option) any later version.
7
- # There is NO WARRANTY for this software, express or implied,
8
- # including the implied warranties of MERCHANTABILITY,
9
- # NON-INFRINGEMENT, or FITNESS FOR A PARTICULAR PURPOSE. You should
10
- # have received a copy of GPLv2 along with this software; if not, see
11
- # http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
12
1
  module Content
13
2
  class HostgroupProduct < ActiveRecord::Base
14
3
  belongs_to :product