From: Jan Provaznik <jprovazn(a)redhat.com>
First shot in supporting Pulp as a package repository. This version enables
groups/packages listing (parsing yum repos directly is still supported).
If you want to run Pulp locally, I suggest to use RPMs, version 0.0.50 (GIT
version doesn't work well now - repository sync fails, but this could be fixed
in a short time).
By default, Pulp repos are exposed as standard yum repos in /var/www/pub dir so
these repos can be used by image builder too.
---
src/app/util/image_descriptor_xml.rb | 9 +-
src/app/util/repository_manager.rb | 157 ++++----------------
.../util/repository_manager/abstract_repository.rb | 9 +
.../util/repository_manager/comps_repository.rb | 116 +++++++++++++++
src/app/util/repository_manager/pulp_repository.rb | 62 ++++++++
src/app/views/templates/software.haml | 2 +-
.../image_descriptor_package_repositories.yml | 21 ++-
7 files changed, 232 insertions(+), 144 deletions(-)
create mode 100644 src/app/util/repository_manager/abstract_repository.rb
create mode 100644 src/app/util/repository_manager/comps_repository.rb
create mode 100644 src/app/util/repository_manager/pulp_repository.rb
diff --git a/src/app/util/image_descriptor_xml.rb b/src/app/util/image_descriptor_xml.rb
index d9b8348..2100109 100644
--- a/src/app/util/image_descriptor_xml.rb
+++ b/src/app/util/image_descriptor_xml.rb
@@ -216,9 +216,9 @@ class ImageDescriptorXML
rnode = get_or_create_node('repo', repo_node)
rnode.content = repconf['baseurl']
- repository_manager.repositories.each do |rname, repo|
+ repository_manager.repositories.each do |repo|
rnode = get_or_create_node('repo', repo_node)
- rnode.content = repo['baseurl']
+ rnode.content = repo.baseurl
end
end
@@ -246,9 +246,6 @@ class ImageDescriptorXML
end
def repository_manager
- unless @repository_manager
- @repository_manager = RepositoryManager.new
- end
- return @repository_manager
+ @repository_manager ||= RepositoryManager.new
end
end
diff --git a/src/app/util/repository_manager.rb b/src/app/util/repository_manager.rb
index 05cc5da..9d4baa3 100644
--- a/src/app/util/repository_manager.rb
+++ b/src/app/util/repository_manager.rb
@@ -17,145 +17,24 @@
# MA 02110-1301, USA. A copy of the GNU General Public License is
# also available at
http://www.gnu.org/copyleft/gpl.html.
-require 'open-uri'
require 'yaml'
+require 'util/repository_manager/comps_repository'
+require 'util/repository_manager/pulp_repository'
class RepositoryManager
- class CompsRepository
- def initialize(baseurl, id)
- @id = id
- @baseurl = baseurl
- end
-
- def get_packages
- packages = []
- get_packages_nodes.each do |node|
- name = node.at_xpath('./xmlns:name/child::text()')
- group = node.at_xpath('./xmlns:format/rpm:group/child::text()')
- description = node.at_xpath('./xmlns:description/child::text()')
- next unless name and group
- packages << {
- :repository_id => @id,
- :name => name.text,
- :group => group.text,
- :description => description ? description.text : '',
- }
- end
- return packages
- end
-
- def get_groups
- groups = {}
- get_groups_nodes.each do |g|
- pkgs = get_group_packages(g)
- next if pkgs.empty?
- name = g.at_xpath('name').text
- groups[name] = {
- :name => name,
- :description => (t = g.at_xpath('description')) ? t.text :
'',
- :packages => pkgs,
- }
- end
- return groups
- end
-
- def download_xml(type)
- begin
- url = get_url(type)
- rescue
- return ''
- end
-
- xml_data = open(url)
- if url =~ /\.gz$/
- return Zlib::GzipReader.new(xml_data).read
- else
- return xml_data.read
- end
- end
-
- private
-
- def get_xml(type)
- # FIXME: I'm not sure config is right dir for automatic storing of
- # xml files, but this should be temporary solution until Image Repo is
- # done
- xml_dir = "#{RAILS_ROOT}/config/image_descriptor_xmls"
- xml_file = "#{xml_dir}/#{(a)id}.#{type}.xml"
- begin
- return File.open(xml_file) { |f| f.read }
- rescue
- xml = download_xml(type)
- Dir.mkdir(xml_dir) unless File.directory?(xml_dir)
- File.open(xml_file, 'w') { |f| f.write xml }
- return xml
- end
- end
-
- def get_group_packages(group_node)
- pkgs = {}
- group_node.xpath('packagelist/packagereq').each do |p|
- pkgs[p.text] = p.attr('type')
- end
- return pkgs
- end
-
- def get_packages_nodes
- unless @packages_nodes
- data = get_xml('primary')
- xml = Nokogiri::XML(data)
- @packages_nodes = xml.xpath('/xmlns:metadata/xmlns:package')
- end
- return @packages_nodes
- end
-
- def get_groups_nodes
- unless @groups_nodes
- data = get_xml('group')
- xml = Nokogiri::XML(data)
- @groups_nodes = xml.xpath('/comps/group')
- end
- return @groups_nodes
- end
-
- def get_url(type)
- if type == 'repomd'
- return File.join(@baseurl, 'repodata', 'repomd.xml')
- else
- location =
repomd.xpath("/xmlns:repomd/xmlns:data[@type=\"#{type}\"]/xmlns:location").first
- raise "location for #{type} data not found" unless location
- return File.join(@baseurl, location['href'])
- end
- end
-
- def repomd
- unless @repomd
- @repomd = Nokogiri::XML(get_xml('repomd'))
- end
- return @repomd
- end
- end
+ attr_reader :repositories
def initialize
@config =
YAML.load_file("#{RAILS_ROOT}/config/image_descriptor_package_repositories.yml")
- end
-
- def get_repository(repository_id)
- repo = @config[repository_id]
- raise "Repository '#{repository_id}' doesn't exist" unless
repo
- return CompsRepository.new(repo['baseurl'], repository_id)
- end
-
- def repositories
- return @config
+ @repositories = get_repositories
end
def all_groups(repository = nil)
unless @all_groups
@all_groups = {}
- repositories.keys.each do |r|
- next if repository and repository != 'all' and repository != r
- get_repository(r).get_groups.each do |group, data|
+ repositories.each do |r|
+ next if repository and repository != 'all' and repository != r.id
+ r.groups.each do |group, data|
if @all_groups[group]
@all_groups[group][:packages].merge!(data[:packages])
else
@@ -170,11 +49,27 @@ class RepositoryManager
def all_packages(repository = nil)
unless @all_packages
@all_packages = []
- repositories.keys.each do |r|
- next if repository and repository != 'all' and repository != r
- @all_packages += get_repository(r).get_packages
+ repositories.each do |r|
+ next if repository and repository != 'all' and repository != r.id
+ @all_packages += r.packages
end
end
return @all_packages
end
+
+ private
+
+ def get_repositories
+ repositories = []
+ if @config
+ @config.each do |rep|
+ if rep['type'] == 'xml'
+ repositories << CompsRepository.new(rep)
+ elsif rep['type'] == 'pulp'
+ repositories += PulpRepository.repositories(rep)
+ end
+ end
+ end
+ return repositories
+ end
end
diff --git a/src/app/util/repository_manager/abstract_repository.rb
b/src/app/util/repository_manager/abstract_repository.rb
new file mode 100644
index 0000000..ab35d04
--- /dev/null
+++ b/src/app/util/repository_manager/abstract_repository.rb
@@ -0,0 +1,9 @@
+class AbstractRepository
+ attr_reader :id, :name, :baseurl
+
+ def initialize(conf)
+ @id = conf['id']
+ @name = conf['name']
+ @baseurl = conf['baseurl']
+ end
+end
diff --git a/src/app/util/repository_manager/comps_repository.rb
b/src/app/util/repository_manager/comps_repository.rb
new file mode 100644
index 0000000..d7e192a
--- /dev/null
+++ b/src/app/util/repository_manager/comps_repository.rb
@@ -0,0 +1,116 @@
+require 'util/repository_manager/abstract_repository'
+require 'open-uri'
+
+class CompsRepository < AbstractRepository
+ def initialize(conf)
+ super
+ @baseurl = conf['baseurl']
+ end
+
+ def packages
+ packages = []
+ get_packages_nodes.each do |node|
+ name = node.at_xpath('./xmlns:name/child::text()')
+ group = node.at_xpath('./xmlns:format/rpm:group/child::text()')
+ description = node.at_xpath('./xmlns:description/child::text()')
+ next unless name and group
+ packages << {
+ :repository_id => @id,
+ :name => name.text,
+ :description => description ? description.text : '',
+ }
+ end
+ return packages
+ end
+
+ def groups
+ groups = {}
+ get_groups_nodes.each do |g|
+ pkgs = get_group_packages(g)
+ next if pkgs.empty?
+ name = g.at_xpath('name').text
+ groups[name] = {
+ :name => name,
+ :description => (t = g.at_xpath('description')) ? t.text :
'',
+ :packages => pkgs,
+ }
+ end
+ return groups
+ end
+
+ def download_xml(type)
+ begin
+ url = get_url(type)
+ rescue
+ return ''
+ end
+
+ xml_data = open(url)
+ if url =~ /\.gz$/
+ return Zlib::GzipReader.new(xml_data).read
+ else
+ return xml_data.read
+ end
+ end
+
+ private
+
+ def get_xml(type)
+ # FIXME: I'm not sure config is right dir for automatic storing of
+ # xml files, but this should be temporary solution until Image Repo is
+ # done
+ xml_dir = "#{RAILS_ROOT}/config/image_descriptor_xmls"
+ xml_file = "#{xml_dir}/#{(a)id}.#{type}.xml"
+ begin
+ return File.open(xml_file) { |f| f.read }
+ rescue
+ xml = download_xml(type)
+ Dir.mkdir(xml_dir) unless File.directory?(xml_dir)
+ File.open(xml_file, 'w') { |f| f.write xml }
+ return xml
+ end
+ end
+
+ def get_group_packages(group_node)
+ pkgs = {}
+ group_node.xpath('packagelist/packagereq').each do |p|
+ pkgs[p.text] = p.attr('type')
+ end
+ return pkgs
+ end
+
+ def get_packages_nodes
+ unless @packages_nodes
+ data = get_xml('primary')
+ xml = Nokogiri::XML(data)
+ @packages_nodes = xml.xpath('/xmlns:metadata/xmlns:package')
+ end
+ return @packages_nodes
+ end
+
+ def get_groups_nodes
+ unless @groups_nodes
+ data = get_xml('group')
+ xml = Nokogiri::XML(data)
+ @groups_nodes = xml.xpath('/comps/group')
+ end
+ return @groups_nodes
+ end
+
+ def get_url(type)
+ if type == 'repomd'
+ return File.join(@baseurl, 'repodata', 'repomd.xml')
+ else
+ location =
repomd.xpath("/xmlns:repomd/xmlns:data[@type=\"#{type}\"]/xmlns:location").first
+ raise "location for #{type} data not found" unless location
+ return File.join(@baseurl, location['href'])
+ end
+ end
+
+ def repomd
+ unless @repomd
+ @repomd = Nokogiri::XML(get_xml('repomd'))
+ end
+ return @repomd
+ end
+end
diff --git a/src/app/util/repository_manager/pulp_repository.rb
b/src/app/util/repository_manager/pulp_repository.rb
new file mode 100644
index 0000000..ee9840f
--- /dev/null
+++ b/src/app/util/repository_manager/pulp_repository.rb
@@ -0,0 +1,62 @@
+require 'restclient'
+require 'json'
+require 'util/repository_manager/abstract_repository'
+
+class PulpRepository < AbstractRepository
+ class WrappedRestClient
+ def self.method_missing(method, *args)
+ begin
+ JSON.parse(RestClient.send(method, *args))
+ rescue Errno::ECONNREFUSED
+ raise "pulp repository: connection failed (#{args.first})"
+ rescue RestClient::ResourceNotFound
+ raise "pulp repository: resource not found (#{args.first})"
+ rescue JSON::ParserError
+ raise "pulp repository: failed to parse response (#{args.first})"
+ end
+ end
+ end
+
+ def self.repositories(conf)
+ WrappedRestClient.get("#{conf['baseurl']}/repositories/").map do
|r|
+ next if conf['except'] and
conf['except'].include?(r['id'])
+ PulpRepository.new(r.merge('baseurl' => conf['baseurl']))
+ end.compact
+ end
+
+ def initialize(conf)
+ super
+ @packages_url = @baseurl + conf['packages']
+ @groups_url = @baseurl + conf['packagegroups']
+ end
+
+ def packages
+ packages = []
+ WrappedRestClient.get((a)packages_url).each_value do |info|
+ packages << {
+ :repository_id => @id,
+ :name => info['name'],
+ :description => info['description'],
+ }
+ end
+ return packages
+ end
+
+ def groups
+ groups = {}
+ WrappedRestClient.get(@groups_url, {}).each do |id, info|
+ pkgs = {}
+ info['default_package_names'].each {|p| pkgs[p] = 'default'}
+ info['optional_package_names'].each {|p| pkgs[p] = 'optional'}
+ info['mandatory_package_names'].each {|p| pkgs[p] = 'mandatory'}
+ next if pkgs.empty?
+ name = info['name']
+ groups[name] = {
+ :name => name,
+ :description => info['description'].to_s,
+ :packages => pkgs,
+ }
+ end
+ return groups
+ end
+end
diff --git a/src/app/views/templates/software.haml
b/src/app/views/templates/software.haml
index 998ce9b..9d11b5e 100644
--- a/src/app/views/templates/software.haml
+++ b/src/app/views/templates/software.haml
@@ -82,7 +82,7 @@
%li{ :class => "#{selection_style} ui-state-default
ui-corner-top", :style => 'clear: none' }
= "<a href=\"#{url_for(:action => "software",
:id => @image_descriptor, :tab =>
item[:tab])}\"><span>#{item[:text]}</span></a>"
%li{ :class => "select_repository"}
- = select_tag("repository", ["<option value='all'
selected='selected'>All</option>"] +
@repository_manager.repositories.map{|repid, rep| "<option
value=\"#{repid}\">#{rep['name']}</option>"}, {:onchange
=> "get_repository(event)"})
+ = select_tag("repository", ["<option value='all'
selected='selected'>All</option>"] +
@repository_manager.repositories.map{|rep| "<option
value=\"#{rep.id}\">#{rep.name}</option>"}, {:onchange =>
"get_repository(event)"})
- unless request.xhr?
= render :partial => @selected_tab
.pkglist{:style => "margin-left: 30px", :class =>
"left-pkglist"}
diff --git a/src/config/image_descriptor_package_repositories.yml
b/src/config/image_descriptor_package_repositories.yml
index 40335ea..42f2d8e 100644
--- a/src/config/image_descriptor_package_repositories.yml
+++ b/src/config/image_descriptor_package_repositories.yml
@@ -1,6 +1,15 @@
-fedora:
- name: Fedora
- baseurl:
http://download.fedoraproject.org/pub/fedora/linux/releases/11/Everything...
-jboss:
- name: JBoss
- baseurl:
http://repo.oddthesis.org/cirras/packages/fedora/11/RPMS/noarch/
+#-
+# id: fedora
+# name: Fedora
+# baseurl:
http://download.fedoraproject.org/pub/fedora/linux/releases/11/Everything...
+# type: xml
+#
+#-
+# id: jboss
+# name: JBoss
+# baseurl:
http://repo.oddthesis.org/cirras/packages/fedora/11/RPMS/noarch/
+# type: xml
+#
+-
+ baseurl:
https://admin:admin@localhost:8811/
+ type: pulp
--
1.7.0.1