From a220aa15b056914df1b9debc95322d01a0e408e8 Mon Sep 17 00:00:00 2001 From: Alessio Ababilov Date: Wed, 29 Aug 2012 19:16:37 +0300 Subject: API extension for fpinging instances It may be interesting for a cloud user or administrator to perform a simple instance monitoring. A ping could be an acceptable solution: it is fast and quite reliable. A limit for ping is 1 time a minute by default. API calls. GET /os-fping?[all_tenants=1]&[include=uuid[,uuid...][&exclude=...] Performs fping for all VM in the current project and returns results. If `all_tenants` is requested, data for all projects is returned. By default, `all_tenants` is allowed only for admins. `include` and `exclude` are parameters specifying VM masks. Consider that VM list is `VM_all`, then if `include` is set, the result will be `VM_all * VM_include`. if `include` is set, the result will be `VM_all - VM_exclude`. `exclude` is ignored if `include` is specified. GET /os-fping/ Performs a check for single instance. Configuration flags. fping_path - full path to fping Implement blueprint fping-instances-ext Change-Id: I7d942270aa52bd6216eda0d7ae366ef0195d52a8 --- nova/api/openstack/compute/contrib/fping.py | 162 ++++++++++++++++++++++++++++ nova/api/openstack/compute/limits.py | 1 + 2 files changed, 163 insertions(+) create mode 100644 nova/api/openstack/compute/contrib/fping.py (limited to 'nova/api') diff --git a/nova/api/openstack/compute/contrib/fping.py b/nova/api/openstack/compute/contrib/fping.py new file mode 100644 index 000000000..3ae876f5a --- /dev/null +++ b/nova/api/openstack/compute/contrib/fping.py @@ -0,0 +1,162 @@ +# vim: tabstop=4 shiftwidth=4 softtabstop=4 + +# Copyright 2011 Grid Dynamics +# Copyright 2011 OpenStack LLC. +# 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 itertools +import os +import time + +from webob import exc + +from nova.api.openstack import common +from nova.api.openstack import extensions +from nova import compute +from nova import exception +from nova import flags +from nova.openstack.common import cfg +from nova.openstack.common import log as logging +from nova import utils + + +LOG = logging.getLogger(__name__) +authorize = extensions.extension_authorizer('compute', 'fping') +authorize_all_tenants = extensions.extension_authorizer( + 'compute', 'fping:all_tenants') +fping_opts = [ + cfg.StrOpt("fping_path", + default="/usr/sbin/fping", + help="Full path to fping."), +] + +FLAGS = flags.FLAGS +FLAGS.register_opts(fping_opts) + + +class FpingController(object): + + def __init__(self, network_api=None): + self.compute_api = compute.API() + self.last_call = {} + + def check_fping(self): + if not os.access(FLAGS.fping_path, os.X_OK): + raise exc.HTTPServiceUnavailable( + explanation=_("fping utility is not found.")) + + @staticmethod + def fping(ips): + fping_ret = utils.execute(FLAGS.fping_path, *ips, + check_exit_code=False) + if not fping_ret: + return set() + alive_ips = set() + for line in fping_ret[0].split("\n"): + ip = line.split(" ", 1)[0] + if "alive" in line: + alive_ips.add(ip) + return alive_ips + + @staticmethod + def _get_instance_ips(context, instance): + ret = [] + for network in common.get_networks_for_instance( + context, instance).values(): + all_ips = itertools.chain(network["ips"], network["floating_ips"]) + ret += [ip["address"] for ip in all_ips] + return ret + + def index(self, req): + context = req.environ["nova.context"] + search_opts = dict(deleted=False) + if "all_tenants" in req.GET: + authorize_all_tenants(context) + else: + authorize(context) + if context.project_id: + search_opts["project_id"] = context.project_id + else: + search_opts["user_id"] = context.user_id + self.check_fping() + include = req.GET.get("include", None) + if include: + include = set(include.split(",")) + exclude = set() + else: + include = None + exclude = req.GET.get("exclude", None) + if exclude: + exclude = set(exclude.split(",")) + else: + exclude = set() + + instance_list = self.compute_api.get_all( + context, search_opts=search_opts) + ip_list = [] + instance_ips = {} + instance_projects = {} + + for instance in instance_list: + uuid = instance["uuid"] + if uuid in exclude or (include is not None and + uuid not in include): + continue + ips = [str(ip) for ip in self._get_instance_ips(context, instance)] + instance_ips[uuid] = ips + instance_projects[uuid] = instance["project_id"] + ip_list += ips + alive_ips = self.fping(ip_list) + res = [] + for instance_uuid, ips in instance_ips.iteritems(): + res.append({ + "id": instance_uuid, + "project_id": instance_projects[instance_uuid], + "alive": bool(set(ips) & alive_ips), + }) + return {"servers": res} + + def show(self, req, id): + try: + context = req.environ["nova.context"] + authorize(context) + self.check_fping() + instance = self.compute_api.get(context, id) + ips = [str(ip) for ip in self._get_instance_ips(context, instance)] + alive_ips = self.fping(ips) + return { + "server": { + "id": instance["uuid"], + "project_id": instance["project_id"], + "alive": bool(set(ips) & alive_ips), + } + } + except exception.NotFound: + raise exc.HTTPNotFound() + + +class Fping(extensions.ExtensionDescriptor): + """Fping Management Extension.""" + + name = "Fping" + alias = "os-fping" + namespace = "http://docs.openstack.org/compute/ext/fping/api/v1.1" + updated = "2012-07-06T00:00:00+00:00" + + def get_resources(self): + res = extensions.ResourceExtension( + "os-fping", + FpingController()) + return [res] diff --git a/nova/api/openstack/compute/limits.py b/nova/api/openstack/compute/limits.py index c0ef65670..767280a45 100644 --- a/nova/api/openstack/compute/limits.py +++ b/nova/api/openstack/compute/limits.py @@ -212,6 +212,7 @@ DEFAULT_LIMITS = [ Limit("PUT", "*", ".*", 10, PER_MINUTE), Limit("GET", "*changes-since*", ".*changes-since.*", 3, PER_MINUTE), Limit("DELETE", "*", ".*", 100, PER_MINUTE), + Limit("GET", "*/os-fping", "^/os-fping", 12, PER_HOUR), ] -- cgit