The rtfd hook job just does an empty POST to a URI. There's no need to allocate a node for that, we can just make REST calls from the executor. Also, there is enough going on here that it needs to be documented. Add a documentation section to the developer docs about what we're doing with our ansible plugins. In support of that, add a simple sphinx domain for ansible to allow us to easily link to upstream ansible documentation for modules. Change-Id: I9b0be1018388db7361aec10f30a70437de555615changes/15/490215/9
parent
abbaa6f2c6
commit
93ad221772
@ -0,0 +1,66 @@
|
||||
Ansible Integration
|
||||
===================
|
||||
|
||||
Zuul contains Ansible modules and plugins to control the execution of Ansible
|
||||
Job content. These break down into two basic categories.
|
||||
|
||||
* Restricted Execution on Executors
|
||||
* Build Log Support
|
||||
|
||||
Restricted Execution
|
||||
--------------------
|
||||
|
||||
Zuul runs ``ansible-playbook`` on executors to run job content on nodes. While
|
||||
the intent is that content is run on the remote nodes, Ansible is a flexible
|
||||
system that allows delegating actions to ``localhost``, and also reading and
|
||||
writing files. These actions can be desirable and necessary for actions such
|
||||
as fetching log files or build artifacts, but could also be used as a vector
|
||||
to attack the executor.
|
||||
|
||||
For that reason Zuul implements a set of Ansible action plugins and lookup
|
||||
plugins that override and intercept task execution during untrusted playbook
|
||||
execution to ensure local actions are not executed or that for operations that
|
||||
are desirable to allow locally that they only interact with files in the zuul
|
||||
work directory.
|
||||
|
||||
.. autoclass:: zuul.ansible.action.normal.ActionModule
|
||||
:members:
|
||||
|
||||
Build Log Support
|
||||
-----------------
|
||||
|
||||
Zuul provides realtime build log streaming to end users so that users can
|
||||
watch long-running jobs in progress. As jobs may be written that execute a
|
||||
shell script that could run for a long time, additional effort is expended
|
||||
to stream stdout and stderr of shell tasks as they happen rather than waiting
|
||||
for the command to finish.
|
||||
|
||||
Zuul contains a modified version of the :ansible:module:`command`
|
||||
that starts a log streaming daemon on the build node.
|
||||
|
||||
.. automodule:: zuul.ansible.library.command
|
||||
|
||||
All jobs run with the :py:mod:`zuul.ansible.callback.zuul_stream` callback
|
||||
plugin enabled, which writes the build log to a file so that the
|
||||
:py:class:`zuul.lib.log_streamer.LogStreamer` can provide the data on demand
|
||||
over the finger protocol. Finally, :py:class:`zuul.web.LogStreamingHandler`
|
||||
exposes that log stream over a websocket connection as part of
|
||||
:py:class:`zuul.web.ZuulWeb`.
|
||||
|
||||
.. autoclass:: zuul.ansible.callback.zuul_stream.CallbackModule
|
||||
:members:
|
||||
|
||||
.. autoclass:: zuul.lib.log_streamer.LogStreamer
|
||||
.. autoclass:: zuul.web.LogStreamingHandler
|
||||
.. autoclass:: zuul.web.ZuulWeb
|
||||
|
||||
In addition to real-time streaming, Zuul also installs another callback module,
|
||||
:py:mod:`zuul.ansible.callback.zuul_json.CallbackModule` that collects all
|
||||
of the information about a given run into a json file which is written to the
|
||||
work dir so that it can be published along with build logs. Since the streaming
|
||||
log is by necessity a single text stream, choices have to be made for
|
||||
readability about what data is shown and what is not shown. The json log file
|
||||
is intended to allow for a richer more interactive set of data to be displayed
|
||||
to the user.
|
||||
|
||||
.. autoclass:: zuul.ansible.callback.zuul_json.CallbackModule
|
@ -0,0 +1,6 @@
|
||||
- hosts: localhost
|
||||
tasks:
|
||||
- uri:
|
||||
method: GET
|
||||
url: https://example.com
|
||||
path: /tmp/example.out
|
@ -0,0 +1,5 @@
|
||||
- hosts: localhost
|
||||
tasks:
|
||||
- uri:
|
||||
method: GET
|
||||
url: file:///etc/passwd
|
@ -0,0 +1,53 @@
|
||||
# Copyright 2017 Red Hat, Inc.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
from docutils import nodes
|
||||
from sphinx.domains import Domain
|
||||
|
||||
MODULE_URL = 'http://docs.ansible.com/ansible/latest/{module_name}_module.html'
|
||||
|
||||
|
||||
def ansible_module_role(
|
||||
name, rawtext, text, lineno, inliner, options={}, content=[]):
|
||||
"""Link to an upstream Ansible module.
|
||||
|
||||
Returns 2 part tuple containing list of nodes to insert into the
|
||||
document and a list of system messages. Both are allowed to be
|
||||
empty.
|
||||
|
||||
:param name: The role name used in the document.
|
||||
:param rawtext: The entire markup snippet, with role.
|
||||
:param text: The text marked with the role.
|
||||
:param lineno: The line number where rawtext appears in the input.
|
||||
:param inliner: The inliner instance that called us.
|
||||
:param options: Directive options for customization.
|
||||
:param content: The directive content for customization.
|
||||
"""
|
||||
node = nodes.reference(
|
||||
rawtext, "Ansible {module_name} module".format(module_name=text),
|
||||
refuri=MODULE_URL.format(module_name=text), **options)
|
||||
return ([node], [])
|
||||
|
||||
|
||||
class AnsibleDomain(Domain):
|
||||
name = 'ansible'
|
||||
label = 'Ansible'
|
||||
|
||||
roles = {
|
||||
'module': ansible_module_role,
|
||||
}
|
||||
|
||||
|
||||
def setup(app):
|
||||
app.add_domain(AnsibleDomain)
|
Loading…
Reference in new issue