OSDN Git Service

6b8d59a483d436ca4ee7233d80a6e150f47be332
[ti2/ti2.git] / linkpair / collector.py
1 #!/usr/bin/env python
2 # -*- coding: utf-8 -*-
3 #
4
5 __version__ = '1.1'
6
7 import sys
8 import os
9 import re
10 from xml.dom import minidom
11 from subprocess import Popen, PIPE
12 from socket import gethostname
13 import shlex
14 import libvirt
15 from device import Device
16 from port import Port
17 from linkpair import LinkPair
18 from formatter.grapheasy import GraphEasyFormatter
19 from commonutils import CommonUtils
20 from dbutils import DBUtils
21 from collectagent.commandrunner import CommandRunner
22
23 class Collector(object):
24     '''LinkpPair collector
25
26     This class gets the LinkPair information from LinuxBridge and Open vSwitch and libvirt
27     '''
28
29     PEER_FOUND = 1
30
31     def __init__(self, remote_desc, dbu, formatter=GraphEasyFormatter()):
32         self._linkpairs = []
33         self._port_to_br = {}
34         self._iface_to_nss = {}
35         self._u = CommonUtils()
36         self._db_enable = False
37         self._sql_conn = None
38         self._remote_desc = remote_desc
39         self._ssh_username = ""
40         self._ssh_hostname = ""
41         self._ssh_hostport = 22
42         self._remote_password = ""
43         self._remote_sshkey = ""
44         self._ssh_keyauth = False
45         self._ssh_passauth = False
46
47         ''' set parameters '''
48         [self._ssh_username, self._ssh_hostname, self._ssh_hostport] = self._u.parse_remote_desc(remote_desc)
49         self._dbu = dbu
50         self._formatter = formatter
51         self._runner = CommandRunner(self._remote_desc)
52         
53     def run(self):
54         self.map_port_to_namespace()
55         self.pick_ovs_configuration()
56         self.pick_bridge_configuration()
57         self.pick_libvirt_configuration()
58     
59     def add_linkpair(self, dev1, dev2, port1, port2, format=""):
60         if format == "":
61             format = self._formatter.DEFAULT_FORMAT
62         self._linkpairs.append(
63             LinkPair(dev1, dev2, port1, port2, format))
64 #        if self._dbu.enable_db:
65 #            insert_record(fmt, src, src_style, label, dst, dst_style)
66
67     def get_linkpairs(self):
68         return self._linkpairs
69
70     def drop_linkpairs(self):
71         self._linkpairs = []
72
73     def pick_libvirt_configuration(self):
74         virt_conn = self.get_libvirt_conn()
75         for id in virt_conn.listDomainsID():
76             vm = virt_conn.lookupByID(id)
77             vmXMLDesc = minidom.parseString(vm.XMLDesc(0))
78             for iface in vmXMLDesc.getElementsByTagName("interface"):
79                 [device, bridge] = self.pick_libvirt_iface_configuration(iface)
80                 mac = iface.getElementsByTagName(
81                     "mac")[0].getAttribute("address")
82                 device = iface.getElementsByTagName(
83                     "target")[0].getAttribute("dev")
84                 bridge = self.regist_to_port2br(device, bridge)
85                 self.add_linkpair(
86                     Device(str(vm.name()), Device.VM_TYPE),
87                     Device(bridge, Device.BR_TYPE),
88                     Port(device),
89                     Port(""))
90
91     def pick_libvirt_iface_configuration(self, iface):
92         ifaceType = iface.getAttribute("type")
93         bridge = ""
94         device = ""
95         if ifaceType == "network":
96             network = iface.getElementsByTagName(
97                 "source")[0].getAttribute("network")
98             netXMLDesc = minidom.parseString(
99                 virt_conn.networkLookupByName(network).XMLDesc(0))
100             bridge = netXMLDesc.getElementsByTagName(
101                 "bridge")[0].getAttribute("name")
102         elif ifaceType == "bridge":
103             bridge = iface.getElementsByTagName(
104                 "source")[0].getAttribute("bridge")
105         return [device, bridge]
106
107     def regist_to_port2br(self, device, bridge):
108         if device in self._port_to_br:
109             if bridge == "":
110                 return self._port_to_br[device]
111             else:
112                 return bridge
113         else:
114             self._port_to_br[device] = bridge
115             return bridge
116
117     def map_port_to_namespace(self):
118         result = self._runner.exec_cmd("ip netns")
119     # if result....
120         for ns in result:
121             ns = ns.rstrip()
122             result2 = self._runner.exec_cmd("ip netns exec " + ns + " ip link show")
123             for linkpair_out in result2:
124                 linkpair_out = linkpair_out.rstrip()
125                 match = re.match(r'\d+: (.*?): ', linkpair_out)
126                 if match is not None and match.group(1) != 'lo':
127                     self._iface_to_nss[match.group(1).rstrip()] = ns
128
129     def pick_bridge_configuration(self):
130         br_name = ""
131         result = self._runner.exec_cmd("brctl show")
132         for br_line in result:
133             br_line = br_line.rstrip()
134             if self._u.d_push(re.match(r'^(\S+)\s+(\S+)\s+(\S+)\s+(\S+)$', br_line)) is not None:
135                 match = self._u.d_pop()
136                 br_name = match.group(1)
137                 port = match.group(4)
138                 if port not in self._port_to_br and br_name != "":
139                     self._port_to_br[port] = br_name
140                     ## for OpenStack quntum...
141                     if self._u.d_push(re.match(r'^qvb(.+)', port)):
142                         quantum_idprefix = self._u.d_pop().group(1)
143                         if "qvo" + quantum_idprefix in self._port_to_br:
144                             self.add_linkpair(
145                                 Device(br_name, Device.BR_TYPE),
146                                 Device(self._port_to_br[
147                                        "qvo" + quantum_idprefix], Device.BR_TYPE),
148                                 Port(port),
149                                 Port("qvo" + quantum_idprefix),
150                                 self._formatter.VETH_FORMAT)
151                     else:
152                         self.add_linkpair(
153                             Device(br_name),
154                             Device("INTERNAL", Device.OS_ROUTE_TYPE),
155                             Port(port),
156                             Port(""))
157     #            else:
158     #                print self._port_to_br.keys()
159     #                if self._u.d_push(re.match(r'^qvo(.+)', port)):
160     #                    continue
161     #                add_linkpair(self.DEFAULT_FORMAT, br_name, self.DEFAULT_TYPE, port, \
162     #                  "INTERNAL", self.OS_ROUTE_TYPE )
163
164             elif self._u.d_push(re.match(r'^\s+(\S+)$', br_line)) is not None:
165                 port = self._u.d_pop().group(1)
166                 if port not in self._port_to_br and br_name != "":
167                     self._port_to_br[port] = br_name
168                     ## for OpenStack quntum...
169                     if self._u.d_push(re.match(r'^qvb(.+)', port)):
170                         quantum_idprefix = self._u.d_pop().group(1)
171                         if "qvo" + quantum_idprefix in self._port_to_br:
172                             self.add_linkpair(
173                                 Device(br_name, Device.BR_TYPE),
174                                 Device(self._port_to_br[
175                                        "qvo" + quantum_idprefix], Device.BR_TYPE),
176                                 Port(port),
177                                 Port("qvo" + quantum_idprefix),
178                                 self._formatter.VETH_FORMAT)
179                     else:
180                         if self._u.d_push(re.match(r'^qvo(.+)', port)):
181                             continue
182                         self.add_linkpair(
183                             Device(br_name),
184                             Device("INTERNAL", Device.OS_ROUTE_TYPE),
185                             Port(port),
186                             Port(""))
187
188     def pick_ovs_configuration(self):
189         patch_peers = {}
190
191         result = self._runner.exec_cmd("ovs-vsctl list-br")
192         for br_src in result:
193             br_src = br_src.rstrip()
194             result2 = self._runner.exec_cmd("ovs-dpctl show " + br_src)
195             for port_desc in result2:
196                 port_desc = port_desc.rstrip()
197                 if self._u.d_push(
198                     re.search(r'port \d+: (.*?) \(patch: peer=(.*?)\)',
199                               port_desc)) is not None:
200                     match = self._u.d_pop()
201                     patch_src = match.group(1)
202                     patch_dst = match.group(2)
203                     patch_peers[patch_src + ":" + patch_dst] = self.PEER_FOUND
204
205                     if patch_dst + ":" + patch_src in patch_peers:
206                         continue
207
208                     result3 = self._runner.exec_cmd(
209                         "ovs-vsctl port-to-br " + patch_dst)
210                     if result3 is not None and len(result3) > 0:
211                         br_dst = result3[0].rstrip()
212                         self.add_linkpair(
213                             Device(br_src, Device.BR_TYPE),
214                             Device(br_dst, Device.BR_TYPE),
215                             Port(patch_src),
216                             Port(patch_dst),
217                             self._formatter.PATCH_FORMAT)
218                     else:
219                         self.add_linkpair(
220                             Device(br_src, Device.BR_TYPE),
221                             Device("NOT CONNECTED", Device.NOT_CONNECTED_TYPE),
222                             Port(patch_src),
223                             Port(patch_dst),
224                             self._formatter.PATCH_FORMAT)
225
226                 else:
227                     # Internal OVSPort.
228                     if self._u.d_push(
229                         re.search(
230                             r'port \d+: ' + br_src + ' \(internal\)',
231                             port_desc)) is None:
232                         if self._u.d_push(re.search(r'port \d+: (.*)', port_desc)) is not None:
233                             port = self._u.d_pop().group(1).rstrip()
234                             if self._u.d_push(re.match(r'^eth\d+$', port)) \
235                                 or self._u.d_push(re.match(r'^em\d+$', port)) \
236                                     or self._u.d_push(re.match(r'^igb\d+$', port)):
237                                 self._port_to_br[port] = br_src
238                                 self.add_linkpair(
239                                     Device(br_src, Device.BR_TYPE),
240                                     Device("Physical NW", Device.PHYNET_TYPE),
241                                     Port(port),
242                                     Port(""))
243                             elif self._u.d_push(re.match(r'(vxlan\d+)', port)) \
244                                 or self._u.d_push(re.match(r'(gre\d+)', port)) \
245                                     or self._u.d_push(re.match(r'(gre-\d+)', port)):
246                                 port2 = self._u.d_pop().group(1)
247                                 self._port_to_br[port2] = br_src
248                                 self.add_linkpair(
249                                     Device(br_src, Device.BR_TYPE),
250                                     Device("OS Routing", Device.OS_ROUTE_TYPE),
251                                     Port(port),
252                                     Port(""))
253                             elif re.search(r' \(internal\)', port):
254                                 port = re.sub(r' \(internal\)', '', port)
255                                 if port in self._iface_to_nss:
256                                     self.add_linkpair(
257                                         Device(br_src, Device.BR_TYPE),
258                                         Device(self._iface_to_nss[
259                                                port], Device.NAMESPACE_TYPE),
260                                         Port(port),
261                                         Port(""),
262                                         self._formatter.NAMESPACE_FORMAT)
263                                 else:
264                                     self.add_linkpair(
265                                         Device(br_src, Device.BR_TYPE),
266                                         Device(
267                                             "INTERNAL", Device.OS_ROUTE_TYPE),
268                                         Port(port),
269                                         Port(""))
270                             else:
271                                 ## Other OVSPort
272                                 self._port_to_br[port] = br_src
273                         else:
274                             continue
275
276     def get_libvirt_conn(self):
277         if self._remote_desc is not None:
278             conn = libvirt.open("qemu+ssh://" + self._remote_desc + "/system")
279         else:
280             conn = libvirt.open("qemu:///system")
281         return conn
282
283     def set_remote_sshkey(self, remote_sshkey):
284         self._runner.set_remote_sshkey(remote_sshkey)
285
286     def set_remote_password(self, remote_password):
287         self._runner.set_remote_password(remote_password)
288