Initial checkin of new API implementation
authorTony Mack <tmack@cs.princeton.edu>
Fri, 15 Sep 2006 20:31:06 +0000 (20:31 +0000)
committerTony Mack <tmack@cs.princeton.edu>
Fri, 15 Sep 2006 20:31:06 +0000 (20:31 +0000)
PLC/Methods/AdmAddNodeNetwork.py [new file with mode: 0644]
PLC/Methods/AdmDeleteNodeNetwork.py [new file with mode: 0644]
PLC/Methods/AdmGetAllNodeNetworkBandwidthLimits.py [new file with mode: 0644]
PLC/Methods/AdmGetAllNodeNetworks.py [new file with mode: 0644]
PLC/Methods/AdmGetSitePersons.py [new file with mode: 0644]
PLC/Methods/AdmUpdateNodeNetwork.py [new file with mode: 0644]
PLC/Methods/AdmUpdateSite.py [new file with mode: 0644]

diff --git a/PLC/Methods/AdmAddNodeNetwork.py b/PLC/Methods/AdmAddNodeNetwork.py
new file mode 100644 (file)
index 0000000..037d54a
--- /dev/null
@@ -0,0 +1,76 @@
+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.Sites import Site, Sites
+from PLC.Auth import PasswordAuth
+
+class AdmAddNodeNetwork(Method):
+    """
+    Adds a new newtwork for a node. Any values specified in optional_vals are used,
+    otherwise defaults are used. Acceptable values for method are dhcp, static, 
+    proxy, tap, and ipmi. Acceptable value for type is ipv4. If type is static, 
+    the parameter optional_vals 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. Returns the new nodenetwork_id (>0) if successful.
+
+    PIs and techs may only add networks to their own nodes. Admins may
+    add networks to any node.
+
+    Returns the new nodenetwork_id (> 0) if successful, faults otherwise.
+    """
+
+    roles = ['admin', 'pi', 'tech']
+
+    cant_update = lambda (field, value): field not in \
+                 ['nodenetwork_id']
+    update_fields = dict(filter(cant_update, NodeNetwork.all_fields.items()))
+
+    accepts = [
+        PasswordAuth(),
+        NodeNetwork.all_fields['node_id'],
+        NodeNetwork.all_fields['method'],
+        NodeNetwork.all_fields['type'],
+        update_fields
+        ]
+
+    returns = Parameter(int, '1 if successful')
+
+    def call(self, auth, node_id, method, type, optional_vals = {}):
+        if filter(lambda field: field not in self.update_fields, optional_vals):
+            raise PLCInvalidArgument, "Invalid fields specified"
+
+        # check if node exists
+        nodes = Nodes(self.api, [node_id], Node.extra_fields).values()
+        if not nodes:
+            raise PLCInvalidArgument, "No such node"
+       node = nodes[0]
+       
+        # Make sure node network doesnt already exist
+        nodenetworks = NodeNetworks(self.api).values()
+       if nodenetworks:
+               for nodenetwork in nodenetworks:
+                       if nodenetwork['node_id'] == node_id and nodenetwork['method'] == method and nodenetwork['type'] == type:
+                               raise PLCInvalidArgument, "Node Network already exists"
+
+        # 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']:
+               if node['site_id'] not in self.caller['site_ids']:
+                       raise PLCPermissionDenied, "Not allowed to add node network for specified node"
+               if 'tech' not in self.caller['roles']:
+                       raise PLCPermissionDenied, "Not allowed to add node network for specified node"
+       
+
+        # add node network
+       nodenetwork = NodeNetwork(self.api, optional_vals)
+        nodenetwork['node_id'] = node_id
+       nodenetwork['method'] = method
+        nodenetwork['type'] = type
+        nodenetwork.flush()
+
+        return nodenetwork['nodenetwork_id']
diff --git a/PLC/Methods/AdmDeleteNodeNetwork.py b/PLC/Methods/AdmDeleteNodeNetwork.py
new file mode 100644 (file)
index 0000000..a2e8005
--- /dev/null
@@ -0,0 +1,59 @@
+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 AdmDeleteNodeNetwork(Method):
+    """
+    Delete an existing Node Network. Nodenetwork_id must be associated to 
+    node_id and not be associated with a different node.
+
+    Admins 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(NodeNetwork.all_fields['node_id'],
+             NodeNetwork.all_fields['hostname']),
+       Mixed(NodeNetwork.all_fields['nodenetwork_id'],
+             NodeNetwork.all_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 not node['node_id'] ==  nodenetwork['node_id'] or nodenetwork['nodenetwork_id'] not in node['nodenetwork_ids']:
+               raise PLCInvalidArgument, "node network not assoicated with this node"
+
+       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 node network at this node"
+               if 'tech' not in self.caller['roles']:
+                        raise PLCPermissionDenied, "Not allowed to add node network for specified node"
+        nodenetwork.delete()
+
+        return 1
diff --git a/PLC/Methods/AdmGetAllNodeNetworkBandwidthLimits.py b/PLC/Methods/AdmGetAllNodeNetworkBandwidthLimits.py
new file mode 100644 (file)
index 0000000..463d9a3
--- /dev/null
@@ -0,0 +1,29 @@
+import os
+
+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 AdmGetAllNodeNetworkBandwidthLimits(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):
+        # Authenticated function
+        assert self.caller is not None
+
+        nodenetwork_bwlimits = NodeNetwork.bwlimits          
+
+        return nodenetwork_bwlimits
diff --git a/PLC/Methods/AdmGetAllNodeNetworks.py b/PLC/Methods/AdmGetAllNodeNetworks.py
new file mode 100644 (file)
index 0000000..a1fd3a8
--- /dev/null
@@ -0,0 +1,43 @@
+import os
+
+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 AdmGetAllNodeNetworks(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.all_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], NodeNetwork.all_fields).values()
+       if not nodes:
+               raise PLCInvalidArgument, "No such node"
+       node = nodes[0]
+        
+       # Get node networks for this node
+       nodenetwork_ids = node['nodenetwork_ids']
+       if not nodenetwork_ids:
+               raise PLCInvalidArgument, "Node has no node networks"
+       nodenetworks = NodeNetworks(self.api, nodenetwork_ids).values()            
+
+        return nodenetworks
diff --git a/PLC/Methods/AdmGetSitePersons.py b/PLC/Methods/AdmGetSitePersons.py
new file mode 100644 (file)
index 0000000..0839bc6
--- /dev/null
@@ -0,0 +1,46 @@
+import os
+
+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 AdmGetSitePersons(Method):
+    """
+    Return a list of person_ids for the site specified.
+
+    Admins may retrieve person_ids at any site by not specifying
+    site_id_or_name or by specifying an empty list. PIs may only retrieve 
+    the person_ids at their site
+
+    """
+
+    roles = ['admin', 'pi']
+
+    accepts = [
+        PasswordAuth(),
+        Site.fields['site_id']
+        ]
+
+    returns = [Site.all_fields['person_ids']]
+
+    def call(self, auth, site_id):
+        # Authenticated function
+        assert self.caller is not None
+
+        # Get site information
+       sites = Sites(self.api, [site_id], ['person_ids']).values()     
+
+       # make sure sites are found
+       if not sites:
+               raise PLCInvalidArgument, "No such site"
+       site = sites[0]
+       if 'admin' not in self.caller['roles']: 
+                if site['site_id'] not in self.caller['site_ids']:
+                        raise PLCPermissionDenied, "Not allowed to update node network"
+                if 'pi' not in self.caller['roles']:
+                        raise PLCPermissionDenied, "User account not allowed to update node network"   
+       person_ids = site['person_ids']
+       
+       return person_ids
diff --git a/PLC/Methods/AdmUpdateNodeNetwork.py b/PLC/Methods/AdmUpdateNodeNetwork.py
new file mode 100644 (file)
index 0000000..22d57f4
--- /dev/null
@@ -0,0 +1,75 @@
+
+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 AdmUpdateNodeNetwork(Method):
+    """
+    Updates an existing node network. Any values specified in optional_vals 
+    are used, otherwise defaults are used. Acceptable values for method are
+    dhcp and static. If type is static, the parameter optional_vals 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 add networks to their own nodes. Admins may
+    add networks to any node.
+    Returns 1 if successful, faults otherwise.
+    """
+
+    roles = ['admin', 'pi', 'tech']
+
+    cant_update = lambda (field, value): field not in \
+                 ['nodenetwork_id']
+    update_fields = dict(filter(cant_update, NodeNetwork.all_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, optional_vals=None):
+        if filter(lambda field: field not in self.update_fields, optional_vals):
+               raise PLCInvalidArgument, "Invalid fields specified"
+
+        # Authenticated function
+        assert self.caller is not None
+
+       # Get nodenetwork information
+       nodenetworks = NodeNetworks(self.api, [nodenetwork_id_or_hostname]).values()
+       if not nodenetworks:
+               raise PLCInvalidArgument, "No such node network"
+       nodenetwork = nodenetworks[0]
+
+       # Get Node using this node network
+       #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 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"
+               if 'tech' not in self.caller['roles']:
+                       raise PLCPermissionDenied, "User account not allowed to update node network"
+       
+       # Update node network
+       nodenetwork.update(optional_vals)
+        nodenetwork.flush()
+       
+        return 1
diff --git a/PLC/Methods/AdmUpdateSite.py b/PLC/Methods/AdmUpdateSite.py
new file mode 100644 (file)
index 0000000..b17fcc7
--- /dev/null
@@ -0,0 +1,76 @@
+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 AdmUpdateSite(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', 'tech']
+
+    cant_update = lambda (field, value): field not in \
+                 ['site_id', 'nodegroup_id', 'organization_id', 'ext_consortium_id', 'date_created']
+    update_fields = dict(filter(cant_update, Site.all_fields.items()))
+
+    accepts = [
+        PasswordAuth(),
+        Mixed(Site.fields['site_id'],
+              Site.fields['abbreviated_name']),
+        update_fields
+        ]
+
+    returns = Parameter(int, '1 if successful')
+
+    def call(self, auth, site_id_or_abbrev_name, update_fields):
+       # Only admin can update max_slices
+       #if 'admin' not in self.caller['roles']:
+       #       if update_fields.has_key('max_slices '):
+       #               raise PLCInvalidArgument, "Only admins can update max_slices"
+       
+       # 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 in ['name', 'abbreviated_name', 'login_base', 'is_public', 'max_slices']:
+                    raise PLCInvalidArgument, "%s cannot be unset" % key
+                update_fields[key] = None
+
+        # Get site information
+        sites = Sites(self.api, [site_id_or_abbrev_name], Site.all_fields)
+        if not sites :
+            raise PLCInvalidArgument, "No such site"
+
+        site = sites.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']:
+               if site['site_id'] not in self.caller['site_ids']:
+                       raise PLCPermissionDenied, "Not allowed to modify specified site"
+               if 'tech' not in self.caller['roles']:
+                        raise PLCPermissionDenied, "Not allowed to add node network for specified node"
+               
+       
+        site.update(update_fields)
+       site.flush()
+       
+       return 1
+