fe9c952676995caabe7c7a5367bdf63e76e3143a
[nepi.git] / src / nepi / resources / planetlab / vroute.py
1 #
2 #    NEPI, a framework to manage network experiments
3 #    Copyright (C) 2013 INRIA
4 #
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.
9 #
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.
14 #
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/>.
17 #
18 # Author: Alina Quereilhac <alina.quereilhac@inria.fr>
19
20 from nepi.execution.attribute import Attribute, Flags, Types
21 from nepi.execution.resource import clsinit_copy, ResourceState 
22 from nepi.resources.linux.application import LinuxApplication
23 from nepi.resources.planetlab.node import PlanetlabNode
24 from nepi.resources.planetlab.tap import PlanetlabTap
25 from nepi.util.timefuncs import tnow, tdiffsec
26
27 import os
28 import time
29
30 PYTHON_VSYS_VERSION = "1.0"
31
32 @clsinit_copy
33 class PlanetlabVroute(LinuxApplication):
34     _rtype = "planetlab::Vroute"
35     _help = "Creates a Vroute on a PlanetLab host"
36     _platform = "planetlab"
37
38     @classmethod
39     def _register_attributes(cls):
40         action = Attribute("action", "Either add or del",
41               allowed = ["add", "del"],
42               default = "add",
43               flags = Flags.Design)
44
45         prefix = Attribute("prefix", "IPv4 Prefix",
46               flags = Flags.Design)
47
48         nexthop = Attribute("nexthop", "IPv4 Address of the next hop",
49               flags = Flags.Design)
50
51         network = Attribute("network", "IPv4 Network Address",
52               flags = Flags.Design)
53
54         cls._register_attribute(action)
55         cls._register_attribute(prefix)
56         cls._register_attribute(nexthop)
57         cls._register_attribute(network)
58
59     def __init__(self, ec, guid):
60         super(PlanetlabVroute, self).__init__(ec, guid)
61         self._home = "vroute-%s" % self.guid
62
63     @property
64     def tap(self):
65         tap = self.get_connected(PlanetlabTap.get_rtype())
66         if tap: return tap[0]
67         return None
68
69     @property
70     def node(self):
71         node = self.tap.get_connected(PlanetlabNode.get_rtype())
72         if node: return node[0]
73         return None
74
75     def upload_sources(self):
76         # upload vif-creation python script
77         pl_vroute = os.path.join(os.path.dirname(__file__), 
78                 "scripts",
79                 "pl-vroute.py")
80
81         self.node.upload(pl_vroute,
82                 os.path.join(self.node.src_dir, "pl-vroute.py"),
83                 overwrite = False)
84
85         # upload stop.sh script
86         stop_command = self.replace_paths(self._stop_command)
87         self.node.upload(stop_command,
88                 os.path.join(self.app_home, "stop.sh"),
89                 text = True,
90                 # Overwrite file every time. 
91                 # The stop.sh has the path to the socket, wich should change
92                 # on every experiment run.
93                 overwrite = True)
94
95     def upload_start_command(self):
96         # Overwrite file every time. 
97         # The stop.sh has the path to the socket, wich should change
98         # on every experiment run.
99         command = self.get("command")
100         shfile = os.path.join(self.app_home, "start.sh")
101         self.node.run_and_wait(command, self.run_home,
102                 shfile=shfile,
103                 overwrite=True)
104   
105     def do_deploy(self):
106         if not self.tap or self.tap.state < ResourceState.PROVISIONED:
107             self.ec.schedule(self.reschedule_delay, self.deploy)
108         else:
109             if not self.get("command"):
110                 self.set("command", self._start_command)
111
112             self.do_discover()
113             self.do_provision()
114
115             self.debug("----- READY ---- ")
116             self.set_ready()
117
118     def do_start(self):
119         if self.state == ResourceState.READY:
120             command = self.get("command")
121             self.info("Starting command '%s'" % command)
122
123             # Vroute started during deployment
124             self.set_started()
125         else:
126             msg = " Failed to execute command '%s'" % command
127             self.error(msg, out, err)
128             raise RuntimeError, msg
129
130     def do_stop(self):
131
132         command = self.get('command') or ''
133
134         if self.state == ResourceState.STARTED:
135             self.info("Stopping command '%s'" % self._stop_command)
136
137             command = "bash %s" % os.path.join(self.app_home, "stop.sh")
138             (out, err), proc = self.execute_command(command,
139                     blocking = True)
140
141             self.set_stopped()
142
143     def do_release(self):
144         # Node needs to wait until all associated RMs are released
145         # to be released
146         if not self.get("tearDown"):
147             self.set("tearDown", self._tear_down_command())
148
149         super(PlanetlabVroute, self).do_release()
150
151     def _tear_down_command(self):
152         if self.get("action") == "del":
153             return
154
155         return self._stop_command
156
157     @property
158     def _start_command(self):
159         command = ["sudo -S python ${SRC}/pl-vroute.py"]
160         command.append("-a %s" % self.get("action"))
161         command.append("-n %s" % self.get("network"))
162         command.append("-p %s" % self.get("prefix"))
163         command.append("-g %s" % self.tap.get("pointopoint"))
164         command.append("-f %s" % self.tap.get("deviceName"))
165         command = " ".join(command)
166
167         command = self.replace_paths(command)
168         return command
169
170     @property
171     def _stop_command(self):
172         command = ["sudo -S python ${SRC}/pl-vroute.py"]
173         command.append("-a %s" % "del")
174         command.append("-n %s" % self.get("network"))
175         command.append("-p %s" % self.get("prefix"))
176         command.append("-g %s" % self.get("nexthop"))
177         command.append("-f %s" % self.tap.get("deviceName"))
178         command = " ".join(command)
179         
180         command = self.replace_paths(command)
181         return command
182
183     def valid_connection(self, guid):
184         # TODO: Validate!
185         return True
186