2 # NEPI, a framework to manage network experiments
3 # Copyright (C) 2013 INRIA
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU General Public License as published by
7 # the Free Software Foundation, either version 3 of the License, or
8 # (at your option) any later version.
10 # This program is distributed in the hope that it will be useful,
11 # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 # GNU General Public License for more details.
15 # You should have received a copy of the GNU General Public License
16 # along with this program. If not, see <http://www.gnu.org/licenses/>.
18 # Author: Alina Quereilhac <alina.quereilhac@inria.fr>
20 from nepi.execution.attribute import Attribute, Flags, Types
21 from nepi.execution.resource import ResourceManager, clsinit_copy, ResourceState, \
23 from nepi.resources.linux.node import LinuxNode
24 from nepi.resources.planetlab.plcapi import PLCAPIFactory
28 class PlanetlabNode(LinuxNode):
29 _rtype = "PlanetlabNode"
32 def _register_attributes(cls):
33 cls._remove_attribute("username")
35 ip = Attribute("ip", "PlanetLab host public IP address",
36 flags = Flags.ReadOnly)
38 slicename = Attribute("slice", "PlanetLab slice name",
39 flags = Flags.Credential)
41 pl_url = Attribute("plcApiUrl", "URL of PlanetLab PLCAPI host (e.g. www.planet-lab.eu or www.planet-lab.org) ",
42 default = "www.planet-lab.eu",
43 flags = Flags.Credential)
45 pl_ptn = Attribute("plcApiPattern", "PLC API service regexp pattern (e.g. https://%(hostname)s:443/PLCAPI/ ) ",
46 default = "https://%(hostname)s:443/PLCAPI/",
47 flags = Flags.ExecReadOnly)
49 city = Attribute("city",
50 "Constrain location (city) during resource discovery. May use wildcards.",
53 country = Attribute("country",
54 "Constrain location (country) during resource discovery. May use wildcards.",
57 region = Attribute("region",
58 "Constrain location (region) during resource discovery. May use wildcards.",
61 architecture = Attribute("architecture",
62 "Constrain architecture during resource discovery.",
63 type = Types.Enumerate,
68 operating_system = Attribute("operatingSystem",
69 "Constrain operating system during resource discovery.",
70 type = Types.Enumerate,
78 site = Attribute("site",
79 "Constrain the PlanetLab site this node should reside on.",
80 type = Types.Enumerate,
86 min_reliability = Attribute("minReliability",
87 "Constrain reliability while picking PlanetLab nodes. Specifies a lower acceptable bound.",
92 max_reliability = Attribute("maxReliability",
93 "Constrain reliability while picking PlanetLab nodes. Specifies an upper acceptable bound.",
98 min_bandwidth = Attribute("minBandwidth",
99 "Constrain available bandwidth while picking PlanetLab nodes. Specifies a lower acceptable bound.",
102 flags = Flags.Filter)
104 max_bandwidth = Attribute("maxBandwidth",
105 "Constrain available bandwidth while picking PlanetLab nodes. Specifies an upper acceptable bound.",
108 flags = Flags.Filter)
110 min_load = Attribute("minLoad",
111 "Constrain node load average while picking PlanetLab nodes. Specifies a lower acceptable bound.",
114 flags = Flags.Filter)
116 max_load = Attribute("maxLoad",
117 "Constrain node load average while picking PlanetLab nodes. Specifies an upper acceptable bound.",
120 flags = Flags.Filter)
122 min_cpu = Attribute("minCpu",
123 "Constrain available cpu time while picking PlanetLab nodes. Specifies a lower acceptable bound.",
126 flags = Flags.Filter)
128 max_cpu = Attribute("maxCpu",
129 "Constrain available cpu time while picking PlanetLab nodes. Specifies an upper acceptable bound.",
132 flags = Flags.Filter)
134 timeframe = Attribute("timeframe",
135 "Past time period in which to check information about the node. Values are year,month, week, latest",
137 type = Types.Enumerate,
142 flags = Flags.Filter)
144 cls._register_attribute(ip)
145 cls._register_attribute(slicename)
146 cls._register_attribute(pl_url)
147 cls._register_attribute(pl_ptn)
148 cls._register_attribute(city)
149 cls._register_attribute(country)
150 cls._register_attribute(region)
151 cls._register_attribute(architecture)
152 cls._register_attribute(operating_system)
153 cls._register_attribute(min_reliability)
154 cls._register_attribute(max_reliability)
155 cls._register_attribute(min_bandwidth)
156 cls._register_attribute(max_bandwidth)
157 cls._register_attribute(min_load)
158 cls._register_attribute(max_load)
159 cls._register_attribute(min_cpu)
160 cls._register_attribute(max_cpu)
161 cls._register_attribute(timeframe)
163 def __init__(self, ec, guid):
164 super(PLanetlabNode, self).__init__(ec, guid)
171 slicename = self.get("slice")
172 pl_pass = self.get("password")
173 pl_url = self.get("plcApiUrl")
174 pl_ptn = self.get("plcApiPattern")
176 self._plapi = PLCAPIFactory.get_api(slicename, pl_pass, pl_url,
186 if (not self.get("hostname") or not self.get("username")):
187 msg = "Can't resolve OS, insufficient data "
189 raise RuntimeError, msg
191 (out, err), proc = self.execute("cat /etc/issue", with_lock = True)
193 if err and proc.poll():
194 msg = "Error detecting OS "
195 self.error(msg, out, err)
196 raise RuntimeError, "%s - %s - %s" %( msg, out, err )
198 if out.find("Fedora release 12") == 0:
200 elif out.find("Fedora release 14") == 0:
203 msg = "Unsupported OS"
205 raise RuntimeError, "%s - %s " %( msg, out )
210 if not self.is_alive():
211 self._state = ResourceState.FAILED
212 msg = "Deploy failed. Unresponsive node %s" % self.get("hostname")
214 raise RuntimeError, msg
216 if self.get("cleanProcesses"):
217 self.clean_processes()
219 if self.get("cleanHome"):
222 self.mkdir(self.node_home)
224 super(PlanetlabNode, self).provision()
227 if self.state == ResourceState.NEW:
230 if self.state == ResourceState.DISCOVERED:
233 self._state = ResourceState.FAILED
236 if self.state != ResourceState.PROVISIONED:
237 self.ec.schedule(reschedule_delay, self.deploy)
239 super(PlanetlabNode, self).deploy()
241 def valid_connection(self, guid):
245 def clean_processes(self, killer = False):
246 self.info("Cleaning up processes")
249 cmd = ("sudo -S killall python tcpdump || /bin/true ; " +
250 "sudo -S killall python tcpdump || /bin/true ; " +
251 "sudo -S kill $(ps -N -T -o pid --no-heading | grep -v $PPID | sort) || /bin/true ; " +
252 "sudo -S killall -u root || /bin/true ; " +
253 "sudo -S killall -u root || /bin/true ; ")
256 (out, err), proc = self.execute(cmd, retry = 1, with_lock = True)
260 self.warn(" Blacklisting malfunctioning node ")
262 #util.appendBlacklist(self.hostname)