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
@@ -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 OperatingsystemRepository < ActiveRecord::Base
14
3
  belongs_to :operatingsystem
@@ -3,11 +3,8 @@ module Content
3
3
  include ::Taxonomix
4
4
 
5
5
  has_many :repositories
6
- has_many :environment_products, :dependent => :destroy, :uniq=>true
7
- has_many :environments, :through => :environment_products
8
-
9
- has_many :product_operatingsystems, :dependent => :destroy, :uniq=>true
10
- has_many :operatingsystems, :through => :product_operatingsystems
6
+ has_many :repository_clones, :through => :repositories
7
+ has_many :content_views, :as => :originator
11
8
 
12
9
  has_many :hostgroup_products, :dependent => :destroy, :uniq=>true
13
10
  has_many :hostgroups, :through => :hostgroup_products
@@ -15,6 +12,10 @@ module Content
15
12
  has_many :host_products, :dependent => :destroy, :uniq=>true
16
13
  has_many :hosts, :through => :host_products
17
14
 
15
+ before_destroy EnsureNotUsedBy.new(:hostgroups, :hosts, :repositories)
16
+
17
+ scope :has_repos, joins(:repositories).uniq
18
+
18
19
  validates_with Validators::DescriptionFormat, :attributes => :description
19
20
  validates :name, :presence => true
20
21
  validates_with Validators::NameFormat, :attributes => :name
@@ -0,0 +1,14 @@
1
+ module Content
2
+ class Repository::OperatingSystem < Repository
3
+
4
+ validates_presence_of :operatingsystem
5
+
6
+ def self.model_name
7
+ Repository.model_name
8
+ end
9
+
10
+ def entity_name
11
+ operatingsystem.to_label
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,21 @@
1
+ module Content
2
+ class Repository::Product < Repository
3
+
4
+ has_many :operatingsystem_repositories, :foreign_key => :repository_id, :dependent => :destroy, :uniq => true
5
+ has_many :operatingsystems, :through => :operatingsystem_repositories
6
+
7
+ validates_presence_of :product
8
+
9
+ def self.model_name
10
+ Repository.model_name
11
+ end
12
+
13
+ def content_types
14
+ TYPES - [KICKSTART_TYPE]
15
+ end
16
+
17
+ def entity_name
18
+ product.name
19
+ end
20
+ end
21
+ end
@@ -1,29 +1,25 @@
1
- require 'content/orchestration/pulp'
2
- # TODO: split into a custom and red hat repositories:
3
- # as handling of repo creation/updates is different between them
4
1
  module Content
5
2
  class Repository < ActiveRecord::Base
6
- include CustomRepositoryPaths
7
- include Content::Remote::Pulp::Repository
8
- include ::Orchestration
9
- include Content::Orchestration::Pulp
3
+ include Content::Orchestration::Pulp::Sync
4
+ include Foreman::STI
10
5
 
11
6
  YUM_TYPE = 'yum'
12
7
  KICKSTART_TYPE = 'kickstart'
13
8
  FILE_TYPE = 'iso'
14
9
  TYPES = [YUM_TYPE, KICKSTART_TYPE, FILE_TYPE]
15
10
 
16
- REPO_PREFIX = '/pulp/repos/'
17
-
18
- belongs_to :product
11
+ belongs_to :product, :class_name => 'Content::Product'
12
+ belongs_to :operatingsystem
19
13
  belongs_to :gpg_key
20
14
  belongs_to :architecture
21
- has_many :operatingsystem_repositories, :dependent => :destroy, :uniq => true
22
- has_many :operatingsystems, :through => :operatingsystem_repositories
15
+ has_many :repository_clones
16
+
17
+ before_destroy EnsureNotUsedBy.new(:repository_clones)
18
+
19
+ validates_presence_of :type # can't create this object, only child
23
20
 
24
- validates :product, :presence => true
25
21
  validates :name, :presence => true
26
- validates_uniqueness_of :name, :scope => :product_id
22
+ validates_uniqueness_of :name, :scope => [:operatingsystem_id, :product_id]
27
23
  validates_inclusion_of :content_type,
28
24
  :in => TYPES,
29
25
  :allow_blank => false,
@@ -31,40 +27,33 @@ module Content
31
27
 
32
28
  scoped_search :on => [:name, :enabled], :complete_value => :true
33
29
  scoped_search :in => :architecture, :on => :name, :rename => :architecture, :complete_value => :true
34
- scoped_search :in => :operatingsystems, :on => :name, :rename => :os, :complete_value => :true
30
+ scoped_search :in => :operatingsystem, :on => :name, :rename => :os, :complete_value => :true
35
31
  scoped_search :in => :product, :on => :name, :rename => :product, :complete_value => :true
36
32
 
37
- # Repositories filtered by operating system architecture and environment.
38
- # architecture_id is nil for noarch repositories.
39
- scope :available_for_host, lambda { |host|
40
- joins(:operatingsystems => :operatingsystem_repositories , :product => :environments).
41
- where(:architecture_id => [nil, host.architecture_id],
42
- :content_operatingsystem_repositories => { :operatingsystem_id => host.operatingsystem_id},
43
- :content_environment_products => { :environment_id => host.environment_id }).
44
- uniq}
45
-
46
- #
47
- scope :attached_to_host, lambda { |host|
48
- where(:product_id => host.all_product_ids).available_for_host(host)
49
- }
50
-
51
33
  scope :kickstart, where(:content_type => KICKSTART_TYPE)
52
34
  scope :yum, where(:content_type => YUM_TYPE)
53
35
 
54
- def update_cache
55
- nil
56
- end
57
-
58
- def full_path
59
- pulp_url = URI.parse(Setting.pulp_url)
60
- scheme = (unprotected ? 'http' : 'https')
61
- port = (pulp_url.port == 443 || pulp_url.port == 80 ? "" : ":#{pulp_url.port}")
62
- "#{scheme}://#{pulp_url.host}#{port}#{REPO_PREFIX}#{relative_path}"
36
+ def content_types
37
+ TYPES
63
38
  end
64
39
 
65
40
  # The label is used as a repository label in a yum repo file.
66
41
  def to_label
67
- "#{product.name}-#{name}".parameterize
42
+ "#{entity_name}-#{name}".parameterize
43
+ end
44
+
45
+ #inhariters are expected to override this method
46
+ def entity_name
47
+ ''
68
48
  end
49
+
50
+ def publish content_view
51
+ repository_clones.create!(
52
+ :content_views => [content_view],
53
+ :name => self.name + "_clone",
54
+ :relative_path => "content_views/#{to_label}/#{Foreman.uuid}"
55
+ )
56
+ end
57
+
69
58
  end
70
59
  end
@@ -0,0 +1,29 @@
1
+ module Content
2
+ class RepositoryClone < ActiveRecord::Base
3
+ include Content::Orchestration::Pulp::Clone
4
+
5
+ REPO_PREFIX = '/pulp/repos/'
6
+
7
+ belongs_to :repository
8
+ has_many :content_view_repository_clones, :dependent => :destroy
9
+ has_many :content_views, :through => :content_view_repository_clones
10
+ before_destroy EnsureNotUsedBy.new(:content_views)
11
+
12
+ attr_accessible :description, :last_published, :name, :pulp_id, :relative_path, :status, :content_views
13
+ validate :relative_path, :repository_id, :presence => true
14
+
15
+ delegate :content_type, :architecture, :unprotected, :gpg_key, :product, :to => :repository
16
+
17
+ scope :for_content_views, lambda { |ids|
18
+ joins(:content_view_repository_clones).
19
+ where('content_content_view_repository_clones' => {:content_view_id => ids})
20
+ }
21
+
22
+ def full_path
23
+ pulp_url = URI.parse(Setting.pulp_url)
24
+ scheme = (unprotected ? 'http' : 'https')
25
+ port = (pulp_url.port == 443 || pulp_url.port == 80 ? "" : ":#{pulp_url.port}")
26
+ "#{scheme}://#{pulp_url.host}#{port}#{REPO_PREFIX}#{relative_path}"
27
+ end
28
+ end
29
+ end
@@ -1,15 +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
-
13
1
  module Content
14
2
  module Validators
15
3
  class ContentValidator < ActiveModel::EachValidator
@@ -1,15 +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
-
13
1
  module Content
14
2
  module Validators
15
3
  class DescriptionFormat < ActiveModel::EachValidator
@@ -1,15 +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
-
13
1
  module Content
14
2
  module Validators
15
3
  class NoTrailingSpace < ActiveModel::EachValidator
@@ -21,22 +21,4 @@ class Setting::Content< ::Setting
21
21
 
22
22
  end
23
23
 
24
- def self.ensure_sync_notification
25
- include Rails.application.routes.url_helpers
26
-
27
- resource = Runcible::Resources::EventNotifier
28
- url = events_repositories_url(:only_path => false, :host => Setting[:foreman_url])
29
- type = '*' #resource::EventTypes::REPO_SYNC_COMPLETE
30
- notifs = resource.list
31
-
32
- #delete any similar tasks with the wrong url (in case it changed)
33
- notifs.select { |n| n['event_types'] == [type] && n['notifier_config']['url'] != url }.each do |e|
34
- resource.delete(e['id'])
35
- end
36
-
37
- #only create a notifier if one doesn't exist with the correct url
38
- exists = notifs.select { |n| n['event_types'] == [type] && n['notifier_config']['url'] == url }
39
- resource.create(resource::NotifierTypes::REST_API, { :url => url }, [type]) if exists.empty?
40
- end
41
-
42
24
  end
@@ -1,9 +1,9 @@
1
1
  Deface::Override.new(:virtual_path => "hosts/_form",
2
2
  :name => "add_content_tab",
3
3
  :insert_after => 'ul.nav > li a#params-tab',
4
- :partial => 'content/products/form_tab')
4
+ :partial => 'content/content_views/form_tab')
5
5
 
6
6
  Deface::Override.new(:virtual_path => "hosts/_form",
7
7
  :name => "add_content_tab_pane",
8
8
  :insert_after => 'div.tab-pane#params',
9
- :partial => 'content/products/host_tab_pane')
9
+ :partial => 'content/content_views/host_tab_pane')
@@ -6,4 +6,4 @@ Deface::Override.new(:virtual_path => "hostgroups/_form",
6
6
  Deface::Override.new(:virtual_path => "hostgroups/_form",
7
7
  :name => "add_content_tab_pane",
8
8
  :insert_after => 'div.tab-pane#params',
9
- :partial => 'content/products/hostgroup_tab_pane')
9
+ :partial => 'content/products/hostgroup_tab_pane')
@@ -0,0 +1,41 @@
1
+ module Content
2
+ class ContentViewFactory
3
+ include ActiveModel::Conversion
4
+ extend ActiveModel::Naming
5
+
6
+ attr_accessor :type, :originator_id, :parent_cv, :product_cv, :os_cv
7
+ # create a content view of a single product
8
+ def self.create_product_content_view(product_id)
9
+ product = Product.find_by_id(product_id)
10
+ ContentView.new(:source_repositories => product.repositories, :originator => product)
11
+ end
12
+
13
+ # create a content view of an operating system
14
+ def self.create_os_content_view(operatingsystem_id)
15
+ os = Operatingsystem.find_by_id(operatingsystem_id)
16
+ ContentView.new(:source_repositories => os.repositories, :originator => os)
17
+ end
18
+
19
+ # create a composite content view of a hostgroup (the hostgroup may have a list of products) and a parent
20
+ # content view. The parent content view is one of the hostgroup parent content views.
21
+ # A hostgroup may have number of content views representing different versions of that hostgroup content.
22
+ def self.create_composite_content_view(options = {})
23
+ factory = new(options)
24
+ hostgroup = Hostgroup.find_by_id(factory.originator_id)
25
+ clone_ids = Content::RepositoryClone.for_content_views([factory.product_cv, factory.os_cv]).
26
+ pluck(:id)
27
+ ContentView.new(:source_repositories=> [], :originator => hostgroup,
28
+ :repository_clone_ids => clone_ids, :parent_id => factory.parent_cv)
29
+ end
30
+
31
+ def initialize(attributes = {})
32
+ attributes.each do |name, value|
33
+ instance_variable_set("@#{name}", value) if respond_to?("#{name}".to_sym)
34
+ end
35
+ end
36
+
37
+ def persisted?
38
+ false
39
+ end
40
+ end
41
+ end
@@ -1,7 +1,7 @@
1
1
  require 'runcible'
2
2
  require 'uri'
3
3
 
4
- class Content::PulpConfiguration
4
+ class Content::Pulp::Configuration
5
5
  def initialize options = {}
6
6
  Runcible::Base.config = runcible_config.merge(options)
7
7
  end
@@ -0,0 +1,61 @@
1
+ class Content::Pulp::EventHandler
2
+ attr_reader :type, :status
3
+ delegate :name, :to => :repo
4
+ delegate :logger, :to => :Rails
5
+
6
+ def initialize(pulp_id, params)
7
+ @pulp_id = pulp_id
8
+ @params = params
9
+ @type, @status = parse_type
10
+ return nil unless repo
11
+ log
12
+ update_state
13
+ end
14
+
15
+ private
16
+ attr_reader :pulp_id, :params
17
+
18
+ def repo
19
+ @repo ||= case type
20
+ when 'sync'
21
+ Content::Repository.where(:pulp_id => pulp_id).first
22
+ when 'promote'
23
+ Content::RepositoryClone.where(:pulp_id => pulp_id).first
24
+ end
25
+ end
26
+
27
+ def log
28
+ logger.info "Repository #{name} #{type} #{status}"
29
+ end
30
+
31
+ def parse_type
32
+ # converts repo.sync.start to ['sync','start']
33
+ params['event_type'].gsub(/^repo\./, '').split('.')
34
+ end
35
+
36
+ def update_state
37
+ #nothing to do if we didnt finish a task
38
+ return unless status == 'finish'
39
+
40
+ case type
41
+ when 'sync'
42
+ repo.update_attribute(:last_sync, finished_at) if success?
43
+ when 'promote'
44
+ repo.update_attribute(:last_published, finished_at) if success?
45
+
46
+ end
47
+ end
48
+
49
+ def success?
50
+ result == 'success'
51
+ end
52
+
53
+ def result
54
+ params['payload']['result']
55
+ end
56
+
57
+ def finished_at
58
+ Time.parse(params['payload']['completed'])
59
+ end
60
+
61
+ end
@@ -0,0 +1,200 @@
1
+ class Content::Pulp::Repository
2
+ PULP_SELECT_FIELDS = ['name', 'epoch', 'version', 'release', 'arch', 'checksumtype', 'checksum']
3
+
4
+ attr_reader :pulp_id, :content_type, :relative_path, :name, :description
5
+ delegate :logger, :to => :Rails
6
+
7
+ class << self
8
+
9
+ def create(options = {})
10
+ new(options).create
11
+ end
12
+
13
+ def delete(pulp_id)
14
+ new(:pulp_id => pulp_id).delete
15
+ end
16
+
17
+ def sync(pulp_id)
18
+ new(:pulp_id => pulp_id).sync
19
+ end
20
+
21
+ end
22
+
23
+ def initialize options = {}
24
+ options.each do |k, v|
25
+ instance_variable_set("@#{k}", v) if respond_to?("#{k}".to_sym)
26
+ end
27
+
28
+ raise('must define pulp id') unless pulp_id
29
+
30
+ # initiate pulp connection
31
+ Content::Pulp::Configuration.new
32
+ end
33
+
34
+ def create_with_distributor
35
+ create_repository [pulp_distributor]
36
+ end
37
+
38
+ def create
39
+ create_repository
40
+ end
41
+
42
+ def display_name
43
+ details['display_name']
44
+ end
45
+
46
+ def checksum_type
47
+ details['checksum_type']
48
+ end
49
+
50
+ def description
51
+ @description || details['description']
52
+ end
53
+
54
+ def counters
55
+ details['content_unit_counts']
56
+ end
57
+
58
+ def feed
59
+ @feed || importer['config']['feed_url']
60
+ end
61
+
62
+ def last_sync
63
+ importer['last_sync']
64
+ end
65
+
66
+ def last_publish
67
+ distributor['last_publish']
68
+ end
69
+
70
+ def auto_publish
71
+ @auto_publish.nil? ? distributor['auto_publish'] : @auto_publish
72
+ end
73
+
74
+ def protected
75
+ @protected.nil? ? distributor['protected'] : @protected
76
+ end
77
+
78
+ def reload!
79
+ @details = nil
80
+ end
81
+
82
+ def sync_status
83
+ status = Runcible::Extensions::Repository.sync_status(pulp_id)
84
+ Content::Pulp::RepositorySyncStatus.new(status.first) unless status.empty?
85
+ end
86
+
87
+ def sync_history
88
+ history = Runcible::Extensions::Repository.sync_history(pulp_id)
89
+ (history || []).map do |sync|
90
+ Content::Pulp::RepositorySyncHistory.new(sync)
91
+ end
92
+ end
93
+
94
+ def delete
95
+ Runcible::Resources::Repository.delete(pulp_id)
96
+ rescue RestClient::ResourceNotFound => e
97
+ true #not found is not a failure for delete
98
+ end
99
+
100
+ def sync
101
+ Runcible::Resources::Repository.sync(pulp_id)
102
+ end
103
+
104
+ def publish
105
+ Runcible::Extensions::Repository.publish_all(pulp_id)
106
+ end
107
+
108
+ def cancel_running_sync!
109
+ return if sync_status.blank? || sync_status.not_synced?
110
+ Runcible::Resources::Task.cancel(sync_status.task_id)
111
+ rescue RestClient::ResourceNotFound
112
+ # task already done, nothing to do here
113
+ end
114
+
115
+ # once we keep a list pulp servers, this should be done in create/destroy
116
+ def create_event_notifier
117
+ url = Rails.application.routes.url_helpers.
118
+ events_api_repositories_url(:only_path => false, :host => Setting[:foreman_url])
119
+ type = '*'
120
+ resource = Runcible::Resources::EventNotifier
121
+ notifs = resource.list
122
+
123
+ #only create a notifier if one doesn't exist with the correct url
124
+ exists = notifs.select { |n| n['event_types'] == [type] && n['notifier_config']['url'] == url }
125
+ resource.create(resource::NotifierTypes::REST_API, { :url => url }, [type]) if exists.empty?
126
+ true
127
+ end
128
+
129
+ private
130
+
131
+ def create_repository pulp_distributors = []
132
+ defaults
133
+ Runcible::Extensions::Repository.create_with_importer_and_distributors(pulp_id,
134
+ pulp_importer,
135
+ pulp_distributors,
136
+ { :display_name => relative_path || name,
137
+ :description => description })
138
+ rescue RestClient::BadRequest => e
139
+ raise parse_error(e)
140
+ end
141
+
142
+ def pulp_importer
143
+ options = {
144
+ :feed_url => feed
145
+ }
146
+
147
+ case content_type
148
+ when Content::Repository::YUM_TYPE, Content::Repository::KICKSTART_TYPE
149
+ Runcible::Extensions::YumImporter.new(options)
150
+ when Content::Repository::FILE_TYPE
151
+ Runcible::Extensions::IsoImporter.new(options)
152
+ else
153
+ raise "Unexpected repo type %s" % content_type
154
+ end
155
+ end
156
+
157
+ def pulp_distributor
158
+ case content_type
159
+ when Content::Repository::YUM_TYPE, Content::Repository::KICKSTART_TYPE
160
+ Runcible::Extensions::YumDistributor.new(relative_path, protected, true,
161
+ { :protected => protected, :id => pulp_id,
162
+ :auto_publish => auto_publish })
163
+ when Content::Repository::FILE_TYPE
164
+ dist = Runcible::Extensions::IsoDistributor.new(true, true)
165
+ dist.auto_publish = true
166
+ dist
167
+ else
168
+ raise "Unexpected repo type %s" % content_type
169
+ end
170
+ end
171
+
172
+ def defaults
173
+ @protected = true if @protected.nil?
174
+ end
175
+
176
+ def importer
177
+ details['importers'].empty? ? {} : details['importers'].first
178
+ end
179
+
180
+ def distributor
181
+ details['distributors'].empty? ? {} : details['distributors'].first
182
+ end
183
+
184
+ def details
185
+ @details ||= Runcible::Resources::Repository.retrieve(pulp_id, { :details => true })
186
+ rescue RestClient::ResourceNotFound => e
187
+ logger.warn "Repo not found: #{parse_error(e)}"
188
+ {:state => 'not found'}
189
+ end
190
+
191
+ def state
192
+ return 'published' if last_publish.present?
193
+ return sync_status.state if sync_status.present?
194
+ return details[:state] if details[:state]
195
+ end
196
+
197
+ def parse_error exception
198
+ JSON.parse(exception.response)['error_message']
199
+ end
200
+ end
@@ -0,0 +1,24 @@
1
+ class Content::Pulp::RepositoryClone < Content::Pulp::Repository
2
+ PULP_SELECT_FIELDS = %w(name epoch version release arch checksumtype checksum)
3
+
4
+ def copy_from(src_repo_id)
5
+ # In order to reduce the memory usage of pulp during the copy process,
6
+ # include the fields that will uniquely identify the rpm. If no fields
7
+ # are listed, pulp will retrieve every field it knows about for the rpm
8
+ # (e.g. changelog, filelist...etc).
9
+ Runcible::Extensions::Rpm.copy(src_repo_id, pulp_id, { :fields => PULP_SELECT_FIELDS })
10
+ Runcible::Extensions::Distribution.copy(src_repo_id, pulp_id)
11
+
12
+ # Since the rpms will be copied above, during the copy of errata and package groups,
13
+ # include the copy_children flag to request that pulp skip copying them again.
14
+ Runcible::Extensions::Errata.copy(src_repo_id, pulp_id, { :copy_children => false })
15
+ Runcible::Extensions::PackageGroup.copy(src_repo_id, pulp_id, { :copy_children => false })
16
+ Runcible::Extensions::YumRepoMetadataFile.copy(src_repo_id, pulp_id)
17
+ end
18
+
19
+ def defaults; end
20
+
21
+ def pulp_importer
22
+ Runcible::Extensions::YumImporter.new
23
+ end
24
+ end
@@ -0,0 +1,35 @@
1
+ class Content::Pulp::RepositorySyncHistory
2
+ attr_reader :exception, :removed_count, :started, :completed, :summary,
3
+ :error_message, :added_count, :updated_count, :details, :result
4
+
5
+ def initialize(attrs)
6
+ attrs.each do |k, v|
7
+ instance_variable_set("@#{k}", v) if respond_to?("#{k}".to_sym)
8
+ end
9
+ end
10
+
11
+ def times
12
+ {
13
+ :comps => summary[:time_total_sec],
14
+ :errata => summary[:errata_time_total_sec],
15
+ :packages => summary[:packages][:time_total_sec]
16
+ }
17
+ end
18
+
19
+ def metrics
20
+ {
21
+ :updated => updated_count,
22
+ :removed => removed_count,
23
+ :added => added_count,
24
+ }
25
+ end
26
+
27
+ def status
28
+ {
29
+ :result => result,
30
+ :message => error_message || summary['error'],
31
+ :completed => completed
32
+ }
33
+ end
34
+
35
+ end