Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add initial content #1

Merged
merged 1 commit into from
May 23, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
61 changes: 61 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
*$py.class

# C extensions
*.so

# Distribution / packaging
.Python
env/
ven*/
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
*.egg-info/
.installed.cfg
*.egg

# PyInstaller
# Usually these files are written by a python script from a template
# before PyInstaller builds the exe, so as to inject date/other infos into it.
*.manifest
*.spec

# Installer logs
pip-log.txt
pip-delete-this-directory.txt

# Unit test / coverage reports
htmlcov/
.tox/
.coverage
.coverage.*
.cache
nosetests.xml
coverage.xml
*,cover
.hypothesis/

# PyBuilder
target/

# dotenv
.env

# pytest
.pytest_cache/

# project
*settings.yaml
manifests/*
manifester_settings.yaml
27 changes: 27 additions & 0 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
# configuration for pre-commit git hooks

repos:
- repo: https://github.com/asottile/reorder_python_imports
rev: v3.0.1
hooks:
- id: reorder-python-imports
- repo: https://github.com/asottile/pyupgrade
rev: v2.32.0
hooks:
- id: pyupgrade
args: [--py36-plus]
- repo: https://github.com/psf/black
rev: 22.3.0
hooks:
- id: black
- repo: https://gitlab.com/pycqa/flake8
rev: 3.9.2
hooks:
- id: flake8
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v4.2.0
hooks:
- id: trailing-whitespace
- id: end-of-file-fixer
- id: check-yaml
- id: debug-statements
35 changes: 35 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
# Manifester

Red Hat subscriptions made manifest.

# Description
Manifester is a tool that uses the Red Hat Subscription Management (RHSM) API to dynamically create and populate subscription allocations and to export subscription manifests for use by Red Hat Satellite and other Red Hat products.
# Installation

Clone this repository:
```
git clone https://github.com/SatelliteQE/manifester
```
Copy and rename the `manifester_settings.yaml.example` file to `manifester_settings.yaml`.

An offline token is required to generate an offline token the temporary access tokens used for authenticating to the RHSM API. Either use an existing offline token for an RHSM account or generate one using the instructions in the article [Getting started with Red Hat APIs](https://access.redhat.com/articles/3626371#bgenerating-a-new-offline-tokenb-3). Add the offline token to `manifester_settings.yaml`.

From the base directory of the local clone of the manifest repository, install the project to a local Python environment:
```
pip install .
```
# Configuration

The `manifester_settings.yaml` file is used to configure manifester via [DynaConf](https://github.com/rochacbruno/dynaconf/).

Multiple types of manifests can be configured in the `manifest_category` section of `manifester_settings.yaml`. These types can be differentiated based on the Satellite version of the subscription allocation, the names and quantities of the subscriptions to be added to the manifest, and whether [Simple Content Access](https://access.redhat.com/documentation/en-us/subscription_central/2021/html-single/getting_started_with_simple_content_access/index) is enabled on the manifest.

The value of the `name` setting for each subscription in a manifest must exactly match the name of a subscription available in the account which was used to generate the offline token. One method for determining the subscription names available in an account is to register a system to RHSM and then run `subscription manager list --available` on that system. A planned future feature of Manifester is a CLI command that will return a list of available subscriptions.

# CLI Usage

Currently, the only action supported by the manifester CLI is generating a manifest using the `get-manifest` subcommand:
```
manifester get-manifest --manifest-category <manifest category name> --allocation_name <allocation name>
```
Two options are available for this subcommand. The `--manifest_category` option is required and must match one of the manifest categories defined in `manifester_settings.yaml`. The `--allocation_name` option specifies the name of the subscription allocation in RHSM and is also used in the file name of the manifest archive exported by Manifester. If no value is supplied for `--allocation_name`, a string of 10 random alphabetic characters will be used for the allocation name.
4 changes: 4 additions & 0 deletions logs/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# Ignore everything in this directory
*
# Except this file
!.gitignore
1 change: 1 addition & 0 deletions manifester/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
from manifester.manifester import Manifester
24 changes: 24 additions & 0 deletions manifester/commands.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import click

from manifester import logger as mlog
from manifester.settings import settings
from manifester import Manifester

# To do: add a command for returning subscription pools
@click.group
def cli():
pass


@cli.command()
@click.option("--manifest_category", type=str, help="Category of manifest (golden_ticket or robottelo_automation by default)")
@click.option("--allocation_name", type=str, help="Name of upstream subscription allocation")
def get_manifest(manifest_category, allocation_name):
manifester = Manifester(manifest_category, allocation_name)
manifester.create_subscription_allocation()
for sub in manifester.subscription_data:
manifester.process_subscription_pools(
subscription_pools=manifester.subscription_pools,
subscription_data=sub,
)
manifester.trigger_manifest_export()
23 changes: 23 additions & 0 deletions manifester/helpers.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import time

from logzero import logger


def simple_retry(cmd, cmd_args=None, cmd_kwargs=None, max_timeout=240, _cur_timeout=1):
"""Re(Try) a function given its args and kwargs up until a max timeout"""
cmd_args = cmd_args if cmd_args else []
cmd_kwargs = cmd_kwargs if cmd_kwargs else {}
# If additional debug information is needed, the following log entry can be modified to
# include the data being passed by adding {cmd_kwargs=} to the f-string. Please do so
# with caution as some data (notably the offline token) should be treated as a secret.
logger.debug(f"Sending request to endpoint {cmd_args}")
response = cmd(*cmd_args, **cmd_kwargs)
logger.debug(f"Response status code is {response.status_code}")
if response.status_code in [429, 500, 504]:
new_wait = _cur_timeout * 2
if new_wait > max_timeout:
raise Exception("Timeout exceeded")
logger.debug(f"Trying again in {_cur_timeout} seconds")
time.sleep(_cur_timeout)
response = simple_retry(cmd, cmd_args, cmd_kwargs, max_timeout, new_wait)
return response
28 changes: 28 additions & 0 deletions manifester/logger.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import logging

import logzero

from manifester.settings import settings

def setup_logzero(level="info", path="logs/manifester.log", silent=True):
log_fmt = "%(color)s[%(levelname)s %(asctime)s]%(end_color)s %(message)s"
debug_fmt = (
"%(color)s[%(levelname)1.1s %(asctime)s %(module)s:%(lineno)d]"
"%(end_color)s %(message)s"
)
log_level = getattr(logging, level.upper(), logging.INFO)
# formatter for terminal
formatter = logzero.LogFormatter(
fmt=debug_fmt if log_level is logging.DEBUG else log_fmt
)
logzero.setup_default_logger(formatter=formatter, disableStderrLogger=silent)
logzero.loglevel(log_level)
# formatter for file
formatter = logzero.LogFormatter(
fmt=debug_fmt if log_level is logging.DEBUG else log_fmt, color=False
)
logzero.logfile(
path, loglevel=log_level, maxBytes=1e9, backupCount=3, formatter=formatter
)

setup_logzero(level=settings.log_level)
Loading