ac94864869
for convenience of api consumers, allows both of of-config style element names (eg. logical-switches) and python style attribute names (eg. logical_switches). Signed-off-by: YAMAMOTO Takashi <yamamoto@valinux.co.jp> Signed-off-by: FUJITA Tomonori <fujita.tomonori@lab.ntt.co.jp>
156 lines
4.2 KiB
Python
156 lines
4.2 KiB
Python
# Copyright (C) 2013 Nippon Telegraph and Telephone Corporation.
|
|
# Copyright (C) 2013 YAMAMOTO Takashi <yamamoto at valinux co jp>
|
|
#
|
|
# 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.
|
|
|
|
# convenient classes to manipulate OF-Config XML
|
|
# in a little more pythonic way.
|
|
# currently assuming OF-Config 1.1.1.
|
|
|
|
from ryu.lib import stringify
|
|
|
|
from lxml import objectify
|
|
import lxml.etree as ET
|
|
|
|
|
|
_ns_of111 = 'urn:onf:of111:config:yang'
|
|
_ns_netconf = 'urn:ietf:params:xml:ns:netconf:base:1.0'
|
|
_nsmap = {
|
|
'of111': _ns_of111,
|
|
'nc': _ns_netconf,
|
|
}
|
|
|
|
|
|
def _pythonify(name):
|
|
return name.replace('-', '_')
|
|
|
|
|
|
class _e(object):
|
|
def __init__(self, name, is_list):
|
|
self.name = name
|
|
self.cls = None
|
|
self.is_list = is_list
|
|
|
|
|
|
# complexType
|
|
class _ct(_e):
|
|
def __init__(self, name, cls, is_list):
|
|
super(_ct, self).__init__(name, is_list)
|
|
self.cls = cls
|
|
|
|
|
|
class _Base(stringify.StringifyMixin):
|
|
_M = objectify.ElementMaker(annotate=False,
|
|
namespace=_ns_of111,
|
|
nsmap=_nsmap)
|
|
|
|
def __init__(self, **kwargs):
|
|
for e in self._ELEMENTS:
|
|
k = _pythonify(e.name)
|
|
try:
|
|
v = kwargs.pop(k)
|
|
assert not e.name in kwargs
|
|
except KeyError:
|
|
k = e.name
|
|
try:
|
|
v = kwargs.pop(k)
|
|
except KeyError:
|
|
if e.is_list:
|
|
v = []
|
|
else:
|
|
v = None
|
|
setattr(self, k, v)
|
|
if kwargs:
|
|
raise TypeError('unknown kwargs %s' % kwargs)
|
|
|
|
def to_et(self, tag):
|
|
def convert(v):
|
|
if isinstance(v, _Base):
|
|
return v.to_et(e.name)
|
|
elif isinstance(v, objectify.ObjectifiedElement):
|
|
assert ET.QName(v.tag).localname == itag
|
|
return v
|
|
return self._M(itag, v)
|
|
|
|
args = []
|
|
for e in self._ELEMENTS:
|
|
itag = e.name
|
|
k = _pythonify(itag)
|
|
v = getattr(self, k)
|
|
if v is None:
|
|
continue
|
|
if isinstance(v, list):
|
|
assert e.is_list
|
|
ele = map(convert, v)
|
|
else:
|
|
assert not e.is_list
|
|
ele = [convert(v)]
|
|
args.extend(ele)
|
|
return self._M(tag, *args)
|
|
|
|
def to_xml(self, tag):
|
|
e = self.to_et(tag)
|
|
return ET.tostring(e, pretty_print=True)
|
|
|
|
@classmethod
|
|
def from_xml(cls, xmlstring):
|
|
et = objectify.fromstring(xmlstring)
|
|
return cls.from_et(et)
|
|
|
|
@classmethod
|
|
def from_et(cls, et):
|
|
def convert(v):
|
|
if not e.cls is None:
|
|
return e.cls.from_et(v)
|
|
return v
|
|
|
|
kwargs = {}
|
|
for e in cls._ELEMENTS:
|
|
try:
|
|
v = et[e.name]
|
|
except AttributeError:
|
|
continue
|
|
assert isinstance(v, objectify.ObjectifiedElement)
|
|
if len(v) == 1:
|
|
v = convert(v)
|
|
if e.is_list:
|
|
v = [v]
|
|
else:
|
|
assert e.is_list
|
|
v = map(convert, v)
|
|
k = _pythonify(e.name)
|
|
assert not k in kwargs
|
|
kwargs[k] = v
|
|
return cls(**kwargs)
|
|
|
|
def __getattribute__(self, k):
|
|
return stringify.StringifyMixin.__getattribute__(self, _pythonify(k))
|
|
|
|
def __setattr__(self, k, v):
|
|
stringify.StringifyMixin.__setattr__(self, _pythonify(k), v)
|
|
|
|
|
|
class _Unimpl(_Base):
|
|
_ELEMENTS = [
|
|
_e('raw_et', is_list=False),
|
|
]
|
|
|
|
def to_et(self, tag):
|
|
assert self.raw_et.tag == tag
|
|
return self.raw_et
|
|
|
|
@classmethod
|
|
def from_et(cls, et):
|
|
return cls(raw_et=et)
|