Initial commit
This commit is contained in:
commit
c689baa002
|
@ -0,0 +1,21 @@
|
|||
*.py[cod]
|
||||
|
||||
# Unit test / coverage reports
|
||||
.coverage
|
||||
cover
|
||||
.tox
|
||||
.testrepository
|
||||
|
||||
# Packages
|
||||
.eggs
|
||||
*.egg
|
||||
*.egg-info
|
||||
dist
|
||||
build
|
||||
eggs
|
||||
parts
|
||||
sdist
|
||||
develop-eggs
|
||||
.installed.cfg
|
||||
lib
|
||||
lib64
|
|
@ -0,0 +1,4 @@
|
|||
[DEFAULT]
|
||||
test_command=OS_STDOUT_CAPTURE=1 OS_STDERR_CAPTURE=1 OS_TEST_TIMEOUT=60 OS_LOG_CAPTURE=1 ${PYTHON:-python} -m subunit.run discover -t ./dlrn_repo ./dlrn_repo $LISTOPT $IDOPTION
|
||||
test_id_option=--load-list $IDFILE
|
||||
test_list_option=--list
|
|
@ -0,0 +1,11 @@
|
|||
dlrn-repo
|
||||
=========
|
||||
|
||||
A tool for managing dlrn repos.
|
||||
|
||||
See: https://github.com/openstack-packages/DLRN
|
||||
|
||||
Note that this is intended as a tool for bootstrapping the repo setup in
|
||||
things like TripleO, so it should not have any runtime OpenStack dependencies
|
||||
or we end up in a chicken-and-egg pickle, and let's be honest - no one wants a
|
||||
chicken and egg pickle.
|
|
@ -0,0 +1,145 @@
|
|||
#!/usr/bin/env python
|
||||
|
||||
# Copyright 2016 Red Hat, Inc.
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
# implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
import argparse
|
||||
import os
|
||||
import re
|
||||
import subprocess
|
||||
import sys
|
||||
|
||||
import requests
|
||||
|
||||
TARGET = '/etc/yum.repos.d'
|
||||
# Uncomment when doing development if you don't want to mess with your actual
|
||||
# system repos while testing
|
||||
#TARGET = 'test'
|
||||
TITLE_RE = re.compile('\[(.*)\]')
|
||||
# Packages to be included from delorean-current when using current-tripleo
|
||||
INCLUDE_PKGS = ('includepkgs=diskimage-builder,instack,instack-undercloud,'
|
||||
'os-apply-config,os-cloud-config,os-collect-config,'
|
||||
'os-net-config,os-refresh-config,python-tripleoclient,'
|
||||
'tripleo-common,openstack -tripleo-heat-templates,'
|
||||
'openstack-tripleo-image-elements,openstack-tripleo,'
|
||||
'openstack-tripleo-puppet-elements,openstack-puppet-modules'
|
||||
)
|
||||
|
||||
class InvalidArguments(Exception):
|
||||
pass
|
||||
|
||||
class NoRepoTitle(Exception):
|
||||
pass
|
||||
|
||||
def _parse_args():
|
||||
parser = argparse.ArgumentParser(
|
||||
description='Download and instll dlrn repos. Note that these repos '
|
||||
'require yum-plugin-priorities in order to function '
|
||||
'correctly, so that will also be installed.')
|
||||
parser.add_argument('repos', metavar='REPO', nargs='+',
|
||||
help='A list of delorean repos. Available repos: '
|
||||
'current, deps, current-tripleo. current-tripleo '
|
||||
'downloads both the current-tripleo and current '
|
||||
'repos, but sets the current repo to only be used '
|
||||
'for TripleO projects')
|
||||
parser.add_argument('-d', '--distro',
|
||||
default='centos7',
|
||||
help='Target distro. Currently only centos7 is '
|
||||
'supported')
|
||||
parser.add_argument('-b', '--branch',
|
||||
default='master',
|
||||
help='Target branch. Should be the lowercase name of '
|
||||
'the OpenStack release. e.g. liberty')
|
||||
return parser.parse_args()
|
||||
|
||||
def _get_repo(path):
|
||||
r = requests.get(path)
|
||||
if r.status_code == 200:
|
||||
return r.text
|
||||
else:
|
||||
r.raise_for_status()
|
||||
|
||||
def _write_repo(content):
|
||||
m = TITLE_RE.match(content)
|
||||
if not m:
|
||||
raise NoRepoTitle('Could not find repo title in: \n%s' % content)
|
||||
filename = m.group(1) + '.repo'
|
||||
filename = os.path.join(TARGET, filename)
|
||||
with open(filename, 'w') as f:
|
||||
f.write(content)
|
||||
print('Installed repo %s to %s' % (m.group(1), filename))
|
||||
|
||||
def _validate_args(args):
|
||||
if 'current' in args.repos and 'current-tripleo' in args.repos:
|
||||
raise InvalidArguments('Cannot use "current" and "current-tripleo" '
|
||||
'together')
|
||||
if args.branch != 'master' and 'current-tripleo' in args.repos:
|
||||
raise InvalidArguments('Cannot use current-tripleo on any branch '
|
||||
'except master')
|
||||
if args.distro != 'centos7':
|
||||
raise InvalidArguments('centos7 is the only supported distro')
|
||||
|
||||
def _remove_existing():
|
||||
"""Remove any delorean* repos that already exist"""
|
||||
for f in os.listdir(TARGET):
|
||||
if f.startswith('delorean'):
|
||||
filename = os.path.join(TARGET, f)
|
||||
os.remove(filename)
|
||||
print('Removed old repo "%s"' % filename)
|
||||
|
||||
def _get_base_path(args):
|
||||
if args.branch != 'master':
|
||||
distro_branch = '%s-%s' % (args.distro, args.branch)
|
||||
else:
|
||||
distro_branch = args.distro
|
||||
return 'http://trunk.rdoproject.org/%s/' % distro_branch
|
||||
|
||||
def _install_priorities():
|
||||
try:
|
||||
subprocess.check_call(['yum', 'install', '-y',
|
||||
'yum-plugin-priorities'])
|
||||
except subprocess.CalledProcessError:
|
||||
print('ERROR: Failed to install yum-plugin-priorities.')
|
||||
raise
|
||||
|
||||
def _install_repos(args, base_path):
|
||||
for repo in args.repos:
|
||||
if repo == 'current':
|
||||
content = _get_repo(base_path + 'current/delorean.repo')
|
||||
if args.branch != 'master':
|
||||
content = TITLE_RE.sub('[delorean-%s]' % args.branch, content)
|
||||
_write_repo(content)
|
||||
elif repo == 'deps':
|
||||
content = _get_repo(base_path + 'delorean-deps.repo')
|
||||
_write_repo(content)
|
||||
elif repo == 'current-tripleo':
|
||||
content = _get_repo(base_path + 'current-tripleo/delorean.repo')
|
||||
content = TITLE_RE.sub('[delorean-current-tripleo]', content)
|
||||
_write_repo(content)
|
||||
content = _get_repo(base_path + 'current/delorean.repo')
|
||||
content += '\n%s' % INCLUDE_PKGS
|
||||
_write_repo(content)
|
||||
else:
|
||||
raise InvalidArguments('Invalid repo "%s" specified' % repo)
|
||||
|
||||
def main():
|
||||
args = _parse_args()
|
||||
_validate_args(args)
|
||||
base_path = _get_base_path(args)
|
||||
_install_priorities()
|
||||
_remove_existing()
|
||||
_install_repos(args, base_path)
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
|
@ -0,0 +1,214 @@
|
|||
# Copyright 2016 Red Hat, Inc.
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
# implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
import subprocess
|
||||
import sys
|
||||
|
||||
import mock
|
||||
import testtools
|
||||
|
||||
from dlrn_repo import main
|
||||
|
||||
class TestDlrnRepo(testtools.TestCase):
|
||||
def test_target(self):
|
||||
self.assertEqual('/etc/yum.repos.d', main.TARGET)
|
||||
|
||||
@mock.patch('dlrn_repo.main._parse_args')
|
||||
@mock.patch('dlrn_repo.main._validate_args')
|
||||
@mock.patch('dlrn_repo.main._get_base_path')
|
||||
@mock.patch('dlrn_repo.main._install_priorities')
|
||||
@mock.patch('dlrn_repo.main._remove_existing')
|
||||
@mock.patch('dlrn_repo.main._install_repos')
|
||||
def test_main(self, mock_install, mock_remove, mock_ip, mock_gbp,
|
||||
mock_validate, mock_parse):
|
||||
mock_args = mock.Mock()
|
||||
mock_parse.return_value = mock_args
|
||||
mock_path = mock.Mock()
|
||||
mock_gbp.return_value = mock_path
|
||||
main.main()
|
||||
mock_validate.assert_called_once_with(mock_args)
|
||||
mock_gbp.assert_called_once_with(mock_args)
|
||||
mock_ip.assert_called_once_with()
|
||||
mock_remove.assert_called_once_with()
|
||||
mock_install.assert_called_once_with(mock_args, mock_path)
|
||||
|
||||
@mock.patch('requests.get')
|
||||
def test_get_repo(self, mock_get):
|
||||
mock_response = mock.Mock()
|
||||
mock_response.status_code = 200
|
||||
mock_response.text = '88MPH'
|
||||
mock_get.return_value = mock_response
|
||||
fake_addr = 'http://lone/pine/mall'
|
||||
content = main._get_repo(fake_addr)
|
||||
self.assertEqual('88MPH', content)
|
||||
mock_get.assert_called_once_with(fake_addr)
|
||||
|
||||
@mock.patch('requests.get')
|
||||
def test_get_repo_404(self, mock_get):
|
||||
mock_response = mock.Mock()
|
||||
mock_response.status_code = 404
|
||||
mock_get.return_value = mock_response
|
||||
fake_addr = 'http://twin/pines/mall'
|
||||
main._get_repo(fake_addr)
|
||||
mock_get.assert_called_once_with(fake_addr)
|
||||
mock_response.raise_for_status.assert_called_once_with()
|
||||
|
||||
@mock.patch('os.listdir')
|
||||
@mock.patch('os.remove')
|
||||
def test_remove_existing(self, mock_remove, mock_listdir):
|
||||
fake_list = ['foo.repo', 'delorean.repo',
|
||||
'delorean-current-tripleo.repo']
|
||||
mock_listdir.return_value = fake_list
|
||||
main._remove_existing()
|
||||
self.assertIn(mock.call('/etc/yum.repos.d/delorean.repo'),
|
||||
mock_remove.mock_calls)
|
||||
self.assertIn(mock.call('/etc/yum.repos.d/'
|
||||
'delorean-current-tripleo.repo'),
|
||||
mock_remove.mock_calls)
|
||||
self.assertNotIn(mock.call('/etc/yum.repos.d/foo.repo'),
|
||||
mock_remove.mock_calls)
|
||||
|
||||
def test_get_base_path(self):
|
||||
args = mock.Mock()
|
||||
args.branch = 'master'
|
||||
args.distro = 'centos7'
|
||||
path = main._get_base_path(args)
|
||||
self.assertEqual('http://trunk.rdoproject.org/centos7/', path)
|
||||
|
||||
def test_get_base_path_branch(self):
|
||||
args = mock.Mock()
|
||||
args.branch = 'liberty'
|
||||
args.distro = 'centos7'
|
||||
path = main._get_base_path(args)
|
||||
self.assertEqual('http://trunk.rdoproject.org/centos7-liberty/', path)
|
||||
|
||||
@mock.patch('subprocess.check_call')
|
||||
def test_install_priorities(self, mock_check_call):
|
||||
main._install_priorities()
|
||||
mock_check_call.assert_called_once_with(['yum', 'install', '-y',
|
||||
'yum-plugin-priorities'])
|
||||
|
||||
@mock.patch('subprocess.check_call')
|
||||
def test_install_priorities_fails(self, mock_check_call):
|
||||
mock_check_call.side_effect = subprocess.CalledProcessError(88, '88')
|
||||
self.assertRaises(subprocess.CalledProcessError,
|
||||
main._install_priorities)
|
||||
|
||||
@mock.patch('dlrn_repo.main._get_repo')
|
||||
@mock.patch('dlrn_repo.main._write_repo')
|
||||
def test_install_repos_current(self, mock_write, mock_get):
|
||||
args = mock.Mock()
|
||||
args.repos = ['current']
|
||||
args.branch = 'master'
|
||||
mock_get.return_value = '[delorean]\nMr. Fusion'
|
||||
main._install_repos(args, 'roads/')
|
||||
mock_get.assert_called_once_with('roads/current/delorean.repo')
|
||||
mock_write.assert_called_once_with('[delorean]\nMr. Fusion')
|
||||
|
||||
@mock.patch('dlrn_repo.main._get_repo')
|
||||
@mock.patch('dlrn_repo.main._write_repo')
|
||||
def test_install_repos_current_mitaka(self, mock_write, mock_get):
|
||||
args = mock.Mock()
|
||||
args.repos = ['current']
|
||||
args.branch = 'mitaka'
|
||||
mock_get.return_value = '[delorean]\nMr. Fusion'
|
||||
main._install_repos(args, 'roads/')
|
||||
mock_get.assert_called_once_with('roads/current/delorean.repo')
|
||||
mock_write.assert_called_once_with('[delorean-mitaka]\nMr. Fusion')
|
||||
|
||||
@mock.patch('dlrn_repo.main._get_repo')
|
||||
@mock.patch('dlrn_repo.main._write_repo')
|
||||
def test_install_repos_deps(self, mock_write, mock_get):
|
||||
args = mock.Mock()
|
||||
args.repos = ['deps']
|
||||
args.branch = 'master'
|
||||
mock_get.return_value = '[delorean-deps]\nMr. Fusion'
|
||||
main._install_repos(args, 'roads/')
|
||||
mock_get.assert_called_once_with('roads/delorean-deps.repo')
|
||||
mock_write.assert_called_once_with('[delorean-deps]\nMr. Fusion')
|
||||
|
||||
@mock.patch('dlrn_repo.main._get_repo')
|
||||
@mock.patch('dlrn_repo.main._write_repo')
|
||||
def test_install_repos_current_tripleo(self, mock_write, mock_get):
|
||||
args = mock.Mock()
|
||||
args.repos = ['current-tripleo']
|
||||
args.branch = 'master'
|
||||
mock_get.return_value = '[delorean]\nMr. Fusion'
|
||||
main._install_repos(args, 'roads/')
|
||||
mock_get.assert_any_call('roads/current-tripleo/delorean.repo')
|
||||
mock_write.assert_any_call('[delorean-current-tripleo]\n'
|
||||
'Mr. Fusion')
|
||||
mock_get.assert_called_with('roads/current/delorean.repo')
|
||||
mock_write.assert_called_with('[delorean]\nMr. Fusion\n%s' %
|
||||
main.INCLUDE_PKGS)
|
||||
|
||||
def test_install_repos_invalid(self):
|
||||
args = mock.Mock()
|
||||
args.repos = ['roads?']
|
||||
self.assertRaises(main.InvalidArguments, main._install_repos, args,
|
||||
'roads/')
|
||||
|
||||
def test_write_repo(self):
|
||||
m = mock.mock_open()
|
||||
with mock.patch('dlrn_repo.main.open', m, create=True):
|
||||
main._write_repo('[delorean]\nThis=Heavy')
|
||||
m.assert_called_once_with('/etc/yum.repos.d/delorean.repo', 'w')
|
||||
m().write.assert_called_once_with('[delorean]\nThis=Heavy')
|
||||
|
||||
def test_write_repo_invalid(self):
|
||||
self.assertRaises(main.NoRepoTitle, main._write_repo, 'Great Scot!')
|
||||
|
||||
def test_parse_args(self):
|
||||
with mock.patch.object(sys, 'argv', ['', 'current', 'deps', '-d',
|
||||
'centos7', '-b', 'liberty']):
|
||||
args = main._parse_args()
|
||||
self.assertEqual(['current', 'deps'], args.repos)
|
||||
self.assertEqual('centos7', args.distro)
|
||||
self.assertEqual('liberty', args.branch)
|
||||
|
||||
def test_parse_args_long(self):
|
||||
with mock.patch.object(sys, 'argv', ['', 'current', '--distro',
|
||||
'centos7', '--branch',
|
||||
'mitaka']):
|
||||
args = main._parse_args()
|
||||
self.assertEqual(['current'], args.repos)
|
||||
self.assertEqual('centos7', args.distro)
|
||||
self.assertEqual('mitaka', args.branch)
|
||||
|
||||
class TestValidate(testtools.TestCase):
|
||||
def setUp(self):
|
||||
super(TestValidate, self).setUp()
|
||||
self.args = mock.Mock()
|
||||
self.args.repos = ['current']
|
||||
self.args.branch = 'master'
|
||||
self.args.distro = 'centos7'
|
||||
|
||||
def test_good(self):
|
||||
main._validate_args(self.args)
|
||||
|
||||
def test_current_and_tripleo(self):
|
||||
self.args.repos = ['current', 'current-tripleo']
|
||||
self.assertRaises(main.InvalidArguments, main._validate_args,
|
||||
self.args)
|
||||
|
||||
def test_branch_and_tripleo(self):
|
||||
self.args.repos = ['current-tripleo']
|
||||
self.args.branch = 'liberty'
|
||||
self.assertRaises(main.InvalidArguments, main._validate_args,
|
||||
self.args)
|
||||
|
||||
def test_invalid_distro(self):
|
||||
self.args.distro = 'Jigawatts 1.21'
|
||||
self.assertRaises(main.InvalidArguments, main._validate_args,
|
||||
self.args)
|
|
@ -0,0 +1 @@
|
|||
requests
|
|
@ -0,0 +1,33 @@
|
|||
[metadata]
|
||||
name = dlrn-repo
|
||||
summary = A tool for managing dlrn repos
|
||||
description-file =
|
||||
README.rst
|
||||
author = Ben Nemec
|
||||
author-email = bnemec@redhat.com
|
||||
home-page = http://www.redhat.com/
|
||||
classifier =
|
||||
Environment :: OpenStack
|
||||
Intended Audience :: Information Technology
|
||||
Intended Audience :: System Administrators
|
||||
License :: OSI Approved :: Apache Software License
|
||||
Operating System :: POSIX :: Linux
|
||||
Programming Language :: Python
|
||||
Programming Language :: Python :: 2
|
||||
Programming Language :: Python :: 2.7
|
||||
Programming Language :: Python :: 3
|
||||
Programming Language :: Python :: 3.4
|
||||
|
||||
[files]
|
||||
packages =
|
||||
dlrn_repo
|
||||
|
||||
[entry_points]
|
||||
console_scripts =
|
||||
dlrn-repo = dlrn_repo.main:main
|
||||
|
||||
[build_sphinx]
|
||||
all_files = 1
|
||||
build-dir = doc/build
|
||||
source-dir = doc/source
|
||||
|
|
@ -0,0 +1,23 @@
|
|||
#!/usr/bin/env python
|
||||
# Copyright (c) 2013 Hewlett-Packard Development Company, L.P.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
# implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
# THIS FILE IS MANAGED BY THE GLOBAL REQUIREMENTS REPO - DO NOT EDIT
|
||||
import setuptools
|
||||
|
||||
setuptools.setup(
|
||||
setup_requires=['pbr'],
|
||||
pbr=True)
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
coverage>=3.6
|
||||
discover
|
||||
fixtures>=0.3.14
|
||||
python-subunit>=0.0.18
|
||||
testrepository>=0.0.18
|
||||
testtools>=0.9.36,!=1.2.0
|
||||
mock>=1.0
|
|
@ -0,0 +1,31 @@
|
|||
[tox]
|
||||
minversion = 1.6
|
||||
skipsdist = True
|
||||
envlist = py34,py27,pep8
|
||||
|
||||
[testenv]
|
||||
usedevelop = True
|
||||
setenv = VIRTUAL_ENV={envdir}
|
||||
deps = -r{toxinidir}/test-requirements.txt
|
||||
-r{toxinidir}/requirements.txt
|
||||
commands = python setup.py testr --slowest --testr-args='{posargs}'
|
||||
|
||||
[testenv:venv]
|
||||
commands = {posargs}
|
||||
|
||||
[testenv:docs]
|
||||
commands = python setup.py build_sphinx
|
||||
|
||||
[testenv:pep8]
|
||||
deps = flake8
|
||||
commands = flake8
|
||||
|
||||
[testenv:cover]
|
||||
commands = python setup.py test --coverage --coverage-package-name=dlrn_repo --testr-args='{posargs}'
|
||||
|
||||
[flake8]
|
||||
ignore = H803
|
||||
show-source = True
|
||||
# puppet-stack-config horribly violates E501 (line length), but I'm not
|
||||
# bothered enough to spend the time to fix it.
|
||||
exclude = .tox,dist,doc,*.egg,build
|
Loading…
Reference in New Issue