Document metalsmith_instances
Change-Id: I9d3d17f104caea470252d400d26c225ca5de3b6e
This commit is contained in:
@@ -6,3 +6,4 @@ sphinx>=2.0.0,!=2.1.0 # BSD
|
|||||||
sphinxcontrib-apidoc>=0.2.0 # BSD
|
sphinxcontrib-apidoc>=0.2.0 # BSD
|
||||||
sphinxcontrib-svg2pdfconverter>=0.1.0 # BSD
|
sphinxcontrib-svg2pdfconverter>=0.1.0 # BSD
|
||||||
openstackdocstheme>=2.2.1 # Apache-2.0
|
openstackdocstheme>=2.2.1 # Apache-2.0
|
||||||
|
ansible>=2.8
|
||||||
|
264
doc/source/_exts/ansible-autodoc.py
Normal file
264
doc/source/_exts/ansible-autodoc.py
Normal file
@@ -0,0 +1,264 @@
|
|||||||
|
# Copyright 2019 Red Hat, Inc.
|
||||||
|
# All Rights Reserved.
|
||||||
|
#
|
||||||
|
# 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 imp
|
||||||
|
import os
|
||||||
|
|
||||||
|
from docutils import core
|
||||||
|
from docutils import nodes
|
||||||
|
from docutils.parsers import rst
|
||||||
|
from docutils.parsers.rst import Directive
|
||||||
|
from docutils.writers.html4css1 import Writer
|
||||||
|
|
||||||
|
import yaml
|
||||||
|
|
||||||
|
|
||||||
|
DOCYAML = yaml
|
||||||
|
DOCYAML.default_flow_style = False
|
||||||
|
|
||||||
|
|
||||||
|
class AnsibleAutoPluginDirective(Directive):
|
||||||
|
directive_name = "ansibleautoplugin"
|
||||||
|
has_content = True
|
||||||
|
option_spec = {
|
||||||
|
'module': rst.directives.unchanged,
|
||||||
|
'role': rst.directives.unchanged,
|
||||||
|
'documentation': rst.directives.unchanged,
|
||||||
|
'examples': rst.directives.unchanged
|
||||||
|
}
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def _render_html(source):
|
||||||
|
return core.publish_parts(
|
||||||
|
source=source,
|
||||||
|
writer=Writer(),
|
||||||
|
writer_name='html',
|
||||||
|
settings_overrides={'no_system_messages': True}
|
||||||
|
)
|
||||||
|
|
||||||
|
def make_node(self, title, contents, content_type=None):
|
||||||
|
section = self._section_block(title=title)
|
||||||
|
if not content_type:
|
||||||
|
# Doc section
|
||||||
|
for content in contents['docs']:
|
||||||
|
for paragraph in content.split('\n'):
|
||||||
|
retnode = nodes.paragraph()
|
||||||
|
retnode.append(self._raw_html_block(data=paragraph))
|
||||||
|
section.append(retnode)
|
||||||
|
|
||||||
|
# Options Section
|
||||||
|
options_list = nodes.field_list()
|
||||||
|
options_section = self._section_block(title='Options')
|
||||||
|
for key, value in contents['options'].items():
|
||||||
|
options_list.append(
|
||||||
|
self._raw_fields(
|
||||||
|
data=value['description'],
|
||||||
|
field_name=key
|
||||||
|
)
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
options_section.append(options_list)
|
||||||
|
section.append(options_section)
|
||||||
|
|
||||||
|
# Authors Section
|
||||||
|
authors_list = nodes.field_list()
|
||||||
|
authors_list.append(
|
||||||
|
self._raw_fields(
|
||||||
|
data=contents['author']
|
||||||
|
)
|
||||||
|
)
|
||||||
|
authors_section = self._section_block(title='Authors')
|
||||||
|
authors_section.append(authors_list)
|
||||||
|
section.append(authors_section)
|
||||||
|
|
||||||
|
elif content_type == 'yaml':
|
||||||
|
for content in contents:
|
||||||
|
section.append(
|
||||||
|
self._literal_block(
|
||||||
|
data=content,
|
||||||
|
dump_data=False
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
return section
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def load_module(filename):
|
||||||
|
return imp.load_source('__ansible_module__', filename)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def build_documentation(module):
|
||||||
|
docs = DOCYAML.load(module.DOCUMENTATION)
|
||||||
|
doc_data = dict()
|
||||||
|
doc_data['docs'] = docs['description']
|
||||||
|
doc_data['author'] = docs.get('author', list())
|
||||||
|
doc_data['options'] = docs.get('options', dict())
|
||||||
|
return doc_data
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def build_examples(module):
|
||||||
|
examples = DOCYAML.load(module.EXAMPLES)
|
||||||
|
return_examples = list()
|
||||||
|
for example in examples:
|
||||||
|
return_examples.append(DOCYAML.dump([example], sort_keys=False))
|
||||||
|
return return_examples
|
||||||
|
|
||||||
|
def _raw_html_block(self, data):
|
||||||
|
html = self._render_html(source=data)
|
||||||
|
return nodes.raw('', html['body'], format='html')
|
||||||
|
|
||||||
|
def _raw_fields(self, data, field_name=''):
|
||||||
|
body = nodes.field_body()
|
||||||
|
if isinstance(data, list):
|
||||||
|
for item in data:
|
||||||
|
body.append(self._raw_html_block(data=item))
|
||||||
|
else:
|
||||||
|
body.append(self._raw_html_block(data=data))
|
||||||
|
|
||||||
|
field = nodes.field()
|
||||||
|
field.append(nodes.field_name(text=field_name))
|
||||||
|
field.append(body)
|
||||||
|
return field
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def _literal_block(data, language='yaml', dump_data=True):
|
||||||
|
if dump_data:
|
||||||
|
literal = nodes.literal_block(
|
||||||
|
text=DOCYAML.dump(data)
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
literal = nodes.literal_block(text=data)
|
||||||
|
literal['language'] = 'yaml'
|
||||||
|
return literal
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def _section_block(title, text=None):
|
||||||
|
section = nodes.section(
|
||||||
|
title,
|
||||||
|
nodes.title(text=title),
|
||||||
|
ids=[nodes.make_id('-'.join(title))],
|
||||||
|
)
|
||||||
|
if text:
|
||||||
|
section_body = nodes.field_body()
|
||||||
|
section_body.append(nodes.paragraph(text=text))
|
||||||
|
section.append(section_body)
|
||||||
|
|
||||||
|
return section
|
||||||
|
|
||||||
|
def _yaml_section(self, to_yaml_data, section_title, section_text=None):
|
||||||
|
yaml_section = self._section_block(
|
||||||
|
title=section_title,
|
||||||
|
text=section_text
|
||||||
|
)
|
||||||
|
yaml_section.append(self._literal_block(data=to_yaml_data))
|
||||||
|
return yaml_section
|
||||||
|
|
||||||
|
def _run_role(self, role):
|
||||||
|
section = self._section_block(
|
||||||
|
title='Role Documentation',
|
||||||
|
text='Welcome to the "{}" role documentation.'.format(
|
||||||
|
os.path.basename(role)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
defaults_file = os.path.join(role, 'defaults', 'main.yml')
|
||||||
|
if os.path.exists(defaults_file):
|
||||||
|
with open(defaults_file) as f:
|
||||||
|
role_defaults = DOCYAML.load(f.read())
|
||||||
|
section.append(
|
||||||
|
self._yaml_section(
|
||||||
|
to_yaml_data=role_defaults,
|
||||||
|
section_title='Role Defaults',
|
||||||
|
section_text='This section highlights all of the defaults'
|
||||||
|
' and variables set within the "{}"'
|
||||||
|
' role.'.format(os.path.basename(role))
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
vars_path = os.path.join(role, 'vars')
|
||||||
|
if os.path.exists(vars_path):
|
||||||
|
for v_file in os.listdir(vars_path):
|
||||||
|
vars_file = os.path.join(vars_path, v_file)
|
||||||
|
with open(vars_file) as f:
|
||||||
|
vars_values = DOCYAML.load(f.read())
|
||||||
|
section.append(
|
||||||
|
self._yaml_section(
|
||||||
|
to_yaml_data=vars_values,
|
||||||
|
section_title='Role Variables: {}'.format(v_file)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
self.run_returns.append(section)
|
||||||
|
|
||||||
|
# Document any libraries nested within the role
|
||||||
|
library_path = os.path.join(role, 'library')
|
||||||
|
if os.path.exists(library_path):
|
||||||
|
self.options['documentation'] = True
|
||||||
|
self.options['examples'] = True
|
||||||
|
for lib in os.listdir(library_path):
|
||||||
|
if lib.endswith('.py'):
|
||||||
|
self._run_module(
|
||||||
|
module=self.load_module(
|
||||||
|
filename=os.path.join(
|
||||||
|
library_path,
|
||||||
|
lib
|
||||||
|
)
|
||||||
|
),
|
||||||
|
module_title='Embedded module: {}'.format(lib),
|
||||||
|
example_title='Examples for embedded module'
|
||||||
|
)
|
||||||
|
|
||||||
|
def _run_module(self, module, module_title="Module Documentation",
|
||||||
|
example_title="Example Tasks"):
|
||||||
|
if self.options.get('documentation'):
|
||||||
|
docs = self.build_documentation(module=module)
|
||||||
|
self.run_returns.append(
|
||||||
|
self.make_node(
|
||||||
|
title=module_title,
|
||||||
|
contents=docs
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
if self.options.get('examples'):
|
||||||
|
examples = self.build_examples(module=module)
|
||||||
|
self.run_returns.append(
|
||||||
|
self.make_node(
|
||||||
|
title=example_title,
|
||||||
|
contents=examples,
|
||||||
|
content_type='yaml'
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
def run(self):
|
||||||
|
self.run_returns = list()
|
||||||
|
|
||||||
|
if self.options.get('module'):
|
||||||
|
module = self.load_module(filename=self.options['module'])
|
||||||
|
self._run_module(module=module)
|
||||||
|
|
||||||
|
if self.options.get('role'):
|
||||||
|
self._run_role(role=self.options['role'])
|
||||||
|
|
||||||
|
return self.run_returns
|
||||||
|
|
||||||
|
|
||||||
|
def setup(app):
|
||||||
|
classes = [
|
||||||
|
AnsibleAutoPluginDirective,
|
||||||
|
]
|
||||||
|
for directive_class in classes:
|
||||||
|
app.add_directive(directive_class.directive_name, directive_class)
|
||||||
|
|
||||||
|
return {'version': '0.2'}
|
@@ -14,7 +14,10 @@
|
|||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
|
# Add the project
|
||||||
sys.path.insert(0, os.path.abspath('../..'))
|
sys.path.insert(0, os.path.abspath('../..'))
|
||||||
|
# Add the extensions
|
||||||
|
sys.path.insert(0, os.path.join(os.path.abspath('.'), '_exts'))
|
||||||
# -- General configuration ----------------------------------------------------
|
# -- General configuration ----------------------------------------------------
|
||||||
|
|
||||||
# Add any Sphinx extension module names here, as strings. They can be
|
# Add any Sphinx extension module names here, as strings. They can be
|
||||||
@@ -23,6 +26,7 @@ extensions = [
|
|||||||
'sphinxcontrib.apidoc',
|
'sphinxcontrib.apidoc',
|
||||||
'sphinxcontrib.rsvgconverter',
|
'sphinxcontrib.rsvgconverter',
|
||||||
'openstackdocstheme',
|
'openstackdocstheme',
|
||||||
|
'ansible-autodoc'
|
||||||
]
|
]
|
||||||
|
|
||||||
autoclass_content = 'both'
|
autoclass_content = 'both'
|
||||||
|
@@ -1 +1,9 @@
|
|||||||
.. include:: ../../../metalsmith_ansible/roles/metalsmith_deployment/README.rst
|
.. include:: ../../../metalsmith_ansible/roles/metalsmith_deployment/README.rst
|
||||||
|
|
||||||
|
Module - metalsmith_instances
|
||||||
|
=============================
|
||||||
|
|
||||||
|
.. ansibleautoplugin::
|
||||||
|
:module: metalsmith_ansible/ansible_plugins/modules/metalsmith_instances.py
|
||||||
|
:documentation: true
|
||||||
|
:examples: true
|
||||||
|
@@ -186,6 +186,26 @@ options:
|
|||||||
- error
|
- error
|
||||||
'''
|
'''
|
||||||
|
|
||||||
|
EXAMPLES = '''
|
||||||
|
- name: Provision instances
|
||||||
|
metalsmith_instances:
|
||||||
|
instances:
|
||||||
|
- name: node-0
|
||||||
|
hostname: compute-0
|
||||||
|
image: overcloud-full
|
||||||
|
state: present
|
||||||
|
wait: true
|
||||||
|
clean_up: false
|
||||||
|
timeout: 1200
|
||||||
|
concurrency: 20
|
||||||
|
log_level: info
|
||||||
|
register: baremetal_provisioned
|
||||||
|
|
||||||
|
- name: Metalsmith log for provision instances
|
||||||
|
debug:
|
||||||
|
var: baremetal_provisioned.logging
|
||||||
|
'''
|
||||||
|
|
||||||
|
|
||||||
METALSMITH_LOG_MAP = {
|
METALSMITH_LOG_MAP = {
|
||||||
'debug': logging.DEBUG,
|
'debug': logging.DEBUG,
|
||||||
|
@@ -1,5 +1,5 @@
|
|||||||
Metalsmith Deployment
|
Role - metalsmith_deployment
|
||||||
=====================
|
============================
|
||||||
|
|
||||||
This role deploys instances using **metalsmith** CLI.
|
This role deploys instances using **metalsmith** CLI.
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user