153 lines
4.8 KiB
Python
153 lines
4.8 KiB
Python
# Copyright 2011 Grid Dynamics
|
|
# Copyright 2011 OpenStack Foundation
|
|
# 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
|
|
|
|
from oslo_config import cfg
|
|
import six
|
|
from webob import exc
|
|
|
|
from nova.api.openstack import common
|
|
from nova.api.openstack import extensions
|
|
from nova.api.openstack import wsgi
|
|
from nova import compute
|
|
from nova.i18n import _
|
|
from nova import utils
|
|
|
|
ALIAS = "os-fping"
|
|
|
|
authorize = extensions.os_compute_authorizer(ALIAS)
|
|
|
|
CONF = cfg.CONF
|
|
CONF.import_opt('fping_path', 'nova.api.openstack.compute.legacy_v2.contrib.'
|
|
'fping')
|
|
|
|
|
|
class FpingController(wsgi.Controller):
|
|
|
|
def __init__(self, network_api=None):
|
|
self.compute_api = compute.API(skip_policy_check=True)
|
|
self.last_call = {}
|
|
|
|
def check_fping(self):
|
|
if not os.access(CONF.fping_path, os.X_OK):
|
|
raise exc.HTTPServiceUnavailable(
|
|
explanation=_("fping utility is not found."))
|
|
|
|
@staticmethod
|
|
def fping(ips):
|
|
fping_ret = utils.execute(CONF.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
|
|
|
|
@extensions.expected_errors(503)
|
|
def index(self, req):
|
|
context = req.environ["nova.context"]
|
|
search_opts = dict(deleted=False)
|
|
if "all_tenants" in req.GET:
|
|
authorize(context, action='all_tenants')
|
|
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, want_objects=True)
|
|
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 six.iteritems(instance_ips):
|
|
res.append({
|
|
"id": instance_uuid,
|
|
"project_id": instance_projects[instance_uuid],
|
|
"alive": bool(set(ips) & alive_ips),
|
|
})
|
|
return {"servers": res}
|
|
|
|
@extensions.expected_errors((404, 503))
|
|
def show(self, req, id):
|
|
context = req.environ["nova.context"]
|
|
authorize(context)
|
|
self.check_fping()
|
|
instance = common.get_instance(self.compute_api, 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),
|
|
}
|
|
}
|
|
|
|
|
|
class Fping(extensions.V21APIExtensionBase):
|
|
"""Fping Management Extension."""
|
|
|
|
name = "Fping"
|
|
alias = ALIAS
|
|
version = 1
|
|
|
|
def get_resources(self):
|
|
res = extensions.ResourceExtension(ALIAS, FpingController())
|
|
return [res]
|
|
|
|
def get_controller_extensions(self):
|
|
return []
|