diff --git a/.zuul.yaml b/.zuul.yaml
index f0f07c7..412a7e6 100644
--- a/.zuul.yaml
+++ b/.zuul.yaml
@@ -92,16 +92,19 @@
- project:
check:
jobs:
+ - zuul-tox-docs
- zuul-operator-build-image
- zuul-operator-functional-k8s:
dependencies: zuul-operator-build-image
gate:
jobs:
+ - zuul-tox-docs
- zuul-operator-upload-image
- zuul-operator-functional-k8s:
dependencies: zuul-operator-upload-image
promote:
jobs:
+ - zuul-promote-docs
- zuul-operator-promote-image
release:
jobs:
diff --git a/Makefile b/Makefile
index 8229131..80325b2 100644
--- a/Makefile
+++ b/Makefile
@@ -2,7 +2,7 @@ image:
podman build -f build/Dockerfile -t docker.io/zuul/zuul-operator .
install:
- kubectl apply -f deploy/crds/zuul-ci_v1alpha2_zuul_crd.yaml -f deploy/rbac.yaml -f deploy/operator.yaml
+ kubectl apply -f deploy/crds/zuul-ci_v1alpha2_zuul_crd.yaml -f deploy/rbac-admin.yaml -f deploy/operator.yaml
deploy-cr:
kubectl apply -f deploy/crds/zuul-ci_v1alpha2_zuul_cr.yaml
diff --git a/deploy/rbac-admin.yaml b/deploy/rbac-admin.yaml
new file mode 100644
index 0000000..149cacd
--- /dev/null
+++ b/deploy/rbac-admin.yaml
@@ -0,0 +1,124 @@
+apiVersion: v1
+kind: ServiceAccount
+metadata:
+ name: zuul-operator
+
+---
+
+apiVersion: rbac.authorization.k8s.io/v1
+kind: ClusterRole
+metadata:
+ name: zuul-operator
+rules:
+- apiGroups:
+ - ""
+ resources:
+ - pods
+ - pods/exec
+ - services
+ - services/finalizers
+ - endpoints
+ - persistentvolumeclaims
+ - events
+ - configmaps
+ - secrets
+ - ingresses
+ - namespaces
+ verbs:
+ - create
+ - delete
+ - get
+ - list
+ - patch
+ - update
+ - watch
+- apiGroups:
+ - apps
+ resources:
+ - deployments
+ - daemonsets
+ - replicasets
+ - statefulsets
+ verbs:
+ - create
+ - delete
+ - get
+ - list
+ - patch
+ - update
+ - watch
+- apiGroups:
+ - networking.k8s.io
+ resources:
+ - ingresses
+ verbs:
+ - create
+ - delete
+ - get
+ - list
+ - patch
+ - update
+ - watch
+- apiGroups:
+ - policy
+ resources:
+ - poddisruptionbudgets
+ verbs:
+ - create
+ - delete
+ - get
+ - list
+ - patch
+ - update
+ - watch
+- apiGroups:
+ - apps
+ resourceNames:
+ - zuul-operator
+ resources:
+ - deployments/finalizers
+ verbs:
+ - update
+- apiGroups:
+ - apps
+ resources:
+ - replicasets
+ - deployments
+ verbs:
+ - get
+- apiGroups:
+ - operator.zuul-ci.org
+ - cert-manager.io
+ - pxc.percona.com
+ resources:
+ - '*'
+ verbs:
+ - create
+ - delete
+ - get
+ - list
+ - patch
+ - update
+ - watch
+- apiGroups:
+ - monitoring.coreos.com
+ resources:
+ - servicemonitors
+ verbs:
+ - get
+ - create
+
+---
+
+kind: ClusterRoleBinding
+apiVersion: rbac.authorization.k8s.io/v1
+metadata:
+ name: zuul-operator
+subjects:
+- kind: ServiceAccount
+ name: zuul-operator
+ namespace: default
+roleRef:
+ kind: ClusterRole
+ name: cluster-admin #zuul-operator
+ apiGroup: rbac.authorization.k8s.io
diff --git a/doc/requirements.txt b/doc/requirements.txt
new file mode 100644
index 0000000..682955a
--- /dev/null
+++ b/doc/requirements.txt
@@ -0,0 +1,2 @@
+sphinx>=1.6.1
+zuul-sphinx
diff --git a/doc/source/_static/custom.css b/doc/source/_static/custom.css
new file mode 100644
index 0000000..b49c2c0
--- /dev/null
+++ b/doc/source/_static/custom.css
@@ -0,0 +1,6 @@
+.logo img {
+ width: 75%;
+}
+div.sphinxsidebarwrapper p.logo {
+ text-align: left;
+}
diff --git a/doc/source/_static/logo.svg b/doc/source/_static/logo.svg
new file mode 100644
index 0000000..ded6d34
--- /dev/null
+++ b/doc/source/_static/logo.svg
@@ -0,0 +1,22 @@
+
+
+
diff --git a/doc/source/conf.py b/doc/source/conf.py
new file mode 100755
index 0000000..55e3ff9
--- /dev/null
+++ b/doc/source/conf.py
@@ -0,0 +1,93 @@
+# -*- 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',
+ 'zuul_sphinx',
+]
+
+# 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
+
+primary_domain = 'zuul'
+
+# The suffix of source filenames.
+source_suffix = '.rst'
+
+# The master toctree document.
+master_doc = 'index'
+
+# General information about the project.
+project = u'zuul-operator'
+copyright = u'2021, Zuul contributors'
+
+# 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'
+
+# -- 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'Zuul contributors', 'manual'),
+]
+
+# Example configuration for intersphinx: refer to the Python standard library.
+#intersphinx_mapping = {'http://docs.python.org/': None}
+
+# The name of an image file (relative to this directory) to place at the top
+# of the sidebar.
+html_logo = '_static/logo.svg'
+
+# The name of an image file (within the static path) to use as favicon of the
+# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32
+# pixels large.
+#html_favicon = None
+
+# Add any paths that contain custom static files (such as style sheets) here,
+# relative to this directory. They are copied after the builtin static files,
+# so a file named "default.css" will overwrite the builtin "default.css".
+html_static_path = ['_static']
+
+# Sample additional role paths
+zuul_role_paths = ['tests/roles']
diff --git a/doc/source/index.rst b/doc/source/index.rst
new file mode 100644
index 0000000..accb78d
--- /dev/null
+++ b/doc/source/index.rst
@@ -0,0 +1,460 @@
+Zuul Operator
+=============
+
+This is a Kubernetes Operator for the Zuul Project Gating System.
+
+Zuul has a number of components and depencencies, and this operator is
+designed to simplify creating and maintaining Zuul systems in
+Kubernetes.
+
+Somewhat unusually, this operator offers the ability to completely
+manage Zuul's operational dependencies, to the point of even
+installing other operators upon which it relies. Be sure to read
+about deployment options if you want to perform some of these tasks
+yourself.
+
+Simple Example
+--------------
+
+The quickest way to get a running Zuul is to allow the operator to
+manage all of the dependencies for you. In this case, the operator
+will:
+
+* Install cert-manager and set up a self-signed cluster issuer
+* Install the Percona XtraDB operator and create a three-node PXC
+ database cluster
+* Create a three-node ZooKeeper cluster
+* And of course, create a Zuul system
+
+.. note::
+
+ Installing other operators requires a high level of access, so when
+ used in this manner, zuul-operator runs with cluster admin
+ privileges. If you would like the operator to run with reduced
+ privileges, see Managing Operator Dependencies.
+
+From the root of the zuul-operator repo, run:
+
+.. code-block:: bash
+
+ kubectl apply -f deploy/crds/zuul-ci_v1alpha1_zuul_crd.yaml
+ kubectl apply -f deploy/rbac-admin.yaml
+ kubectl apply -f deploy/operator.yaml
+
+You probably want a namespace, so go ahead and create one with:
+
+.. code-block:: bash
+
+ kubectl create namespace zuul
+
+You will need to prepare two config files for Zuul: the Nodepool
+config file and the Zuul tenant config file. See the Zuul and
+Nodepool manuals for how to prepare those. When they are ready, add
+them to Kubernetes with commands like:
+
+.. code-block:: bash
+
+ kubectl -n zuul create secret generic zuul-nodepool-config --from-file=nodepool.yaml
+ kubectl -n zuul create secret generic zuul-tenant-config --from-file=main.yaml
+
+Then create a file called ``zuul.yaml`` which looks like:
+
+.. code-block:: yaml
+
+ ---
+ apiVersion: operator.zuul-ci.org/v1alpha2
+ kind: Zuul
+ metadata:
+ name: zuul
+ spec:
+ executor:
+ count: 1
+ sshkey:
+ secretName: gerrit-secrets
+ scheduler:
+ config:
+ secretName: zuul-tenant-config
+ launcher:
+ config:
+ secretName: zuul-nodepool-config
+ web:
+ count: 1
+ connections:
+ opendev:
+ driver: git
+ baseurl: https://opendev.org
+
+This will create the most basic of Zuul installations, with one each
+of the `zuul-executor`, `zuul-scheduler`, and `zuul-web` processes.
+It will also create a Nodepool launcher for each of the providers
+listed in your ``nodepool.yaml``. If your Zuul tenant config file
+requires more connections, be sure to add them here.
+
+Managing Operator Dependencies
+------------------------------
+
+You may not want zuul-operator to install other operators (for
+example, if your cluster has other users and you don't want
+cert-manager or pxc-operator to be tied to a Zuul installation, or if
+you would prefer to avoid granting zuul-operator cluster admin
+privileges). In that case, you may install the other operators
+yourself and still allow zuul-operator to use those other operators.
+It can still create a PXC cluster for you as long as the pxc-operator
+is present.
+
+To use this mode of operation, make sure the following dependencies
+are installed before using zuul-operator:
+
+* Cert-manager (at least version 1.2.0)
+* Percona-xtradb-cluster-operator (at least version 1.7.0)
+
+With these installed, you may install zuul-operator with reduced
+privileges:
+
+.. code-block:: bash
+
+ kubectl apply -f deploy/crds/zuul-ci_v1alpha1_zuul_crd.yaml
+ kubectl apply -f deploy/rbac.yaml
+ kubectl apply -f deploy/operator.yaml
+
+After this point, usage is the same as other methods.
+
+Externally Managed Zuul Dependencies
+------------------------------------
+
+If you want zuul-operator to do even less work, you can have it avoid
+managing either ZooKeeper or the SQL database.
+
+Externally Managed ZooKeeper
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+If you already have a ZooKeeper instance you would like Zuul to use,
+add the following to the `Zuul` spec:
+
+.. code-block:: yaml
+
+ ---
+ apiVersion: operator.zuul-ci.org/v1alpha2
+ kind: Zuul
+ spec:
+ zookeeper:
+ connectionString: ...
+ secretName: ...
+
+The ``connectionString`` field should be a standard ZooKeeper
+connection string, and the ``secretName`` field should be a Kubernetes
+TLS secret with the client cert for Zuul to use when connecting to
+ZooKeeper. TLS is required.
+
+Externally Managed Database
+~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+If you would like to use an existing database, add the following to
+the `Zuul` spec:
+
+.. code-block:: yaml
+
+ ---
+ apiVersion: operator.zuul-ci.org/v1alpha2
+ kind: Zuul
+ spec:
+ database:
+ dburi: ...
+
+The ``dburi`` field should contain a Python db-api URI; it corresponds
+to the ``dburi`` entry in ``zuul.conf``.
+
+Secrets
+-------
+
+The operator uses Kubernetes secrets as input values for several
+aspects of operation. There are some general rules about how secrets
+are used:
+
+* For configuration files, secret keys are expected to be the typical
+ filename (for example, ``nodepool.yaml`` for the Nodepool config
+ file).
+
+* For Zuul connection entries, secret keys correspond to the
+ configuration file attributes for that section (e.g., ``app_key``
+ for the github driver).
+
+See the reference documentation for the specific `secretName` entry
+for details.
+
+Specification Reference
+-----------------------
+
+This is a fully populated example (with the exception of connection
+entries which can contain `zuul.conf` attributes passed through
+verbatim):
+
+.. code-block:: yaml
+
+ apiVersion: zuul-ci.org/v1alpha2
+ kind: Zuul
+ spec:
+ database:
+ secretName: mariadbSecret
+ zookeeper:
+ hosts: zk.example.com:2282
+ secretName: zookeeperTLS
+ merger:
+ count: 5
+ git_user_email: zuul@example.org
+ git_user_name: Example Zuul
+ executor:
+ count: 5
+ manage_ansible: false
+ web:
+ count: 1
+ status_url: https://zuul.example.org
+ fingergw:
+ count: 1
+ scheduler:
+ count: 1
+ connections:
+ gerrit:
+ driver: gerrit
+ server: gerrit.example.com
+ secretName: gerritSecrets
+ user: zuul
+ baseurl: http://gerrit.example.com:8080
+ github:
+ driver: github
+ secretName: githubSecrets
+ rate_limit_logging: false
+ app_id: 1234
+ jobVolumes:
+ - context: trusted
+ access: ro
+ path: /authdaemon/token
+ volume:
+ name: gcp-auth
+ hostPath:
+ path: /var/authdaemon/executor
+ type: DirectoryOrCreate
+
+.. attr:: Zuul
+
+ The Zuul kind is currently the only resource directly handled by
+ the operator. It holds a complete description of a Zuul system
+ (though at least partly via secrets referenced by this resource).
+
+ .. attr:: spec
+
+ .. attr:: imagePrefix
+ :default: docker.io/zuul
+
+ The prefix to use for images. The image names are fixed
+ (``zuul-executor``, etc). However, changing the prefix will
+ allow you to use custom images or private registries.
+
+ .. attr:: zuulImageVersion
+ :default: latest
+
+ The image tag to append to the Zuul images.
+
+ .. attr:: nodepoolImageVersion
+ :default: latest
+
+ The image tag to append to the Nodepool images.
+
+ .. attr:: database
+
+ This is not required unless you want to manage the database
+ yourself. If you omit this section, zuul-operator will
+ create a Percona XtraDB cluster for you.
+
+ You may add any attribute corresponding to the `database`
+ section of zuul.conf here. The ``dburi`` attribute will come
+ from the secret below.
+
+ .. attr:: secretName
+
+ The name of a secret containing connection information for
+ the database.
+
+ The key name in the secret should be ``dburi``.
+
+ .. attr:: zookeeper
+
+ This is not required unless you want to manage the ZooKeeper
+ cluster yourself. If you omit this section, zuul-operator
+ will create a ZooKeeper cluster for you
+
+ You may add any attribute corresponding to the `zookeeper`
+ section of zuul.conf here. The ``hosts`` and TLS attributes
+ will come from the secret below.
+
+ .. attr:: hosts
+
+ A standard ZooKeeper connection string.
+
+ .. attr:: secretName
+
+ The name of a secret containing a TLS client certificate
+ and key for ZooKeeper. This should be (or the format
+ should match) a standard Kubernetes TLS secret.
+
+ The key names in the secret should be:
+
+ * ``ca.crt``
+ * ``tls.crt``
+ * ``tls.key``
+
+ .. attr:: scheduler
+
+ .. attr:: config
+
+ .. attr:: secretName
+
+ The name of a secret containing the Zuul tenant config
+ file.
+
+ The key name in the secret should be ``main.yaml``.
+
+ .. attr:: launcher
+
+ .. attr:: config
+
+ .. attr:: secretName
+
+ The name of a secret containing the Nodepool config
+ file.
+
+ The key name in the secret should be ``nodepool.yaml``.
+
+ .. attr:: executor
+
+ .. attr:: count
+ :default: 1
+
+ How many executors to manage. This is a required
+ component and should be at least 1.
+
+ .. attr:: sshkey
+
+ .. attr:: secretName
+
+ The name of a secret containing the SSH private key
+ that executors should use when logging into Nodepool
+ nodes. You will need to arrange for the public half of
+ this key to be installed on those nodes via whatever
+ mechanism provided by your cloud.
+
+ The key name in the secret should be ``sshkey``.
+
+ .. attr:: merger
+
+ .. attr:: count
+ :default: 0
+
+ How many mergers to manage. Executors also act as mergers
+ so this is not required. They may be useful on a busy
+ system.
+
+ .. attr:: web
+
+ .. attr:: count
+ :default: 1
+
+ How many Zuul webservers to manage. This is a required
+ component and should be at least 1.
+
+ .. attr:: fingergw
+
+ .. attr:: count
+ :default: 1
+
+ How many Zuul finger gateway servers to manage.
+
+ .. attr:: connections
+
+ This is a mapping designed to match the `connections` entries
+ in the main Zuul config file (`zuul.conf`). Each key in the
+ mapping is the name of a connection (this is the name you
+ will use in the tenant config file), and the values are
+ key/value pairs that are directly added to that connectien
+ entry in `zuul.conf`. In the case of keys which are
+ typically files (for example, SSH keys), the values will be
+ written to disk for you (so you should include the full
+ values here and not the path).
+
+ You may provide any of these values directly in this resource
+ or using the secret described below. You may use both, and
+ the values will be combined (for example, you may include all
+ the values here except a private key which you include in a
+ secret).
+
+ Example:
+
+ .. code-block:: yaml
+
+ connections:
+ opendev:
+ driver: git
+ baseurl: https://opendev.org
+ gerrit:
+ driver: git
+ baseurl: https://gerrit.examplec.mo
+ secretName: gerrit-secrets
+
+ .. attr::
+
+ The name of the connection. You will use this is the
+ tenant config file. All of the attributes describing this
+ connection should be included underneath this key.
+
+ .. attr:: secretName
+
+ The name of a secret describing this connection. All
+ of the keys and values in this secret will be merged
+ with the keys and values described in this connection
+ entry. If you need to provide a file (for example, the
+ ``sshkey`` attribute of a Gerrit connection), include
+ the contents as the value of the ``sshkey`` attribute
+ in the secret.
+
+ .. attr:: jobVolumes
+
+ A list of Kubernetes volumes to be bind mounted into the
+ executor's execution context. These correspond to the
+ `trusted_ro_paths`, `untrusted_ro_paths`, `trusted_rw_paths`,
+ and `untrusted_ro_paths` entries in `zuul.conf`.
+
+ The first part of each entry describes how the volume should
+ appear in the executor, and the `volume` attribute describes
+ the Kubernetes volume.
+
+ .. attr:: context
+
+ One of the following values:
+
+ .. value:: trusted
+
+ To be mounted in the `trusted` execution context.
+
+ .. value:: untrusted
+
+ To be mounted in the `untrusted` execution context.
+
+ .. attr:: access
+
+ One of the following values:
+
+ .. value:: rw
+
+ To be mounted read/write.
+
+ .. value:: ro
+
+ To be mounted read-only.
+
+ .. attr:: path
+
+ The mount point within the execution context.
+
+ .. attr:: volume
+
+ A mapping corresponding to a Kubernetes volume.
diff --git a/tox.ini b/tox.ini
new file mode 100644
index 0000000..afb2f3a
--- /dev/null
+++ b/tox.ini
@@ -0,0 +1,42 @@
+[tox]
+minversion = 1.6
+skipsdist = True
+envlist = pep8
+
+[testenv]
+basepython = python3
+install_command = pip install {opts} {packages}
+deps = -r{toxinidir}/requirements.txt
+ -r{toxinidir}/test-requirements.txt
+commands =
+ python setup.py testr --slowest --testr-args='{posargs}'
+
+[testenv:bindep]
+# Do not install any requirements. We want this to be fast and work even if
+# system dependencies are missing, since it's used to tell you what system
+# dependencies are missing! This also means that bindep must be installed
+# separately, outside of the requirements files.
+deps = bindep
+commands = bindep test
+
+[testenv:docs]
+install_command = pip install {opts} {packages}
+deps =
+ -r{toxinidir}/doc/requirements.txt
+commands =
+ sphinx-build -E -W -d doc/build/doctrees -b html doc/source/ doc/build/html
+
+[testenv:pep8]
+whitelist_externals = bash
+commands =
+ flake8 {posargs}
+
+[testenv:venv]
+commands = {posargs}
+
+[flake8]
+# These are ignored intentionally in openstack-infra projects;
+# please don't submit patches that solely correct them or enable them.
+ignore = E124,E125,E129,E252,E402,E741,H,W503,W504
+show-source = True
+exclude = .venv,.tox,dist,doc,build,*.egg