Neutron Feature Classification
The feature classification matrix will provide information about plugins and the features they support. Acts as a launching point for users to read about the intent of the matrix before reviewing the matrix to find features and plugins that meet their needs. Will implement a page where users can view Neutron features and plugins and their status. Similar to Nova's implementation here: http://docs.openstack.org/developer/nova/feature_classification.html http://docs.openstack.org/developer/nova/support-matrix.html Co-Authored-By: Darek Smigiel <dariusz.smigiel@intel.com> Closes-Bug: #1580327 Change-Id: I67f4dc67883623decdbf136c598eb9e2d0bc24c4
This commit is contained in:
parent
edeb1f0bcc
commit
c0130c57e5
33
doc/source/_static/support_matrix.css
Normal file
33
doc/source/_static/support_matrix.css
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
|
||||||
|
.sp_feature_required {
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sp_impl_complete {
|
||||||
|
color: rgb(0, 120, 0);
|
||||||
|
font-weight: normal;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sp_impl_missing {
|
||||||
|
color: rgb(120, 0, 0);
|
||||||
|
font-weight: normal;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sp_impl_partial {
|
||||||
|
color: rgb(170, 170, 0);
|
||||||
|
font-weight: normal;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sp_impl_unknown {
|
||||||
|
color: rgb(170, 170, 170);
|
||||||
|
font-weight: normal;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sp_impl_summary {
|
||||||
|
font-size: 2em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sp_cli {
|
||||||
|
font-family: monospace;
|
||||||
|
background-color: #F5F5F5;
|
||||||
|
}
|
@ -37,6 +37,7 @@ import warnings
|
|||||||
BASE_DIR = os.path.dirname(os.path.abspath(__file__))
|
BASE_DIR = os.path.dirname(os.path.abspath(__file__))
|
||||||
NEUTRON_DIR = os.path.abspath(os.path.join(BASE_DIR, "..", ".."))
|
NEUTRON_DIR = os.path.abspath(os.path.join(BASE_DIR, "..", ".."))
|
||||||
sys.path.insert(0, NEUTRON_DIR)
|
sys.path.insert(0, NEUTRON_DIR)
|
||||||
|
sys.path.append(os.path.abspath("ext"))
|
||||||
|
|
||||||
# -- General configuration ---------------------------------------------------
|
# -- General configuration ---------------------------------------------------
|
||||||
|
|
||||||
@ -47,7 +48,8 @@ extensions = ['sphinx.ext.autodoc',
|
|||||||
'sphinx.ext.ifconfig',
|
'sphinx.ext.ifconfig',
|
||||||
'sphinx.ext.graphviz',
|
'sphinx.ext.graphviz',
|
||||||
'sphinx.ext.todo',
|
'sphinx.ext.todo',
|
||||||
'oslosphinx']
|
'oslosphinx',
|
||||||
|
'support_matrix']
|
||||||
|
|
||||||
todo_include_todos = True
|
todo_include_todos = True
|
||||||
|
|
||||||
@ -152,7 +154,7 @@ modindex_common_prefix = ['neutron.']
|
|||||||
# Add any paths that contain custom static files (such as style sheets) here,
|
# 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,
|
# relative to this directory. They are copied after the builtin static files,
|
||||||
# so a file named "default.css" will overwrite the builtin "default.css".
|
# so a file named "default.css" will overwrite the builtin "default.css".
|
||||||
# html_static_path = ['_static']
|
html_static_path = ['_static']
|
||||||
|
|
||||||
# If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
|
# If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
|
||||||
# using the given strftime format.
|
# using the given strftime format.
|
||||||
|
482
doc/source/ext/support_matrix.py
Normal file
482
doc/source/ext/support_matrix.py
Normal file
@ -0,0 +1,482 @@
|
|||||||
|
# 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.
|
||||||
|
"""
|
||||||
|
This provides a sphinx extension able to render the
|
||||||
|
source/general_feature_support_matrix.ini
|
||||||
|
file into the developer documentation.
|
||||||
|
|
||||||
|
It is used via a single directive in the .rst file
|
||||||
|
|
||||||
|
.. support_matrix::
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
import re
|
||||||
|
|
||||||
|
from docutils import nodes
|
||||||
|
from docutils.parsers import rst
|
||||||
|
from six.moves import configparser
|
||||||
|
|
||||||
|
RE_PATTERN = re.compile("[^a-zA-Z0-9_]")
|
||||||
|
|
||||||
|
|
||||||
|
class SupportMatrix(object):
|
||||||
|
"""Represents the entire support matrix for Neutron drivers"""
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
self.features = []
|
||||||
|
self.targets = {}
|
||||||
|
|
||||||
|
|
||||||
|
class SupportMatrixFeature(object):
|
||||||
|
STATUS_IMMATURE = "immature"
|
||||||
|
STATUS_MATURE = "mature"
|
||||||
|
STATUS_REQUIRED = "required"
|
||||||
|
STATUS_DEPRECATED = "deprecated"
|
||||||
|
|
||||||
|
STATUS_ALL = [STATUS_IMMATURE, STATUS_MATURE,
|
||||||
|
STATUS_REQUIRED, STATUS_DEPRECATED]
|
||||||
|
|
||||||
|
def __init__(self, key, title, status=STATUS_IMMATURE,
|
||||||
|
group=None, notes=None, cli=(), api=None):
|
||||||
|
self.key = key
|
||||||
|
self.title = title
|
||||||
|
self.status = status
|
||||||
|
self.group = group
|
||||||
|
self.notes = notes
|
||||||
|
self.cli = cli
|
||||||
|
self.api = api
|
||||||
|
|
||||||
|
self.implementations = {}
|
||||||
|
|
||||||
|
|
||||||
|
class SupportMatrixImplementation(object):
|
||||||
|
STATUS_COMPLETE = "complete"
|
||||||
|
STATUS_PARTIAL = "partial"
|
||||||
|
STATUS_INCOMPLETE = "incomplete"
|
||||||
|
STATUS_UNKNOWN = "unknown"
|
||||||
|
|
||||||
|
STATUS_ALL = [STATUS_COMPLETE, STATUS_INCOMPLETE,
|
||||||
|
STATUS_PARTIAL, STATUS_UNKNOWN]
|
||||||
|
|
||||||
|
def __init__(self, status=STATUS_INCOMPLETE, notes=None):
|
||||||
|
|
||||||
|
self.status = status
|
||||||
|
self.notes = notes
|
||||||
|
|
||||||
|
|
||||||
|
STATUS_DICT = {
|
||||||
|
SupportMatrixImplementation.STATUS_COMPLETE: u"\u2714",
|
||||||
|
SupportMatrixImplementation.STATUS_INCOMPLETE: u"\u2716",
|
||||||
|
SupportMatrixImplementation.STATUS_PARTIAL: u"\u2714",
|
||||||
|
SupportMatrixImplementation.STATUS_UNKNOWN: u"?"
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class SupportMatrixTarget(object):
|
||||||
|
def __init__(self, key, title, driver, plugin=None,
|
||||||
|
architecture=None, api=None):
|
||||||
|
""":param key: Unique identifier for plugin
|
||||||
|
:param title: Human readable name for plugin
|
||||||
|
:param driver: name of the driver
|
||||||
|
:param plugin: optional name of plugin
|
||||||
|
:param architecture: optional name of architecture
|
||||||
|
"""
|
||||||
|
self.api = api
|
||||||
|
self.key = key
|
||||||
|
self.title = title
|
||||||
|
self.driver = driver
|
||||||
|
self.plugin = plugin
|
||||||
|
self.architecture = architecture
|
||||||
|
|
||||||
|
|
||||||
|
class SupportMatrixDirective(rst.Directive):
|
||||||
|
|
||||||
|
# general_feature_support_matrix.ini is the arg
|
||||||
|
required_arguments = 1
|
||||||
|
|
||||||
|
def run(self):
|
||||||
|
matrix = self._load_support_matrix()
|
||||||
|
return self._build_markup(matrix)
|
||||||
|
|
||||||
|
def _load_support_matrix(self):
|
||||||
|
"""Reads the support-matrix.ini file and populates an instance
|
||||||
|
of the SupportMatrix class with all the data.
|
||||||
|
|
||||||
|
:returns: SupportMatrix instance
|
||||||
|
"""
|
||||||
|
|
||||||
|
cfg = configparser.SafeConfigParser()
|
||||||
|
env = self.state.document.settings.env
|
||||||
|
fname = self.arguments[0]
|
||||||
|
rel_fpath, fpath = env.relfn2path(fname)
|
||||||
|
with open(fpath) as fp:
|
||||||
|
cfg.readfp(fp)
|
||||||
|
|
||||||
|
# This ensures that the docs are rebuilt whenever the
|
||||||
|
# .ini file changes
|
||||||
|
env.note_dependency(rel_fpath)
|
||||||
|
|
||||||
|
matrix = SupportMatrix()
|
||||||
|
matrix.targets = self._get_targets(cfg)
|
||||||
|
matrix.features = self._get_features(cfg, matrix.targets)
|
||||||
|
|
||||||
|
return matrix
|
||||||
|
|
||||||
|
def _get_targets(self, cfg):
|
||||||
|
# The 'targets' section is special - it lists all the
|
||||||
|
# backend drivers that this file records data for
|
||||||
|
|
||||||
|
targets = {}
|
||||||
|
network_target = "networking-"
|
||||||
|
|
||||||
|
for item in cfg.options("targets"):
|
||||||
|
if not item.startswith(network_target):
|
||||||
|
continue
|
||||||
|
|
||||||
|
# The driver string will optionally contain
|
||||||
|
# 'networking-*' qualifier
|
||||||
|
# so we expect between 1 and 3 components
|
||||||
|
# in the name
|
||||||
|
key = item[len(network_target):]
|
||||||
|
title = cfg.get("targets", item)
|
||||||
|
name = key.split("-")
|
||||||
|
if len(name) > 3:
|
||||||
|
raise Exception("'%s' field is malformed in '[%s]' section" %
|
||||||
|
(item, "DEFAULT"))
|
||||||
|
else:
|
||||||
|
target = SupportMatrixTarget(key, title, *name)
|
||||||
|
|
||||||
|
targets[key] = target
|
||||||
|
|
||||||
|
return targets
|
||||||
|
|
||||||
|
def _get_features(self, cfg, targets):
|
||||||
|
# All sections except 'targets' describe some feature of
|
||||||
|
# the Neutron backend driver.
|
||||||
|
|
||||||
|
features = []
|
||||||
|
|
||||||
|
for section in cfg.sections():
|
||||||
|
if section == "targets":
|
||||||
|
continue
|
||||||
|
if not cfg.has_option(section, "title"):
|
||||||
|
raise Exception(
|
||||||
|
"'title' field missing in '[%s]' section" % section)
|
||||||
|
|
||||||
|
title = cfg.get(section, "title")
|
||||||
|
|
||||||
|
status = SupportMatrixFeature.STATUS_IMMATURE
|
||||||
|
if cfg.has_option(section, "status"):
|
||||||
|
# The value is a string "status(group)" where
|
||||||
|
# the 'group' part is optional
|
||||||
|
status = cfg.get(section, "status")
|
||||||
|
offset = status.find("(")
|
||||||
|
group = None
|
||||||
|
if offset != -1:
|
||||||
|
group = status[offset + 1:-1]
|
||||||
|
status = status[0:offset]
|
||||||
|
|
||||||
|
if status not in SupportMatrixFeature.STATUS_ALL:
|
||||||
|
raise Exception(
|
||||||
|
"'status' field value '%s' in ['%s']"
|
||||||
|
"section must be %s" %
|
||||||
|
(status, section,
|
||||||
|
",".join(SupportMatrixFeature.STATUS_ALL)))
|
||||||
|
|
||||||
|
cli = []
|
||||||
|
if cfg.has_option(section, "cli"):
|
||||||
|
cli = cfg.get(section, "cli")
|
||||||
|
|
||||||
|
api = None
|
||||||
|
if cfg.has_option(section, "api"):
|
||||||
|
api = cfg.get(section, "api")
|
||||||
|
|
||||||
|
notes = None
|
||||||
|
if cfg.has_option(section, "notes"):
|
||||||
|
notes = cfg.get(section, "notes")
|
||||||
|
feature = SupportMatrixFeature(section, title, status, group,
|
||||||
|
notes, cli, api)
|
||||||
|
|
||||||
|
# Now we've got the basic feature details, we must process
|
||||||
|
# the backend driver implementation for each feature
|
||||||
|
for item in cfg.options(section):
|
||||||
|
network_target = "networking-"
|
||||||
|
network_notes = "networking-notes-"
|
||||||
|
|
||||||
|
if not item.startswith(network_target):
|
||||||
|
continue
|
||||||
|
|
||||||
|
key = item[len(network_target):]
|
||||||
|
if key not in targets:
|
||||||
|
raise Exception(
|
||||||
|
"networking-'%s' in '[%s]' not declared" %
|
||||||
|
(item, section))
|
||||||
|
|
||||||
|
status = cfg.get(section, item)
|
||||||
|
if status not in SupportMatrixImplementation.STATUS_ALL:
|
||||||
|
raise Exception(
|
||||||
|
"'%s' value '%s' in '[%s]' section must be %s" %
|
||||||
|
(item, status, section,
|
||||||
|
",".join(SupportMatrixImplementation.STATUS_ALL)))
|
||||||
|
notes_key = network_notes + item[len(network_notes):]
|
||||||
|
notes = None
|
||||||
|
if cfg.has_option(section, notes_key):
|
||||||
|
notes = cfg.get(section, notes_key)
|
||||||
|
|
||||||
|
target = targets[key]
|
||||||
|
impl = SupportMatrixImplementation(status, notes)
|
||||||
|
feature.implementations[target.key] = impl
|
||||||
|
|
||||||
|
for key in targets:
|
||||||
|
if key not in feature.implementations:
|
||||||
|
raise Exception("'%s' missing in '[%s]' section" %
|
||||||
|
(target.key, section))
|
||||||
|
|
||||||
|
features.append(feature)
|
||||||
|
|
||||||
|
return features
|
||||||
|
|
||||||
|
def _build_markup(self, matrix):
|
||||||
|
"""Constructs the docutils content for the support matrix
|
||||||
|
"""
|
||||||
|
content = []
|
||||||
|
self._build_summary(matrix, content)
|
||||||
|
self._build_details(matrix, content)
|
||||||
|
self._build_notes(content)
|
||||||
|
return content
|
||||||
|
|
||||||
|
def _build_summary(self, matrix, content):
|
||||||
|
"""Constructs the docutils content for the summary of
|
||||||
|
the support matrix.
|
||||||
|
|
||||||
|
The summary consists of a giant table, with one row
|
||||||
|
for each feature, and a column for each backend
|
||||||
|
driver. It provides an 'at a glance' summary of the
|
||||||
|
status of each driver
|
||||||
|
"""
|
||||||
|
|
||||||
|
summary_title = nodes.subtitle(text="Summary")
|
||||||
|
summary = nodes.table()
|
||||||
|
cols = len(matrix.targets.keys())
|
||||||
|
cols += 2
|
||||||
|
summary_group = nodes.tgroup(cols=cols)
|
||||||
|
summary_body = nodes.tbody()
|
||||||
|
summary_head = nodes.thead()
|
||||||
|
|
||||||
|
for i in range(cols):
|
||||||
|
summary_group.append(nodes.colspec(colwidth=1))
|
||||||
|
summary_group.append(summary_head)
|
||||||
|
summary_group.append(summary_body)
|
||||||
|
summary.append(summary_group)
|
||||||
|
content.append(summary_title)
|
||||||
|
content.append(summary)
|
||||||
|
|
||||||
|
# This sets up all the column headers - two fixed
|
||||||
|
# columns for feature name & status
|
||||||
|
header = nodes.row()
|
||||||
|
blank = nodes.entry()
|
||||||
|
blank.append(nodes.emphasis(text="Feature"))
|
||||||
|
header.append(blank)
|
||||||
|
blank = nodes.entry()
|
||||||
|
blank.append(nodes.emphasis(text="Status"))
|
||||||
|
header.append(blank)
|
||||||
|
summary_head.append(header)
|
||||||
|
|
||||||
|
# then one column for each backend driver
|
||||||
|
impls = matrix.targets.keys()
|
||||||
|
impls.sort()
|
||||||
|
for key in impls:
|
||||||
|
target = matrix.targets[key]
|
||||||
|
implcol = nodes.entry()
|
||||||
|
header.append(implcol)
|
||||||
|
implcol.append(nodes.strong(text=target.title))
|
||||||
|
|
||||||
|
# We now produce the body of the table, one row for
|
||||||
|
# each feature to report on
|
||||||
|
for feature in matrix.features:
|
||||||
|
item = nodes.row()
|
||||||
|
|
||||||
|
# the hyperlink target name linking to details
|
||||||
|
feature_id = re.sub(RE_PATTERN, "_", feature.key)
|
||||||
|
|
||||||
|
# first the fixed columns for title/status
|
||||||
|
key_col = nodes.entry()
|
||||||
|
item.append(key_col)
|
||||||
|
key_ref = nodes.reference(refid=feature_id)
|
||||||
|
key_txt = nodes.inline()
|
||||||
|
key_col.append(key_txt)
|
||||||
|
key_txt.append(key_ref)
|
||||||
|
key_ref.append(nodes.strong(text=feature.title))
|
||||||
|
|
||||||
|
status_col = nodes.entry()
|
||||||
|
item.append(status_col)
|
||||||
|
status_col.append(nodes.inline(
|
||||||
|
text=feature.status,
|
||||||
|
classes=["sp_feature_" + feature.status]))
|
||||||
|
|
||||||
|
# and then one column for each backend driver
|
||||||
|
impls = matrix.targets.keys()
|
||||||
|
impls.sort()
|
||||||
|
for key in impls:
|
||||||
|
target = matrix.targets[key]
|
||||||
|
impl = feature.implementations[key]
|
||||||
|
impl_col = nodes.entry()
|
||||||
|
item.append(impl_col)
|
||||||
|
|
||||||
|
key_id = re.sub(RE_PATTERN, "_",
|
||||||
|
"{}_{}".format(feature.key, key))
|
||||||
|
|
||||||
|
impl_ref = nodes.reference(refid=key_id)
|
||||||
|
impl_txt = nodes.inline()
|
||||||
|
impl_col.append(impl_txt)
|
||||||
|
impl_txt.append(impl_ref)
|
||||||
|
|
||||||
|
status = STATUS_DICT.get(impl.status, "")
|
||||||
|
|
||||||
|
impl_ref.append(nodes.literal(
|
||||||
|
text=status,
|
||||||
|
classes=["sp_impl_summary", "sp_impl_" + impl.status]))
|
||||||
|
|
||||||
|
summary_body.append(item)
|
||||||
|
|
||||||
|
def _build_details(self, matrix, content):
|
||||||
|
"""Constructs the docutils content for the details of
|
||||||
|
the support matrix.
|
||||||
|
"""
|
||||||
|
|
||||||
|
details_title = nodes.subtitle(text="Details")
|
||||||
|
details = nodes.bullet_list()
|
||||||
|
|
||||||
|
content.append(details_title)
|
||||||
|
content.append(details)
|
||||||
|
|
||||||
|
# One list entry for each feature we're reporting on
|
||||||
|
for feature in matrix.features:
|
||||||
|
item = nodes.list_item()
|
||||||
|
|
||||||
|
status = feature.status
|
||||||
|
if feature.group is not None:
|
||||||
|
status += "({})".format(feature.group)
|
||||||
|
|
||||||
|
feature_id = re.sub(RE_PATTERN, "_", feature.key)
|
||||||
|
|
||||||
|
# Highlight the feature title name
|
||||||
|
item.append(nodes.strong(text=feature.title, ids=[feature_id]))
|
||||||
|
|
||||||
|
# Add maturity status
|
||||||
|
para = nodes.paragraph()
|
||||||
|
para.append(nodes.strong(text="Status: {} ".format(status)))
|
||||||
|
item.append(para)
|
||||||
|
|
||||||
|
# If API Alias exists add it
|
||||||
|
if feature.api is not None:
|
||||||
|
para = nodes.paragraph()
|
||||||
|
para.append(
|
||||||
|
nodes.strong(text="API Alias: {} ".format(feature.api)))
|
||||||
|
item.append(para)
|
||||||
|
|
||||||
|
if feature.cli:
|
||||||
|
item.append(self._create_cli_paragraph(feature))
|
||||||
|
|
||||||
|
if feature.notes is not None:
|
||||||
|
item.append(self._create_notes_paragraph(feature.notes))
|
||||||
|
|
||||||
|
para_divers = nodes.paragraph()
|
||||||
|
para_divers.append(nodes.strong(text="Driver Support:"))
|
||||||
|
# A sub-list giving details of each backend driver target
|
||||||
|
impls = nodes.bullet_list()
|
||||||
|
for key in feature.implementations:
|
||||||
|
target = matrix.targets[key]
|
||||||
|
impl = feature.implementations[key]
|
||||||
|
subitem = nodes.list_item()
|
||||||
|
|
||||||
|
key_id = re.sub(RE_PATTERN, "_",
|
||||||
|
"{}_{}".format(feature.key, key))
|
||||||
|
|
||||||
|
subitem += [
|
||||||
|
nodes.strong(text="{}: ".format(target.title)),
|
||||||
|
nodes.literal(text=impl.status,
|
||||||
|
classes=["sp_impl_{}".format(impl.status)],
|
||||||
|
ids=[key_id]),
|
||||||
|
]
|
||||||
|
if impl.notes is not None:
|
||||||
|
subitem.append(self._create_notes_paragraph(impl.notes))
|
||||||
|
impls.append(subitem)
|
||||||
|
|
||||||
|
para_divers.append(impls)
|
||||||
|
item.append(para_divers)
|
||||||
|
details.append(item)
|
||||||
|
|
||||||
|
def _build_notes(self, content):
|
||||||
|
"""Constructs a list of notes content for the support matrix.
|
||||||
|
|
||||||
|
This is generated as a bullet list.
|
||||||
|
"""
|
||||||
|
notes_title = nodes.subtitle(text="Notes:")
|
||||||
|
notes = nodes.bullet_list()
|
||||||
|
|
||||||
|
content.append(notes_title)
|
||||||
|
content.append(notes)
|
||||||
|
|
||||||
|
for note in ["This document is a continuous work in progress"]:
|
||||||
|
item = nodes.list_item()
|
||||||
|
item.append(nodes.strong(text=note))
|
||||||
|
notes.append(item)
|
||||||
|
|
||||||
|
def _create_cli_paragraph(self, feature):
|
||||||
|
"""Create a paragraph which represents the CLI commands of the feature
|
||||||
|
|
||||||
|
The paragraph will have a bullet list of CLI commands.
|
||||||
|
"""
|
||||||
|
para = nodes.paragraph()
|
||||||
|
para.append(nodes.strong(text="CLI commands:"))
|
||||||
|
commands = nodes.bullet_list()
|
||||||
|
for c in feature.cli.split(";"):
|
||||||
|
cli_command = nodes.list_item()
|
||||||
|
cli_command += nodes.literal(text=c, classes=["sp_cli"])
|
||||||
|
commands.append(cli_command)
|
||||||
|
para.append(commands)
|
||||||
|
return para
|
||||||
|
|
||||||
|
def _create_notes_paragraph(self, notes):
|
||||||
|
"""Constructs a paragraph which represents the implementation notes
|
||||||
|
|
||||||
|
The paragraph consists of text and clickable URL nodes if links were
|
||||||
|
given in the notes.
|
||||||
|
"""
|
||||||
|
para = nodes.paragraph()
|
||||||
|
para.append(nodes.strong(text="Notes: "))
|
||||||
|
# links could start with http:// or https://
|
||||||
|
link_idxs = [m.start() for m in re.finditer('https?://', notes)]
|
||||||
|
start_idx = 0
|
||||||
|
for link_idx in link_idxs:
|
||||||
|
# assume the notes start with text (could be empty)
|
||||||
|
para.append(nodes.inline(text=notes[start_idx:link_idx]))
|
||||||
|
# create a URL node until the next text or the end of the notes
|
||||||
|
link_end_idx = notes.find(" ", link_idx)
|
||||||
|
if link_end_idx == -1:
|
||||||
|
# In case the notes end with a link without a blank
|
||||||
|
link_end_idx = len(notes)
|
||||||
|
uri = notes[link_idx:link_end_idx + 1]
|
||||||
|
para.append(nodes.reference("", uri, refuri=uri))
|
||||||
|
start_idx = link_end_idx + 1
|
||||||
|
|
||||||
|
# get all text after the last link (could be empty) or all of the
|
||||||
|
# text if no link was given
|
||||||
|
para.append(nodes.inline(text=notes[start_idx:]))
|
||||||
|
return para
|
||||||
|
|
||||||
|
|
||||||
|
def setup(app):
|
||||||
|
app.add_directive('support_matrix', SupportMatrixDirective)
|
||||||
|
app.add_stylesheet('support_matrix.css')
|
@ -0,0 +1,90 @@
|
|||||||
|
============
|
||||||
|
Introduction
|
||||||
|
============
|
||||||
|
|
||||||
|
This document describes how features are listed in
|
||||||
|
:doc:`general_feature_support_matrix` and :doc:`provider_network_support_matrix`.
|
||||||
|
|
||||||
|
Goals
|
||||||
|
~~~~~
|
||||||
|
|
||||||
|
The object of this document is to inform users whether or not
|
||||||
|
features are complete, well-documented, stable, and tested.
|
||||||
|
This approach ensures a good user-experience for those well-maintained features.
|
||||||
|
|
||||||
|
.. note::
|
||||||
|
|
||||||
|
Tests are specific to particular combinations of technologies.
|
||||||
|
The plugins chosen for deployment make a big difference to whether
|
||||||
|
or not features will work.
|
||||||
|
|
||||||
|
|
||||||
|
Concepts
|
||||||
|
~~~~~~~~
|
||||||
|
|
||||||
|
These definitions clarify the terminology used throughout this document.
|
||||||
|
|
||||||
|
Feature status
|
||||||
|
~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
* Immature
|
||||||
|
* Mature
|
||||||
|
* Required
|
||||||
|
* Deprecated (scheduled to be removed in a future release)
|
||||||
|
|
||||||
|
Immature
|
||||||
|
--------
|
||||||
|
|
||||||
|
Immature features do not have enough functionality to satisfy real-world
|
||||||
|
use cases.
|
||||||
|
|
||||||
|
An immature feature is a feature being actively developed, which is only
|
||||||
|
partially functional and upstream tested, most likely introduced in a
|
||||||
|
recent release, and that will take time to mature thanks to feedback
|
||||||
|
from downstream QA.
|
||||||
|
|
||||||
|
Users of these features will likely identify gaps and/or defects
|
||||||
|
that were not identified during specification and code review.
|
||||||
|
|
||||||
|
Mature
|
||||||
|
------
|
||||||
|
|
||||||
|
A feature is considered mature if it satisfies the following criteria:
|
||||||
|
|
||||||
|
* Complete API documentation including concept and REST call definition.
|
||||||
|
* Complete Administrator documentation.
|
||||||
|
* Tempest tests that define the correct functionality of the feature.
|
||||||
|
* Enough functionality and reliability to be useful in real-world scenarios.
|
||||||
|
* Low probability of support for the feature being dropped.
|
||||||
|
|
||||||
|
Required
|
||||||
|
--------
|
||||||
|
|
||||||
|
Required features are core networking principles that have been thoroughly
|
||||||
|
tested and have been implemented in real-world use cases.
|
||||||
|
|
||||||
|
In addition they satisfy the same criteria for any mature features.
|
||||||
|
|
||||||
|
.. note::
|
||||||
|
|
||||||
|
Any new drivers must prove that they support all required features
|
||||||
|
before they are merged into neutron.
|
||||||
|
|
||||||
|
|
||||||
|
Deprecated
|
||||||
|
----------
|
||||||
|
|
||||||
|
Deprecated features are no longer supported and only security related fixes
|
||||||
|
or development will happen towards them.
|
||||||
|
|
||||||
|
Deployment rating of features
|
||||||
|
-----------------------------
|
||||||
|
|
||||||
|
The deployment rating shows only the state of the tests for each
|
||||||
|
feature on a particular deployment.
|
||||||
|
|
||||||
|
.. important::
|
||||||
|
|
||||||
|
Despite the obvious parallels that could be drawn, this list is
|
||||||
|
unrelated to the DefCore effort.
|
||||||
|
See `InteropWG <https://wiki.openstack.org/wiki/Governance/InteropWG>`_
|
@ -0,0 +1,190 @@
|
|||||||
|
# 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.
|
||||||
|
|
||||||
|
[targets]
|
||||||
|
networking-ovs=Open vSwitch
|
||||||
|
networking-linux-bridge=Linux Bridge
|
||||||
|
networking-odl=Networking ODL
|
||||||
|
networking-midonet=Networking MidoNet
|
||||||
|
networking-ovn=Networking OVN
|
||||||
|
|
||||||
|
[operation.Networks]
|
||||||
|
title=Networks
|
||||||
|
status=required
|
||||||
|
api=core
|
||||||
|
cli=openstack network *
|
||||||
|
notes=The ability to create, modify and delete networks.
|
||||||
|
Other OpenStack Client commands are create, delete, list,
|
||||||
|
segment list, segment show, set, show.
|
||||||
|
networking-ovs=complete
|
||||||
|
networking-linux-bridge=complete
|
||||||
|
networking-odl=complete
|
||||||
|
networking-midonet=complete
|
||||||
|
networking-ovn=complete
|
||||||
|
|
||||||
|
[operation.Subnets]
|
||||||
|
title=Subnets
|
||||||
|
status=required
|
||||||
|
api=core
|
||||||
|
cli=openstack subnet *
|
||||||
|
notes=The ability to create and manipulate subnets and subnet pools.
|
||||||
|
Other OpenStack Client commands are create, delete, list,
|
||||||
|
pool create, pool delete, pool list, pool set, pool show,
|
||||||
|
set, show.
|
||||||
|
networking-ovs=complete
|
||||||
|
networking-linux-bridge=complete
|
||||||
|
networking-odl=complete
|
||||||
|
networking-midonet=complete
|
||||||
|
networking-ovn=complete
|
||||||
|
|
||||||
|
[operation.Ports]
|
||||||
|
title=Ports
|
||||||
|
status=required
|
||||||
|
api=core
|
||||||
|
cli=openstack port *
|
||||||
|
notes=The ability to create and manipulate ports.
|
||||||
|
Other OpenStack Client commands are create, delete, list, set,
|
||||||
|
show.
|
||||||
|
networking-ovs=complete
|
||||||
|
networking-linux-bridge=complete
|
||||||
|
networking-odl=complete
|
||||||
|
networking-midonet=complete
|
||||||
|
networking-ovn=complete
|
||||||
|
|
||||||
|
[operation.Router]
|
||||||
|
title=Routers
|
||||||
|
status=required
|
||||||
|
api=router
|
||||||
|
cli=openstack router *
|
||||||
|
notes=The ability to create and manipulate routers.
|
||||||
|
Other OpenStack Client commands are create, add port,
|
||||||
|
add subnet, delete, list, remove port, remove subnet,
|
||||||
|
set, show.
|
||||||
|
networking-ovs=complete
|
||||||
|
networking-linux-bridge=complete
|
||||||
|
networking-odl=complete
|
||||||
|
networking-midonet=complete
|
||||||
|
networking-ovn=complete
|
||||||
|
|
||||||
|
[operation.Security_Groups]
|
||||||
|
title=Security Groups
|
||||||
|
status=mature
|
||||||
|
api=security-group
|
||||||
|
cli=openstack security group *
|
||||||
|
notes=Security groups are set by default, and can be modified to control
|
||||||
|
ingress & egress traffic.
|
||||||
|
Other OpenStack Client commands are create, delete, list, rule create,
|
||||||
|
rule delete, rule list, rule show, set, show.
|
||||||
|
networking-ovs=complete
|
||||||
|
networking-linux-bridge=complete
|
||||||
|
networking-odl=complete
|
||||||
|
networking-midonet=complete
|
||||||
|
networking-ovn=complete
|
||||||
|
|
||||||
|
[operation.External_Nets]
|
||||||
|
title=External Networks
|
||||||
|
status=mature
|
||||||
|
api=external-net
|
||||||
|
notes=The ability to create an external network to provide internet access
|
||||||
|
to and from instances using floating IP addresses and security group rules.
|
||||||
|
networking-ovs=complete
|
||||||
|
networking-linux-bridge=complete
|
||||||
|
networking-odl=complete
|
||||||
|
networking-midonet=complete
|
||||||
|
networking-ovn=complete
|
||||||
|
|
||||||
|
[operation.DVR]
|
||||||
|
title=Distributed Virtual Routers
|
||||||
|
status=immature
|
||||||
|
api=dvr
|
||||||
|
notes=The ability to support the distributed virtual routers.
|
||||||
|
networking-ovs=complete
|
||||||
|
networking-linux-bridge=incomplete
|
||||||
|
networking-odl=partial
|
||||||
|
networking-midonet=complete
|
||||||
|
networking-ovn=partial
|
||||||
|
|
||||||
|
[operation.L3_HA]
|
||||||
|
title=L3 High Availability
|
||||||
|
status=immature
|
||||||
|
api=l3-ha
|
||||||
|
notes=The ability to support the High Availability features and extensions.
|
||||||
|
https://wiki.openstack.org/wiki/Neutron/L3_High_Availability_VRRP.
|
||||||
|
networking-ovs=complete
|
||||||
|
networking-linux-bridge=complete
|
||||||
|
networking-odl=partial
|
||||||
|
networking-midonet=incomplete
|
||||||
|
networking-ovn=partial
|
||||||
|
|
||||||
|
[operation.QoS]
|
||||||
|
title=Quality of Service
|
||||||
|
status=mature
|
||||||
|
api=qos
|
||||||
|
notes=Support for Neutron Quality of Service policies and API.
|
||||||
|
networking-ovs=complete
|
||||||
|
networking-linux-bridge=partial
|
||||||
|
networking-odl=partial
|
||||||
|
networking-midonet=complete
|
||||||
|
networking-ovn=complete
|
||||||
|
|
||||||
|
[operation.BGP]
|
||||||
|
title=Border Gateway Protocol
|
||||||
|
status=immature
|
||||||
|
networking-ovs=complete
|
||||||
|
networking-linux-bridge=unknown
|
||||||
|
networking-odl=unknown
|
||||||
|
networking-midonet=complete
|
||||||
|
networking-ovn=unknown
|
||||||
|
|
||||||
|
[operation.DNS]
|
||||||
|
title=DNS
|
||||||
|
status=mature
|
||||||
|
api=dns-integration
|
||||||
|
notes=The ability to integrate with an external DNS
|
||||||
|
as a Service. http://docs.openstack.org/newton/
|
||||||
|
networking-guide/config-dns-int.html
|
||||||
|
networking-ovs=complete
|
||||||
|
networking-linux-bridge=complete
|
||||||
|
networking-odl=complete
|
||||||
|
networking-midonet=incomplete
|
||||||
|
networking-ovn=complete
|
||||||
|
|
||||||
|
[operation.Trunk_Ports]
|
||||||
|
title=Trunk Ports
|
||||||
|
status=mature
|
||||||
|
api=trunk
|
||||||
|
networking-ovs=complete
|
||||||
|
networking-linux-bridge=complete
|
||||||
|
networking-odl=incomplete
|
||||||
|
networking-midonet=incomplete
|
||||||
|
networking-ovn=complete
|
||||||
|
|
||||||
|
[operation.Metering]
|
||||||
|
title=Metering
|
||||||
|
status=mature
|
||||||
|
api=metering
|
||||||
|
networking-ovs=complete
|
||||||
|
networking-linux-bridge=complete
|
||||||
|
networking-odl=incomplete
|
||||||
|
networking-midonet=incomplete
|
||||||
|
networking-ovn=unknown
|
||||||
|
|
||||||
|
[operations.Routed_Provider_Networks]
|
||||||
|
title=Routed Provider Networks
|
||||||
|
status=immature
|
||||||
|
notes=The ability to present a multi-segment layer-3
|
||||||
|
network as a single entity
|
||||||
|
networking-ovs=partial
|
||||||
|
networking-linux-bridge=partial
|
||||||
|
networking-odl=incomplete
|
||||||
|
networking-midonet=incomplete
|
||||||
|
networking-ovn=partial
|
@ -0,0 +1,32 @@
|
|||||||
|
=======================
|
||||||
|
General Feature Support
|
||||||
|
=======================
|
||||||
|
|
||||||
|
.. warning::
|
||||||
|
Please note, while this document is still being maintained, this is slowly
|
||||||
|
being updated to re-group and classify features using the definitions
|
||||||
|
described in here: :doc:`feature_classification_introduction`.
|
||||||
|
|
||||||
|
This document covers the maturity and support of the Neutron API
|
||||||
|
and its API extensions. Details about the API can be found at
|
||||||
|
`Networking API v2.0 <http://developer.openstack.org/api-ref/networking/v2/>`_.
|
||||||
|
|
||||||
|
When considering which capabilities should be marked as mature the
|
||||||
|
following general guiding principles were applied:
|
||||||
|
|
||||||
|
* **Inclusivity** - people have shown ability to make effective
|
||||||
|
use of a wide range of network plugins and drivers with broadly
|
||||||
|
varying feature sets. Aiming to keep the requirements as inclusive
|
||||||
|
as possible, avoids second-guessing how a user wants to use their
|
||||||
|
networks.
|
||||||
|
|
||||||
|
* **Bootstrapping** - a practical use case test is to consider that
|
||||||
|
starting point for the network deploy is an empty data center
|
||||||
|
with new machines and network connectivity. Then look at what
|
||||||
|
are the minimum features required of the network service, in order
|
||||||
|
to get user instances running and connected over the network.
|
||||||
|
|
||||||
|
* **Reality** - there are many networking drivers and plugins compatible with
|
||||||
|
neutron. Each with their own supported feature set.
|
||||||
|
|
||||||
|
.. support_matrix:: general_feature_support_matrix.ini
|
43
doc/source/feature_classification/index.rst
Normal file
43
doc/source/feature_classification/index.rst
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
..
|
||||||
|
Copyright 2010-2011 United States Government as represented by the
|
||||||
|
Administrator of the National Aeronautics and Space Administration.
|
||||||
|
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.
|
||||||
|
|
||||||
|
Convention for heading levels in Neutron devref:
|
||||||
|
======= Heading 0 (reserved for the title in a document)
|
||||||
|
------- Heading 1
|
||||||
|
~~~~~~~ Heading 2
|
||||||
|
+++++++ Heading 3
|
||||||
|
''''''' Heading 4
|
||||||
|
(Avoid deeper levels because they do not render well.)
|
||||||
|
|
||||||
|
|
||||||
|
Neutron Feature Classification
|
||||||
|
==============================
|
||||||
|
|
||||||
|
.. toctree::
|
||||||
|
:maxdepth: 3
|
||||||
|
|
||||||
|
feature_classification_introduction
|
||||||
|
general_feature_support_matrix
|
||||||
|
provider_network_support_matrix
|
||||||
|
|
||||||
|
|
||||||
|
Indices and tables
|
||||||
|
------------------
|
||||||
|
|
||||||
|
* :ref:`genindex`
|
||||||
|
* :ref:`modindex`
|
||||||
|
* :ref:`search`
|
@ -0,0 +1,54 @@
|
|||||||
|
# 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.
|
||||||
|
|
||||||
|
[targets]
|
||||||
|
networking-ovs=Open vSwitch
|
||||||
|
networking-linux-bridge=Linux Bridge
|
||||||
|
networking-odl=Networking ODL
|
||||||
|
networking-midonet=Networking MidoNet
|
||||||
|
networking-ovn=Networking OVN
|
||||||
|
|
||||||
|
[operation.VLAN]
|
||||||
|
title=VLAN provider network support
|
||||||
|
status=mature
|
||||||
|
networking-ovs=complete
|
||||||
|
networking-linux-bridge=complete
|
||||||
|
networking-odl=unknown
|
||||||
|
networking-midonet=incomplete
|
||||||
|
networking-ovn=complete
|
||||||
|
|
||||||
|
[operation.VXLAN]
|
||||||
|
title=VXLAN provider network support
|
||||||
|
status=mature
|
||||||
|
networking-ovs=complete
|
||||||
|
networking-linux-bridge=complete
|
||||||
|
networking-odl=complete
|
||||||
|
networking-midonet=incomplete
|
||||||
|
networking-ovn=incomplete
|
||||||
|
|
||||||
|
[operation.GRE]
|
||||||
|
title=GRE provider network support
|
||||||
|
status=immature
|
||||||
|
networking-ovs=complete
|
||||||
|
networking-linux-bridge=unknown
|
||||||
|
networking-odl=complete
|
||||||
|
networking-midonet=incomplete
|
||||||
|
networking-ovn=incomplete
|
||||||
|
|
||||||
|
[operation.Geneve]
|
||||||
|
title=Geneve provider network support
|
||||||
|
status=immature
|
||||||
|
networking-ovs=complete
|
||||||
|
networking-linux-bridge=unknown
|
||||||
|
networking-odl=incomplete
|
||||||
|
networking-midonet=incomplete
|
||||||
|
networking-ovn=complete
|
@ -0,0 +1,31 @@
|
|||||||
|
========================
|
||||||
|
Provider Network Support
|
||||||
|
========================
|
||||||
|
|
||||||
|
.. warning::
|
||||||
|
Please note, while this document is still being maintained, this is slowly
|
||||||
|
being updated to re-group and classify features using the definitions
|
||||||
|
described in here: :doc:`feature_classification_introduction`.
|
||||||
|
|
||||||
|
This document covers the maturity and support for various
|
||||||
|
network isolation technologies.
|
||||||
|
|
||||||
|
When considering which capabilities should be marked as mature the
|
||||||
|
following general guiding principles were applied:
|
||||||
|
|
||||||
|
* **Inclusivity** - people have shown ability to make effective
|
||||||
|
use of a wide range of network plugins and drivers with broadly
|
||||||
|
varying feature sets. Aiming to keep the requirements as inclusive
|
||||||
|
as possible, avoids second-guessing how a user wants to use their
|
||||||
|
networks.
|
||||||
|
|
||||||
|
* **Bootstrapping** - a practical use case test is to consider that
|
||||||
|
starting point for the network deploy is an empty data center
|
||||||
|
with new machines and network connectivity. Then look at what
|
||||||
|
are the minimum features required of the network service, in order
|
||||||
|
to get user instances running and connected over the network.
|
||||||
|
|
||||||
|
* **Reality** - there are many networking drivers and plugins compatible with
|
||||||
|
neutron. Each with their own supported feature set.
|
||||||
|
|
||||||
|
.. support_matrix:: provider_network_support_matrix.ini
|
@ -55,6 +55,14 @@ Neutron Stadium
|
|||||||
|
|
||||||
stadium/index
|
stadium/index
|
||||||
|
|
||||||
|
Neutron Feature Classification
|
||||||
|
==============================
|
||||||
|
|
||||||
|
.. toctree::
|
||||||
|
:maxdepth: 3
|
||||||
|
|
||||||
|
feature_classification/index
|
||||||
|
|
||||||
Developer Docs
|
Developer Docs
|
||||||
==============
|
==============
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user