More fixes to ovs modules
Because this code deserves to be beautiful. Change-Id: I0cc85d9a1103d4d4d7a19bf617838179197f9c90
This commit is contained in:
@@ -1,23 +1,36 @@
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# analyzer.py:
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
# This file implements the following:
|
||||
# 1. Analysis of the collected info
|
||||
# 2. Report any problems
|
||||
# 3. Report what is correct
|
||||
#
|
||||
import pprint
|
||||
import re
|
||||
|
||||
import argparse
|
||||
import subprocess
|
||||
from itertools import combinations
|
||||
import json
|
||||
import os
|
||||
from itertools import combinations
|
||||
|
||||
from common import settings, debug, get_router
|
||||
from common import load_json, get_subnet, is_network_public
|
||||
import pprint
|
||||
import re
|
||||
import subprocess
|
||||
import yaml
|
||||
|
||||
from openstack_dashboard.don.ovs.common import debug
|
||||
from openstack_dashboard.don.ovs.common import get_router
|
||||
from openstack_dashboard.don.ovs.common import get_subnet
|
||||
from openstack_dashboard.don.ovs.common import is_network_public
|
||||
from openstack_dashboard.don.ovs.common import load_json
|
||||
from openstack_dashboard.don.ovs.common import settings
|
||||
|
||||
tick = '✔'
|
||||
cross = '✘'
|
||||
|
||||
@@ -146,9 +159,8 @@ def get_vm_credentials(config_file='credentials.yaml'):
|
||||
try:
|
||||
with open(config_file, 'r') as s:
|
||||
return yaml.safe_load(s)
|
||||
except IOError, e:
|
||||
print '%s :%s' % (e.args[1], config_file)
|
||||
raise
|
||||
except IOError as e:
|
||||
raise '%s :%s' % (e.args[1], config_file)
|
||||
|
||||
|
||||
def test_ping(info):
|
||||
@@ -203,7 +215,8 @@ def run_ovs_command(cmd, comment=''):
|
||||
return subprocess.check_output(cmd,
|
||||
shell=True,
|
||||
stderr=subprocess.STDOUT,
|
||||
universal_newlines=True).replace('\t', ' ')
|
||||
universal_newlines=True).replace(
|
||||
'\t', ' ')
|
||||
|
||||
|
||||
def process_ovs_output(output):
|
||||
@@ -361,8 +374,9 @@ def analyze(json_filename, params):
|
||||
|
||||
|
||||
def check_args():
|
||||
parser = argparse.ArgumentParser(description='Static analysis of output of commands',
|
||||
formatter_class=argparse.ArgumentDefaultsHelpFormatter)
|
||||
parser = argparse.ArgumentParser(
|
||||
description='Static analysis of output of commands',
|
||||
formatter_class=argparse.ArgumentDefaultsHelpFormatter)
|
||||
parser.add_argument('--debug', dest='debug',
|
||||
help='Enable debugging',
|
||||
default=True, action='store_true')
|
||||
|
@@ -1,5 +1,3 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
|
@@ -1,10 +1,22 @@
|
||||
# common.py: Common functions and data structures used by multiple modules.
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
# common.py: Common functions and data structures used by multiple modules.
|
||||
import json
|
||||
import paramiko
|
||||
import sys
|
||||
import re
|
||||
import pprint
|
||||
import re
|
||||
import subprocess
|
||||
import sys
|
||||
import yaml
|
||||
|
||||
# Program settings
|
||||
@@ -17,7 +29,7 @@ settings = {
|
||||
|
||||
def debug(msg):
|
||||
if settings['debug']:
|
||||
if not sys.stdout == sys.__stdout__:
|
||||
if sys.stdout != sys.__stdout__:
|
||||
tmp = sys.stdout
|
||||
sys.stdout = sys.__stdout__
|
||||
print('DEBUG: ' + msg)
|
||||
@@ -27,7 +39,7 @@ def debug(msg):
|
||||
|
||||
|
||||
def error(msg):
|
||||
if not sys.stdout == sys.__stdout__:
|
||||
if sys.stdout != sys.__stdout__:
|
||||
tmp = sys.stdout
|
||||
sys.stdout = sys.__stdout__
|
||||
print('ERROR: ' + msg)
|
||||
@@ -37,7 +49,7 @@ def error(msg):
|
||||
|
||||
|
||||
def warning(msg):
|
||||
if not sys.stdout == sys.__stdout__:
|
||||
if sys.stdout != sys.__stdout__:
|
||||
tmp = sys.stdout
|
||||
sys.stdout = sys.__stdout__
|
||||
print('WARNING: ' + msg)
|
||||
@@ -49,7 +61,7 @@ def warning(msg):
|
||||
def status_update(msg):
|
||||
# storing in log file for interactive display on UI
|
||||
log = open('collector_log.txt', 'w')
|
||||
if not sys.stdout == sys.__stdout__:
|
||||
if sys.stdout != sys.__stdout__:
|
||||
tmp = sys.stdout
|
||||
sys.stdout = sys.__stdout__
|
||||
print('STATUS: ' + msg)
|
||||
@@ -61,12 +73,11 @@ def status_update(msg):
|
||||
|
||||
|
||||
def dump_json(json_info, json_filename):
|
||||
import json
|
||||
try:
|
||||
outfile = open(json_filename, "w")
|
||||
except IOError, e:
|
||||
print e
|
||||
print 'Couldn\'t open <%s>; Redirecting output to stdout' % json_filename
|
||||
except IOError as e:
|
||||
print(e)
|
||||
print('Couldn\'t open <%s>; Redirecting output to stdout' % json_filename)
|
||||
outfile = sys.stdout
|
||||
|
||||
json.dump(json_info, outfile)
|
||||
@@ -75,12 +86,11 @@ def dump_json(json_info, json_filename):
|
||||
|
||||
|
||||
def load_json(json_filename):
|
||||
import json
|
||||
try:
|
||||
infile = open(json_filename, "r")
|
||||
except IOError, e:
|
||||
print e
|
||||
print 'Couldn\'t open <%s>; Error!' % json_filename
|
||||
except IOError as e:
|
||||
print(e)
|
||||
print('Couldn\'t open <%s>; Error!' % json_filename)
|
||||
return None
|
||||
|
||||
tmp = json.load(infile)
|
||||
@@ -94,7 +104,7 @@ def connect_to_box(server, username, password, timeout=3):
|
||||
try:
|
||||
ssh.connect(server, username=username,
|
||||
password=password, timeout=timeout)
|
||||
except:
|
||||
except Exception:
|
||||
return None
|
||||
return ssh
|
||||
# def connect_to_box (server, username, password,timeout=3) :
|
||||
@@ -108,7 +118,7 @@ def ssh_cmd(ssh, cmd):
|
||||
ssh_stdin, ssh_stdout, ssh_stderr = ssh.exec_command(cmd)
|
||||
error = ssh_stderr.read()
|
||||
if len(error):
|
||||
print 'ERROR: ' + error
|
||||
print('ERROR: ' + error)
|
||||
output = ssh_stdout.read()
|
||||
ssh_stdout.flush()
|
||||
return output
|
||||
@@ -230,13 +240,15 @@ def execute_cmd(cmd, sudo=False, shell=False, env=None):
|
||||
shell=shell,
|
||||
stderr=subprocess.STDOUT,
|
||||
env=env,
|
||||
universal_newlines=True).replace('\t', ' ')
|
||||
universal_newlines=True).replace(
|
||||
'\t', ' ')
|
||||
|
||||
|
||||
def get_instance_ips(objs):
|
||||
ip_list = []
|
||||
for line in objs:
|
||||
if re.search('^\+', line) or re.search('^$', line) or re.search('Networks', line):
|
||||
if re.search('^\+', line) or re.search('^$', line) or re.search(
|
||||
'Networks', line):
|
||||
continue
|
||||
parts = line.split('|')
|
||||
parts = [x.strip() for x in parts]
|
||||
@@ -247,7 +259,8 @@ def get_instance_ips(objs):
|
||||
# excluding ipv6 ip
|
||||
if len(entry.split(',')) > 1:
|
||||
# network = entry.split('=')[0]
|
||||
ip = filter(lambda a: re.search("(\d+\.\d+\.\d+\.\d+)", a) is not None,
|
||||
ip = filter(lambda a: re.search("(\d+\.\d+\.\d+\.\d+)",
|
||||
a) is not None,
|
||||
entry.split('=')[1].split(','))[0].strip()
|
||||
ip_list.append(ip)
|
||||
else:
|
||||
@@ -259,7 +272,8 @@ def get_router_names(objs):
|
||||
routers = []
|
||||
|
||||
for line in objs:
|
||||
if re.search('^\+', line) or re.search('^$', line) or re.search('external_gateway_info', line):
|
||||
if re.search('^\+', line) or re.search('^$', line) or re.search(
|
||||
'external_gateway_info', line):
|
||||
continue
|
||||
parts = line.split('|')
|
||||
parts = [x.strip() for x in parts]
|
||||
@@ -272,9 +286,8 @@ def get_router_names(objs):
|
||||
def get_env(file_path):
|
||||
try:
|
||||
lines = open(file_path, 'r').read().splitlines()
|
||||
except IOError, e:
|
||||
print "%s :%s" % (e.args[1], file_path)
|
||||
raise
|
||||
except IOError as e:
|
||||
raise "%s :%s" % (e.args[1], file_path)
|
||||
env = {}
|
||||
for line in lines:
|
||||
if line.startswith('export'):
|
||||
@@ -290,6 +303,5 @@ def get_vm_credentials(config_file='credentials.yaml'):
|
||||
try:
|
||||
with open(config_file, 'r') as s:
|
||||
return yaml.safe_load(s)
|
||||
except IOError, e:
|
||||
print '%s :%s' % (e.args[1], config_file)
|
||||
raise
|
||||
except IOError as e:
|
||||
raise '%s :%s' % (e.args[1], config_file)
|
||||
|
@@ -1,3 +1,15 @@
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
from django import forms
|
||||
|
||||
|
||||
|
@@ -1,7 +1,19 @@
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
import pprint
|
||||
import sys
|
||||
|
||||
from common import load_json
|
||||
from openstack_dashboard.don.ovs.common import load_json
|
||||
|
||||
if len(sys.argv) != 2:
|
||||
print ('Usage: ' + sys.argv[0] + ' <json file to display>')
|
||||
|
@@ -1,12 +1,23 @@
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
# ovs.py: Runs ovs-appctl command to check if A -> B flow is working fine.
|
||||
#
|
||||
#
|
||||
import re
|
||||
import argparse
|
||||
import json
|
||||
from common import debug, settings
|
||||
from common import execute_cmd
|
||||
import re
|
||||
|
||||
from openstack_dashboard.don.ovs.common import debug
|
||||
from openstack_dashboard.don.ovs.common import execute_cmd
|
||||
from openstack_dashboard.don.ovs.common import settings
|
||||
|
||||
params = {}
|
||||
|
||||
@@ -74,7 +85,8 @@ def ovs_test(src_port_id, dst_port_id, tag, ovs_bridge):
|
||||
|
||||
if vlan != tag:
|
||||
output_dict['errors'].append(
|
||||
'%s learnt on vlan %s but should have been learnt on vlan %s on port %s' % (smac, vlan, tag, port))
|
||||
'%s learnt on vlan %s but should have been learnt on vlan %s on port %s' % (
|
||||
smac, vlan, tag, port))
|
||||
output_dict['pass'] = False
|
||||
return False
|
||||
output_dict['debugs'].append(
|
||||
@@ -116,12 +128,14 @@ def ovs_test(src_port_id, dst_port_id, tag, ovs_bridge):
|
||||
output_dict['debugs'].append(
|
||||
'Packet forwarded to correct port %s' % egress_port)
|
||||
else:
|
||||
output_dict['errors'].append('Packet forwarded to incorrect port %s, expected %s' %
|
||||
(egress_port, src_port_id))
|
||||
output_dict['errors'].append(
|
||||
'Packet forwarded to incorrect port %s, expected %s' %
|
||||
(egress_port, src_port_id))
|
||||
result = False
|
||||
else:
|
||||
output_dict['errors'].append('No egress port assigned to packet! Expected %s' %
|
||||
src_port_id)
|
||||
output_dict['errors'].append(
|
||||
'No egress port assigned to packet! Expected %s' %
|
||||
src_port_id)
|
||||
result = False
|
||||
|
||||
output_dict['pass'] = result
|
||||
@@ -132,17 +146,23 @@ def check_args():
|
||||
global params
|
||||
|
||||
parser = argparse.ArgumentParser(
|
||||
description='OVS test', formatter_class=argparse.ArgumentDefaultsHelpFormatter)
|
||||
description='OVS test',
|
||||
formatter_class=argparse.ArgumentDefaultsHelpFormatter)
|
||||
parser.add_argument('--debug', dest='debug',
|
||||
help='Enable debugging', default=False, action='store_true')
|
||||
help='Enable debugging',
|
||||
default=False, action='store_true')
|
||||
parser.add_argument('--src_port_id', dest='src_port_id',
|
||||
help='OVS src port id (required)', type=str, required=True)
|
||||
help='OVS src port id (required)',
|
||||
type=str, required=True)
|
||||
parser.add_argument('--dst_port_id', dest='dst_port_id',
|
||||
help='OVS dst port id (required)', type=str, required=True)
|
||||
help='OVS dst port id (required)',
|
||||
type=str, required=True)
|
||||
parser.add_argument(
|
||||
'--tag', dest='tag', help='VLAN tag of port (required)', type=str, required=True)
|
||||
'--tag', dest='tag', help='VLAN tag of port (required)',
|
||||
type=str, required=True)
|
||||
parser.add_argument('--ovs_bridge', dest='ovs_bridge',
|
||||
help='OVS bridge to be tested (required)', type=str, required=True)
|
||||
help='OVS bridge to be tested (required)',
|
||||
type=str, required=True)
|
||||
args = parser.parse_args()
|
||||
|
||||
settings['debug'] = args.debug
|
||||
@@ -165,12 +185,12 @@ def main():
|
||||
ovs_success = ovs_test(src_port_id, dst_port_id, tag, ovs_bridge)
|
||||
|
||||
output_dict[
|
||||
'comment'] = 'ovs %s port %s --> %s' % (ovs_bridge, src_port_id, dst_port_id)
|
||||
'comment'] = 'ovs %s port %s --> %s' % (
|
||||
ovs_bridge, src_port_id, dst_port_id)
|
||||
output_dict['pass'] = ovs_success
|
||||
|
||||
a = json.dumps(output_dict, sort_keys=True, indent=4)
|
||||
print a
|
||||
pass
|
||||
print(a)
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
|
@@ -1,19 +1,35 @@
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
# path.py: Figures out a path between two IP addresses and then traces it
|
||||
#
|
||||
# HOWTO:
|
||||
#
|
||||
import re
|
||||
import pprint
|
||||
import subprocess
|
||||
import argparse
|
||||
import os.path
|
||||
import signal
|
||||
import json
|
||||
import os.path
|
||||
import pprint
|
||||
import re
|
||||
import signal
|
||||
import subprocess
|
||||
import time
|
||||
from common import error, settings, debug, status_update
|
||||
from common import load_json, execute_cmd, dump_json
|
||||
from common import ip_to_intf, intf_to_namespace, router_to_namespace
|
||||
|
||||
from openstack_dashboard.don.ovs.common import debug
|
||||
from openstack_dashboard.don.ovs.common import dump_json
|
||||
from openstack_dashboard.don.ovs.common import error
|
||||
from openstack_dashboard.don.ovs.common import execute_cmd
|
||||
from openstack_dashboard.don.ovs.common import intf_to_namespace
|
||||
from openstack_dashboard.don.ovs.common import ip_to_intf
|
||||
from openstack_dashboard.don.ovs.common import load_json
|
||||
from openstack_dashboard.don.ovs.common import router_to_namespace
|
||||
from openstack_dashboard.don.ovs.common import settings
|
||||
from openstack_dashboard.don.ovs.common import status_update
|
||||
|
||||
COUNT = 10 # how many packets to be captured by tcpdump
|
||||
|
||||
@@ -63,7 +79,8 @@ def qrouter_usable(qrouter, src_ip, dst_ip, username, passwd):
|
||||
return False
|
||||
|
||||
|
||||
def launch_ping(src_ip, dst_ip, username, passwd, count, timeout, qrouter, filename):
|
||||
def launch_ping(src_ip, dst_ip, username, passwd,
|
||||
count, timeout, qrouter, filename):
|
||||
cmd = 'sudo ip netns exec ' + str(qrouter)
|
||||
cmd += ' python ping.py --src_ip %s --dst_ip %s --username "%s" --passwd "%s" --count %d --timeout %d' % \
|
||||
(src_ip, dst_ip, username, passwd, count, timeout)
|
||||
@@ -95,7 +112,6 @@ def capture_network_packets(params, hop_list):
|
||||
net_info['pids'].append(pid)
|
||||
status_update(
|
||||
'net: tcpdump launched with pid %d for interface %s' % (pid, dev))
|
||||
pass
|
||||
|
||||
|
||||
def capture_packets(params, tag='src', src_tag=None):
|
||||
@@ -481,8 +497,6 @@ def path(params):
|
||||
(src_ip, dst_ip))
|
||||
path_same_network(params, next_hop_list)
|
||||
|
||||
pass
|
||||
|
||||
|
||||
def main():
|
||||
|
||||
|
@@ -1,19 +1,30 @@
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
# ping.py: Runs a ping test from src_ip to dst_ip. Also provides analysis if
|
||||
# things are not okay (TBD).
|
||||
#
|
||||
# HOWTO:
|
||||
#
|
||||
# For OpenStack, this program must be run from inside the correct namespace
|
||||
#
|
||||
# sudo ip netns exec qrouter-ac41aab2-f9c3-4a06-8eef-f909ee1e6e50 python ping.py 10.0.3.3 10.0.2.4 cirros "cubswin:)"
|
||||
#
|
||||
import re
|
||||
|
||||
import argparse
|
||||
import json
|
||||
from common import connect_to_box, ssh_cmd
|
||||
from common import settings
|
||||
import re
|
||||
|
||||
from openstack_dashboard.don.ovs.common import connect_to_box
|
||||
from openstack_dashboard.don.ovs.common import settings
|
||||
from openstack_dashboard.don.ovs.common import ssh_cmd
|
||||
|
||||
params = {}
|
||||
|
||||
@@ -56,8 +67,8 @@ def ping_test(src_ip, dst_ip, username, passwd, count, timeout):
|
||||
result = True
|
||||
break
|
||||
except (KeyboardInterrupt, SystemExit):
|
||||
print '\nkeyboardinterrupt caught (again)'
|
||||
print '\n...Program Stopped Manually!'
|
||||
print('\nkeyboardinterrupt caught (again)')
|
||||
print('\n...Program Stopped Manually!')
|
||||
raise
|
||||
cmd_dict['pass'] = result
|
||||
output_dict['command_list'].append(cmd_dict)
|
||||
@@ -115,8 +126,7 @@ def main():
|
||||
output_dict['comment'] = 'PING %s to %s' % (src_ip, dst_ip)
|
||||
output_dict['pass'] = ping_success
|
||||
|
||||
a = json.dumps(output_dict, sort_keys=True, indent=4)
|
||||
print a
|
||||
print(json.dumps(output_dict, sort_keys=True, indent=4))
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
|
@@ -1,19 +1,36 @@
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# plot.py: Generates an SVG file showing the networking internals of a compute node.
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
import pprint
|
||||
import subprocess
|
||||
import re
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
import argparse
|
||||
import sys
|
||||
import pprint
|
||||
import random
|
||||
import re
|
||||
import subprocess
|
||||
import sys
|
||||
|
||||
from common import settings, debug, warning
|
||||
from common import load_json, get_subnet
|
||||
from common import get_vlan_tag, get_intf_ip, get_ip_network
|
||||
from common import debug
|
||||
from common import get_intf_ip
|
||||
from common import get_ip_network
|
||||
from common import get_subnet
|
||||
from common import get_vlan_tag
|
||||
from common import load_json
|
||||
from common import settings
|
||||
from common import warning
|
||||
|
||||
|
||||
class DotGenerator:
|
||||
class DotGenerator(object):
|
||||
"""Generates an SVG file showing the network internals of
|
||||
|
||||
a compute node.
|
||||
"""
|
||||
|
||||
def __init__(self, in_json_filename,
|
||||
compute_dot_file, compute_svg_file,
|
||||
@@ -236,34 +253,34 @@ class DotGenerator:
|
||||
return port_count
|
||||
|
||||
def __html_row_open(self):
|
||||
print '<TR>'
|
||||
print('<TR>')
|
||||
|
||||
def __html_row_close(self):
|
||||
print '</TR>'
|
||||
print('</TR>')
|
||||
|
||||
def __html_row(self, name, rspan, cspan, color, tag=None):
|
||||
# tags do not allow "-" (dash) in DOT language. Convert to "_"
|
||||
# (underscore)
|
||||
if tag:
|
||||
print '<TD ROWSPAN="%d" COLSPAN="%d" BGCOLOR="%s" PORT="%s">%s</TD>' % (rspan, cspan, color, tag.replace('-', '_'), name)
|
||||
print('<TD ROWSPAN="%d" COLSPAN="%d" BGCOLOR="%s" PORT="%s">%s</TD>' % (rspan, cspan, color, tag.replace('-', '_'), name))
|
||||
else:
|
||||
print '<TD ROWSPAN="%d" COLSPAN="%d" BGCOLOR="%s">%s</TD>' % (rspan, cspan, color, name)
|
||||
print('<TD ROWSPAN="%d" COLSPAN="%d" BGCOLOR="%s">%s</TD>' % (rspan, cspan, color, name))
|
||||
pass
|
||||
|
||||
def __html_edge(selft, src_tag, dst_tag, color, penwidth="4", style=None):
|
||||
src_tag = src_tag.replace('-', '_')
|
||||
dst_tag = dst_tag.replace('-', '_')
|
||||
if not style:
|
||||
print '%s:s -> %s:n [color = "%s", penwidth = "%s"]' % (src_tag,
|
||||
print('%s:s -> %s:n [color = "%s", penwidth = "%s"]' % (src_tag,
|
||||
dst_tag,
|
||||
color,
|
||||
penwidth)
|
||||
penwidth))
|
||||
else:
|
||||
print '%s:s -> %s:n [color = "%s", penwidth = "%s", style="%s"]' % (src_tag,
|
||||
print('%s:s -> %s:n [color = "%s", penwidth = "%s", style="%s"]' % (src_tag,
|
||||
dst_tag,
|
||||
color,
|
||||
penwidth,
|
||||
style)
|
||||
style))
|
||||
|
||||
def __digraph_open(self, tag):
|
||||
msg = 'digraph DON_' + tag + ' {' + \
|
||||
@@ -276,36 +293,36 @@ concentrate = true;
|
||||
compound = true;
|
||||
edge [dir=none]
|
||||
'''
|
||||
print msg
|
||||
print(msg)
|
||||
|
||||
def __digraph_close(self):
|
||||
msg = '\n}\n'
|
||||
print msg
|
||||
print(msg)
|
||||
|
||||
def __cluster_name(self, tag, col_span, color="white"):
|
||||
self.__html_row_open()
|
||||
port = tag.replace(' ', '').replace('-', '_')
|
||||
print '<TD COLSPAN="%d" BORDER="0" BGCOLOR="%s" PORT="%s">%s</TD>' % (col_span, color, port, tag)
|
||||
print('<TD COLSPAN="%d" BORDER="0" BGCOLOR="%s" PORT="%s">%s</TD>' % (col_span, color, port, tag))
|
||||
self.__html_row_close()
|
||||
|
||||
def __cluster_open_plain(self, tag, label=None):
|
||||
print 'subgraph cluster_%s {' % (tag)
|
||||
print 'style=filled'
|
||||
print('subgraph cluster_%s {' % (tag))
|
||||
print('style=filled')
|
||||
if label:
|
||||
print 'label="%s"' % (label)
|
||||
print('label="%s"' % (label))
|
||||
|
||||
def __cluster_close_plain(self):
|
||||
print '}\n'
|
||||
print('}\n')
|
||||
|
||||
def __cluster_open(self, tag, color="white"):
|
||||
print 'subgraph cluster_%s {' % (tag)
|
||||
print '%s [ shape = plaintext, label = <' % (tag)
|
||||
print '<TABLE BORDER="0" CELLBORDER="1" CELLSPACING="5" CELLPADDING="5" BGCOLOR="%s">' % (color)
|
||||
print('subgraph cluster_%s {' % (tag))
|
||||
print('%s [ shape = plaintext, label = <' % (tag))
|
||||
print('<TABLE BORDER="0" CELLBORDER="1" CELLSPACING="5" CELLPADDING="5" BGCOLOR="%s">' % (color))
|
||||
pass
|
||||
|
||||
def __cluster_close(self):
|
||||
print '</TABLE>>];\n'
|
||||
print '}\n'
|
||||
print('</TABLE>>];\n')
|
||||
print('}\n')
|
||||
pass
|
||||
|
||||
def __plot_title_edges(self, tag):
|
||||
@@ -451,7 +468,8 @@ edge [dir=none]
|
||||
if br_int['ports'].has_key(qvo_port):
|
||||
tag = br_int['ports'][qvo_port]['tag']
|
||||
self.__html_row('VLAN tag:' + tag, row_span, col_span,
|
||||
self.__get_vlan_color(tag), qvo_port + 'tag_' + tag)
|
||||
self.__get_vlan_color(tag),
|
||||
qvo_port + 'tag_' + tag)
|
||||
self.__html_row_close()
|
||||
|
||||
col_span = self.__get_total_vm_port_count()
|
||||
@@ -468,9 +486,7 @@ edge [dir=none]
|
||||
self.__html_row_close()
|
||||
|
||||
self.__cluster_close()
|
||||
pass
|
||||
|
||||
# TODO
|
||||
def __plot_br_ex_to_br_int(self):
|
||||
namespaces = self.info['namespaces']
|
||||
|
||||
@@ -492,7 +508,6 @@ edge [dir=none]
|
||||
dst_tag = 'network_br_int:' + intf
|
||||
self.__html_edge(src_tag, dst_tag,
|
||||
self.__get_color('edge'))
|
||||
pass
|
||||
|
||||
def __plot_br_ex_network(self):
|
||||
routers = self.info['routers']
|
||||
@@ -571,9 +586,11 @@ edge [dir=none]
|
||||
port_id = '[' + br_int['ports'][intf]['id'] + '] '
|
||||
color = self.__get_vlan_color(tag, intf)
|
||||
self.__html_row(
|
||||
port_id + intf, row_span, col_span, color, intf)
|
||||
port_id + intf, row_span,
|
||||
col_span, color, intf)
|
||||
# now plot the corresponding tap interface
|
||||
(tap_nms, tap) = self.__get_tap_interface(nms, intf)
|
||||
(tap_nms, tap) = self.__get_tap_interface(nms,
|
||||
intf)
|
||||
tag = br_int['ports'][tap]['tag']
|
||||
color = self.__get_vlan_color(tag, tap)
|
||||
port_id = '[' + br_int['ports'][tap]['id'] + '] '
|
||||
@@ -602,7 +619,8 @@ edge [dir=none]
|
||||
|
||||
tag = br_int['ports'][tap_intf]['tag']
|
||||
self.__html_row('VLAN tag:' + tag, row_span, col_span,
|
||||
self.__get_vlan_color(tag), tap_intf + 'tag_' + tag)
|
||||
self.__get_vlan_color(tag),
|
||||
tap_intf + 'tag_' + tag)
|
||||
|
||||
self.__html_row_close()
|
||||
|
||||
@@ -695,7 +713,6 @@ edge [dir=none]
|
||||
color = self.__get_edge_color(src_tag, dst_tag)
|
||||
self.__html_edge(src_tag, dst_tag, color)
|
||||
break
|
||||
pass
|
||||
|
||||
def __plot_linuxbridge_to_br_int(self):
|
||||
brctl = self.info['brctl']
|
||||
@@ -713,7 +730,6 @@ edge [dir=none]
|
||||
color = self.__get_edge_color(src_tag, dst_tag)
|
||||
self.__html_edge(src_tag, dst_tag, color)
|
||||
break
|
||||
pass
|
||||
|
||||
def __plot_br_int_to_br_tun(self, tag):
|
||||
br_int = self.info['bridges']['br-int']['ports']
|
||||
@@ -734,7 +750,6 @@ edge [dir=none]
|
||||
self.__html_edge(src_tag, dst_tag,
|
||||
self.__get_color('edge'))
|
||||
return
|
||||
pass
|
||||
|
||||
def plot_combined(self):
|
||||
self.outfile = open(self.combined_dot_file, 'w')
|
||||
@@ -845,12 +860,15 @@ edge [dir=none]
|
||||
|
||||
|
||||
def check_args():
|
||||
parser = argparse.ArgumentParser(description='Plot the compute node network internals',
|
||||
formatter_class=argparse.ArgumentDefaultsHelpFormatter)
|
||||
parser = argparse.ArgumentParser(
|
||||
description='Plot the compute node network internals',
|
||||
formatter_class=argparse.ArgumentDefaultsHelpFormatter)
|
||||
parser.add_argument('--debug', dest='debug',
|
||||
help='Enable debugging', default=True, action='store_true')
|
||||
help='Enable debugging',
|
||||
default=True, action='store_true')
|
||||
parser.add_argument('--info_file', dest='info_file',
|
||||
help='Info is read in JSON format in this file', default="don.json", type=str)
|
||||
help='Info is read in JSON format in this file',
|
||||
default="don.json", type=str)
|
||||
parser.add_argument('--compute_file', dest='compute_file',
|
||||
help='[compute_file].dot and [compute_file].svg will be generated for compute node', default="compute", type=str)
|
||||
parser.add_argument('--network_file', dest='network_file',
|
||||
@@ -858,7 +876,8 @@ def check_args():
|
||||
parser.add_argument('--combined_file', dest='combined_file',
|
||||
help='[combined_file].dot and [combined_file].svg will be generated', default="don", type=str)
|
||||
parser.add_argument('--highlight_file', dest='highlight_file',
|
||||
help='pass and fail node are specified in this file', default=None, type=str)
|
||||
help='pass and fail node are specified in this file',
|
||||
default=None, type=str)
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
|
@@ -1,13 +1,23 @@
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
# run_nms_cmd.py: This needs to be run from inside appropriate namespace
|
||||
#
|
||||
# sudo ip netns exec qrouter-ac41aab2-f9c3-4a06-8eef-f909ee1e6e50 python # run_nms_cmd.py "command"
|
||||
#
|
||||
import argparse
|
||||
import json
|
||||
from common import connect_to_box, ssh_cmd
|
||||
from common import settings
|
||||
|
||||
from openstack_dashboard.don.ovs.common import connect_to_box
|
||||
from openstack_dashboard.don.ovs.common import settings
|
||||
from openstack_dashboard.don.ovs.common import ssh_cmd
|
||||
|
||||
params = {}
|
||||
|
||||
@@ -45,8 +55,8 @@ def run_nms_cmd(args):
|
||||
cmd_dict['cmd'] = cmd
|
||||
cmd_dict['output'] = output
|
||||
except (KeyboardInterrupt, SystemExit):
|
||||
print '\nkeyboardinterrupt caught (again)'
|
||||
print '\n...Program Stopped Manually!'
|
||||
print('\nkeyboardinterrupt caught (again)')
|
||||
print('\n...Program Stopped Manually!')
|
||||
result = False
|
||||
raise
|
||||
cmd_dict['pass'] = result
|
||||
@@ -58,17 +68,23 @@ def check_args():
|
||||
global params
|
||||
|
||||
parser = argparse.ArgumentParser(
|
||||
description='Run command from inside nms', formatter_class=argparse.ArgumentDefaultsHelpFormatter)
|
||||
description='Run command from inside nms',
|
||||
formatter_class=argparse.ArgumentDefaultsHelpFormatter)
|
||||
parser.add_argument('--debug', dest='debug',
|
||||
help='Enable debugging', default=False, action='store_true')
|
||||
help='Enable debugging',
|
||||
default=False, action='store_true')
|
||||
parser.add_argument('--host_ip', dest='host_ip',
|
||||
help='IP where the command will be run', type=str, required=True)
|
||||
help='IP where the command will be run',
|
||||
type=str, required=True)
|
||||
parser.add_argument('--username', dest='username',
|
||||
help='SSH login username (required)', type=str, required=True)
|
||||
help='SSH login username (required)',
|
||||
type=str, required=True)
|
||||
parser.add_argument('--passwd', dest='passwd',
|
||||
help='SSH login passwd (required)', type=str, required=True)
|
||||
help='SSH login passwd (required)',
|
||||
type=str, required=True)
|
||||
parser.add_argument('--cmd', dest='cmd',
|
||||
help='cmd to be run', type=str, required=True)
|
||||
help='cmd to be run',
|
||||
type=str, required=True)
|
||||
args = parser.parse_args()
|
||||
|
||||
settings['debug'] = args.debug
|
||||
@@ -85,8 +101,7 @@ def main():
|
||||
|
||||
output_dict['pass'] = run_nms_cmd(params)
|
||||
|
||||
a = json.dumps(output_dict, sort_keys=True, indent=4)
|
||||
print a
|
||||
print(json.dumps(output_dict, sort_keys=True, indent=4))
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
|
@@ -1,11 +1,19 @@
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
from django.conf.urls import patterns
|
||||
from django.conf.urls import url
|
||||
|
||||
from don.ovs.views \
|
||||
import IndexView
|
||||
|
||||
from . import views
|
||||
|
||||
from don.ovs.views import IndexView
|
||||
import openstack_dashboard.don.ovs.views as views
|
||||
|
||||
urlpatterns = patterns(
|
||||
'',
|
||||
|
@@ -1,20 +1,33 @@
|
||||
from horizon import views
|
||||
from django.http import HttpResponse
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
from django.conf import settings
|
||||
from plot import DotGenerator
|
||||
import os
|
||||
import subprocess
|
||||
from .forms import PingForm
|
||||
# from django.shortcuts import render_to_response
|
||||
from horizon import messages
|
||||
import analyzer
|
||||
import path
|
||||
from common import execute_cmd, get_instance_ips, get_env, get_router_names
|
||||
import json
|
||||
import shlex
|
||||
|
||||
|
||||
from django.http import HttpResponse
|
||||
from django.shortcuts import render
|
||||
from forms import PingForm
|
||||
from horizon import messages
|
||||
from horizon import views
|
||||
import json
|
||||
import os
|
||||
import shlex
|
||||
import subprocess
|
||||
|
||||
import openstack_dashboard.don.ovs.analyzer as analyzer
|
||||
from openstack_dashboard.don.ovs.common import execute_cmd
|
||||
from openstack_dashboard.don.ovs.common import get_env
|
||||
from openstack_dashboard.don.ovs.common import get_instance_ips
|
||||
from openstack_dashboard.don.ovs.common import get_router_names
|
||||
import openstack_dashboard.don.ovs.path as path
|
||||
from openstack_dashboard.don.ovs.plot import DotGenerator
|
||||
|
||||
|
||||
class IndexView(views.APIView):
|
||||
@@ -31,8 +44,6 @@ def index(request):
|
||||
|
||||
|
||||
def view(request):
|
||||
# import pdb
|
||||
# pdb.set_trace()
|
||||
pwd = settings.ROOT_PATH # +'/openstack_dashboard/dashboards/admin/don/'
|
||||
|
||||
JSON_FILE = pwd + '/don/ovs/don.json'
|
||||
@@ -53,7 +64,6 @@ def view(request):
|
||||
COMBINED_SVG_FILE = static_path + '/don/don.svg'
|
||||
|
||||
macro = {}
|
||||
# return HttpResponseRedirect('static/view.html')
|
||||
|
||||
plotter = DotGenerator(JSON_FILE,
|
||||
COMPUTE_DOT_FILE,
|
||||
@@ -72,12 +82,11 @@ def view(request):
|
||||
|
||||
plotter.plot_combined()
|
||||
plotter.generate_combined_svg()
|
||||
# return HttpResponseRedirect('static/view.html')
|
||||
|
||||
return render(request, "don/ovs/views.html", macro)
|
||||
|
||||
|
||||
def analyze(request):
|
||||
# pwd = settings.BASE_DIR
|
||||
pwd = settings.ROOT_PATH
|
||||
JSON_FILE = pwd + '/don/ovs/don.json'
|
||||
|
||||
@@ -89,14 +98,9 @@ def analyze(request):
|
||||
'test:ovs': True,
|
||||
'test:report_file': pwd + '/don/templates/don/don.report.html',
|
||||
}
|
||||
print "params ====> ", params
|
||||
print("params ====> ", params)
|
||||
analyzer.analyze(JSON_FILE, params)
|
||||
# output = analyzer.analyze(JSON_FILE, params)
|
||||
# html = '<html><body>Output: %s</body></html>' % output
|
||||
# return HttpResponse(html)
|
||||
# return HttpResponseRedirect('/static/don.report.html')
|
||||
return render(request, "don/ovs/analyze.html")
|
||||
# return render_to_response('don/ovs/analyze.html')
|
||||
|
||||
|
||||
def test(request):
|
||||
@@ -111,13 +115,10 @@ def ping(request):
|
||||
# check whether it's valid:
|
||||
if form.is_valid():
|
||||
# process the data in form.cleaned_data as required
|
||||
# ...
|
||||
# redirect to a new URL:
|
||||
src_ip = form.cleaned_data['src_ip']
|
||||
dst_ip = form.cleaned_data['dst_ip']
|
||||
router = form.cleaned_data['router']
|
||||
# html = '<html><body>SIP: %s DIP: %s router: %s</body></html>' % (src_ip, dst_ip, router)
|
||||
# return HttpResponse(html)
|
||||
static_path = settings.STATIC_ROOT
|
||||
pwd = settings.ROOT_PATH
|
||||
JSON_FILE = pwd + '/don/ovs/don.json'
|
||||
@@ -148,7 +149,6 @@ def ping(request):
|
||||
NETWORK_SVG_FILE = None
|
||||
COMBINED_DOT_FILE = static_path + '/don/ping.dot'
|
||||
COMBINED_SVG_FILE = static_path + '/don/ping.svg'
|
||||
# HIGHLIGHT_FILE = pwd + '/don/ovs/static/ping.html'
|
||||
HIGHLIGHT_FILE = static_path + '/don/ping.html'
|
||||
|
||||
plotter = DotGenerator(JSON_FILE,
|
||||
@@ -163,7 +163,6 @@ def ping(request):
|
||||
plotter.plot_combined()
|
||||
plotter.generate_combined_svg()
|
||||
|
||||
# return HttpResponseRedirect('/static/path.html')
|
||||
return render(request, 'don/ovs/path.html')
|
||||
|
||||
# if a GET (or any other method) we'll create a blank form
|
||||
@@ -177,7 +176,8 @@ def ping(request):
|
||||
ip_list = get_instance_ips(output)
|
||||
ip_list.sort()
|
||||
router_op = execute_cmd(
|
||||
['neutron', 'router-list'], sudo=False, shell=False, env=myenv).split('\n')
|
||||
['neutron', 'router-list'],
|
||||
sudo=False, shell=False, env=myenv).split('\n')
|
||||
router_list = get_router_names(router_op)
|
||||
router_list.sort()
|
||||
# insert first value of select menu
|
||||
@@ -197,11 +197,11 @@ def collect(request):
|
||||
status = 0
|
||||
|
||||
BASE_DIR = settings.ROOT_PATH
|
||||
# CUR_DIR = os.getcwd()
|
||||
os.chdir(BASE_DIR + '/don/ovs')
|
||||
cmd = 'sudo python collector.py'
|
||||
for line in run_command(cmd):
|
||||
if line.startswith('STATUS:') and line.find('Writing collected info') != -1:
|
||||
if line.startswith('STATUS:') and line.find(
|
||||
'Writing collected info') != -1:
|
||||
status = 1
|
||||
macro['collect_status'] = \
|
||||
"Collecton successful. Click visualize to display"
|
||||
@@ -230,4 +230,5 @@ def get_status(request):
|
||||
BASE_DIR = settings.ROOT_PATH + '/don/ovs/'
|
||||
status = open(BASE_DIR + 'collector_log.txt', 'r').readline()
|
||||
if status != " " and status != '\n':
|
||||
return HttpResponse(json.dumps({'status': status}), content_type="application/json")
|
||||
return HttpResponse(json.dumps(
|
||||
{'status': status}), content_type="application/json")
|
||||
|
Reference in New Issue
Block a user