Merge with head
[nepi.git] / src / nepi / testbeds / planetlab / util.py
1 #!/usr/bin/env python
2 # -*- coding: utf-8 -*-
3
4 from constants import TESTBED_ID, TESTBED_VERSION
5 from nepi.core import testbed_impl
6 from nepi.core.metadata import Parallel
7 from nepi.util.constants import TIME_NOW
8 from nepi.util.graphtools import mst
9 from nepi.util import ipaddr2
10 from nepi.util import environ
11 from nepi.util.parallel import ParallelRun
12 import sys
13 import os
14 import os.path
15 import time
16 import resourcealloc
17 import collections
18 import operator
19 import functools
20 import socket
21 import struct
22 import tempfile
23 import subprocess
24 import random
25 import shutil
26 import logging
27 import metadata
28 import weakref
29
30 def getAPI(user, pass_):
31     import plcapi
32     return plcapi.PLCAPI(username=user, password=pass_)
33
34 def filterBlacklist(candidates):
35     blpath = environ.homepath('plblacklist')
36     
37     try:
38         bl = open(blpath, "r")
39     except:
40         return candidates
41         
42     try:
43         blacklist = set(
44             map(int,
45                 map(str.strip, bl.readlines())
46             )
47         )
48         return [ x for x in candidates if x not in blacklist ]
49     finally:
50         bl.close()
51
52 def appendBlacklist(node_ids):
53     if not isinstance(node_ids, list):
54         node_ids = [ node_ids ]
55     
56     blpath = environ.homepath('plblacklist')
57     bl = open(blpath, "a")
58     
59     try:
60         for node_id in node_ids:
61             bl.write("%s\n" % (node_id,))
62     finally:
63         bl.close()
64
65 def getNodes(api, num, **constraints):
66     # Now do the backtracking search for a suitable solution
67     # First with existing slice nodes
68     reqs = []
69     nodes = []
70     
71     import node as Node
72         
73     for i in xrange(num):
74         node = Node.Node(api)
75         node.min_num_external_interface = 1
76         nodes.append(node)
77     
78     node = nodes[0]
79     candidates = filterBlacklist(node.find_candidates())
80     reqs = [candidates] * num
81
82     def pickbest(fullset, nreq, node=nodes[0]):
83         if len(fullset) > nreq:
84             fullset = zip(node.rate_nodes(fullset),fullset)
85             fullset.sort(reverse=True)
86             del fullset[nreq:]
87             return set(map(operator.itemgetter(1),fullset))
88         else:
89             return fullset
90     
91     solution = resourcealloc.alloc(reqs, sample=pickbest)
92     
93     # Do assign nodes
94     runner = ParallelRun(maxthreads=4)
95     for node, node_id in zip(nodes, solution):
96         runner.put(node.assign_node_id, node_id)
97     runner.join()
98     
99     return nodes
100
101 def getSpanningTree(nodes, root = None, maxbranching = 2, hostgetter = operator.attrgetter('hostname')):
102     if not root:
103         # Pick root (deterministically)
104         root = min(nodes, key=hostgetter)
105     
106     # Obtain all IPs in numeric format
107     # (which means faster distance computations)
108     for node in nodes:
109         node._ip = socket.gethostbyname(hostgetter(node))
110         node._ip_n = struct.unpack('!L', socket.inet_aton(node._ip))[0]
111     
112     # Compute plan
113     # NOTE: the plan is an iterator
114     plan = mst.mst(
115         nodes,
116         lambda a,b : ipaddr2.ipdistn(a._ip_n, b._ip_n),
117         root = root,
118         maxbranching = maxbranching)
119
120     return plan
121