applied the except and raise fixers to the master branch to close the gap with py3
[nepi.git] / src / nepi / resources / linux / ns3 / tuntapfdlink.py
1 #
2 #    NEPI, a framework to manage network experiments
3 #    Copyright (C) 2014 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 version 2 as
7 #    published by the Free Software Foundation;
8 #
9 #    This program is distributed in the hope that it will be useful,
10 #    but WITHOUT ANY WARRANTY; without even the implied warranty of
11 #    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12 #    GNU General Public License for more details.
13 #
14 #    You should have received a copy of the GNU General Public License
15 #    along with this program.  If not, see <http://www.gnu.org/licenses/>.
16 #
17 # Author: Alina Quereilhac <alina.quereilhac@inria.fr>
18 from nepi.execution.resource import ResourceState, clsinit_copy
19 from nepi.resources.linux.application import LinuxApplication
20
21 import base64
22 import fcntl
23 import os
24 import socket
25 import struct
26
27 @clsinit_copy
28 class LinuxTunTapFdLink(LinuxApplication):
29     """ Interconnects a TAP or TUN Linux device to a FdNetDevice
30     """
31     _rtype = "linux::ns3::TunTapFdLink"
32
33     def __init__(self, ec, guid):
34         super(LinuxTunTapFdLink, self).__init__(ec, guid)
35         self._tap = None
36         self._fdnetdevice = None
37         self._fd_node = None
38         self.send_address = None
39         self._home = "tuntap-link-%s" % self.guid
40
41     @property
42     def fdnetdevice(self):
43         if not self._fdnetdevice:
44             from nepi.resources.ns3.ns3fdnetdevice import NS3BaseFdNetDevice
45             devices = self.get_connected(NS3BaseFdNetDevice.get_rtype())
46             if not devices or len(devices) != 1: 
47                 msg = "TunTapFdLink must be connected to exactly one FdNetDevice"
48                 self.error(msg)
49                 raise RuntimeError(msg)
50
51             self._fdnetdevice = devices[0]
52         
53             simu = self._fdnetdevice.simulation
54             from nepi.resources.linux.node import LinuxNode
55             nodes = simu.get_connected(LinuxNode.get_rtype())
56             self._fd_node = nodes[0]
57         
58         return self._fdnetdevice
59
60     @property
61     def fdnode(self):
62         return self._fd_node
63
64     @property
65     def tap(self):
66         if not self._tap:
67             from nepi.resources.linux.tap import LinuxTap
68             devices = self.get_connected(LinuxTap.get_rtype())
69             if not devices or len(devices) != 1: 
70                 msg = "TunTapLink must be connected to exactly one Tap or Tun"
71                 self.error(msg)
72                 raise RuntimeError(msg)
73
74             self._tap = devices[0]
75         
76         return self._tap
77
78     @property
79     def tapnode(self):
80         return self.tap.node
81
82     @property
83     def node(self):
84         return self.tapnode
85
86     def upload_sources(self):
87         scripts = []
88
89         # vif-passfd python script
90         linux_passfd = os.path.join(os.path.dirname(__file__),
91                 "..",
92                 "scripts",
93                 "linux-tap-passfd.py")
94
95         scripts.append(linux_passfd)
96         
97         # Upload scripts
98         scripts = ";".join(scripts)
99
100         self.node.upload(scripts,
101                 os.path.join(self.node.src_dir),
102                 overwrite = False)
103
104     def upload_start_command(self):
105         if self.tapnode.get("hostname") != \
106                 self.fdnode.get("hostname"):
107             msg = "Tap and FdNetDevice are not in the same host"
108             self.error(msg)
109             raise RuntimeError(msg)
110
111         self.send_address = self.fdnetdevice.recv_fd()
112         self.set("command", self._start_command)
113
114         command = self.get("command")
115
116         shfile = os.path.join(self.app_home, "start.sh")
117         self.node.run_and_wait(command, self.run_home,
118                 shfile=shfile,
119                 wait_run=False,
120                 overwrite=True)
121         
122     def do_deploy(self):
123         if self.tap.state < ResourceState.READY or \
124                 self.fdnetdevice.state < ResourceState.READY:
125             self.debug("---- RESCHEDULING DEPLOY ---- ")
126             self.ec.schedule(self.reschedule_delay, self.deploy)
127         else:
128             self.do_discover()
129             self.do_provision()
130
131             self.set_ready()
132
133     def do_start(self):
134         if self.state == ResourceState.READY:
135             command = self.get("command")
136             self.info("Starting command '%s'" % command)
137
138             self.set_started()
139         else:
140             msg = " Failed to execute command '%s'" % command
141             self.error(msg, out, err)
142             raise RuntimeError(msg)
143
144     @property
145     def _start_command(self):
146         address = base64.b64encode(self.send_address)
147
148         command = []
149         # Use tap-passfd.py to send fd from TAP to FdNetDevice
150         command.append("sudo -S")
151         command.append("PYTHONPATH=$PYTHONPATH:${SRC}")
152         command.append("python ${SRC}/linux-tap-passfd.py")
153         command.append("-a %s" % address)
154         command.append("-S %s " % self.tap.sock_name)
155
156         command = " ".join(command)
157         command = self.replace_paths(command)
158
159         return command
160