OSDN Git Service

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