Merge pull request #153 from kilogram/diagnostics
Diagnostics Extensions
This commit is contained in:
62
quark/api/extensions/diagnostics.py
Normal file
62
quark/api/extensions/diagnostics.py
Normal file
@@ -0,0 +1,62 @@
|
||||
# Copyright (c) 2013 OpenStack Foundation
|
||||
#
|
||||
# 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 functools
|
||||
|
||||
from neutron.api import extensions
|
||||
from neutron.common import exceptions
|
||||
from neutron import manager
|
||||
from neutron.openstack.common import log as logging
|
||||
LOG = logging.getLogger("quark.diagnostics")
|
||||
|
||||
|
||||
class Diagnostician(object):
|
||||
def __init__(self, plugin):
|
||||
self.plugin = plugin
|
||||
|
||||
def diag_not_implemented(self, res, id, input):
|
||||
LOG.warning("Diagnostics not implemented on resource %ss." % res)
|
||||
raise exceptions.ServiceUnavailable()
|
||||
|
||||
def diagnose(self, res, input, req, id):
|
||||
LOG.debug("Requested diagnostics fields %s on resource %s with id %s"
|
||||
% (input['diag'], res, id))
|
||||
return getattr(
|
||||
self.plugin, 'diagnose_%s' % res.replace('-', '_'),
|
||||
functools.partial(self.diag_not_implemented, res))(
|
||||
req.context, id, input['diag'])
|
||||
|
||||
|
||||
class Diagnostics(extensions.ExtensionDescriptor):
|
||||
def get_name(self):
|
||||
return "Diagnostics"
|
||||
|
||||
def get_alias(self):
|
||||
return "diagnostics"
|
||||
|
||||
def get_description(self):
|
||||
return "Diagnostics extension"
|
||||
|
||||
def get_namespace(self):
|
||||
return "None"
|
||||
|
||||
def get_updated(self):
|
||||
return "never"
|
||||
|
||||
def get_actions(self):
|
||||
diagnose = Diagnostician(manager.NeutronManager.get_plugin()).diagnose
|
||||
resources = ['port', 'subnet', 'network']
|
||||
return (extensions.ActionExtension('%ss' % res, 'diag',
|
||||
functools.partial(diagnose, res)) for res in resources)
|
||||
@@ -37,6 +37,10 @@ class BaseDriver(object):
|
||||
def delete_network(self, context, network_id):
|
||||
LOG.info("delete_network %s" % network_id)
|
||||
|
||||
def diag_network(self, context, network_id, **kwargs):
|
||||
LOG.info("diag_network %s" % network_id)
|
||||
return {}
|
||||
|
||||
def create_port(self, context, network_id, port_id, **kwargs):
|
||||
LOG.info("create_port %s %s %s" % (context.tenant_id, network_id,
|
||||
port_id))
|
||||
@@ -49,6 +53,10 @@ class BaseDriver(object):
|
||||
def delete_port(self, context, port_id, **kwargs):
|
||||
LOG.info("delete_port %s %s" % (context.tenant_id, port_id))
|
||||
|
||||
def diag_port(self, context, network_id, **kwargs):
|
||||
LOG.info("diag_port %s" % network_id)
|
||||
return {}
|
||||
|
||||
def create_security_group(self, context, group_name, **group):
|
||||
LOG.info("Creating security profile %s for tenant %s" %
|
||||
(group_name, context.tenant_id))
|
||||
|
||||
@@ -60,6 +60,14 @@ physical_net_type_map = {
|
||||
CONF.register_opts(nvp_opts, "NVP")
|
||||
|
||||
|
||||
def _tag_roll(tags):
|
||||
return [{'scope': k, 'tag': v} for k, v in tags]
|
||||
|
||||
|
||||
def _tag_unroll(tags):
|
||||
return dict((t['scope'], t['tag']) for t in tags)
|
||||
|
||||
|
||||
class NVPDriver(base.BaseDriver):
|
||||
def __init__(self):
|
||||
self.nvp_connections = []
|
||||
@@ -117,6 +125,31 @@ class NVPDriver(base.BaseDriver):
|
||||
LOG.debug("Deleting lswitch %s" % switch["uuid"])
|
||||
connection.lswitch(switch["uuid"]).delete()
|
||||
|
||||
def _collect_lswitch_info(self, lswitch, get_status):
|
||||
info = {
|
||||
'port_isolation_enabled': lswitch['port_isolation_enabled'],
|
||||
'display_name': lswitch['display_name'],
|
||||
'uuid': lswitch['uuid'],
|
||||
'transport_zones': lswitch['transport_zones'],
|
||||
}
|
||||
info.update(_tag_unroll(lswitch['tags']))
|
||||
if get_status:
|
||||
status = lswitch.pop('_relations')['LogicalSwitchStatus']
|
||||
info.update({
|
||||
'lport_stats': {
|
||||
'fabric_up': status['lport_fabric_up_count'],
|
||||
'admin_up': status['lport_admin_up_count'],
|
||||
'link_up': status['lport_link_up_count'],
|
||||
'count': status['lport_count'],
|
||||
}, 'fabric_status': status['fabric_status'],
|
||||
})
|
||||
return info
|
||||
|
||||
def diag_network(self, context, network_id, get_status):
|
||||
switches = self._lswitch_status_query(context, network_id)['results']
|
||||
return {'logical_switches': [self._collect_lswitch_info(s, get_status)
|
||||
for s in switches]}
|
||||
|
||||
def create_port(self, context, network_id, port_id,
|
||||
status=True, security_groups=[], allowed_pairs=[]):
|
||||
tenant_id = context.tenant_id
|
||||
@@ -159,6 +192,67 @@ class NVPDriver(base.BaseDriver):
|
||||
LOG.debug("Deleting port %s from lswitch %s" % (port_id, lswitch_uuid))
|
||||
connection.lswitch_port(lswitch_uuid, port_id).delete()
|
||||
|
||||
def _collect_lport_info(self, lport, get_status):
|
||||
info = {
|
||||
'mirror_targets': lport['mirror_targets'],
|
||||
'display_name': lport['display_name'],
|
||||
'portno': lport['portno'],
|
||||
'allowed_address_pairs': lport['allowed_address_pairs'],
|
||||
'nvp_security_groups': lport['security_profiles'],
|
||||
'uuid': lport['uuid'],
|
||||
'admin_status_enabled': lport['admin_status_enabled'],
|
||||
'queue_uuid': lport['queue_uuid'],
|
||||
}
|
||||
if get_status:
|
||||
stats = lport['statistics']
|
||||
status = lport['status']
|
||||
lswitch = {
|
||||
'uuid': status['lswitch']['uuid'],
|
||||
'display_name': status['lswitch']['display_name'],
|
||||
}
|
||||
lswitch.update(_tag_unroll(status['lswitch']['tags']))
|
||||
info.update({
|
||||
'statistics': {
|
||||
'recieved': {
|
||||
'packets': stats['rx_packets'],
|
||||
'bytes': stats['rx_bytes'],
|
||||
'errors': stats['rx_errors']
|
||||
},
|
||||
'transmitted': {
|
||||
'packets': stats['tx_packets'],
|
||||
'bytes': stats['tx_bytes'],
|
||||
'errors': stats['tx_errors']
|
||||
},
|
||||
},
|
||||
'status': {
|
||||
'link_status_up': status['link_status_up'],
|
||||
'admin_status_up': status['admin_status_up'],
|
||||
'fabric_status_up': status['fabric_status_up'],
|
||||
},
|
||||
'lswitch': lswitch,
|
||||
})
|
||||
info.update(_tag_unroll(lport['tags']))
|
||||
return info
|
||||
|
||||
def diag_port(self, context, port_id, get_status=False):
|
||||
connection = self.get_connection()
|
||||
lswitch_uuid = self._lswitch_from_port(context, port_id)
|
||||
lswitch_port = connection.lswitch_port(lswitch_uuid, port_id)
|
||||
|
||||
query = lswitch_port.query()
|
||||
query.relations("LogicalPortAttachment")
|
||||
results = query.results()
|
||||
if results['result_count'] == 0:
|
||||
return {'lport': "Logical port not found."}
|
||||
|
||||
config = results['results'][0]
|
||||
relations = config.pop('_relations')
|
||||
config['attachment'] = relations['LogicalPortAttachment']['type']
|
||||
if get_status:
|
||||
config['status'] = lswitch_port.status()
|
||||
config['statistics'] = lswitch_port.statistics()
|
||||
return {'lport': self._collect_lport_info(config, get_status)}
|
||||
|
||||
def _get_network_details(self, context, network_id, switches):
|
||||
name, phys_net, phys_type, segment_id = None, None, None, None
|
||||
for res in switches["results"]:
|
||||
|
||||
@@ -75,7 +75,7 @@ class Plugin(neutron_plugin_base_v2.NeutronPluginBaseV2,
|
||||
sg_ext.SecurityGroupPluginBase):
|
||||
supported_extension_aliases = ["mac_address_ranges", "routes",
|
||||
"ip_addresses", "ports_quark",
|
||||
"security-group",
|
||||
"security-group", "diagnostics",
|
||||
"subnets_quark", "provider",
|
||||
"ip_policies", "quotas"]
|
||||
|
||||
@@ -188,6 +188,9 @@ class Plugin(neutron_plugin_base_v2.NeutronPluginBaseV2,
|
||||
def disassociate_port(self, context, id, ip_address_id):
|
||||
return ports.disassociate_port(context, id, ip_address_id)
|
||||
|
||||
def diagnose_port(self, context, id, fields):
|
||||
return ports.diagnose_port(context, id, fields)
|
||||
|
||||
def get_route(self, context, id):
|
||||
return routes.get_route(context, id)
|
||||
|
||||
@@ -218,6 +221,9 @@ class Plugin(neutron_plugin_base_v2.NeutronPluginBaseV2,
|
||||
def delete_subnet(self, context, id):
|
||||
return subnets.delete_subnet(context, id)
|
||||
|
||||
def diagnose_subnet(self, context, id, fields):
|
||||
return subnets.diagnose_subnet(context, id, fields)
|
||||
|
||||
def create_network(self, context, network):
|
||||
return networks.create_network(context, network)
|
||||
|
||||
@@ -235,3 +241,6 @@ class Plugin(neutron_plugin_base_v2.NeutronPluginBaseV2,
|
||||
|
||||
def delete_network(self, context, id):
|
||||
return networks.delete_network(context, id)
|
||||
|
||||
def diagnose_network(self, context, id, fields):
|
||||
return networks.diagnose_network(context, id, fields)
|
||||
|
||||
@@ -24,6 +24,7 @@ from oslo.config import cfg
|
||||
|
||||
from quark.db import api as db_api
|
||||
from quark import network_strategy
|
||||
from quark.plugin_modules import ports
|
||||
from quark.plugin_modules import security_groups
|
||||
from quark.plugin_modules import subnets
|
||||
from quark import plugin_views as v
|
||||
@@ -202,3 +203,31 @@ def delete_network(context, id):
|
||||
for subnet in net["subnets"]:
|
||||
subnets._delete_subnet(context, subnet)
|
||||
db_api.network_delete(context, net)
|
||||
|
||||
|
||||
def _diag_network(context, network, fields):
|
||||
if not network:
|
||||
return False
|
||||
net = v._make_network_dict(network)
|
||||
net['ports'] = [p.get('id') for p in network.get('ports', [])]
|
||||
if 'subnets' in fields:
|
||||
net['subnets'] = [subnets.diagnose_subnet(context, s, fields)
|
||||
for s in network.get('subnets', [])]
|
||||
if 'ports' in fields:
|
||||
net['ports'] = [ports.diagnose_port(context, s, fields)
|
||||
for s in net['ports']]
|
||||
if 'config' in fields or 'status' in fields:
|
||||
net.update(net_driver.diag_network(
|
||||
context, net['id'], get_status='status' in fields))
|
||||
return net
|
||||
|
||||
|
||||
def diagnose_network(context, id, fields):
|
||||
if id == "*":
|
||||
return {'networks': [_diag_network(context, net, fields) for
|
||||
net in db_api.network_find(context).all()]}
|
||||
db_net = db_api.network_find(context, id=id, scope=db_api.ONE)
|
||||
if not db_net:
|
||||
raise exceptions.NetworkNotFound(net_id=id)
|
||||
net = _diag_network(context, db_net, fields)
|
||||
return {'networks': net}
|
||||
|
||||
@@ -322,3 +322,24 @@ def disassociate_port(context, id, ip_address_id):
|
||||
if len(the_address["ports"]) == 0:
|
||||
the_address["deallocated"] = 1
|
||||
return v._make_port_dict(port)
|
||||
|
||||
|
||||
def _diag_port(context, port, fields):
|
||||
if not port:
|
||||
return False
|
||||
p = v._make_port_dict(port)
|
||||
if 'config' in fields:
|
||||
p.update(net_driver.diag_port(
|
||||
context, port["backend_key"], get_status='status' in fields))
|
||||
return p
|
||||
|
||||
|
||||
def diagnose_port(context, id, fields):
|
||||
if id == "*":
|
||||
return {'ports': [_diag_port(context, port, fields) for
|
||||
port in db_api.port_find(context).all()]}
|
||||
db_port = db_api.port_find(context, id=id, scope=db_api.ONE)
|
||||
if not db_port:
|
||||
raise exceptions.PortNotFound(port_id=id, net_id='')
|
||||
port = _diag_port(context, db_port, fields)
|
||||
return {'ports': port}
|
||||
|
||||
@@ -277,3 +277,9 @@ def delete_subnet(context, id):
|
||||
if not subnet:
|
||||
raise exceptions.SubnetNotFound(subnet_id=id)
|
||||
_delete_subnet(context, subnet)
|
||||
|
||||
|
||||
def diagnose_subnet(context, id, fields):
|
||||
if id == "*":
|
||||
return {'subnets': get_subnets(context, filters={})}
|
||||
return {'subnets': get_subnet(context, id)}
|
||||
|
||||
Reference in New Issue
Block a user