diff --git a/atkinson/pungi/depends.py b/atkinson/pungi/depends.py new file mode 100644 index 0000000..6b17fb0 --- /dev/null +++ b/atkinson/pungi/depends.py @@ -0,0 +1,308 @@ +#! /usr/bin/env python +""" Interface with rpmreq to determine build dependencies """ +from __future__ import print_function + +import copy +import os +import stat +import logging + +from toolchest.rpm.utils import split_filename, componentize + +try: + from rpmreq.actions import build_requires + from rpmreq.query import Repo +except ImportError: + def build_requires(filename, repos, **kwargs): # NOQA + # pylint: disable=unused-argument + """ + Stub build-requires + rpmreq and, by extension, hawkey is required for deployment, + but not for testing. + Hawkey is part of libdnf, written in C, and not published + to PyPI. + """ + if 'logger' in kwargs: + kwargs['logger'].warn('build_requires: hawkey missing') + return [], [], [] + + from collections import namedtuple + Repo = namedtuple('Repo', ['id', 'url']) + +from atkinson.config.manager import ConfigManager + + +class DependencySet(): + """ + Dependency Set generated from a source spec file and a given build tag. + Includes: Met dependencies, dependencies with the wrong version, + and missing dependencies. + + Met dependencies: + [ {'name', 'version', 'release', 'epoch', 'component'}, ... ] + ^ From source rpm name + ('comparison' is included, too, but is always '==') + + Unmet dependencies: + [ {'name', 'version', 'release', 'epoch', 'comparison'}, ... ] + ^ >=, ==, >, if available + Missing: + [ {'name', 'version', 'release', 'epoch', 'comparison'}, ... ] + + Config file format: + --- + + build_sources: + build-version-1: + - http://whatever-location-1/x86_64 + - http://whatever-location-2/x86_64 + build-version-2: + - http://whatever-location-3/arch/ + """ + + def __init__(self, **kwargs): + if 'config' not in kwargs: + # Don't need to keep this around + args = {} + if 'config_file' in kwargs: + args['filenames'] = [kwargs['config_file']] + del kwargs['config_file'] + else: + args['filenames'] = ['build_sources.yml'] + + if 'config_path' in kwargs: + args['paths'] = kwargs['config_path'] + + mgr = ConfigManager(**args) + self.config = copy.copy(mgr.config) + else: + self.config = copy.copy(kwargs['config']) + del kwargs['config'] + + self.met = [] + self.wrong_version = [] + self.unmet = [] + + # Allow caller to inject logging infrastructure, if desired. + # Eventually, pass to rpmreq, although, we don't log anything + # in this code directly. + if 'logger' in kwargs: + self.log = kwargs['logger'] + self.provided_log = True + else: + self.log = logging.getLogger(__name__) + self.provided_log = False + + if 'filename' in kwargs and 'version' in kwargs: + filename = kwargs['filename'] + del kwargs['filename'] + version = kwargs['version'] + del kwargs['version'] + self.get_spec_build_deps(filename, version, **kwargs) + + def get_spec_build_deps(self, filename, version, **kwargs): + """Call in to rpmreq and retrieve dependencies.""" + st_info = os.stat(filename) + if not stat.S_ISREG(st_info.st_mode): + raise ValueError('{0} is not a regular file'.format(filename)) + + if not filename.endswith('.spec'): + raise ValueError('{0} is not a spec file'.format(filename)) + + self.filename = filename + + if not self.config or self.config == {} or \ + 'build_sources' not in self.config: + return + + srcs = self.config['build_sources'] + if version not in srcs: + raise ValueError('Invalid version: {0}, expected one of {1}'.format( + version, + [ver for ver in srcs])) + + repos = [] + for idx in range(len(srcs[version])): + repos.append(Repo(str(idx), srcs[version][idx])) + + # TODO: rpmreq supporting passdown of logger + # e.g. if self.provided_log: + # (add logger=self.log to kwargs) + met_deps, wrong_version, unmet_deps = \ + build_requires(filename, repos) + + self.met = transmogrify_met(met_deps) + self.wrong_version = transmogrify_unmet(wrong_version) + self.unmet = transmogrify_unmet(unmet_deps) + + if 'logger' in kwargs: + kwargs['logger'].info(str(self)) + + def __str__(self): + """Report useful information about ourself.""" + fname = os.path.basename(self.filename) + str_format = '{0}: {1} met, {2} incorrect, {3} missing' + return str_format.format(fname, len(self.met), len(self.wrong_version), len(self.unmet)) + + +def transmogrify_met(met_deps): + """ + Convert a Hawkey dependency into a simple dict + + This is generally only used by DependencySet, but could be used + elsewhere + """ + if not isinstance(met_deps, list): + raise ValueError('met_deps is not a list') + ret = [] + for dep in met_deps: + info = {'component': componentize(dep.sourcerpm), + 'epoch': dep.epoch, + 'name': dep.name, + 'comparison': '==', # This is the version provided + 'version': dep.version, + 'release': dep.release} + ret.append(info) + return ret + + +def transmogrify_unmet(unmet_deps): + """ + Convert list of string or repo.Depends to our simple dict format + + This is generally only used by DependencySet, but could be used + elsewhere + """ + if not isinstance(unmet_deps, list): + raise ValueError('unmet_deps is not a list') + ret = [] + for dep in unmet_deps: + info = rpmdep_to_dep(str(dep)) + ret.append(info) + return ret + + +def dep_to_tuple(dep): + """Convert one of our dependencies into an RPM-style tuple""" + if not isinstance(dep, dict): + raise ValueError('dep is not a dict') + if 'version' not in dep: + raise ValueError('Cannot convert {0}: version missing'.format(str(dep))) + epoch = 0 + version = None + release = None + if 'epoch' in dep: + epoch = int(dep['epoch']) + version = dep['version'] + if 'release' in dep: + release = dep['release'] + return (epoch, version, release) + + +def dep_to_nevr(dep): + """Convert one of our dependencies into an RPM NEVR string""" + if not isinstance(dep, dict): + raise ValueError('dep is not a dict') + for field in ('name', 'version', 'release'): + if field not in dep: + raise ValueError('Cannot convert {0}: {1} missing'.format(str(dep), field)) + ret = dep['name'] + ret = ret + '-' + if 'epoch' in dep and dep['epoch'] not in ('0', 0, ''): + ret = ret + str(dep['epoch']) + ':' + ret = ret + str(dep['version']) + ret = ret + '-' + dep['release'] + return ret + + +def dep_to_rpmdep(dep): + """Convert a dependency into an RPM dependency string""" + if 'comparison' not in dep: + return dep['name'] + ret = '{0} {1} '.format(dep['name'], dep['comparison']) + if 'epoch' in dep and dep['epoch'] not in ('', 0, '0'): + ret = ret + '{0}:'.format(dep['epoch']) + ret = ret + '{0}'.format(dep['version']) + if 'release' in dep and dep['release'] != '': + ret = ret + '-{0}'.format(dep['release']) + return ret + + +def rpmdep_to_dep(dep): + """Convert a RPM style dependency into a simple dict""" + vals = dep.split(' ') + if len(vals) == 1: + return {'name': vals[0]} + if len(vals) != 3: + raise ValueError('Could not parse: \"' + dep + '\"') + ret = {'name': vals[0], + 'comparison': vals[1]} + evr = vals[2].split('-') + if len(evr) > 2: + raise ValueError('Could not parse: \"' + dep + '\"') + + if len(evr) == 2: + ret['release'] = evr[1] + if ret['release'] == 'None': + del ret['release'] + + if ':' in evr[0]: + e_v = evr[0].split(':') + ret['epoch'] = int(e_v[0]) + if ret['epoch'] == '0': + del ret['epoch'] + ret['version'] = e_v[1] + else: + ret['version'] = evr[0] + + return ret + + +def nevr_to_dep(dep): + """Convert a RPM NEVR string to a simple dict""" + (name, version, release, epoch, _) = split_filename(dep) + ret = {} + + if name == '': + raise ValueError('Could not parse: \"' + dep + '\"') + + ret['name'] = name + ret['version'] = version + ret['comparison'] = '==' + if epoch not in ('', 0, '0'): + ret['epoch'] = int(epoch) + if release != 'None' and release is not None: + ret['release'] = release + + return ret + + +def _main(argv): + """Simple test program""" + if len(argv) < 3: + print('Usage: {0} '.format(argv[0])) + return 1 + depends = DependencySet(filename=argv[1], version=argv[2]) + if not depends: + return 1 + + if depends.met: + print('Met:') + for dep in depends.met: + print(' ' + dep_to_nevr(dep)) + if depends.wrong_version: + print() + print('Wrong version:') + for dep in depends.wrong_version: + print(' ' + dep_to_rpmdep(dep)) + if depends.unmet: + print() + print('Unmet:') + for dep in depends.unmet: + print(' ' + dep_to_rpmdep(dep)) + return 0 + + +if __name__ == '__main__': + import sys + exit(_main(sys.argv)) diff --git a/tests/unit/pungi/test_depends.py b/tests/unit/pungi/test_depends.py new file mode 100644 index 0000000..c3708a3 --- /dev/null +++ b/tests/unit/pungi/test_depends.py @@ -0,0 +1,174 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +"""Tests for `atkinson.pungi.depends` package.""" + +import copy +import os + +import pytest + +from toolchest.genericargs import GenericArgs + +from atkinson.pungi.depends import rpmdep_to_dep, dep_to_tuple, dep_to_nevr +from atkinson.pungi.depends import dep_to_rpmdep, nevr_to_dep, transmogrify_met +from atkinson.pungi.depends import transmogrify_unmet, DependencySet + + +def test_rpmdep_to_dep(): + """Tests for rpmdep_to_dep""" + with pytest.raises(ValueError): + rpmdep_to_dep('foo 1.0') + with pytest.raises(ValueError): + rpmdep_to_dep('foo > 1.0-1-1') + + expected = {'name': 'foo'} + assert rpmdep_to_dep('foo') == expected + + expected = {'name': 'foo', 'comparison': '>', 'version': '2.0'} + assert rpmdep_to_dep('foo > 2.0') == expected + + expected = {'name': 'foo', 'comparison': '>=', 'release': '7', + 'epoch': 1, 'version': '2.0'} + assert rpmdep_to_dep('foo >= 1:2.0-7') == expected + + +def test_dep_to_tuple(): + """Test dep_to_tuple""" + with pytest.raises(ValueError): + dep_to_tuple('Hello') + with pytest.raises(ValueError): + dep_to_tuple({}) + + assert dep_to_tuple({'version': '1.0', 'release': '7'}) == (0, '1.0', '7') + assert dep_to_tuple({'epoch': '2', 'version': '1.0', 'release': '7'}) == (2, '1.0', '7') + + +def test_dep_to_nevr(): + """Tests for dep_to_nevr function""" + with pytest.raises(ValueError): + dep_to_nevr({}) + + val = {'name': 'test', 'version': '1.0', 'release': '1.el7ost'} + for key in val: + val_copy = copy.copy(val) + del val_copy[key] + print(val_copy) + with pytest.raises(ValueError): + dep_to_nevr(val_copy) + + assert dep_to_nevr(val) == 'test-1.0-1.el7ost' + + val['epoch'] = 1 + assert dep_to_nevr(val) == 'test-1:1.0-1.el7ost' + + +def test_dep_to_rpmdep(): + """Tests for dep_to_rpmdep function""" + assert dep_to_rpmdep({'name': 'foo'}) == 'foo' + assert dep_to_rpmdep({'name': 'foo', + 'comparison': '>', + 'version': '2.0'}) == 'foo > 2.0' + + assert dep_to_rpmdep({'name': 'foo', + 'comparison': '>=', + 'release': '7', + 'epoch': '1', + 'version': '2.0'}) == 'foo >= 1:2.0-7' + + +def test_nevr_to_dep(): + """Tests for nevr_to_dep function""" + with pytest.raises(ValueError): + nevr_to_dep('1.0-1') + + val = {'name': 'test', 'version': '1.0', 'release': '1.el7ost', 'comparison': '=='} + assert nevr_to_dep('test-1.0-1.el7ost') == val + + val['epoch'] = 1 + assert nevr_to_dep('test-1:1.0-1.el7ost') == val + + +def test_transmogrify_met(): + """Tests for transmogrify_met function""" + val_one = GenericArgs() + val_two = GenericArgs() + + val_one.sourcerpm = 'foo-1.2-1.src.rpm' + val_one.epoch = 0 + val_one.name = 'foo' + val_one.version = '1.2' + val_one.release = '1' + + val_two.sourcerpm = 'test-0.3-4.src.rpm' + val_two.epoch = 1 + val_two.name = 'test' + val_two.version = '0.3' + val_two.release = '4' + + vals = [val_one, val_two] + deps = transmogrify_met(vals) + assert dep_to_nevr(deps[0]) == 'foo-1.2-1' + assert dep_to_nevr(deps[1]) == 'test-1:0.3-4' + + +def test_transmogrify_unmet(): + """Tests for transmogrify_unmet function""" + deps_nevr = ['test-1:0.3-4', 'foo-1.2-1'] + deps = [] + expected = [] + for dep in deps_nevr: + expected.append(nevr_to_dep(dep)) + deps.append(dep_to_rpmdep(nevr_to_dep(dep))) + + with pytest.raises(ValueError): + transmogrify_unmet('') + + ret = transmogrify_unmet(deps) + assert expected == ret + + +def test_dependency_set_base(): + """ Test the DependencySet class """ + depset = DependencySet() + assert depset.met == [] + assert depset.unmet == [] + assert depset.met == [] + + # Config injection + conf = {'build_sources': + {'koji-tag-1': ['http://localhost/1', + 'http://localhost/1.1'], + 'koji-tag-2': ['http://localhost/2']}} + conf_copy = copy.copy(conf) + + depset = DependencySet(config={'build_sources': + {'koji-tag-1': ['http://localhost/1', + 'http://localhost/1.1'], + 'koji-tag-2': ['http://localhost/2']}}) + assert depset.config == conf_copy + + +def test_dependency_set(datadir): + """ Test loading a configuration file """ + depset = DependencySet(config_file='test_build_sources.yml', + config_path=datadir) + print(depset.config) + assert depset.config == {'build_sources': + {'koji-tag-1': ['http://localhost/1', + 'http://localhost/1.1'], + 'koji-tag-2': ['http://localhost/2']}} + + # Invalid version + with pytest.raises(ValueError): + specfile = os.path.join(datadir, 'openstack-swift.spec') + depset.get_spec_build_deps(specfile, 'invalid-version') + + # File not fount + with pytest.raises(OSError): + specfile = os.path.join(datadir, 'nonexistent') + depset.get_spec_build_deps(specfile, 'koji-tag-1') + + # Don't load a directory + with pytest.raises(ValueError): + depset.get_spec_build_deps(datadir, 'koji-tag-1') diff --git a/tests/unit/pungi/test_depends/openstack-swift.spec b/tests/unit/pungi/test_depends/openstack-swift.spec new file mode 100644 index 0000000..f92a20e --- /dev/null +++ b/tests/unit/pungi/test_depends/openstack-swift.spec @@ -0,0 +1,555 @@ +%global dlrn_nvr swift-2.19.1.dev186-0.20181119232648.3465d63 +%global dlrn 1 +%define upstream_version 2.19.1.dev186 +%{!?upstream_version: %global upstream_version %{version}%{?milestone}} +%global with_doc 0 + +%global common_desc \ +OpenStack Object Storage (Swift) aggregates commodity servers to work together \ +in clusters for reliable, redundant, and large-scale storage of static objects. \ +Objects are written to multiple hardware devices in the data center, with the \ +OpenStack software responsible for ensuring data replication and integrity \ +across the cluster. Storage clusters can scale horizontally by adding new nodes, \ +which are automatically configured. Should a node fail, OpenStack works to \ +replicate its content from other active nodes. Because OpenStack uses software \ +logic to ensure data replication and distribution across different devices, \ +inexpensive commodity hard drives and servers can be used in lieu of more \ +expensive equipment. + +Name: openstack-swift +Version: 2.19.1 +Release: 0.20181119232648.3465d63%{?dist} +Summary: OpenStack Object Storage (Swift) + +License: ASL 2.0 +URL: http://launchpad.net/swift +Source0: swift-2.19.1.dev186-0.20181119232648.3465d63.tar.gz + +Source2: %{name}-account.service +Source21: %{name}-account@.service +Source22: account-server.conf +Source23: %{name}-account-replicator.service +Source24: %{name}-account-replicator@.service +Source25: %{name}-account-auditor.service +Source26: %{name}-account-auditor@.service +Source27: %{name}-account-reaper.service +Source28: %{name}-account-reaper@.service +Source4: %{name}-container.service +Source41: %{name}-container@.service +Source42: container-server.conf +Source43: %{name}-container-replicator.service +Source44: %{name}-container-replicator@.service +Source45: %{name}-container-auditor.service +Source46: %{name}-container-auditor@.service +Source47: %{name}-container-updater.service +Source48: %{name}-container-updater@.service +Source49: %{name}-container-sharder.service +# we seriously need to think about dropping the enumerated units - no sharder@ +Source5: %{name}-object.service +Source51: %{name}-object@.service +Source52: object-server.conf +Source53: %{name}-object-replicator.service +Source54: %{name}-object-replicator@.service +Source55: %{name}-object-auditor.service +Source56: %{name}-object-auditor@.service +Source57: %{name}-object-updater.service +Source58: %{name}-object-updater@.service +Source59: %{name}-object-expirer.service +Source63: %{name}-container-reconciler.service +Source6: %{name}-proxy.service +Source61: proxy-server.conf +Source62: object-expirer.conf +Source64: container-reconciler.conf +Source20: %{name}.tmpfs +Source7: swift.conf +Source71: %{name}.rsyslog +Source72: %{name}.logrotate +Source73: %{name}-object-reconstructor.service +Source74: %{name}-object-reconstructor@.service +Source75: %{name}-container-sync.service +Source76: %{name}-container-sync@.service +Source77: internal-client.conf + + +BuildArch: noarch +BuildRequires: openstack-macros +BuildRequires: python2-devel +BuildRequires: python2-setuptools +BuildRequires: python2-pbr +BuildRequires: git + +BuildRequires: systemd +Obsoletes: openstack-swift-auth <= 1.4.0 + +# Required to compile translation files +BuildRequires: python2-babel + +Requires: python-swift = %{version}-%{release} + +%description +%{common_desc} + +%package -n python-swift +Summary: Python libraries for the OpenStack Object Storage (Swift) + +Provides: openstack-swift = %{version}-%{release} +Obsoletes: openstack-swift < %{version}-%{release} + +Requires: python2-eventlet >= 0.17.4 +Requires: python2-greenlet >= 0.3.1 +Requires: python-paste-deploy +# Not in 2.7.0 anymore, went to stock json in order to support py3 +#Requires: python-simplejson +Requires: pyxattr +Requires: python-netifaces +Requires: python2-dns +Requires: python2-pyeclib +Requires: python-six +Requires: python2-cryptography +Requires: python2-oslo-config >= 2:5.1.0 +Requires: python2-castellan >= 0.7.0 +Requires: python2-ipaddress >= 1.0.16 +Requires: python-lxml >= 3.2.1 +Requires: python2-requests >= 2.14.2 + +%{?systemd_requires} +Requires(pre): shadow-utils + +%description -n python-swift +%{common_desc} + +This package contains the %{name} Python library. + +%package account +Summary: Account services for Swift + +Requires: python-swift = %{version}-%{release} +Requires: rsync >= 3.0 + +%description account +%{common_desc} + +This package contains the %{name} account server. + +%package container +Summary: Container services for Swift + +Requires: python-swift = %{version}-%{release} +Requires: rsync >= 3.0 + +%description container +%{common_desc} + +This package contains the %{name} container server. + +%package object +Summary: Object services for Swift + +Requires: python-swift = %{version}-%{release} +Requires: rsync >= 3.0 + +%description object +%{common_desc} + +This package contains the %{name} object server. + +%package proxy +Summary: A proxy server for Swift + +Requires: python-swift = %{version}-%{release} +Requires: python2-keystonemiddleware +Requires: python2-ceilometermiddleware + +%description proxy +%{common_desc} + +This package contains the %{name} proxy server. + +%package -n python-swift-tests +Summary: Swift tests +Requires: python-swift = %{version}-%{release} + +%description -n python-swift-tests +%{common_desc} + +This package contains the %{name} test files. + +%if 0%{?with_doc} +%package doc +Summary: Documentation for %{name} + +BuildRequires: python2-sphinx >= 1.0 +BuildRequires: python2-openstackdocstheme +# Required for generating docs (otherwise py-modindex.html is missing) +BuildRequires: python2-eventlet +BuildRequires: python-netifaces +BuildRequires: python-paste-deploy +BuildRequires: python2-pyeclib +BuildRequires: pyxattr +BuildRequires: python-lxml + +%description doc +%{common_desc} + +This package contains documentation files for %{name}. +%endif + +%prep +%autosetup -n swift-%{upstream_version} -S git + +# Let RPM handle the dependencies +%py_req_cleanup + +%build +%{__python2} setup.py build +# Generate i18n files +%{__python2} setup.py compile_catalog -d build/lib/swift/locale + +%if 0%{?with_doc} +# Fails unless we create the build directory +mkdir -p doc/build +# Build docs +export PYTHONPATH=. +# NOTE(ykarel) Re-add -W option once following bz is fixed. +# bug: https://bugzilla.redhat.com/show_bug.cgi?id=1479804 +sphinx-build -b html doc/source doc/build/html +# Fix hidden-file-or-dir warning +rm -rf doc/build/html/.{doctrees,buildinfo} +%endif + +%install +%{__python2} setup.py install -O1 --skip-build --root %{buildroot} +# systemd units +install -p -D -m 644 %{SOURCE2} %{buildroot}%{_unitdir}/%{name}-account.service +install -p -D -m 644 %{SOURCE21} %{buildroot}%{_unitdir}/%{name}-account@.service +install -p -D -m 644 %{SOURCE23} %{buildroot}%{_unitdir}/%{name}-account-replicator.service +install -p -D -m 644 %{SOURCE24} %{buildroot}%{_unitdir}/%{name}-account-replicator@.service +install -p -D -m 644 %{SOURCE25} %{buildroot}%{_unitdir}/%{name}-account-auditor.service +install -p -D -m 644 %{SOURCE26} %{buildroot}%{_unitdir}/%{name}-account-auditor@.service +install -p -D -m 644 %{SOURCE27} %{buildroot}%{_unitdir}/%{name}-account-reaper.service +install -p -D -m 644 %{SOURCE28} %{buildroot}%{_unitdir}/%{name}-account-reaper@.service +install -p -D -m 644 %{SOURCE4} %{buildroot}%{_unitdir}/%{name}-container.service +install -p -D -m 644 %{SOURCE41} %{buildroot}%{_unitdir}/%{name}-container@.service +install -p -D -m 644 %{SOURCE43} %{buildroot}%{_unitdir}/%{name}-container-replicator.service +install -p -D -m 644 %{SOURCE44} %{buildroot}%{_unitdir}/%{name}-container-replicator@.service +install -p -D -m 644 %{SOURCE45} %{buildroot}%{_unitdir}/%{name}-container-auditor.service +install -p -D -m 644 %{SOURCE46} %{buildroot}%{_unitdir}/%{name}-container-auditor@.service +install -p -D -m 644 %{SOURCE47} %{buildroot}%{_unitdir}/%{name}-container-updater.service +install -p -D -m 644 %{SOURCE48} %{buildroot}%{_unitdir}/%{name}-container-updater@.service +install -p -D -m 644 %{SOURCE49} %{buildroot}%{_unitdir}/%{name}-container-sharder.service +install -p -D -m 644 %{SOURCE5} %{buildroot}%{_unitdir}/%{name}-object.service +install -p -D -m 644 %{SOURCE51} %{buildroot}%{_unitdir}/%{name}-object@.service +install -p -D -m 644 %{SOURCE53} %{buildroot}%{_unitdir}/%{name}-object-replicator.service +install -p -D -m 644 %{SOURCE54} %{buildroot}%{_unitdir}/%{name}-object-replicator@.service +install -p -D -m 644 %{SOURCE55} %{buildroot}%{_unitdir}/%{name}-object-auditor.service +install -p -D -m 644 %{SOURCE56} %{buildroot}%{_unitdir}/%{name}-object-auditor@.service +install -p -D -m 644 %{SOURCE57} %{buildroot}%{_unitdir}/%{name}-object-updater.service +install -p -D -m 644 %{SOURCE58} %{buildroot}%{_unitdir}/%{name}-object-updater@.service +install -p -D -m 644 %{SOURCE59} %{buildroot}%{_unitdir}/%{name}-object-expirer.service +install -p -D -m 644 %{SOURCE63} %{buildroot}%{_unitdir}/%{name}-container-reconciler.service +install -p -D -m 644 %{SOURCE6} %{buildroot}%{_unitdir}/%{name}-proxy.service +install -p -D -m 644 %{SOURCE73} %{buildroot}%{_unitdir}/%{name}-object-reconstructor.service +install -p -D -m 644 %{SOURCE74} %{buildroot}%{_unitdir}/%{name}-object-reconstructor@.service +install -p -D -m 644 %{SOURCE75} %{buildroot}%{_unitdir}/%{name}-container-sync.service +install -p -D -m 644 %{SOURCE76} %{buildroot}%{_unitdir}/%{name}-container-sync@.service +# Misc other +install -d -m 755 %{buildroot}%{_sysconfdir}/swift +install -d -m 755 %{buildroot}%{_sysconfdir}/swift/account-server +install -d -m 755 %{buildroot}%{_sysconfdir}/swift/container-server +install -d -m 755 %{buildroot}%{_sysconfdir}/swift/object-server +install -d -m 755 %{buildroot}%{_sysconfdir}/swift/proxy-server +# Config files +install -p -D -m 660 %{SOURCE22} %{buildroot}%{_sysconfdir}/swift/account-server.conf +install -p -D -m 660 %{SOURCE42} %{buildroot}%{_sysconfdir}/swift/container-server.conf +install -p -D -m 660 %{SOURCE52} %{buildroot}%{_sysconfdir}/swift/object-server.conf +install -p -D -m 660 %{SOURCE61} %{buildroot}%{_sysconfdir}/swift/proxy-server.conf +install -p -D -m 660 %{SOURCE62} %{buildroot}%{_sysconfdir}/swift/object-expirer.conf +install -p -D -m 660 %{SOURCE64} %{buildroot}%{_sysconfdir}/swift/container-reconciler.conf +install -p -D -m 660 %{SOURCE7} %{buildroot}%{_sysconfdir}/swift/swift.conf +install -p -D -m 660 %{SOURCE77} %{buildroot}%{_sysconfdir}/swift/internal-client.conf +# Install pid directory +install -d -m 755 %{buildroot}%{_localstatedir}/run/swift +install -d -m 755 %{buildroot}%{_localstatedir}/run/swift/account-server +install -d -m 755 %{buildroot}%{_localstatedir}/run/swift/container-server +install -d -m 755 %{buildroot}%{_localstatedir}/run/swift/object-server +install -d -m 755 %{buildroot}%{_localstatedir}/run/swift/proxy-server +# syslog +install -d -m 755 %{buildroot}%{_localstatedir}/log/swift +install -p -D -m 644 %{SOURCE71} %{buildroot}%{_sysconfdir}/rsyslog.d/openstack-swift.conf +install -p -D -m 644 %{SOURCE72} %{buildroot}%{_sysconfdir}/logrotate.d/openstack-swift +# Swift run directories +install -p -D -m 644 %{SOURCE20} %{buildroot}%{_libdir}/tmpfiles.d/openstack-swift.conf +# Install recon directory +install -d -m 755 %{buildroot}%{_localstatedir}/cache/swift +# Install home directory +install -d -m 755 %{buildroot}%{_sharedstatedir}/swift +# man pages +install -d -m 755 %{buildroot}%{_mandir}/man5 +for m in doc/manpages/*.5; do + install -p -m 0644 $m %{buildroot}%{_mandir}/man5 +done +install -d -m 755 %{buildroot}%{_mandir}/man1 +for m in doc/manpages/*.1; do + install -p -m 0644 $m %{buildroot}%{_mandir}/man1 +done + +# tests +mkdir -p %{buildroot}%{_datadir}/swift/test +cp -r test %{buildroot}%{python2_sitelib}/swift/test + +# Install i18n files +install -d -m 755 %{buildroot}%{_datadir} +rm -f %{buildroot}%{python2_sitelib}/swift/locale/*/LC_*/swift*po +rm -f %{buildroot}%{python2_sitelib}/swift/locale/*pot +mv %{buildroot}%{python2_sitelib}/swift/locale %{buildroot}%{_datadir}/locale + +# Find language files +%find_lang swift --all-name + +%clean +rm -rf %{buildroot} + +%pre -n python-swift +getent group swift >/dev/null || groupadd -r swift -g 160 +getent passwd swift >/dev/null || \ +useradd -r -g swift -u 160 -d %{_sharedstatedir}/swift -s /sbin/nologin \ +-c "OpenStack Swift Daemons" swift +exit 0 + +%post account +%systemd_post %{name}-account.service +%systemd_post %{name}-account-replicator.service +%systemd_post %{name}-account-auditor.service +%systemd_post %{name}-account-reaper.service + +%preun account +%systemd_preun %{name}-account.service +%systemd_preun %{name}-account-replicator.service +%systemd_preun %{name}-account-auditor.service +%systemd_preun %{name}-account-reaper.service + +%postun account +%systemd_postun %{name}-account.service +%systemd_postun %{name}-account-replicator.service +%systemd_postun %{name}-account-auditor.service +%systemd_postun %{name}-account-reaper.service + +%post container +%systemd_post %{name}-container.service +%systemd_post %{name}-container-replicator.service +%systemd_post %{name}-container-auditor.service +%systemd_post %{name}-container-updater.service +%systemd_post %{name}-container-sync.service + +%preun container +%systemd_preun %{name}-container.service +%systemd_preun %{name}-container-replicator.service +%systemd_preun %{name}-container-auditor.service +%systemd_preun %{name}-container-updater.service +%systemd_preun %{name}-container-sync.service + +%postun container +%systemd_postun %{name}-container.service +%systemd_postun %{name}-container-replicator.service +%systemd_postun %{name}-container-auditor.service +%systemd_postun %{name}-container-updater.service +%systemd_postun %{name}-container-sync.service + +%post object +%systemd_post %{name}-object.service +%systemd_post %{name}-object-replicator.service +%systemd_post %{name}-object-reconstructor.service +%systemd_post %{name}-object-auditor.service +%systemd_post %{name}-object-updater.service + +%preun object +%systemd_preun %{name}-object.service +%systemd_preun %{name}-object-replicator.service +%systemd_preun %{name}-object-reconstructor.service +%systemd_preun %{name}-object-auditor.service +%systemd_preun %{name}-object-updater.service + +%postun object +%systemd_postun %{name}-object.service +%systemd_postun %{name}-object-replicator.service +%systemd_postun %{name}-object-reconstructor.service +%systemd_postun %{name}-object-auditor.service +%systemd_postun %{name}-object-updater.service + +%post proxy +%systemd_post %{name}-proxy.service +%systemd_post %{name}-object-expirer.service + +%preun proxy +%systemd_preun %{name}-proxy.service +%systemd_preun %{name}-object-expirer.service + +%postun proxy +%systemd_postun %{name}-proxy.service +%systemd_postun %{name}-object-expirer.service + +%post -n python-swift +/usr/bin/kill -HUP `cat /var/run/syslogd.pid 2>/dev/null` 2>/dev/null || : + +%files -n python-swift -f swift.lang +%defattr(-,root,root,-) +%license LICENSE +%doc README.rst +%doc etc/*-sample +%{_mandir}/man5/dispersion.conf.5* +%{_mandir}/man1/swift-account-audit.1* +%{_mandir}/man1/swift-ring-builder-analyzer.1* +%{_mandir}/man1/swift-config.1* +%{_mandir}/man1/swift-dispersion-populate.1* +%{_mandir}/man1/swift-dispersion-report.1* +%{_mandir}/man1/swift-drive-audit.1* +%{_mandir}/man1/swift-form-signature.1* +%{_mandir}/man1/swift-get-nodes.1* +%{_mandir}/man1/swift-init.1* +%{_mandir}/man1/swift-oldies.1.* +%{_mandir}/man1/swift-orphans.1* +%{_mandir}/man1/swift-recon.1* +%{_mandir}/man1/swift-recon-cron.1* +%{_mandir}/man1/swift-ring-builder.1* +%{_mandir}/man1/swift-ring-composer.1* +%{_mandir}/man5/swift.conf.5* +%{_mandir}/man5/container-sync-realms.conf.5* +%{_libdir}/tmpfiles.d/openstack-swift.conf +%dir %attr(0755, swift, swift)%{_sysconfdir}/swift +%config(noreplace) %attr(640, root, swift) %{_sysconfdir}/swift/swift.conf +%config(noreplace) %{_sysconfdir}/rsyslog.d/openstack-swift.conf +%config(noreplace) %{_sysconfdir}/logrotate.d/openstack-swift +%dir %{_localstatedir}/log/swift +%dir %attr(0755, swift, swift) %{_localstatedir}/run/swift +%dir %attr(0755, swift, swift) %{_localstatedir}/cache/swift +%dir %attr(0755, swift, root) %{_sharedstatedir}/swift +%dir %{python2_sitelib}/swift +%{_bindir}/swift-account-audit +%{_bindir}/swift-config +%{_bindir}/swift-dispersion-populate +%{_bindir}/swift-dispersion-report +%{_bindir}/swift-drive-audit +%{_bindir}/swift-form-signature +%{_bindir}/swift-get-nodes +%{_bindir}/swift-init +%{_bindir}/swift-manage-shard-ranges +%{_bindir}/swift-oldies +%{_bindir}/swift-orphans +%{_bindir}/swift-ring-builder +%{_bindir}/swift-ring-builder-analyzer +%{_bindir}/swift-ring-composer +%{_bindir}/swift-recon* +%{python2_sitelib}/swift/*.py* +%{python2_sitelib}/swift/cli +%{python2_sitelib}/swift/common +%{python2_sitelib}/swift/account +%{python2_sitelib}/swift/container +%{python2_sitelib}/swift/obj +%{python2_sitelib}/swift/proxy +%{python2_sitelib}/swift-%{version}*.egg-info +%exclude %{python2_sitelib}/swift/test + +%files -n python-swift-tests +%license LICENSE +%{python2_sitelib}/swift/test + +%files account +%defattr(-,root,root,-) +%{_mandir}/man5/account-server.conf.5* +%{_mandir}/man1/swift-account-auditor.1* +%{_mandir}/man1/swift-account-info.1* +%{_mandir}/man1/swift-account-reaper.1* +%{_mandir}/man1/swift-account-replicator.1* +%{_mandir}/man1/swift-account-server.1* +%{_unitdir}/%{name}-account*.service +%dir %{_sysconfdir}/swift/account-server +%config(noreplace) %attr(640, swift, swift) %{_sysconfdir}/swift/account-server.conf +%dir %attr(0755, swift, root) %{_localstatedir}/run/swift/account-server +%{_bindir}/swift-account-auditor +%{_bindir}/swift-account-info +%{_bindir}/swift-account-reaper +%{_bindir}/swift-account-replicator +%{_bindir}/swift-account-server + +%files container +%defattr(-,root,root,-) +%{_mandir}/man5/container-server.conf.5* +%{_mandir}/man1/swift-container-auditor.1* +%{_mandir}/man1/swift-container-info.1* +%{_mandir}/man1/swift-container-replicator.1* +%{_mandir}/man1/swift-container-server.1* +%{_mandir}/man1/swift-container-sync.1* +%{_mandir}/man1/swift-container-updater.1* +%{_unitdir}/%{name}-container*.service +%dir %{_sysconfdir}/swift/container-server +%config(noreplace) %attr(640, swift, swift) %{_sysconfdir}/swift/container-server.conf +%config(noreplace) %attr(640, swift, swift) %{_sysconfdir}/swift/internal-client.conf +%dir %attr(0755, swift, root) %{_localstatedir}/run/swift/container-server +%{_bindir}/swift-container-auditor +%{_bindir}/swift-container-info +%{_bindir}/swift-container-server +%{_bindir}/swift-container-replicator +%{_bindir}/swift-container-updater +%{_bindir}/swift-container-sync +%{_bindir}/swift-container-sharder + +%files object +%defattr(-,root,root,-) +%{_mandir}/man5/object-server.conf.5* +%{_mandir}/man1/swift-object-auditor.1* +%{_mandir}/man1/swift-object-info.1* +%{_mandir}/man1/swift-object-reconstructor.1* +%{_mandir}/man1/swift-object-replicator.1* +%{_mandir}/man1/swift-object-server.1* +%{_mandir}/man1/swift-object-updater.1* +%{_unitdir}/%{name}-object.service +%{_unitdir}/%{name}-object@.service +%{_unitdir}/%{name}-object-auditor.service +%{_unitdir}/%{name}-object-auditor@.service +%{_unitdir}/%{name}-object-replicator.service +%{_unitdir}/%{name}-object-replicator@.service +%{_unitdir}/%{name}-object-reconstructor.service +%{_unitdir}/%{name}-object-reconstructor@.service +%{_unitdir}/%{name}-object-updater.service +%{_unitdir}/%{name}-object-updater@.service +%dir %{_sysconfdir}/swift/object-server +%config(noreplace) %attr(640, swift, swift) %{_sysconfdir}/swift/object-server.conf +%dir %attr(0755, swift, root) %{_localstatedir}/run/swift/object-server +%{_bindir}/swift-object-auditor +%{_bindir}/swift-object-info +%{_bindir}/swift-object-replicator +%{_bindir}/swift-object-relinker +%{_bindir}/swift-object-server +%{_bindir}/swift-object-updater +%{_bindir}/swift-object-reconstructor + +%files proxy +%defattr(-,root,root,-) +%{_mandir}/man5/object-expirer.conf.5* +%{_mandir}/man5/proxy-server.conf.5* +%{_mandir}/man5/container-reconciler.conf.5* +%{_mandir}/man1/swift-container-reconciler.1* +%{_mandir}/man1/swift-object-expirer.1* +%{_mandir}/man1/swift-proxy-server.1* +%{_mandir}/man1/swift-reconciler-enqueue.1* +%{_mandir}/man1/swift-object-relinker.1* +%{_unitdir}/%{name}-container-reconciler.service +%{_unitdir}/%{name}-object-expirer.service +%{_unitdir}/%{name}-proxy.service +%dir %{_sysconfdir}/swift/proxy-server +%config(noreplace) %attr(640, root, swift) %{_sysconfdir}/swift/container-reconciler.conf +%config(noreplace) %attr(640, root, swift) %{_sysconfdir}/swift/proxy-server.conf +%config(noreplace) %attr(640, root, swift) %{_sysconfdir}/swift/object-expirer.conf +%dir %attr(0755, swift, root) %{_localstatedir}/run/swift/proxy-server +%{_bindir}/swift-container-reconciler +%{_bindir}/swift-object-expirer +%{_bindir}/swift-proxy-server + +%if 0%{?with_doc} +%files doc +%defattr(-,root,root,-) +%doc doc/build/html +%license LICENSE +%endif + +%changelog diff --git a/tests/unit/pungi/test_depends/test_build_sources.yml b/tests/unit/pungi/test_depends/test_build_sources.yml new file mode 100644 index 0000000..71128ad --- /dev/null +++ b/tests/unit/pungi/test_depends/test_build_sources.yml @@ -0,0 +1,8 @@ +--- + +build_sources: + koji-tag-1: + - http://localhost/1 + - http://localhost/1.1 + koji-tag-2: + - http://localhost/2