--- /dev/null
+from PLC.Faults import *
+from PLC.Method import Method
+from PLC.Parameter import Parameter, Mixed
+from PLC.NodeGroups import NodeGroup, NodeGroups
+from PLC.Nodes import Node, Nodes
+from PLC.Auth import PasswordAuth
+
+class AddNodeToNodeGroup(Method):
+ """
+ Add a node to the specified node group. If the node is
+ already a member of the nodegroup, no errors are returned.
+
+ Returns 1 if successful, faults otherwise.
+ """
+
+ roles = ['admin']
+
+ accepts = [
+ PasswordAuth(),
+ Mixed(NodeGroup.fields['nodegroup_id'],
+ NodeGroup.fields['name']),
+ Mixed(Node.fields['node_id'],
+ Node.fields['hostname'])
+ ]
+
+ returns = Parameter(int, '1 if successful')
+
+ def call(self, auth, nodegroup_id_or_name, node_id_or_hostname):
+ # Get node info
+ nodes = Nodes(self.api, [node_id_or_hostname])
+ if not nodes:
+ raise PLCInvalidArgument, "No such node"
+ node = nodes.values()[0]
+
+ # Get nodegroup info
+ nodegroups = NodeGroups(self.api, [nodegroup_id_or_name])
+ if not nodegroups:
+ raise PLCInvalidArgument, "No such nodegroup"
+
+ nodegroup = nodegroups.values()[0]
+
+ # add node to nodegroup
+ if node['node_id'] not in nodegroup['node_ids']:
+ nodegroup.add_node(node)
+
+ return 1
--- /dev/null
+from PLC.Faults import *
+from PLC.Method import Method
+from PLC.Parameter import Parameter, Mixed
+from PLC.Persons import Person, Persons
+from PLC.Auth import PasswordAuth
+
+class AddPerson(Method):
+ """
+ Adds a new account. Any fields specified in optional_vals are
+ used, otherwise defaults are used.
+
+ Accounts are disabled by default. To enable an account, use
+ SetPersonEnabled() or UpdatePerson().
+
+ Returns the new person_id (> 0) if successful, faults otherwise.
+ """
+
+ roles = ['admin', 'pi']
+
+ can_update = lambda (field, value): field in \
+ ['title', 'email', 'password', 'phone', 'url', 'bio']
+ update_fields = dict(filter(can_update, Person.fields.items()))
+
+ accepts = [
+ PasswordAuth(),
+ Person.fields['first_name'],
+ Person.fields['last_name'],
+ update_fields
+ ]
+
+ returns = Parameter(int, 'New person_id (> 0) if successful')
+
+ def call(self, auth, first_name, last_name, optional_vals = {}):
+ if filter(lambda field: field not in self.update_fields, optional_vals):
+ raise PLCInvalidArgument, "Invalid fields specified"
+
+ person = Person(self.api, optional_vals)
+ person['first_name'] = first_name
+ person['last_name'] = last_name
+ person['enabled'] = False
+ person.sync()
+
+ return person['person_id']
--- /dev/null
+from PLC.Faults import *
+from PLC.Method import Method
+from PLC.Parameter import Parameter, Mixed
+from PLC.Persons import Person, Persons
+from PLC.Sites import Site, Sites
+from PLC.Auth import PasswordAuth
+
+class AddPersonToSite(Method):
+ """
+ Adds the specified person to the specified site. If the person is
+ already a member of the site, no errors are returned. Does not
+ change the person's primary site.
+
+ Returns 1 if successful, faults otherwise.
+ """
+
+ roles = ['admin']
+
+ accepts = [
+ PasswordAuth(),
+ Mixed(Person.fields['person_id'],
+ Person.fields['email']),
+ Mixed(Site.fields['site_id'],
+ Site.fields['login_base'])
+ ]
+
+ returns = Parameter(int, '1 if successful')
+
+ def call(self, auth, person_id_or_email, site_id_or_login_base):
+ # Get account information
+ persons = Persons(self.api, [person_id_or_email])
+ if not persons:
+ raise PLCInvalidArgument, "No such account"
+
+ person = persons.values()[0]
+
+ # Get site information
+ sites = Sites(self.api, [site_id_or_login_base])
+ if not sites:
+ raise PLCInvalidArgument, "No such site"
+
+ site = sites.values()[0]
+
+ if site['site_id'] not in person['site_ids']:
+ site.add_person(person)
+
+ return 1
--- /dev/null
+from PLC.Faults import *
+from PLC.Method import Method
+from PLC.Parameter import Parameter, Mixed
+from PLC.Persons import Person, Persons
+from PLC.Auth import PasswordAuth
+from PLC.Roles import Roles
+
+class AddRoleToPerson(Method):
+ """
+ Grants the specified role to the person.
+
+ PIs can only grant the tech and user roles to users and techs at
+ their sites. ins can grant any role to any user.
+
+ Returns 1 if successful, faults otherwise.
+ """
+
+ roles = ['admin', 'pi']
+
+ accepts = [
+ PasswordAuth(),
+ Mixed(Person.fields['person_id'],
+ Person.fields['email']),
+ Mixed(Parameter(int, "Role identifier"),
+ Parameter(str, "Role name"))
+ ]
+
+ returns = Parameter(int, '1 if successful')
+
+ def call(self, auth, person_id_or_email, role_id_or_name):
+ # Get all roles
+ roles = Roles(self.api)
+ if role_id_or_name not in roles:
+ raise PLCInvalidArgument, "Invalid role identifier or name"
+
+ if isinstance(role_id_or_name, int):
+ role_id = role_id_or_name
+ else:
+ role_id = roles[role_id_or_name]
+
+ # Get account information
+ persons = Persons(self.api, [person_id_or_email])
+ if not persons:
+ raise PLCInvalidArgument, "No such account"
+
+ person = persons.values()[0]
+
+ # Authenticated function
+ assert self.caller is not None
+
+ # Check if we can update this account
+ if not self.caller.can_update(person):
+ raise PLCPermissionDenied, "Not allowed to update specified account"
+
+ # Can only grant lesser (higher) roles to others
+ if 'admin' not in self.caller['roles'] and \
+ role_id <= min(self.caller['role_ids']):
+ raise PLCInvalidArgument, "Not allowed to grant that role"
+
+ if role_id not in person['role_ids']:
+ person.add_role(role_id)
+
+ return 1
--- /dev/null
+from PLC.Faults import *
+from PLC.Method import Method
+from PLC.Parameter import Parameter, Mixed
+from PLC.Sites import Site, Sites
+from PLC.Auth import PasswordAuth
+
+class AddSite(Method):
+ """
+ Adds a new site, and creates a node group for that site. Any
+ fields specified in optional_vals are used, otherwise defaults are
+ used.
+
+ Returns the new site_id (> 0) if successful, faults otherwise.
+ """
+
+ roles = ['admin']
+
+ can_update = lambda (field, value): field in \
+ ['is_public', 'latitude', 'longitude', 'url',
+ 'organization_id', 'ext_consortium_id']
+ update_fields = dict(filter(can_update, Site.fields.items()))
+
+ accepts = [
+ PasswordAuth(),
+ Site.fields['name'],
+ Site.fields['abbreviated_name'],
+ Site.fields['login_base'],
+ update_fields
+ ]
+
+ returns = Parameter(int, 'New site_id (> 0) if successful')
+
+ def call(self, auth, name, abbreviated_name, login_base, optional_vals = {}):
+ if filter(lambda field: field not in self.update_fields, optional_vals):
+ raise PLCInvalidArgument, "Invalid field specified"
+
+ site = Site(self.api, optional_vals)
+ site['name'] = name
+ site['abbreviated_name'] = abbreviated_name
+ site['login_base'] = login_base
+ site.sync()
+
+ return site['site_id']
--- /dev/null
+from PLC.Faults import *
+from PLC.Method import Method
+from PLC.Parameter import Parameter, Mixed
+from PLC.Auth import PasswordAuth
+from PLC.Nodes import Node, Nodes
+
+class DeleteNode(Method):
+ """
+ Mark an existing node as deleted.
+
+ PIs and techs may only delete nodes at their own sites. ins may
+ delete nodes at any site.
+
+ Returns 1 if successful, faults otherwise.
+ """
+
+ roles = ['admin', 'pi', 'tech']
+
+ accepts = [
+ PasswordAuth(),
+ Mixed(Node.fields['node_id'],
+ Node.fields['hostname'])
+ ]
+
+ returns = Parameter(int, '1 if successful')
+
+ def call(self, auth, node_id_or_hostname):
+ # Get account information
+ nodes = Nodes(self.api, [node_id_or_hostname])
+ if not nodes:
+ raise PLCInvalidArgument, "No such node"
+
+ node = nodes.values()[0]
+
+ # If we are not an admin, make sure that the caller is a
+ # member of the site at which the node is located.
+ if 'admin' not in self.caller['roles']:
+ # Authenticated function
+ assert self.caller is not None
+
+ if node['site_id'] not in self.caller['site_ids']:
+ raise PLCPermissionDenied, "Not allowed to delete nodes from specified site"
+
+ node.delete()
+
+ return 1
--- /dev/null
+from PLC.Faults import *
+from PLC.Method import Method
+from PLC.Parameter import Parameter, Mixed
+from PLC.Auth import PasswordAuth
+from PLC.NodeGroups import NodeGroup, NodeGroups
+
+class DeleteNodeGroup(Method):
+ """
+ Delete an existing Node Group.
+
+ ins may delete any node group
+
+ Returns 1 if successful, faults otherwise.
+ """
+
+ roles = ['admin']
+
+ accepts = [
+ PasswordAuth(),
+ Mixed(NodeGroup.fields['nodegroup_id'],
+ NodeGroup.fields['name'])
+ ]
+
+ returns = Parameter(int, '1 if successful')
+
+ def call(self, auth, node_group_id_or_name):
+ # Get account information
+ nodegroups = NodeGroups(self.api, [node_group_id_or_name])
+ if not nodegroups:
+ raise PLCInvalidArgument, "No such node group"
+
+ nodegroup = nodegroups.values()[0]
+
+ nodegroup.delete()
+
+ return 1
--- /dev/null
+from PLC.Faults import *
+from PLC.Method import Method
+from PLC.Parameter import Parameter, Mixed
+from PLC.Auth import PasswordAuth
+from PLC.Nodes import Node, Nodes
+from PLC.NodeNetworks import NodeNetwork, NodeNetworks
+
+class DeleteNodeNetwork(Method):
+ """
+ Delete an existing Node Network. Nodenetwork_id must be associated to
+ node_id and not be associated with a different node.
+
+ ins may delete any node network. PIs and techs can only delete
+ nodenetworks for thier nodes.
+
+ Returns 1 if successful, faults otherwise.
+ """
+
+ roles = ['admin', 'pi', 'tech']
+
+ accepts = [
+ PasswordAuth(),
+ Mixed(Node.fields['node_id'],
+ Node.fields['hostname']),
+ Mixed(NodeNetwork.fields['nodenetwork_id'],
+ NodeNetwork.fields['hostname'])
+ ]
+
+ returns = Parameter(int, '1 if successful')
+
+ def call(self, auth, node_id_or_hostname, nodenetwork_id_or_hostname):
+ # Get node network information
+ nodenetworks = NodeNetworks(self.api, [nodenetwork_id_or_hostname]).values()
+ if not nodenetworks:
+ raise PLCInvalidArgument, "No such node network"
+ nodenetwork = nodenetworks[0]
+
+ # Get node information
+ nodes = Nodes(self.api, [node_id_or_hostname]).values()
+ if not nodes:
+ raise PLCInvalidArgument, "No such node"
+ node = nodes[0]
+
+ # Check if node network is associated with specified node
+ if node['node_id'] != nodenetwork['node_id'] or \
+ nodenetwork['nodenetwork_id'] not in node['nodenetwork_ids']:
+ raise PLCInvalidArgument, "Node network not associated with node"
+
+ # Authenticated functino
+ assert self.caller is not None
+
+ # If we are not an admin, make sure that the caller is a
+ # member of the site at which the node is located.
+ if 'admin' not in self.caller['roles']:
+ if node['site_id'] not in self.caller['site_ids']:
+ raise PLCPermissionDenied, "Not allowed to delete this node network"
+
+ nodenetwork.delete()
+
+ return 1
--- /dev/null
+from PLC.Faults import *
+from PLC.Method import Method
+from PLC.Parameter import Parameter, Mixed
+from PLC.Persons import Person, Persons
+from PLC.Auth import PasswordAuth
+
+class DeletePerson(Method):
+ """
+ Mark an existing account as deleted.
+
+ Users and techs can only delete themselves. PIs can only delete
+ themselves and other non-PIs at their sites. ins can delete
+ anyone.
+
+ Returns 1 if successful, faults otherwise.
+ """
+
+ roles = ['admin', 'pi', 'user', 'tech']
+
+ accepts = [
+ PasswordAuth(),
+ Mixed(Person.fields['person_id'],
+ Person.fields['email'])
+ ]
+
+ returns = Parameter(int, '1 if successful')
+
+ def call(self, auth, person_id_or_email):
+ # Get account information
+ persons = Persons(self.api, [person_id_or_email])
+ if not persons:
+ raise PLCInvalidArgument, "No such account"
+
+ person = persons.values()[0]
+
+ # Authenticated function
+ assert self.caller is not None
+
+ # Check if we can update this account
+ if not self.caller.can_update(person):
+ raise PLCPermissionDenied, "Not allowed to delete specified account"
+
+ person.delete()
+
+ return 1
--- /dev/null
+from PLC.Faults import *
+from PLC.Method import Method
+from PLC.Parameter import Parameter, Mixed
+from PLC.Sites import Site, Sites
+from PLC.Persons import Person, Persons
+from PLC.Nodes import Node, Nodes
+from PLC.PCUs import PCU, PCUs
+from PLC.Auth import PasswordAuth
+
+class DeleteSite(Method):
+ """
+ Mark an existing site as deleted. The accounts of people who are
+ not members of at least one other non-deleted site will also be
+ marked as deleted. Nodes, PCUs, and slices associated with the
+ site will be deleted.
+
+ Returns 1 if successful, faults otherwise.
+ """
+
+ roles = ['admin']
+
+ accepts = [
+ PasswordAuth(),
+ Mixed(Site.fields['site_id'],
+ Site.fields['login_base'])
+ ]
+
+ returns = Parameter(int, '1 if successful')
+
+ def call(self, auth, site_id_or_login_base):
+ # Get account information
+ sites = Sites(self.api, [site_id_or_login_base])
+ if not sites:
+ raise PLCInvalidArgument, "No such site"
+
+ site = sites.values()[0]
+ site.delete()
+
+ return 1
--- /dev/null
+from PLC.Faults import *
+from PLC.Method import Method
+from PLC.Parameter import Parameter, Mixed
+from PLC.Auth import PasswordAuth
+from PLC.NodeGroups import NodeGroup, NodeGroups
+
+class GetNodeGroups(Method):
+ """
+ Returns an array of structs containing details about all node
+ groups. If nodegroup_id_or_name_list is specified, only the
+ specified node groups will be queried.
+ """
+
+ roles = ['admin', 'pi', 'user', 'tech']
+
+ accepts = [
+ PasswordAuth(),
+ [Mixed(NodeGroup.fields['nodegroup_id'],
+ NodeGroup.fields['name'])]
+ ]
+
+ returns = [NodeGroup.fields]
+
+ def call(self, auth, nodegroup_id_or_name_list = None):
+ # Get node group details
+ nodegroups = NodeGroups(self.api, nodegroup_id_or_name_list).values()
+
+ # Filter out undesired or None fields (XML-RPC cannot marshal
+ # None) and turn each nodegroup into a real dict.
+ valid_return_fields_only = lambda (key, value): value is not None
+ nodegroups = [dict(filter(valid_return_fields_only, nodegroup.items())) \
+ for nodegroup in nodegroups]
+
+ return nodegroups
--- /dev/null
+from PLC.Faults import *
+from PLC.Method import Method
+from PLC.Parameter import Parameter, Mixed
+from PLC.NodeNetworks import NodeNetwork, NodeNetworks
+from PLC.Auth import PasswordAuth
+
+class GetNodeNetworkBandwidthLimits(Method):
+ """
+ Returns an array of all the valid bandwith limits for node networks.
+ """
+
+ roles = ['admin', 'pi', 'user', 'tech']
+
+ accepts = [
+ PasswordAuth()
+ ]
+
+ returns = [NodeNetwork.fields['bwlimit']]
+
+ def call(self, auth):
+ return NodeNetwork.bwlimits
--- /dev/null
+from PLC.Faults import *
+from PLC.Method import Method
+from PLC.Parameter import Parameter, Mixed
+from PLC.NodeNetworks import NodeNetwork, NodeNetworks
+from PLC.Nodes import Node, Nodes
+from PLC.Auth import PasswordAuth
+
+class GetNodeNetworks(Method):
+ """
+ Returns all the networks this node is connected to, as an array of
+ structs.
+ """
+
+ roles = ['admin', 'pi', 'user', 'tech']
+
+ accepts = [
+ PasswordAuth(),
+ Mixed(Node.fields['node_id'],
+ Node.fields['hostname'])
+ ]
+
+ returns = [NodeNetwork.fields]
+
+ def call(self, auth, node_id_or_hostname):
+ # Authenticated function
+ assert self.caller is not None
+
+ # Get node information
+ nodes = Nodes(self.api, [node_id_or_hostname]).values()
+ if not nodes:
+ raise PLCInvalidArgument, "No such node"
+ node = nodes[0]
+
+ # Get node networks for this node
+ if node['nodenetwork_ids']:
+ nodenetworks = NodeNetworks(self.api, node['nodenetwork_ids']).values()
+ else:
+ nodenetworks = []
+
+ # Filter out undesired or None fields (XML-RPC cannot marshal
+ # None) and turn each node into a real dict.
+ valid_return_fields_only = lambda (key, value): value is not None
+ nodenetworks = [dict(filter(valid_return_fields_only, nodenetwork.items())) \
+ for nodenetwork in nodenetworks]
+
+ return nodenetworks
--- /dev/null
+import os
+
+from PLC.Faults import *
+from PLC.Method import Method
+from PLC.Parameter import Parameter, Mixed
+from PLC.Nodes import Node, Nodes
+from PLC.Auth import PasswordAuth
+
+class GetNodes(Method):
+ """
+ Return an array of dictionaries containing details about the
+ specified nodes.
+
+ If return_fields is specified, only the specified fields will be
+ returned. Only admins may retrieve certain fields. Otherwise, the
+ default set of fields returned is:
+
+ """
+
+ roles = ['admin', 'pi', 'user', 'tech']
+
+ accepts = [
+ PasswordAuth(),
+ [Mixed(Node.fields['node_id'],
+ Node.fields['hostname'])],
+ Parameter([str], 'List of fields to return')
+ ]
+
+ returns = [Node.fields]
+
+ def __init__(self, *args, **kwds):
+ Method.__init__(self, *args, **kwds)
+ # Update documentation with list of default fields returned
+ self.__doc__ += os.linesep.join(Node.fields.keys())
+
+ def call(self, auth, node_id_or_hostname_list = None, return_fields = None):
+ # Authenticated function
+ assert self.caller is not None
+
+ valid_fields = Node.fields.keys()
+
+ # Remove admin only fields
+ if 'admin' not in self.caller['roles']:
+ for key in ['boot_nonce', 'key', 'session', 'root_person_ids']:
+ valid_fields.remove(key)
+
+ # Make sure that only valid fields are specified
+ if return_fields is None:
+ return_fields = valid_fields
+ elif filter(lambda field: field not in valid_fields, return_fields):
+ raise PLCInvalidArgument, "Invalid return field specified"
+
+ # Get node information
+ nodes = Nodes(self.api, node_id_or_hostname_list).values()
+
+ # Filter out undesired or None fields (XML-RPC cannot marshal
+ # None) and turn each node into a real dict.
+ valid_return_fields_only = lambda (key, value): \
+ key in return_fields and value is not None
+ nodes = [dict(filter(valid_return_fields_only, node.items())) \
+ for node in nodes]
+
+ return nodes
--- /dev/null
+import os
+
+from PLC.Faults import *
+from PLC.Method import Method
+from PLC.Parameter import Parameter, Mixed
+from PLC.Persons import Person, Persons
+from PLC.Auth import PasswordAuth
+
+class GetPersons(Method):
+ """
+ Return an array of dictionaries containing details about the
+ specified accounts.
+
+ ins may retrieve details about all accounts by not specifying
+ person_id_or_email_list or by specifying an empty list. Users and
+ techs may only retrieve details about themselves. PIs may retrieve
+ details about themselves and others at their sites.
+
+ If return_fields is specified, only the specified fields will be
+ returned, if set. Otherwise, the default set of fields returned is:
+
+ """
+
+ roles = ['admin', 'pi', 'user', 'tech']
+
+ accepts = [
+ PasswordAuth(),
+ [Mixed(Person.fields['person_id'],
+ Person.fields['email'])],
+ Parameter([str], 'List of fields to return')
+ ]
+
+ # Filter out password field
+ can_return = lambda (field, value): field not in ['password']
+ return_fields = dict(filter(can_return, Person.fields.items()))
+ returns = [return_fields]
+
+ def __init__(self, *args, **kwds):
+ Method.__init__(self, *args, **kwds)
+ # Update documentation with list of default fields returned
+ self.__doc__ += os.linesep.join(self.return_fields.keys())
+
+ def call(self, auth, person_id_or_email_list = None, return_fields = None):
+ # Make sure that only valid fields are specified
+ if return_fields is None:
+ return_fields = self.return_fields
+ elif filter(lambda field: field not in self.return_fields, return_fields):
+ raise PLCInvalidArgument, "Invalid return field specified"
+
+ # Authenticated function
+ assert self.caller is not None
+
+ # Only admins can not specify person_id_or_email_list or
+ # specify an empty list.
+ if not person_id_or_email_list and 'admin' not in self.caller['roles']:
+ raise PLCInvalidArgument, "List of accounts to retrieve not specified"
+
+ # Get account information
+ persons = Persons(self.api, person_id_or_email_list)
+
+ # Filter out accounts that are not viewable and turn into list
+ persons = filter(self.caller.can_view, persons.values())
+
+ # Filter out undesired or None fields (XML-RPC cannot marshal
+ # None) and turn each person into a real dict.
+ valid_return_fields_only = lambda (key, value): \
+ key in return_fields and value is not None
+ persons = [dict(filter(valid_return_fields_only, person.items())) \
+ for person in persons]
+
+ return persons
--- /dev/null
+import os
+
+from PLC.Method import Method
+from PLC.Parameter import Parameter, Mixed
+from PLC.Auth import PasswordAuth
+from PLC.Sites import Site, Sites
+
+class GetSites(Method):
+ """
+ Return an array of structs containing details about all sites. If
+ site_id_list is specified, only the specified sites will be
+ queried.
+
+ If return_fields is specified, only the specified fields will be
+ returned, if set. Otherwise, the default set of fields returned is:
+
+ """
+
+ roles = ['admin', 'pi', 'user', 'tech']
+
+ accepts = [
+ PasswordAuth(),
+ [Mixed(Site.fields['site_id'],
+ Site.fields['login_base'])],
+ Parameter([str], 'List of fields to return')
+ ]
+
+ returns = [Site.fields]
+
+ def __init__(self, *args, **kwds):
+ Method.__init__(self, *args, **kwds)
+ # Update documentation with list of default fields returned
+ self.__doc__ += os.linesep.join(Site.fields.keys())
+
+ def call(self, auth, site_id_or_login_base_list = None, return_fields = None):
+ # Make sure that only valid fields are specified
+ if return_fields is None:
+ return_fields = Site.fields
+ elif filter(lambda field: field not in Site.fields, return_fields):
+ raise PLCInvalidArgument, "Invalid return field specified"
+
+ # Get site information
+ sites = Sites(self.api, site_id_or_login_base_list)
+
+ # Filter out undesired or None fields (XML-RPC cannot marshal
+ # None) and turn each site into a real dict.
+ valid_return_fields_only = lambda (key, value): \
+ key in return_fields and value is not None
+ sites = [dict(filter(valid_return_fields_only, site.items())) \
+ for site in sites.values()]
+
+ return sites
--- /dev/null
+from PLC.Faults import *
+from PLC.Method import Method
+from PLC.Parameter import Parameter, Mixed
+from PLC.NodeGroups import NodeGroup, NodeGroups
+from PLC.Nodes import Node, Nodes
+from PLC.Auth import PasswordAuth
+
+class RemoveNodeFromNodeGroup(Method):
+ """
+ Removes a node from the specified node group.
+
+ Returns 1 if successful, faults otherwise.
+ """
+
+ roles = ['admin']
+
+ accepts = [
+ PasswordAuth(),
+ Mixed(NodeGroup.fields['nodegroup_id'],
+ NodeGroup.fields['name']),
+ Mixed(Node.fields['node_id'],
+ Node.fields['hostname'])
+ ]
+
+ returns = Parameter(int, '1 if successful')
+
+ def call(self, auth, nodegroup_id_or_name, node_id_or_hostname):
+ # Get node info
+ nodes = Nodes(self.api, [node_id_or_hostname])
+ if not nodes:
+ raise PLCInvalidArgument, "No such node"
+
+ node = nodes.values()[0]
+
+ # Get nodegroup info
+ nodegroups = NodeGroups(self.api, [nodegroup_id_or_name])
+ if not nodegroups:
+ raise PLCInvalidArgument, "No such nodegroup"
+
+ nodegroup = nodegroups.values()[0]
+
+ # Remove node from nodegroup
+ if node['node_id'] in nodegroup['node_ids']:
+ nodegroup.remove_node(node)
+
+ return 1
--- /dev/null
+from PLC.Faults import *
+from PLC.Method import Method
+from PLC.Parameter import Parameter, Mixed
+from PLC.Persons import Person, Persons
+from PLC.Sites import Site, Sites
+from PLC.Auth import PasswordAuth
+
+class RemovePersonFromSite(Method):
+ """
+ Removes the specified person from the specified site. If the
+ person is not a member of the specified site, no error is
+ returned.
+
+ Returns 1 if successful, faults otherwise.
+ """
+
+ roles = ['admin']
+
+ accepts = [
+ PasswordAuth(),
+ Mixed(Person.fields['person_id'],
+ Person.fields['email']),
+ Mixed(Site.fields['site_id'],
+ Site.fields['login_base'])
+ ]
+
+ returns = Parameter(int, '1 if successful')
+
+ def call(self, auth, person_id_or_email, site_id_or_login_base):
+ # Get account information
+ persons = Persons(self.api, [person_id_or_email])
+ if not persons:
+ raise PLCInvalidArgument, "No such account"
+
+ person = persons.values()[0]
+
+ # Get site information
+ sites = Sites(self.api, [site_id_or_login_base])
+ if not sites:
+ raise PLCInvalidArgument, "No such site"
+
+ site = sites.values()[0]
+
+ if site['site_id'] in person['site_ids']:
+ site.remove_person(person)
+
+ return 1
--- /dev/null
+from PLC.Faults import *
+from PLC.Method import Method
+from PLC.Parameter import Parameter, Mixed
+from PLC.Persons import Person, Persons
+from PLC.Auth import PasswordAuth
+from PLC.Roles import Roles
+
+class RemoveRoleFromPerson(Method):
+ """
+ Revokes the specified role from the person.
+
+ PIs can only revoke the tech and user roles from users and techs
+ at their sites. ins can revoke any role from any user.
+
+ Returns 1 if successful, faults otherwise.
+ """
+
+ roles = ['admin', 'pi']
+
+ accepts = [
+ PasswordAuth(),
+ Mixed(Person.fields['person_id'],
+ Person.fields['email']),
+ Parameter(int, 'Role ID')
+ ]
+
+ returns = Parameter(int, '1 if successful')
+
+ def call(self, auth, person_id_or_email, role_id):
+ # Get all roles
+ roles = Roles(self.api)
+ if role_id not in roles:
+ raise PLCInvalidArgument, "Invalid role ID"
+
+ # Get account information
+ persons = Persons(self.api, [person_id_or_email])
+ if not persons:
+ raise PLCInvalidArgument, "No such account"
+
+ person = persons.values()[0]
+
+ # Authenticated function
+ assert self.caller is not None
+
+ # Check if we can update this account
+ if not self.caller.can_update(person):
+ raise PLCPermissionDenied, "Not allowed to update specified account"
+
+ # Can only revoke lesser (higher) roles from others
+ if 'admin' not in self.caller['roles'] and \
+ role_id <= min(self.caller['role_ids']):
+ raise PLCPermissionDenied, "Not allowed to revoke that role"
+
+ if role_id in person['role_ids']:
+ person.remove_role(role_id)
+
+ return 1
--- /dev/null
+from PLC.Faults import *
+from PLC.Method import Method
+from PLC.Parameter import Parameter, Mixed
+from PLC.Persons import Person, Persons
+from PLC.Sites import Site, Sites
+from PLC.Auth import PasswordAuth
+
+class SetPersonPrimarySite(Method):
+ """
+ Makes the specified site the person's primary site. The person
+ must already be a member of the site.
+
+ ins may update anyone. All others may only update themselves.
+ """
+
+ roles = ['admin', 'pi', 'user', 'tech']
+
+ accepts = [
+ PasswordAuth(),
+ Mixed(Person.fields['person_id'],
+ Person.fields['email']),
+ Mixed(Site.fields['site_id'],
+ Site.fields['login_base'])
+ ]
+
+ returns = Parameter(int, '1 if successful')
+
+ def call(self, auth, person_id_or_email, site_id_or_login_base):
+ # Get account information
+ persons = Persons(self.api, [person_id_or_email])
+ if not persons:
+ raise PLCInvalidArgument, "No such account"
+
+ person = persons.values()[0]
+
+ # Authenticated function
+ assert self.caller is not None
+
+ # Non-admins can only update their own primary site
+ if 'admin' not in self.caller['roles'] and \
+ self.caller['person_id'] != person['person_id']:
+ raise PLCPermissionDenied, "Not allowed to update specified account"
+
+ # Get site information
+ sites = Sites(self.api, [site_id_or_login_base])
+ if not sites:
+ raise PLCInvalidArgument, "No such site"
+
+ site = sites.values()[0]
+
+ if site['site_id'] not in person['site_ids']:
+ raise PLCInvalidArgument, "Not a member of the specified site"
+
+ person.set_primary_site(site)
+
+ return 1
--- /dev/null
+from PLC.Faults import *
+from PLC.Method import Method
+from PLC.Parameter import Parameter, Mixed
+from PLC.Nodes import Node, Nodes
+from PLC.Auth import PasswordAuth
+
+class UpdateNode(Method):
+ """
+ Updates a node. Only the fields specified in update_fields are
+ updated, all other fields are left untouched.
+
+ To remove a value without setting a new one in its place (for
+ example, to remove an address from the node), specify -1 for int
+ and double fields and 'null' for string fields. hostname and
+ boot_state cannot be unset.
+
+ PIs and techs can only update the nodes at their sites.
+
+ Returns 1 if successful, faults otherwise.
+ """
+
+ roles = ['admin', 'pi', 'tech']
+
+ can_update = lambda (field, value): field in \
+ ['hostname', 'boot_state', 'model', 'version']
+ update_fields = dict(filter(can_update, Node.fields.items()))
+
+ accepts = [
+ PasswordAuth(),
+ Mixed(Node.fields['node_id'],
+ Node.fields['hostname']),
+ update_fields
+ ]
+
+ returns = Parameter(int, '1 if successful')
+
+ def call(self, auth, node_id_or_hostname, update_fields):
+ if filter(lambda field: field not in self.update_fields, update_fields):
+ raise PLCInvalidArgument, "Invalid field specified"
+
+ # XML-RPC cannot marshal None, so we need special values to
+ # represent "unset".
+ for key, value in update_fields.iteritems():
+ if value == -1 or value == "null":
+ if key in ['hostname', 'boot_state']:
+ raise PLCInvalidArgument, "hostname and boot_state cannot be unset"
+ update_fields[key] = None
+
+ # Get account information
+ nodes = Nodes(self.api, [node_id_or_hostname])
+ if not nodes:
+ raise PLCInvalidArgument, "No such node"
+
+ node = nodes.values()[0]
+
+ # Authenticated function
+ assert self.caller is not None
+
+ # If we are not an admin, make sure that the caller is a
+ # member of the site at which the node is located.
+ if 'admin' not in self.caller['roles']:
+ if node['site_id'] not in self.caller['site_ids']:
+ raise PLCPermissionDenied, "Not allowed to delete nodes from specified site"
+
+ node.update(update_fields)
+ node.sync()
+
+ return 1
--- /dev/null
+from PLC.Faults import *
+from PLC.Method import Method
+from PLC.Parameter import Parameter, Mixed
+from PLC.NodeGroups import NodeGroup, NodeGroups
+from PLC.Auth import PasswordAuth
+
+class UpdateNodeGroup(Method):
+ """
+ Updates a custom node group.
+
+ Returns 1 if successful, faults otherwise.
+ """
+
+ roles = ['admin']
+
+ accepts = [
+ PasswordAuth(),
+ Mixed(NodeGroup.fields['nodegroup_id'],
+ NodeGroup.fields['name']),
+ NodeGroup.fields['name'],
+ NodeGroup.fields['description']
+ ]
+
+ returns = Parameter(int, '1 if successful')
+
+ def call(self, auth, nodegroup_id_or_name, name, description):
+ # Get nodegroup information
+ nodegroups = NodeGroups(self.api, [nodegroup_id_or_name])
+ if not nodegroups:
+ raise PLCInvalidArgument, "No such nodegroup"
+
+ nodegroup = nodegroups.values()[0]
+
+ # Modify node group
+ update_fields = {
+ 'name': name,
+ 'description': description
+ }
+
+ nodegroup.update(update_fields)
+ nodegroup.sync()
+
+ return 1
--- /dev/null
+
+from PLC.Faults import *
+from PLC.Method import Method
+from PLC.Parameter import Parameter, Mixed
+from PLC.Nodes import Node, Nodes
+from PLC.NodeNetworks import NodeNetwork, NodeNetworks
+from PLC.Auth import PasswordAuth
+
+class UpdateNodeNetwork(Method):
+ """
+ Updates an existing node network. Any values specified in update_fields
+ are used, otherwise defaults are used. Acceptable values for method are
+ dhcp and static. If type is static, the parameter update_fields must
+ be present and ip, gateway, network, broadcast, netmask, and dns1 must
+ all be specified. If type is dhcp, these parameters, even if
+ specified, are ignored.
+
+ PIs and techs may only update networks associated with their own
+ nodes. ins may update any node network.
+
+ Returns 1 if successful, faults otherwise.
+ """
+
+ roles = ['admin', 'pi', 'tech']
+
+ can_update = lambda (field, value): field not in \
+ ['nodenetwork_id']
+ update_fields = dict(filter(can_update, NodeNetwork.fields.items()))
+
+ accepts = [
+ PasswordAuth(),
+ Mixed(NodeNetwork.fields['nodenetwork_id'],
+ NodeNetwork.fields['hostname']),
+ update_fields
+ ]
+
+ returns = Parameter(int, '1 if successful')
+
+ def call(self, auth, nodenetwork_id_or_hostname, update_fields):
+ # Check for invalid fields
+ if filter(lambda field: field not in self.update_fields, update_fields):
+ raise PLCInvalidArgument, "Invalid fields specified"
+
+ # XML-RPC cannot marshal None, so we need special values to
+ # represent "unset".
+ for key, value in update_fields.iteritems():
+ if value == -1 or value == "null":
+ if key in ['method', 'type', 'mac', 'ip', 'bwlimit']:
+ raise PLCInvalidArgument, "%s cannot be unset" % key
+ update_fields[key] = None
+
+ # Get node network information
+ nodenetworks = NodeNetworks(self.api, [nodenetwork_id_or_hostname]).values()
+ if not nodenetworks:
+ raise PLCInvalidArgument, "No such node network"
+
+ nodenetwork = nodenetworks[0]
+
+ # Authenticated function
+ assert self.caller is not None
+
+ # If we are not an admin, make sure that the caller is a
+ # member of the site where the node exists.
+ if 'admin' not in self.caller['roles']:
+ nodes = Nodes(self.api, [nodenetwork['node_id']]).values()
+ if not nodes:
+ raise PLCPermissionDenied, "Node network is not associated with a node"
+ node = nodes[0]
+ if node['site_id'] not in self.caller['site_ids']:
+ raise PLCPermissionDenied, "Not allowed to update node network"
+
+ # Update node network
+ nodenetwork.update(update_fields)
+ nodenetwork.sync()
+
+ return 1
--- /dev/null
+from PLC.Faults import *
+from PLC.Method import Method
+from PLC.Parameter import Parameter, Mixed
+from PLC.Persons import Person, Persons
+from PLC.Auth import PasswordAuth
+
+class UpdatePerson(Method):
+ """
+ Updates a person. Only the fields specified in update_fields are
+ updated, all other fields are left untouched.
+
+ To remove a value without setting a new one in its place (for
+ example, to remove an address from the person), specify -1 for int
+ and double fields and 'null' for string fields. first_name and
+ last_name cannot be unset.
+
+ Users and techs can only update themselves. PIs can only update
+ themselves and other non-PIs at their sites.
+
+ Returns 1 if successful, faults otherwise.
+ """
+
+ roles = ['admin', 'pi', 'user', 'tech']
+
+ can_update = lambda (field, value): field in \
+ ['first_name', 'last_name', 'title', 'email',
+ 'password', 'phone', 'url', 'bio', 'accepted_aup']
+ update_fields = dict(filter(can_update, Person.fields.items()))
+
+ accepts = [
+ PasswordAuth(),
+ Mixed(Person.fields['person_id'],
+ Person.fields['email']),
+ update_fields
+ ]
+
+ returns = Parameter(int, '1 if successful')
+
+ def call(self, auth, person_id_or_email, update_fields):
+ if filter(lambda field: field not in self.update_fields, update_fields):
+ raise PLCInvalidArgument, "Invalid field specified"
+
+ # XML-RPC cannot marshal None, so we need special values to
+ # represent "unset".
+ for key, value in update_fields.iteritems():
+ if value == -1 or value == "null":
+ if key in ['first_name', 'last_name']:
+ raise PLCInvalidArgument, "first_name and last_name cannot be unset"
+ update_fields[key] = None
+
+ # Get account information
+ persons = Persons(self.api, [person_id_or_email])
+ if not persons:
+ raise PLCInvalidArgument, "No such account"
+
+ person = persons.values()[0]
+
+ # Authenticated function
+ assert self.caller is not None
+
+ # Check if we can update this account
+ if not self.caller.can_update(person):
+ raise PLCPermissionDenied, "Not allowed to update specified account"
+
+ person.update(update_fields)
+ person.sync()
+
+ return 1
--- /dev/null
+from PLC.Faults import *
+from PLC.Method import Method
+from PLC.Parameter import Parameter, Mixed
+from PLC.Sites import Site, Sites
+from PLC.Auth import PasswordAuth
+
+class UpdateSite(Method):
+ """
+ Updates a site. Only the fields specified in update_fields are
+ updated, all other fields are left untouched.
+
+ To remove a value without setting a new one in its place (for
+ example, to remove an address from the node), specify -1 for int
+ and double fields and 'null' for string fields. hostname and
+ boot_state cannot be unset.
+
+ PIs can only update sites they are a member of. Only admins can
+ update max_slices.
+
+ Returns 1 if successful, faults otherwise.
+ """
+
+ roles = ['admin', 'pi']
+
+ can_update = lambda (field, value): field in \
+ ['name', 'abbreviated_name',
+ 'is_public', 'latitude', 'longitude', 'url',
+ 'max_slices', 'max_slivers']
+ update_fields = dict(filter(can_update, Site.fields.items()))
+
+ accepts = [
+ PasswordAuth(),
+ Mixed(Site.fields['site_id'],
+ Site.fields['login_base']),
+ update_fields
+ ]
+
+ returns = Parameter(int, '1 if successful')
+
+ def call(self, auth, site_id_or_login_base, update_fields):
+ # Check for invalid fields
+ if filter(lambda field: field not in self.update_fields, update_fields):
+ raise PLCInvalidArgument, "Invalid field specified"
+
+ # XML-RPC cannot marshal None, so we need special values to
+ # represent "unset".
+ for key, value in update_fields.iteritems():
+ if value == -1 or value == "null":
+ if key not in ['latitude', 'longitude', 'url']:
+ raise PLCInvalidArgument, "%s cannot be unset" % key
+ update_fields[key] = None
+
+ # Get site information
+ sites = Sites(self.api, [site_id_or_login_base])
+ if not sites:
+ raise PLCInvalidArgument, "No such site"
+
+ site = sites.values()[0]
+
+ # Authenticated function
+ assert self.caller is not None
+
+ # If we are not an admin, make sure that the caller is a
+ # member of the site.
+ if 'admin' not in self.caller['roles']:
+ if site['site_id'] not in self.caller['site_ids']:
+ raise PLCPermissionDenied, "Not allowed to modify specified site"
+
+ if 'max_slices' or 'max_slivers' in update_fields:
+ raise PLCInvalidArgument, "Only admins can update max_slices and max_slivers"
+
+ site.update(update_fields)
+ site.sync()
+
+ return 1