+ if not _plapi:
+ self.fail_plapi()
+
+ self._plapi = weakref.ref(_plapi)
+
+ return self._plapi()
+
+ def do_discover(self):
+ """
+ Based on the attributes defined by the user, discover the suitable
+ nodes for provision.
+ """
+ if self._skip_provision():
+ super(PlanetlabNode, self).do_discover()
+ return
+
+ hostname = self._get_hostname()
+ if hostname:
+ # the user specified one particular node to be provisioned
+ self._hostname = True
+ node_id = self._get_nodes_id({'hostname':hostname})
+ node_id = node_id.pop()['node_id']
+
+ # check that the node is not blacklisted or being provisioned
+ # by other RM
+ with PlanetlabNode.lock:
+ plist = self.plapi.reserved()
+ blist = self.plapi.blacklisted()
+ if node_id not in blist and node_id not in plist:
+
+ # check that is really alive, by performing ping
+ ping_ok = self._do_ping(node_id)
+ if not ping_ok:
+ self._blacklist_node(node_id)
+ self.fail_node_not_alive(hostname)
+ else:
+ if self._check_if_in_slice([node_id]):
+ self._slicenode = True
+ self._put_node_in_provision(node_id)
+ self._node_to_provision = node_id
+ else:
+ self.fail_node_not_available(hostname)
+ super(PlanetlabNode, self).do_discover()
+
+ else:
+ # the user specifies constraints based on attributes, zero, one or
+ # more nodes can match these constraints
+ nodes = self._filter_based_on_attributes()
+
+ # nodes that are already part of user's slice have the priority to
+ # provisioned
+ nodes_inslice = self._check_if_in_slice(nodes)
+ nodes_not_inslice = list(set(nodes) - set(nodes_inslice))
+
+ node_id = None
+ if nodes_inslice:
+ node_id = self._choose_random_node(nodes_inslice)
+ self._slicenode = True
+
+ if not node_id:
+ # Either there were no matching nodes in the user's slice, or
+ # the nodes in the slice were blacklisted or being provisioned
+ # by other RM. Note nodes_not_inslice is never empty
+ node_id = self._choose_random_node(nodes_not_inslice)
+ self._slicenode = False
+
+ if node_id:
+ self._node_to_provision = node_id
+ try:
+ self._set_hostname_attr(node_id)
+ self.info(" Selected node to provision ")
+ super(PlanetlabNode, self).do_discover()
+ except:
+ with PlanetlabNode.lock:
+ self._blacklist_node(node_id)
+ self.do_discover()
+ else:
+ self.fail_not_enough_nodes()
+
+ def do_provision(self):
+ """
+ Add node to user's slice after verifing that the node is functioning
+ correctly
+ """
+ if self._skip_provision():
+ super(PlanetlabNode, self).do_provision()
+ return
+
+ provision_ok = False
+ ssh_ok = False
+ proc_ok = False
+ timeout = 1800
+
+ while not provision_ok:
+ node = self._node_to_provision
+ if not self._slicenode:
+ self._add_node_to_slice(node)
+ if self._check_if_in_slice([node]):
+ self.debug( "Node added to slice" )
+ else:
+ self.warning(" Could not add to slice ")
+ with PlanetlabNode.lock:
+ self._blacklist_node(node)
+ self.do_discover()
+ continue
+
+ # check ssh connection
+ t = 0
+ while t < timeout and not ssh_ok:
+
+ cmd = 'echo \'GOOD NODE\''
+ ((out, err), proc) = self.execute(cmd)
+ if out.find("GOOD NODE") < 0:
+ self.debug( "No SSH connection, waiting 60s" )
+ t = t + 60
+ time.sleep(60)
+ continue
+ else:
+ self.debug( "SSH OK" )
+ ssh_ok = True
+ continue
+ else:
+ cmd = 'echo \'GOOD NODE\''
+ ((out, err), proc) = self.execute(cmd)
+ if not out.find("GOOD NODE") < 0:
+ ssh_ok = True
+
+ if not ssh_ok:
+ # the timeout was reach without establishing ssh connection
+ # the node is blacklisted, deleted from the slice, and a new
+ # node to provision is discovered
+ with PlanetlabNode.lock:
+ self.warning(" Could not SSH login ")
+ self._blacklist_node(node)
+ #self._delete_node_from_slice(node)
+ self.do_discover()
+ continue
+
+ # check /proc directory is mounted (ssh_ok = True)
+ # and file system is not read only
+ else:
+ cmd = 'mount |grep proc'
+ ((out1, err1), proc1) = self.execute(cmd)
+ cmd = 'touch /tmp/tmpfile; rm /tmp/tmpfile'
+ ((out2, err2), proc2) = self.execute(cmd)
+ if out1.find("/proc type proc") < 0 or \
+ "Read-only file system".lower() in err2.lower():
+ with PlanetlabNode.lock:
+ self.warning(" Corrupted file system ")
+ self._blacklist_node(node)
+ #self._delete_node_from_slice(node)
+ self.do_discover()
+ continue
+
+ else:
+ provision_ok = True
+ if not self.get('hostname'):
+ self._set_hostname_attr(node)
+ # set IP attribute
+ ip = self._get_ip(node)
+ self.set("ip", ip)
+ self.info(" Node provisioned ")
+
+ super(PlanetlabNode, self).do_provision()
+
+ def do_release(self):
+ super(PlanetlabNode, self).do_release()
+ if self.state == ResourceState.RELEASED and not self._skip_provision():
+ self.debug(" Releasing PLC API ")
+ self.plapi.release()
+
+ def _filter_based_on_attributes(self):
+ """
+ Retrive the list of nodes ids that match user's constraints
+ """
+ # Map user's defined attributes with tagnames of PlanetLab