Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for json2xml lookup plugin #5

Merged
merged 2 commits into from
Aug 24, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
122 changes: 122 additions & 0 deletions plugins/lookup/json2xml.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
# (c) 2020 Red Hat, Inc.
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
#
# You should have received a copy of the GNU General Public License
# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
from __future__ import absolute_import, division, print_function

__metaclass__ = type

DOCUMENTATION = """
lookup: json2xml
author: Ganesh Nalawade (@ganeshrn)
short_description: Validates json configuration against yang data model and convert it to xml.
description:
- This plugin lookups the input json configuration, validates it against the respective yang data
model which is also given as input to this plugin and coverts it to xml format which can be used
as payload within Netconf rpc.
options:
_terms:
description:
- Input json configuration file path that adheres to a particular yang model.
required: True
type: path
doctype:
description:
- Specifies the target root node of the generated xml. The default value is C(config)
default: config
yang_file:
description:
- Path to yang model file against which the json configuration is validated and
converted to xml.
required: True
type: path
search_path:
description:
- This option is a colon C(:) separated list of directories to search for imported yang modules
in the yang file mentioned in C(path) option. If the value is not given it will search in
the current directory.
required: false
keep_tmp_files:
description:
- This is a boolean flag to indicate if the intermediate files generated while validation json
configuration should be kept or deleted. If the value is C(true) the files will not be deleted else by
default all the intermediate files will be deleted irrespective of whether task run is
successful or not. The intermediate files are stored in path C(~/.ansible/tmp/json2xml), this
option is mainly used for debugging purpose.
default: False
type: bool
"""

EXAMPLES = """
- name: translate json to xml
debug: msg="{{ lookup('yang_json2xml', config_json,
yang_file='openconfig/public/release/models/interfaces/openconfig-interfaces.yang',
search_path='openconfig/public/release/models:pyang/modules/') }}"
"""

RETURN = """
_raw:
description: The translated xml string from json
"""

import os
import json

from ansible.plugins.lookup import LookupBase
from ansible.module_utils._text import to_text
from ansible.errors import AnsibleError

from ansible_collections.community.yang.plugins.module_utils.translator import (
Translator,
)

try:
import pyang # noqa
except ImportError:
raise AnsibleError("pyang is not installed")

try:
from __main__ import display
except ImportError:
from ansible.utils.display import Display

display = Display()


class LookupModule(LookupBase):
def run(self, terms, variables, **kwargs):

res = []
try:
json_config = terms[0]
except IndexError:
raise AnsibleError("path to json file must be specified")

try:
yang_file = kwargs["yang_file"]
except KeyError:
raise AnsibleError("value of 'yang_file' must be specified")

search_path = kwargs.pop("search_path", "")
keep_tmp_files = kwargs.pop("keep_tmp_files", False)

json_config = os.path.realpath(os.path.expanduser(json_config))
try:
# validate json
with open(json_config) as fp:
json.load(fp)
except Exception as exc:
raise AnsibleError(
"Failed to load json configuration: %s"
% (to_text(exc, errors="surrogate_or_strict"))
)

doctype = kwargs.get("doctype", "config")

tl = Translator(yang_file, search_path, doctype, keep_tmp_files)

xml_data = tl.json_to_xml(json_config)
res.append(xml_data)

return res
84 changes: 84 additions & 0 deletions plugins/module_utils/files/yang/ietf-yang-metadata.yang
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
module ietf-yang-metadata {

namespace "urn:ietf:params:xml:ns:yang:ietf-yang-metadata";

prefix "md";

organization
"IETF NETMOD (NETCONF Data Modeling Language) Working Group";

contact
"WG Web: <https://datatracker.ietf.org/wg/netmod/>

WG List: <mailto:[email protected]>

WG Chair: Lou Berger
<mailto:[email protected]>

WG Chair: Kent Watsen
<mailto:[email protected]>

Editor: Ladislav Lhotka
<mailto:[email protected]>";

description
"This YANG module defines an 'extension' statement that allows
for defining metadata annotations.

Copyright (c) 2016 IETF Trust and the persons identified as
authors of the code. All rights reserved.

Redistribution and use in source and binary forms, with or
without modification, is permitted pursuant to, and subject to
the license terms contained in, the Simplified BSD License set
forth in Section 4.c of the IETF Trust's Legal Provisions
Relating to IETF Documents
(http://trustee.ietf.org/license-info).

This version of this YANG module is part of RFC 7952
(http://www.rfc-editor.org/info/rfc7952); see the RFC itself
for full legal notices.";
revision 2016-08-05 {
description
"Initial revision.";
reference
"RFC 7952: Defining and Using Metadata with YANG";
}

extension annotation {
argument name;
description
"This extension allows for defining metadata annotations in
YANG modules. The 'md:annotation' statement can appear only
at the top level of a YANG module or submodule, i.e., it
becomes a new alternative in the ABNF production rule for
'body-stmts' (Section 14 in RFC 7950).

The argument of the 'md:annotation' statement defines the name
of the annotation. Syntactically, it is a YANG identifier as
defined in Section 6.2 of RFC 7950.

An annotation defined with this 'extension' statement inherits
the namespace and other context from the YANG module in which
it is defined.

The data type of the annotation value is specified in the same
way as for a leaf data node using the 'type' statement.

The semantics of the annotation and other documentation can be
specified using the following standard YANG substatements (all
are optional): 'description', 'if-feature', 'reference',
'status', and 'units'.

A server announces support for a particular annotation by
including the module in which the annotation is defined among
the advertised YANG modules, e.g., in a NETCONF <hello>
message or in the YANG library (RFC 7950). The annotation can
then be attached to any instance of a data node defined in any
YANG module that is advertised by the server.

XML encoding and JSON encoding of annotations are defined in
RFC 7952.";
}
}

13 changes: 13 additions & 0 deletions plugins/module_utils/files/yang/nc-op.yang
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
module nc-op {
namespace "https://github.com/ansible-network/yang/nc-op";
prefix "nc-op";
import ietf-yang-metadata {
prefix "md";
}
md:annotation operation {
type string;
description
"annotations for netconf edit-config operation.";
}
description "NETCONF 'operation' attribute values";
}
Loading