e.g.
AddIlinkType ('dummynet')
AddIlink (interface_id_src, interface_id_dst, 'dummynet', 'a value if that makes sense')
TODO: clean up ilinks when nodes or interfaces get deleted
index-clean:
rm $(init)
-####################
+#################### regenerate indexes - not used by the build, as both files are svn added - please update as appropriate
# All .py files in PLC/
# the current content of __init__.py
--- /dev/null
+#
+# Thierry Parmentelat - INRIA
+#
+# $Revision: 9423 $
+#
+from types import StringTypes
+
+from PLC.Faults import *
+from PLC.Parameter import Parameter
+from PLC.Filter import Filter
+from PLC.Table import Row, Table
+from PLC.Roles import Role, Roles
+
+class IlinkType (Row):
+
+ """
+ Representation of a row in the ilink_types table.
+ """
+
+ table_name = 'ilink_types'
+ primary_key = 'ilink_type_id'
+ join_tables = ['ilink']
+ fields = {
+ 'ilink_type_id': Parameter(int, "ilink type identifier"),
+ 'name': Parameter(str, "ilink type name", max = 100),
+ 'description': Parameter(str, "ilink type description", max = 254),
+ 'min_role_id': Parameter(int, "Minimum (least powerful) role that can set or change this attribute"),
+ }
+
+ def validate_name(self, name):
+ if not len(name):
+ raise PLCInvalidArgument, "ilink type name must be set"
+
+ conflicts = IlinkTypes(self.api, [name])
+ for tag_type in conflicts:
+ if 'ilink_type_id' not in self or \
+ self['ilink_type_id'] != tag_type['ilink_type_id']:
+ raise PLCInvalidArgument, "ilink type name already in use"
+
+ return name
+
+ def validate_min_role_id(self, role_id):
+ roles = [row['role_id'] for row in Roles(self.api)]
+ if role_id not in roles:
+ raise PLCInvalidArgument, "Invalid role"
+
+ return role_id
+
+class IlinkTypes(Table):
+ """
+ Representation of row(s) from the ilink_types table
+ in the database.
+ """
+
+ def __init__(self, api, ilink_type_filter = None, columns = None):
+ Table.__init__(self, api, IlinkType, columns)
+
+ sql = "SELECT %s FROM ilink_types WHERE True" % \
+ ", ".join(self.columns)
+
+ if ilink_type_filter is not None:
+ if isinstance(ilink_type_filter, (list, tuple, set)):
+ # Separate the list into integers and strings
+ ints = filter(lambda x: isinstance(x, (int, long)), ilink_type_filter)
+ strs = filter(lambda x: isinstance(x, StringTypes), ilink_type_filter)
+ ilink_type_filter = Filter(IlinkType.fields, {'ilink_type_id': ints, 'name': strs})
+ sql += " AND (%s) %s" % ilink_type_filter.sql(api, "OR")
+ elif isinstance(ilink_type_filter, dict):
+ ilink_type_filter = Filter(IlinkType.fields, ilink_type_filter)
+ sql += " AND (%s) %s" % ilink_type_filter.sql(api, "AND")
+ elif isinstance (ilink_type_filter, StringTypes):
+ ilink_type_filter = Filter(IlinkType.fields, {'name':[ilink_type_filter]})
+ sql += " AND (%s) %s" % ilink_type_filter.sql(api, "AND")
+ else:
+ raise PLCInvalidArgument, "Wrong ilink type filter %r"%ilink_type_filter
+
+ self.selectall(sql)
--- /dev/null
+#
+# Thierry Parmentelat - INRIA
+#
+# $Revision: 9423 $
+#
+from PLC.Faults import *
+from PLC.Parameter import Parameter
+from PLC.Filter import Filter
+from PLC.Table import Row, Table
+from PLC.Interfaces import Interface, Interfaces
+from PLC.IlinkTypes import IlinkType, IlinkTypes
+
+class Ilink(Row):
+ """
+ Representation of a row in the ilink table.
+ To use, instantiate with a dict of values.
+ """
+
+ table_name = 'ilink'
+ primary_key = 'ilink_id'
+ fields = {
+ 'ilink_id': Parameter(int, "ilink identifier"),
+ 'ilink_type_id': IlinkType.fields['ilink_type_id'],
+ 'src_interface_id': Parameter(int, "source interface identifier"),
+ 'dst_interface_id': Parameter(int, "destination interface identifier"),
+ 'value': Parameter( str, "optional ilink value"),
+ }
+
+class Ilinks(Table):
+ """
+ Representation of row(s) from the ilink table in the
+ database.
+ """
+
+ def __init__(self, api, ilink_filter = None, columns = None):
+ Table.__init__(self, api, Ilink, columns)
+
+ sql = "SELECT %s FROM view_ilinks WHERE True" % \
+ ", ".join(self.columns)
+
+ if ilink_filter is not None:
+ if isinstance(ilink_filter, (list, tuple, set)):
+ ilink_filter = Filter(Ilink.fields, {'ilink_id': ilink_filter})
+ elif isinstance(ilink_filter, dict):
+ ilink_filter = Filter(Ilink.fields, ilink_filter)
+ elif isinstance(ilink_filter, int):
+ ilink_filter = Filter(Ilink.fields, {'ilink_id': [ilink_filter]})
+ else:
+ raise PLCInvalidArgument, "Wrong ilink filter %r"%ilink_filter
+ sql += " AND (%s) %s" % ilink_filter.sql(api)
+
+
+ self.selectall(sql)
--- /dev/null
+#
+# Thierry Parmentelat - INRIA
+#
+# $Revision: 9423 $
+#
+from PLC.Faults import *
+from PLC.Method import Method
+from PLC.Parameter import Parameter, Mixed
+from PLC.Auth import Auth
+
+from PLC.IlinkTypes import IlinkType, IlinkTypes
+from PLC.Ilinks import Ilink, Ilinks
+from PLC.Interfaces import Interface, Interfaces
+
+from PLC.Sites import Sites
+
+class AddIlink(Method):
+ """
+ Create a link between two interfaces
+ The link has a type, that needs be created beforehand
+ and an optional value.
+
+ Returns the new ilink_id (> 0) if successful, faults
+ otherwise.
+ """
+
+ roles = ['admin', 'pi', 'tech', 'user']
+
+ accepts = [
+ Auth(),
+ # refer to either the id or the type name
+ Ilink.fields['src_interface_id'],
+ Ilink.fields['dst_interface_id'],
+ Mixed(IlinkType.fields['ilink_type_id'],
+ IlinkType.fields['name']),
+ Ilink.fields['value'],
+ ]
+
+ returns = Parameter(int, 'New ilink_id (> 0) if successful')
+
+ def call(self, auth, src_if_id, dst_if_id, ilink_type_id_or_name, value):
+
+ src_if = Interfaces (self.api, [src_if_id],[interface_id])
+ if not src_if:
+ raise PLCInvalidArgument, "No such source interface %r"%src_if_id
+ dst_if = Interfaces (self.api, [dst_if_id],[interface_id])
+ if not dst_if:
+ raise PLCInvalidArgument, "No such destination interface %r"%dst_if_id
+
+ ilink_types = IlinkTypes(self.api, [ilink_type_id_or_name])
+ if not ilink_types:
+ raise PLCInvalidArgument, "No such ilink type %r"%ilink_type_id_or_name
+ ilink_type = ilink_types[0]
+
+ # checks for existence - with the same type
+ conflicts = Ilinks(self.api,
+ {'ilink_type_id':ilink_type['ilink_type_id'],
+ 'src_interface_id':src_if_id,
+ 'dst_interface_id':dst_if_id,})
+
+ if len(conflicts) :
+ ilink=conflicts[0]
+ raise PLCInvalidArgument, "Ilink (%s,%d,%d) already exists and has value %r"\
+ %(ilink_type['name'],src_if_id,dst_if_id,ilink['value'])
+
+ if 'admin' not in self.caller['roles']:
+# # check permission : it not admin, is the user affiliated with the right site(s) ????
+# # locate node
+# node = Nodes (self.api,[node['node_id']])[0]
+# # locate site
+# site = Sites (self.api, [node['site_id']])[0]
+# # check caller is affiliated with this site
+# if self.caller['person_id'] not in site['person_ids']:
+# raise PLCPermissionDenied, "Not a member of the hosting site %s"%site['abbreviated_site']
+
+ required_min_role = ilink_type ['min_role_id']
+ if required_min_role is not None and \
+ min(self.caller['role_ids']) > required_min_role:
+ raise PLCPermissionDenied, "Not allowed to modify the specified ilink, requires role %d",required_min_role
+
+ ilink = Ilink(self.api)
+ ilink['ilink_type_id'] = ilink_type['ilink_type_id']
+ ilink['src_interface_id'] = src_if_id
+ ilink['dst_interface_id'] = dst_if_id
+ ilink['value'] = value
+
+ ilink.sync()
+
+ self.object_type = 'Interface'
+ self.object_ids = [src_if_id,dst_if_id]
+
+ return ilink['ilink_id']
--- /dev/null
+#
+# Thierry Parmentelat - INRIA
+#
+# $Revision: 9423 $
+#
+
+
+from PLC.Faults import *
+from PLC.Method import Method
+from PLC.Parameter import Parameter, Mixed
+from PLC.IlinkTypes import IlinkType, IlinkTypes
+from PLC.Auth import Auth
+
+can_update = lambda (field, value): field in \
+ ['name', 'description', 'category', 'min_role_id']
+
+class AddIlinkType(Method):
+ """
+ Adds a new type of ilink.
+ Any fields specified are used, otherwise defaults are used.
+
+ Returns the new ilink_id (> 0) if successful,
+ faults otherwise.
+ """
+
+ roles = ['admin']
+
+ ilink_type_fields = dict(filter(can_update, IlinkType.fields.items()))
+
+ accepts = [
+ Auth(),
+ ilink_type_fields
+ ]
+
+ returns = Parameter(int, 'New ilink_id (> 0) if successful')
+
+
+ def call(self, auth, ilink_type_fields):
+ ilink_type_fields = dict(filter(can_update, ilink_type_fields.items()))
+ ilink_type = IlinkType(self.api, ilink_type_fields)
+ ilink_type.sync()
+
+ self.object_ids = [ilink_type['ilink_type_id']]
+
+ return ilink_type['ilink_type_id']
from PLC.NodeTags import NodeTag, NodeTags
from PLC.Nodes import Node, Nodes
-from PLC.Nodes import Nodes
from PLC.Sites import Sites
class AddNodeTag(Method):
--- /dev/null
+#
+# Thierry Parmentelat - INRIA
+#
+# $Revision: 9423 $
+#
+
+from PLC.Faults import *
+from PLC.Method import Method
+from PLC.Parameter import Parameter, Mixed
+from PLC.Auth import Auth
+
+from PLC.Ilinks import Ilink, Ilinks
+from PLC.Nodes import Node, Nodes
+
+from PLC.Nodes import Node, Nodes
+from PLC.Sites import Site, Sites
+
+class DeleteIlink(Method):
+ """
+ Deletes the specified ilink
+
+ Attributes may require the caller to have a particular role in order
+ to be deleted, depending on the related ilink type.
+ Admins may delete attributes of any slice or sliver.
+
+ Returns 1 if successful, faults otherwise.
+ """
+
+ roles = ['admin', 'pi', 'user']
+
+ accepts = [
+ Auth(),
+ Ilink.fields['ilink_id']
+ ]
+
+ returns = Parameter(int, '1 if successful')
+
+ object_type = 'Node'
+
+
+ def call(self, auth, ilink_id):
+ ilinks = Ilinks(self.api, [ilink_id])
+ if not ilinks:
+ raise PLCInvalidArgument, "No such ilink %r"%ilink_id
+ ilink = ilinks[0]
+
+ ### reproducing a check from UpdateSliceAttribute, looks dumb though
+ nodes = Nodes(self.api, [ilink['node_id']])
+ if not nodes:
+ raise PLCInvalidArgument, "No such node %r"%ilink['node_id']
+ node = nodes[0]
+
+ assert ilink['ilink_id'] in node['tag_ids']
+
+ # check permission : it not admin, is the user affiliated with the right site
+ if 'admin' not in self.caller['roles']:
+ # locate node
+ node = Nodes (self.api,[node['node_id']])[0]
+ # locate site
+ site = Sites (self.api, [node['site_id']])[0]
+ # check caller is affiliated with this site
+ if self.caller['person_id'] not in site['person_ids']:
+ raise PLCPermissionDenied, "Not a member of the hosting site %s"%site['abbreviated_site']
+
+ required_min_role = ilink_type ['min_role_id']
+ if required_min_role is not None and \
+ min(self.caller['role_ids']) > required_min_role:
+ raise PLCPermissionDenied, "Not allowed to modify the specified ilink, requires role %d",required_min_role
+
+ ilink.delete()
+ self.object_ids = [ilink['ilink_id']]
+
+ return 1
--- /dev/null
+#
+# Thierry Parmentelat - INRIA
+#
+# $Revision: 9423 $
+#
+from PLC.Faults import *
+from PLC.Method import Method
+from PLC.Parameter import Parameter, Mixed
+from PLC.IlinkTypes import IlinkType, IlinkTypes
+from PLC.Auth import Auth
+
+class DeleteIlinkType(Method):
+ """
+ Deletes the specified ilink type.
+
+ Returns 1 if successful, faults otherwise.
+ """
+
+ roles = ['admin']
+
+ accepts = [
+ Auth(),
+ Mixed(IlinkType.fields['ilink_type_id'],
+ IlinkType.fields['name']),
+ ]
+
+ returns = Parameter(int, '1 if successful')
+
+
+ def call(self, auth, ilink_type_id_or_name):
+ ilink_types = IlinkTypes(self.api, [ilink_type_id_or_name])
+ if not ilink_types:
+ raise PLCInvalidArgument, "No such ilink type"
+ ilink_type = ilink_types[0]
+
+ ilink_type.delete()
+ self.object_ids = [ilink_type['ilink_type_id']]
+
+ return 1
--- /dev/null
+#
+# Thierry Parmentelat - INRIA
+#
+# $Revision: 9423 $
+#
+from PLC.Method import Method
+from PLC.Parameter import Parameter, Mixed
+from PLC.Filter import Filter
+from PLC.Auth import Auth
+from PLC.IlinkTypes import IlinkType, IlinkTypes
+
+class GetIlinkTypes(Method):
+ """
+ Returns an array of structs containing details about
+ ilink types.
+
+ The usual filtering scheme applies on this method.
+ """
+
+ roles = ['admin', 'pi', 'user', 'tech', 'node']
+
+ accepts = [
+ Auth(),
+ Mixed([Mixed(IlinkType.fields['ilink_type_id'],
+ IlinkType.fields['name'])],
+ Filter(IlinkType.fields)),
+ Parameter([str], "List of fields to return", nullok = True)
+ ]
+
+ returns = [IlinkType.fields]
+
+ def call(self, auth, ilink_type_filter = None, return_fields = None):
+ return IlinkTypes(self.api, ilink_type_filter, return_fields)
--- /dev/null
+#
+# Thierry Parmentelat - INRIA
+#
+# $Revision: 9423 $
+#
+from PLC.Faults import *
+from PLC.Method import Method
+from PLC.Parameter import Parameter, Mixed
+from PLC.Filter import Filter
+from PLC.Auth import Auth
+
+from PLC.Ilinks import Ilink, Ilinks
+from PLC.Sites import Site, Sites
+from PLC.Nodes import Node, Nodes
+
+class GetIlinks(Method):
+ """
+ Returns an array of structs containing details about
+ nodes and related tags.
+
+ If ilink_filter is specified and is an array of
+ ilink identifiers, only ilinks matching
+ the filter will be returned. If return_fields is specified, only
+ the specified details will be returned.
+ """
+
+ roles = ['admin', 'pi', 'user', 'node']
+
+ accepts = [
+ Auth(),
+ Mixed([Ilink.fields['ilink_id']],
+ Parameter(int,"ilink id"),
+ Filter(Ilink.fields)),
+ Parameter([str], "List of fields to return", nullok = True)
+ ]
+
+ returns = [Ilink.fields]
+
+
+ def call(self, auth, ilink_filter = None, return_fields = None):
+
+ ilinks = Ilinks(self.api, ilink_filter, return_fields)
+
+ return ilinks
--- /dev/null
+#
+# Thierry Parmentelat - INRIA
+#
+# $Revision: 9423 $
+#
+
+from PLC.Faults import *
+from PLC.Method import Method
+from PLC.Parameter import Parameter, Mixed
+from PLC.Auth import Auth
+
+from PLC.Ilinks import Ilink, Ilinks
+from PLC.Interfaces import Interface, Interfaces
+
+from PLC.Sites import Sites
+
+class UpdateIlink(Method):
+ """
+ Updates the value of an existing ilink
+
+ Access rights depend on the ilink type.
+
+ Returns 1 if successful, faults otherwise.
+ """
+
+ roles = ['admin', 'pi', 'tech', 'user']
+
+ accepts = [
+ Auth(),
+ Ilink.fields['ilink_id'],
+ Ilink.fields['value']
+ ]
+
+ returns = Parameter(int, '1 if successful')
+
+ object_type = 'Interface'
+
+ def call(self, auth, ilink_id, value):
+ ilinks = Ilinks(self.api, [ilink_id])
+ if not ilinks:
+ raise PLCInvalidArgument, "No such ilink %r"%ilink_id
+ ilink = ilinks[0]
+
+ if 'admin' not in self.caller['roles']:
+# # check permission : it not admin, is the user affiliated with the right site
+# # locate node
+# node = Nodes (self.api,[node['node_id']])[0]
+# # locate site
+# site = Sites (self.api, [node['site_id']])[0]
+# # check caller is affiliated with this site
+# if self.caller['person_id'] not in site['person_ids']:
+# raise PLCPermissionDenied, "Not a member of the hosting site %s"%site['abbreviated_site']
+
+ required_min_role = ilink_type ['min_role_id']
+ if required_min_role is not None and \
+ min(self.caller['role_ids']) > required_min_role:
+ raise PLCPermissionDenied, "Not allowed to modify the specified ilink, requires role %d",required_min_role
+
+ ilink['value'] = value
+ ilink.sync()
+
+ self.object_ids = [ilink['src_interface_id'],ilink['dst_interface_id']]
+ return 1
--- /dev/null
+#
+# Thierry Parmentelat - INRIA
+#
+# $Revision: 9423 $
+#
+from PLC.Faults import *
+from PLC.Method import Method
+from PLC.Parameter import Parameter, Mixed
+from PLC.IlinkTypes import IlinkType, IlinkTypes
+from PLC.Auth import Auth
+
+can_update = lambda (field, value): field in \
+ ['name', 'description', 'category', 'min_role_id']
+
+class UpdateIlinkType(Method):
+ """
+ Updates the parameters of an existing tag type
+ with the values in ilink_type_fields.
+
+ Returns 1 if successful, faults otherwise.
+ """
+
+ roles = ['admin']
+
+ ilink_type_fields = dict(filter(can_update, IlinkType.fields.items()))
+
+ accepts = [
+ Auth(),
+ Mixed(IlinkType.fields['ilink_type_id'],
+ IlinkType.fields['name']),
+ ilink_type_fields
+ ]
+
+ returns = Parameter(int, '1 if successful')
+
+ def call(self, auth, ilink_type_id_or_name, ilink_type_fields):
+ ilink_type_fields = dict(filter(can_update, ilink_type_fields.items()))
+
+ ilink_types = IlinkTypes(self.api, [ilink_type_id_or_name])
+ if not ilink_types:
+ raise PLCInvalidArgument, "No such tag type"
+ ilink_type = ilink_types[0]
+
+ ilink_type.update(ilink_type_fields)
+ ilink_type.sync()
+ self.object_ids = [ilink_type['ilink_type_id']]
+
+ return 1
AddConfFile
AddConfFileToNode
AddConfFileToNodeGroup
+AddIlink
+AddIlinkType
AddInitScript
AddInterface
AddInterfaceSetting
DeleteConfFile
DeleteConfFileFromNode
DeleteConfFileFromNodeGroup
+DeleteIlink
+DeleteIlinkType
DeleteInitScript
DeleteInterface
DeleteInterfaceSetting
GetConfFiles
GetEventObjects
GetEvents
+GetIlinkTypes
+GetIlinks
GetInitScripts
GetInterfaceSettingTypes
GetInterfaceSettings
UpdateAddress
UpdateAddressType
UpdateConfFile
+UpdateIlink
+UpdateIlinkType
UpdateInitScript
UpdateInterface
UpdateInterfaceSetting
Faults
Filter
GPG
+IlinkTypes
+Ilinks
InitScripts
InterfaceSettingTypes
InterfaceSettings
----------------------------------------
-- node tags
----------------------------------------
-CREATE TABLE node_tag_types (
-
- node_tag_type_id serial PRIMARY KEY, -- ID
- name text UNIQUE NOT NULL, -- Tag Name
- description text, -- Optional Description
- category text NOT NULL, -- Free text for grouping tags together
- min_role_id integer REFERENCES roles -- set minimal role required
-) WITH OIDS;
-
-CREATE TABLE node_tag (
- node_tag_id serial PRIMARY KEY, -- ID
- node_id integer REFERENCES nodes NOT NULL, -- node id
- node_tag_type_id integer REFERENCES node_tag_types,
- -- tag type id
- value text -- value attached
-) WITH OIDS;
+CREATE TABLE node_tag_types ...
+CREATE TABLE node_tag ...
---------- related views
-CREATE OR REPLACE VIEW node_tags AS
-SELECT node_id,
-array_accum(node_tag_id) AS tag_ids
-FROM node_tag
-GROUP BY node_id;
-
-CREATE OR REPLACE VIEW view_node_tags AS
-SELECT
-node_tag.node_tag_id,
-node_tag.node_id,
-node_tag_types.node_tag_type_id,
-node_tag_types.name,
-node_tag_types.description,
-node_tag_types.category,
-node_tag_types.min_role_id,
-node_tag.value
-FROM node_tag
-INNER JOIN node_tag_types USING (node_tag_type_id);
+CREATE OR REPLACE VIEW node_tags AS ...
+CREATE OR REPLACE VIEW view_node_tags AS ...
----------------------------------------
-- nodegroups
DROP TABLE IF EXISTS nodegroups CASCADE;
-- Node groups
-CREATE TABLE nodegroups (
- nodegroup_id serial PRIMARY KEY, -- Group identifier
- groupname text UNIQUE NOT NULL, -- Group name
- node_tag_type_id integer REFERENCES node_tag_types, -- node is in nodegroup if it has this tag defined
- value text -- with value 'value'
-) WITH OIDS;
-
-CREATE OR REPLACE VIEW nodegroup_node AS
-SELECT nodegroup_id, node_id
-FROM node_tag_types
-JOIN node_tag
-USING (node_tag_type_id)
-JOIN nodegroups
-USING (node_tag_type_id,value);
-
-CREATE OR REPLACE VIEW nodegroup_nodes AS
-SELECT nodegroup_id,
-array_accum(node_id) AS node_ids
-FROM nodegroup_node
-GROUP BY nodegroup_id;
-
--- Node groups that each node is a member of
-CREATE OR REPLACE VIEW node_nodegroups AS
-SELECT node_id,
-array_accum(nodegroup_id) AS nodegroup_ids
-FROM nodegroup_node
-GROUP BY node_id;
-
+CREATE TABLE nodegroups ...
+CREATE OR REPLACE VIEW nodegroup_node AS ...
+CREATE OR REPLACE VIEW nodegroup_nodes AS ...
+CREATE OR REPLACE VIEW node_nodegroups AS ...
CREATE OR REPLACE VIEW view_nodegroups AS
-SELECT
-nodegroups.*,
-COALESCE((SELECT conf_file_ids FROM nodegroup_conf_files WHERE nodegroup_conf_files.nodegroup_id = nodegroups.nodegroup_id), '{}') AS conf_file_ids
-FROM nodegroups;
+
----------------------------------------
-- the nodes view
----------------------------------------
DROP VIEW view_nodes;
-CREATE OR REPLACE VIEW view_nodes AS
-SELECT
-nodes.node_id,
-nodes.hostname,
-nodes.site_id,
-nodes.boot_state,
-nodes.deleted,
-nodes.model,
-nodes.boot_nonce,
-nodes.version,
-nodes.ssh_rsa_key,
-nodes.key,
-CAST(date_part('epoch', nodes.date_created) AS bigint) AS date_created,
-CAST(date_part('epoch', nodes.last_updated) AS bigint) AS last_updated,
-CAST(date_part('epoch', nodes.last_contact) AS bigint) AS last_contact,
-peer_node.peer_id,
-peer_node.peer_node_id,
-COALESCE((SELECT interface_ids FROM node_interfaces WHERE node_interfaces.node_id = nodes.node_id), '{}') AS interface_ids,
-COALESCE((SELECT nodegroup_ids FROM node_nodegroups WHERE node_nodegroups.node_id = nodes.node_id), '{}') AS nodegroup_ids,
-COALESCE((SELECT slice_ids FROM node_slices WHERE node_slices.node_id = nodes.node_id), '{}') AS slice_ids,
-COALESCE((SELECT slice_ids_whitelist FROM node_slices_whitelist WHERE node_slices_whitelist.node_id = nodes.node_id), '{}') AS slice_ids_whitelist,
-COALESCE((SELECT pcu_ids FROM node_pcus WHERE node_pcus.node_id = nodes.node_id), '{}') AS pcu_ids,
-COALESCE((SELECT ports FROM node_pcus WHERE node_pcus.node_id = nodes.node_id), '{}') AS ports,
-COALESCE((SELECT conf_file_ids FROM node_conf_files WHERE node_conf_files.node_id = nodes.node_id), '{}') AS conf_file_ids,
-COALESCE((SELECT tag_ids FROM node_tags WHERE node_tags.node_id = nodes.node_id), '{}') AS tag_ids,
-node_session.session_id AS session
-FROM nodes
-LEFT JOIN peer_node USING (node_id)
-LEFT JOIN node_session USING (node_id);
+CREATE OR REPLACE VIEW view_nodes AS ...
+
+----------------------------------------
+-- ilinks
+----------------------------------------
+CREATE TABLE ilink_types ...
+CREATE TABLE ilink ...
+
+CREATE OR REPLACE VIEW ilinks AS ...
+CREATE OR REPLACE VIEW ilink_src_node AS ...
+CREATE OR REPLACE VIEW ilink_nodes AS ...
----------------------------------------
-- update versioning
INNER JOIN nodes USING (node_id);
--------------------------------------------------------------------------------
--- Node groups
---------------------------------------------------------------------------------
-
--- Node groups
-CREATE TABLE nodegroups (
- nodegroup_id serial PRIMARY KEY, -- Group identifier
- groupname text UNIQUE NOT NULL, -- Group name
- node_tag_type_id integer REFERENCES node_tag_types, -- node is in nodegroup if it has this tag defined
- tagvalue text NOT NULL -- with this value attached
-) WITH OIDS;
-
--- xxx - first rough implem
-CREATE OR REPLACE VIEW nodegroup_node AS
-SELECT nodegroup_id, node_id
-FROM node_tag_types
-JOIN node_tag
-USING (node_tag_type_id)
-JOIN nodegroups
-USING (node_tag_type_id,tagvalue);
-
-CREATE OR REPLACE VIEW nodegroup_nodes AS
-SELECT nodegroup_id,
-array_accum(node_id) AS node_ids
-FROM nodegroup_node
-GROUP BY nodegroup_id;
-
--- Node groups that each node is a member of
-CREATE OR REPLACE VIEW node_nodegroups AS
-SELECT node_id,
-array_accum(nodegroup_id) AS nodegroup_ids
-FROM nodegroup_node
-GROUP BY node_id;
-
---------------------------------------------------------------------------------
--- Node configuration files
---------------------------------------------------------------------------------
-
-CREATE TABLE conf_files (
- conf_file_id serial PRIMARY KEY, -- Configuration file identifier
- enabled bool NOT NULL DEFAULT true, -- Configuration file is active
- source text NOT NULL, -- Relative path on the boot server
- -- where file can be downloaded
- dest text NOT NULL, -- Absolute path where file should be installed
- file_permissions text NOT NULL DEFAULT '0644', -- chmod(1) permissions
- file_owner text NOT NULL DEFAULT 'root', -- chown(1) owner
- file_group text NOT NULL DEFAULT 'root', -- chgrp(1) owner
- preinstall_cmd text, -- Shell command to execute prior to installing
- postinstall_cmd text, -- Shell command to execute after installing
- error_cmd text, -- Shell command to execute if any error occurs
- ignore_cmd_errors bool NOT NULL DEFAULT false, -- Install file anyway even if an error occurs
- always_update bool NOT NULL DEFAULT false -- Always attempt to install file even if unchanged
-) WITH OIDS;
-
-CREATE TABLE conf_file_node (
- conf_file_id integer REFERENCES conf_files NOT NULL, -- Configuration file identifier
- node_id integer REFERENCES nodes NOT NULL, -- Node identifier
- PRIMARY KEY (conf_file_id, node_id)
-);
-CREATE INDEX conf_file_node_conf_file_id_idx ON conf_file_node (conf_file_id);
-CREATE INDEX conf_file_node_node_id_idx ON conf_file_node (node_id);
-
--- Nodes linked to each configuration file
-CREATE OR REPLACE VIEW conf_file_nodes AS
-SELECT conf_file_id,
-array_accum(node_id) AS node_ids
-FROM conf_file_node
-GROUP BY conf_file_id;
-
--- Configuration files linked to each node
-CREATE OR REPLACE VIEW node_conf_files AS
-SELECT node_id,
-array_accum(conf_file_id) AS conf_file_ids
-FROM conf_file_node
-GROUP BY node_id;
-
-CREATE TABLE conf_file_nodegroup (
- conf_file_id integer REFERENCES conf_files NOT NULL, -- Configuration file identifier
- nodegroup_id integer REFERENCES nodegroups NOT NULL, -- Node group identifier
- PRIMARY KEY (conf_file_id, nodegroup_id)
-);
-CREATE INDEX conf_file_nodegroup_conf_file_id_idx ON conf_file_nodegroup (conf_file_id);
-CREATE INDEX conf_file_nodegroup_nodegroup_id_idx ON conf_file_nodegroup (nodegroup_id);
-
--- Node groups linked to each configuration file
-CREATE OR REPLACE VIEW conf_file_nodegroups AS
-SELECT conf_file_id,
-array_accum(nodegroup_id) AS nodegroup_ids
-FROM conf_file_nodegroup
-GROUP BY conf_file_id;
-
--- Configuration files linked to each node group
-CREATE OR REPLACE VIEW nodegroup_conf_files AS
-SELECT nodegroup_id,
-array_accum(conf_file_id) AS conf_file_ids
-FROM conf_file_nodegroup
-GROUP BY nodegroup_id;
-
---------------------------------------------------------------------------------
--- Node network interfaces
+-- (network) interfaces
--------------------------------------------------------------------------------
-- Valid network addressing schemes
name text UNIQUE NOT NULL, -- Setting Name
description text, -- Optional Description
category text NOT NULL DEFAULT 'general', -- Free text for grouping, e.g. Wifi, or whatever
- min_role_id integer REFERENCES roles DEFAULT 10 -- If set, minimal role required
+ min_role_id integer REFERENCES roles DEFAULT 10 -- minimal role required
) WITH OIDS;
CREATE TABLE interface_setting (
COALESCE((SELECT interface_setting_ids FROM interface_settings WHERE interface_settings.interface_id = interfaces.interface_id), '{}') AS interface_setting_ids
FROM interfaces;
+--------------------------------------------------------------------------------
+-- ilinks : links between interfaces
+--------------------------------------------------------------------------------
+CREATE TABLE ilink_types (
+ ilink_type_id serial PRIMARY KEY, -- id
+ name text UNIQUE NOT NULL, -- link name
+ description text, -- optional description
+ min_role_id integer REFERENCES roles DEFAULT 10 -- minimal role required
+) WITH OIDS;
+
+CREATE TABLE ilink (
+ ilink_id serial PRIMARY KEY, -- id
+ ilink_type_id integer REFERENCES ilink_types, -- id of the ilink type
+ src_interface_id integer REFERENCES interfaces not NULL, -- id of src interface
+ dst_interface_id integer REFERENCES interfaces NOT NULL, -- id of dst interface
+ value text -- optional value on the link
+) WITH OIDS;
+
+CREATE OR REPLACE VIEW view_ilinks AS
+SELECT * FROM ilink_types
+INNER JOIN ilink USING (ilink_type_id);
+
+-- expose node_ids ???
+-- -- cannot mention the same table twice in a join ?
+-- -- CREATE OR REPLACE VIEW ilink_src_node AS
+-- SELECT
+-- ilink.ilink_type_id,
+-- ilink.src_interface_id,
+-- interfaces.node_id AS src_node_id,
+-- ilink.dst_interface_id
+-- FROM ilink
+-- INNER JOIN interfaces ON ilink.src_interface_id = interfaces.interface_id;
+--
+-- CREATE OR REPLACE VIEW ilink_nodes AS
+-- SELECT
+-- ilink_src_node.*,
+-- interfaces.node_id as dst_node_id
+-- FROM ilink_src_node
+-- INNER JOIN interfaces ON ilink_src_node.dst_interface_id = interfaces.interface_id;
+
+--------------------------------------------------------------------------------
+-- Node groups
+--------------------------------------------------------------------------------
+
+-- Node groups
+CREATE TABLE nodegroups (
+ nodegroup_id serial PRIMARY KEY, -- Group identifier
+ groupname text UNIQUE NOT NULL, -- Group name
+ node_tag_type_id integer REFERENCES node_tag_types, -- node is in nodegroup if it has this tag defined
+ tagvalue text NOT NULL -- with this value attached
+) WITH OIDS;
+
+-- xxx - first rough implem. similar to former semantics but might be slow
+CREATE OR REPLACE VIEW nodegroup_node AS
+SELECT nodegroup_id, node_id
+FROM node_tag_types
+JOIN node_tag
+USING (node_tag_type_id)
+JOIN nodegroups
+USING (node_tag_type_id,tagvalue);
+
+CREATE OR REPLACE VIEW nodegroup_nodes AS
+SELECT nodegroup_id,
+array_accum(node_id) AS node_ids
+FROM nodegroup_node
+GROUP BY nodegroup_id;
+
+-- Node groups that each node is a member of
+CREATE OR REPLACE VIEW node_nodegroups AS
+SELECT node_id,
+array_accum(nodegroup_id) AS nodegroup_ids
+FROM nodegroup_node
+GROUP BY node_id;
+
+--------------------------------------------------------------------------------
+-- Node configuration files
+--------------------------------------------------------------------------------
+
+CREATE TABLE conf_files (
+ conf_file_id serial PRIMARY KEY, -- Configuration file identifier
+ enabled bool NOT NULL DEFAULT true, -- Configuration file is active
+ source text NOT NULL, -- Relative path on the boot server
+ -- where file can be downloaded
+ dest text NOT NULL, -- Absolute path where file should be installed
+ file_permissions text NOT NULL DEFAULT '0644', -- chmod(1) permissions
+ file_owner text NOT NULL DEFAULT 'root', -- chown(1) owner
+ file_group text NOT NULL DEFAULT 'root', -- chgrp(1) owner
+ preinstall_cmd text, -- Shell command to execute prior to installing
+ postinstall_cmd text, -- Shell command to execute after installing
+ error_cmd text, -- Shell command to execute if any error occurs
+ ignore_cmd_errors bool NOT NULL DEFAULT false, -- Install file anyway even if an error occurs
+ always_update bool NOT NULL DEFAULT false -- Always attempt to install file even if unchanged
+) WITH OIDS;
+
+CREATE TABLE conf_file_node (
+ conf_file_id integer REFERENCES conf_files NOT NULL, -- Configuration file identifier
+ node_id integer REFERENCES nodes NOT NULL, -- Node identifier
+ PRIMARY KEY (conf_file_id, node_id)
+);
+CREATE INDEX conf_file_node_conf_file_id_idx ON conf_file_node (conf_file_id);
+CREATE INDEX conf_file_node_node_id_idx ON conf_file_node (node_id);
+
+-- Nodes linked to each configuration file
+CREATE OR REPLACE VIEW conf_file_nodes AS
+SELECT conf_file_id,
+array_accum(node_id) AS node_ids
+FROM conf_file_node
+GROUP BY conf_file_id;
+
+-- Configuration files linked to each node
+CREATE OR REPLACE VIEW node_conf_files AS
+SELECT node_id,
+array_accum(conf_file_id) AS conf_file_ids
+FROM conf_file_node
+GROUP BY node_id;
+
+CREATE TABLE conf_file_nodegroup (
+ conf_file_id integer REFERENCES conf_files NOT NULL, -- Configuration file identifier
+ nodegroup_id integer REFERENCES nodegroups NOT NULL, -- Node group identifier
+ PRIMARY KEY (conf_file_id, nodegroup_id)
+);
+CREATE INDEX conf_file_nodegroup_conf_file_id_idx ON conf_file_nodegroup (conf_file_id);
+CREATE INDEX conf_file_nodegroup_nodegroup_id_idx ON conf_file_nodegroup (nodegroup_id);
+
+-- Node groups linked to each configuration file
+CREATE OR REPLACE VIEW conf_file_nodegroups AS
+SELECT conf_file_id,
+array_accum(nodegroup_id) AS nodegroup_ids
+FROM conf_file_nodegroup
+GROUP BY conf_file_id;
+
+-- Configuration files linked to each node group
+CREATE OR REPLACE VIEW nodegroup_conf_files AS
+SELECT nodegroup_id,
+array_accum(conf_file_id) AS conf_file_ids
+FROM conf_file_nodegroup
+GROUP BY nodegroup_id;
+
--------------------------------------------------------------------------------
-- Power control units (PCUs)
--------------------------------------------------------------------------------