Cibyl
Cibyl is a command-line interface and REST API for querying CI environments and systems.
It supports out-of-the-box the following CI systems:
Jenkins
Zuul
Cibyl allows you to configure multiple environments, where each environment contains one or more CI/CD system and each CI/CD system can be queried using different types of source

The project originated from Red Hat OpenStack DevOps team that looked for a solution to provide a powerful and flexible way for inspecting multiple different CI environments and systems, with regards to product aspects.
The name Cibyl, a form of Sybil, derived from the Greek sybilla or sibilla. Like a prophetess, Cibyl delves into the depths of CI systems for “hidden” info revelation. CI-byl is also a wordplay that reflects the relation to CI.
Index
Bootstrap
Installation
Install cibyl from GitHub (Recommended):
pip install 'git+https://github.com/rhos-infra/cibyl.git'
Configuration
In order to use Cibyl’s CLI, you should set up configuration first in ~/.config/cibyl.yaml
.
Configuration is structured as follows
# Minimal configuration
environments: # List of CI/CD environments
production: # An environment called "production"
production_jenkins: # A single system called "production_jenkins"
system_type: jenkins # The type of the system (jenkins or zuul)
sources: # List of sources belong to "production_jenkins" system
jenkins_api: # The name of the source which belongs to "production_jenkins" system
driver: jenkins # The driver the source will be using
url: https://... # The URL of the system
username: user # The username to use for the authentication
token: xyz # The token to use for the authentication
cert: False # Disable/Enable certificates to use for the authentication
plugins: # (Optional) Specify the plugins to enable when running Cibyl
- openstack # OpenStack adds its own product related models and arguments
Note
For more information on how to set up the configuration, read the configuration section.
Usage - CLI
Once you’ve installed Cibyl and set up the configuration, you can start running cibyl commands
cibyl query --jobs
will print all the jobs from each specified system in the configuration
To get an idea of what type of commands you can use with Cibyl, run cibyl -h
To get an idea of what type of information you query for with Cibyl, run cibyl query -h
For a more in depth guide on how to use Cibyl, read the CLI usage section.
Usage
CLI
Basic
Running cibyl
with no arguments, will print the environments and systems as set up in your configuration.
Cibyl supports multiple subcommands. The most common one is query, that allows
to query many environments for different CI/CD and product specific data.
Another example is the features
subcommand, which allows to query whether
certain product-specific features are supported in each of the environments of
the configuration (see features section for more details).
Jobs
Running cibyl query --jobs
will retrieve information on all the jobs for each environment specified in your configuration.
In order to retrieve jobs for a specific environment, use the --envs Environment
argument.
If the environment includes multiple systems, you can also choose a specific system with the --systems System
argument.
The same can be done for sources with the --sources Source
argument.
This was a simple example of what you could do with cibyl, to get a more depth overview see the CLI usage section.
Python
To Do
Installation
Install cibyl from GitHub (Recommended):
pip install 'git+https://github.com/rhos-infra/cibyl.git'
To obtain latest stable released version of Cibyl, install it from PyPi:
pip install cibyl
Warning
Using Cibyl from virtualenv might not work as expected if certifications are required to connect the CI system(s)
Note
For development purposes, it’s recommended to use pip install -e 'git+https://github.com/rhos-infra/cibyl.git'
Configuration
In order to use Cibyl’s CLI, you should set up configuration first. Configuration is structured as follows:
environments:
example_env:
example_system:
system_type: jenkins
sources:
osp_jenkins:
driver: jenkins
url: 'https://some.jenkins.com'
cert: False
username: example_username # Required specifically by Jenkins
token: example_token # Required specifically by Jenkins
Default location for the configuration file is ~/.config/cibyl.yaml
Each type of system will require a different set of parameters in order to start using/querying it. For more information on how to set up configuration for CLI usage, read the configuration section.
Configuration
Cibyl CLI is fully visible and usable only once you’ve setup the configuration file. This is because the CLI is dynamically changing based on the type of CI systems you have defined in the configuration file.
Format
The configuration file is written in YAML and is divided in two sections: environments and plugins. See below for an example of a minimal configuration that shows both sections.
# Minimal configuration
environments: # List of CI/CD environments
production: # An environment called "production"
production_jenkins: # A single system called "production_jenkins"
system_type: jenkins # The type of the system (jenkins or zuul)
sources: # List of sources belong to "production_jenkins" system
jenkins_api: # The name of the source which belongs to "production_jenkins" system
driver: jenkins # The driver the source will be using
url: https://... # The URL of the system
username: user # The username to use for the authentication
token: xyz # The token to use for the authentication
cert: False # Disable/Enable certificates to use for the authentication
plugins: # (Optional) Specify the plugins to enable when running Cibyl
- openstack # OpenStack adds its own product related models and arguments
The environments contains a list of environments. Each environment might contain one or more systems, which in turn might contain one or more sources. More details about this hierarchy can be found in the Core Models section. In short, an environment models a group of CI systems that are setup for a common purpose. At the same time, each CI system can have multiple sources of information available. See the Full Configuration section for an example of a configuration file with multiple environments, systems and sources.
The plugins section contains a list of plugins that should be loaded to provide cibyl with product-specific functionality.
Configuration Path
By default cibyl will look for the configuration file in the following paths:
~/.config/cibyl.yaml
/etc/cibyl/cibyl.yaml
A different path can be used if the argument --conf path
is used.
Additionally, the --conf
argument also supports passing a URL to
configuration file. If a URL is passed, it will be downloaded to ~/.config/cibyl.yaml
.
Sources
Cibyl supports multiple different types of sources. Each source may require some specific configuration. Below we link a page for each source implemented in cibyl. This pages contain a brief description of the source, a configuration sample and which plugins support it.
Validate Configuration
The best way to validate the configuration you’ve added is correct,
is to run the cibyl
command. This should list the environments
and systems specified in the configuration file. If the configuration is
correct, then cibyl will print the environments and systems defined in the
configuration. Taking the minimal configuration defined in the Format
section, running cibyl will print:
Environment: production
System: production_jenkins
If there is some problem with the configuration file, cibyl will raise one of the following errors:
ConfigurationNotFound
: There is no configuration file in any of the default paths or the path specified by the user.
EmptyConfiguration
: A configuration file was found, but it’s empty.
MissingEnvrionments
: The configuration file does not include any environments
MissingSystems
: An environment in the configuration file does not include any systems
MissingSystemKey
: A system in the configuration is missing a required key
MissingSystemType
: The type of one system in the configuration was not specified
NonSupportedSystemKey
: A key in the configuration of one system is not supported (e.g. a parameter was added to the wrong system)
MissingSystemSources
: A system in the configuration has no sources
NonSupportedSourceKey
: A key in the configuration of one source is not supported (e.g. a parameter was added to the wrong source)
NonSuppportedSourceType
: A source type in the configuration is not supported
MissingSourceKey
: The configuration of one source is incomplete and missing a required key
MissingSourceType
: The type of a source in the configuration is not specified
Full Configuration
As mentioned before, the configuration file might contain many environments, systems and sources. In the example below, a configuration consisting of two environments is shown. The first environment production, contains three systems: production_jenkins_1, production_jenkins_2 and production_zuul. The production_jenkins_1 system contains two sources, a Jenkins source called jenkins1_api and a Jenkins Job Builder source called job_definitions. The production_jenkins_2 and production_zuul systems contain one source each, a Jenkins and Zuul source, respectively. Finally, the staging environment contains a system staging_jenkins with a single Jenkins source.
# Full Configuration Example
environments: # List of CI/CD environments
production: # An environment called "production"
production_jenkins_1: # A single system called "production_jenkins_1" belongs to "production" environment
system_type: jenkins # The type of the system (jenkins or zuul)
sources: # List of sources belong to "production_jenkins" system
jenkins1_api: # The name of the source which belongs to "production_jenkins_1" system
driver: jenkins # The driver the source will be using
url: https://... # The URL of the system
username: user # The username to use for the authentication
token: xyz # The token to use for the authentication
cert: False # Disable/Enable certificates to use for the authentication
job_definitions: # Another source that belongs to the same system called "production_jenkins_1"
driver: jenkins_job_builder
repos:
- url: https://job_definitions_repo.git
production_jenkins_2: # Another system belongs to the "production" environment
system_type: jenkins
sources:
jenkins2_api:
driver: jenkins
url: https://...
username: user
token: xyz
cert: False
production_zuul:
system_type: zuul
sources:
zuul_api:
driver: zuul
url: https://...
staging: # Another environment called "staging"
staging_jenkins:
system_type: jenkins
sources:
staging_jenkins_api:
driver: jenkins
url: https://...
username: user
token: xyz
Disabling environments, systems and sources
It’s possible to disable each type of entity in Cibyl with the directive enabled: false
.
For example, the following will disable the environment staging`
and the system production-2
environments:
production:
production_jenkins_1:
system_type: jenkins
sources:
jenkins_api_prod:
driver: jenkins
url: https://...
username: user
token: xyz
production_jenkins_2:
enabled: false # Makes 'production_jenkins_2' system disabled
system_type: jenkins
sources:
jenkins_api_prod:
driver: jenkins
url: https://...
username: user
token: xyz
staging:
enabled: false # Makes 'staging' environment disabled
staging_jenkins:
system_type: jenkins
sources:
jenkins_api_staging:
driver: jenkins
url: https://...
username: user
token: xyz
Note
you can’t use a disabled environment, even if specifying it directly with one of the following arguments: –envs, –systems and –sources.
CLI
Cibyl can be used as as a CLI tool to query CI related information from multiple CI systems. Cibyl can provide information from two domains: CI/CD data and product-specific data. The first corresponds to concepts that are pertinent to many CI systems, like builds, jobs, tests or system-specific concepts like pipelines and tenants in Zuul systems (for more details on CI concepts supported by cibyl check the core models section).
Product-specific information is provided by plugins (see the openstack plugin as an example). As the name indicates, these are properties that are not related to the CI system but to the product being tested. In the case of openstack, some examples include the topology of the deployment, or the openstack version being deployed.
Due to this dual source of information, cibyl can be used to query both kinds of properties, as well as combine them in more complex queries. This page will provide several examples of queries that can be done with cibyl.
CLI arguments that accept values follow the assumption that if they are passed
without any value, the user is requesting to list the corresponding
information, while if passed with a value, the value will be used as a filter.
As an example, running cibyl query --jobs
will list all available jobs, while
cibyl query --jobs abc
will list the jobs that have the string abc in their
names.
Note
Throughout this page we assume for simplicity that there is only one CI system defined in the user configuration. Nevertheless, every command shown here can be run with a configuration composed of multiple environments, systems and sources. Check the configuration section for more details on how to construct the configuration for such cases.
Note
In cibyl, all cli arguments that accept a value, like –jobs or –tests will consider the input as a regular expression. The regex are matched using the syntax defined in the re module (docs).
CLI organization
Cibyl supports the following subcommands:
query
features
spec
This page will cover many uses of the query
subcommand, for examples of the
features
one see the features section and for
examples of the spec
subcommand see the spec section.
General parameters
Before listing interesting use-cases, cibyl has also a set of application-wide cli arguments that will affect the queries. This arguments must be specified before the subcommand. For example, to run a command to list of all jobs with a verbose output and a configuration file outside the default path, you should run:
cibyl -v --config path/to/config.yml query --jobs
The application-level arguments supported by cibyl are:
-d, --debug
Turn on debug-level logging
-v, --verbose
Verbosity level. This flag is additive, -vv will print more output than -v. In verbose mode, additional fields for the output are printed, such as the url for jobs, or the duration for builds.
-c, --config
Path to the configuration file, this can be a local path, or a url. If it’s a url, the file will be downloaded and stored in your local machine.
--log-mode=[terminal|file|both]
Where to write the logging output. Options are terminal, file or both, default is both.
--log-file
Path to store the logging output if the file or both option for
--log-mode
is selected, default is cibyl_output.log.--output-format=[text|colorized|json]
Sets the output format. Both text and colorized print to standard output, but the colorized uses color for better visuals. Json support is not complete.
-o, --output
Write output to the file passed as value.
-p, --plugin
Plugins to use in the queries.
CI/CD queries
Environment selection
The user configuration might consist of many environments, systems and sources. However, for any particular query the user might want to only use a subset of the defined environments. There are four arguments that can be used to achive this:
--envs
Environments to use in the query, filtering by name
--systems
Systems to use in the query, filtering by name
--system-type
Systems to use in the query, filtering by type
--sources
Sources to use in the query, filtering by name
The arguments presented in this section can be combined with any of the commands shown anywhere in this page.
Job queries
Cibyl can be used to query the list of all jobs defined in a CI system:
cibyl query --jobs
or to list the jobs that contain the string 123:
cibyl query --jobs 123
or to list the jobs that end with the string 123:
cibyl query --jobs "123$"
Build queries
Cibyl can be used to query the list of all builds for all jobs defined in a CI system:
cibyl query --jobs --builds
or the last build for all jobs:
cibyl query --jobs --last-build
or the last build for all jobs where that build failed:
cibyl query --jobs --last-build --build-status FAILED
Note
The value for the –build-status argument in case insensitive, so both FAILED and failed would produce the same result
or the last build for all jobs that have the string 123 in the name and where that build failed:
cibyl query --jobs 123 --last-build --build-status FAILED
Test queries
Cibyl can be used to query the list of all tests for all jobs defined in a CI system. To query for tests, the user must specify a build where the tests were run, either through the –last-build or –builds arguments:
cibyl query --jobs --last-build --tests
listing the tests that run in build number 5:
cibyl query --jobs --builds 5 --tests
or list the tests that contain the string 123 in their name:
cibyl query --jobs --last-build --tests 123
or list only the failing tests:
cibyl query --jobs --last-build --test-result FAILED
or list only the tests that run for more than 5 minutes, but less than 10 minutes (test duration is specified in seconds):
cibyl query --jobs --last-build --test-duration ">300" "<600"
Note
The –test-duration is a ranged argument. In cibyl, ranged arguments take multiple values in the form “OPERATOR VALUE”, without the space in between. Common operators like “<”, “>”, “!=”, “==”, “<=”, “>=” are supported. Additionally using a single equal sign “=” is also a valid equality operator, and if no operator is specified, the equality one is used by deafault.
Zuul specific queries
In cibyl, there are some argumetns that are only supported when running queries against a Zuul system, and will be ignored otherwise. For example, we can list all jobs in the default tenant:
cibyl query --tenants default --jobs
or list all jobs related to project example-project in all tenants:
cibyl query --projects example-project --jobs
or list all jobs under the check pipeline:
ciby query --pipelines check --jobs
The arguments shown in previous sections can be combined with the Zuul specific ones. For example, we could use cibyl to list the last build of the jobs that have the string 123 in their name, belong to a project named example, to a check pipeline and under the default tenant, but only if the build was successful:
cibyl query --tenants default --project example --pipeline check --jobs 123
--last-build --build-statu SUCCESS
Jenkins specific queries
As is the case with Zuul systems, Jenkins systems have some specific arguments that can combined with the more general ones. Cibyl can query Jenkins systems to list the stages that were run in a build. For example the following command would show the stages run for the last build of the job called job_name:
cibyl query --jobs job_name --last-build --stages
Product queries
Openstack queries
As part of the functionality provided by the openstack plugin, cibyl can query the CI systems for openstack related information. For example it’s quite simple to list the version of the ip protocol used in each job:
cibyl query --ip-version
or listing the jobs that use ipv6 protocol:
cibyl query --ip-version 6
Similarly, other openstack properties can be used for queries, and can be combined for more complex queries. Building on the previous example, let’s build a cibyl command to show the network backend used in every job that also used ipv6:
cibyl query --ip-version 6 --network-backend
Other examples of relevant openstack arguments include checking which jobs setup the tests from git, instead of rpm packages:
cibyl query --test-setup git
or filtering by the number of compute and controller nodes used in
a deployment. This can be done via the --controllers
and --computes
arguments, which are ranged arguments (see note above for more deatils on what
that means). Let’s see an example of how to query for those jobs that use at
least 2 compute nodes and more than 3 controller nodes, but no more than
6 controllers:
cibyl query --controllers ">3" "<=6" --computes ">=2"
The list shown here is not a comprehensive collection of all the arguments defined in the openstack plugin, check the plugin page in the documentation for the full list.
Combination of openstack and CI/CD queries
In a cibyl query, CI/CD and openstack arguments can be combined to form more complex queries. This section will show some examples of such calls. The following call will list all jobs that contain the string example, deploy openstack using ceph as the cinder backend and geneve as the network backend, and also print the last build for each job:
cibyl query --jobs example --cinder-backend ceph --network-backend geneve
--last-build
the previous example could be expanded to only list those jobs that had a passing last build:
cibyl query --jobs example --cinder-backend ceph --network-backend geneve
--last-build --build-status SUCCESS
API
Parser
Cibyl provides two sources of user input, the configuration file and the command line arguments. The configuration file details the ci environment that the user wants to query, while the command line arguments tell Cibyl what the user wants to query.
Cibyl’s cli is divided in several subcommands. The parser is the component
responsible for bringing all the subcommands together and ensuring the
corresponding arguments are added. In the case of the features
subcommands
that is simple, since it only has one argument. The case of the query
sucommand is different, since the cli arguments are extended dynamically depending on the
contents of the configuration.
Note
The rest of this page is relevant only for the query
subcommand.
When running cibyl query -h
only the arguments that are relevant to the user,
according to its configuration, will be shown. If there is no configuration
file, Cibyl will just print a few general arguments when calling cibyl query -h
.
If the configuration is populated then arguments will be added depending on its contents.
The parser is extended using a hierarchy of CI models. This hierarchy is
Cibyl’s internal representation of the CI environments. The models are created after reading the
configuration and the hierarchy is implicitely defined in the API attribute of
said models. For example, one environment might include a Jenkins instance as
CI system, and have it also as source for information, in addition to an
ElasticSearch instance as a second source. With this environment, if the user
runs cibyl query -h
, it will show arguments that are relevant to a Jenkins
system, like --jobs
, --builds
or --build-status
. In such a case it will
not show arguments like --pipelines
which would be useful if the CI system
was a Zuul instance.
The API of a CI model is a dictionary with the following structure (extracted from the System API):
API = {
'name': {
'attr_type': str,
'arguments': []
},
'sources': {
'attr_type': Source,
'attribute_value_class': AttributeListValue,
'arguments': [Argument(name='--sources', arg_type=str,
nargs="*",
description="Source name")]
},
'jobs': {'attr_type': Job,
'attribute_value_class': AttributeDictValue,
'arguments': [Argument(name='--jobs', arg_type=str,
nargs='*',
description="System jobs",
func='get_jobs')]}
}
each key corresponds to the name of an attribute, and the value is another
dictionary with attribute-related information. At this point we need to
distinguish between arguments and attributes. In Cibyl an Argument
is the object
that is obtained from parsing the user input. The values passed to each option
like --debug
or --jobs
are stored in an Argument
. Attributes correspond to the actual
key-value pairs in the API. An attribute has an attribute_value_class
which
by default is AttributeValue
, but can also be AttributeDictValue
and AttributeListValue
.
The difference between the three is the how they store the arguments. The first
is intended to hold a single option (things like name, type, etc.). While the
other two hold a collection of values either in a dictionary or a list (hence
the name). The information provided by the user is accessible throgh the
value
field of any Attribute
class.
Each API element has also an attr_type, which describes what kind of object will it hold. In the example above name will hold a string, while jobs will hold a dictonary of Job objects. This allows us to establish the hierarchy mentioned previously, by checking if the attr_type field is not a builtin type. Finally, there is an arguments field, which associates the actual options that will be shown in the cli with an attribute. An attribute may have no arguments, one argument or multiple arguments associated with it.
Argument
objects have a set of options to configure the behavior of the
cli. The name determines the option that will be shown, arg_type specifies
the type used to store the user input (str, int, etc.), nargs and
description have the same meaning as they do in the arparse module.
The level argument, measures how deep in the hierarchy
a given model is. Finally, we see the func argument, which points to the
method a source must implement in order to provide information about a certain
model. In the example shown here, only jobs has an argument with func
defined, as it is the only CI model present. If the user runs a query like:
cibyl query --jobs
then Cibyl will look at the sources defined and check whether any has a method
get_jobs
, and if it finds one it will use it to get all the jobs available
in that source.
Arguments are added to the application parser in the extend_parser
method
of the Orchestrator
class. This method loops through the API of a model
(in the first call it will be an Environment
model) and adds its arguments. If any
of the API elements is a CI model, the element’s API is recursively used to
augment the parser. As the extend_parser
method iterates through the model
hierarchy, it creates a graph of the relationships between query methods (the
sources’ methods that are added to the arguments’ func attribute). The edges
of the graph are created when a new recursive call is made. As an example, when
exploring the API for the Job model, we know that the arguments will call
get_jobs
, so when a new call is made for the Build API, a new edge wil be
created from get_jobs
to all the new query methods that are found, in this
case it will be get_builds
.
For each recursive call, the level is increased. The level parameter is key to identify the source of information for the query that the user sends. In the Jenkins environment example mentioned before, we may have a hierarchy like:
Environment => System => Job => Build
where each at each step we increase the level by 1. We can then parse the cli
arguments and sort by decreasing level. To select which query method should be
called, cibyl relies on the graph constructed during the call to
extend_parser
. It iterates over the sorted list of arguments and for each
of them constructs a path to the root of the graph. The intermediate nodes in
this path are removed from the list of arguments to query, since by the
hierarchical nature of the relationship between the models, calling an
argument’s func makes the call to the argument’s parent func redundant.
In the example above, Build is the model with the largest level. If we assume that
user has made a call like cibyl --jobs --builds
, we want to query the sources for builds,
but we known that each build will be associated with a job, and each job will be associated with
a system, etc. We also know that after calling get_builds
, we will not need
to call get_jobs
. Thus we get a sorted list of arguments, which is [builds, jobs].
We create a path from builds to the root of the graph, which in the case of
a Jenkins systems is jobs (for a zuul system this would be more complex).
After iterating over the path, we remove jobs from the list of arguments to
query, since builds already will provide the jobs information.
Plugins
Plugins allow you to extend built-in models with your own models. This can be useful in case you would like to associate product related data with your CI models for example, as can be seen in the image below. In this case, the Job model is being associated with the Deployment model through the deployment key in Job’s API.

A supported plugin in Cibyl has to adhere following structure:
cibyl
├── plugins
│ └── example # Arbitrary plugin name
│ └── __init__.py # Should include Plugin class with _extend method
Plugin Class
class ExamplePlugin:
def _extend(self, model_api: dict):
model_api['new_attribute'] = {
'attr_type': str,
arguments: []
}
Sources
Sources in Cibyl are responsible for performing the queries and getting the data the user is interested in. A source can be anything: a CI system, repository, database, etc. Cibyl supports the following sources out-of-the-box:
Configuring Sources
The following is an example of Jenkins source configuration:
environments:
example_environment:
jenkins_system:
system_type: jenkins
sources:
jenkins_source:
driver: jenkins
username: some_username
token: some_token
url: https://jenkins.example.com
See configuration to understand how to properly configure Cibyl for CLI usage.
Source Interface
Each source can support one or more of the arguments specified by the different models of Cibyl. The only constraint regarding sources is that each source must inherit from the Source class.
Arguments Matrix
Argument / Source |
Description |
Jenkins |
Zuul |
ES |
JJB |
Zuul.d |
---|---|---|---|---|---|---|
–jobs |
Jobs names or pattern
Default: all jobs
|
☑️ |
☑️ |
☑️ |
☑️ |
🔲 |
–builds |
Build numbers
Default: all builds
|
☑️ |
☑️ |
☑️ |
❌ |
❌ |
–last-build |
The last build of a job
|
☑️ |
☑️ |
☑️ |
❌ |
❌ |
–build-status |
Build status (default: all)
failure, success,
abandoned, unstable
|
☑️ |
☑️ |
☑️ |
❌ |
❌ |
–tests |
Test names or pattern
Default: all tests
|
☑️ |
🔲 |
☑️ |
❌ |
❌ |
–test-result |
Test result (default: all)
success, failed, skipped
|
☑️ |
🔲 |
☑️ |
❌ |
❌ |
–test-duration |
Test duration (in seconds,
default: all)
(Can be also range: “>=3”)
|
☑️ |
🔲 |
🔲 |
❌ |
❌ |
Output
The output of a cibyl command is the result of the query made by the user. Cibyl provides a great amount of control on the format of this output. By default, cibyl will print the output to the terminal, using colored text.
The user can choose to print to a file using the -o
or --output
flag. This
flag takes a file path as its value and will write there the query result.
Note
If the file specified exists, it will be overwritten.
The user can choose the format of the output. Currently three formats are supported:
colorized
, colored text, is the default mode, well suited for printing to a terminal, but not very useful if printing to a file
text
, plain text, ideal to use when writing to a file
json
, output in json format, useful if the output of cibyl has to be passed to another piece of software
The user can also control the level of detail of the output, using the -v
or
--verbose
flag. This flag is cumulative, so -vv
will produce more output
than -v
. As an example, Job models will have a url field, but it will only
be printed in verbose mode. Similarly, Test models have a duration field that
is only shown in verbose mode.
Additionally, cibyl also has a stream of logging output. Normally, cibyl will log the duration
of the query, the system queried and where is the output written. If debug mode
is used with -d
or --debug
, then additional information will be printed.
Jenkins
The Jenkins source pulls data from the Jenkins API.
Usage
To following is a configuration sample of how to configure the Jenkins source
# Minimal configuration
environments: # List of CI/CD environments
production: # An environment called "production"
production_jenkins: # A single system called "production_jenkins"
system_type: jenkins # The type of the system (jenkins or zuul)
sources: # List of sources belong to "production_jenkins" system
jenkins_api: # The name of the source which belongs to "production_jenkins" system
driver: jenkins # The driver the source will be using
url: https://... # The URL of the system
username: user # The username to use for the authentication
token: xyz # The token to use for the authentication
cert: False # Disable/Enable certificates to use for the authentication
plugins: # (Optional) Specify the plugins to enable when running Cibyl
- openstack # OpenStack adds its own product related models and arguments
Plugin Support
The Jenkins source is supported by the following built-in plugins:
OpenStack
Zuul API
The Zuul API source pulls data from the Zuul CI/CD system.
Usage
The following is a configuration sample of how to configure the Zuul source
environments: # List of CI/CD environments
production: # An environment called "production"
production_zuul: # A single system called "production_jenkins"
system_type: zuul # The type of the system
sources: # List of sources belong to "production_jenkins" system
zuul_api: # The name of the source which belongs to "production_zuul" system
driver: zuul # The driver the source will be using
url: https://... # The URL of the system
tenants: # List of tenants to use. This section is optional
- default # and allows the user to restrict which zuul
- local # tenants will be queried can be useful
Plugin Support
The Zuul source is supported by the following built-in plugins:
OpenStack
Jenkins Job Builder
“Jenkins Job Builder” is the source for obtaining information from jenkins job definitions repositories. It’s supported only with Jenkins CI/CD system.
Usage
To following is a configuration sample of how to configure the ‘Jenkins Job Builder’ source
environments: # List of CI/CD environments
production: # An environment called "production"
production_jenkins: # A single system called "production_jenkins"
system_type: jenkins # The type of the system (jenkins or zuul)
sources: # List of sources belong to "production_jenkins" system
jjb: # The name of the source which belongs to "production_jenkins" system
driver: jenkins_job_builder # The driver the source will be using
repos: # List of repositories where the job definitions are located
- url: 'https://jjb_repo_example.git'
Plugin Support
The ‘Jenkins Job Builder’ source is supported by the following built-in plugins:
OpenStack
Elasticsearch
The Elasticsearch source pulls data from the different indexes of the Elasticsearch database.
Usage
To following is a configuration sample of how to configure the Elasticsearch source
environments: # List of CI/CD environments
production: # An environment called "production"
production_jenkins: # A single system called "production_jenkins"
system_type: jenkins # The type of the system (jenkins or zuul)
sources: # List of sources belong to "production_jenkins" system
es: # The name of the source which belongs to "production_jenkins" system
driver: elasticsearch # The driver the source will be using
url: https://... # The URL of the source
Fields
Elasticsearch should include the following fields in order to be fully operational:
job_name
build_number
build_result
current_build_result
Plugin Support
The Elasticsearch source is supported by the following built-in plugins:
OpenStack
Zuul Definitions
Zuul Definitions is the source for pulling data out of Zuul job definition repositories (usually repos with zuul.d directory).
Zuul definitions support two ways to gather data from Zuul job definition repositories:
By Clonning and parsing files in zuul.d dir
By Quering GitHub API and parsing files in zuul.d dir
Cibyl will clone repos to ~/.cibyl directory.
When remote: True
option is set it will query using GitHub API instead of cloning the repositories and query them locally.
Warning
To prevent rate limiting on GitHub you might need to add username and token options in the config.
Usage
To following is a configuration sample of how to configure the Zuul definitions source to work with local repos
environments: # List of CI/CD environments
production: # An environment called "production"
production_zuul: # A single system called "production_jenkins"
system_type: zuul # The type of the system
sources: # List of sources belong to "production_jenkins" system
zuul_api: # The name of the source which belongs to "production_zuul" system
driver: zuul.d # The driver the source will be using
remote: False # Optional as this is the default
repos: # The repos to clone and query when running Cibyl query commands
- url: 'http://zuul_defitions_repo.git'
- url: 'http://zuul_defitions_repo1.git'
To following is a configuration sample of how to configure the Zuul definitions source to work with GitHub API
environments: # List of CI/CD environments
production: # An environment called "production"
production_zuul: # A single system called "production_jenkins"
system_type: zuul # The type of the system
sources: # List of sources belong to "production_jenkins" system
zuul_api: # The name of the source which belongs to "production_zuul" system
driver: zuul.d # The driver the source will be using
remote: True # Query GitHub API instead of querying local repos
username: user # Required only when 'remote: True'
token: xyz # Required only when 'remote: True'
repos: # The repos to query using GitHub API
- url: 'http://localhost/zuul_defitions_repo.git'
- url: 'http://localhost/zuul_defitions_repo1.git'
Plugin Support
The “Zuul Definitions” source is supported by the following built-in plugins:
OpenStack
Core Models
Core models (aka CI/CD models) are built-in CI/CD Cibyl models:
Environment: A CI/CD environment with one or more CI/CD systems. This is mostly a logical separation, rather than a physical one.
System: A CI/CD system such as Jenkins, Zuul ,etc.
Pipeline: A specific Zuul concept which used for describing a workflow
Job: A particular task/automation in the CI/CD system
Build: An execution instance of a job
Test: A test execution that is part of a build
The way they are organized and associated one with each other, mainly depends on the type of the CI/CD system being used. For a Jenkins system for example, the hierarchy includes Job and Build models, while for Zuul system, the hierarchy includes Pipeline, Job and Build models.
Environment
├── System
│ └── Job # Jenkins
│ └── Build
│ └── Test
│ └── Pipeline # Zuul
│ └── Job
│ └── Build
│ └── Test
Plugin Models
Plugin models are provided by different plugins. They are not associated by default with the core models of Cibyl, but only when the plugin is being used. In addition, the way the plugin models are associated with core models, is very much depends on the implementation of the plugin.
An example of plugin models can be seen in openstack plugin page
OpenStack Plugin
OpenStack is an open source cloud software. The OpenStack plugin associates CI job model with OpenStack deployment model.
Models
Deployment: An entire OpenStack cluster
Node: A single node in an OpenStack deployment/cluster associated with a single deployment
Container: A container associated with a single node
Package: An RPM associated with either a single node or a single container
Service: A service associated with a single deployment
Deployment
├── Node
│ └── Container
│ └── Package
│ └── Package
├── Service
Usage
To use the OpenStack plugin with Cibyl, specify –plugin openstack or include it in the configuration file.
Spec
Note
cibyl spec JOB_NAME allows you to easily get the full OpenStack specification of a single job.
The idea behind it is to allow the user to quickly get information on which OpenStack services and features are covered by a single job so the user doesn’t have to go and deep dive into the job configuration and build artifacts to figure it out by himself.
An example of an output from running cibyl spec JOB_NAME:
Openstack deployment:
Release: 17.0
Infra type: virt
Topology: compute:2,controller:3,ironic:2
Network:
IP version: 4
Network backend: geneve
ML2 driver: ovn
Security group mechanism: native ovn
DVR: True
TLS everywhere: False
Storage:
Cinder backend: lvm
Ironic:
Ironic inspector: True
Cleaning network: False
Arguments Matrix
Argument / Source |
Description |
Jenkins |
Zuul |
ES |
JJB |
Zuul.d |
---|---|---|---|---|---|---|
–ip-version |
The IP version used
by the deployment (4 or 6)
|
☑️ |
☑️ |
☑️ |
🔲 |
🔲 |
–release |
OpenStack Release
(OSP and RDO supported)
|
☑️ |
☑️ |
🔲 |
🔲 |
🔲 |
–infra-type |
The infrastructure on which
OS is deployed (e.g. ovb,
baremetal, virthost)
|
☑️ |
☑️ |
🔲 |
🔲 |
🔲 |
–topology |
The combination of node
types deployed
|
☑️ |
☑️ |
☑️ |
🔲 |
🔲 |
–nodes |
List of nodes on the topology.
|
☑️ |
☑️ |
🔲 |
🔲 |
🔲 |
–controllers |
Number of controllers
(Can be also range: “>=3”)
|
☑️ |
☑️ |
🔲 |
🔲 |
🔲 |
–computes |
Number of computes
(Can be also range: “>=3”)
|
☑️ |
☑️ |
🔲 |
🔲 |
🔲 |
–ml2-driver |
Which ml2 driver does
the deployment use
|
☑️ |
☑️ |
🔲 |
🔲 |
🔲 |
–network-backend |
What network protocol is
used (e.g. vxlan, vlan, …)
|
☑️ |
☑️ |
☑️ |
🔲 |
🔲 |
–cinder-backend |
What cinder backend is
used (vlan, Ceph, Netapp, nfs)
|
☑️ |
☑️ |
☑️ |
🔲 |
🔲 |
–containers |
List of containers running
on the hosts
|
☑️ |
🔲 |
🔲 |
❌ |
❌ |
–packages |
Package installed by the
deployment
|
☑️ |
🔲 |
❌ |
❌ |
❌ |
–services |
Services installed by the
deployment
|
☑️ |
🔲 |
🔲 |
❌ |
❌ |
–test-setup |
Source of test setup (rpm, git)
|
☑️ |
🔲 |
🔲 |
🔲 |
🔲 |
Features
Cibyl allows users to define their own product related data in form of what is known as “features”. Features are basically blocks of code with the purpose of querying for specific product features in one or more environments.
Out of the box Cibyl supports multiple features for existing plugins and users can easily list them with cibyl features
Allowing users to define their own sort of product arguments has multiple advantages:
Use internal project functions and mechanisms to define complex custom queries
Consistent approach towards querying for product data, in different environments and sources
Sharing product related data with other users without extending endlessly the number of product arguments supported by Cibyl
Usage
To list all the existing features: cibyl features
Query IPv4 feature: cibyl features ipv6
Query two features: cibyl features ipv6 ha
Query for a feature in specific set of jobs: cibyl features ha --jobs production
Development
Would like to add a new feature? Read the features development section.
Tests
Cibyl tests cover the following:
unit: testing each component of the application
coverage: verify unit testing coverage is above 90%
e2e: testing as a user would experience it
linters: code analysis
docs: documentation testing
Each of the above can be executed with tox -e <type>
or tox
to run them all
Sources
To add/develop a new type of source, follow the following guidelines:
A source should be added to cibyl/sources/<SOURCE_NAME>
The source class you develop should inherit from the Source class (
cibyl/sources/source.py
)For a source to support an argument, it should implement the function name associated with that argument
Each source method that implements a method of an argument, should be returning an AttributeDict value of the top level entity associated with the CI systems (e.g.
AttributeDictValue("jobs", attr_type=Job, value=job_objects)
)A source should handle only CI/CD related data. If you would like a certain source to pull a product related data, you should add a source class (with the same name as the CI/CD source) to corresponding plugin (
cibyl/plugin/<PLUGIN_NAME>/sources/<SOURCE_DIR/FILE>
)
Features
In cibyl we define features, which are classes containing a query method that can run a custom query using python code. A feature is defined as a class that inherits from the FeatureDefinition class, defined in cibyl/features/__init__.py.
There is a FeatureTemplate class that can be used to quickly define simple features. The query method of this class will select the most appropiate source considering the speed_index and the method to query in the source. To define a new feature using this template, one only needs to define a class that inherits from FeatureTemplate, set the attribute method_to_query to the method of choice for the source and include in the args attribute the arguments that should be passed to the source’s method to perform the query (see for example the HA, IPV4, IPV6 features as a sample).
One could define a feature without using the FeatureTemplate code at all, the only requirements would be that the class should provide a query method that accepts a system and returns an AttributeDictValue object, and should define a name attribute for the feature. This way of implementing a feature gives the developer total freedom, but does not provide some functionality like selecting the best sources given the input arguments. There could be a mixed implementation, that relies on the FeatureTemplate query method but provided a bit more flexibility. Let’s say for example that one wanted a feature called Example that wants to check whether a system has any job called ‘example’ with at least 3 passing builds and runs a test called ‘test_example’. Such a feature could be implemented for example like:
class Example(FeatureTemplate, FeatureDefinition):
def __init__(self):
self.name = "Example"
def get_template_args(self):
"""Get the arguments necessary to obtain the information that defines
the feature."""
args = {}
args['jobs'] = Argument("jobs", arg_type=str,
description="jobs",
value=["example"])
args['builds'] = Argument("build", arg_type=str,
description="build",
value=[])
args['jobs'] = Argument("tests", arg_type=str,
description="tests",
value=["test_example"])
return args
def query(self, system, **kwargs):
def get_method_to_query(self):
return "get_builds"
self.get_method_to_query = get_method_to_query
return_builds = super().query(system, **self.args, **kwargs)
def get_method_to_query(self):
return "get_tests"
self.get_method_to_query = get_method_to_query
return_tests = super().query(system, **self.args, **kwargs)
# more code to combine the the returns and apply the desired
# conditions
Features are classes that inherit from the FeatureDefinition class. The name of the module where the feature is defined is used as a category for the features it contains. Features are loaded in the orchestrator, in the load_features method. There, cibyl will go through the paths that are registered by the plugins and the default location to look for features. If features are found and requested by the user, the the run_features method is executed. If not, a normal query is executed.
As mentioned before, the query method should return an AttributeDictValue with the appropiate CI model according to the system and source used. These models are added to the system in the run_features method. If more than one feature is run, the output is combined to filter the returned models to add only those that satisfy all features. In addition, for each feature that runs, a Feature model is added to the system. This model (which is a CI model, akin to a System or Job) has only two attributes, the feature name and a boolean marking whether the feature is present in the system or not.
After all features run, the publisher is used to print all the output. The same
publisher is used for both normal queries and feature queries. The printers for
all systems will print the Feature models added to each system, and after that
it will continue printing other information found in the system if the user ran
cibyl with other arguments like –jobs. In order to handle the different cases,
there are two kind of queries added to the QueryType class: FEATURES and
FEATURES_JOBS. The first will signal the case when the user has called the
features subcommand, while the second will mark the case where the user has
called the features subcommand with the --jobs
argument.
Output
To see an overview of cibyl output from a user’s perspective see the output page. From a developer’s perspective there are three objects that are involved in printing the output, which are summarized in the diagram below.

First, the Orchestrator processes the query and creates a Publisher to handle the output creation. There are two kinds of publishers: the PrintPublisher, which prints human-readeable text and the JSONPublisher that prints JSON output.
The main difference is that the PrintPublisher prints the output for each system after each environment is queried, while the JSONPublisher prints the output after all environment are queried. To produce valid json, all the output needs to be aggregated into a single object, but when printing human-readeable text, producing output after each environment is queried gives faster feedback to the user.
To produce the output, the Publisher creates a Printer object. Cibyl has
a Printer abstract class that is specialized. The used printer
is typically called CI*Printer. The CI prefix is used because the class
implements the interface defined by the CIPrinter
class. The interface
mandates the implementation of a print_environment method. This method
takes an environment object and produces a string representation of its contents.
There are several Printer classes in cibyl, specialized depending on the output format and the contents. For example, for printing colored output, the hierarchy shown in the diagram below is established.

The class CIColoredPrinter is the Printer that is used for colored text and it will produce a string representation for all core models. While producing the output, the printer creates a CISystemPrinter object, which is specialized depending on which kind of system (zuul or jenkins) is being processed. The system printer is the object that will go through the whole model hierarchy, starting at the system level, and complete the output string.
As an aside, the ColoredPrinter class takes as argument a Palette object. Using a DefaultPalette will produce colored output, while using a ClearText palette will produce plain text ( which is the result of passing the flag -f text to cibyl).
For serialized text (json being the main example), there is another set of classes that provide the funcionality, as shown in the diagram below:

In this case, we have a generic CISerializedPrinter that can be specialized depending on the output format. Currently only a JSON implementation is available, but through the use of a different SerializationProvider, a YAML or XML implementation could be easily created. For json output, the printer would be the CIJSONPrinter, which would again have some type of CISystemPrinter. In this case it would be either a JSONBaseSystemPrinter, a JSONJobsSystemPrinter or a JSONZuulSystemPrinter. As can be seen in the diagram, these three classes are extensions of the SerializedBaseSystemPrinter, SerializedJobsSystemPrinter and SerializedZuulSystemPrinter, respectively.
The printers explained above deal with the core models. If the query involved any funcionality or models provided by a plugin, then the plugin own printer must be also called. Plugins must create their own printers by inheriting from the PluginPrinterTemplate abstract class. We will ilustrate this relationship using the openstack plugin as an example:

The openstack plugin introduces a PrinterRouter class which implements the PluginPrinterTemplate requirements (an as_text and an as_json method). Then, the plugin introduces two printers: OSJSONPrinter and OSColoredPrinter for json and human-readeable output. When producing the output, the system printers explained above will call the as_text or as_json method from the appropiate openstack printer and will get the correct string representation for the plugin-specific models found in the query.
Contribute
Please submit a pull requests to the cibyl project on GitHub.
Style
Cibyl CI enforces code linting according to the Google Python Style Guide