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.
- checksums.yaml +4 -4
- data/README.md +40 -1
- data/app/controllers/content/api/repositories_controller.rb +3 -5
- data/app/controllers/content/content_views_controller.rb +48 -0
- data/app/controllers/content/products_controller.rb +1 -1
- data/app/controllers/content/repositories_controller.rb +9 -6
- data/app/helpers/content/content_views_helper.rb +21 -0
- data/app/helpers/content/products_helper.rb +9 -0
- data/app/helpers/content/repositories_helper.rb +3 -49
- data/app/models/concerns/content/environment_extensions.rb +2 -2
- data/app/models/concerns/content/home_helper.rb +1 -0
- data/app/models/concerns/content/host_extensions.rb +17 -1
- data/app/models/concerns/content/hostgroup_extensions.rb +14 -0
- data/app/models/concerns/content/operatingsystem_extensions.rb +6 -5
- data/app/models/concerns/content/orchestration/pulp/clone.rb +77 -0
- data/app/models/concerns/content/orchestration/pulp/sync.rb +70 -0
- data/app/models/concerns/content/orchestration/pulp.rb +25 -0
- data/app/models/content/available_content_view.rb +12 -0
- data/app/models/content/content_view.rb +66 -0
- data/app/models/content/content_view_host.rb +9 -0
- data/app/models/content/content_view_repository_clone.rb +5 -0
- data/app/models/content/host_product.rb +0 -11
- data/app/models/content/hostgroup_product.rb +0 -11
- data/app/models/content/operatingsystem_repository.rb +0 -11
- data/app/models/content/product.rb +6 -5
- data/app/models/content/repository/operating_system.rb +14 -0
- data/app/models/content/repository/product.rb +21 -0
- data/app/models/content/repository.rb +28 -39
- data/app/models/content/repository_clone.rb +29 -0
- data/app/models/content/validators/content_validator.rb +0 -12
- data/app/models/content/validators/description_format.rb +0 -12
- data/app/models/content/validators/no_trailing_space.rb +0 -12
- data/app/models/setting/content.rb +0 -18
- data/app/overrides/{add_host_conent_tab.rb → add_host_content_tab.rb} +2 -2
- data/app/overrides/{add_hostgroup_conent_tab.rb → add_hostgroup_content_tab.rb} +1 -1
- data/app/services/content/content_view_factory.rb +41 -0
- data/app/services/content/{pulp_configuration.rb → pulp/configuration.rb} +1 -1
- data/app/services/content/pulp/event_handler.rb +61 -0
- data/app/services/content/pulp/repository.rb +200 -0
- data/app/services/content/pulp/repository_clone.rb +24 -0
- data/app/services/content/pulp/repository_sync_history.rb +35 -0
- data/app/services/content/pulp/repository_sync_status.rb +30 -0
- data/app/views/content/content_views/_form.html.erb +49 -0
- data/app/views/content/content_views/_form_tab.html.erb +3 -0
- data/app/views/content/content_views/_host_tab_pane.html.erb +5 -0
- data/app/views/content/content_views/_step1.html.erb +18 -0
- data/app/views/content/content_views/_step2.html.erb +16 -0
- data/app/views/content/content_views/edit.html.erb +5 -0
- data/app/views/content/content_views/index.html.erb +27 -0
- data/app/views/content/content_views/new.html.erb +11 -0
- data/app/views/content/products/_form.html.erb +2 -13
- data/app/views/content/products/_form_tab.html.erb +3 -3
- data/app/views/content/products/_hostgroup_tab_pane.html.erb +2 -2
- data/app/views/content/products/index.html.erb +6 -1
- data/app/views/content/repositories/_os_form.html.erb +22 -0
- data/app/views/content/repositories/{_form.html.erb → _product_form.html.erb} +4 -6
- data/app/views/content/repositories/edit.html.erb +5 -2
- data/app/views/content/repositories/index.html.erb +12 -9
- data/app/views/content/repositories/new.html.erb +5 -2
- data/app/views/content/repositories/show.html.erb +9 -16
- data/config/environment.rb +0 -0
- data/config/routes.rb +6 -0
- data/db/migrate/20130702140034_create_content_repositories.rb +6 -2
- data/db/migrate/20130722084911_create_content_operatingsystem_repositories.rb +1 -1
- data/db/migrate/20130807121629_create_content_content_views.rb +15 -0
- data/db/migrate/20130807123220_create_content_available_content_views.rb +11 -0
- data/db/migrate/20130812154754_create_content_content_view_hosts.rb +9 -0
- data/db/migrate/20130813110455_create_content_repository_clones.rb +17 -0
- data/db/migrate/20130825145431_create_content_content_view_repository_clones.rb +12 -0
- data/lib/content/engine.rb +2 -0
- data/lib/content/version.rb +1 -1
- data/test/fixtures/content/repository_clones.yml +21 -0
- data/test/unit/content/repository_clone_test.rb +7 -0
- metadata +44 -17
- data/app/models/concerns/content/custom_repository_paths.rb +0 -29
- data/app/models/content/environment_product.rb +0 -19
- data/app/models/content/orchestration/pulp.rb +0 -93
- data/app/models/content/product_operatingsystem.rb +0 -19
- data/app/models/content/remote/pulp/repository.rb +0 -48
- data/app/overrides/add_os_conent_tab.rb +0 -9
- data/app/services/content/pulp_event_handler.rb +0 -25
- data/app/views/content/products/_host_tab_pane.html.erb +0 -5
- data/app/views/content/products/_operatingsystem_tab_pane.html.erb +0 -5
- data/db/migrate/20130717032320_create_content_environments_products.rb +0 -9
- 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 :
|
|
7
|
-
has_many :
|
|
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,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
|
|
7
|
-
include
|
|
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
|
-
|
|
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 :
|
|
22
|
-
|
|
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 => :
|
|
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
|
|
55
|
-
|
|
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
|
-
"#{
|
|
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/
|
|
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/
|
|
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
|
|
@@ -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
|