This patch brings two new classes, which are used in PyRecipes.
LnstTask: Contains only Controller handle, same as in Task.ctl
LnstNetwork: contains methods for network definition, which are
stored in req variable and can be accessed via get_machines() method.
For more info on how to use these classes in recipes, see cover letter.
Signed-off-by: Jiri Prochazka <jprochaz(a)redhat.com>
---
lnst/Controller/PyRecipe.py | 225 ++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 225 insertions(+)
create mode 100644 lnst/Controller/PyRecipe.py
diff --git a/lnst/Controller/PyRecipe.py b/lnst/Controller/PyRecipe.py
new file mode 100644
index 0000000..4fa7880
--- /dev/null
+++ b/lnst/Controller/PyRecipe.py
@@ -0,0 +1,225 @@
+"""
+This module defines LnstTask and LnstNetwork classes which are
+parent classes for PyRecipes.
+
+Copyright 2015 Red Hat, Inc.
+Licensed under the GNU General Public License, version 2 as
+published by the Free Software Foundation; see COPYING for details.
+"""
+
+__author__ = """
+jprochaz(a)redhat.com (Jiri Prochazka)
+"""
+
+class LnstTask(object):
+ def __init__(self, ctl):
+ self.ctl = ctl
+
+class LnstNetwork(object):
+ def __init__(self):
+ self.req = {'machines' : []}
+
+ def get_machines(self):
+ return self.req['machines']
+
+ def add_host(self, id):
+ if self.id_exists(id):
+ msg = "Machine with id '%s' already exists" % id
+ raise Exception(msg)
+
+ self.req['machines'].append({'id' : id,
+ 'interfaces' : []})
+
+ return Host(self.req['machines'][-1])
+
+ def id_exists(self, id):
+ for m in self.req['machines']:
+ if id == m['id']:
+ return True
+ return False
+
+class Host(object):
+ def __init__(self, req):
+ self.req = req
+ self.id = req['id']
+
+ def add_interface(self, type, id, label=None, netns=None):
+ if type not in ['eth', 'vlan', 'team', 'bond',
'bridge', 'veth',
+ 'macvlan', 'lo', 'vti',
'ovs_bridge', 'vxlan']:
+ msg = "Unknown interface type '%s'" % type
+ raise Exception(msg)
+
+ if self.id_exists(id):
+ msg = "Machine with id '%s' already exists" % id
+ raise Exception(msg)
+
+ if label is not None and type != 'eth':
+ msg = "Attribute label can be defined only on eth interfaces"
+ raise Exception(msg)
+
+ if label is None and type == 'eth':
+ msg = "Missing attribute label on interface '%s'" % id
+ raise Exception(msg)
+
+ self.req['interfaces'].append({
+ 'id' : id,
+ 'type' : type,
+ 'netns' : netns
+ })
+ if type == 'eth':
+ self.req['interfaces'][-1]['network'] = label
+
+ return Interface(self.req['interfaces'][-1])
+
+ def add_param(self, param):
+ if 'params' not in self.req:
+ self.req['params'] = []
+
+ if type(param) != dict:
+ msg = "Param must be dict() type"
+ raise Exception(msg)
+
+ name, value = param.popitem()
+
+ for p in self.req['params']:
+ if p['name'] == name:
+ msg = "Param with name '%s' already exists on host
'%s'" % (name, self.id)
+ raise Exception(msg)
+
+ self.req['params'].append({'name' : name, 'value' :
value})
+
+ def id_exists(self, id):
+ for i in self.req['interfaces']:
+ if id == i['id']:
+ return True
+ return False
+
+ def pair_veths(self, iface1, iface2):
+ if iface1.type != 'veth':
+ msg = "Interface '%s' needs to be veth type for veth
pairing" % iface1.req['id']
+ raise Exception(msg)
+ else:
+ if 'peer' in iface1.req:
+ msg = "Interface '%s' already is in veth pair" %
iface1.req['id']
+ raise Exception(msg)
+ iface1.req['peer'] = iface2.req['id']
+
+ if iface2.type != 'veth':
+ msg = "Interface '%s' needs to be veth type for veth
pairing" % iface2.req['id']
+ raise Exception(msg)
+ else:
+ if 'peer' in iface2.req:
+ msg = "Interface '%s' already is in veth pair" %
iface2.req['id']
+ raise Exception(msg)
+ iface2.req['peer'] = iface1.req['id']
+
+class Interface(object):
+ def __init__(self, req):
+ self.req = req
+ self.id = req['id']
+ self.type = req['type']
+
+ def add_address(self, address):
+ if 'addresses' not in self.req:
+ self.req['addresses'] = []
+
+ if address not in self.req['addresses']:
+ self.req['addresses'].append(address)
+
+ def add_addresses(self, addresses):
+ for address in addresses:
+ self.add_address(address)
+
+ def add_ovs_bond_slave(self, bond_id, iface):
+ if self.type != 'ovs_bridge':
+ msg = "Open vSwitch bond slave can be assigned only to ovs_bridge"
+ raise Exception(msg)
+
+ if 'ovs_conf' not in self.req:
+ self.req['ovs_conf'] = {'bonds' : {},
+ 'vlans' : {}}
+ if bond_id not in self.req['ovs_conf']['bonds']:
+ self.req['ovs_conf']['bonds'][bond_id] = {'slaves' :
[]}
+
+ if iface.id not in
self.req['ovs_conf']['bonds'][bond_id]['slaves']:
+
self.req['ovs_conf']['bonds'][bond_id]['slaves'].append(iface.id)
+
+ def add_ovs_bond_slaves(self, bond_id, ifaces):
+ for iface in ifaces:
+ self.add_ovs_bond_slave(bond_id, iface)
+
+ def add_ovs_vlan_slave(self, vlan_tag, iface):
+ if self.type != 'ovs_bridge':
+ msg = "Open vSwitch VLAN slave can be assigned only to ovs_bridge"
+ raise Exception(msg)
+
+ if 'ovs_conf' not in self.req:
+ self.req['ovs_conf'] = {'bonds' : {},
+ 'vlans' : {}}
+ if vlan_tag not in self.req['ovs_conf']['vlans']:
+ self.req['ovs_conf']['vlans'][vlan_tag] = {'slaves' :
[]}
+
+ if iface.id not in
self.req['ovs_conf']['vlans'][vlan_tag]['slaves']:
+
self.req['ovs_conf']['vlans'][vlan_tag]['slaves'].append(iface.id)
+
+ def add_ovs_vlan_slaves(self, vlan_tag, ifaces):
+ for iface in ifaces:
+ self.add_ovs_vlan_slave(vlan_tag, iface)
+
+ def add_option(self, option):
+ if self.type == 'eth':
+ msg = "Options can't be specified on eth interfaces"
+ raise Exception(msg)
+
+ if 'options' not in self.req:
+ self.req['options'] = []
+
+ name, value = option.popitem()
+
+ for o in self.req['options']:
+ if o['name'] == name:
+ msg = "Option with name '%s' already exists on interface
'%s'" % (name, self.id)
+ raise Exception(msg)
+
+ self.req['options'].append({'name' : name, 'value' :
value})
+
+ def add_param(self, param):
+ if self.type != 'eth':
+ msg = "Params must be specified only on eth interfaces"
+ raise Exception(msg)
+
+ if 'params' not in self.req:
+ self.req['params'] = []
+
+ if type(param) != dict:
+ msg = "Param must be dict() type"
+ raise Exception(msg)
+
+ name, value = param.popitem()
+
+ for p in self.req['params']:
+ if p['name'] == name:
+ msg = "Param with name '%s' already exists on interface
'%s'" % (name, self.id)
+ raise Exception(msg)
+
+ self.req['params'].append({'name' : name, 'value' :
value})
+
+ def add_slave(self, iface):
+ if self.type not in ['bond', 'vlan', 'team',
'bridge',
+ 'macvlan', 'ovs_bridge', 'vxlan']:
+ msg = "Interface type '%s' does not allow slaves" %
self.type
+ raise Exception(msg)
+
+ if 'slaves' not in self.req:
+ self.req['slaves'] = []
+
+ for slave in self.req['slaves']:
+ if iface.id == slave['id']:
+ msg = "Interface '%s' is already slave of '%s'"
% (iface.id, self.id)
+ raise Exception(msg)
+
+ self.req['slaves'].append({'id' : iface.id})
+
+ def add_slaves(self, ifaces):
+ for iface in ifaces:
+ self.add_slave(iface)
--
2.4.3