From fd05df0293ef09f6ef7db5d6cb997ca58cb21ec6 Mon Sep 17 00:00:00 2001 From: Ghanshyam Mann Date: Sat, 24 Feb 2024 11:33:44 -0800 Subject: [PATCH] Retire Tripleo: remove repo content TripleO project is retiring - https://review.opendev.org/c/openstack/governance/+/905145 this commit remove the content of this project repo Change-Id: I0b5c328f22d893f7d4e73935b31281f0f9826cd4 --- .gitignore | 25 - .stestr.conf | 3 - CONTRIBUTING.rst | 17 - LICENSE | 175 ---- MANIFEST.in | 3 - README.md | 1 - README.rst | 76 +- ansible.cfg | 4 - doc/requirements.txt | 3 - doc/source/conf.py | 80 -- doc/source/contributing.rst | 4 - doc/source/index.rst | 25 - doc/source/installation.rst | 12 - doc/source/readme.rst | 1 - doc/source/usage.rst | 3 - docs/get_hash.md | 86 -- docs/yum_config.md | 107 --- galaxy.yml | 39 - meta/runtime.yml | 1 - molecule/default/assert_ini_key_value.yml | 23 - molecule/default/converge.yml | 86 -- molecule/default/molecule.yml | 14 - molecule/default/prepare.yml | 7 - molecule/default/verify.yml | 47 -- molecule/default/verify_compose_repos.yml | 26 - playbooks/example_get_hash.yaml | 40 - playbooks/example_yum_config.yaml | 33 - .../module_utils/tripleo_repos/__init__.py | 0 .../tripleo_repos/get_hash/__init__.py | 0 .../tripleo_repos/get_hash/__main__.py | 114 --- .../tripleo_repos/get_hash/config.yaml | 53 -- .../tripleo_repos/get_hash/constants.py | 90 -- .../tripleo_repos/get_hash/exceptions.py | 62 -- .../get_hash/tripleo_hash_info.py | 226 ----- plugins/module_utils/tripleo_repos/main.py | 632 -------------- plugins/module_utils/tripleo_repos/utils.py | 83 -- .../tripleo_repos/yum_config/__init__.py | 0 .../tripleo_repos/yum_config/__main__.py | 306 ------- .../tripleo_repos/yum_config/compose_repos.py | 206 ----- .../tripleo_repos/yum_config/constants.py | 87 -- .../tripleo_repos/yum_config/dnf_manager.py | 92 --- .../tripleo_repos/yum_config/exceptions.py | 76 -- .../tripleo_repos/yum_config/utils.py | 50 -- .../tripleo_repos/yum_config/yum_config.py | 449 ---------- plugins/modules/get_hash.py | 145 ---- plugins/modules/yum_config.py | 373 --------- .../stream_by_default-783cc6a2208b942c.yaml | 5 - requirements.txt | 7 - setup.cfg | 40 - setup.py | 20 - test-requirements.txt | 15 - tests/sanity/ignore-2.10.txt | 1 - tests/sanity/ignore-2.11.txt | 1 - tests/sanity/ignore-2.12.txt | 1 - tests/sanity/ignore-2.9.txt | 1 - tests/sanity/ignore.txt | 3 - tests/sanity/requirements.txt | 1 - tests/unit/__init__.py | 0 tests/unit/get_hash/__init__.py | 0 tests/unit/get_hash/fakes.py | 115 --- tests/unit/get_hash/test_tripleo_get_hash.py | 231 ------ .../get_hash/test_tripleo_get_hash_info.py | 227 ----- tests/unit/tripleo_repos/__init__.py | 0 tests/unit/tripleo_repos/test_main.py | 773 ------------------ tests/unit/yum_config/__init__.py | 0 tests/unit/yum_config/fakes.py | 113 --- tests/unit/yum_config/mock_modules.py | 18 - tests/unit/yum_config/test_compose_repos.py | 119 --- tests/unit/yum_config/test_dnf_manager.py | 71 -- tests/unit/yum_config/test_main.py | 209 ----- tests/unit/yum_config/test_yum_config.py | 462 ----------- tox.ini | 108 --- tripleo_repos | 1 - zuul.d/layout.yaml | 40 - 74 files changed, 8 insertions(+), 6559 deletions(-) delete mode 100644 .gitignore delete mode 100644 .stestr.conf delete mode 100644 CONTRIBUTING.rst delete mode 100644 LICENSE delete mode 100644 MANIFEST.in delete mode 100644 README.md delete mode 100644 ansible.cfg delete mode 100644 doc/requirements.txt delete mode 100755 doc/source/conf.py delete mode 100644 doc/source/contributing.rst delete mode 100644 doc/source/index.rst delete mode 100644 doc/source/installation.rst delete mode 100644 doc/source/readme.rst delete mode 100644 doc/source/usage.rst delete mode 100644 docs/get_hash.md delete mode 100644 docs/yum_config.md delete mode 100644 galaxy.yml delete mode 100644 meta/runtime.yml delete mode 100644 molecule/default/assert_ini_key_value.yml delete mode 100644 molecule/default/converge.yml delete mode 100644 molecule/default/molecule.yml delete mode 100644 molecule/default/prepare.yml delete mode 100644 molecule/default/verify.yml delete mode 100644 molecule/default/verify_compose_repos.yml delete mode 100644 playbooks/example_get_hash.yaml delete mode 100644 playbooks/example_yum_config.yaml delete mode 100644 plugins/module_utils/tripleo_repos/__init__.py delete mode 100644 plugins/module_utils/tripleo_repos/get_hash/__init__.py delete mode 100644 plugins/module_utils/tripleo_repos/get_hash/__main__.py delete mode 100644 plugins/module_utils/tripleo_repos/get_hash/config.yaml delete mode 100644 plugins/module_utils/tripleo_repos/get_hash/constants.py delete mode 100644 plugins/module_utils/tripleo_repos/get_hash/exceptions.py delete mode 100644 plugins/module_utils/tripleo_repos/get_hash/tripleo_hash_info.py delete mode 100755 plugins/module_utils/tripleo_repos/main.py delete mode 100644 plugins/module_utils/tripleo_repos/utils.py delete mode 100644 plugins/module_utils/tripleo_repos/yum_config/__init__.py delete mode 100644 plugins/module_utils/tripleo_repos/yum_config/__main__.py delete mode 100644 plugins/module_utils/tripleo_repos/yum_config/compose_repos.py delete mode 100644 plugins/module_utils/tripleo_repos/yum_config/constants.py delete mode 100644 plugins/module_utils/tripleo_repos/yum_config/dnf_manager.py delete mode 100644 plugins/module_utils/tripleo_repos/yum_config/exceptions.py delete mode 100644 plugins/module_utils/tripleo_repos/yum_config/utils.py delete mode 100644 plugins/module_utils/tripleo_repos/yum_config/yum_config.py delete mode 100644 plugins/modules/get_hash.py delete mode 100644 plugins/modules/yum_config.py delete mode 100644 releasenotes/notes/stream_by_default-783cc6a2208b942c.yaml delete mode 100644 requirements.txt delete mode 100644 setup.cfg delete mode 100755 setup.py delete mode 100644 test-requirements.txt delete mode 120000 tests/sanity/ignore-2.10.txt delete mode 120000 tests/sanity/ignore-2.11.txt delete mode 120000 tests/sanity/ignore-2.12.txt delete mode 120000 tests/sanity/ignore-2.9.txt delete mode 100644 tests/sanity/ignore.txt delete mode 100644 tests/sanity/requirements.txt delete mode 100644 tests/unit/__init__.py delete mode 100644 tests/unit/get_hash/__init__.py delete mode 100644 tests/unit/get_hash/fakes.py delete mode 100644 tests/unit/get_hash/test_tripleo_get_hash.py delete mode 100644 tests/unit/get_hash/test_tripleo_get_hash_info.py delete mode 100644 tests/unit/tripleo_repos/__init__.py delete mode 100644 tests/unit/tripleo_repos/test_main.py delete mode 100644 tests/unit/yum_config/__init__.py delete mode 100644 tests/unit/yum_config/fakes.py delete mode 100644 tests/unit/yum_config/mock_modules.py delete mode 100644 tests/unit/yum_config/test_compose_repos.py delete mode 100644 tests/unit/yum_config/test_dnf_manager.py delete mode 100644 tests/unit/yum_config/test_main.py delete mode 100644 tests/unit/yum_config/test_yum_config.py delete mode 100644 tox.ini delete mode 120000 tripleo_repos delete mode 100644 zuul.d/layout.yaml diff --git a/.gitignore b/.gitignore deleted file mode 100644 index 5b0d014..0000000 --- a/.gitignore +++ /dev/null @@ -1,25 +0,0 @@ -*.py[cod] - -# Unit test / coverage reports -.coverage -cover -.tox -.testrepository -.stestr/ - -# Packages -.eggs -*.egg* -dist -build -eggs -parts -sdist -develop-eggs -.installed.cfg -lib -lib64 - -# built ansible collection -*.tar.gz - diff --git a/.stestr.conf b/.stestr.conf deleted file mode 100644 index e84adce..0000000 --- a/.stestr.conf +++ /dev/null @@ -1,3 +0,0 @@ -[DEFAULT] -test_path=./tests/unit -top_dir=./ diff --git a/CONTRIBUTING.rst b/CONTRIBUTING.rst deleted file mode 100644 index 71ca117..0000000 --- a/CONTRIBUTING.rst +++ /dev/null @@ -1,17 +0,0 @@ -If you would like to contribute to the development of OpenStack, you must -follow the steps in this page: - - http://docs.openstack.org/infra/manual/developers.html - -If you already have a good understanding of how the system works and your -OpenStack accounts are set up, you can skip to the development workflow -section of this documentation to learn how changes to OpenStack should be -submitted for review via the Gerrit tool: - - http://docs.openstack.org/infra/manual/developers.html#development-workflow - -Pull requests submitted through GitHub will be ignored. - -Bugs should be filed on Launchpad, not GitHub: - - https://bugs.launchpad.net/tripleo diff --git a/LICENSE b/LICENSE deleted file mode 100644 index 67db858..0000000 --- a/LICENSE +++ /dev/null @@ -1,175 +0,0 @@ - - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. diff --git a/MANIFEST.in b/MANIFEST.in deleted file mode 100644 index f02a4b6..0000000 --- a/MANIFEST.in +++ /dev/null @@ -1,3 +0,0 @@ -global-exclude *.py[cod] -global-exclude __pycache__ -recursive-exclude plugins * diff --git a/README.md b/README.md deleted file mode 100644 index 643e64a..0000000 --- a/README.md +++ /dev/null @@ -1 +0,0 @@ -# tripleo.repos collection diff --git a/README.rst b/README.rst index 0b470fe..4ee2c5f 100644 --- a/README.rst +++ b/README.rst @@ -1,70 +1,10 @@ -tripleo-repos -============= +This project is no longer maintained. -A tool for managing tripleo repos from places like RDO Trunk and Ceph. +The contents of this repository are still available in the Git +source code management system. To see the contents of this +repository before it reached its end of life, please check out the +previous commit with "git checkout HEAD^1". -See: https://blogs.rdoproject.org/2016/04/newbie-in-rdo-2-rdo-trunk-from-a-bird-s-eye-view/ - -Also ensures yum-plugin-priorities is installed since the RDO Trunk repos -require that to work sanely. - -.. note:: The tool will remove any delorean* repos at the target location - to avoid conflicts with older repos. This means you must specify - all of the repos you want to enable in one tripleo-repos call. - -Examples --------- -Install TripleO CI testing repos for UBI-8 by the distro specific path:: - - tripleo-repos -d ubi8 tripleo-ci-testing --output-path /etc/distro.repos.d - -Install current master RDO Trunk repo and the deps repo:: - - tripleo-repos current - -Install current-tripleo RDO Trunk repo and the deps repo:: - - tripleo-repos current-tripleo - -Install the current-tripleo-dev repo. This will also pull current and deps, -and will adjust the priorities of each repo appropriately:: - - tripleo-repos current-tripleo-dev - -Install the mitaka RDO Trunk repo and deps:: - - tripleo-repos -b mitaka current - -Write repos to a different path:: - - tripleo-repos -o ~/test-repos current - -Install the current-tripleo, deps, and ceph repos. NOTE: The Ceph repo is -installed from a package and thus does not respect -o:: - - tripleo-repos current-tripleo ceph - -TripleO -``````` - -To use this for TripleO development, replace the tripleo.sh --repo-setup -step with the following:: - - git clone https://github.com/cybertron/tripleo-repos - cd tripleo-repos - sudo ./setup.py install - sudo tripleo-repos current-tripleo-dev ceph - -Now you're ready to install the undercloud:: - - tripleo.sh --undercloud - -And to build images:: - - export OVERCLOUD_IMAGES_DIB_YUM_REPO_CONF="$(ls /etc/yum.repos.d/delorean* /etc/yum.repos.d/CentOS-Ceph-*)" - tripleo.sh --overcloud-images - -.. note:: This is a tool for bootstrapping the repo setup for 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. +For any further questions, please email +openstack-discuss@lists.openstack.org or join #openstack-dev on +OFTC. diff --git a/ansible.cfg b/ansible.cfg deleted file mode 100644 index 1c30ebd..0000000 --- a/ansible.cfg +++ /dev/null @@ -1,4 +0,0 @@ -# Used for testing to avoid using one from outside repository -[defaults] -# Avoid noise which can make debugging test failures harder -deprecation_warnings=False diff --git a/doc/requirements.txt b/doc/requirements.txt deleted file mode 100644 index 5a4090d..0000000 --- a/doc/requirements.txt +++ /dev/null @@ -1,3 +0,0 @@ -sphinx>=1.8.0,!=2.1.0 # BSD -openstackdocstheme>=2.0.0 # Apache-2.0 - diff --git a/doc/source/conf.py b/doc/source/conf.py deleted file mode 100755 index af8be1f..0000000 --- a/doc/source/conf.py +++ /dev/null @@ -1,80 +0,0 @@ -# -*- coding: utf-8 -*- -# 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 os -import sys - -sys.path.insert(0, os.path.abspath('../..')) -# -- General configuration ---------------------------------------------------- - -# Add any Sphinx extension module names here, as strings. They can be -# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom ones. -extensions = [ - 'sphinx.ext.autodoc', - #'sphinx.ext.intersphinx', - 'openstackdocstheme' -] - - -# autodoc generation is a bit aggressive and a nuisance when doing heavy -# text edit cycles. -# execute "export SPHINX_DEBUG=1" in your terminal to disable - -# The suffix of source filenames. -source_suffix = '.rst' - -# The master toctree document. -master_doc = 'index' - -# General information about the project. -project = u'tripleo-repos' -copyright = u'2017, OpenStack Foundation' - -# If true, '()' will be appended to :func: etc. cross-reference text. -add_function_parentheses = True - -# If true, the current module name will be prepended to all description -# unit titles (such as .. function::). -add_module_names = True - -# The name of the Pygments (syntax highlighting) style to use. -pygments_style = 'sphinx' - -html_theme = 'openstackdocs' -repository_name = 'openstack/tripleo-repos' -bug_project = 'tripleo' - -# -- Options for HTML output -------------------------------------------------- - -# The theme to use for HTML and HTML Help pages. Major themes that come with -# Sphinx are currently 'default' and 'sphinxdoc'. -# html_theme_path = ["."] -# html_theme = '_theme' -# html_static_path = ['static'] - -# Output file base name for HTML help builder. -htmlhelp_basename = '%sdoc' % project - -# Grouping the document tree into LaTeX files. List of tuples -# (source start file, target name, title, author, documentclass -# [howto/manual]). -latex_documents = [ - ('index', - '%s.tex' % project, - u'%s Documentation' % project, - u'OpenStack Foundation', 'manual'), -] - -# Example configuration for intersphinx: refer to the Python standard library. -#intersphinx_mapping = {'http://docs.python.org/': None} diff --git a/doc/source/contributing.rst b/doc/source/contributing.rst deleted file mode 100644 index 1728a61..0000000 --- a/doc/source/contributing.rst +++ /dev/null @@ -1,4 +0,0 @@ -============ -Contributing -============ -.. include:: ../../CONTRIBUTING.rst diff --git a/doc/source/index.rst b/doc/source/index.rst deleted file mode 100644 index 51bbf56..0000000 --- a/doc/source/index.rst +++ /dev/null @@ -1,25 +0,0 @@ -.. tripleo-repos documentation master file, created by - sphinx-quickstart on Tue Jul 9 22:26:36 2013. - You can adapt this file completely to your liking, but it should at least - contain the root `toctree` directive. - -Welcome to tripleo-repos's documentation! -========================================= - -Contents: - -.. toctree:: - :maxdepth: 2 - - readme - installation - usage - contributing - -Indices and tables -================== - -* :ref:`genindex` -* :ref:`modindex` -* :ref:`search` - diff --git a/doc/source/installation.rst b/doc/source/installation.rst deleted file mode 100644 index f1838ce..0000000 --- a/doc/source/installation.rst +++ /dev/null @@ -1,12 +0,0 @@ -============ -Installation -============ - -At the command line:: - - $ pip install tripleo-repos - -Or, if you have virtualenvwrapper installed:: - - $ mkvirtualenv tripleo-repos - $ pip install tripleo-repos diff --git a/doc/source/readme.rst b/doc/source/readme.rst deleted file mode 100644 index a6210d3..0000000 --- a/doc/source/readme.rst +++ /dev/null @@ -1 +0,0 @@ -.. include:: ../../README.rst diff --git a/doc/source/usage.rst b/doc/source/usage.rst deleted file mode 100644 index e6300a9..0000000 --- a/doc/source/usage.rst +++ /dev/null @@ -1,3 +0,0 @@ -===== -Usage -===== diff --git a/docs/get_hash.md b/docs/get_hash.md deleted file mode 100644 index f122b21..0000000 --- a/docs/get_hash.md +++ /dev/null @@ -1,86 +0,0 @@ -# tripleo.repos.get_hash - -## What is tripleo.repos.get_hash - -This utility is meant for use by TripleO deployments, particularly in zuul -continuous integration jobs. Given an [RDO named tag](https://docs.openstack.org/tripleo-docs/latest/ci/stages-overview.html#rdo-dlrn-promotion-criteria), -such as 'current-tripleo' or 'tripleo-ci-testing' it will return the hash -information, including the commit, distro and full hashes where available. - -It includes a simple command line interface. If you clone the source you can -try it out of the box without installation invoking it as a module: -``` - tripleo-get-hash # by default centos8, master, current-tripleo. - tripleo-get-hash --component tripleo --release victoria --os-version centos8 - tripleo-get-hash --release master --os-version centos7 - tripleo-get-hash --release train # by default centos8 - tripleo-get-hash --os-version rhel8 --release osp16-2 --dlrn-url http://osp-trunk.hosted.upshift.rdu2.redhat.com - tripleo-get-hash --help -``` - -## Quick start - -#### Install using setup.py - -It is recommended to perform a user/local installation using python setup.py -to avoid the use of sudo. However you may need to set your PYTHONPATH depending -on where the python code is installed on your system. - -``` -python setup.py install --user -tripleo-get-hash --help -``` -The tripleo-get-hash utility uses a yaml configuration file named 'config.yaml'. -If you install this utility using --user as above, the configuration file -is placed in $HOME/.local/etc/tripleo_get_hash/config.yaml (on fedora). -If this cannot be found then the config is used directly from the source directory. -When you invoke tripleo-get-hash it will tell you which config is in use: -``` -$ tripleo-get-hash -2021-10-15 16:22:23,724 - tripleo-get-hash - INFO - Using config file at /home/username/.local/etc/tripleo_get_hash/config.yaml -``` - -#### Install using pip - -You can also install using python pip - you can see the -[tripleo-get-hash module here](https://pypi.org/project/tripleo-repos/) - -``` - pip install tripleo-repos --user -``` - -After installation you can invoke tripleo-get-hash --help to see the various -options: -``` - tripleo-get-hash --help -``` - -By default this queries the delorean server at "https://trunk.rdoproject.org", -with this URL specified in config.yaml. To use a different delorean server you -can either update config.yaml or use the --dlrn-url parameter to the cli. If -instead you are instantiating TripleOHashInfo objects in code, you can create -the objects passing an existing 'config' dictionary. Note this has to contain -all of constants.CONFIG_KEYS to avoid explosions. - -## Ansible Module - -It is required that you install `tripleo.repos` collection to use the ansible -module. - -See the [example playbook](https://opendev.org/openstack/tripleo-repos/src/branch/master/playbooks/example_get_hash.yaml) included here for examples of -usage. You can also test the ansible module is available and working correctly -from using shell: - -``` -$ ansible localhost -m tripleo.repos.get_hash -a "component=compute release=victoria" -localhost | SUCCESS => { - "changed": false, - "commit_hash": "e954a56fec69637ebd671643d41bb0ecc85a2656", - "distro_hash": "de7baf4889fba4d42ac39c9e912c42e38abb5193", - "dlrn_url": "https://trunk.rdoproject.org/centos8-victoria/component/compute/current-tripleo/commit.yaml", - "error": "", - "extended_hash": "None", - "full_hash": "e954a56fec69637ebd671643d41bb0ecc85a2656_de7baf48", - "success": true -} -``` diff --git a/docs/yum_config.md b/docs/yum_config.md deleted file mode 100644 index b140ce9..0000000 --- a/docs/yum_config.md +++ /dev/null @@ -1,107 +0,0 @@ -# tripleo.repos.yum_config - -*tripleo-yum-config* utility was designed to simplify the way that TripleO -deployments manage their yum configuration. This tool helps on updating -specific configuration options for different yum configuration files like yum -repos, yum modules and yum global configuration file. - -## Quick start - -### Using as a python module - -It is possible to use *tripleo-yum-config* as a standalone module by cloning -its repository and invoking in command line: -* **repo** - - This subcommand lets you enable or disable a repo and sets its configuration options. - The *tripleo-yum-config* module will search for the provided repo name in all *.repo* files at REPO_DIR_PATH. - Optionally, you can provide a path where your repo files live or specify the full path of the repo file. - By default REPO_DIR_PATH is set to */etc/yum.repos.d/*. - - Examples: - ``` - sudo python -m tripleo_yum_config repo --name appstream --enable --set-opts baseurl=http://newbaseurl exclude="package*" - sudo python -m tripleo_yum_config repo --name epel --disable --config-dir-path=/path/to/yum.repos.d - ``` - The parameter *--down-url* can be used to retrieve a configuration file from a URL and populate the destination - configuration file with all its content. When used together with *--name*, only the requested repo name will be - updated in the process. - Examples: - ``` - sudo python -m tripleo_yum_config repo --down-url http://remoterepofile.repo --enable --set-opts priority=20 --config-file-path=/path/to/file.repo - sudo python -m tripleo_yum_config repo --name appstream --down-url http://remoterepofile.repo --enable - ``` - -* **module** - - This subcommand lets you enable, disable, remove, install or reset a module. - Depending on the selected operation and module, the optional parameters 'stream' or 'profile' will also need to be provided: - 1. when enabling a module, the *stream* version will be required if the module has zero or more than one default stream. - 2. when installing a module, the *profile* will be required if the enabled stream has no default profile set. - - Examples: - ``` - sudo tripleo-yum-config module remove tomcat - sudo tripleo-yum-config module disable tomcat - sudo tripleo-yum-config module enable nginx --stream mainline - sudo tripleo-yum-config module install nginx --profile common - ``` -* **global** - - This subcommand lets you set any global yum/dnf configuration value under *[main]* section. - If no configuration file is found by the module, a new one is created and populated. - Optionally you can also provide the path to the configuration file. - By default CONFIG_FILE_PATH is set to */etc/yum.conf* - - Example: - ``` - sudo python -m tripleo_yum_config global --set-opts keepcache=1 cachedir="/var/cache/dnf" - ``` - -* **enable-compose-repos** - - This subcommand will enable a list os yum repos based on the metadata retrieved from the `compose-url`. - The *tripleo-yum-config* module will create new repo files at REPO_DIR_PATH and enable them. - Optionally, you can provide a path where your repo files live, specify the variants that should be created and which repos need to be disabled afterwards. - By default REPO_DIR_PATH is set to */etc/yum.repos.d/*. - - Example: - ``` - sudo python -m tripleo_yum_config enable-compose-repos --compose-url https://composes.centos.org/latest-CentOS-Stream-8/compose/ --release centos-stream-8 --disable-all-conflicting - ``` - -#### Install using setup.py - -Installation using python setup.py requires sudo, because the python source -is installed at /usr/local/lib/python. - -``` -sudo python setup.py install -``` - -#### Install using pip -Alternatively you can install tripleo-yum-config with python pip: -``` -pip install tripleo-repos --user -``` -See PyPI [tripleo-repos](https://pypi.org/project/tripleo-repos/) -project for more details. - -## Usage - -The utility provides a command line interface with various options. You can -invoke *tripleo-yum-config --help* to see all the available commands. -``` -tripleo-yum-config --help -``` - -## Ansible Module - -It is required that you install `tripleo.repos` collection to use the ansible -module. - -An ansible module [tripleo.repos.yum_config](https://opendev.org/openstack/tripleo-repos/src/branch/master/modules/module/modules/yum_config.py) -is available for you when you install `tripleo.repos` collection. - -An [example playbook](https://opendev.org/openstack/tripleo-repos/src/branch/master/playbooks/example_yum_config.yaml) -is available to assist with module usage. diff --git a/galaxy.yml b/galaxy.yml deleted file mode 100644 index bc4df7e..0000000 --- a/galaxy.yml +++ /dev/null @@ -1,39 +0,0 @@ -name: repos -namespace: tripleo -version: 0.0.5 -readme: README.md -authors: - - Red Hat -description: TripleO Repos -build_ignore: - - "*.egg-info" - - .DS_Store - - .eggs - - .gitignore - - .gitreview - - .mypy_cache - - .pytest_cache - - .stestr - - .stestr.conf - - .tox - - .vscode - - MANIFEST.in - - build - - dist - - doc - - report.html - - setup.cfg - - setup.py - - "tests/unit/*.*" - - README.rst - - tox.ini - - tripleo_repos - - zuul.d - # excluded because galaxy server refuses uploads with __main___ inside - - plugins/module_utils/tripleo_repos/get_hash/__main__.py - - plugins/module_utils/tripleo_repos/yum_config/__main__.py - # that is not needed for ansible modules and it would upset sanity (pylint) - - plugins/module_utils/tripleo_repos/main.py - -repository: https://opendev.org/openstack/tripleo-repos -license_file: LICENSE diff --git a/meta/runtime.yml b/meta/runtime.yml deleted file mode 100644 index 1a15205..0000000 --- a/meta/runtime.yml +++ /dev/null @@ -1 +0,0 @@ -requires_ansible: ">=2.9.0" diff --git a/molecule/default/assert_ini_key_value.yml b/molecule/default/assert_ini_key_value.yml deleted file mode 100644 index 1d979d5..0000000 --- a/molecule/default/assert_ini_key_value.yml +++ /dev/null @@ -1,23 +0,0 @@ ---- - - name: Get the content of {{ item.name }} repo - command: "cat {{ item.path }}" - register: file_output - - - name: Print {{ item.name }} repo content - debug: - msg: - - "Content of {{ item.name }} repo located at '{{ item.path }}'" - - "{{ file_output.stdout_lines }}" - - - set_fact: - tmp_repo_file: /tmp/{{ item.name|lower }}.temp - - - name: Retrieve remote repo ini file - fetch: - src: "{{ item.path }}" - dest: "{{ tmp_repo_file }}" - flat: yes - - - assert: - that: - - "{{ lookup('ini', '{{ item.key }} section={{ item.section|lower }} file={{ tmp_repo_file }}') }} == {{ item.value }}" diff --git a/molecule/default/converge.yml b/molecule/default/converge.yml deleted file mode 100644 index 3c53927..0000000 --- a/molecule/default/converge.yml +++ /dev/null @@ -1,86 +0,0 @@ ---- -- name: Converge - hosts: all - tasks: - - name: "Check get_hash" - tripleo.repos.get_hash: - release: master - - - name: "Check get_hash with invalid url" - tripleo.repos.get_hash: - release: master - dlrn_url: 'https://httpbin.org/status/404' - register: result - failed_when: result is success - - - name: "Test disable system repo" - become: true - tripleo.repos.yum_config: - type: repo - name: "{{ 'rt' if (ansible_distribution_major_version is version(8, '>=')) else 'cr' }}" - enabled: false - tags: - # TODO: fix yum_config to correctly report changed state and uncomment - # the line below which disables molecule idempotence test. - - molecule-idempotence-notest - - - name: "Test create new repo file" - become: true - tripleo.repos.yum_config: - type: repo - name: "fakerepo" - # Keep it disabled to not affect any other test - enabled: false - file_path: "/etc/yum.repos.d/fake_repo.repo" - set_options: - baseurl: "http://fakemirror/fakerepo" - priority: "10" - gpgcheck: "0" - exclude: "fakepkg*" - tags: - # TODO: fix yum_config to correctly report changed state and uncomment - # the line below which disables molecule idempotence test. - - molecule-idempotence-notest - - - name: "Test yum-config global config" - become: true - tripleo.repos.yum_config: - type: global - file_path: "{{ '/etc/dnf/dnf.conf' if (ansible_distribution_major_version is version(8, '>=')) else '/etc/yum.conf' }}" - set_options: - skip_if_unavailable: "False" - fake_conf: "True" - tags: - # TODO: fix yum_config to correctly report changed state and uncomment - # the line below which disables molecule idempotence test. - - molecule-idempotence-notest - - - name: "Test yum_config enable-compose-repos" - become: true - tripleo.repos.yum_config: - type: enable-compose-repos - compose_url: https://composes.centos.org/latest-CentOS-Stream-8/compose/ - centos_release: centos-stream-8 - variants: - - AppStream - - BaseOS - disable_repos: - - /etc/yum.repos.d/CentOS-Stream-AppStream.repo - - /etc/yum.repos.d/CentOS-Stream-BaseOS.repo - tags: - - molecule-idempotence-notest - # NOTE: operation available only for CentOS >= 8 - when: ansible_distribution_major_version is version(8, '>=') - - name: "Test create repo from repo file" - become: true - tripleo.repos.yum_config: - type: repo - enabled: true - file_path: "/etc/yum.repos.d/delorean.repo" - down_url: "https://trunk.rdoproject.org/centos8-master/current-tripleo/delorean.repo" - set_options: - priority: "20" - tags: - # TODO: fix yum_config to correctly report changed state and uncomment - # the line below which disables molecule idempotence test. - - molecule-idempotence-notest diff --git a/molecule/default/molecule.yml b/molecule/default/molecule.yml deleted file mode 100644 index 7ffa7ba..0000000 --- a/molecule/default/molecule.yml +++ /dev/null @@ -1,14 +0,0 @@ ---- -dependency: - name: galaxy -driver: - name: docker -platforms: - - name: instance - image: quay.io/centos/centos:stream8 - - name: instance_c7 - image: quay.io/centos/centos:centos7 -provisioner: - name: ansible -verifier: - name: ansible diff --git a/molecule/default/prepare.yml b/molecule/default/prepare.yml deleted file mode 100644 index 4b97247..0000000 --- a/molecule/default/prepare.yml +++ /dev/null @@ -1,7 +0,0 @@ -- hosts: instance_c7 - tasks: - - name: Update ca-certificates - become: true - package: - name: ca-certificates - state: latest diff --git a/molecule/default/verify.yml b/molecule/default/verify.yml deleted file mode 100644 index 587a86c..0000000 --- a/molecule/default/verify.yml +++ /dev/null @@ -1,47 +0,0 @@ ---- -- name: Verify - hosts: all - tasks: - - name: Check if RT or CR repos are disabled - vars: - section_name: "{{ 'rt' if (ansible_distribution_major_version is version(8, '>=')) else 'cr' }}" - repo_path: /etc/yum.repos.d/CentOS-{{ 'Stream-RealTime' if (ansible_distribution_major_version is version(8, '>=')) else 'CR' }}.repo - include_tasks: assert_ini_key_value.yml - with_items: - - name: "{{ section_name|upper }}" - path: "{{ repo_path }}" - section: "{{ section_name }}" - key: enabled - value: "0" - - - name: Check if yum/dnf conf file was updated - vars: - conf_file_path: "{{ '/etc/dnf/dnf.conf' if (ansible_distribution_major_version is version(8, '>=')) else '/etc/yum.conf' }}" - include_tasks: assert_ini_key_value.yml - with_items: - - name: global_conf - path: "{{ conf_file_path }}" - section: main - key: skip_if_unavailable - value: "False" - - name: global_conf - path: "{{ conf_file_path }}" - section: main - key: fake_conf - value: "True" - - - name: Validate compose repos outputs - include_tasks: verify_compose_repos.yml - with_items: - - "AppStream" - - "BaseOS" - # NOTE: operation available only for CentOS >= 8 - when: ansible_distribution_major_version is version(8, '>=') - - name: Check if 'priority' was set to 20 in 'delorean-component-compute' - include_tasks: assert_ini_key_value.yml - with_items: - - name: "delorean-component-compute" - path: "/etc/yum.repos.d/delorean.repo" - section: "delorean-component-compute" - key: priority - value: "20" diff --git a/molecule/default/verify_compose_repos.yml b/molecule/default/verify_compose_repos.yml deleted file mode 100644 index 3a6dc1f..0000000 --- a/molecule/default/verify_compose_repos.yml +++ /dev/null @@ -1,26 +0,0 @@ ---- - - name: "Search for {{ item }} repos" - find: - paths: "/etc/yum.repos.d" - file_type: file - use_regex: yes - patterns: - - "^CentOS-Stream.*{{ item }}.*.repo$" - excludes: - - "CentOS-Stream-{{ item }}.repo" - register: compose_repos - failed_when: compose_repos.files|length != 1 - - - name: Validate repo file configuration - include_tasks: assert_ini_key_value.yml - with_items: - - name: "{{ item }}" - path: "{{ compose_repos.files[0].path }}" - section: "{{ item|lower }}" - key: enabled - value: "1" - - name: "{{ item }}" - path: "/etc/yum.repos.d/CentOS-Stream-{{ item }}.repo" - section: "{{ item|lower }}" - key: enabled - value: "0" diff --git a/playbooks/example_get_hash.yaml b/playbooks/example_get_hash.yaml deleted file mode 100644 index c807117..0000000 --- a/playbooks/example_get_hash.yaml +++ /dev/null @@ -1,40 +0,0 @@ ---- -- name: Example usage for tripleo-get-hash python module - hosts: localhost - tasks: - - name: get component-ci-testing for victoria compute component - tripleo.repos.get_hash: - os_version: centos8 # default: centos8 - release: victoria # default: master - component: compute # default: None - tag: component-ci-testing # default: current-tripleo - register: component_ci_testing_victoria_compute - - - debug: - msg: "Centos8 component-ci-testing victoria compute component: {{ component_ci_testing_victoria_compute['full_hash'] }}" - - - debug: - var: component_ci_testing_victoria_compute - - - name: get centos7 tripleo-ci-testing for train - tripleo.repos.get_hash: - os_version: centos7 - release: train - tag: tripleo-ci-testing - register: centos7_tripleo_ci_testing_train - - - debug: - msg: "Centos7 current-tripleo train: {{ centos7_tripleo_ci_testing_train['full_hash'] }}" - - - debug: - var: centos7_tripleo_ci_testing_train - - - name: get current-tripleo centos8 for master branch - tripleo.repos.get_hash: - register: centos8_current_tripleo_master - - - debug: - msg: "Centos8 current-tripleo master: {{ centos8_current_tripleo_master['full_hash'] }}" - - - debug: - var: centos8_current_tripleo_master diff --git a/playbooks/example_yum_config.yaml b/playbooks/example_yum_config.yaml deleted file mode 100644 index 21e25f9..0000000 --- a/playbooks/example_yum_config.yaml +++ /dev/null @@ -1,33 +0,0 @@ ---- -- name: Example usage for tripleo.repos.yum_config ansible module - hosts: localhost - tasks: - - name: Enable appstream yum repo and set exclude packages - become: true - tripleo.repos.yum_config: - type: repo - name: appstream - enabled: true - set_options: - exclude: - - nodejs* - - mariadb* - - - name: Enable and install nginx module - become: true - tripleo.repos.yum_config: - type: module - name: nginx - enabled: true - operation: install - profile: common - stream: mainline - - - name: Set yum global options in dnf.conf - become: true - tripleo.repos.yum_config: - type: global - file_path: /etc/dnf/dnf.conf - set_options: - skip_if_unavailable: "False" - keepcache: "0" diff --git a/plugins/module_utils/tripleo_repos/__init__.py b/plugins/module_utils/tripleo_repos/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/plugins/module_utils/tripleo_repos/get_hash/__init__.py b/plugins/module_utils/tripleo_repos/get_hash/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/plugins/module_utils/tripleo_repos/get_hash/__main__.py b/plugins/module_utils/tripleo_repos/get_hash/__main__.py deleted file mode 100644 index 757cf7a..0000000 --- a/plugins/module_utils/tripleo_repos/get_hash/__main__.py +++ /dev/null @@ -1,114 +0,0 @@ -# Copyright 2021 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 logging -import sys -from tripleo_repos.utils import load_logging -from tripleo_repos.get_hash.tripleo_hash_info import TripleOHashInfo -import tripleo_repos.get_hash.exceptions as exc - - -def _validate_args(parsed_args): - if parsed_args.os_version == 'centos7' and ( - parsed_args.component is not None - ): - raise exc.TripleOHashInvalidParameter( - 'Cannot specify component for centos 7' - ) - - -def main(): - load_logging(module_name="tripleo-get-hash") - config = TripleOHashInfo.load_config() - parser = argparse.ArgumentParser(description='tripleo-get-hash.py') - parser.add_argument( - '--component', - help=('Use this to specify a component ' - 'This is NOT valid for Centos 7.'), - choices=config['tripleo_ci_components'], - ) - parser.add_argument( - '--dlrn-url', - help=( - 'The URL for the delorean server to use. Defaults to ' - 'https://trunk.rdoproject.org' - ), - ) - parser.add_argument( - '--os-version', - default='centos8', - choices=config['os_versions'], - help=('The operating system and version to fetch the build tag for'), - ) - parser.add_argument( - '--tag', - default='current-tripleo', - choices=config['rdo_named_tags'], - help=('The known tag to retrieve the hash_info for'), - ) - parser.add_argument( - '--release', - default='master', - help=('The release of OpenStack you want the hash info for. ' - 'Default master'), - choices=config['tripleo_releases'], - ) - parser.add_argument( - '--verbose', - action='store_true', - help=('Enable verbose log level for debugging'), - ) - - args = parser.parse_args() - - if args.verbose: - logging.getLogger().setLevel(logging.DEBUG) - logging.debug("Logging level set to DEBUG") - _validate_args(args) - - if args.dlrn_url is not None: - logging.debug( - "Overriding configuration dlrn_url. Original value {}. " - "New value {}".format(config['dlrn_url'], args.dlrn_url) - ) - config['dlrn_url'] = args.dlrn_url - logging.debug( - "Proceeding with the following configuration: {}".format(config) - ) - - tripleo_hash_info = TripleOHashInfo( - args.os_version, - args.release, - args.component, - args.tag, - config, - ) - print(tripleo_hash_info) - return tripleo_hash_info - - -def cli_entrypoint(): - try: - main() - sys.exit(0) - except KeyboardInterrupt: - logging.info("Exiting on user interrupt") - raise - - -if __name__ == "__main__": - main() diff --git a/plugins/module_utils/tripleo_repos/get_hash/config.yaml b/plugins/module_utils/tripleo_repos/get_hash/config.yaml deleted file mode 100644 index 63d6350..0000000 --- a/plugins/module_utils/tripleo_repos/get_hash/config.yaml +++ /dev/null @@ -1,53 +0,0 @@ -# This file is installed to the path in [options.data_files] of the project -# setup.cfg file. It *must* contain all the keys specified in constants -# CONFIG_KEYS or there will be explosions. - -dlrn_url: 'https://trunk.rdoproject.org' - -tripleo_releases: - - master - - zed - - wallaby - - victoria - - ussuri - - train - - stein - - queens - - osp16-2 - - osp17 - - osp17-1 - - osp18 - -tripleo_ci_components: - - baremetal - - cinder - - clients - - cloudops - - common - - compute - - glance - - manila - - network - - octavia - - security - - swift - - tempest - - tripleo - - ui - - validation - -rdo_named_tags: - - current - - consistent - - component-ci-testing - - promoted-components - - tripleo-ci-testing - - current-tripleo - - current-tripleo-rdo - -os_versions: - - centos7 - - centos8 - - centos9 - - rhel8 - - rhel9 diff --git a/plugins/module_utils/tripleo_repos/get_hash/constants.py b/plugins/module_utils/tripleo_repos/get_hash/constants.py deleted file mode 100644 index 534b57f..0000000 --- a/plugins/module_utils/tripleo_repos/get_hash/constants.py +++ /dev/null @@ -1,90 +0,0 @@ -# Copyright 2021 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. -# -# -from __future__ import (absolute_import, division, print_function) - - -__metaclass__ = type - - -""" -These are the keys we expect to find in a well-formed config.yaml -If any keys are missing from the configuration hash resolution doesn't proceed. -""" -CONFIG_KEYS = [ - 'dlrn_url', - 'tripleo_releases', - 'tripleo_ci_components', - 'rdo_named_tags', - 'os_versions', -] - -""" -This is the path that we expect to find the system installed config.yaml. -The path is specified in [options.data_files] of the project setup.cfg. -""" -CONFIG_PATH = '/usr/local/etc/tripleo_get_hash/config.yaml' - -DEFAULT_CONFIG = { - "tripleo_releases": [ - "master", - "zed", - "wallaby", - "victoria", - "ussuri", - "train", - "stein", - "queens", - "osp16-2", - "osp17", - "osp17-1", - "osp18" - ], - "dlrn_url": "https://trunk.rdoproject.org", - "rdo_named_tags": [ - "current", - "consistent", - "component-ci-testing", - "promoted-components", - "tripleo-ci-testing", - "current-tripleo", - "current-tripleo-rdo" - ], - "tripleo_ci_components": [ - "baremetal", - "cinder", - "clients", - "cloudops", - "common", - "compute", - "glance", - "manila", - "network", - "octavia", - "security", - "swift", - "tempest", - "tripleo", - "ui", - "validation" - ], - "os_versions": [ - "centos7", - "centos8", - "centos9", - "rhel8", - "rhel9" - ] -} diff --git a/plugins/module_utils/tripleo_repos/get_hash/exceptions.py b/plugins/module_utils/tripleo_repos/get_hash/exceptions.py deleted file mode 100644 index 29f542d..0000000 --- a/plugins/module_utils/tripleo_repos/get_hash/exceptions.py +++ /dev/null @@ -1,62 +0,0 @@ -# Copyright 2021 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. -# -# -from __future__ import (absolute_import, division, print_function) - - -__metaclass__ = type - - -class Base(Exception): - """Base Exception""" - - -class TripleOHashMissingConfig(Base): - """Missing configuration file for TripleOHashInfo. This is thrown - when there is no config.yaml in constants.CONFIG_PATH or the local - directory assuming execution from a source checkout. - """ - - def __init__(self, error_msg): - super(TripleOHashMissingConfig, self).__init__(error_msg) - - -class TripleOHashInvalidConfig(Base): - """Invalid configuration file for TripleOHashInfo. This is used when - any of they keys in constants.CONFIG_KEYS is not found in config.yaml. - """ - - def __init__(self, error_msg): - super(TripleOHashInvalidConfig, self).__init__(error_msg) - - -class TripleOHashInvalidParameter(Base): - """Invalid parameters passed for TripleOHashInfo. This is thrown when - the user passed invalid combination ofparameters parameters to the cli - entrypoint, for example specifying --component with centos7. - """ - - def __init__(self, error_msg): - super(TripleOHashInvalidParameter, self).__init__(error_msg) - - -class TripleOHashInvalidDLRNResponse(Base): - """Invalid response received from the DLRN server. This is seen if - the delorean server replies with a status code other than 200 OK for - a query to commit.yaml or delorean.repo.md5. - """ - - def __init__(self, error_msg): - super(TripleOHashInvalidDLRNResponse, self).__init__(error_msg) diff --git a/plugins/module_utils/tripleo_repos/get_hash/tripleo_hash_info.py b/plugins/module_utils/tripleo_repos/get_hash/tripleo_hash_info.py deleted file mode 100644 index 71edb2c..0000000 --- a/plugins/module_utils/tripleo_repos/get_hash/tripleo_hash_info.py +++ /dev/null @@ -1,226 +0,0 @@ -# Copyright 2021 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. -# -# -from __future__ import (absolute_import, division, print_function) - -import logging -import os -from .constants import CONFIG_PATH, CONFIG_KEYS, DEFAULT_CONFIG -from .exceptions import ( - TripleOHashInvalidConfig, TripleOHashInvalidDLRNResponse -) -try: - from tripleo_repos.utils import http_get -except ImportError: - from ansible_collections.tripleo.repos.plugins.module_utils. \ - tripleo_repos.utils import http_get - - -__metaclass__ = type - - -class TripleOHashInfo: - """ - Objects of type TripleOHashInfo contain the attributes required to - represent a particular delorean build hash. This includes the full, commit, - distro and extended hashes (where applicable), as well as the release, - OS name and version, component name (if applicable), named tag - (current-tripleo, tripleo-ci-testing etc) as well as the URL to the - delorean server that provided the information used to build each object - instance. - """ - - @classmethod - def load_yaml(cls, filename): - import yaml - return yaml.safe_load(filename) - - @classmethod - def _resolve_local_config_path(cls): - """ Load local config from disk from expected locations. """ - paths = [ - # pip install --user - os.path.expanduser( - "~/.local/etc/tripleo_get_hash/config.yaml"), - # root install - "/etc/tripleo_get_hash/config.yaml", - # embedded config.yaml as fallback - os.path.join( - os.path.dirname(os.path.abspath(__file__)), "config.yaml") - ] - for _local_config in paths: - if cls._check_read_file(_local_config): - return _local_config - - @classmethod - def _check_read_file(cls, filepath): - if os.path.isfile(filepath) and os.access(filepath, os.R_OK): - return True - return False - - @classmethod - def load_config(cls, passed_config=None): - """ - This is a class method since we call it from the CLI entrypoint - before the TripleOHashInfo object is created. The method will first - try to use constants.CONFIG_PATH. If that is missing it tries to use - a local config.yaml for example for invocations from a source checkout - directory. If the file is not found TripleOHashMissingConfig is raised. - If any of the contants.CONFIG_KEYS is missing from config.yaml then - TripleOHashInvalidConfig is raised. If the passed_config dict contains - a given config value then that is used instead of the value from the - loaded config file. Returns a dictionary containing - the key->value for all the keys in constants.CONFIG_KEYS. - - :param passed_config: dict with configuration overrides - :raises TripleOHashMissingConfig for missing config.yaml - :raises TripleOHashInvalidConfig for missing keys in config.yaml - :return: a config dictionary with the keys in constants.CONFIG_KEYS - """ - - passed_config = passed_config or {} - result_config = {} - config_path = '' - local_config = cls._resolve_local_config_path() - # prefer const.CONFIG_PATH then local_config - if cls._check_read_file(CONFIG_PATH): - config_path = CONFIG_PATH - elif local_config: - config_path = local_config - else: - logging.info("Using embedded config file") - loaded_config = DEFAULT_CONFIG - logging.info("Using config file at %s", config_path) - if config_path != '': - with open(config_path, 'r') as config_yaml: - loaded_config = cls.load_yaml(config_yaml) - for k in CONFIG_KEYS: - if k not in loaded_config: - error_str = ( - "Malformed config file - missing {0}. Expected all" - "of these configuration items: {1}" - ).format( - k, ", ".join(CONFIG_KEYS) - ) - logging.error(error_str) - raise TripleOHashInvalidConfig(error_str) - # if the passed config contains the key then use that value - if passed_config.get(k): - result_config[k] = passed_config[k] - else: - result_config[k] = loaded_config[k] - return result_config - - def __init__(self, os_version, release, component, tag, config=None): - """Create a new TripleOHashInfo object - - :param os_version: The OS and version e.g. centos8 - :param release: The OpenStack release e.g. wallaby - :param component: The tripleo-ci component e.g. 'common' or None - :param tag: The Delorean server named tag e.g. current-tripleo - :param config: Use an existing config dictionary and don't load it - """ - config = TripleOHashInfo.load_config(config) - - self.os_version = os_version - self.release = release - self.component = component - self.tag = tag - - repo_url = self._resolve_repo_url(config['dlrn_url']) - self.dlrn_url = repo_url - - repo_url_response, status = http_get(repo_url) - - if status != 200: - error_str = ( - "Invalid response received from the delorean server. Queried " - "URL: {0}. Response code: {1}. Response text: {2}. Failed to " - "create TripleOHashInfo object." - ).format(repo_url, status, repo_url_response) - logging.error(error_str) - raise TripleOHashInvalidDLRNResponse(error_str) - - if repo_url.endswith('commit.yaml'): - from_commit_yaml = self._hashes_from_commit_yaml(repo_url_response) - self.full_hash = from_commit_yaml[0] - self.commit_hash = from_commit_yaml[1] - self.distro_hash = from_commit_yaml[2] - self.extended_hash = from_commit_yaml[3] - else: - self.full_hash = repo_url_response - self.commit_hash = None - self.distro_hash = None - self.extended_hash = None - - def _resolve_repo_url(self, dlrn_url): - """Resolve the delorean server URL given the various attributes of - this TripleOHashInfo object. The only passed parameter is the - dlrn_url. There are three main cases: - * centos8/rhel8 component https://trunk.rdoproject.org/centos8/component/common/current-tripleo/commit.yaml - * centos7 https://trunk.rdoproject.org/centos7/current-tripleo/commit.yaml - * centos8/rhel8 non component https://trunk.rdoproject.org/centos8/current-tripleo/delorean.repo.md5 - Returns a string which is the full URL to the required item (i.e. - commit.yaml or repo.md5 depending on the case). - - :param dlrn_url: The base url for the delorean server - :returns string URL to required commit.yaml or repo.md5 - """ # noqa - repo_url = '' - if 'centos7' in self.os_version: - repo_url = "%s/%s-%s/%s/commit.yaml" % ( - dlrn_url, - self.os_version, - self.release, - self.tag, - ) - elif self.component is not None: - repo_url = "%s/%s-%s/component/%s/%s/commit.yaml" % ( - dlrn_url, - self.os_version, - self.release, - self.component, - self.tag, - ) - else: - repo_url = "%s/%s-%s/%s/delorean.repo.md5" % ( - dlrn_url, - self.os_version, - self.release, - self.tag, - ) - logging.debug("repo_url is %s", repo_url) - return repo_url - - def _hashes_from_commit_yaml(self, delorean_result): - """This function is used when a commit.yaml file is returned - by _resolve_repo_url. Returns a tuple containing the various - extracted hashes: full, commit, distro and extended - - :returns tuple of strings full, commit, distro, extended hashes - """ - parsed_yaml = self.load_yaml(delorean_result) - commit = parsed_yaml['commits'][0]['commit_hash'] - distro = parsed_yaml['commits'][0]['distro_hash'] - full = "%s_%s" % (commit, distro[0:8]) - extended = parsed_yaml['commits'][0]['extended_hash'] - logging.debug( - "delorean commit.yaml results %s", parsed_yaml['commits'][0]) - return full, commit, distro, extended - - def __repr__(self): - """Returns a string representation of the object""" - attrs = vars(self) - return ',\n'.join('%s: %s' % item for item in attrs.items()) diff --git a/plugins/module_utils/tripleo_repos/main.py b/plugins/module_utils/tripleo_repos/main.py deleted file mode 100755 index bfd6315..0000000 --- a/plugins/module_utils/tripleo_repos/main.py +++ /dev/null @@ -1,632 +0,0 @@ -#!/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. - -from __future__ import (absolute_import, division, print_function) -import argparse -import os -import platform -import re -import subprocess -import sys - - -__metaclass__ = type -TITLE_RE = re.compile('\\[(.*)\\]') -NAME_RE = re.compile('name=(.+)') -PRIORITY_RE = re.compile('priority=\\d+') -# Packages to be included from delorean-current when using current-tripleo -INCLUDE_PKGS = ('includepkgs=instack,instack-undercloud,' - 'os-apply-config,os-collect-config,os-net-config,' - 'os-refresh-config,python*-tripleoclient,' - 'openstack-tripleo-*,openstack-puppet-modules,' - 'ansible-role-tripleo*,puppet-*,python*-tripleo-common,' - 'python*-paunch*,tripleo-ansible,ansible-config_template') -DEFAULT_OUTPUT_PATH = '/etc/yum.repos.d' -DEFAULT_RDO_MIRROR = 'https://trunk.rdoproject.org' - -# RHEL is only provided to licensed cloud providers via RHUI -DEFAULT_MIRROR_MAP = { - 'fedora': 'https://mirrors.fedoraproject.org', - 'centos7': 'http://mirror.centos.org', - 'centos8': 'http://mirror.centos.org', - 'centos9': 'http://mirror.stream.centos.org', - 'ubi8': 'http://mirror.centos.org', - 'ubi9': 'http://mirror.stream.centos.org', - 'rhel8': 'https://trunk.rdoproject.org', - 'rhel9': 'https://trunk.rdoproject.org', -} -CEPH_REPO_TEMPLATE = ''' -[tripleo-centos-ceph-%(ceph_release)s] -name=tripleo-centos-ceph-%(ceph_release)s -baseurl=%(mirror)s/centos/%(centos_release)s/storage/$basearch/ceph-%(ceph_release)s/ -gpgcheck=0 -enabled=1 -''' -CEPH_SIG_REPO_TEMPLATE = ''' -[tripleo-centos-ceph-%(ceph_release)s] -name=tripleo-centos-ceph-%(ceph_release)s -baseurl=%(mirror)s/SIGs/%(centos_release)s/storage/$basearch/ceph-%(ceph_release)s/ -gpgcheck=0 -enabled=1 -''' -CEPH_RDO_REPO_TEMPLATE = ''' -[tripleo-centos-ceph-%(ceph_release)s] -name=tripleo-centos-ceph-%(ceph_release)s -baseurl=https://trunk.rdoproject.org/centos8-master/deps/storage/%(ceph_release)s/ -gpgcheck=0 -enabled=1 -''' -OPSTOOLS_REPO_TEMPLATE = ''' -[tripleo-centos-opstools] -name=tripleo-centos-opstools -baseurl=%(mirror)s/centos/7/opstools/$basearch/ -gpgcheck=0 -enabled=1 -''' -# centos-8 only -HIGHAVAILABILITY_REPO_TEMPLATE = ''' -[tripleo-centos-highavailability] -name=tripleo-centos-highavailability -baseurl=%(mirror)s/%(legacy_url)s%(stream)s/HighAvailability/$basearch/os/ -gpgcheck=0 -enabled=1 -''' -# centos-8 only -POWERTOOLS_REPO_TEMPLATE = ''' -[tripleo-centos-powertools] -name=tripleo-centos-powertools -baseurl=%(mirror)s/%(legacy_url)s%(stream)s/%(pt_name)s/$basearch/os/ -gpgcheck=0 -enabled=1 -''' -# ubi-8 only -APPSTREAM_REPO_TEMPLATE = ''' -[tripleo-centos-appstream] -name=tripleo-centos-appstream -baseurl=%(mirror)s/%(legacy_url)s%(stream)s/AppStream/$basearch/os/ -gpgcheck=0 -enabled=1 -%(extra)s -''' -BASE_REPO_TEMPLATE = ''' -[tripleo-centos-baseos] -name=tripleo-centos-baseos -baseurl=%(mirror)s/%(legacy_url)s%(stream)s/BaseOS/$basearch/os/ -gpgcheck=0 -enabled=1 -''' - - -# unversioned fedora added for backwards compatibility -SUPPORTED_DISTROS = [ - ('centos', '7'), - ('centos', '8'), - ('centos', '9'), - ('fedora', ''), - ('rhel', '8'), - ('rhel', '9'), - ('ubi', '8'), - ('ubi', '9') # a subcase of the rhel distro -] -DISTRO_CHOICES = ["".join(distro_pair) - for distro_pair in SUPPORTED_DISTROS] - - -class InvalidArguments(Exception): - pass - - -class NoRepoTitle(Exception): - pass - - -def _get_distro(): - """Get distro info from os-release - - returns: distro_id, distro_major_version_id, distro_name - """ - # Avoids a crash on unsupported platforms which would prevent even - # running with `--help`. - if not os.path.exists('/etc/os-release'): - return platform.system(), 'unknown', 'unknown' - - output = subprocess.Popen( - 'source /etc/os-release && echo -e -n "$ID\n$VERSION_ID\n$NAME"', - shell=True, - stdout=subprocess.PIPE, - stderr=open(os.devnull, 'w'), - executable='/bin/bash', - universal_newlines=True).communicate() - - # distro_id and distro_version_id will always be at least an empty string - distro_id, distro_version_id, distro_name = output[0].split('\n') - - # if distro_version_id is empty string the major version will be empty - # string too - distro_major_version_id = distro_version_id.split('.')[0] - - # check if that is UBI subcase? - if os.path.exists('/etc/yum.repos.d/ubi.repo'): - distro_id = 'ubi' - - if (distro_id, distro_major_version_id) not in SUPPORTED_DISTROS: - print( - "WARNING: Unsupported platform '{0}{1}' detected by tripleo-repos," - " centos7 will be used unless you use CLI param to change it." - "".format(distro_id, distro_major_version_id), file=sys.stderr) - distro_id = 'centos' - distro_major_version_id = '7' - - if distro_id == 'ubi': - print( - "WARNING: Centos{0} Base and AppStream will be installed for " - "this UBI distro".format(distro_major_version_id)) - - return distro_id, distro_major_version_id, distro_name - - -def _parse_args(distro_id, distro_major_version_id): - - distro = "{0}{1}".format(distro_id, distro_major_version_id) - - parser = argparse.ArgumentParser( - description='Download and install repos necessary for TripleO. Note ' - 'that some of these repos require yum-plugin-priorities, ' - 'so that will also be installed.', - formatter_class=argparse.ArgumentDefaultsHelpFormatter) - parser.add_argument('repos', metavar='REPO', nargs='+', - choices=['current', 'deps', 'current-tripleo', - 'current-tripleo-dev', 'ceph', 'opstools', - 'tripleo-ci-testing', 'current-tripleo-rdo'], - help='A list of repos. Available repos: ' - '%(choices)s. The deps repo will always be ' - 'included when using current or ' - 'current-tripleo. current-tripleo-dev ' - 'downloads the current-tripleo, current, and ' - 'deps repos, but sets the current repo to only ' - 'be used for TripleO projects. It also modifies ' - 'each repo\'s priority so packages are installed ' - 'from the appropriate location.') - parser.add_argument('-d', '--distro', - default=distro, - choices=DISTRO_CHOICES, - nargs='?', - help='Target distro with default detected at runtime. ' - ) - parser.add_argument('-b', '--branch', - default='master', - help='Target branch. Should be the lowercase name of ' - 'the OpenStack release. e.g. liberty') - parser.add_argument('-o', '--output-path', - default=DEFAULT_OUTPUT_PATH, - help='Directory in which to save the selected repos.') - parser.add_argument('--mirror', - help='Server from which to install base OS packages. ' - 'Default value is based on distro param.') - parser.add_argument('--rdo-mirror', - default=DEFAULT_RDO_MIRROR, - help='Server from which to install RDO packages.') - stream_group = parser.add_mutually_exclusive_group() - stream_group.add_argument('--stream', - action='store_true', - default=True, - help='Enable stream support for CentOS repos') - stream_group.add_argument('--no-stream', - action='store_true', - default=False, - help='Disable stream support for CentOS repos') - - args = parser.parse_args() - if args.no_stream: - args.stream = False - - # Default mirror for args.distro (which defaults to 'distro') - default_mirror = DEFAULT_MIRROR_MAP.get(args.distro, None) - if default_mirror is None and 'fedora' in args.distro: - # We don't have different mirrors for specific fedora releases - default_mirror = DEFAULT_MIRROR_MAP.get('fedora', None) - - if args.mirror is None: - args.mirror = default_mirror - args.old_mirror = default_mirror - - return args - - -def _get_repo(path, args): - - # lazy import - if 'requests' not in globals(): - import requests - - r = requests.get(path) - if r.status_code == 200: - return _inject_mirrors(r.text, args) - else: - r.raise_for_status() - - -def _write_repo(content, target, name=None): - if not name: - m = TITLE_RE.search(content) - if not m: - raise NoRepoTitle('Could not find repo title in: \n%s' % content) - name = m.group(1) - # centos-8 dlrn repos have changed. repos per component - # are folded into a single repo. - if 'component' in name: - name = 'delorean' - filename = name + '.repo' - filename = os.path.join(target, filename) - with open(filename, 'w') as f: - f.write(content) - print('Installed repo %s to %s' % (name, filename)) - - -def _validate_distro_repos(args): - """Validate requested repos are valid for the distro""" - valid_repos = [] - if 'fedora' in args.distro: - valid_repos = ['current', 'current-tripleo', 'ceph', 'deps', - 'tripleo-ci-testing'] - elif args.distro in DISTRO_CHOICES: - valid_repos = ['ceph', 'current', 'current-tripleo', - 'current-tripleo-dev', 'deps', 'tripleo-ci-testing', - 'opstools', 'current-tripleo-rdo'] - invalid_repos = [x for x in args.repos if x not in valid_repos] - if len(invalid_repos) > 0: - raise InvalidArguments( - '{0} repo(s) are not valid for {1}. Valid repos ' - 'are: {2}'.format(invalid_repos, args.distro, valid_repos)) - return True - - -def _validate_current_tripleo(repos): - """Validate current usage - - current and current-tripleo cannot be specified with each other and - current-tripleo-dev is a mix of current, current-tripleo and deps - so they should not be specified on the command line with each other. - """ - if 'current-tripleo' in repos and 'current' in repos: - raise InvalidArguments('Cannot use current and current-tripleo at the ' - 'same time.') - if 'current-tripleo-dev' not in repos: - return True - if 'current' in repos or 'current-tripleo' in repos or 'deps' in repos: - raise InvalidArguments('current-tripleo-dev should not be used with ' - 'any other RDO Trunk repos.') - return True - - -def _validate_tripleo_ci_testing(repos): - """Validate tripleo-ci-testing - - With tripleo-ci-testing for repo (currently only periodic container build) - no other repos expected except optionally deps|ceph|opstools - which is enabled regardless. - """ - if 'tripleo-ci-testing' in repos and len(repos) > 1: - if 'deps' in repos or 'ceph' in repos or 'opstools' in repos: - return True - else: - raise InvalidArguments('Cannot use tripleo-ci-testing at the ' - 'same time as other repos, except ' - 'deps|ceph|opstools.') - return True - - -def _validate_distro_stream(args, distro_name, distro_major_version_id): - """Validate stream related args vs host - - Fails if stream is to be used but the host isn't a stream OS or vice versa - """ - if args.output_path != DEFAULT_OUTPUT_PATH: - # don't validate distro name because the output path is not - # /etc/yum.repos.d, so the repo files may not be used to install - # packages on this host - return True - if 'centos' not in distro_name.lower(): - return True - if distro_name.lower() == 'centos' and distro_major_version_id != '8': - return True - is_stream = args.stream and not args.no_stream - if is_stream and 'stream' not in distro_name.lower(): - raise InvalidArguments('--stream provided, but OS is not the Stream ' - 'version. Please ensure the host is Stream.') - elif not is_stream and 'stream' in distro_name.lower(): - raise InvalidArguments('--no-stream provided, but OS is the Stream ' - 'version. Please ensure the host is not the ' - 'Stream version.') - return True - - -def _validate_args(args, distro_name, distro_major_version_id): - _validate_current_tripleo(args.repos) - _validate_distro_repos(args) - _validate_tripleo_ci_testing(args.repos) - _validate_distro_stream(args, distro_name, distro_major_version_id) - - -def _remove_existing(args): - """Remove any delorean* or opstools repos that already exist""" - if args.distro in ['ubi8', 'ubi9']: - regex = '^(BaseOS|AppStream|delorean|tripleo-centos-' \ - '(opstools|ceph|highavailability|powertools)).*.repo' - else: - regex = '^(delorean|tripleo-centos-' \ - '(opstools|ceph|highavailability|powertools)).*.repo' - pattern = re.compile(regex) - if os.path.exists("/etc/distro.repos.d"): - paths = set( - os.listdir(args.output_path) + os.listdir("/etc/distro.repos.d")) - else: - paths = os.listdir(args.output_path) - for f in paths: - if pattern.match(f): - filename = os.path.join(args.output_path, f) - if os.path.exists(filename): - os.remove(filename) - print('Removed old repo "%s"' % filename) - filename = os.path.join("/etc/distro.repos.d", f) - if os.path.exists(filename): - os.remove(filename) - print('Removed old repo "%s"' % filename) - - -def _get_base_path(args): - if args.distro in ['ubi8', 'ubi9']: - # there are no base paths for UBI that work well - distro = args.distro.replace('ubi', 'centos') - else: - distro = args.distro - - # The mirror url with /$DISTRO$VERSION path for master branch is - # deprecated. - # The default for rdo mirrors is $DISTRO$VERSION-$BRANCH - # it should work for every (distro, branch) pair that - # makes sense - # Any exception should be corrected at source, not here. - distro_branch = '%s-%s' % (distro, args.branch) - return '%s/%s/' % (args.rdo_mirror, distro_branch) - - -def _install_priorities(): - try: - subprocess.check_call(['yum', 'install', '-y', - 'yum-plugin-priorities']) - except subprocess.CalledProcessError as e: - print('ERROR: Failed to install yum-plugin-priorities\n%s\n%s' % - (e.cmd, e.output)) - raise - - -def _create_ceph(args, release): - """Generate a Ceph repo file for release""" - centos_release = '9-stream' - template = CEPH_SIG_REPO_TEMPLATE - if args.distro == 'centos7': - centos_release = '7' - template = CEPH_REPO_TEMPLATE - elif args.distro == 'centos8' and release == 'nautilus': - template = CEPH_RDO_REPO_TEMPLATE - elif args.distro == 'centos8': - centos_release = '8-stream' - template = CEPH_REPO_TEMPLATE - - return template % {'centos_release': centos_release, - 'ceph_release': release, - 'mirror': args.mirror} - - -def _change_priority(content, new_priority): - new_content = PRIORITY_RE.sub('priority=%d' % new_priority, content) - # This shouldn't happen, but let's be safe. - if not PRIORITY_RE.search(new_content): - new_content = [] - for line in content.split("\n"): - new_content.append(line) - if line.startswith('['): - new_content.append('priority=%d' % new_priority) - new_content = "\n".join(new_content) - return new_content - - -def _add_includepkgs(content): - new_content = [] - for line in content.split("\n"): - new_content.append(line) - if line.startswith('['): - new_content.append(INCLUDE_PKGS) - return "\n".join(new_content) - - -def _inject_mirrors(content, args): - """Replace any references to the default mirrors in repo content - - In some cases we want to use mirrors whose repo files still point to the - default servers. If the user specified to use the mirror, we want to - replace any such references with the mirror address. This function - handles that by using a regex to swap out the baseurl server. - """ - - content = re.sub('baseurl=%s' % DEFAULT_RDO_MIRROR, - 'baseurl=%s' % args.rdo_mirror, - content) - - if args.old_mirror: - content = re.sub('baseurl=%s' % args.old_mirror, - 'baseurl=%s' % args.mirror, - content) - - return content - - -def _install_repos(args, base_path): - def install_deps(args, base_path): - content = _get_repo(base_path + 'delorean-deps.repo', args) - _write_repo(content, args.output_path) - - for repo in args.repos: - if repo == 'current': - content = _get_repo(base_path + 'current/delorean.repo', args) - _write_repo(content, args.output_path, name='delorean') - install_deps(args, base_path) - elif repo == 'deps': - install_deps(args, base_path) - elif repo == 'current-tripleo': - content = _get_repo(base_path + 'current-tripleo/delorean.repo', - args) - _write_repo(content, args.output_path) - install_deps(args, base_path) - elif repo == 'current-tripleo-dev': - content = _get_repo(base_path + 'delorean-deps.repo', args) - _write_repo(content, args.output_path) - content = _get_repo(base_path + 'current-tripleo/delorean.repo', - args) - content = TITLE_RE.sub('[\\1-current-tripleo]', content) - content = NAME_RE.sub('name=\\1-current-tripleo', content) - # We need to twiddle priorities since we're mixing multiple repos - # that are generated with the same priority. - content = _change_priority(content, 20) - _write_repo(content, args.output_path, - name='delorean-current-tripleo') - content = _get_repo(base_path + 'current/delorean.repo', args) - content = _add_includepkgs(content) - content = _change_priority(content, 10) - _write_repo(content, args.output_path, name='delorean') - elif repo == 'tripleo-ci-testing': - content = _get_repo(base_path + 'tripleo-ci-testing/delorean.repo', - args) - _write_repo(content, args.output_path) - install_deps(args, base_path) - elif repo == 'current-tripleo-rdo': - content = _get_repo( - base_path + 'current-tripleo-rdo/delorean.repo', args) - _write_repo(content, args.output_path) - install_deps(args, base_path) - elif repo == 'ceph': - if args.branch in ['liberty', 'mitaka']: - content = _create_ceph(args, 'hammer') - elif args.branch in ['newton', 'ocata', 'pike']: - content = _create_ceph(args, 'jewel') - elif args.branch in ['queens', 'rocky']: - content = _create_ceph(args, 'luminous') - elif args.branch in ['stein', 'train', 'ussuri', 'victoria']: - content = _create_ceph(args, 'nautilus') - else: - content = _create_ceph(args, 'pacific') - _write_repo(content, args.output_path) - elif repo == 'opstools': - content = OPSTOOLS_REPO_TEMPLATE % {'mirror': args.mirror} - _write_repo(content, args.output_path) - else: - raise InvalidArguments('Invalid repo "%s" specified' % repo) - - distro = args.distro - # CentOS-8 AppStream is required for UBI-8 - legacy_url = 'centos/' - if distro in ['ubi8', 'ubi9']: - if not os.path.exists("/etc/distro.repos.d"): - print('WARNING: For UBI it is recommended to create ' - '/etc/distro.repos.d and rerun!') - dp_exists = False - else: - dp_exists = True - if args.output_path == DEFAULT_OUTPUT_PATH and dp_exists: - distro_path = "/etc/distro.repos.d" - else: - distro_path = args.output_path - # TODO: Remove it once bugs are fixed - # Add extra options to APPSTREAM_REPO_TEMPLATE because of - # rhbz/1961558 and lpbz/1929634 - extra = '' - if args.branch in ['train', 'ussuri', 'victoria']: - extra = 'exclude=edk2-ovmf-20200602gitca407c7246bf-5*' - - distro_name = str(distro[-1]) + '-stream' - content = APPSTREAM_REPO_TEMPLATE % {'mirror': args.mirror, - 'extra': extra, - 'legacy_url': legacy_url, - 'stream': distro_name} - _write_repo(content, distro_path) - content = BASE_REPO_TEMPLATE % {'mirror': args.mirror, - 'legacy_url': legacy_url, - 'stream': distro_name} - _write_repo(content, distro_path) - if distro in ['centos8', 'centos9', 'ubi8', 'ubi9']: - distro = 'centos' + str(distro[-1]) - - if 'centos' in distro: - stream = str(distro[-1]) - # HA, Powertools are required for CentOS-8 - if int(stream) >= 8: - if args.stream and not args.no_stream: - stream = stream + '-stream' - - pt_name = 'PowerTools' - if '9' in stream: - legacy_url = '' - pt_name = 'CRB' - - content = HIGHAVAILABILITY_REPO_TEMPLATE % { - 'mirror': args.mirror, - 'stream': stream, - 'legacy_url': legacy_url} - _write_repo(content, args.output_path) - - content = POWERTOOLS_REPO_TEMPLATE % {'mirror': args.mirror, - 'stream': stream, - 'legacy_url': legacy_url, - 'pt_name': pt_name} - _write_repo(content, args.output_path) - - if '9' in stream: - content = APPSTREAM_REPO_TEMPLATE % {'mirror': args.mirror, - 'extra': '', - 'legacy_url': legacy_url, - 'stream': stream} - _write_repo(content, args.output_path) - - content = BASE_REPO_TEMPLATE % {'mirror': args.mirror, - 'legacy_url': legacy_url, - 'stream': stream} - _write_repo(content, args.output_path) - - -def _run_pkg_clean(distro): - pkg_mgr = 'yum' if distro == 'centos7' else 'dnf' - try: - subprocess.check_call([pkg_mgr, 'clean', 'metadata']) - except subprocess.CalledProcessError: - print('ERROR: Failed to clean yum metadata.') - raise - - -def main(): - distro_id, distro_major_version_id, distro_name = _get_distro() - args = _parse_args(distro_id, distro_major_version_id) - _validate_args(args, distro_name, distro_major_version_id) - base_path = _get_base_path(args) - if (distro_name.lower(), distro_major_version_id) == ("centos", "7"): - _install_priorities() - _remove_existing(args) - _install_repos(args, base_path) - _run_pkg_clean(args.distro) - - -if __name__ == '__main__': - main() diff --git a/plugins/module_utils/tripleo_repos/utils.py b/plugins/module_utils/tripleo_repos/utils.py deleted file mode 100644 index 145a9da..0000000 --- a/plugins/module_utils/tripleo_repos/utils.py +++ /dev/null @@ -1,83 +0,0 @@ -# Copyright 2021 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. -# -from __future__ import (absolute_import, division, print_function) - -import logging -import sys - -__metaclass__ = type - -# portable http_get that uses either ansible recommended way or python native -# urllib. Also deals with python2 vs python3 for centos7 train jobs. -py_version = sys.version_info.major -if py_version < 3: - import urllib2 - - def http_get(url): - try: - response = urllib2.urlopen(url) - return ( - response.read().decode('utf-8'), - int(response.code)) - except Exception as e: - return (str(e), -1) -else: - try: - from ansible.module_utils.urls import open_url - - def http_get(url): - try: - response = open_url(url, method='GET') - return (response.read().decode('utf-8'), response.status) - except Exception as e: - return (str(e), -1) - except ImportError: - from urllib.request import urlopen - - def http_get(url): - try: - response = urlopen(url) - return ( - response.read().decode('utf-8'), - int(response.status)) - except Exception as e: - return (str(e), -1) - - -def load_logging(level=logging.INFO, module_name="tripleo-repos"): - """Load and set logging level. Default is set to logging.INFO level.""" - logger = logging.getLogger() - # Only add logger once to avoid duplicated streams in tests - if not logger.handlers: - stdout_handlers = [ - _handler - for _handler in logger.handlers - if - ( - hasattr(_handler, 'stream') and 'stdout' in - _handler.stream.name - ) - ] - if stdout_handlers == []: - formatter = logging.Formatter( - ( - "%(asctime)s - " + module_name + " - %(levelname)s - " - "%(message)s" - ) - ) - handler = logging.StreamHandler(sys.stdout) - handler.setFormatter(formatter) - logger.addHandler(handler) - logger.setLevel(level) diff --git a/plugins/module_utils/tripleo_repos/yum_config/__init__.py b/plugins/module_utils/tripleo_repos/yum_config/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/plugins/module_utils/tripleo_repos/yum_config/__main__.py b/plugins/module_utils/tripleo_repos/yum_config/__main__.py deleted file mode 100644 index 6ab8f11..0000000 --- a/plugins/module_utils/tripleo_repos/yum_config/__main__.py +++ /dev/null @@ -1,306 +0,0 @@ - -# Copyright 2021 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 logging -import os -import sys - -from tripleo_repos.utils import load_logging -import tripleo_repos.yum_config.constants as const -import tripleo_repos.yum_config.yum_config as cfg -import tripleo_repos.yum_config.utils as utils - - -def options_to_dict(options): - opt_dict = {} - if options: - for opt in options: - try: - k, v = opt.split('=') - except ValueError: - msg = 'Set options must be provided as "key=value" pairs' - logging.error(msg) - sys.exit(2) - opt_dict[k] = v - return opt_dict - - -def main(): - load_logging(module_name="tripleo-yum-config") - # Get release model and version - distro, major_version, __ = utils.get_distro_info() - py_version = sys.version_info.major - if py_version < 3: - logging.warning("Some operations will be disabled when running with " - "python 2.") - - # Repo arguments - repo_args_parser = argparse.ArgumentParser(add_help=False) - repo_args_parser.add_argument( - '--name', - help='name of the repo to be modified' - ) - - environment_parse = argparse.ArgumentParser(add_help=False) - environment_parse.add_argument( - '--environment-file', - dest='env_file', - default=None, - help=('path to an environment file to be read before creating repo ' - 'files'), - ) - - parser_enable_group = repo_args_parser.add_mutually_exclusive_group() - parser_enable_group.add_argument( - '--enable', - action='store_true', - dest='enable', - default=None, - help='enable a yum repo or module' - ) - parser_enable_group.add_argument( - '--disable', - action='store_false', - dest='enable', - default=None, - help='disable a yum repo or module' - ) - repo_args_parser.add_argument( - '--config-dir-path', - dest='config_dir_path', - default=const.YUM_REPO_DIR, - help=( - 'set the absolute directory path that holds all repo ' - 'configuration files') - ) - repo_args_parser.add_argument( - '--down-url', - dest='down_url', - help=( - 'URL of a repo file to be used as base to create or update ' - 'a repo configuration file.') - ) - - # Generic key-value options - options_parse = argparse.ArgumentParser(add_help=False) - options_parse.add_argument( - '--set-opts', - dest='set_opts', - nargs='+', - help='sets config options as key=value pairs for a specific ' - 'configuration file' - ) - - # dnf module parser - dnf_module_parser = argparse.ArgumentParser(add_help=False) - dnf_module_parser.add_argument( - 'operation', - choices=['enable', 'disable', 'install', 'remove', 'reset'], - help="dnf module operation to be executed" - ) - dnf_module_parser.add_argument( - 'name', - help='name of the module to be modified' - ) - dnf_module_parser.add_argument( - '--stream', - help="sets module stream" - ) - dnf_module_parser.add_argument( - '--profile', - help="sets module profile" - ) - - # Compose repo arguments - compose_args_parser = argparse.ArgumentParser(add_help=False) - compose_args_parser.add_argument( - '--compose-url', - dest='compose_url', - required=True, - help='CentOS compose URL' - ) - compose_args_parser.add_argument( - '--release', - dest='release', - choices=const.COMPOSE_REPOS_RELEASES, - default='centos-stream-8', - help='target CentOS release.' - ) - compose_args_parser.add_argument( - '--arch', - choices=const.COMPOSE_REPOS_SUPPORTED_ARCHS, - default='x86_64', - help='set the architecture for the destination repos.' - ) - compose_args_parser.add_argument( - '--disable-repos', - nargs='+', - help='list of repo names or repo absolute file paths to be disabled.' - ) - compose_args_parser.add_argument( - '--disable-all-conflicting', - action='store_true', - dest='disable_conflicting', - default=False, - help='after enabling compose repos, disable all other repos that ' - 'match variant names.' - ) - compose_args_parser.add_argument( - '--variants', - nargs='+', - help='Name of the repos to be enabled. Default behavior is to enable ' - 'all that match a specific release and architecture.' - ) - compose_args_parser.add_argument( - '--config-dir-path', - dest='config_dir_path', - default=const.YUM_REPO_DIR, - help='set the absolute directory path that holds all repo ' - 'configuration files' - ) - - # Common file path argument - common_parse = argparse.ArgumentParser(add_help=False) - common_parse.add_argument( - '--config-file-path', - dest='config_file_path', - help=('set the absolute file path of the configuration file to be ' - 'updated.') - ) - - # Main parser - main_parser = argparse.ArgumentParser() - main_parser.add_argument( - '--verbose', '-v', - action='store_true', - default=False, - help='enable verbose log level for debugging', - ) - subparsers = main_parser.add_subparsers(dest='command') - - # Subcommands - subparsers.add_parser( - 'repo', - parents=[common_parse, environment_parse, repo_args_parser, - options_parse], - help='updates a yum repository options' - ) - subparsers.add_parser( - 'global', - parents=[common_parse, environment_parse, options_parse], - help='updates global yum configuration options' - ) - - if py_version >= 3: - subparsers.add_parser( - 'enable-compose-repos', - parents=[compose_args_parser, environment_parse], - help='enable CentOS compose repos based on an compose url.' - ) - - for min_distro_ver in const.DNF_MODULE_MINIMAL_DISTRO_VERSIONS: - if (distro == min_distro_ver.get('distro') and int( - major_version) >= min_distro_ver.get('min_version')): - subparsers.add_parser( - 'module', - parents=[dnf_module_parser], - help='updates yum module options' - ) - break - - args = main_parser.parse_args() - if args.command is None: - main_parser.print_help() - sys.exit(2) - - if args.verbose: - logging.getLogger().setLevel(logging.DEBUG) - logging.debug('Logging level set to DEBUG') - - if args.command == 'repo': - set_dict = options_to_dict(args.set_opts) - config_obj = cfg.TripleOYumRepoConfig( - dir_path=args.config_dir_path, - environment_file=args.env_file) - if args.name is not None: - config_obj.add_or_update_section(args.name, set_dict=set_dict, - file_path=args.config_file_path, - enabled=args.enable, - from_url=args.down_url) - else: - # When no section (name) is provided, we consider all sections from - # repo file downloaded from the URL, otherwise fail. - if args.down_url is None: - logging.error("You must provide a repo 'name' or a valid " - "'url' where repo info can be downloaded.") - sys.exit(2) - config_obj.add_or_update_all_sections_from_url( - args.down_url, file_path=args.config_file_path, - set_dict=set_dict, enabled=args.enable) - - elif args.command == 'module': - import tripleo_repos.yum_config.dnf_manager as dnf_mgr - dnf_mod_mgr = dnf_mgr.DnfModuleManager() - dnf_method = getattr(dnf_mod_mgr, args.operation + "_module") - dnf_method(args.name, stream=args.stream, profile=args.profile) - - elif args.command == 'global': - set_dict = options_to_dict(args.set_opts) - config_obj = cfg.TripleOYumGlobalConfig( - file_path=args.config_file_path, - environment_file=args.env_file) - - config_obj.update_section('main', set_dict) - - elif args.command == 'enable-compose-repos': - import tripleo_repos.yum_config.compose_repos as compose_repos - repo_obj = compose_repos.TripleOYumComposeRepoConfig( - args.compose_url, - args.release, - dir_path=args.config_dir_path, - arch=args.arch, - environment_file=args.env_file) - - repo_obj.enable_compose_repos(variants=args.variants, - override_repos=args.disable_conflicting) - if args.disable_repos: - for file in args.disable_repos: - valid_path = None - rel_path = os.path.join(args.config_dir_path, file) - - if cfg.validated_file_path(file): - valid_path = file - elif cfg.validated_file_path(rel_path): - valid_path = rel_path - - if valid_path is not None: - repo_obj.update_all_sections(valid_path, enabled=False) - - -def cli_entrypoint(): - try: - main() - sys.exit(0) - except KeyboardInterrupt: - logging.info("Exiting on user interrupt") - sys.exit(2) - except Exception as e: - logging.error(str(e)) - sys.exit(2) - - -if __name__ == "__main__": - cli_entrypoint() diff --git a/plugins/module_utils/tripleo_repos/yum_config/compose_repos.py b/plugins/module_utils/tripleo_repos/yum_config/compose_repos.py deleted file mode 100644 index 75d5e2c..0000000 --- a/plugins/module_utils/tripleo_repos/yum_config/compose_repos.py +++ /dev/null @@ -1,206 +0,0 @@ -# Copyright 2021 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. -# -from __future__ import (absolute_import, division, print_function) - -import logging -import json -import os -import re - -from .constants import ( - YUM_REPO_DIR, - YUM_REPO_FILE_EXTENSION, - YUM_REPO_SUPPORTED_OPTIONS, - COMPOSE_REPOS_RELEASES, - COMPOSE_REPOS_INFO_PATH, - COMPOSE_REPOS_URL_PATTERN, - COMPOSE_REPOS_URL_REPLACE_STR, -) -from .exceptions import ( - TripleOYumConfigInvalidSection, - TripleOYumConfigComposeError, -) -from .yum_config import ( - TripleOYumConfig -) - -__metaclass__ = type - - -class TripleOYumComposeRepoConfig(TripleOYumConfig): - """Manages yum repo configuration files for CentOS Compose.""" - - def __init__(self, compose_url, release, dir_path=None, arch=None, - environment_file=None): - conf_dir_path = dir_path or YUM_REPO_DIR - self.arch = arch or 'x86_64' - - # 1. validate release name - if release not in COMPOSE_REPOS_RELEASES: - msg = 'CentOS release not supported.' - raise TripleOYumConfigComposeError(error_msg=msg) - self.release = release - - # 2. Validate URL - pattern = re.compile(COMPOSE_REPOS_URL_PATTERN[self.release]) - if not pattern.match(compose_url): - msg = 'The provided URL does not match the expect pattern.' - raise TripleOYumConfigComposeError(error_msg=msg) - - # 3. Get compose info from url - segments = [compose_url, - COMPOSE_REPOS_INFO_PATH[self.release]] - self.compose_info_url = '/'.join(s.strip('/') for s in segments) - self.compose_info = self._get_compose_info() - - # 4. Get compose-id from metadata - self.compose_id = self.compose_info['compose']['id'] - - # 5. Replace the compose-id from url to avoid 'labels' - repl_args = {'compose_id': self.compose_id} - self.compose_url = ( - pattern.sub( - COMPOSE_REPOS_URL_REPLACE_STR[self.release] % repl_args, - compose_url) - ) - - super(TripleOYumComposeRepoConfig, self).__init__( - valid_options=YUM_REPO_SUPPORTED_OPTIONS, - dir_path=conf_dir_path, - file_extension=YUM_REPO_FILE_EXTENSION, - environment_file=environment_file) - - def _get_compose_info(self): - """Retrieve compose info for a provided compose-id url.""" - # NOTE(dviroel): works for both centos 8 and 9 - import urllib.request - try: - logging.debug("Retrieving compose info from url: %s", - self.compose_info_url) - res = urllib.request.urlopen(self.compose_info_url) - except Exception: - msg = ("Failed to retrieve compose info from url: %s" - % self.compose_info_url) - raise TripleOYumConfigComposeError(error_msg=msg) - compose_info = json.loads(res.read()) - if compose_info['header']['version'] != "1.2": - # NOTE(dviroel): Log a warning just in case we receive a different - # version here. Code may fail depending on the change. - logging.warning("Expecting compose info version '1.2' but got %s.", - compose_info['header']['version']) - return compose_info['payload'] - - def _get_repo_name(self, variant): - return " ".join([self.compose_id, variant]) - - def _get_repo_filename(self, variant): - return "-".join([self.compose_id, variant]) + '.repo' - - def _get_repo_base_url(self, variant): - """Build the base_url based on variant name and system architecture.""" - variant_info = self.compose_info['variants'][variant] - if not variant_info['paths'].get('repository', {}).get(self.arch): - # Variant has no support yet - return None - segments = [self.compose_url, - variant_info['paths']['repository'][self.arch]] - return '/'.join(s.strip('/') for s in segments) - - def get_compose_variants(self): - return self.compose_info['variants'].keys() - - def enable_compose_repos(self, variants=None, override_repos=False): - """Enable CentOS compose repos of a given variant list. - - This function will build from scratch all repos for a given compose-id - url. If a list of variants is not provided, it will enable all for all - variants returned from compose info. - - :param variants: A list of variant names to be enabled. - :param override_repos: True if all matching variants in the same - repo directory should be disable in favor of the new repos. - """ - if variants: - for var in variants: - if not (var in self.compose_info['variants'].keys()): - msg = 'One or more provided variants are invalid.' - raise TripleOYumConfigComposeError(error_msg=msg) - - else: - variants = self.compose_info['variants'].keys() - - updated_repos = {} - for var in variants: - base_url = self._get_repo_base_url(var) - if not base_url: - continue - add_dict = { - 'name': self._get_repo_name(var), - 'baseurl': base_url, - 'enabled': '1', - 'gpgcheck': '0', - } - filename = self._get_repo_filename(var) - file_path = os.path.join(self.dir_path, filename) - # create a file if doesn't exist and add a section to it - try: - self.add_section(var.lower(), add_dict, file_path) - except TripleOYumConfigInvalidSection: - logging.debug("Section '%s' that already exists in this file. " - "Trying to update it...", var) - self.update_section(var.lower(), - set_dict=add_dict, - file_path=file_path) - # needed to override other repos - updated_repos[var.lower()] = file_path - - if override_repos: - for var in updated_repos: - config_files = self._get_config_files(var) - for file in config_files: - if file != updated_repos[var]: - msg = ("Disabling matching section '%(section)s' in " - "configuration file: %(file)s.") - msg_args = { - 'section': var, - 'file': file, - } - logging.debug(msg, msg_args) - self.update_section(var, enabled=False, file_path=file) - - def add_section(self, section, add_dict, file_path): - # Create a new file if it does not exists - if not os.path.isfile(file_path): - with open(file_path, 'w+'): - pass - super(TripleOYumComposeRepoConfig, self).add_section( - section, add_dict, file_path) - - def update_section( - self, section, set_dict=None, enabled=None, file_path=None): - update_dict = set_dict or {} - if enabled is not None: - update_dict['enabled'] = '1' if enabled else '0' - if update_dict: - super(TripleOYumComposeRepoConfig, self).update_section( - section, update_dict, file_path=file_path) - - def update_all_sections(self, file_path, set_dict=None, enabled=None): - update_dict = set_dict or {} - if enabled is not None: - update_dict['enabled'] = '1' if enabled else '0' - if update_dict: - super(TripleOYumComposeRepoConfig, self).update_all_sections( - update_dict, file_path) diff --git a/plugins/module_utils/tripleo_repos/yum_config/constants.py b/plugins/module_utils/tripleo_repos/yum_config/constants.py deleted file mode 100644 index 8312979..0000000 --- a/plugins/module_utils/tripleo_repos/yum_config/constants.py +++ /dev/null @@ -1,87 +0,0 @@ -# Copyright 2021 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. -# -# -from __future__ import (absolute_import, division, print_function) -""" -List of options that can be updated for yum repo files. -""" - -__metaclass__ = type - -YUM_REPO_SUPPORTED_OPTIONS = [ - 'baseurl', - 'cost', - 'enabled', - 'exclude', - 'excludepkgs', - 'gpgcheck', - 'gpgkey', - 'includepkgs', - 'metalink', - 'mirrorlist', - 'module_hotfixes', - 'name', - 'priority', - 'skip_if_unavailable', -] - -""" -Default constants for yum repo operations. -""" -YUM_REPO_DIR = '/etc/yum.repos.d' -YUM_REPO_FILE_EXTENSION = '.repo' - -""" -Default constants for yum/dnf global configurations. -""" -YUM_GLOBAL_CONFIG_FILE_PATH = '/etc/yum.conf' - -""" -CentOS Stream compose repos defaults -""" -COMPOSE_REPOS_RELEASES = [ - "centos-stream-8", - "centos-stream-9" -] - -COMPOSE_REPOS_SUPPORTED_ARCHS = [ - "aarch64", - "ppc64le", - "x86_64" -] - -COMPOSE_REPOS_URL_PATTERN = { - "centos-stream-8": r"(^https:.*.centos.org/)([^/]*)(/compose/?$)", - "centos-stream-9": r"(^https:.*.centos.org/.*/)(.*)(/compose/?$)", -} - -COMPOSE_REPOS_URL_REPLACE_STR = { - "centos-stream-8": r"\1%(compose_id)s\3", - "centos-stream-9": r"\1%(compose_id)s\3", -} - -COMPOSE_REPOS_INFO_PATH = { - "centos-stream-8": "metadata/composeinfo.json", - "centos-stream-9": "metadata/composeinfo.json", -} - -""" -DNF Manager constants -""" -DNF_MODULE_MINIMAL_DISTRO_VERSIONS = [ - {'distro': 'centos', 'min_version': 8}, - {'distro': 'rhel', 'min_version': 8}, - {'distro': 'fedora', 'min_version': 22}, -] diff --git a/plugins/module_utils/tripleo_repos/yum_config/dnf_manager.py b/plugins/module_utils/tripleo_repos/yum_config/dnf_manager.py deleted file mode 100644 index 4843cba..0000000 --- a/plugins/module_utils/tripleo_repos/yum_config/dnf_manager.py +++ /dev/null @@ -1,92 +0,0 @@ -# Copyright 2021 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. -from __future__ import (absolute_import, division, print_function) -import logging - - -__metaclass__ = type - - -class DnfModuleManager: - """Class that manages dnf modules.""" - - def __init__(self): - # lazy import to allow CLI to start without dnf - import dnf - self.base = dnf.Base() - self.base.conf.read() - self.base.conf.best = True - self.base.read_all_repos() - self.base.fill_sack() - self.module_base = dnf.module.module_base.ModuleBase(self.base) - - def _get_module_spec(self, name, stream=None, profile=None): - """Return a module spec string based on stream and/or profile.""" - module_spec = name - if stream: - module_spec += ':{0}'.format(stream) - if profile: - module_spec += '/{0}'.format(profile) - return module_spec - - def _do_transaction(self): - """Perform the resolved transaction.""" - try: - self.base.do_transaction() - except RuntimeError: - logging.error('This command has to be run with superuser ' - 'privileges.') - raise - - def enable_module(self, name, stream=None, profile=None): - """Enable a module stream.""" - self.module_base.enable( - [self._get_module_spec(name, stream=stream, profile=profile)] - ) - self._do_transaction() - logging.info("Module %s was enabled.", name) - - def disable_module(self, name, stream=None, profile=None): - """Disable a module stream.""" - self.module_base.disable( - [self._get_module_spec(name, stream=stream, profile=profile)] - ) - self._do_transaction() - logging.info("Module %s was disabled.", name) - - def reset_module(self, name, stream=None, profile=None): - """Reset a module. It will no longer be enabled or disabled.""" - self.module_base.reset( - [self._get_module_spec(name, stream=stream, profile=profile)] - ) - self._do_transaction() - logging.info("Module %s was reset.", name) - - def install_module(self, name, stream=None, profile=None): - """Install packages of a module profile.""" - self.module_base.install( - [self._get_module_spec(name, stream=stream, profile=profile)] - ) - self.base.resolve() - self.base.download_packages(self.base.transaction.install_set) - self._do_transaction() - logging.info("Module %s was installed.", name) - - def remove_module(self, name, stream=None, profile=None): - """Remove packages of a module profile.""" - self.module_base.remove( - [self._get_module_spec(name, stream=stream, profile=profile)] - ) - self._do_transaction() - logging.info("Module %s was removed.", name) diff --git a/plugins/module_utils/tripleo_repos/yum_config/exceptions.py b/plugins/module_utils/tripleo_repos/yum_config/exceptions.py deleted file mode 100644 index 266d508..0000000 --- a/plugins/module_utils/tripleo_repos/yum_config/exceptions.py +++ /dev/null @@ -1,76 +0,0 @@ -# Copyright 2021 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. -# -# -from __future__ import (absolute_import, division, print_function) - - -__metaclass__ = type - - -class Base(Exception): - """Base Exception class.""" - - -class TripleOYumConfigNotFound(Base): - """A configuration file was not found in the provided file path.""" - - def __init__(self, error_msg): - super(TripleOYumConfigNotFound, self).__init__(error_msg) - - -class TripleOYumConfigPermissionDenied(Base): - """THh user has no permission to modify the configuration file.""" - - def __init__(self, error_msg): - super(TripleOYumConfigPermissionDenied, self).__init__(error_msg) - - -class TripleOYumConfigFileParseError(Base): - """Encountered an error while parsing the configuration file.""" - - def __init__(self, error_msg): - super(TripleOYumConfigFileParseError, self).__init__(error_msg) - - -class TripleOYumConfigInvalidSection(Base): - """The configuration file does not have the requested section. - - This exception is raised when the expected section in the configuration - file does not exist and the class will not create a new one. - """ - - def __init__(self, error_msg): - super(TripleOYumConfigInvalidSection, self).__init__(error_msg) - - -class TripleOYumConfigInvalidOption(Base): - """One or more options are not valid for this configuration file.""" - - def __init__(self, error_msg): - super(TripleOYumConfigInvalidOption, self).__init__(error_msg) - - -class TripleOYumConfigComposeError(Base): - """An error occurred while configuring CentOS compose repos.""" - - def __init__(self, error_msg): - super(TripleOYumConfigComposeError, self).__init__(error_msg) - - -class TripleOYumConfigUrlError(Base): - """An error occurred while fetching repo from the url.""" - - def __init__(self, error_msg): - super(TripleOYumConfigUrlError, self).__init__(error_msg) diff --git a/plugins/module_utils/tripleo_repos/yum_config/utils.py b/plugins/module_utils/tripleo_repos/yum_config/utils.py deleted file mode 100644 index c4a3646..0000000 --- a/plugins/module_utils/tripleo_repos/yum_config/utils.py +++ /dev/null @@ -1,50 +0,0 @@ -# Copyright 2021 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. -from __future__ import (absolute_import, division, print_function) -import os -import platform -import subprocess - -__metaclass__ = type - - -# TODO(dviroel): Merge in a utils file when refactoring tripleo-repos. -def get_distro_info(): - """Get distro info from os-release file. - - :return: distro_id, distro_major_version_id and distro_name - """ - if not os.path.exists('/etc/os-release'): - return platform.system(), 'unknown', 'unknown' - - output = subprocess.Popen( - 'source /etc/os-release && echo -e -n "$ID\n$VERSION_ID\n$NAME"', - shell=True, - stdout=subprocess.PIPE, - stderr=open(os.devnull, 'w'), - executable='/bin/bash', - universal_newlines=True).communicate() - - # distro_id and distro_version_id will always be at least an empty string - distro_id, distro_version_id, distro_name = output[0].split('\n') - - # if distro_version_id is empty string the major version will be empty - # string too - distro_major_version_id = distro_version_id.split('.')[0] - - # check if that is UBI subcase? - if os.path.exists('/etc/yum.repos.d/ubi.repo'): - distro_id = 'ubi' - - return distro_id, distro_major_version_id, distro_name diff --git a/plugins/module_utils/tripleo_repos/yum_config/yum_config.py b/plugins/module_utils/tripleo_repos/yum_config/yum_config.py deleted file mode 100644 index caa1249..0000000 --- a/plugins/module_utils/tripleo_repos/yum_config/yum_config.py +++ /dev/null @@ -1,449 +0,0 @@ -# Copyright 2021 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. -# -from __future__ import (absolute_import, division, print_function) - - -import io -import logging -import os -import subprocess -import sys - -from .constants import ( - YUM_GLOBAL_CONFIG_FILE_PATH, - YUM_REPO_DIR, - YUM_REPO_FILE_EXTENSION, - YUM_REPO_SUPPORTED_OPTIONS, -) -from .exceptions import ( - TripleOYumConfigFileParseError, - TripleOYumConfigInvalidOption, - TripleOYumConfigInvalidSection, - TripleOYumConfigNotFound, - TripleOYumConfigUrlError, -) -try: - import tripleo_repos.utils as repos_utils -except ImportError: - import ansible_collections.tripleo.repos.plugins.module_utils.\ - tripleo_repos.utils as repos_utils - - -py_version = sys.version_info.major -if py_version < 3: - import ConfigParser as cfg_parser - - def save_section_to_file(file_path, config, section, updates): - """Updates a specific 'section' in a 'config' and write to disk. - - :param file_path: Absolute path to the file to be updated. - :param config: configparser object created from the file. - :param section: section name to be updated. - :param updates: dict with options to update in section. - """ - - for k, v in updates.items(): - config.set(section, k, v) - with open(file_path, 'w') as f: - config.write(f) - - # NOTE(dviroel) Need to manually remove whitespaces around "=", to - # avoid legacy scripts failing on parsing ini files. - with open(file_path, 'r+') as f: - lines = f.readlines() - # erase content before writing again - f.truncate(0) - f.seek(0) - for line in lines: - line = line.strip() - if "=" in line: - option_kv = line.split("=", 1) - option_kv = list(map(str.strip, option_kv)) - f.write("%s%s%s\n" % (option_kv[0], "=", option_kv[1])) - else: - f.write(line + "\n") - -else: - import configparser as cfg_parser - - def save_section_to_file(file_path, config, section, updates): - """Updates a specific 'section' in a 'config' and write to disk. - - :param file_path: Absolute path to the file to be updated. - :param config: configparser object created from the file. - :param section: section name to be updated. - :param updates: dict with options to update in section. - """ - config[section].update(updates) - with open(file_path, 'w') as f: - config.write(f, space_around_delimiters=False) - -__metaclass__ = type - - -def validated_file_path(file_path): - if os.path.isfile(file_path) and os.access(file_path, os.W_OK): - return True - return False - - -def source_env_file(source_file, update=True): - """Source a file and get all environment variables in a dict format.""" - p_open = subprocess.Popen(". %s; env" % source_file, - stdout=subprocess.PIPE, - shell=True) - data = p_open.communicate()[0].decode('ascii') - - env_dict = dict( - line.split("=", 1) for line in data.splitlines() - if len(line.split("=", 1)) > 1) - if update: - os.environ.update(env_dict) - return env_dict - - -class TripleOYumConfig: - """ - This class is a base class for updating yum configuration files in - ini format. The class validates the if the configuration files exists and - if it has the the permissions needed. A list of updatable options may be - provided to the class constructor. - """ - - def __init__(self, valid_options=None, dir_path=None, file_extension=None, - environment_file=None): - """ - Creates a TripleOYumConfig object that holds configuration file - information. - - :param valid_options: A list of options that can be updated on this - file. - :param dir_path: The directory path that this class can use to search - for configuration files to be updated. - :param: file_extension: File extension to filter configuration files - in the search directory. - :param environment_file: File to be read before updating environment - variables. - """ - self.dir_path = dir_path - self.file_extension = file_extension - self.valid_options = valid_options - self.env_file = environment_file - - # Sanity checks - if dir_path: - if not os.path.isdir(dir_path): - msg = ('The configuration dir "{0}" was not found in the ' - 'provided path.').format(dir_path) - raise TripleOYumConfigNotFound(error_msg=msg) - - if self.env_file: - source_env_file(os.path.expanduser(self.env_file), update=True) - - def _read_config_file(self, file_path, section=None): - """Reads a configuration file. - - :param section: The name of the section that will be update. Only used - to fail earlier if the section is not found. - :return: a config parser object and the full file path. - """ - config = cfg_parser.ConfigParser() - file_paths = [file_path] - if self.dir_path: - # if dir_path is configured, we can search for filename there - file_paths.append(os.path.join(self.dir_path, file_path)) - - valid_file_path = None - for file in file_paths: - if validated_file_path(file): - valid_file_path = file - break - if not valid_file_path: - msg = ('The configuration file "{0}" was ' - 'not found.'.format(file_path)) - raise TripleOYumConfigNotFound(error_msg=msg) - - try: - config.read(valid_file_path) - except cfg_parser.Error: - msg = 'Unable to parse configuration file {0}.'.format( - valid_file_path) - raise TripleOYumConfigFileParseError(error_msg=msg) - - if section and section not in config.sections(): - msg = ('The provided section "{0}" was not found in the ' - 'configuration file {1}.').format( - section, valid_file_path) - raise TripleOYumConfigInvalidSection(error_msg=msg) - - return config, valid_file_path - - def _get_config_files(self, section): - """Gets all configuration file paths for a given section. - - This method will search for a 'section' name in all files inside the - configuration directory. All files with 'section' will be returned. - - :param section: Section to be found inside configuration files. - :return: A list of config file paths. - """ - # Search for a configuration file that has the provided section - config_files_path = [] - if section and self.dir_path: - for file in os.listdir(self.dir_path): - # Skip files that don't match the file extension or are not - # writable - if self.file_extension and not file.endswith( - self.file_extension): - continue - if not os.access(os.path.join(self.dir_path, file), os.W_OK): - continue - - tmp_config = cfg_parser.ConfigParser() - try: - tmp_config.read(os.path.join(self.dir_path, file)) - except cfg_parser.Error: - continue - if section in tmp_config.sections(): - config_files_path.append(os.path.join(self.dir_path, file)) - - return config_files_path - - def update_section(self, section, set_dict, file_path=None): - """Updates a set of options of a section. - - If a file path is not provided by the caller, this function will search - for the section in all files located in the working directory and - update each one of them. - - :param section: Name of the section on the configuration file that will - be updated. - :param set_dict: Dict with all options and values to be updated in the - configuration file section. - :param file_path: Path to the configuration file to be updated. - """ - if self.valid_options: - if not all(key in self.valid_options for key in set_dict.keys()): - msg = 'One or more provided options are not valid.' - raise TripleOYumConfigInvalidOption(error_msg=msg) - - files = [file_path] if file_path else self._get_config_files(section) - if not files: - msg = ('No configuration files were found for the provided ' - 'section {0}'.format(section)) - raise TripleOYumConfigNotFound(error_msg=msg) - - for k, v in set_dict.items(): - set_dict[k] = os.path.expandvars(v) - for file in files: - config, file = self._read_config_file(file, section=section) - # Update configuration file with dict updates - save_section_to_file(file, config, section, set_dict) - - logging.info("Section '%s' was successfully " - "updated.", section) - - def add_section(self, section, add_dict, file_path): - """ Adds a new section with options in a provided config file. - - :param section: Section name to be added to the config file. - :param add_dict: Dict with all options and values to be added into the - new section. - :param file_path: Path to the configuration file to be updated. - """ - if self.valid_options: - if not all(key in self.valid_options for key in add_dict.keys()): - msg = 'One or more provided options are not valid.' - raise TripleOYumConfigInvalidOption(error_msg=msg) - - # This section shouldn't exist in the provided file - config, file_path = self._read_config_file(file_path=file_path) - if section in config.sections(): - msg = ("Section '%s' already exists in the configuration " - "file.", section) - raise TripleOYumConfigInvalidSection(error_msg=msg) - - for k, v in add_dict.items(): - add_dict[k] = os.path.expandvars(v) - # Add new section - config.add_section(section) - # Update configuration file with dict updates - save_section_to_file(file_path, config, section, add_dict) - - logging.info("Section '%s' was successfully " - "added.", section) - - def update_all_sections(self, set_dict, file_path): - """Updates all section of a given configuration file. - - :param set_dict: Dict with all options and values to be updated in - the configuration file. - :param file_path: Path to the configuration file to be updated. - """ - if self.valid_options: - if not all(key in self.valid_options for key in set_dict.keys()): - msg = 'One or more provided options are not valid.' - raise TripleOYumConfigInvalidOption(error_msg=msg) - - config, file_path = self._read_config_file(file_path) - for section in config.sections(): - save_section_to_file(file_path, config, section, set_dict) - - logging.info("All sections for '%s' were successfully " - "updated.", file_path) - - def get_config_from_url(self, url): - content, status = repos_utils.http_get(url) - if status != 200: - msg = ("Invalid response code received from provided url: " - "{0}. Response code: {1}." - ).format(url, status) - logging.error(msg) - raise TripleOYumConfigUrlError(error_msg=msg) - config = cfg_parser.ConfigParser() - if py_version < 3: - sfile = io.StringIO(content) - config.readfp(sfile) - else: - config.read_string(content) - return config - - def get_options_from_url(self, url, section): - config = self.get_config_from_url(url) - if section not in config.sections(): - msg = ("Section '{0}' was not found in the configuration file " - "provided by the url {1}.").format(section, url) - raise TripleOYumConfigInvalidSection(error_msg=msg) - return dict(config.items(section)) - - -class TripleOYumRepoConfig(TripleOYumConfig): - """Manages yum repo configuration files.""" - - def __init__(self, dir_path=None, environment_file=None): - conf_dir_path = dir_path or YUM_REPO_DIR - - super(TripleOYumRepoConfig, self).__init__( - valid_options=YUM_REPO_SUPPORTED_OPTIONS, - dir_path=conf_dir_path, - file_extension=YUM_REPO_FILE_EXTENSION, - environment_file=environment_file) - - def update_section( - self, section, set_dict=None, file_path=None, enabled=None, - from_url=None): - update_dict = ( - self.get_options_from_url(from_url, section) if from_url else {}) - if set_dict: - update_dict.update(set_dict) - if enabled is not None: - update_dict['enabled'] = '1' if enabled else '0' - if update_dict: - super(TripleOYumRepoConfig, self).update_section( - section, update_dict, file_path=file_path) - - def add_section(self, section, add_dict, file_path, enabled=None, - from_url=None): - update_dict = ( - self.get_options_from_url(from_url, section) if from_url else {}) - update_dict.update(add_dict) - - if enabled is not None: - update_dict['enabled'] = '1' if enabled else '0' - super(TripleOYumRepoConfig, self).add_section( - section, update_dict, file_path) - - def add_or_update_section(self, section, set_dict=None, - file_path=None, enabled=None, - create_if_not_exists=True, from_url=None): - new_set_dict = ( - self.get_options_from_url(from_url, section) if from_url else {}) - new_set_dict.update(set_dict) - # make sure that it has a name - if 'name' not in new_set_dict.keys(): - new_set_dict['name'] = section - # Try to update existing repos - try: - self.update_section( - section, set_dict=new_set_dict, file_path=file_path, - enabled=enabled) - except TripleOYumConfigNotFound: - if not create_if_not_exists or file_path is None: - # there is nothing to do, we can't create a new config file - raise - # Create a new file if it does not exists - with open(file_path, 'w+'): - pass - self.add_section(section, new_set_dict, file_path, enabled=enabled) - - except TripleOYumConfigInvalidSection: - self.add_section(section, new_set_dict, file_path, enabled=enabled) - - def add_or_update_all_sections_from_url( - self, from_url, file_path=None, set_dict=None, enabled=None, - create_if_not_exists=True): - """Adds or updates all sections based on repo file from a URL.""" - tmp_config = self.get_config_from_url(from_url) - if file_path is None: - # Build a file_path based on download url. If not compatible, - # don't fill file_path and let the code search for sections in all - # repo files inside config dir_path. - file_name = from_url.split('/')[-1] - if file_name.endswith(".repo"): - # Expecting a '*.repo' filename here, since the file can't be - # created with a different extension - file_path = os.path.join(self.dir_path, file_name) - - for section in tmp_config.sections(): - update_dict = dict(tmp_config.items(section)) - update_dict.update(set_dict) - self.add_or_update_section( - section, set_dict=update_dict, - file_path=file_path, enabled=enabled, - create_if_not_exists=create_if_not_exists) - - -class TripleOYumGlobalConfig(TripleOYumConfig): - """Manages yum global configuration file.""" - - def __init__(self, file_path=None, environment_file=None): - self.conf_file_path = file_path or YUM_GLOBAL_CONFIG_FILE_PATH - logging.info("Using '%s' as yum global configuration " - "file.", self.conf_file_path) - if file_path is not None: - # validate user provided file path - validated_file_path(file_path) - else: - # If there is no default 'yum.conf' configuration file, we need to - # create it. If the user specify another conf file that doesn't - # exists, the operation will fail. - if not os.path.isfile(self.conf_file_path): - config = cfg_parser.ConfigParser() - config.read(self.conf_file_path) - config.add_section('main') - with open(self.conf_file_path, 'w+') as file: - config.write(file) - - super(TripleOYumGlobalConfig, self).__init__( - environment_file=environment_file) - - def update_section(self, section, set_dict, file_path=None): - super(TripleOYumGlobalConfig, self).update_section( - section, set_dict, file_path=(file_path or self.conf_file_path)) - - def add_section(self, section, add_dict, file_path=None): - add_file_path = file_path or self.conf_file_path - super(TripleOYumGlobalConfig, self).add_section( - section, add_dict, add_file_path) diff --git a/plugins/modules/get_hash.py b/plugins/modules/get_hash.py deleted file mode 100644 index 7b44b16..0000000 --- a/plugins/modules/get_hash.py +++ /dev/null @@ -1,145 +0,0 @@ -#!/usr/bin/python -# Copyright 2021 Red Hat, Inc. -# GNU General Public License v3.0+ (see COPYING or -# https://www.gnu.org/licenses/gpl-3.0.txt) -from __future__ import (absolute_import, division, print_function) - - -__metaclass__ = type - - -DOCUMENTATION = r''' ---- -module: get_hash - -short_description: Resolve rdo named tag to commit, full and distro hashes - -version_added: "1.0.0" - -description: "" - -options: - os_version: - description: The operating system and version to fetch hashes for - required: false - type: str - default: centos8 - release: - description: The release of OpenStack you want the hash info for - required: false - type: str - default: master - component: - description: The tripleo-ci component you are interested in - required: false - type: str - tag: - description: The named tag to fetch - required: false - type: str - default: current-tripleo - dlrn_url: - description: The url of the DLRN server to use for hash queries - required: false - type: str - default: https://trunk.rdoproject.org - -author: - - Marios Andreou (@marios) -''' - -EXAMPLES = r''' -- name: Get the latest hash info for victoria centos8 tripleo component - tripleo_get_hash: - os_version: centos8 - release: victoria - component: tripleo - dlrn_url: 'https://foo.bar.baz' -''' - -RETURN = r''' -full_hash: - description: The full hash that identifies the build - type: str - returned: always - sample: 'f47f1db5af04ddd1ab4cc3ccadf95884d335b3f3_92f50ace' -distro_hash: - description: The distro hash - type: str - returned: when available - sample: '92f50acecd0a218936b7163e8362e75913b62af2' -commit_hash: - description: The commit hash - type: str - returned: when available - sample: 'f47f1db5af04ddd1ab4cc3ccadf95884d335b3f3' -extended_hash: - description: The extended hash - type: str - returned: when available - sample: 'f47f1db5af04ddd1ab4cc3ccadf95884d335b3f3' -dlrn_url: - description: The dlrn server url from which hash info was collected. - type: str - returned: always - sample: 'https://trunk.rdoproject.org/centos8-master/current-tripleo/delorean.repo.md5' # noqa E501 -''' - -from ansible.module_utils.basic import AnsibleModule # noqa: E402 - - -def run_module(): - result = dict( - success=False, - changed=False, - error="", - ) - - argument_spec = dict( - os_version=dict(type='str', required=False, default='centos8'), - release=dict(type='str', required=False, default='master'), - component=dict(type='str', required=False, default=None), - tag=dict(type='str', required=False, default='current-tripleo'), - dlrn_url=dict(type='str', - required=False, - default='https://trunk.rdoproject.org'), - ) - - module = AnsibleModule( - argument_spec, - supports_check_mode=False - ) - - try: - - from ansible_collections.tripleo.repos.plugins.module_utils.\ - tripleo_repos.get_hash.tripleo_hash_info import TripleOHashInfo - - os_version = module.params.get('os_version') - release = module.params.get('release') - component = module.params.get('component') - tag = module.params.get('tag') - dlrn_url = module.params.get('dlrn_url') - - hash_result = TripleOHashInfo(os_version, release, component, tag, - config={'dlrn_url': dlrn_url}) - result['commit_hash'] = hash_result.commit_hash - result['distro_hash'] = hash_result.distro_hash - result['full_hash'] = hash_result.full_hash - result['extended_hash'] = hash_result.extended_hash - result['dlrn_url'] = hash_result.dlrn_url - result['success'] = True - except Exception as exc: - result['error'] = str(exc) - result['msg'] = "Error something went wrong fetching hash info" - module.fail_json(**result) - - module.exit_json(**result) - - -def main(): - run_module() - - -if __name__ == '__main__': - main() diff --git a/plugins/modules/yum_config.py b/plugins/modules/yum_config.py deleted file mode 100644 index 9799152..0000000 --- a/plugins/modules/yum_config.py +++ /dev/null @@ -1,373 +0,0 @@ -#!/usr/bin/python -# Copyright 2021 Red Hat, Inc. -# GNU General Public License v3.0+ (see COPYING or -# https://www.gnu.org/licenses/gpl-3.0.txt) -from __future__ import (absolute_import, division, print_function) - - -__metaclass__ = type - -DOCUMENTATION = r''' ---- -module: yum_config - -short_description: Update yum configuration files for TripleO deployments. - -version_added: "1.0.0" - -description: - - Update specific options for different yum configuration files like - yum repos, yum modules and yum global configuration. - -options: - type: - description: - - The type of yum configuration to be changed. - required: true - type: str - choices: [repo, module, global, 'enable-compose-repos'] - name: - description: - - Name of the repo or module to be changed. This options is - mandatory only for 'repo' when no 'down_url' is provided. This - options is always mandatory for 'module' type. - type: str - enabled: - description: - - Change the yum repo or module to enabled or disabled. - - This options is ignored for yum global configuration. - type: bool - default: true - down_url: - description: - - URL of a downloadable repo file to be used as base to construct a - new repo file. When used together with 'name', will update only the - requested section, without a specific section 'name' will add or - update all sections available in the downloaded file. - type: str - operation: - description: - - Operation to be execute within a dnf module. - type: str - choices: [install, remove, reset] - stream: - description: - - Sets a module stream. This options is recommended when enabling a - module that doesn't have a default stream. - type: str - profile: - description: - - Sets a module profile. This options is recommended when installing - a module that doesn't have a default profile. - type: str - set_options: - description: - - Dictionary with options to be updated. All dictionary values must - be string or list of strings. - type: dict - file_path: - description: - - Absolute path of the configuration file to be changed. - type: path - dir_path: - description: - - Absolute path of the directory that contains the configuration - file to be changed. - type: path - default: /etc/yum.repos.d - environment_file: - description: - - Absolute path to an environment file to be read before updating or - creating yum config and repo files. - type: path - compose_url: - description: - - URL that contains CentOS compose repositories. - type: str - centos_release: - description: - - Target CentOS release. - type: str - choices: [centos-stream-8, centos-stream-9] - arch: - description: - - System architecture which the repos will be configure. - type: str - choices: [aarch64, ppc64le, x86_64] - default: x86_64 - variants: - description: - - Repository variants that should be configured. If not provided, - all available variants will be configured. - type: list - elements: str - disable_conflicting_variants: - description: - - Disable all repos from the same directory that match variants' - name. - type: bool - default: false - disable_repos: - description: - - List with file path of repos that should be disabled after - successfully enabling all compose repos. - type: list - elements: str - -author: - - Douglas Viroel (@viroel) -''' - -EXAMPLES = r''' -# Set yum 'appstream' repo to enabled and exclude a list of packages -- name: Enable appstream repo and exclude nodejs and mariadb packages - become: true - become_user: root - tripleo_yum_config: - type: repo - name: appstream - enabled: true - set_options: - exclude: - - nodejs* - - mariadb* - -# Enable and install a yum/dnf module -- name: Enable nginx module - become: true - become_user: root - tripleo_yum_config: - type: module - name: tomcat - enabled: false - stream: "1.18" - -- name: Enable nginx module - become: true - become_user: root - tripleo_yum_config: - type: module - name: nginx - operation: install - profile: common - -# Set yum global configuration options -- name: Set yum global options - become: true - become_user: root - tripleo_yum_config: - type: global - file_path: /etc/dnf/dnf.conf - set_options: - skip_if_unavailable: "False" - keepcache: "0" - -- name: Configure a set of repos based on latest CentOS Stream 8 compose - become: true - become_user: root - tripleo_yum_config: - compose_url: https://composes.centos.org/latest-CentOS-Stream-8/compose/ - centos_release: centos-stream-8 - variants: - - AppStream - - BaseOS - disable_conflicting_variants: true - disable_repos: - - /etc/yum.repos.d/CentOS-Linux-AppStream.repo - - /etc/yum.repos.d/CentOS-Linux-BaseOS.repo -''' - -RETURN = r''' # ''' - -import os # noqa: E402 - -from ansible.module_utils import six # noqa: E402 -from ansible.module_utils.basic import AnsibleModule # noqa: E402 - - -def run_module(): - try: - import ansible_collections.tripleo.repos.plugins.module_utils. \ - tripleo_repos.yum_config.constants as const - from ansible_collections.tripleo.repos.plugins.module_utils. \ - tripleo_repos.yum_config import utils - except ImportError: - import tripleo_repos.yum_config.constants as const - from tripleo_repos.yum_config import utils - - supported_config_types = ['repo', 'global', 'module', - 'enable-compose-repos'] - supported_module_operations = ['install', 'remove', 'reset'] - module_args = dict( - type=dict(type='str', required=True, choices=supported_config_types), - name=dict(type='str'), - enabled=dict(type='bool', default=True), - down_url=dict(type='str'), - operation=dict(type='str', choices=supported_module_operations), - stream=dict(type='str'), - profile=dict(type='str'), - set_options=dict(type='dict', default={}), - file_path=dict(type='path'), - dir_path=dict(type='path', default=const.YUM_REPO_DIR), - environment_file=dict(type='path'), - compose_url=dict(type='str'), - centos_release=dict(type='str', - choices=const.COMPOSE_REPOS_RELEASES), - arch=dict(type='str', choices=const.COMPOSE_REPOS_SUPPORTED_ARCHS, - default='x86_64'), - variants=dict(type='list', default=[], - elements='str'), - disable_conflicting_variants=dict(type='bool', default=False), - disable_repos=dict(type='list', default=[], - elements='str'), - ) - required_if_params = [ - ["type", "module", ["name"]], - ["type", "enable-compose-repos", ["compose_url"]] - ] - - module = AnsibleModule( - argument_spec=module_args, - required_if=required_if_params, - supports_check_mode=False - ) - - operations_not_supp_in_py2 = ['module', 'enable-compose-repos'] - if six.PY2 and module.params['type'] in operations_not_supp_in_py2: - msg = ("The configuration type '{0}' is not " - "supported with python 2.").format(module.params['type']) - module.fail_json(msg=msg) - - if (module.params['type'] == 'repo' and not - module.params['name'] and not module.params['down_url']): - msg = ("When using configuration type '{0}' you must provide a repo " - "'name' or a 'down_url'.").format(module.params['type']) - module.fail_json(msg=msg) - - distro, major_version, __ = utils.get_distro_info() - dnf_module_support = False - for min_distro_ver in const.DNF_MODULE_MINIMAL_DISTRO_VERSIONS: - if (distro == min_distro_ver.get('distro') and int( - major_version) >= min_distro_ver.get('min_version')): - dnf_module_support = True - break - if module.params['type'] == 'module' and not dnf_module_support: - msg = ("The configuration type 'module' is not " - "supported in this distro version " - "({0}-{1}).".format(distro, major_version)) - module.fail_json(msg=msg) - - # 'set_options' expects a dict that can also contains a list of values. - # List of elements will be converted to a comma-separated list - m_set_opts = module.params.get('set_options') - if m_set_opts: - for k, v in m_set_opts.items(): - if isinstance(v, list): - m_set_opts[k] = ','.join([str(elem) for elem in v]) - elif not isinstance(v, str): - m_set_opts[k] = str(v) - - # Module execution - try: - try: - import ansible_collections.tripleo.repos.plugins.module_utils.\ - tripleo_repos.yum_config.yum_config as cfg - except ImportError: - import tripleo_repos.yum_config.yum_config as cfg - - if module.params['type'] == 'repo': - config_obj = cfg.TripleOYumRepoConfig( - dir_path=module.params['dir_path'], - environment_file=module.params['environment_file']) - if module.params['name']: - config_obj.add_or_update_section( - module.params['name'], - set_dict=m_set_opts, - file_path=module.params['file_path'], - enabled=module.params['enabled'], - from_url=module.params['down_url']) - else: - config_obj.add_or_update_all_sections_from_url( - module.params['down_url'], - set_dict=m_set_opts, - file_path=module.params['file_path'], - enabled=module.params['enabled']) - - elif module.params['type'] == 'global': - config_obj = cfg.TripleOYumGlobalConfig( - file_path=module.params['file_path'], - environment_file=module.params['environment_file']) - config_obj.update_section('main', m_set_opts) - - elif module.params['type'] == 'enable-compose-repos': - try: - import ansible_collections.tripleo.repos.plugins.module_utils.\ - tripleo_repos.yum_config.compose_repos as repos - except ImportError: - import tripleo_repos.yum_config.compose_repos as repos - - # 1. Create compose repo config object - repo_obj = repos.TripleOYumComposeRepoConfig( - module.params['compose_url'], - module.params['centos_release'], - dir_path=module.params['dir_path'], - arch=module.params['arch'], - environment_file=module.params['environment_file']) - # 2. enable CentOS compose repos - repo_obj.enable_compose_repos( - variants=module.params['variants'], - override_repos=module.params['disable_conflicting_variants']) - # 3. Disable all repos provided in disable_repos - for file in module.params['disable_repos']: - valid_path = None - rel_path = os.path.join(module.params['dir_path'], file) - - if cfg.validated_file_path(file): - valid_path = file - elif cfg.validated_file_path(rel_path): - valid_path = rel_path - - if valid_path is not None: - repo_obj.update_all_sections(valid_path, enabled=False) - - elif module.params['type'] == 'module': - try: - import ansible_collections.tripleo.repos.plugins.module_utils.\ - tripleo_repos.yum_config.dnf_manager as dnf_mgr - except ImportError: - import tripleo_repos.yum_config.dnf_manager as dnf_mgr - - dnf_mod_mgr = dnf_mgr.DnfModuleManager() - if module.params['enabled']: - dnf_mod_mgr.enable_module(module.params['name'], - stream=module.params['stream'], - profile=module.params['profile']) - else: - dnf_mod_mgr.disable_module(module.params['name'], - stream=module.params['stream'], - profile=module.params['profile']) - if module.params['operation']: - dnf_method = getattr(dnf_mod_mgr, - module.params['operation'] + "_module") - dnf_method(module.params['name'], - stream=module.params['stream'], - profile=module.params['profile']) - - except Exception as exc: - module.fail_json(msg=str(exc)) - - # Successful module execution - result = { - 'changed': True, - 'msg': "Yum {0} configuration was successfully updated.".format( - module.params['type']) - } - module.exit_json(**result) - - -def main(): - run_module() - - -if __name__ == '__main__': - main() diff --git a/releasenotes/notes/stream_by_default-783cc6a2208b942c.yaml b/releasenotes/notes/stream_by_default-783cc6a2208b942c.yaml deleted file mode 100644 index 98ab706..0000000 --- a/releasenotes/notes/stream_by_default-783cc6a2208b942c.yaml +++ /dev/null @@ -1,5 +0,0 @@ ---- -features: - - | - tripleo-repos now runs with the --stream argument enabled by default. Use - the --no-stream argument when using tripleo-repos without CentOS stream. diff --git a/requirements.txt b/requirements.txt deleted file mode 100644 index 5ba9353..0000000 --- a/requirements.txt +++ /dev/null @@ -1,7 +0,0 @@ -# The order of packages is significant, because pip processes them in the order -# of appearance. Changing the order has an impact on the overall integration -# process, which may cause wedges in the gate later. - -pbr!=2.1.0,>=2.0.0 # Apache-2.0 -requests>=2.10.0 # Apache-2.0 -PyYAML>=3.12 # MIT diff --git a/setup.cfg b/setup.cfg deleted file mode 100644 index 2d66262..0000000 --- a/setup.cfg +++ /dev/null @@ -1,40 +0,0 @@ -[metadata] -name = tripleo-repos -summary = A tool for managing tripleo repos -description-file = - README.rst -author = OpenStack -author-email = openstack-discuss@lists.openstack.org -home-page = https://docs.openstack.org/tripleo-docs/latest/ -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 :: Implementation :: CPython - Programming Language :: Python :: 3 :: Only - Programming Language :: Python :: 3 - Programming Language :: Python :: 3.6 - Programming Language :: Python :: 3.7 - Programming Language :: Python :: 3.8 - Programming Language :: Python :: 3.9 - -[files] -packages = - tripleo_repos -data_files = - etc/tripleo_get_hash/ = tripleo_repos/get_hash/config.yaml - share/ansible/plugins/modules/ = plugins/modules/* - share/ansible/plugins/module_utils/ = plugins/module_utils/* - -[entry_points] -console_scripts = - tripleo-repos = tripleo_repos.main:main - tripleo-yum-config = tripleo_repos.yum_config.__main__:cli_entrypoint - tripleo-get-hash = tripleo_repos.get_hash.__main__:cli_entrypoint - -[pbr] -skip_authors = True -skip_changelog = True diff --git a/setup.py b/setup.py deleted file mode 100755 index eb4bd43..0000000 --- a/setup.py +++ /dev/null @@ -1,20 +0,0 @@ -# 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. - -import setuptools - -setuptools.setup( - setup_requires=['pbr>=2.0'], - pbr=True) diff --git a/test-requirements.txt b/test-requirements.txt deleted file mode 100644 index 0f172a3..0000000 --- a/test-requirements.txt +++ /dev/null @@ -1,15 +0,0 @@ -# The order of packages is significant, because pip processes them in the order -# of appearance. Changing the order has an impact on the overall integration -# process, which may cause wedges in the gate later. - -hacking>=3.0,<=3.1.0 # Apache-2.0 - -coverage>=4.0,!=4.4 # Apache-2.0 -ddt>=1.0.1 # MIT -python-subunit>=0.0.18 # Apache-2.0/BSD -oslotest>=1.10.0 # Apache-2.0 -testrepository>=0.0.18 # Apache-2.0/BSD -testscenarios>=0.4 # Apache-2.0/BSD -testtools>=1.4.0 # MIT -stestr>=2.0.0 # Apache-2.0 -fixtures>=3.0.0 # Apache-2.0/BSD diff --git a/tests/sanity/ignore-2.10.txt b/tests/sanity/ignore-2.10.txt deleted file mode 120000 index f749b40..0000000 --- a/tests/sanity/ignore-2.10.txt +++ /dev/null @@ -1 +0,0 @@ -ignore.txt \ No newline at end of file diff --git a/tests/sanity/ignore-2.11.txt b/tests/sanity/ignore-2.11.txt deleted file mode 120000 index f749b40..0000000 --- a/tests/sanity/ignore-2.11.txt +++ /dev/null @@ -1 +0,0 @@ -ignore.txt \ No newline at end of file diff --git a/tests/sanity/ignore-2.12.txt b/tests/sanity/ignore-2.12.txt deleted file mode 120000 index f749b40..0000000 --- a/tests/sanity/ignore-2.12.txt +++ /dev/null @@ -1 +0,0 @@ -ignore.txt \ No newline at end of file diff --git a/tests/sanity/ignore-2.9.txt b/tests/sanity/ignore-2.9.txt deleted file mode 120000 index f749b40..0000000 --- a/tests/sanity/ignore-2.9.txt +++ /dev/null @@ -1 +0,0 @@ -ignore.txt \ No newline at end of file diff --git a/tests/sanity/ignore.txt b/tests/sanity/ignore.txt deleted file mode 100644 index c1897b3..0000000 --- a/tests/sanity/ignore.txt +++ /dev/null @@ -1,3 +0,0 @@ -plugins/module_utils/tripleo_repos/utils.py replace-urlopen -plugins/module_utils/tripleo_repos/utils.py pylint:ansible-bad-import -plugins/module_utils/tripleo_repos/yum_config/compose_repos.py replace-urlopen diff --git a/tests/sanity/requirements.txt b/tests/sanity/requirements.txt deleted file mode 100644 index 5500f00..0000000 --- a/tests/sanity/requirements.txt +++ /dev/null @@ -1 +0,0 @@ -PyYAML diff --git a/tests/unit/__init__.py b/tests/unit/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/tests/unit/get_hash/__init__.py b/tests/unit/get_hash/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/tests/unit/get_hash/fakes.py b/tests/unit/get_hash/fakes.py deleted file mode 100644 index 188a88b..0000000 --- a/tests/unit/get_hash/fakes.py +++ /dev/null @@ -1,115 +0,0 @@ -# Copyright 2021 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. -# -# - -TEST_COMMIT_YAML_COMPONENT = """ - commits: - - artifacts: repos/component/common/47/6a/476a52df13202a44336c8b01419f8b73b93d93eb_1f5a41f3/openstack-tacker-4.1.0-0.20210325043415.476a52d.el8.src.rpm,repos/component/common/47/6a/476a52df13202a44336c8b01419f8b73b93d93eb_1f5a41f3/python3-tacker-doc-4.1.0-0.20210325043415.476a52d.el8.noarch.rpm,repos/component/common/47/6a/476a52df13202a44336c8b01419f8b73b93d93eb_1f5a41f3/python3-tacker-tests-4.1.0-0.20210325043415.476a52d.el8.noarch.rpm,repos/component/common/47/6a/476a52df13202a44336c8b01419f8b73b93d93eb_1f5a41f3/openstack-tacker-common-4.1.0-0.20210325043415.476a52d.el8.noarch.rpm,repos/component/common/47/6a/476a52df13202a44336c8b01419f8b73b93d93eb_1f5a41f3/python3-tacker-4.1.0-0.20210325043415.476a52d.el8.noarch.rpm,repos/component/common/47/6a/476a52df13202a44336c8b01419f8b73b93d93eb_1f5a41f3/openstack-tacker-4.1.0-0.20210325043415.476a52d.el8.noarch.rpm - civotes: '[]' - commit_branch: master - commit_hash: 476a52df13202a44336c8b01419f8b73b93d93eb - component: common - distgit_dir: /home/centos8-master-uc/data/openstack-tacker_distro/ - distro_hash: 1f5a41f31db8e3eb51caa9c0e201ab0583747be8 - dt_build: '1616646776' - dt_commit: '1616646661.0' - dt_distro: '1616411951' - dt_extended: '0' - extended_hash: None - flags: '0' - id: '21047' - notes: OK - project_name: openstack-tacker - promotions: '[]' - repo_dir: /home/centos8-master-uc/data/openstack-tacker - status: SUCCESS - type: rpm -""" # noqa - -TEST_COMMIT_YAML_CENTOS_7 = """ - commits: - - artifacts: repos/b5/ef/b5ef03c9c939db551b03e9490edc6981ff582035_76ebc465/openstack-tripleo-heat-templates-12.1.1-0.20200227052810.b5ef03c.el7.src.rpm,repos/b5/ef/b5ef03c9c939db551b03e9490edc6981ff582035_76ebc465/openstack-tripleo-heat-templates-12.1.1-0.20200227052810.b5ef03c.el7.noarch.rpm - commit_branch: master - commit_hash: b5ef03c9c939db551b03e9490edc6981ff582035 - component: None - distgit_dir: /home/centos-master-uc/data/openstack-tripleo-heat-templates_distro/ - distro_hash: 76ebc4655502820b7677579349fd500eeca292e6 - dt_build: '1582781227' - dt_commit: '1582780705.0' - dt_distro: '1580409403' - dt_extended: '0' - extended_hash: None - flags: '0' - id: '86894' - notes: OK - project_name: openstack-tripleo-heat-templates - repo_dir: /home/centos-master-uc/data/openstack-tripleo-heat-templates - status: SUCCESS - type: rpm -""" # noqa - -TEST_REPO_MD5 = 'a96366960d5f9b08f78075b7560514e7' - -BAD_CONFIG_FILE = """ -awoo: 'foo' -""" - -CONFIG_FILE = """ -dlrn_url: 'https://trunk.rdoproject.org' - -tripleo_releases: - - master - - zed - - wallaby - - victoria - - ussuri - - train - - osp16-2 - - osp17 - -tripleo_ci_components: - - baremetal - - cinder - - clients - - cloudops - - common - - compute - - glance - - manila - - network - - octavia - - security - - swift - - tempest - - tripleo - - ui - - validation - -rdo_named_tags: - - current - - consistent - - component-ci-testing - - tripleo-ci-testing - - current-tripleo - - current-tripleo-rdo - -os_versions: - - centos7 - - centos8 - - centos9 - - rhel8 - - rhel9 - -""" diff --git a/tests/unit/get_hash/test_tripleo_get_hash.py b/tests/unit/get_hash/test_tripleo_get_hash.py deleted file mode 100644 index 8998a6f..0000000 --- a/tests/unit/get_hash/test_tripleo_get_hash.py +++ /dev/null @@ -1,231 +0,0 @@ -# Copyright 2021 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 sys -import unittest -from unittest import mock -from unittest.mock import mock_open, MagicMock, patch -import yaml - -import tripleo_repos.get_hash.exceptions as exc -import tripleo_repos.get_hash.__main__ as tgh -from . import fakes as test_fakes - - -@mock.patch( - 'builtins.open', new_callable=mock_open, read_data=test_fakes.CONFIG_FILE -) -class TestGetHash(unittest.TestCase): - """In this class we test the CLI invocations for this module. - The builtin 'open' function is mocked at a - class level so we can mock the config.yaml with the contents of the - fakes.CONFIG_FILE - """ - - def test_centos_8_current_tripleo_stable(self, mock_config): - mocked = MagicMock( - return_value=(test_fakes.TEST_REPO_MD5, 200)) - with patch( - 'tripleo_repos.get_hash.tripleo_hash_info.http_get', mocked): - args = ['--os-version', 'centos8', '--release', 'victoria'] - sys.argv[1:] = args - main_res = tgh.main() - self.assertEqual(main_res.full_hash, test_fakes.TEST_REPO_MD5) - self.assertEqual( - 'https://trunk.rdoproject.org/centos8-victoria/current-tripleo/delorean.repo.md5', # noqa - main_res.dlrn_url, - ) - self.assertEqual('centos8', main_res.os_version) - self.assertEqual('victoria', main_res.release) - -# TODO(marios) reenable https://bugs.launchpad.net/tripleo/+bug/2002112 -# def test_verbose_logging_on(self, mock_config): -# args = ['--verbose'] -# debug_msgs = [] -# -# mocked = MagicMock( -# return_value=(test_fakes.TEST_REPO_MD5, 200)) -# with patch( -# 'tripleo_repos.get_hash.tripleo_hash_info.http_get', mocked): -# with self.assertLogs() as captured: -# sys.argv[1:] = args -# tgh.main() -# debug_msgs = [ -# record.message -# for record in captured.records -# if record.levelname == 'DEBUG' -# ] -# self.assertIn('Logging level set to DEBUG', debug_msgs) -# -# def test_verbose_logging_off(self, mock_config): -# debug_msgs = [] -# -# mocked = MagicMock( -# return_value=(test_fakes.TEST_REPO_MD5, 200)) -# with patch( -# 'tripleo_repos.get_hash.tripleo_hash_info.http_get', mocked): -# -# args = ['--tag', 'current-tripleo', '--os-version', 'centos8'] -# with self.assertLogs() as captured: -# sys.argv[1:] = args -# tgh.main() -# debug_msgs = [ -# record.message -# for record in captured.records -# if record.levelname == 'DEBUG' -# ] -# self.assertEqual(debug_msgs, []) - - def test_invalid_unknown_components(self, mock_config): - args = ['--component', 'nosuchcomponent'] - sys.argv[1:] = args - self.assertRaises(SystemExit, lambda: tgh.main()) - - def test_valid_tripleo_ci_components(self, mock_config): - config_file = open("fake_config_file") # open is mocked at class level - config_yaml = yaml.safe_load(config_file.read()) - config_file.close() - # interate for each of config components - for component in config_yaml['tripleo_ci_components']: - - mocked = MagicMock( - return_value=(test_fakes.TEST_COMMIT_YAML_COMPONENT, 200)) - with patch( - 'tripleo_repos.get_hash.tripleo_hash_info.http_get', - mocked): - - args = ['--component', "{}".format(component)] - sys.argv[1:] = args - main_res = tgh.main() - self.assertEqual( - "https://trunk.rdoproject.org/centos8-master/component" - "/{}/current-tripleo/commit.yaml".format( - component - ), - main_res.dlrn_url, - ) - self.assertEqual("{}".format(component), main_res.component) - - def test_invalid_component_centos7(self, mock_config): - args = ['--os-version', 'centos7', '--component', 'tripleo'] - sys.argv[1:] = args - self.assertRaises(exc.TripleOHashInvalidParameter, lambda: tgh.main()) - - def test_valid_os_version(self, mock_config): - config_file = open("fake_config_file") # open is mocked at class level - config_yaml = yaml.safe_load(config_file.read()) - config_file.close() - # interate for each supported os_version - for os_v in config_yaml['os_versions']: - if '7' in os_v: - mocked = MagicMock( - return_value=(test_fakes.TEST_COMMIT_YAML_CENTOS_7, 200)) - expected_url = ( - "https://trunk.rdoproject.org/{}-master/" - "current-tripleo/commit.yaml".format(os_v) - ) - else: - mocked = MagicMock( - return_value=(test_fakes.TEST_REPO_MD5, 200)) - expected_url = ( - "https://trunk.rdoproject.org/{}-master/" - "current-tripleo/delorean.repo.md5".format(os_v) - ) - with patch( - 'tripleo_repos.get_hash.tripleo_hash_info.http_get', - mocked): - args = ['--os-version', "{}".format(os_v)] - sys.argv[1:] = args - main_res = tgh.main() - self.assertEqual(main_res.dlrn_url, expected_url) - self.assertEqual("{}".format(os_v), main_res.os_version) - - def test_invalid_os_version(self, mock_config): - args = ['--os-version', 'rhelos99', '--component', 'tripleo'] - sys.argv[1:] = args - self.assertRaises(SystemExit, lambda: tgh.main()) - - def test_invalid_unknown_tag(self, mock_config): - args = ['--tag', 'nosuchtag'] - sys.argv[1:] = args - self.assertRaises(SystemExit, lambda: tgh.main()) - - def test_valid_rdo_named_tags(self, mock_config): - config_file = open("fake_config_file") # open is mocked at class level - config_yaml = yaml.safe_load(config_file.read()) - config_file.close() - # iterate for each of config named tags - for tag in config_yaml['rdo_named_tags']: - mocked = MagicMock( - return_value=(test_fakes.TEST_REPO_MD5, 200)) - with patch( - 'tripleo_repos.get_hash.tripleo_hash_info.http_get', - mocked): - - args = ['--tag', "{}".format(tag)] - sys.argv[1:] = args - main_res = tgh.main() - self.assertEqual( - "https://trunk.rdoproject.org/centos8-master" - "/{}/delorean.repo.md5".format( - tag - ), - main_res.dlrn_url, - ) - self.assertEqual(tag, main_res.tag) - - def test_override_dlrn_url(self, mock_config): - mocked = MagicMock( - return_value=(test_fakes.TEST_REPO_MD5, 200)) - with patch( - 'tripleo_repos.get_hash.tripleo_hash_info.http_get', - mocked): - - args = ['--dlrn-url', 'https://awoo.com/awoo'] - sys.argv[1:] = args - main_res = tgh.main() - self.assertEqual( - "https://awoo.com/awoo/centos8-master/current-tripleo" - "/delorean.repo.md5", - main_res.dlrn_url, - ) - - def test_override_os_version_release_rhel8(self, mock_config): - mocked = MagicMock( - return_value=(test_fakes.TEST_REPO_MD5, 200)) - with patch( - 'tripleo_repos.get_hash.tripleo_hash_info.http_get', - mocked): - args = [ - '--dlrn-url', - 'https://awoo.com/awoo', - '--os-version', - 'rhel8', - '--release', - 'osp16-2', - ] - sys.argv[1:] = args - main_res = tgh.main() - self.assertEqual('rhel8', main_res.os_version) - self.assertEqual('osp16-2', main_res.release) - self.assertEqual( - "https://awoo.com/awoo/rhel8-osp16-2/current-tripleo" - "/delorean.repo.md5", main_res.dlrn_url, - ) - - -if __name__ == '__main__': - unittest.main() diff --git a/tests/unit/get_hash/test_tripleo_get_hash_info.py b/tests/unit/get_hash/test_tripleo_get_hash_info.py deleted file mode 100644 index f47ff59..0000000 --- a/tests/unit/get_hash/test_tripleo_get_hash_info.py +++ /dev/null @@ -1,227 +0,0 @@ -# Copyright 2021 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 unittest -import tripleo_repos.get_hash.tripleo_hash_info as thi -import tripleo_repos.get_hash.exceptions as exc -from . import fakes as test_fakes -from unittest import mock -from unittest.mock import mock_open, MagicMock, patch - - -@mock.patch( - 'builtins.open', new_callable=mock_open, read_data=test_fakes.CONFIG_FILE -) -class TestGetHashInfo(unittest.TestCase): - """In this class we test the functions and instantiation of the - TripleOHashInfo class. The builtin 'open' function is mocked at a - class level so we can mock the config.yaml with the contents of the - fakes.CONFIG_FILE - """ - - def test_hashes_from_commit_yaml(self, mock_config): - sample_commit_yaml = test_fakes.TEST_COMMIT_YAML_COMPONENT - expected_result = ( - '476a52df13202a44336c8b01419f8b73b93d93eb_1f5a41f3', - '476a52df13202a44336c8b01419f8b73b93d93eb', - '1f5a41f31db8e3eb51caa9c0e201ab0583747be8', - 'None', - ) - mocked = MagicMock( - return_value=(test_fakes.TEST_COMMIT_YAML_COMPONENT, 200)) - with patch( - 'tripleo_repos.get_hash.tripleo_hash_info.http_get', mocked): - mock_hash_info = thi.TripleOHashInfo( - 'centos8', 'master', 'common', 'current-tripleo' - ) - actual_result = mock_hash_info._hashes_from_commit_yaml( - sample_commit_yaml - ) - self.assertEqual(expected_result, actual_result) - - def test_resolve_repo_url_component_commit_yaml(self, mock_config): - mocked = MagicMock( - return_value=(test_fakes.TEST_COMMIT_YAML_COMPONENT, 200)) - with patch( - 'tripleo_repos.get_hash.tripleo_hash_info.http_get', mocked): - c8_component_hash_info = thi.TripleOHashInfo( - 'centos8', 'master', 'common', 'current-tripleo' - ) - repo_url = c8_component_hash_info._resolve_repo_url("https://woo") - self.assertEqual( - repo_url, - 'https://woo/centos8-master/component/common/current-tripleo/commit.yaml', # noqa - ) - - def test_resolve_repo_url_centos8_repo_md5(self, mock_config): - mocked = MagicMock( - return_value=(test_fakes.TEST_REPO_MD5, 200)) - with patch( - 'tripleo_repos.get_hash.tripleo_hash_info.http_get', mocked): - c8_hash_info = thi.TripleOHashInfo( - 'centos8', 'master', None, 'current-tripleo' - ) - repo_url = c8_hash_info._resolve_repo_url("https://woo") - self.assertEqual( - repo_url, 'https://woo/centos8-master/current-tripleo/delorean.repo.md5' # noqa - - ) - - def test_resolve_repo_url_centos7_commit_yaml(self, mock_config): - mocked = MagicMock( - return_value=(test_fakes.TEST_COMMIT_YAML_CENTOS_7, 200)) - with patch( - 'tripleo_repos.get_hash.tripleo_hash_info.http_get', mocked): - c7_hash_info = thi.TripleOHashInfo( - 'centos7', 'master', None, 'current-tripleo' - ) - repo_url = c7_hash_info._resolve_repo_url("https://woo") - self.assertEqual( - repo_url, 'https://woo/centos7-master/current-tripleo/commit.yaml' # noqa - - ) - - def test_get_tripleo_hash_info_centos8_md5(self, mock_config): - mocked = MagicMock( - return_value=(test_fakes.TEST_REPO_MD5, 200)) - with patch( - 'tripleo_repos.get_hash.tripleo_hash_info.http_get', mocked): - created_hash_info = thi.TripleOHashInfo( - 'centos8', 'master', None, 'current-tripleo' - ) - self.assertIsInstance(created_hash_info, thi.TripleOHashInfo) - self.assertEqual( - created_hash_info.full_hash, test_fakes.TEST_REPO_MD5 - ) - self.assertEqual(created_hash_info.tag, 'current-tripleo') - self.assertEqual(created_hash_info.os_version, 'centos8') - self.assertEqual(created_hash_info.release, 'master') - - def test_get_tripleo_hash_info_component(self, mock_config): - expected_commit_hash = '476a52df13202a44336c8b01419f8b73b93d93eb' - expected_distro_hash = '1f5a41f31db8e3eb51caa9c0e201ab0583747be8' - expected_full_hash = '476a52df13202a44336c8b01419f8b73b93d93eb_1f5a41f3' # noqa - mocked = MagicMock( - return_value=(test_fakes.TEST_COMMIT_YAML_COMPONENT, 200)) - with patch( - 'tripleo_repos.get_hash.tripleo_hash_info.http_get', mocked): - created_hash_info = thi.TripleOHashInfo( - 'centos8', 'victoria', 'common', 'tripleo-ci-testing' - ) - self.assertIsInstance(created_hash_info, thi.TripleOHashInfo) - self.assertEqual(created_hash_info.full_hash, expected_full_hash) - self.assertEqual( - created_hash_info.distro_hash, expected_distro_hash - ) - self.assertEqual( - created_hash_info.commit_hash, expected_commit_hash - ) - self.assertEqual(created_hash_info.component, 'common') - self.assertEqual(created_hash_info.tag, 'tripleo-ci-testing') - self.assertEqual(created_hash_info.release, 'victoria') - - def test_get_tripleo_hash_info_centos7_commit_yaml(self, mock_config): - expected_commit_hash = 'b5ef03c9c939db551b03e9490edc6981ff582035' - expected_distro_hash = '76ebc4655502820b7677579349fd500eeca292e6' - expected_full_hash = 'b5ef03c9c939db551b03e9490edc6981ff582035_76ebc465' # noqa - mocked = MagicMock( - return_value=(test_fakes.TEST_COMMIT_YAML_CENTOS_7, 200)) - with patch( - 'tripleo_repos.get_hash.tripleo_hash_info.http_get', mocked): - created_hash_info = thi.TripleOHashInfo( - 'centos7', 'master', None, 'tripleo-ci-testing' - ) - self.assertIsInstance(created_hash_info, thi.TripleOHashInfo) - self.assertEqual(created_hash_info.full_hash, expected_full_hash) - self.assertEqual( - created_hash_info.distro_hash, expected_distro_hash - ) - self.assertEqual( - created_hash_info.commit_hash, expected_commit_hash - ) - self.assertEqual(created_hash_info.os_version, 'centos7') - - def test_bad_config_file(self, mock_config): - mocked = MagicMock( - return_value=test_fakes.TEST_COMMIT_YAML_CENTOS_7) - with patch( - 'tripleo_repos.get_hash.tripleo_hash_info.http_get', mocked): - with mock.patch( - 'builtins.open', - new_callable=mock_open, - read_data=test_fakes.BAD_CONFIG_FILE, - ): - self.assertRaises( - exc.TripleOHashInvalidConfig, - thi.TripleOHashInfo, - 'centos7', - 'master', - None, - 'tripleo-ci-testing', - ) - - def test_override_config_dlrn_url(self, mock_config): - expected_dlrn_url = 'https://foo.bar.baz/centos8-master/component/common/current-tripleo/commit.yaml' # noqa - mocked = MagicMock( - return_value=(test_fakes.TEST_COMMIT_YAML_COMPONENT, 200)) - with patch( - 'tripleo_repos.get_hash.tripleo_hash_info.http_get', mocked): - mock_hash_info = thi.TripleOHashInfo( - 'centos8', 'master', 'common', 'current-tripleo', - {'dlrn_url': 'https://foo.bar.baz'} - ) - self.assertEqual(expected_dlrn_url, mock_hash_info.dlrn_url) - - def test_override_config_dlrn_url_empty_ignored(self, mock_config): - expected_dlrn_url = 'https://trunk.rdoproject.org/centos8-master/component/common/current-tripleo/commit.yaml' # noqa - mocked = MagicMock( - return_value=(test_fakes.TEST_COMMIT_YAML_COMPONENT, 200)) - with patch( - 'tripleo_repos.get_hash.tripleo_hash_info.http_get', mocked): - mock_hash_info = thi.TripleOHashInfo( - 'centos8', 'master', 'common', 'current-tripleo', - {'dlrn_url': ''} - ) - self.assertEqual(expected_dlrn_url, mock_hash_info.dlrn_url) - - def test_404_dlrn_http_status_code(self, mock_config): - bad_dlrn_url = 'https://server.ok/centos8-master/component/common/current-tripleo/commit.yaml' # noqa - response_text_404 = "Some kind of 404 text NOT FOUND!" - mocked = MagicMock( - return_value=(response_text_404, 404)) - with patch( - 'tripleo_repos.get_hash.tripleo_hash_info.http_get', mocked): - with self.assertLogs() as captured: - self.assertRaises( - exc.TripleOHashInvalidDLRNResponse, - thi.TripleOHashInfo, - 'centos8', - 'master', - 'common', - 'current-tripleo', - {'dlrn_url': 'https://server.ok'}, - ) - debug_msgs = [ - record.message - for record in captured.records - if record.levelname == 'ERROR' - ] - error_str = ( - "Invalid response received from the delorean server. Queried " - "URL: {0}. Response code: {1}. Response text: {2}. Failed to " - "create TripleOHashInfo object." - ).format(bad_dlrn_url, '404', response_text_404) - self.assertIn(error_str, debug_msgs) diff --git a/tests/unit/tripleo_repos/__init__.py b/tests/unit/tripleo_repos/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/tests/unit/tripleo_repos/test_main.py b/tests/unit/tripleo_repos/test_main.py deleted file mode 100644 index 1a3387e..0000000 --- a/tests/unit/tripleo_repos/test_main.py +++ /dev/null @@ -1,773 +0,0 @@ -# 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 -from unittest import mock - -import ddt -import testtools - -from tripleo_repos import main - - -@ddt.ddt -class TestTripleORepos(testtools.TestCase): - @mock.patch('tripleo_repos.main._get_distro') - @mock.patch('sys.argv', ['tripleo-repos', 'current', '-d', 'centos8']) - @mock.patch('tripleo_repos.main._run_pkg_clean') - @mock.patch('tripleo_repos.main._validate_args') - @mock.patch('tripleo_repos.main._get_base_path') - @mock.patch('tripleo_repos.main._remove_existing') - @mock.patch('tripleo_repos.main._install_repos') - def test_main_centos8(self, mock_install, mock_remove, mock_gbp, - mock_validate, mock_clean, mock_distro): - mock_distro.return_value = ('centos', '8', 'CentOS 8') - args = main._parse_args('centos', '8') - mock_path = mock.Mock() - mock_gbp.return_value = mock_path - main.main() - mock_validate.assert_called_once_with(args, 'CentOS 8', '8') - mock_gbp.assert_called_once_with(args) - mock_remove.assert_called_once_with(args) - mock_clean.assert_called_once_with('centos8') - - @mock.patch('tripleo_repos.main._get_distro') - @mock.patch('sys.argv', ['tripleo-repos', 'current', '-d', 'fedora']) - @mock.patch('tripleo_repos.main._run_pkg_clean') - @mock.patch('tripleo_repos.main._validate_args') - @mock.patch('tripleo_repos.main._get_base_path') - @mock.patch('tripleo_repos.main._install_priorities') - @mock.patch('tripleo_repos.main._remove_existing') - @mock.patch('tripleo_repos.main._install_repos') - def test_main_fedora(self, mock_install, mock_remove, mock_ip, mock_gbp, - mock_validate, mock_clean, mock_distro): - mock_distro.return_value = ('centos', '8', 'CentOS 8') - args = main._parse_args('centos', '8') - mock_path = mock.Mock() - mock_gbp.return_value = mock_path - main.main() - mock_validate.assert_called_once_with(args, 'CentOS 8', '8') - mock_gbp.assert_called_once_with(args) - assert not mock_ip.called, '_install_priorities should no tbe called' - mock_remove.assert_called_once_with(args) - mock_install.assert_called_once_with(args, mock_path) - mock_clean.assert_called_once_with('fedora') - - @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' - args = mock.Mock() - args.distro = 'centos' - content = main._get_repo(fake_addr, args) - 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.Mock()) - 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') - @mock.patch('os.path.exists') - def test_remove_existing(self, mock_exists, mock_remove, mock_listdir): - fake_list = ['foo.repo', 'delorean.repo', - 'delorean-current-tripleo.repo', - 'tripleo-centos-opstools.repo', - 'tripleo-centos-highavailability.repo'] - mock_exists.return_value = [True, False, True, False, True, - False, False, True] - mock_listdir.return_value = fake_list - mock_args = mock.Mock() - mock_args.output_path = '/etc/yum.repos.d' - main._remove_existing(mock_args) - 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.assertIn( - mock.call('/etc/yum.repos.d/tripleo-centos-opstools.repo'), - mock_remove.mock_calls) - self.assertIn( - mock.call('/etc/distro.repos.d/' - 'tripleo-centos-highavailability.repo'), - mock_remove.mock_calls) - self.assertNotIn(mock.call('/etc/yum.repos.d/foo.repo'), - mock_remove.mock_calls) - - # There is no $DISTRO single path anymore, every path has branch - # specification, even master - def test_get_base_path(self): - args = mock.Mock() - args.branch = 'master' - args.distro = 'centos7' - args.rdo_mirror = 'http://trunk.rdoproject.org' - path = main._get_base_path(args) - self.assertEqual('http://trunk.rdoproject.org/centos7-master/', path) - - def test_get_base_path_fedora(self): - args = mock.Mock() - args.branch = 'master' - args.distro = 'fedora' - args.rdo_mirror = 'http://trunk.rdoproject.org' - path = main._get_base_path(args) - self.assertEqual('http://trunk.rdoproject.org/fedora-master/', 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('tripleo_repos.main._get_repo') - @mock.patch('tripleo_repos.main._write_repo') - def test_install_repos_current(self, mock_write, mock_get): - args = mock.Mock() - args.repos = ['current'] - args.branch = 'master' - args.output_path = 'test' - args.distro = 'fake' - mock_get.return_value = '[delorean]\nMr. Fusion' - main._install_repos(args, 'roads/') - self.assertEqual([mock.call('roads/current/delorean.repo', args), - mock.call('roads/delorean-deps.repo', args), - ], - mock_get.mock_calls) - self.assertEqual([mock.call('[delorean]\nMr. Fusion', 'test', - name='delorean'), - mock.call('[delorean]\nMr. Fusion', 'test'), - ], - mock_write.mock_calls) - - @mock.patch('tripleo_repos.main._get_repo') - @mock.patch('tripleo_repos.main._write_repo') - def test_install_repos_current_mitaka(self, mock_write, mock_get): - args = mock.Mock() - args.repos = ['current'] - args.branch = 'mitaka' - args.output_path = 'test' - args.distro = 'fake' - mock_get.return_value = '[delorean]\nMr. Fusion' - main._install_repos(args, 'roads/') - self.assertEqual([mock.call('roads/current/delorean.repo', args), - mock.call('roads/delorean-deps.repo', args), - ], - mock_get.mock_calls) - self.assertEqual([mock.call('[delorean]\nMr. Fusion', 'test', - name='delorean'), - mock.call('[delorean]\nMr. Fusion', 'test'), - ], - mock_write.mock_calls) - - @mock.patch('tripleo_repos.main._get_repo') - @mock.patch('tripleo_repos.main._write_repo') - def test_install_repos_deps(self, mock_write, mock_get): - args = mock.Mock() - args.repos = ['deps'] - args.branch = 'master' - args.output_path = 'test' - args.distro = 'fake' - mock_get.return_value = '[delorean-deps]\nMr. Fusion' - main._install_repos(args, 'roads/') - mock_get.assert_called_once_with('roads/delorean-deps.repo', args) - mock_write.assert_called_once_with('[delorean-deps]\nMr. Fusion', - 'test') - - @mock.patch('tripleo_repos.main._get_repo') - @mock.patch('tripleo_repos.main._write_repo') - def test_install_repos_current_tripleo(self, mock_write, mock_get): - args = mock.Mock() - args.repos = ['current-tripleo'] - args.branch = 'master' - args.output_path = 'test' - args.distro = 'fake' - mock_get.return_value = '[delorean]\nMr. Fusion' - main._install_repos(args, 'roads/') - self.assertEqual([mock.call('roads/current-tripleo/delorean.repo', - args), - mock.call('roads/delorean-deps.repo', args), - ], - mock_get.mock_calls) - self.assertEqual([mock.call('[delorean]\nMr. Fusion', 'test'), - mock.call('[delorean]\nMr. Fusion', 'test'), - ], - mock_write.mock_calls) - - @mock.patch('tripleo_repos.main._get_repo') - @mock.patch('tripleo_repos.main._write_repo') - def test_install_repos_current_tripleo_dev(self, mock_write, mock_get): - args = mock.Mock() - args.repos = ['current-tripleo-dev'] - args.branch = 'master' - args.output_path = 'test' - args.distro = 'fake' - mock_get.return_value = '[delorean]\nMr. Fusion' - main._install_repos(args, 'roads/') - mock_get.assert_any_call('roads/delorean-deps.repo', args) - # This is the wrong name for the deps repo, but I'm not bothered - # enough by that to mess with mocking multiple different calls. - mock_write.assert_any_call('[delorean]\nMr. Fusion', 'test') - mock_get.assert_any_call('roads/current-tripleo/delorean.repo', args) - mock_write.assert_any_call('[delorean-current-tripleo]\n' - 'priority=20\nMr. Fusion', 'test', - name='delorean-current-tripleo') - mock_get.assert_called_with('roads/current/delorean.repo', args) - mock_write.assert_called_with('[delorean]\npriority=10\n%s\n' - 'Mr. Fusion' % - main.INCLUDE_PKGS, 'test', - name='delorean') - - @mock.patch('tripleo_repos.main._get_repo') - @mock.patch('tripleo_repos.main._write_repo') - def test_install_repos_tripleo_ci_testing(self, mock_write, mock_get): - args = mock.Mock() - args.repos = ['tripleo-ci-testing'] - args.branch = 'master' - args.output_path = 'test' - args.distro = 'fake' - mock_get.return_value = '[delorean]\nMr. Fusion' - main._install_repos(args, 'roads/') - self.assertEqual([mock.call('roads/tripleo-ci-testing/delorean.repo', - args), - mock.call('roads/delorean-deps.repo', args), - ], - mock_get.mock_calls) - self.assertEqual([mock.call('[delorean]\nMr. Fusion', 'test'), - mock.call('[delorean]\nMr. Fusion', 'test'), - ], - mock_write.mock_calls) - - @mock.patch('tripleo_repos.main._get_repo') - @mock.patch('tripleo_repos.main._write_repo') - def test_install_repos_current_tripleo_rdo(self, mock_write, mock_get): - args = mock.Mock() - args.repos = ['current-tripleo-rdo'] - args.branch = 'master' - args.output_path = 'test' - args.distro = 'fake' - mock_get.return_value = '[delorean]\nMr. Fusion' - main._install_repos(args, 'roads/') - self.assertEqual([mock.call('roads/current-tripleo-rdo/delorean.repo', - args), - mock.call('roads/delorean-deps.repo', args), - ], - mock_get.mock_calls) - self.assertEqual([mock.call('[delorean]\nMr. Fusion', 'test'), - mock.call('[delorean]\nMr. Fusion', 'test'), - ], - mock_write.mock_calls) - - @ddt.data('liberty', 'mitaka', 'newton', 'ocata', 'pike', 'queens', - 'rocky', 'stein', 'master') - @mock.patch('tripleo_repos.main._write_repo') - @mock.patch('tripleo_repos.main._create_ceph') - def test_install_repos_ceph(self, - branch, - mock_create_ceph, - mock_write_repo): - ceph_release = { - 'liberty': 'hammer', - 'mitaka': 'hammer', - 'newton': 'jewel', - 'ocata': 'jewel', - 'pike': 'jewel', - 'queens': 'luminous', - 'rocky': 'luminous', - 'stein': 'nautilus', - 'train': 'nautilus', - 'ussuri': 'nautilus', - 'victoria': 'nautilus', - 'master': 'pacific', - } - args = mock.Mock() - args.repos = ['ceph'] - args.branch = branch - args.output_path = 'test' - args.distro = 'fake' - mock_repo = '[centos-ceph-luminous]\nMr. Fusion' - mock_create_ceph.return_value = mock_repo - main._install_repos(args, 'roads/') - mock_create_ceph.assert_called_once_with(args, ceph_release[branch]) - mock_write_repo.assert_called_once_with(mock_repo, 'test') - - @mock.patch('tripleo_repos.main._write_repo') - def test_install_repos_opstools(self, mock_write): - args = mock.Mock() - args.repos = ['opstools'] - args.branch = 'master' - args.output_path = 'test' - args.mirror = 'http://foo' - args.distro = 'fake' - main._install_repos(args, 'roads/') - expected_repo = ('\n[tripleo-centos-opstools]\n' - 'name=tripleo-centos-opstools\n' - 'baseurl=http://foo/centos/7/opstools/$basearch/\n' - 'gpgcheck=0\n' - 'enabled=1\n') - mock_write.assert_called_once_with(expected_repo, - 'test') - - @mock.patch('requests.get') - @mock.patch('tripleo_repos.main._write_repo') - def test_install_repos_deps_mirror(self, mock_write, mock_get): - args = mock.Mock() - args.repos = ['deps'] - args.branch = 'master' - args.output_path = 'test' - args.old_mirror = 'http://mirror.centos.org' - args.mirror = 'http://foo' - args.distro = 'centos7' - args.rdo_mirror = 'http://bar' - # Abbreviated repos to verify the regex works - fake_repo = ''' -[delorean-current-tripleo] -name=test repo -baseurl=https://trunk.rdoproject.org/centos7/some-repo-hash -enabled=1 - -[rdo-qemu-ev] -name=test qemu-ev -baseurl=http://mirror.centos.org/centos/7/virt/$basearch/kvm-common -enabled=1 -''' - expected_repo = ''' -[delorean-current-tripleo] -name=test repo -baseurl=http://bar/centos7/some-repo-hash -enabled=1 - -[rdo-qemu-ev] -name=test qemu-ev -baseurl=http://foo/centos/7/virt/$basearch/kvm-common -enabled=1 -''' - mock_get.return_value = mock.Mock(text=fake_repo, - status_code=200) - main._install_repos(args, 'roads/') - mock_write.assert_called_once_with(expected_repo, - 'test') - - def test_install_repos_invalid(self): - args = mock.Mock() - args.repos = ['roads?'] - self.assertRaises(main.InvalidArguments, main._install_repos, args, - 'roads/') - - @mock.patch('tripleo_repos.main._get_repo') - @mock.patch('tripleo_repos.main._write_repo') - def test_install_repos_centos8(self, mock_write, mock_get): - args = mock.Mock() - args.repos = ['current'] - args.branch = 'master' - args.output_path = 'test' - args.distro = 'centos8' - args.stream = False - args.mirror = 'mirror' - mock_get.return_value = '[delorean]\nMr. Fusion' - main._install_repos(args, 'roads/') - self.assertEqual([mock.call('roads/current/delorean.repo', args), - mock.call('roads/delorean-deps.repo', args), - ], - mock_get.mock_calls) - self.assertEqual([mock.call('[delorean]\nMr. Fusion', 'test', - name='delorean'), - mock.call('[delorean]\nMr. Fusion', 'test'), - mock.call(( - '\n[tripleo-centos-highavailability]\n' - 'name=tripleo-centos-highavailability\n' - 'baseurl=mirror/centos/8/HighAvailability' - '/$basearch/os/\ngpgcheck=0\nenabled=1\n'), - 'test'), - mock.call(( - '\n[tripleo-centos-powertools]\n' - 'name=tripleo-centos-powertools\n' - 'baseurl=mirror/centos/8/PowerTools' - '/$basearch/os/\ngpgcheck=0\nenabled=1\n'), - 'test') - ], - mock_write.mock_calls) - - @mock.patch('tripleo_repos.main._get_repo') - @mock.patch('tripleo_repos.main._write_repo') - def test_install_repos_centos8_stream(self, mock_write, mock_get): - args = mock.Mock() - args.repos = ['current'] - args.branch = 'master' - args.output_path = 'test' - args.distro = 'centos8' - args.stream = True - args.no_stream = False - args.mirror = 'mirror' - mock_get.return_value = '[delorean]\nMr. Fusion' - main._install_repos(args, 'roads/') - self.assertEqual([mock.call('roads/current/delorean.repo', args), - mock.call('roads/delorean-deps.repo', args), - ], - mock_get.mock_calls) - self.assertEqual([mock.call('[delorean]\nMr. Fusion', 'test', - name='delorean'), - mock.call('[delorean]\nMr. Fusion', 'test'), - mock.call(( - '\n[tripleo-centos-highavailability]\n' - 'name=tripleo-centos-highavailability\n' - 'baseurl=mirror/centos/8-stream/HighAvailability' - '/$basearch/os/\ngpgcheck=0\nenabled=1\n'), - 'test'), - mock.call(( - '\n[tripleo-centos-powertools]\n' - 'name=tripleo-centos-powertools\n' - 'baseurl=mirror/centos/8-stream/PowerTools' - '/$basearch/os/\ngpgcheck=0\nenabled=1\n'), - 'test') - ], - mock_write.mock_calls) - - @mock.patch('tripleo_repos.main._get_repo') - @mock.patch('tripleo_repos.main._write_repo') - def test_install_repos_centos9_stream(self, mock_write, mock_get): - args = mock.Mock() - args.repos = ['current'] - args.branch = 'master' - args.output_path = 'test' - args.distro = 'centos9' - args.stream = True - args.no_stream = False - args.mirror = 'mirror' - mock_get.return_value = '[delorean]\nMr. Fusion' - main._install_repos(args, 'roads/') - self.assertEqual([mock.call('roads/current/delorean.repo', args), - mock.call('roads/delorean-deps.repo', args), - ], - mock_get.mock_calls) - self.assertEqual([mock.call('[delorean]\nMr. Fusion', 'test', - name='delorean'), - mock.call('[delorean]\nMr. Fusion', 'test'), - mock.call(( - '\n[tripleo-centos-highavailability]\n' - 'name=tripleo-centos-highavailability\n' - 'baseurl=mirror/9-stream/HighAvailability' - '/$basearch/os/\ngpgcheck=0\nenabled=1\n'), - 'test'), - mock.call(( - '\n[tripleo-centos-powertools]\n' - 'name=tripleo-centos-powertools\n' - 'baseurl=mirror/9-stream/CRB' - '/$basearch/os/\ngpgcheck=0\nenabled=1\n'), - 'test'), - mock.call(( - '\n[tripleo-centos-appstream]\n' - 'name=tripleo-centos-appstream\n' - 'baseurl=mirror/9-stream/AppStream' - '/$basearch/os/\ngpgcheck=0\nenabled=1\n\n'), - 'test'), - mock.call(( - '\n[tripleo-centos-baseos]\n' - 'name=tripleo-centos-baseos\n' - 'baseurl=mirror/9-stream/BaseOS' - '/$basearch/os/\ngpgcheck=0\nenabled=1\n'), - 'test') - ], - mock_write.mock_calls) - - @mock.patch('tripleo_repos.main._get_repo') - @mock.patch('tripleo_repos.main._write_repo') - def test_install_repos_centos8_no_stream(self, mock_write, mock_get): - args = mock.Mock() - args.repos = ['current'] - args.branch = 'master' - args.output_path = 'test' - args.distro = 'centos8' - args.stream = False - args.no_stream = True - args.mirror = 'mirror' - mock_get.return_value = '[delorean]\nMr. Fusion' - main._install_repos(args, 'roads/') - self.assertEqual([mock.call('roads/current/delorean.repo', args), - mock.call('roads/delorean-deps.repo', args), - ], - mock_get.mock_calls) - self.assertEqual([mock.call('[delorean]\nMr. Fusion', 'test', - name='delorean'), - mock.call('[delorean]\nMr. Fusion', 'test'), - mock.call(( - '\n[tripleo-centos-highavailability]\n' - 'name=tripleo-centos-highavailability\n' - 'baseurl=mirror/centos/8/HighAvailability' - '/$basearch/os/\ngpgcheck=0\nenabled=1\n'), - 'test'), - mock.call(( - '\n[tripleo-centos-powertools]\n' - 'name=tripleo-centos-powertools\n' - 'baseurl=mirror/centos/8/PowerTools' - '/$basearch/os/\ngpgcheck=0\nenabled=1\n'), - 'test') - ], - mock_write.mock_calls) - - def test_write_repo(self): - m = mock.mock_open() - with mock.patch('tripleo_repos.main.open', m, create=True): - main._write_repo('#Doc\n[delorean]\nThis=Heavy', 'test') - m.assert_called_once_with('test/delorean.repo', 'w') - m().write.assert_called_once_with('#Doc\n[delorean]\nThis=Heavy') - - def test_write_repo_invalid(self): - self.assertRaises(main.NoRepoTitle, main._write_repo, 'Great Scot!', - 'test') - - def test_parse_args(self): - with mock.patch.object(sys, 'argv', ['', 'current', 'deps', '-d', - 'centos7', '-b', 'liberty', - '-o', 'test']): - args = main._parse_args('centos', '8') - self.assertEqual(['current', 'deps'], args.repos) - self.assertEqual('centos7', args.distro) - self.assertEqual('liberty', args.branch) - self.assertEqual('test', args.output_path) - - def test_parse_args_long(self): - with mock.patch.object(sys, 'argv', ['', 'current', '--distro', - 'centos7', '--branch', - 'mitaka', '--output-path', - 'test']): - args = main._parse_args('centos', '8') - self.assertEqual(['current'], args.repos) - self.assertEqual('centos7', args.distro) - self.assertEqual('mitaka', args.branch) - self.assertEqual('test', args.output_path) - - def test_change_priority(self): - result = main._change_priority('[delorean]\npriority=1', 10) - self.assertEqual('[delorean]\npriority=10', result) - - def test_change_priority_none(self): - result = main._change_priority('[delorean]', 10) - self.assertEqual('[delorean]\npriority=10', result) - - def test_change_priority_none_muilti(self): - data = "[repo1]\n[repo2]\n" - expected = "[repo1]\n{0}\n[repo2]\n{0}\n".format("priority=10") - result = main._change_priority(data, 10) - self.assertEqual(expected, result) - - def test_add_includepkgs(self): - data = "[repo1]\n[repo2]" - expected = "[repo1]\n{0}\n[repo2]\n{0}".format(main.INCLUDE_PKGS) - result = main._add_includepkgs(data) - self.assertEqual(expected, result) - - def test_create_ceph(self): - mock_args = mock.Mock(mirror='http://foo') - result = main._create_ceph(mock_args, 'jewel') - expected_repo = ''' -[tripleo-centos-ceph-jewel] -name=tripleo-centos-ceph-jewel -baseurl=http://foo/SIGs/9-stream/storage/$basearch/ceph-jewel/ -gpgcheck=0 -enabled=1 -''' - self.assertEqual(expected_repo, result) - - mock_args = mock.Mock(mirror='http://foo', distro='centos8') - result = main._create_ceph(mock_args, 'jewel') - expected_repo = ''' -[tripleo-centos-ceph-jewel] -name=tripleo-centos-ceph-jewel -baseurl=http://foo/centos/8-stream/storage/$basearch/ceph-jewel/ -gpgcheck=0 -enabled=1 -''' - self.assertEqual(expected_repo, result) - - def test_inject_mirrors_centos(self): - start_repo = ''' -[delorean] -name=delorean -baseurl=https://trunk.rdoproject.org/centos7/some-repo-hash -enabled=1 -[centos] -name=centos -baseurl=http://mirror.centos.org/centos/7/virt/$basearch/kvm-common -enabled=1 -''' - expected = ''' -[delorean] -name=delorean -baseurl=http://bar/centos7/some-repo-hash -enabled=1 -[centos] -name=centos -baseurl=http://foo/centos/7/virt/$basearch/kvm-common -enabled=1 -''' - mock_args = mock.Mock(mirror='http://foo', - rdo_mirror='http://bar', - distro='centos', - old_mirror='http://mirror.centos.org') - result = main._inject_mirrors(start_repo, mock_args) - self.assertEqual(expected, result) - - def test_inject_mirrors_rhel(self): - start_repo = ''' -[delorean] -name=delorean -baseurl=https://trunk.rdoproject.org/centos7/some-repo-hash -enabled=1 -[rhel] -name=rhel -baseurl=https://some/stuff -enabled=1 -''' - expected = ''' -[delorean] -name=delorean -baseurl=http://bar/centos7/some-repo-hash -enabled=1 -[rhel] -name=rhel -baseurl=http://foo/stuff -enabled=1 -''' - mock_args = mock.Mock(mirror='http://foo', - rdo_mirror='http://bar', - distro='rhel', - old_mirror='https://some') - result = main._inject_mirrors(start_repo, mock_args) - self.assertEqual(expected, result) - - def test_inject_mirrors_no_match(self): - start_repo = ''' -[delorean] -name=delorean -baseurl=https://some.mirror.com/centos7/some-repo-hash -enabled=1 -''' - mock_args = mock.Mock(rdo_mirror='http://some.mirror.com', - distro='centos') - # If a user has a mirror whose repos already point at itself then - # the _inject_mirrors call should be a noop. - self.assertEqual(start_repo, main._inject_mirrors(start_repo, - mock_args)) - - @mock.patch('subprocess.check_call') - def test_run_pkg_clean(self, mock_check_call): - main._run_pkg_clean('centos7') - mock_check_call.assert_called_once_with(['yum', 'clean', 'metadata']) - - @mock.patch('subprocess.check_call') - def test_run_pkg_clean_fedora(self, mock_check_call): - main._run_pkg_clean('fedora') - mock_check_call.assert_called_once_with(['dnf', 'clean', 'metadata']) - - @mock.patch('subprocess.check_call') - def test_run_pkg_clean_fails(self, mock_check_call): - mock_check_call.side_effect = subprocess.CalledProcessError(88, '88') - self.assertRaises(subprocess.CalledProcessError, - main._run_pkg_clean, ['centos7']) - - -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' - self.distro_major_version_id = "7" - self.args.stream = False - self.args.no_stream = False - - def test_good(self): - main._validate_args(self.args, '', '') - - def test_current_and_tripleo_dev(self): - self.args.repos = ['current', 'current-tripleo-dev'] - self.assertRaises(main.InvalidArguments, main._validate_args, - self.args, '', '') - - def test_tripleo_ci_testing_and_current_tripleo(self): - self.args.repos = ['current-tripleo', 'tripleo-ci-testing'] - self.assertRaises(main.InvalidArguments, main._validate_args, - self.args, '', '') - - def test_tripleo_ci_testing_and_ceph_opstools_allowed(self): - self.args.repos = ['ceph', 'opstools', 'tripleo-ci-testing'] - main._validate_args(self.args, '', '') - - def test_tripleo_ci_testing_and_deps_allowed(self): - self.args.repos = ['deps', 'tripleo-ci-testing'] - main._validate_args(self.args, '', '') - - def test_ceph_and_tripleo_dev(self): - self.args.repos = ['current-tripleo-dev', 'ceph'] - self.args.output_path = main.DEFAULT_OUTPUT_PATH - main._validate_args(self.args, '', '') - - def test_deps_and_tripleo_dev(self): - self.args.repos = ['deps', 'current-tripleo-dev'] - self.assertRaises(main.InvalidArguments, 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_deps_and_tripleo_allowed(self): - self.args.repos = ['deps', 'current-tripleo'] - 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, '', '') - - def test_invalid_stream(self): - self.args.output_path = main.DEFAULT_OUTPUT_PATH - self.args.stream = True - self.assertRaises(main.InvalidArguments, main._validate_args, - self.args, 'CentOS 8', '8') - - def test_invalid_no_stream(self): - self.args.output_path = main.DEFAULT_OUTPUT_PATH - self.args.stream = False - self.args.no_stream = True - self.assertRaises(main.InvalidArguments, main._validate_args, - self.args, 'CentOS 8 Stream', '8') - - def test_validate_distro_repos(self): - self.assertTrue(main._validate_distro_repos(self.args)) - - def test_validate_distro_repos_fedora_tripleo_dev(self): - self.args.distro = 'fedora' - self.args.repos = ['current-tripleo-dev'] - self.assertRaises(main.InvalidArguments, main._validate_distro_repos, - self.args) diff --git a/tests/unit/yum_config/__init__.py b/tests/unit/yum_config/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/tests/unit/yum_config/fakes.py b/tests/unit/yum_config/fakes.py deleted file mode 100644 index 5942f58..0000000 --- a/tests/unit/yum_config/fakes.py +++ /dev/null @@ -1,113 +0,0 @@ -# Copyright 2021 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. - -FAKE_FILE_PATH = '/path/to/file' -FAKE_DIR_PATH = '/path/to/dir' -FAKE_SUPP_OPTIONS = ['fake_option1', 'fake_option2'] -FAKE_OPTION1 = 'fake_option1' -FAKE_DIR_FILES = ['fake_file1.conf', 'fake_file2.conf', 'fake.md'] -FAKE_SECTIONS = ['fake_section1', 'fake_section2'] -FAKE_SECTION1 = 'fake_section1' -FAKE_SECTION2 = 'fake_section2' -FAKE_SET_DICT = { - 'key1': 'value1', - 'key2': 'value2', -} -FAKE_REPO_DOWN_URL = '/fake/down/url/fake.repo' - -FAKE_COMPOSE_URL = ( - 'https://composes.centos.org/fake-CentOS-Stream/compose/') -FAKE_REPO_PATH = '/etc/yum.repos.d/fake.repo' -FAKE_RELEASE_NAME = 'fake_release' - -FAKE_COMPOSE_INFO = { - "header": { - "version": "1.2", - }, - "payload": { - "compose": { - "id": "fake_compose_id", - }, - "release": { - "name": "CentOS Stream", - "short": "CentOS-Stream", - "version": "8", - }, - "variants": { - "AppStream": { - "arches": [ - "aarch64", - "ppc64le", - "x86_64" - ], - "id": "AppStream", - "name": "AppStream", - "paths": { - "packages": { - "aarch64": "AppStream/aarch64/os/Packages", - "ppc64le": "AppStream/ppc64le/os/Packages", - "x86_64": "AppStream/x86_64/os/Packages", - }, - }, - }, - "BaseOS": { - "arches": [ - "aarch64", - "ppc64le", - "x86_64", - ], - "id": "BaseOS", - "name": "BaseOS", - "paths": { - "packages": { - "aarch64": "BaseOS/aarch64/os/Packages", - "ppc64le": "BaseOS/ppc64le/os/Packages", - "x86_64": "BaseOS/x86_64/os/Packages", - }, - }, - }, - }, - }, -} - -FAKE_ENV_OUTPUT = """ -LANG=C.utf8 -HOSTNAME=4cb7d7db1907 -which_declare=declare -f -container=oci -PWD=/ -HOME=/root -TERM=xterm -SHLVL=1 -PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin -_=/usr/bin/env -""" - - -class FakeConfigParser(dict): - def __init__(self, *args, **kwargs): - super(FakeConfigParser, self).__init__(*args, **kwargs) - self.__dict__ = self - - def write(self, file, space_around_delimiters=False): - pass - - def read(self, file): - pass - - def add_section(self, section): - self[section] = {} - - def sections(self): - return self.keys() diff --git a/tests/unit/yum_config/mock_modules.py b/tests/unit/yum_config/mock_modules.py deleted file mode 100644 index 7913643..0000000 --- a/tests/unit/yum_config/mock_modules.py +++ /dev/null @@ -1,18 +0,0 @@ -# Copyright 2021 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 sys - -from unittest import mock - -sys.modules["dnf"] = mock.Mock() diff --git a/tests/unit/yum_config/test_compose_repos.py b/tests/unit/yum_config/test_compose_repos.py deleted file mode 100644 index 41db9f4..0000000 --- a/tests/unit/yum_config/test_compose_repos.py +++ /dev/null @@ -1,119 +0,0 @@ -# Copyright 2021 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 copy -import json -import os -from unittest import mock -import urllib.request - -from . import fakes -from . import test_main -import tripleo_repos.yum_config.constants as const -import tripleo_repos.yum_config.exceptions as exc -import tripleo_repos.yum_config.compose_repos as repos -import tripleo_repos.yum_config.yum_config as yum_config - - -class TestTripleOComposeRepos(test_main.TestTripleoYumConfigBase): - """Tests for TripleComposeRepos class and its methods.""" - def setUp(self): - super(TestTripleOComposeRepos, self).setUp() - self.repos = self._create_compose_repos_obj( - dir_path='/tmp' - ) - - def _create_compose_repos_obj( - self, - compose_url=fakes.FAKE_COMPOSE_URL, - release=const.COMPOSE_REPOS_RELEASES[0], - dir_path=None, - arch=const.COMPOSE_REPOS_SUPPORTED_ARCHS[0]): - - url_res = mock.Mock() - json_data = json.dumps(fakes.FAKE_COMPOSE_INFO) - self.mock_object(urllib.request, "urlopen", - mock.Mock(return_value=url_res)) - self.mock_object(url_res, 'read', - mock.Mock(return_value=json_data)) - - return repos.TripleOYumComposeRepoConfig( - compose_url, release, dir_path=dir_path, arch=arch) - - def test_tripleo_compose_repos_invalid_release(self): - self.assertRaises(exc.TripleOYumConfigComposeError, - repos.TripleOYumComposeRepoConfig, - fakes.FAKE_COMPOSE_URL, - 'invalid_release') - - def test_tripleo_compose_repos_invalid_url(self): - self.assertRaises(exc.TripleOYumConfigComposeError, - repos.TripleOYumComposeRepoConfig, - "http://invalid_url.org", - const.COMPOSE_REPOS_RELEASES[0]) - - def test__get_compose_info_exc(self): - self.mock_object(urllib.request, "urlopen", - mock.Mock(side_effect=Exception)) - - self.assertRaises(exc.TripleOYumConfigComposeError, - self.repos._get_compose_info) - - def test_enable_compose_repos(self): - self.mock_object(self.repos, 'add_section') - self.repos.enable_compose_repos( - variants=fakes.FAKE_COMPOSE_INFO['payload']['variants'].keys(), - override_repos=False - ) - - @mock.patch('builtins.open') - def test_add_section(self, open): - self.mock_object(os.path, 'isfile', mock.Mock(return_value=False)) - mock_add_section = self.mock_object(yum_config.TripleOYumConfig, - "add_section") - - self.repos.add_section(fakes.FAKE_SECTION1, fakes.FAKE_SET_DICT, - fakes.FAKE_FILE_PATH) - - mock_add_section.assert_called_once_with( - fakes.FAKE_SECTION1, fakes.FAKE_SET_DICT, fakes.FAKE_FILE_PATH - ) - - def test_update_section(self): - mock_update = self.mock_object(yum_config.TripleOYumConfig, - "update_section") - expected_set_dict = copy.deepcopy(fakes.FAKE_SET_DICT) - expected_set_dict['enabled'] = '1' - - self.repos.update_section(fakes.FAKE_SECTION1, - set_dict=fakes.FAKE_SET_DICT, - enabled=True, - file_path=fakes.FAKE_FILE_PATH) - - mock_update.assert_called_once_with(fakes.FAKE_SECTION1, - expected_set_dict, - file_path=fakes.FAKE_FILE_PATH) - - def test_update_all_sections(self): - mock_update = self.mock_object(yum_config.TripleOYumConfig, - "update_all_sections") - expected_set_dict = copy.deepcopy(fakes.FAKE_SET_DICT) - expected_set_dict['enabled'] = '0' - - self.repos.update_all_sections(fakes.FAKE_FILE_PATH, - set_dict=fakes.FAKE_SET_DICT, - enabled=False) - - mock_update.assert_called_once_with(expected_set_dict, - fakes.FAKE_FILE_PATH) diff --git a/tests/unit/yum_config/test_dnf_manager.py b/tests/unit/yum_config/test_dnf_manager.py deleted file mode 100644 index 657aa6d..0000000 --- a/tests/unit/yum_config/test_dnf_manager.py +++ /dev/null @@ -1,71 +0,0 @@ -# Copyright 2021 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 ddt -from unittest import mock - -from . import test_main -import tripleo_repos.yum_config.dnf_manager as dnf_mgr - - -@ddt.ddt -class TestTripleODnfManager(test_main.TestTripleoYumConfigBase): - """Tests for DnfModuleManager class and its methods.""" - - def setUp(self): - super(TestTripleODnfManager, self).setUp() - self.dnf = dnf_mgr.DnfModuleManager() - - @ddt.data( - {'module': 'fake', 'stream': None, 'profile': None}, - {'module': 'fake', 'stream': 'fake_stream', 'profile': None}, - {'module': 'fake', 'stream': None, 'profile': 'fake_prof'}, - {'module': 'fake', 'stream': 'fake_stream', 'profile': 'fake_prof'}, - ) - @ddt.unpack - def test__get_module_spec(self, module, stream, profile): - exp_str = module - exp_str += ':' + stream if stream else '' - exp_str += '/' + profile if profile else '' - - result = self.dnf._get_module_spec(module, stream=stream, - profile=profile) - - self.assertEqual(exp_str, result) - - @ddt.data(Exception, RuntimeError) - def test__do_transaction_failure(self, exc): - mock_transaction = self.mock_object( - self.dnf.base, 'do_transaction', - mock.Mock(side_effect=exc)) - - self.assertRaises(exc, self.dnf._do_transaction) - - mock_transaction.assert_called_once() - - @ddt.data('enable', 'disable', 'reset', 'install', 'remove') - def test_module_operations(self, operation): - fake_module = 'fake_module' - fake_stream = 'fake_stream' - fake_profile = 'fake_profile' - mock_get_mod_spec = self.mock_object(self.dnf, '_get_module_spec') - mock_op = self.mock_object(self.dnf.module_base, operation) - mock_transaction = self.mock_object(self.dnf, '_do_transaction') - - dnf_method = getattr(self.dnf, operation + "_module") - dnf_method(fake_module, stream=fake_stream, profile=fake_profile) - - mock_get_mod_spec.assert_called_once_with( - fake_module, stream=fake_stream, profile=fake_profile) - mock_op.assert_called_once() - mock_transaction.assert_called_once() diff --git a/tests/unit/yum_config/test_main.py b/tests/unit/yum_config/test_main.py deleted file mode 100644 index f24989b..0000000 --- a/tests/unit/yum_config/test_main.py +++ /dev/null @@ -1,209 +0,0 @@ -# Copyright 2021 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 ddt -import sys -import unittest -from unittest import mock - -from . import fakes -from . import mock_modules # noqa: F401 -import tripleo_repos.yum_config.__main__ as main -import tripleo_repos.yum_config.compose_repos as repos -import tripleo_repos.yum_config.constants as const -import tripleo_repos.yum_config.dnf_manager as dnf_mgr -import tripleo_repos.yum_config.utils as utils -import tripleo_repos.yum_config.yum_config as yum_cfg - - -class TestTripleoYumConfigBase(unittest.TestCase): - """Base test class for tripleo yum config module.""" - - def mock_object(self, obj, attr, new_attr=None): - if not new_attr: - new_attr = mock.Mock() - - patcher = mock.patch.object(obj, attr, new_attr) - patcher.start() - # stop patcher at the end of the test - self.addCleanup(patcher.stop) - - return new_attr - - -@ddt.ddt -class TestTripleoYumConfigMain(TestTripleoYumConfigBase): - """Test class for main method operations.""" - def setUp(self): - super(TestTripleoYumConfigMain, self).setUp() - self.mock_object(utils, 'get_distro_info', - mock.Mock(return_value=("centos", "8", None))) - - def test_main_repo(self): - sys.argv[1:] = ['repo', '--name', 'fake_repo', '--enable', - '--set-opts', 'key1=value1', 'key2=value2', - '--config-file-path', fakes.FAKE_FILE_PATH, - '--down-url', fakes.FAKE_REPO_DOWN_URL] - - yum_repo_obj = mock.Mock() - mock_update_section = self.mock_object(yum_repo_obj, - 'add_or_update_section') - mock_yum_repo_obj = self.mock_object( - yum_cfg, 'TripleOYumRepoConfig', - mock.Mock(return_value=yum_repo_obj)) - - main.main() - expected_dict = {'key1': 'value1', 'key2': 'value2'} - - mock_yum_repo_obj.assert_called_once_with(dir_path=const.YUM_REPO_DIR, - environment_file=None) - mock_update_section.assert_called_once_with( - 'fake_repo', set_dict=expected_dict, - file_path=fakes.FAKE_FILE_PATH, enabled=True, - from_url=fakes.FAKE_REPO_DOWN_URL) - - def test_main_repo_from_url(self): - sys.argv[1:] = ['repo', '--enable', - '--set-opts', 'key1=value1', 'key2=value2', - '--config-file-path', fakes.FAKE_FILE_PATH, - '--down-url', fakes.FAKE_REPO_DOWN_URL] - - yum_repo_obj = mock.Mock() - mock_update_all_sections = self.mock_object( - yum_repo_obj, 'add_or_update_all_sections_from_url') - mock_yum_repo_obj = self.mock_object( - yum_cfg, 'TripleOYumRepoConfig', - mock.Mock(return_value=yum_repo_obj)) - - main.main() - expected_dict = {'key1': 'value1', 'key2': 'value2'} - - mock_yum_repo_obj.assert_called_once_with(dir_path=const.YUM_REPO_DIR, - environment_file=None) - mock_update_all_sections.assert_called_once_with( - fakes.FAKE_REPO_DOWN_URL, file_path=fakes.FAKE_FILE_PATH, - set_dict=expected_dict, enabled=True) - - @ddt.data('enable', 'disable', 'reset', 'install', 'remove') - def test_main_module(self, operation): - sys.argv[1:] = ['module', operation, 'fake_module', '--stream', - 'fake_stream', '--profile', 'fake_profile'] - - mock_dnf_mod = mock.Mock() - mock_op = self.mock_object(mock_dnf_mod, operation + '_module') - mock_dnf_mod_obj = self.mock_object( - dnf_mgr, 'DnfModuleManager', - mock.Mock(return_value=mock_dnf_mod)) - - main.main() - - mock_dnf_mod_obj.assert_called_once() - mock_op.assert_called_once_with( - 'fake_module', stream='fake_stream', profile='fake_profile') - - def test_main_global_conf(self): - sys.argv[1:] = ['global', '--set-opts', 'key1=value1', 'key2=value2'] - yum_global_obj = mock.Mock() - mock_update_section = self.mock_object( - yum_global_obj, 'update_section') - mock_yum_global_obj = self.mock_object( - yum_cfg, 'TripleOYumGlobalConfig', - mock.Mock(return_value=yum_global_obj)) - - main.main() - expected_dict = {'key1': 'value1', 'key2': 'value2'} - - mock_yum_global_obj.assert_called_once_with(file_path=None, - environment_file=None) - mock_update_section.assert_called_once_with('main', expected_dict) - - def test_main_no_command(self): - sys.argv[1:] = [] - with self.assertRaises(SystemExit) as command: - main.main() - - self.assertEqual(2, command.exception.code) - - @ddt.data('repo') - def test_main_repo_mod_without_name(self, command): - sys.argv[1:] = [command, '--set-opts', 'key1=value1', - '--config-dir-path', '/tmp'] - - with self.assertRaises(SystemExit) as command: - main.main() - - self.assertEqual(2, command.exception.code) - - def test_main_repo_without_name_and_url(self): - sys.argv[1:] = ['repo', '--enable', - '--set-opts', 'key1=value1', 'key2=value2', - '--config-file-path', fakes.FAKE_FILE_PATH, - '--config-dir-path', '/tmp'] - - with self.assertRaises(SystemExit) as command: - main.main() - - self.assertEqual(2, command.exception.code) - - @ddt.data('key:value', 'value', 'key value') - def test_main_invalid_options_format(self, option): - sys.argv[1:] = ['global', '--set-opts', option] - - with self.assertRaises(SystemExit) as command: - main.main() - - self.assertEqual(2, command.exception.code) - - def test_main_enable_compose_repos(self): - sys.argv[1:] = [ - 'enable-compose-repos', '--compose-url', fakes.FAKE_COMPOSE_URL, - '--release', const.COMPOSE_REPOS_RELEASES[0], - '--variants', 'fake_variant', - '--disable-repos', fakes.FAKE_REPO_PATH, - '--arch', const.COMPOSE_REPOS_SUPPORTED_ARCHS[0], - ] - repos_obj = mock.Mock() - mock_yum_global_obj = self.mock_object( - repos, 'TripleOYumComposeRepoConfig', - mock.Mock(return_value=repos_obj)) - mock_enable_composes = self.mock_object( - repos_obj, 'enable_compose_repos') - mock_update_all = self.mock_object( - repos_obj, 'update_all_sections') - self.mock_object(yum_cfg, 'validated_file_path', - mock.Mock(return_value=True)) - - main.main() - - mock_yum_global_obj.assert_called_once_with( - fakes.FAKE_COMPOSE_URL, - const.COMPOSE_REPOS_RELEASES[0], - dir_path=const.YUM_REPO_DIR, - arch=const.COMPOSE_REPOS_SUPPORTED_ARCHS[0], - environment_file=None) - mock_enable_composes.assert_called_once_with( - variants=['fake_variant'], override_repos=False) - mock_update_all.assert_called_once_with( - fakes.FAKE_REPO_PATH, enabled=False - ) - - def test_main_invalid_release_for_dnf_module(self): - self.mock_object(utils, 'get_distro_info', - mock.Mock(return_value=("centos", "7", None))) - sys.argv[1:] = ['module', 'enable', 'fake_module'] - - with self.assertRaises(SystemExit) as command: - main.main() - - self.assertEqual(2, command.exception.code) diff --git a/tests/unit/yum_config/test_yum_config.py b/tests/unit/yum_config/test_yum_config.py deleted file mode 100644 index ac26d7b..0000000 --- a/tests/unit/yum_config/test_yum_config.py +++ /dev/null @@ -1,462 +0,0 @@ -# Copyright 2021 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 configparser -import copy -import ddt -import os -import subprocess -from unittest import mock - -from . import fakes -from . import test_main -import tripleo_repos.yum_config.constants as const -import tripleo_repos.yum_config.exceptions as exc -import tripleo_repos.yum_config.yum_config as yum_cfg -import tripleo_repos.utils as repos_utils - - -@ddt.ddt -class TestTripleOYumConfig(test_main.TestTripleoYumConfigBase): - """Tests for TripleYumConfig class and its methods.""" - - def _create_yum_config_obj(self, dir_path=None, valid_options=None, - file_extension=None): - self.mock_object(os.path, 'isfile') - self.mock_object(os, 'access') - self.mock_object(os.path, 'isdir') - return yum_cfg.TripleOYumConfig(dir_path=dir_path, - valid_options=valid_options, - file_extension=file_extension) - - def test_tripleo_yum_config_invalid_dir_path(self): - self.mock_object(os.path, 'isdir', - mock.Mock(return_value=False)) - - self.assertRaises(exc.TripleOYumConfigNotFound, - yum_cfg.TripleOYumConfig, - dir_path='fake_dir_path') - - def test_read_config_file_path(self): - yum_config = self._create_yum_config_obj() - - parser_mock = mock.Mock() - self.mock_object(configparser, 'ConfigParser', - mock.Mock(return_value=parser_mock)) - read_mock = self.mock_object(parser_mock, 'read') - self.mock_object(parser_mock, 'sections', - mock.Mock(return_value=fakes.FAKE_SECTIONS)) - - config_parser, file_path = yum_config._read_config_file( - fakes.FAKE_FILE_PATH, - section=fakes.FAKE_SECTION1 - ) - - self.assertEqual(parser_mock, config_parser) - self.assertEqual(fakes.FAKE_FILE_PATH, file_path) - read_mock.assert_called_once_with(fakes.FAKE_FILE_PATH) - - def test_read_config_file_path_parse_error(self): - yum_config = self._create_yum_config_obj() - - parser_mock = mock.Mock() - self.mock_object(configparser, 'ConfigParser', - mock.Mock(return_value=parser_mock)) - read_mock = self.mock_object(parser_mock, 'read', - mock.Mock(side_effect=configparser.Error)) - - self.assertRaises(exc.TripleOYumConfigFileParseError, - yum_config._read_config_file, - fakes.FAKE_FILE_PATH, - section=fakes.FAKE_SECTION1) - - read_mock.assert_called_once_with(fakes.FAKE_FILE_PATH) - - def test_read_config_file_path_invalid_section(self): - yum_config = self._create_yum_config_obj() - - parser_mock = mock.Mock() - self.mock_object(configparser, 'ConfigParser', - mock.Mock(return_value=parser_mock)) - read_mock = self.mock_object(parser_mock, 'read') - self.mock_object(parser_mock, 'sections', - mock.Mock(return_value=fakes.FAKE_SECTIONS)) - - self.assertRaises(exc.TripleOYumConfigInvalidSection, - yum_config._read_config_file, - fakes.FAKE_FILE_PATH, - section='invalid_section') - - read_mock.assert_called_once_with(fakes.FAKE_FILE_PATH) - - def test_get_config_files(self): - yum_config = self._create_yum_config_obj( - dir_path=fakes.FAKE_DIR_PATH, - file_extension='.conf') - parser_mocks = [] - for i in range(3): - parser_mock = mock.Mock() - parser_mocks.append(parser_mock) - self.mock_object(parser_mock, 'read') - - self.mock_object(parser_mocks[0], 'sections', - mock.Mock(return_value=[])) - # second file inside dir will have the expected sections - self.mock_object(parser_mocks[1], 'sections', - mock.Mock(return_value=fakes.FAKE_SECTIONS)) - self.mock_object(parser_mocks[2], 'sections', - mock.Mock(return_value=[])) - self.mock_object(os, 'listdir', - mock.Mock(return_value=fakes.FAKE_DIR_FILES)) - self.mock_object(os, 'access', mock.Mock(return_value=True)) - self.mock_object(configparser, 'ConfigParser', - mock.Mock(side_effect=parser_mocks)) - - result = yum_config._get_config_files(fakes.FAKE_SECTION1) - expected_dir_path = [os.path.join(fakes.FAKE_DIR_PATH, - fakes.FAKE_DIR_FILES[1])] - - self.assertEqual(expected_dir_path, result) - - @mock.patch('builtins.open') - def test_update_section(self, open): - yum_config = self._create_yum_config_obj( - valid_options=fakes.FAKE_SUPP_OPTIONS) - config_parser = fakes.FakeConfigParser({fakes.FAKE_SECTION1: {}}) - - mock_read_config = self.mock_object( - yum_config, '_read_config_file', - mock.Mock(return_value=(config_parser, fakes.FAKE_FILE_PATH))) - - updates = {fakes.FAKE_OPTION1: 'new_fake_value'} - - yum_config.update_section(fakes.FAKE_SECTION1, updates, - file_path=fakes.FAKE_FILE_PATH) - - mock_read_config.assert_called_once_with(fakes.FAKE_FILE_PATH, - section=fakes.FAKE_SECTION1) - - def test_update_section_invalid_options(self): - yum_config = self._create_yum_config_obj( - valid_options=fakes.FAKE_SUPP_OPTIONS) - - updates = {'invalid_option': 'new_fake_value'} - - self.assertRaises(exc.TripleOYumConfigInvalidOption, - yum_config.update_section, - fakes.FAKE_SECTION1, - updates, - file_path=fakes.FAKE_FILE_PATH) - - def test_update_section_file_not_found(self): - yum_config = self._create_yum_config_obj( - valid_options=fakes.FAKE_SUPP_OPTIONS) - mock_get_configs = self.mock_object( - yum_config, '_get_config_files', - mock.Mock(return_value=[])) - - updates = {fakes.FAKE_OPTION1: 'new_fake_value'} - - self.assertRaises(exc.TripleOYumConfigNotFound, - yum_config.update_section, - fakes.FAKE_SECTION1, - updates) - mock_get_configs.assert_called_once_with(fakes.FAKE_SECTION1) - - @mock.patch('builtins.open') - def test_add_section(self, open): - yum_config = self._create_yum_config_obj( - valid_options=fakes.FAKE_SUPP_OPTIONS) - config_parser = fakes.FakeConfigParser({fakes.FAKE_SECTION1: {}}) - - mock_read_config = self.mock_object( - yum_config, '_read_config_file', - mock.Mock(return_value=(config_parser, fakes.FAKE_FILE_PATH))) - - updates = {fakes.FAKE_OPTION1: 'new_fake_value'} - - yum_config.add_section(fakes.FAKE_SECTION2, updates, - file_path=fakes.FAKE_FILE_PATH) - - mock_read_config.assert_called_once_with( - file_path=fakes.FAKE_FILE_PATH) - - @mock.patch('builtins.open') - def test_add_section_already_exists(self, open): - yum_config = self._create_yum_config_obj( - valid_options=fakes.FAKE_SUPP_OPTIONS) - config_parser = fakes.FakeConfigParser({fakes.FAKE_SECTION1: {}}) - - mock_read_config = self.mock_object( - yum_config, '_read_config_file', - mock.Mock(return_value=(config_parser, fakes.FAKE_FILE_PATH))) - - updates = {fakes.FAKE_OPTION1: 'new_fake_value'} - - self.assertRaises(exc.TripleOYumConfigInvalidSection, - yum_config.add_section, - fakes.FAKE_SECTION1, updates, - file_path=fakes.FAKE_FILE_PATH) - - mock_read_config.assert_called_once_with( - file_path=fakes.FAKE_FILE_PATH) - - @mock.patch('builtins.open') - def test_add_update_all_sections(self, open): - yum_config = self._create_yum_config_obj( - valid_options=fakes.FAKE_SUPP_OPTIONS) - config_parser = fakes.FakeConfigParser({fakes.FAKE_SECTION1: {}}) - - mock_read_config = self.mock_object( - yum_config, '_read_config_file', - mock.Mock(return_value=(config_parser, fakes.FAKE_FILE_PATH))) - - updates = {fakes.FAKE_OPTION1: 'new_fake_value'} - - yum_config.update_all_sections(updates, fakes.FAKE_FILE_PATH) - - mock_read_config.assert_called_once_with(fakes.FAKE_FILE_PATH) - - def test_source_env_file(self): - p_open_mock = mock.Mock() - mock_open = self.mock_object(subprocess, 'Popen', - mock.Mock(return_value=p_open_mock)) - data_mock = mock.Mock() - self.mock_object(data_mock, 'decode', - mock.Mock(return_value=fakes.FAKE_ENV_OUTPUT)) - self.mock_object(p_open_mock, 'communicate', - mock.Mock(return_value=[data_mock])) - env_update_mock = self.mock_object(os.environ, 'update') - - yum_cfg.source_env_file('fake_source_file', update=True) - - exp_env_dict = dict( - line.split("=", 1) for line in fakes.FAKE_ENV_OUTPUT.splitlines() - if len(line.split("=", 1)) > 1) - - mock_open.assert_called_once_with(". fake_source_file; env", - stdout=subprocess.PIPE, - shell=True) - env_update_mock.assert_called_once_with(exp_env_dict) - - def test_get_config_from_url_invalid_url(self): - yum_config = self._create_yum_config_obj( - valid_options=fakes.FAKE_SUPP_OPTIONS) - fake_context = mock.Mock() - self.mock_object(repos_utils, 'http_get', - mock.Mock(return_value=(fake_context, 404))) - - self.assertRaises(exc.TripleOYumConfigUrlError, - yum_config.get_config_from_url, - fakes.FAKE_REPO_DOWN_URL) - - def test_get_config_from_url(self): - yum_config = self._create_yum_config_obj( - valid_options=fakes.FAKE_SUPP_OPTIONS) - fake_context = mock.Mock() - self.mock_object(repos_utils, 'http_get', - mock.Mock(return_value=(fake_context, 200))) - parser_mock = mock.Mock() - self.mock_object(configparser, 'ConfigParser', - mock.Mock(return_value=parser_mock)) - - result = yum_config.get_config_from_url(fakes.FAKE_REPO_DOWN_URL) - - self.assertEqual(parser_mock, result) - - def test_get_options_from_url_section_not_found(self): - yum_config = self._create_yum_config_obj( - valid_options=fakes.FAKE_SUPP_OPTIONS) - fake_config = mock.Mock() - self.mock_object(fake_config, 'sections', - mock.Mock(return_value=[])) - mock_get_from_url = self.mock_object( - yum_config, 'get_config_from_url', - mock.Mock(return_value=fake_config)) - - self.assertRaises(exc.TripleOYumConfigInvalidSection, - yum_config.get_options_from_url, - fakes.FAKE_REPO_DOWN_URL, - fakes.FAKE_SECTION1) - - mock_get_from_url.assert_called_once_with(fakes.FAKE_REPO_DOWN_URL) - - -@ddt.ddt -class TestTripleOYumRepoConfig(test_main.TestTripleoYumConfigBase): - """Tests for TripleOYumRepoConfig class and its methods.""" - - def setUp(self): - super(TestTripleOYumRepoConfig, self).setUp() - self.config_obj = yum_cfg.TripleOYumRepoConfig( - dir_path='/tmp' - ) - - @ddt.data(True, False, None) - def test_yum_repo_config_update_section(self, enable): - self.mock_object(os.path, 'isfile') - self.mock_object(os, 'access') - self.mock_object(os.path, 'isdir') - - mock_update = self.mock_object(yum_cfg.TripleOYumConfig, - 'update_section') - - updates = {fakes.FAKE_OPTION1: 'new_fake_value'} - expected_updates = copy.copy(updates) - if enable is not None: - expected_updates['enabled'] = '1' if enable else '0' - - self.config_obj.update_section( - fakes.FAKE_SECTION1, set_dict=updates, - file_path=fakes.FAKE_FILE_PATH, enabled=enable) - - mock_update.assert_called_once_with(fakes.FAKE_SECTION1, - expected_updates, - file_path=fakes.FAKE_FILE_PATH) - - @mock.patch('builtins.open') - @ddt.data(None, fakes.FAKE_REPO_DOWN_URL) - def test_add_or_update_section(self, open, down_url): - mock_update = self.mock_object( - self.config_obj, 'update_section', - mock.Mock(side_effect=exc.TripleOYumConfigNotFound( - error_msg='error'))) - mock_add_section = self.mock_object(self.config_obj, 'add_section') - extra_opt = {'key1': 'new value 1'} - mock_get_from_url = self.mock_object( - self.config_obj, 'get_options_from_url', - mock.Mock(return_value=extra_opt)) - - self.config_obj.add_or_update_section( - fakes.FAKE_SECTION1, - set_dict=fakes.FAKE_SET_DICT, - file_path=fakes.FAKE_FILE_PATH, - enabled=True, - create_if_not_exists=True, - from_url=down_url) - - fake_set_dict = copy.deepcopy(fakes.FAKE_SET_DICT) - fake_set_dict['name'] = fakes.FAKE_SECTION1 - if down_url: - fake_set_dict.update(extra_opt) - mock_get_from_url.assert_called_once_with(down_url, - fakes.FAKE_SECTION1) - - mock_update.assert_called_once_with(fakes.FAKE_SECTION1, - set_dict=fake_set_dict, - file_path=fakes.FAKE_FILE_PATH, - enabled=True) - mock_add_section.assert_called_once_with( - fakes.FAKE_SECTION1, - fake_set_dict, - fakes.FAKE_FILE_PATH, - enabled=True) - - @ddt.data((fakes.FAKE_FILE_PATH, False), (None, True)) - @ddt.unpack - def test_add_or_update_section_file_not_found(self, fake_path, - create_if_not_exists): - mock_update = self.mock_object( - self.config_obj, 'update_section', - mock.Mock(side_effect=exc.TripleOYumConfigNotFound( - error_msg='error'))) - - self.assertRaises( - exc.TripleOYumConfigNotFound, - self.config_obj.add_or_update_section, - fakes.FAKE_SECTION1, - set_dict=fakes.FAKE_SET_DICT, - file_path=fake_path, - enabled=True, - create_if_not_exists=create_if_not_exists) - - fake_set_dict = copy.deepcopy(fakes.FAKE_SET_DICT) - fake_set_dict['name'] = fakes.FAKE_SECTION1 - mock_update.assert_called_once_with(fakes.FAKE_SECTION1, - set_dict=fake_set_dict, - file_path=fake_path, - enabled=True) - - @ddt.data(None, False, True) - def test_add_section(self, enabled): - mock_add = self.mock_object(yum_cfg.TripleOYumConfig, 'add_section') - - self.config_obj.add_section( - fakes.FAKE_SECTION1, fakes.FAKE_SET_DICT, - fakes.FAKE_FILE_PATH, enabled=enabled) - - updated_dict = copy.deepcopy(fakes.FAKE_SET_DICT) - if enabled is not None: - updated_dict['enabled'] = '1' if enabled else '0' - mock_add.assert_called_once_with(fakes.FAKE_SECTION1, updated_dict, - fakes.FAKE_FILE_PATH) - - @ddt.data(fakes.FAKE_FILE_PATH, None) - def test_add_or_update_all_sections_from_url(self, file_path): - add_or_update_section = self.mock_object( - self.config_obj, 'add_or_update_section') - fake_config = mock.Mock() - self.mock_object(fake_config, 'sections', - mock.Mock(return_value=[fakes.FAKE_SECTION1])) - options_from_url = {'key3': 'value3'} - self.mock_object(fake_config, 'items', - mock.Mock(return_value=options_from_url)) - mock_get_from_url = self.mock_object( - self.config_obj, 'get_config_from_url', - mock.Mock(return_value=fake_config)) - exp_file_path = ( - file_path or os.path.join( - '/tmp', fakes.FAKE_REPO_DOWN_URL.split('/')[-1]) - ) - - self.config_obj.add_or_update_all_sections_from_url( - fakes.FAKE_REPO_DOWN_URL, - file_path=file_path, - set_dict=fakes.FAKE_SET_DICT, - enabled=True, - create_if_not_exists=True) - - mock_get_from_url.assert_called_once_with(fakes.FAKE_REPO_DOWN_URL) - expected_update_dict = copy.deepcopy(fakes.FAKE_SET_DICT) - expected_update_dict.update(options_from_url) - add_or_update_section.assert_called_once_with( - fakes.FAKE_SECTION1, set_dict=expected_update_dict, - file_path=exp_file_path, enabled=True, - create_if_not_exists=True) - - -@ddt.ddt -class TestTripleOYumGlobalConfig(test_main.TestTripleoYumConfigBase): - """Tests for TripleOYumGlobalConfig class and its methods.""" - - @mock.patch('builtins.open') - def test_create_yum_global_config_create_yum_conf(self, open): - self.mock_object(os, 'access') - self.mock_object(os.path, 'isdir') - self.mock_object(os.path, 'isfile', - mock.Mock(side_effect=[False, True])) - - fake_cfg_parser = mock.Mock() - mock_read = self.mock_object(fake_cfg_parser, 'read') - mock_add = self.mock_object(fake_cfg_parser, 'add_section') - mock_write = self.mock_object(fake_cfg_parser, 'write') - self.mock_object(configparser, 'ConfigParser', - mock.Mock(return_value=fake_cfg_parser)) - - cfg_obj = yum_cfg.TripleOYumGlobalConfig() - - self.assertIsNotNone(cfg_obj) - mock_read.assert_called_once_with(const.YUM_GLOBAL_CONFIG_FILE_PATH) - mock_add.assert_called_once_with('main') - mock_write.assert_called_once() diff --git a/tox.ini b/tox.ini deleted file mode 100644 index ddbcd88..0000000 --- a/tox.ini +++ /dev/null @@ -1,108 +0,0 @@ -[tox] -minversion = 3.18.0 -skipsdist = True -envlist = py,pep8,packaging,sanity -requires = - tox-ansible>=1.5.3 - -[testenv] -usedevelop = True -setenv = - ANSIBLE_FORCE_COLOR={tty:1:0} - VIRTUAL_ENV={envdir} -passenv = - HOME -deps = - -c{env:TOX_CONSTRAINTS_FILE:https://releases.openstack.org/constraints/upper/master} - -r{toxinidir}/test-requirements.txt - -r{toxinidir}/requirements.txt -commands = - stestr run --slowest {posargs} - -[testenv:venv] -commands = {posargs} - -[testenv:docs] -deps = - -c{env:TOX_CONSTRAINTS_FILE:https://releases.openstack.org/constraints/upper/master} - -r{toxinidir}/doc/requirements.txt -allowlist_externals = - rm -commands = - rm -rf doc/build - sphinx-build -W --keep-going -b html doc/source doc/build/html - -[testenv:pep8] -deps = flake8 -commands = flake8 - -[testenv:cover] -setenv = - PYTHON=coverage run --source tripleo_repos --parallel-mode -commands = - stestr run {posargs} - coverage combine - coverage html -d cover - coverage xml -o cover/coverage.xml - -[testenv:packaging] -description = - Build package, verify metadata, install package and assert basic behavior -deps = - build - twine - ansible-core # used for ansible-galaxy command -skip_install = true -commands = - # build wheel and sdist using PEP-517 - {envpython} -c 'import os.path, shutil, sys; \ - dist_dir = os.path.join("{toxinidir}", "dist"); \ - os.path.isdir(dist_dir) or sys.exit(0); \ - print("Removing \{!s\} contents...".format(dist_dir), file=sys.stderr); \ - shutil.rmtree(dist_dir)' - {envpython} -m build \ - --sdist \ - --wheel \ - --outdir {toxinidir}/dist/ \ - {toxinidir} - # Validate metadata using twine - twine check {toxinidir}/dist/* - # Install the wheel - sh -c "python3 -m pip install {toxinidir}/dist/*.whl" - # Assure that CLIs were installed - tripleo-repos --help - tripleo-get-hash --help - tripleo-yum-config --help - # Validate collection installation - ansible-galaxy collection install --force . - # Ensure that ansible is able to load the modules, as syntax check will fail - # if modules cannot be loaded. - sh -c "ansible-playbook --syntax-check playbooks/*.yaml" - ansible localhost -m tripleo.repos.get_hash -a "release=master os_version=centos8" - -allowlist_externals = - sh - -# https://github.com/ansible-community/tox-ansible/issues/96 -# Override ansible version coming from ansible-test package. -[testenv:sanity] -deps = - ansible-core>=2.11,<2.12 - -[testenv:molecule] -description = Used by all molecule jobs (tox-ansible) -deps = - ansible-core - molecule>=3.3.0,<3.4.0 # bug with collection install - molecule-docker -usedevelop = False -skip_install = true -commands = - ansible-galaxy collection install -v 'community.docker:>=1.8.0' - ansible-galaxy collection install -v --force . - molecule test - -[flake8] -ignore = H803 -show-source = True -exclude = .tox,dist,doc,*.egg,build diff --git a/tripleo_repos b/tripleo_repos deleted file mode 120000 index 13d7fbe..0000000 --- a/tripleo_repos +++ /dev/null @@ -1 +0,0 @@ -plugins/module_utils/tripleo_repos \ No newline at end of file diff --git a/zuul.d/layout.yaml b/zuul.d/layout.yaml deleted file mode 100644 index 83e544f..0000000 --- a/zuul.d/layout.yaml +++ /dev/null @@ -1,40 +0,0 @@ -- job: - name: tox-sanity-py39 - description: Run ansible-test sanity tests on a collection - parent: openstack-tox-py39 - vars: - tox_envlist: sanity -- project: - templates: - - check-requirements - - openstack-cover-jobs - - openstack-python3-zed-jobs - check: - jobs: - - openstack-tox-pep8: - vars: - tox_envlist: pep8,packaging - - openstack-tox-py39 - - tripleo-tox-molecule - - tripleo-buildimage-overcloud-hardened-uefi-full-centos-9: - dependencies: &deps_unit_lint_cprovider - - openstack-tox-pep8 - - openstack-tox-py38 - - openstack-tox-py39 - - tripleo-ci-centos-9-content-provider: - dependencies: *deps_unit_lint_cprovider - # TODO(marios) re-enable when https://bugs.launchpad.net/tripleo/+bug/2002112 - # - tox-sanity-py39 - gate: - jobs: - - openstack-tox-pep8: - vars: - tox_envlist: pep8,packaging - - openstack-tox-py39 - - tripleo-buildimage-overcloud-hardened-uefi-full-centos-9: - dependencies: *deps_unit_lint_cprovider - - tripleo-ci-centos-9-content-provider: - dependencies: *deps_unit_lint_cprovider - post: - jobs: - - publish-openstack-python-branch-tarball