Skip to content

Commit

Permalink
Add role schema.
Browse files Browse the repository at this point in the history
  • Loading branch information
felixfontein committed Jun 1, 2021
1 parent 34a9757 commit 21c5f5b
Show file tree
Hide file tree
Showing 6 changed files with 254 additions and 1 deletion.
8 changes: 7 additions & 1 deletion antsibull/cli/doc_commands/stable.py
Original file line number Diff line number Diff line change
Expand Up @@ -117,8 +117,14 @@ def normalize_plugin_info(plugin_type: str,
in :mod:`antsibull.schemas`. The nonfatal errors are strings representing the problems
encountered.
"""
new_info = {}
errors = []
if plugin_type == 'role':
try:
return DOCS_SCHEMAS[plugin_type].parse_obj(plugin_info).dict(by_alias=True), errors
except ValidationError as e:
raise ValueError(str(e))

new_info = {}
# Note: loop through "doc" before any other keys.
for field in ('doc', 'examples', 'return'):
try:
Expand Down
15 changes: 15 additions & 0 deletions antsibull/schemas/ansible_doc.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
from .callback import CallbackSchema
from .module import ModuleSchema
from .plugin import PluginSchema
from .role import RoleSchema


class AnsibleDocSchema(BaseModel):
Expand Down Expand Up @@ -54,6 +55,7 @@ class AnsibleDocSchema(BaseModel):
shell: t.Dict[str, PluginSchema]
strategy: t.Dict[str, PluginSchema]
vars: t.Dict[str, PluginSchema]
role: t.Dict[str, RoleSchema]


class GenericPluginSchema(BaseModel):
Expand Down Expand Up @@ -92,6 +94,18 @@ class ModulePluginSchema(BaseModel):
__root__: t.Dict[str, ModuleSchema]


class RolePluginSchema(BaseModel):
"""
Document the output of ``ansible-doc -t role ROLE_NAME``.
.. note:: Both the model and the dict will be wrapped in an outer dict with your data mapped
to the ``__root__`` key. This happens because the toplevel key of ansible-doc's output is
a dynamic key which we can't automatically map to an attribute name.
"""

__root__: t.Dict[str, RoleSchema]


#: Make sure users can access plugins using the plugin type rather than having to guess that
#: these types use the GenericPluginSchema
BecomePluginSchema = GenericPluginSchema
Expand Down Expand Up @@ -120,6 +134,7 @@ class ModulePluginSchema(BaseModel):
'lookup': LookupPluginSchema,
'module': ModulePluginSchema,
'netconf': NetConfPluginSchema,
'role': RolePluginSchema,
'shell': ShellPluginSchema,
'strategy': StrategyPluginSchema,
'vars': VarsPluginSchema,
Expand Down
2 changes: 2 additions & 0 deletions antsibull/schemas/docs.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
from .module import ModuleDocSchema, ModuleSchema
from .plugin import (PluginDocSchema, PluginExamplesSchema,
PluginMetadataSchema, PluginReturnSchema, PluginSchema)
from .role import RoleSchema

BecomeSchema = PluginSchema
CacheSchema = PluginSchema
Expand Down Expand Up @@ -67,4 +68,5 @@
'shell': _PLUGIN_SCHEMA_RECORD,
'strategy': _PLUGIN_SCHEMA_RECORD,
'vars': _PLUGIN_SCHEMA_RECORD,
'role': RoleSchema,
}
60 changes: 60 additions & 0 deletions antsibull/schemas/role.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
# coding: utf-8
# Author: Toshio Kuratomi <tkuratom@redhat.com>
# Author: Felix Fontein <felix@fontein.de>
# License: GPLv3+
# Copyright: Ansible Project, 2021
"""Schemas for the role documentation data."""

# Ignore Unitialized attribute errors because BaseModel works some magic
# to initialize the attributes when data is loaded into them.
# pyre-ignore-all-errors[13]

import typing as t

import pydantic as p

from .base import (
BaseModel, DeprecationSchema, OptionsSchema,
SeeAlsoModSchema, SeeAlsoRefSchema, SeeAlsoLinkSchema,
COLLECTION_NAME_F,
)


class InnerRoleOptionsSchema(OptionsSchema):
suboptions: t.Dict[str, 'InnerRoleOptionsSchema'] = {}

@p.root_validator(pre=True)
def allow_description_to_be_optional(cls, values):
# Doing this in a validator so that the json-schema will still flag it as an error
if 'description' not in values:
values['description'] = []
return values


InnerRoleOptionsSchema.update_forward_refs()


class RoleOptionsSchema(OptionsSchema):
suboptions: t.Dict[str, 'InnerRoleOptionsSchema'] = {}


class RoleEntrypointSchema(BaseModel):
"""Documentation for role entrypoints."""
description: t.List[str]
short_description: str
author: t.List[str] = []
deprecated: DeprecationSchema = p.Field({})
notes: t.List[str] = []
requirements: t.List[str] = []
seealso: t.List[t.Union[SeeAlsoModSchema, SeeAlsoRefSchema, SeeAlsoLinkSchema]] = []
todo: t.List[str] = []
version_added: str = 'historical'

options: t.Dict[str, RoleOptionsSchema] = {}


class RoleSchema(BaseModel):
"""Documentation for roles."""
collection: str = COLLECTION_NAME_F
entry_points: t.Dict[str, RoleEntrypointSchema]
path: str
85 changes: 85 additions & 0 deletions tests/functional/schema/good_data/one_role.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
{
"felixfontein.acme.account_key_rollover": {
"collection": "felixfontein.acme",
"entry_points": {
"main": {
"author": [
"Felix Fontein (@felixfontein)"
],
"description": [
"This is a role which can use any CA supporting the ACME protocol, such as L(Let's Encrypt,https://letsencrypt.org/), L(Buypass,https://www.buypass.com/ssl/products/acme>) or L(ZeroSSL,https://zerossl.com/features/acme/>), to rekey ACME account keys.",
"This role will create a backup copy of the existing account key if requested to do so, re-create the account key, and then roll over the ACME account to the new key."
],
"options": {
"acme_certificate_account_algorithm": {
"choices": [
"rsa",
"p-256",
"p-384",
"p-521"
],
"default": "rsa",
"description": [
"The algorithm used for creating the account key.",
"The default is C(rsa) for an RSA key.",
"Other choices are C(p-256), C(p-384) or C(p-521) for the NIST elliptic curves C(prime256v1), C(secp384r1) and C(secp521r1), respectively."
],
"type": "str"
},
"acme_certificate_account_key_backup": {
"default": true,
"description": [
"Whether to create a backup of the old account key before rolling over."
],
"type": "bool"
},
"acme_certificate_account_key_length": {
"default": 4096,
"description": [
"The bit-size to use for RSA private keys.",
"Should not be less than 2048. Also values above 4096 might not be supported by every ACME CA."
],
"type": "int"
},
"acme_certificate_account_key_sops_encrypted": {
"default": false,
"description": [
"Use L(Mozilla sops,https://github.com/mozilla/sops) to encrypt private key. Needs C(.sops.yaml) file inside the directory containing the account key or somewhere up the directory chain."
],
"type": "bool"
},
"acme_certificate_acme_account": {
"description": [
"Path to the private ACME account key."
],
"type": "str"
},
"acme_certificate_acme_account_uri": {
"description": [
"Instead of determining the account URI from the account key, assumes the given account URI."
],
"type": "str"
},
"acme_certificate_acme_directory": {
"default": "https://acme-v02.api.letsencrypt.org/directory",
"description": [
"The ACME directory to use.",
"Default is C(https://acme-v02.api.letsencrypt.org/directory), which is the current production ACME v2 endpoint of Let's Encrypt."
],
"type": "str"
},
"acme_certificate_acme_version": {
"default": 2,
"description": [
"The ACME directory's version."
],
"type": "int"
}
},
"short_description": "Do account key rollover",
"version_added": "0.1.0"
}
},
"path": "/path/to/ansible_collections/felixfontein/acme"
}
}
85 changes: 85 additions & 0 deletions tests/functional/schema/good_data/one_role_results.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
{
"felixfontein.acme.account_key_rollover": {
"collection": "felixfontein.acme",
"entry_points": {
"main": {
"author": [
"Felix Fontein (@felixfontein)"
],
"description": [
"This is a role which can use any CA supporting the ACME protocol, such as L(Let's Encrypt,https://letsencrypt.org/), L(Buypass,https://www.buypass.com/ssl/products/acme>) or L(ZeroSSL,https://zerossl.com/features/acme/>), to rekey ACME account keys.",
"This role will create a backup copy of the existing account key if requested to do so, re-create the account key, and then roll over the ACME account to the new key."
],
"options": {
"acme_certificate_account_algorithm": {
"choices": [
"rsa",
"p-256",
"p-384",
"p-521"
],
"default": "rsa",
"description": [
"The algorithm used for creating the account key.",
"The default is C(rsa) for an RSA key.",
"Other choices are C(p-256), C(p-384) or C(p-521) for the NIST elliptic curves C(prime256v1), C(secp384r1) and C(secp521r1), respectively."
],
"type": "str"
},
"acme_certificate_account_key_backup": {
"default": true,
"description": [
"Whether to create a backup of the old account key before rolling over."
],
"type": "bool"
},
"acme_certificate_account_key_length": {
"default": 4096,
"description": [
"The bit-size to use for RSA private keys.",
"Should not be less than 2048. Also values above 4096 might not be supported by every ACME CA."
],
"type": "int"
},
"acme_certificate_account_key_sops_encrypted": {
"default": false,
"description": [
"Use L(Mozilla sops,https://github.com/mozilla/sops) to encrypt private key. Needs C(.sops.yaml) file inside the directory containing the account key or somewhere up the directory chain."
],
"type": "bool"
},
"acme_certificate_acme_account": {
"description": [
"Path to the private ACME account key."
],
"type": "str"
},
"acme_certificate_acme_account_uri": {
"description": [
"Instead of determining the account URI from the account key, assumes the given account URI."
],
"type": "str"
},
"acme_certificate_acme_directory": {
"default": "https://acme-v02.api.letsencrypt.org/directory",
"description": [
"The ACME directory to use.",
"Default is C(https://acme-v02.api.letsencrypt.org/directory), which is the current production ACME v2 endpoint of Let's Encrypt."
],
"type": "str"
},
"acme_certificate_acme_version": {
"default": 2,
"description": [
"The ACME directory's version."
],
"type": "int"
}
},
"short_description": "Do account key rollover",
"version_added": "0.1.0"
}
},
"path": "/path/to/ansible_collections/felixfontein/acme"
}
}

0 comments on commit 21c5f5b

Please sign in to comment.