
Fixes os_xenapi/dom0/etc/xapi.d/plugins/*.py wrt Python 3 compatibility, also remove some tests in os_xenapi/tests/plugins/test_glance.py that are too Py2 centric. Change-Id: Iab721f6a47dc023f01670076ef7d1de107a913ae
644 lines
21 KiB
Python
644 lines
21 KiB
Python
#!/usr/bin/env python
|
|
|
|
# Copyright 2011 OpenStack Foundation
|
|
# Copyright 2011 United States Government as represented by the
|
|
# Administrator of the National Aeronautics and Space Administration.
|
|
# 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.
|
|
|
|
# NOTE: XenServer still only supports Python 2.4 in it's dom0 userspace
|
|
# which means the Nova xenapi plugins must use only Python 2.4 features
|
|
|
|
# TODO(sfinucan): Resolve all 'noqa' items once the above is no longer true
|
|
|
|
#
|
|
# XenAPI plugin for host operations
|
|
#
|
|
|
|
try:
|
|
import json
|
|
except ImportError:
|
|
import simplejson as json
|
|
import logging
|
|
import re
|
|
import sys
|
|
import time
|
|
|
|
import six
|
|
import utils
|
|
|
|
import dom0_pluginlib as pluginlib
|
|
import XenAPI
|
|
import XenAPIPlugin
|
|
|
|
try:
|
|
import xmlrpclib
|
|
except ImportError:
|
|
import six.moves.xmlrpc_client as xmlrpclib
|
|
|
|
|
|
pluginlib.configure_logging("xenhost")
|
|
|
|
|
|
host_data_pattern = re.compile(r"\s*(\S+) \([^\)]+\) *: ?(.*)")
|
|
config_file_path = "/usr/etc/xenhost.conf"
|
|
DEFAULT_TRIES = 23
|
|
DEFAULT_SLEEP = 10
|
|
|
|
|
|
def jsonify(fnc):
|
|
def wrapper(*args, **kwargs):
|
|
return json.dumps(fnc(*args, **kwargs))
|
|
return wrapper
|
|
|
|
|
|
class TimeoutError(Exception):
|
|
pass
|
|
|
|
|
|
def _run_command(cmd, cmd_input=None):
|
|
"""Wrap utils.run_command to raise PluginError on failure"""
|
|
try:
|
|
return utils.run_command(cmd, cmd_input=cmd_input)
|
|
except utils.SubprocessException as e: # noqa
|
|
raise pluginlib.PluginError(e.err)
|
|
|
|
|
|
def _resume_compute(session, compute_ref, compute_uuid):
|
|
"""Resume compute node on slave host after pool join.
|
|
|
|
This has to happen regardless of the success or failure of the join
|
|
operation.
|
|
"""
|
|
try:
|
|
# session is valid if the join operation has failed
|
|
session.xenapi.VM.start(compute_ref, False, True)
|
|
except XenAPI.Failure:
|
|
# if session is invalid, e.g. xapi has restarted, then the pool
|
|
# join has been successful, wait for xapi to become alive again
|
|
for c in range(0, DEFAULT_TRIES):
|
|
try:
|
|
_run_command(["xe", "vm-start", "uuid=%s" % compute_uuid])
|
|
return
|
|
except pluginlib.PluginError:
|
|
logging.exception('Waited %d seconds for the slave to '
|
|
'become available.' % (c * DEFAULT_SLEEP))
|
|
time.sleep(DEFAULT_SLEEP)
|
|
raise pluginlib.PluginError('Unrecoverable error: the host has '
|
|
'not come back for more than %d seconds'
|
|
% (DEFAULT_SLEEP * (DEFAULT_TRIES + 1)))
|
|
|
|
|
|
@jsonify
|
|
def set_host_enabled(self, arg_dict):
|
|
"""Sets this host's ability to accept new instances.
|
|
|
|
It will otherwise continue to operate normally.
|
|
"""
|
|
enabled = arg_dict.get("enabled")
|
|
if enabled is None:
|
|
raise pluginlib.PluginError(
|
|
"Missing 'enabled' argument to set_host_enabled")
|
|
|
|
host_uuid = arg_dict['host_uuid']
|
|
if enabled == "true":
|
|
result = _run_command(["xe", "host-enable", "uuid=%s" % host_uuid])
|
|
elif enabled == "false":
|
|
result = _run_command(["xe", "host-disable", "uuid=%s" % host_uuid])
|
|
else:
|
|
raise pluginlib.PluginError("Illegal enabled status: %s" % enabled)
|
|
# Should be empty string
|
|
if result:
|
|
raise pluginlib.PluginError(result)
|
|
# Return the current enabled status
|
|
cmd = ["xe", "host-param-get", "uuid=%s" % host_uuid, "param-name=enabled"]
|
|
host_enabled = _run_command(cmd)
|
|
if host_enabled == "true":
|
|
status = "enabled"
|
|
else:
|
|
status = "disabled"
|
|
return {"status": status}
|
|
|
|
|
|
def _write_config_dict(dct):
|
|
conf_file = file(config_file_path, "w")
|
|
json.dump(dct, conf_file)
|
|
conf_file.close()
|
|
|
|
|
|
def _get_config_dict():
|
|
"""Returns a dict containing the key/values in the config file.
|
|
|
|
If the file doesn't exist, it is created, and an empty dict
|
|
is returned.
|
|
"""
|
|
try:
|
|
conf_file = file(config_file_path)
|
|
config_dct = json.load(conf_file)
|
|
conf_file.close()
|
|
except IOError:
|
|
# File doesn't exist
|
|
config_dct = {}
|
|
# Create the file
|
|
_write_config_dict(config_dct)
|
|
return config_dct
|
|
|
|
|
|
@jsonify
|
|
def get_config(self, arg_dict):
|
|
"""Return the value stored for the specified key, or None if no match."""
|
|
conf = _get_config_dict()
|
|
params = arg_dict["params"]
|
|
try:
|
|
dct = json.loads(params)
|
|
except Exception:
|
|
dct = params
|
|
key = dct["key"]
|
|
ret = conf.get(key)
|
|
if ret is None:
|
|
# Can't jsonify None
|
|
return "None"
|
|
return ret
|
|
|
|
|
|
@jsonify
|
|
def set_config(self, arg_dict):
|
|
"""Write the specified key/value pair, overwriting any existing value."""
|
|
conf = _get_config_dict()
|
|
params = arg_dict["params"]
|
|
try:
|
|
dct = json.loads(params)
|
|
except Exception:
|
|
dct = params
|
|
key = dct["key"]
|
|
val = dct["value"]
|
|
if val is None:
|
|
# Delete the key, if present
|
|
conf.pop(key, None)
|
|
else:
|
|
conf.update({key: val})
|
|
_write_config_dict(conf)
|
|
|
|
|
|
def iptables_config(session, args):
|
|
# command should be either save or restore
|
|
logging.debug("iptables_config:enter")
|
|
logging.debug("iptables_config: args=%s", args)
|
|
cmd_args = pluginlib.exists(args, 'cmd_args')
|
|
logging.debug("iptables_config: cmd_args=%s", cmd_args)
|
|
process_input = pluginlib.optional(args, 'process_input')
|
|
logging.debug("iptables_config: process_input=%s", process_input)
|
|
cmd = json.loads(cmd_args)
|
|
cmd = map(str, cmd)
|
|
|
|
# either execute iptable-save or iptables-restore
|
|
# command must be only one of these two
|
|
# process_input must be used only with iptables-restore
|
|
if len(list(cmd)) > 0 and cmd[0] in ('iptables-save',
|
|
'iptables-restore',
|
|
'ip6tables-save',
|
|
'ip6tables-restore'):
|
|
result = _run_command(cmd, process_input)
|
|
ret_str = json.dumps(dict(out=result, err=''))
|
|
logging.debug("iptables_config:exit")
|
|
return ret_str
|
|
# else don't do anything and return an error
|
|
else:
|
|
raise pluginlib.PluginError("Invalid iptables command")
|
|
|
|
|
|
def _ovs_add_patch_port(args):
|
|
bridge_name = pluginlib.exists(args, 'bridge_name')
|
|
port_name = pluginlib.exists(args, 'port_name')
|
|
peer_port_name = pluginlib.exists(args, 'peer_port_name')
|
|
cmd_args = ['ovs-vsctl', '--', '--if-exists', 'del-port',
|
|
port_name, '--', 'add-port', bridge_name, port_name,
|
|
'--', 'set', 'interface', port_name,
|
|
'type=patch', 'options:peer=%s' % peer_port_name]
|
|
return _run_command(cmd_args)
|
|
|
|
|
|
def _ovs_del_port(args):
|
|
bridge_name = pluginlib.exists(args, 'bridge_name')
|
|
port_name = pluginlib.exists(args, 'port_name')
|
|
cmd_args = ['ovs-vsctl', '--', '--if-exists', 'del-port',
|
|
bridge_name, port_name]
|
|
return _run_command(cmd_args)
|
|
|
|
|
|
def _ovs_del_br(args):
|
|
bridge_name = pluginlib.exists(args, 'bridge_name')
|
|
cmd_args = ['ovs-vsctl', '--', '--if-exists',
|
|
'del-br', bridge_name]
|
|
return _run_command(cmd_args)
|
|
|
|
|
|
def _ovs_set_if_external_id(args):
|
|
interface = pluginlib.exists(args, 'interface')
|
|
extneral_id = pluginlib.exists(args, 'extneral_id')
|
|
value = pluginlib.exists(args, 'value')
|
|
cmd_args = ['ovs-vsctl', 'set', 'Interface', interface,
|
|
'external-ids:%s=%s' % (extneral_id, value)]
|
|
return _run_command(cmd_args)
|
|
|
|
|
|
def _ovs_add_port(args):
|
|
bridge_name = pluginlib.exists(args, 'bridge_name')
|
|
port_name = pluginlib.exists(args, 'port_name')
|
|
cmd_args = ['ovs-vsctl', '--', '--if-exists', 'del-port', port_name,
|
|
'--', 'add-port', bridge_name, port_name]
|
|
return _run_command(cmd_args)
|
|
|
|
|
|
def _ovs_create_port(args):
|
|
bridge = pluginlib.exists(args, 'bridge')
|
|
port = pluginlib.exists(args, 'port')
|
|
iface_id = pluginlib.exists(args, 'iface-id')
|
|
mac = pluginlib.exists(args, 'mac')
|
|
status = pluginlib.exists(args, 'status')
|
|
cmd_args = ['ovs-vsctl', '--', '--if-exists', 'del-port', port,
|
|
'--', 'add-port', bridge, port,
|
|
'--', 'set', 'Interface', port,
|
|
'external_ids:iface-id=%s' % iface_id,
|
|
'external_ids:iface-status=%s' % status,
|
|
'external_ids:attached-mac=%s' % mac,
|
|
'external_ids:xs-vif-uuid=%s' % iface_id]
|
|
return _run_command(cmd_args)
|
|
|
|
|
|
def _ip_link_get_dev(args):
|
|
device_name = pluginlib.exists(args, 'device_name')
|
|
cmd_args = ['ip', 'link', 'show', device_name]
|
|
return _run_command(cmd_args)
|
|
|
|
|
|
def _ip_link_del_dev(args):
|
|
device_name = pluginlib.exists(args, 'device_name')
|
|
cmd_args = ['ip', 'link', 'delete', device_name]
|
|
return _run_command(cmd_args)
|
|
|
|
|
|
def _ip_link_add_veth_pair(args):
|
|
dev1_name = pluginlib.exists(args, 'dev1_name')
|
|
dev2_name = pluginlib.exists(args, 'dev2_name')
|
|
cmd_args = ['ip', 'link', 'add', dev1_name, 'type', 'veth', 'peer',
|
|
'name', dev2_name]
|
|
return _run_command(cmd_args)
|
|
|
|
|
|
def _ip_link_set_dev(args):
|
|
device_name = pluginlib.exists(args, 'device_name')
|
|
option = pluginlib.exists(args, 'option')
|
|
cmd_args = ['ip', 'link', 'set', device_name, option]
|
|
return _run_command(cmd_args)
|
|
|
|
|
|
def _ip_link_set_promisc(args):
|
|
device_name = pluginlib.exists(args, 'device_name')
|
|
option = pluginlib.exists(args, 'option')
|
|
cmd_args = ['ip', 'link', 'set', device_name, 'promisc', option]
|
|
return _run_command(cmd_args)
|
|
|
|
|
|
def _brctl_add_br(args):
|
|
bridge_name = pluginlib.exists(args, 'bridge_name')
|
|
cmd_args = ['brctl', 'addbr', bridge_name]
|
|
return _run_command(cmd_args)
|
|
|
|
|
|
def _brctl_del_br(args):
|
|
bridge_name = pluginlib.exists(args, 'bridge_name')
|
|
cmd_args = ['brctl', 'delbr', bridge_name]
|
|
return _run_command(cmd_args)
|
|
|
|
|
|
def _brctl_set_fd(args):
|
|
bridge_name = pluginlib.exists(args, 'bridge_name')
|
|
fd = pluginlib.exists(args, 'fd')
|
|
cmd_args = ['brctl', 'setfd', bridge_name, fd]
|
|
return _run_command(cmd_args)
|
|
|
|
|
|
def _brctl_set_stp(args):
|
|
bridge_name = pluginlib.exists(args, 'bridge_name')
|
|
option = pluginlib.exists(args, 'option')
|
|
cmd_args = ['brctl', 'stp', bridge_name, option]
|
|
return _run_command(cmd_args)
|
|
|
|
|
|
def _brctl_add_if(args):
|
|
bridge_name = pluginlib.exists(args, 'bridge_name')
|
|
if_name = pluginlib.exists(args, 'interface_name')
|
|
cmd_args = ['brctl', 'addif', bridge_name, if_name]
|
|
return _run_command(cmd_args)
|
|
|
|
|
|
def _brctl_del_if(args):
|
|
bridge_name = pluginlib.exists(args, 'bridge_name')
|
|
if_name = pluginlib.exists(args, 'interface_name')
|
|
cmd_args = ['brctl', 'delif', bridge_name, if_name]
|
|
return _run_command(cmd_args)
|
|
|
|
|
|
ALLOWED_NETWORK_CMDS = {
|
|
# allowed cmds to config OVS bridge
|
|
'ovs_add_patch_port': _ovs_add_patch_port,
|
|
'ovs_add_port': _ovs_add_port,
|
|
'ovs_create_port': _ovs_create_port,
|
|
'ovs_del_port': _ovs_del_port,
|
|
'ovs_del_br': _ovs_del_br,
|
|
'ovs_set_if_external_id': _ovs_set_if_external_id,
|
|
'ip_link_add_veth_pair': _ip_link_add_veth_pair,
|
|
'ip_link_del_dev': _ip_link_del_dev,
|
|
'ip_link_get_dev': _ip_link_get_dev,
|
|
'ip_link_set_dev': _ip_link_set_dev,
|
|
'ip_link_set_promisc': _ip_link_set_promisc,
|
|
'brctl_add_br': _brctl_add_br,
|
|
'brctl_add_if': _brctl_add_if,
|
|
'brctl_del_br': _brctl_del_br,
|
|
'brctl_del_if': _brctl_del_if,
|
|
'brctl_set_fd': _brctl_set_fd,
|
|
'brctl_set_stp': _brctl_set_stp
|
|
}
|
|
|
|
|
|
def network_config(session, args):
|
|
"""network config functions"""
|
|
cmd = pluginlib.exists(args, 'cmd')
|
|
if not isinstance(cmd, six.string_types):
|
|
msg = "invalid command '%s'" % str(cmd)
|
|
raise pluginlib.PluginError(msg)
|
|
return
|
|
if cmd not in ALLOWED_NETWORK_CMDS:
|
|
msg = "Dom0 execution of '%s' is not permitted" % cmd
|
|
raise pluginlib.PluginError(msg)
|
|
return
|
|
cmd_args = pluginlib.exists(args, 'args')
|
|
return ALLOWED_NETWORK_CMDS[cmd](cmd_args)
|
|
|
|
|
|
def _power_action(action, arg_dict):
|
|
# Host must be disabled first
|
|
host_uuid = arg_dict['host_uuid']
|
|
result = _run_command(["xe", "host-disable", "uuid=%s" % host_uuid])
|
|
if result:
|
|
raise pluginlib.PluginError(result)
|
|
# All running VMs must be shutdown
|
|
result = _run_command(["xe", "vm-shutdown", "--multiple",
|
|
"resident-on=%s" % host_uuid])
|
|
if result:
|
|
raise pluginlib.PluginError(result)
|
|
cmds = {"reboot": "host-reboot",
|
|
"startup": "host-power-on",
|
|
"shutdown": "host-shutdown"}
|
|
result = _run_command(["xe", cmds[action], "uuid=%s" % host_uuid])
|
|
# Should be empty string
|
|
if result:
|
|
raise pluginlib.PluginError(result)
|
|
return {"power_action": action}
|
|
|
|
|
|
@jsonify
|
|
def host_reboot(self, arg_dict):
|
|
"""Reboots the host."""
|
|
return _power_action("reboot", arg_dict)
|
|
|
|
|
|
@jsonify
|
|
def host_shutdown(self, arg_dict):
|
|
"""Reboots the host."""
|
|
return _power_action("shutdown", arg_dict)
|
|
|
|
|
|
@jsonify
|
|
def host_start(self, arg_dict):
|
|
"""Starts the host.
|
|
|
|
Currently not feasible, since the host runs on the same machine as
|
|
Xen.
|
|
"""
|
|
return _power_action("startup", arg_dict)
|
|
|
|
|
|
@jsonify
|
|
def host_join(self, arg_dict):
|
|
"""Join a remote host into a pool.
|
|
|
|
The pool's master is the host where the plugin is called from. The
|
|
following constraints apply:
|
|
|
|
- The host must have no VMs running, except nova-compute, which
|
|
will be shut down (and restarted upon pool-join) automatically,
|
|
- The host must have no shared storage currently set up,
|
|
- The host must have the same license of the master,
|
|
- The host must have the same supplemental packs as the master.
|
|
"""
|
|
session = XenAPI.Session(arg_dict.get("url"))
|
|
session.login_with_password(arg_dict.get("user"),
|
|
arg_dict.get("password"))
|
|
compute_ref = session.xenapi.VM.get_by_uuid(arg_dict.get('compute_uuid'))
|
|
session.xenapi.VM.clean_shutdown(compute_ref)
|
|
try:
|
|
if arg_dict.get("force", "false") == "false":
|
|
session.xenapi.pool.join(arg_dict.get("master_addr"),
|
|
arg_dict.get("master_user"),
|
|
arg_dict.get("master_pass"))
|
|
else:
|
|
session.xenapi.pool.join_force(arg_dict.get("master_addr"),
|
|
arg_dict.get("master_user"),
|
|
arg_dict.get("master_pass"))
|
|
finally:
|
|
_resume_compute(session, compute_ref, arg_dict.get("compute_uuid"))
|
|
|
|
|
|
@jsonify
|
|
def host_data(self, arg_dict):
|
|
# Runs the commands on the xenstore host to return the current status
|
|
# information.
|
|
host_uuid = arg_dict['host_uuid']
|
|
resp = _run_command(["xe", "host-param-list", "uuid=%s" % host_uuid])
|
|
parsed_data = parse_response(resp)
|
|
# We have the raw dict of values. Extract those that we need,
|
|
# and convert the data types as needed.
|
|
ret_dict = cleanup(parsed_data)
|
|
# Add any config settings
|
|
config = _get_config_dict()
|
|
ret_dict.update(config)
|
|
return ret_dict
|
|
|
|
|
|
def parse_response(resp):
|
|
data = {}
|
|
for ln in resp.splitlines():
|
|
if not ln:
|
|
continue
|
|
mtch = host_data_pattern.match(ln.strip())
|
|
try:
|
|
k, v = mtch.groups()
|
|
data[k] = v
|
|
except AttributeError:
|
|
# Not a valid line; skip it
|
|
continue
|
|
return data
|
|
|
|
|
|
@jsonify
|
|
def host_uptime(self, arg_dict):
|
|
"""Returns the result of the uptime command on the xenhost."""
|
|
return {"uptime": _run_command(['uptime'])}
|
|
|
|
|
|
def cleanup(dct):
|
|
# Take the raw KV pairs returned and translate them into the
|
|
# appropriate types, discarding any we don't need.
|
|
def safe_int(val):
|
|
# Integer values will either be string versions of numbers,
|
|
# or empty strings. Convert the latter to nulls.
|
|
try:
|
|
return int(val)
|
|
except ValueError:
|
|
return None
|
|
|
|
def strip_kv(ln):
|
|
return [val.strip() for val in ln.split(":", 1)]
|
|
|
|
out = {}
|
|
|
|
# sbs = dct.get("supported-bootloaders", "")
|
|
# out["host_supported-bootloaders"] = sbs.split("; ")
|
|
# out["host_suspend-image-sr-uuid"] = dct.get("suspend-image-sr-uuid", "")
|
|
# out["host_crash-dump-sr-uuid"] = dct.get("crash-dump-sr-uuid", "")
|
|
# out["host_local-cache-sr"] = dct.get("local-cache-sr", "")
|
|
out["enabled"] = dct.get("enabled", "true") == "true"
|
|
omm = {}
|
|
omm["total"] = safe_int(dct.get("memory-total", ""))
|
|
omm["overhead"] = safe_int(dct.get("memory-overhead", ""))
|
|
omm["free"] = safe_int(dct.get("memory-free", ""))
|
|
omm["free-computed"] = safe_int(dct.get("memory-free-computed", ""))
|
|
out["host_memory"] = omm
|
|
|
|
# out["host_API-version"] = avv = {}
|
|
# avv["vendor"] = dct.get("API-version-vendor", "")
|
|
# avv["major"] = safe_int(dct.get("API-version-major", ""))
|
|
# avv["minor"] = safe_int(dct.get("API-version-minor", ""))
|
|
|
|
out["enabled"] = dct.get("enabled", True)
|
|
out["host_uuid"] = dct.get("uuid", None)
|
|
out["host_name-label"] = dct.get("name-label", "")
|
|
out["host_name-description"] = dct.get("name-description", "")
|
|
# out["host_host-metrics-live"] = dct.get(
|
|
# "host-metrics-live", "false") == "true"
|
|
out["host_hostname"] = dct.get("hostname", "")
|
|
out["host_ip_address"] = dct.get("address", "")
|
|
oc = dct.get("other-config", "")
|
|
ocd = {}
|
|
if oc:
|
|
for oc_fld in oc.split("; "):
|
|
ock, ocv = strip_kv(oc_fld)
|
|
ocd[ock] = ocv
|
|
out["host_other-config"] = ocd
|
|
|
|
capabilities = dct.get("capabilities", "")
|
|
out["host_capabilities"] = capabilities.replace(";", "").split()
|
|
# out["host_allowed-operations"] = dct.get(
|
|
# "allowed-operations", "").split("; ")
|
|
# lsrv = dct.get("license-server", "")
|
|
# out["host_license-server"] = ols = {}
|
|
# if lsrv:
|
|
# for lspart in lsrv.split("; "):
|
|
# lsk, lsv = lspart.split(": ")
|
|
# if lsk == "port":
|
|
# ols[lsk] = safe_int(lsv)
|
|
# else:
|
|
# ols[lsk] = lsv
|
|
# sv = dct.get("software-version", "")
|
|
# out["host_software-version"] = osv = {}
|
|
# if sv:
|
|
# for svln in sv.split("; "):
|
|
# svk, svv = strip_kv(svln)
|
|
# osv[svk] = svv
|
|
cpuinf = dct.get("cpu_info", "")
|
|
ocp = {}
|
|
if cpuinf:
|
|
for cpln in cpuinf.split("; "):
|
|
cpk, cpv = strip_kv(cpln)
|
|
if cpk in ("cpu_count", "family", "model", "stepping"):
|
|
ocp[cpk] = safe_int(cpv)
|
|
else:
|
|
ocp[cpk] = cpv
|
|
out["host_cpu_info"] = ocp
|
|
# out["host_edition"] = dct.get("edition", "")
|
|
# out["host_external-auth-service-name"] = dct.get(
|
|
# "external-auth-service-name", "")
|
|
return out
|
|
|
|
|
|
def query_gc(session, sr_uuid, vdi_uuid):
|
|
result = _run_command(["/opt/xensource/sm/cleanup.py",
|
|
"-q", "-u", sr_uuid])
|
|
# Example output: "Currently running: True"
|
|
return result[19:].strip() == "True"
|
|
|
|
|
|
def get_pci_device_details(session):
|
|
"""Returns a string that is a list of pci devices with details.
|
|
|
|
This string is obtained by running the command lspci. With -vmm option,
|
|
it dumps PCI device data in machine readable form. This verbose format
|
|
display a sequence of records separated by a blank line. We will also
|
|
use option "-n" to get vendor_id and device_id as numeric values and
|
|
the "-k" option to get the kernel driver used if any.
|
|
"""
|
|
return _run_command(["lspci", "-vmmnk"])
|
|
|
|
|
|
def get_pci_type(session, pci_device):
|
|
"""Returns the type of the PCI device (type-PCI, type-VF or type-PF).
|
|
|
|
pci-device -- The address of the pci device
|
|
"""
|
|
# We need to add the domain if it is missing
|
|
if pci_device.count(':') == 1:
|
|
pci_device = "0000:" + pci_device
|
|
output = _run_command(["ls", "/sys/bus/pci/devices/" + pci_device + "/"])
|
|
|
|
if "physfn" in output:
|
|
return "type-VF"
|
|
if "virtfn" in output:
|
|
return "type-PF"
|
|
return "type-PCI"
|
|
|
|
|
|
if __name__ == "__main__":
|
|
# Support both serialized and non-serialized plugin approaches
|
|
_, methodname = xmlrpclib.loads(sys.argv[1])
|
|
if methodname in ['query_gc', 'get_pci_device_details', 'get_pci_type',
|
|
'network_config']:
|
|
utils.register_plugin_calls(query_gc,
|
|
get_pci_device_details,
|
|
get_pci_type,
|
|
network_config)
|
|
|
|
XenAPIPlugin.dispatch(
|
|
{"host_data": host_data,
|
|
"set_host_enabled": set_host_enabled,
|
|
"host_shutdown": host_shutdown,
|
|
"host_reboot": host_reboot,
|
|
"host_start": host_start,
|
|
"host_join": host_join,
|
|
"get_config": get_config,
|
|
"set_config": set_config,
|
|
"iptables_config": iptables_config,
|
|
"host_uptime": host_uptime})
|