Change-Id: I58cb77d708542aaf3a90d4127eddffad67b42956changes/13/104813/1
parent
cf446f9389
commit
d915ab59c3
@ -1,38 +0,0 @@
|
||||
Debug Helper Script for Neutron
|
||||
|
||||
- Configure
|
||||
export NEUTRON_TEST_CONFIG_FILE=/etc/neutron/debug.ini
|
||||
or
|
||||
export NEUTRON_TEST_CONFIG_FILE=/etc/neutron/l3_agent.ini
|
||||
|
||||
you can also specify config file by --config-file option
|
||||
|
||||
- Usage
|
||||
neutron-debug commands
|
||||
|
||||
probe-create <net-id>
|
||||
Create probe port - create port and interface, then plug it in.
|
||||
This commands returns a port id of a probe port. A probe port is a port which is used to test.
|
||||
The port id is probe id.
|
||||
We can have multiple probe probes in a network, in order to check connectivity between ports.
|
||||
|
||||
neutron-debug probe-exec probe_id_1 'nc -l 192.168.100.3 22'
|
||||
neutron-debug probe-exec probe_id_2 'nc -vz 192.168.100.4 22'
|
||||
|
||||
Note: You should use a user and a tenant who has permission to
|
||||
modify network and subnet if you want to probe. For example, you need to be admin user if you
|
||||
want to probe external network.
|
||||
|
||||
probe-delete <port-id> Delete probe - delete port then uplug
|
||||
probe-exec <port-id> 'command' Exec commands on the namespace of the probe
|
||||
`probe-exec <port-id>` 'interactive command' Exec interactive command (eg, ssh)
|
||||
|
||||
probe-list List probes
|
||||
probe-clear Clear All probes
|
||||
|
||||
ping-all --id <network_id> --timeout 1 (optional)
|
||||
ping-all is all-in-one command to ping all fixed ip's in all network or a specified network.
|
||||
In the command probe is automatically created if needed.
|
||||
|
||||
neutron-debug extends the shell of neutronclient, so you can use all the commands of neutron
|
||||
|
@ -1,16 +0,0 @@
|
||||
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
||||
#
|
||||
# Copyright 2012, Nachi Ueno, NTT MCL, Inc.
|
||||
# All Rights Reserved.
|
||||
#
|
||||
# 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.
|
@ -1,157 +0,0 @@
|
||||
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
||||
|
||||
# Copyright 2012, Nachi Ueno, NTT MCL, Inc.
|
||||
# All Rights Reserved.
|
||||
#
|
||||
# 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 cliff import lister
|
||||
from neutronclient.common import utils
|
||||
from neutronclient.neutron import v2_0 as client
|
||||
from neutronclient.neutron.v2_0 import port
|
||||
|
||||
from neutron.openstack.common import log as logging
|
||||
|
||||
|
||||
class ProbeCommand(client.NeutronCommand):
|
||||
log = logging.getLogger(__name__ + '.ProbeCommand')
|
||||
|
||||
def get_debug_agent(self):
|
||||
return self.app.debug_agent
|
||||
|
||||
def run(self, parsed_args):
|
||||
self.log.debug('run(%s)', parsed_args)
|
||||
self.log.info(_('Unimplemented commands'))
|
||||
|
||||
|
||||
class CreateProbe(ProbeCommand):
|
||||
"""Create probe port and interface, then plug it in."""
|
||||
|
||||
log = logging.getLogger(__name__ + '.CreateProbe')
|
||||
|
||||
def get_parser(self, prog_name):
|
||||
parser = super(CreateProbe, self).get_parser(prog_name)
|
||||
parser.add_argument(
|
||||
'id', metavar='network_id',
|
||||
help=_('ID of network to probe'))
|
||||
parser.add_argument(
|
||||
'--device-owner',
|
||||
default='network', choices=['network', 'compute'],
|
||||
help=_('Owner type of the device: network/compute'))
|
||||
return parser
|
||||
|
||||
def run(self, parsed_args):
|
||||
self.log.debug('run(%s)' % parsed_args)
|
||||
debug_agent = self.get_debug_agent()
|
||||
probe_port = debug_agent.create_probe(parsed_args.id,
|
||||
parsed_args.device_owner)
|
||||
self.log.info(_('Probe created : %s '), probe_port.id)
|
||||
|
||||
|
||||
class DeleteProbe(ProbeCommand):
|
||||
"""Delete probe - delete port then uplug."""
|
||||
|
||||
log = logging.getLogger(__name__ + '.DeleteProbe')
|
||||
|
||||
def get_parser(self, prog_name):
|
||||
parser = super(DeleteProbe, self).get_parser(prog_name)
|
||||
parser.add_argument(
|
||||
'id', metavar='port_id',
|
||||
help=_('ID of probe port to delete'))
|
||||
return parser
|
||||
|
||||
def run(self, parsed_args):
|
||||
self.log.debug('run(%s)' % parsed_args)
|
||||
debug_agent = self.get_debug_agent()
|
||||
debug_agent.delete_probe(parsed_args.id)
|
||||
self.log.info(_('Probe %s deleted'), parsed_args.id)
|
||||
|
||||
|
||||
class ListProbe(client.NeutronCommand, lister.Lister):
|
||||
"""List probes."""
|
||||
|
||||
log = logging.getLogger(__name__ + '.ListProbe')
|
||||
_formatters = {'fixed_ips': port._format_fixed_ips, }
|
||||
|
||||
def get_debug_agent(self):
|
||||
return self.app.debug_agent
|
||||
|
||||
def get_data(self, parsed_args):
|
||||
|
||||
debug_agent = self.get_debug_agent()
|
||||
info = debug_agent.list_probes()
|
||||
columns = len(info) > 0 and sorted(info[0].keys()) or []
|
||||
return (columns, (utils.get_item_properties(
|
||||
s, columns, formatters=self._formatters, )
|
||||
for s in info), )
|
||||
|
||||
|
||||
class ClearProbe(ProbeCommand):
|
||||
"""Clear All probes."""
|
||||
|
||||
log = logging.getLogger(__name__ + '.ClearProbe')
|
||||
|
||||
def run(self, parsed_args):
|
||||
self.log.debug('run(%s)' % parsed_args)
|
||||
debug_agent = self.get_debug_agent()
|
||||
debug_agent.clear_probe()
|
||||
self.log.info(_('All Probes deleted '))
|
||||
|
||||
|
||||
class ExecProbe(ProbeCommand):
|
||||
"""Exec commands on the namespace of the probe."""
|
||||
|
||||
log = logging.getLogger(__name__ + '.ExecProbe')
|
||||
|
||||
def get_parser(self, prog_name):
|
||||
parser = super(ExecProbe, self).get_parser(prog_name)
|
||||
parser.add_argument(
|
||||
'id', metavar='port_id',
|
||||
help=_('ID of probe port to execute command'))
|
||||
parser.add_argument(
|
||||
'command', metavar='command',
|
||||
nargs='?',
|
||||
default=None,
|
||||
help=_('Command to execute'))
|
||||
return parser
|
||||
|
||||
def run(self, parsed_args):
|
||||
self.log.debug('run(%s)' % parsed_args)
|
||||
debug_agent = self.get_debug_agent()
|
||||
result = debug_agent.exec_command(parsed_args.id, parsed_args.command)
|
||||
self.app.stdout.write(result + '\n')
|
||||
|
||||
|
||||
class PingAll(ProbeCommand):
|
||||
"""Ping all fixed_ip."""
|
||||
|
||||
log = logging.getLogger(__name__ + '.ExecProbe')
|
||||
|
||||
def get_parser(self, prog_name):
|
||||
parser = super(PingAll, self).get_parser(prog_name)
|
||||
parser.add_argument(
|
||||
'--timeout', metavar='<timeout>',
|
||||
default=10,
|
||||
help=_('Ping timeout'))
|
||||
parser.add_argument(
|
||||
'--id', metavar='network_id',
|
||||
default=None,
|
||||
help=_('ID of network'))
|
||||
return parser
|
||||
|
||||
def run(self, parsed_args):
|
||||
self.log.debug('run(%s)' % parsed_args)
|
||||
debug_agent = self.get_debug_agent()
|
||||
result = debug_agent.ping_all(parsed_args.id,
|
||||
timeout=parsed_args.timeout)
|
||||
self.app.stdout.write(result + '\n')
|
@ -1,198 +0,0 @@
|
||||
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
||||
|
||||
# Copyright 2012, Nachi Ueno, NTT MCL, Inc.
|
||||
# All Rights Reserved.
|
||||
#
|
||||
# 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 shlex
|
||||
import socket
|
||||
|
||||
import netaddr
|
||||
from oslo.config import cfg
|
||||
|
||||
from neutron.agent.common import config
|
||||
from neutron.agent.linux import dhcp
|
||||
from neutron.agent.linux import ip_lib
|
||||
from neutron.agent.linux import utils
|
||||
from neutron.openstack.common import log as logging
|
||||
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
DEVICE_OWNER_NETWORK_PROBE = 'network:probe'
|
||||
|
||||
DEVICE_OWNER_COMPUTE_PROBE = 'compute:probe'
|
||||
|
||||
|
||||
class NeutronDebugAgent():
|
||||
|
||||
OPTS = [
|
||||
# Needed for drivers
|
||||
cfg.StrOpt('external_network_bridge', default='br-ex',
|
||||
help=_("Name of bridge used for external network "
|
||||
"traffic.")),
|
||||
]
|
||||
|
||||
def __init__(self, conf, client, driver):
|
||||
self.conf = conf
|
||||
self.root_helper = config.get_root_helper(conf)
|
||||
self.client = client
|
||||
self.driver = driver
|
||||
|
||||
def _get_namespace(self, port):
|
||||
return "qprobe-%s" % port.id
|
||||
|
||||
def create_probe(self, network_id, device_owner='network'):
|
||||
network = self._get_network(network_id)
|
||||
bridge = None
|
||||
if network.external:
|
||||
bridge = self.conf.external_network_bridge
|
||||
|
||||
port = self._create_port(network, device_owner)
|
||||
interface_name = self.driver.get_device_name(port)
|
||||
namespace = None
|
||||
if self.conf.use_namespaces:
|
||||
namespace = self._get_namespace(port)
|
||||
|
||||
if ip_lib.device_exists(interface_name, self.root_helper, namespace):
|
||||
LOG.debug(_('Reusing existing device: %s.'), interface_name)
|
||||
else:
|
||||
self.driver.plug(network.id,
|
||||
port.id,
|
||||
interface_name,
|
||||
port.mac_address,
|
||||
bridge=bridge,
|
||||
namespace=namespace)
|
||||
ip_cidrs = []
|
||||
for fixed_ip in port.fixed_ips:
|
||||
subnet = fixed_ip.subnet
|
||||
net = netaddr.IPNetwork(subnet.cidr)
|
||||
ip_cidr = '%s/%s' % (fixed_ip.ip_address, net.prefixlen)
|
||||
ip_cidrs.append(ip_cidr)
|
||||
self.driver.init_l3(interface_name, ip_cidrs, namespace=namespace)
|
||||
return port
|
||||
|
||||
def _get_subnet(self, subnet_id):
|
||||
subnet_dict = self.client.show_subnet(subnet_id)['subnet']
|
||||
return dhcp.DictModel(subnet_dict)
|
||||
|
||||
def _get_network(self, network_id):
|
||||
network_dict = self.client.show_network(network_id)['network']
|
||||
network = dhcp.DictModel(network_dict)
|
||||
network.external = network_dict.get('router:external')
|
||||
obj_subnet = [self._get_subnet(s_id) for s_id in network.subnets]
|
||||
network.subnets = obj_subnet
|
||||
return network
|
||||
|
||||
def clear_probe(self):
|
||||
ports = self.client.list_ports(
|
||||
device_id=socket.gethostname(),
|
||||
device_owner=[DEVICE_OWNER_NETWORK_PROBE,
|
||||
DEVICE_OWNER_COMPUTE_PROBE])
|
||||
info = ports['ports']
|
||||
for port in info:
|
||||
self.delete_probe(port['id'])
|
||||
|
||||
def delete_probe(self, port_id):
|
||||
port = dhcp.DictModel(self.client.show_port(port_id)['port'])
|
||||
network = self._get_network(port.network_id)
|
||||
bridge = None
|
||||
if network.external:
|
||||
bridge = self.conf.external_network_bridge
|
||||
ip = ip_lib.IPWrapper(self.root_helper)
|
||||
namespace = self._get_namespace(port)
|
||||
if self.conf.use_namespaces and ip.netns.exists(namespace):
|
||||
self.driver.unplug(self.driver.get_device_name(port),
|
||||
bridge=bridge,
|
||||
namespace=namespace)
|
||||
try:
|
||||
ip.netns.delete(namespace)
|
||||
except Exception:
|
||||
LOG.warn(_('Failed to delete namespace %s'), namespace)
|
||||
else:
|
||||
self.driver.unplug(self.driver.get_device_name(port),
|
||||
bridge=bridge)
|
||||
self.client.delete_port(port.id)
|
||||
|
||||
def list_probes(self):
|
||||
ports = self.client.list_ports(
|
||||
device_owner=[DEVICE_OWNER_NETWORK_PROBE,
|
||||
DEVICE_OWNER_COMPUTE_PROBE])
|
||||
info = ports['ports']
|
||||
for port in info:
|
||||
port['device_name'] = self.driver.get_device_name(
|
||||
dhcp.DictModel(port))
|
||||
return info
|
||||
|
||||
def exec_command(self, port_id, command=None):
|
||||
port = dhcp.DictModel(self.client.show_port(port_id)['port'])
|
||||
ip = ip_lib.IPWrapper(self.root_helper)
|
||||
namespace = self._get_namespace(port)
|
||||
if self.conf.use_namespaces:
|
||||
if not command:
|
||||
return "sudo ip netns exec %s" % self._get_namespace(port)
|
||||
namespace = ip.ensure_namespace(namespace)
|
||||
return namespace.netns.execute(shlex.split(command))
|
||||
else:
|
||||
return utils.execute(shlex.split(command))
|
||||
|
||||
def ensure_probe(self, network_id):
|
||||
ports = self.client.list_ports(network_id=network_id,
|
||||
device_id=socket.gethostname(),
|
||||
device_owner=DEVICE_OWNER_NETWORK_PROBE)
|
||||
info = ports.get('ports', [])
|
||||
if info:
|
||||
return dhcp.DictModel(info[0])
|
||||
else:
|
||||
return self.create_probe(network_id)
|
||||
|
||||
def ping_all(self, network_id=None, timeout=1):
|
||||
if network_id:
|
||||
ports = self.client.list_ports(network_id=network_id)['ports']
|
||||
else:
|
||||
ports = self.client.list_ports()['ports']
|
||||
result = ""
|
||||
for port in ports:
|
||||
probe = self.ensure_probe(port['network_id'])
|
||||
if port['device_owner'] == DEVICE_OWNER_NETWORK_PROBE:
|
||||
continue
|
||||
for fixed_ip in port['fixed_ips']:
|
||||
address = fixed_ip['ip_address']
|
||||
subnet = self._get_subnet(fixed_ip['subnet_id'])
|
||||
if subnet.ip_version == 4:
|
||||
ping_command = 'ping'
|
||||
else:
|
||||
ping_command = 'ping6'
|
||||
result += self.exec_command(probe.id,
|
||||
'%s -c 1 -w %s %s' % (ping_command,
|
||||
timeout,
|
||||
address))
|
||||
return result
|
||||
|
||||
def _create_port(self, network, device_owner):
|
||||
host = self.conf.host
|
||||
body = {'port': {'admin_state_up': True,
|
||||
'network_id': network.id,
|
||||
'device_id': '%s' % socket.gethostname(),
|
||||
'device_owner': '%s:probe' % device_owner,
|
||||
'tenant_id': network.tenant_id,
|
||||
'binding:host_id': host,
|
||||
'fixed_ips': [dict(subnet_id=s.id)
|
||||
for s in network.subnets]}}
|
||||
port_dict = self.client.create_port(body)['port']
|
||||
port = dhcp.DictModel(port_dict)
|
||||
port.network = network
|
||||
for fixed_ip in port.fixed_ips:
|
||||
fixed_ip.subnet = self._get_subnet(fixed_ip.subnet_id)
|
||||
return port
|
@ -1,90 +0,0 @@
|
||||
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
||||
#
|
||||
# Copyright 2012, Nachi Ueno, NTT MCL, Inc.
|
||||
# All Rights Reserved.
|
||||
#
|
||||
# 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 sys
|
||||
|
||||
from oslo.config import cfg
|
||||
|
||||
from neutron.agent.common import config
|
||||
from neutron.agent.linux import interface
|
||||
from neutron.debug import debug_agent
|
||||
from neutron.openstack.common import importutils
|
||||
from neutronclient.common import exceptions as exc
|
||||
from neutronclient.common import utils
|
||||
from neutronclient import shell
|
||||
|
||||
COMMAND_V2 = {
|
||||
'probe-create': utils.import_class(
|
||||
'neutron.debug.commands.CreateProbe'),
|
||||
'probe-delete': utils.import_class(
|
||||
'neutron.debug.commands.DeleteProbe'),
|
||||
'probe-list': utils.import_class(
|
||||
'neutron.debug.commands.ListProbe'),
|
||||
'probe-clear': utils.import_class(
|
||||
'neutron.debug.commands.ClearProbe'),
|
||||
'probe-exec': utils.import_class(
|
||||
'neutron.debug.commands.ExecProbe'),
|
||||
'ping-all': utils.import_class(
|
||||
'neutron.debug.commands.PingAll'),
|
||||
#TODO(nati) ping, netcat , nmap, bench
|
||||
}
|
||||
COMMANDS = {'2.0': COMMAND_V2}
|
||||
|
||||
|
||||
class NeutronDebugShell(shell.NeutronShell):
|
||||
def __init__(self, api_version):
|
||||
super(NeutronDebugShell, self).__init__(api_version)
|
||||
for k, v in COMMANDS[api_version].items():
|
||||
self.command_manager.add_command(k, v)
|
||||
|
||||
def build_option_parser(self, description, version):
|
||||
parser = super(NeutronDebugShell, self).build_option_parser(
|
||||
description, version)
|
||||
default = (
|
||||
shell.env('NEUTRON_TEST_CONFIG_FILE') or
|
||||
shell.env('QUANTUM_TEST_CONFIG_FILE')
|
||||
)
|
||||
parser.add_argument(
|
||||
'--config-file',
|
||||
default=default,
|
||||
help=_('Config file for interface driver '
|
||||
'(You may also use l3_agent.ini)'))
|
||||
return parser
|
||||
|
||||
def initialize_app(self, argv):
|
||||
super(NeutronDebugShell, self).initialize_app(argv)
|
||||
if not self.options.config_file:
|
||||
raise exc.CommandError(
|
||||
_("You must provide a config file for bridge -"
|
||||
" either --config-file or env[NEUTRON_TEST_CONFIG_FILE]"))
|
||||
client = self.client_manager.neutron
|
||||
cfg.CONF.register_opts(interface.OPTS)
|
||||
cfg.CONF.register_opts(debug_agent.NeutronDebugAgent.OPTS)
|
||||
config.register_interface_driver_opts_helper(cfg.CONF)
|
||||
config.register_use_namespaces_opts_helper(cfg.CONF)
|
||||
config.register_root_helper(cfg.CONF)
|
||||
cfg.CONF(['--config-file', self.options.config_file])
|
||||
config.setup_logging(cfg.CONF)
|
||||
driver = importutils.import_object(cfg.CONF.interface_driver, cfg.CONF)
|
||||
self.debug_agent = debug_agent.NeutronDebugAgent(cfg.CONF,
|
||||
client,
|
||||
driver)
|
||||
|
||||
|
||||
def main(argv=None):
|
||||
return NeutronDebugShell(shell.NEUTRON_API_VERSION).run(
|
||||
argv or sys.argv[1:])
|
Loading…
Reference in new issue