2 # -*- coding: utf-8 -*-
10 from xml.dom import minidom
11 from subprocess import Popen, PIPE
12 from socket import gethostname
15 from device import Device
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
23 class Collector(object):
24 '''LinkpPair collector
26 This class gets the LinkPair information from LinuxBridge and Open vSwitch and libvirt
31 def __init__(self, remote_desc, dbu, formatter=GraphEasyFormatter()):
34 self._iface_to_nss = {}
35 self._u = CommonUtils()
36 self._db_enable = False
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
47 ''' set parameters '''
48 [self._ssh_username, self._ssh_hostname, self._ssh_hostport] = self._u.parse_remote_desc(remote_desc)
50 self._formatter = formatter
51 self._runner = CommandRunner(self._remote_desc)
54 self.map_port_to_namespace()
55 self.pick_ovs_configuration()
56 self.pick_bridge_configuration()
57 self.pick_libvirt_configuration()
59 def add_linkpair(self, dev1, dev2, port1, port2, 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)
67 def get_linkpairs(self):
68 return self._linkpairs
70 def drop_linkpairs(self):
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)
86 Device(str(vm.name()), Device.VM_TYPE),
87 Device(bridge, Device.BR_TYPE),
91 def pick_libvirt_iface_configuration(self, iface):
92 ifaceType = iface.getAttribute("type")
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]
107 def regist_to_port2br(self, device, bridge):
108 if device in self._port_to_br:
110 return self._port_to_br[device]
114 self._port_to_br[device] = bridge
117 def map_port_to_namespace(self):
118 result = self._runner.exec_cmd("ip netns")
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
129 def pick_bridge_configuration(self):
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:
145 Device(br_name, Device.BR_TYPE),
146 Device(self._port_to_br[
147 "qvo" + quantum_idprefix], Device.BR_TYPE),
149 Port("qvo" + quantum_idprefix),
150 self._formatter.VETH_FORMAT)
154 Device("INTERNAL", Device.OS_ROUTE_TYPE),
158 # print self._port_to_br.keys()
159 # if self._u.d_push(re.match(r'^qvo(.+)', port)):
161 # add_linkpair(self.DEFAULT_FORMAT, br_name, self.DEFAULT_TYPE, port, \
162 # "INTERNAL", self.OS_ROUTE_TYPE )
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:
173 Device(br_name, Device.BR_TYPE),
174 Device(self._port_to_br[
175 "qvo" + quantum_idprefix], Device.BR_TYPE),
177 Port("qvo" + quantum_idprefix),
178 self._formatter.VETH_FORMAT)
180 if self._u.d_push(re.match(r'^qvo(.+)', port)):
184 Device("INTERNAL", Device.OS_ROUTE_TYPE),
188 def pick_ovs_configuration(self):
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()
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
205 if patch_dst + ":" + patch_src in patch_peers:
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()
213 Device(br_src, Device.BR_TYPE),
214 Device(br_dst, Device.BR_TYPE),
217 self._formatter.PATCH_FORMAT)
220 Device(br_src, Device.BR_TYPE),
221 Device("NOT CONNECTED", Device.NOT_CONNECTED_TYPE),
224 self._formatter.PATCH_FORMAT)
230 r'port \d+: ' + br_src + ' \(internal\)',
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
239 Device(br_src, Device.BR_TYPE),
240 Device("Physical NW", Device.PHYNET_TYPE),
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
249 Device(br_src, Device.BR_TYPE),
250 Device("OS Routing", Device.OS_ROUTE_TYPE),
253 elif re.search(r' \(internal\)', port):
254 port = re.sub(r' \(internal\)', '', port)
255 if port in self._iface_to_nss:
257 Device(br_src, Device.BR_TYPE),
258 Device(self._iface_to_nss[
259 port], Device.NAMESPACE_TYPE),
262 self._formatter.NAMESPACE_FORMAT)
265 Device(br_src, Device.BR_TYPE),
267 "INTERNAL", Device.OS_ROUTE_TYPE),
272 self._port_to_br[port] = br_src
276 def get_libvirt_conn(self):
277 if self._remote_desc is not None:
278 conn = libvirt.open("qemu+ssh://" + self._remote_desc + "/system")
280 conn = libvirt.open("qemu:///system")
283 def set_remote_sshkey(self, remote_sshkey):
284 self._runner.set_remote_sshkey(remote_sshkey)
286 def set_remote_password(self, remote_password):
287 self._runner.set_remote_password(remote_password)