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