summaryrefslogtreecommitdiffstats
path: root/plugins
diff options
context:
space:
mode:
Diffstat (limited to 'plugins')
-rwxr-xr-xplugins/xenserver/xenapi/etc/xapi.d/plugins/glance22
-rwxr-xr-xplugins/xenserver/xenapi/etc/xapi.d/plugins/xenhost109
2 files changed, 128 insertions, 3 deletions
diff --git a/plugins/xenserver/xenapi/etc/xapi.d/plugins/glance b/plugins/xenserver/xenapi/etc/xapi.d/plugins/glance
index 86e837849..a06312890 100755
--- a/plugins/xenserver/xenapi/etc/xapi.d/plugins/glance
+++ b/plugins/xenserver/xenapi/etc/xapi.d/plugins/glance
@@ -248,6 +248,22 @@ def _upload_tarball(staging_path, image_id, glance_host, glance_port, os_type,
using chunked-transfer-encoded HTTP.
"""
conn = httplib.HTTPConnection(glance_host, glance_port)
+
+ # NOTE(dprince): We need to resend any existing Glance meta/property
+ # headers so they are preserved in Glance. We obtain them here with a
+ # HEAD request.
+ conn.request('HEAD', '/v1/images/%s' % image_id)
+ resp = conn.getresponse()
+ if resp.status != httplib.OK:
+ raise Exception("Unexpected response from Glance %i" % resp.status)
+ headers = {}
+ for header, value in resp.getheaders():
+ if header.lower().startswith("x-image-meta-property-"):
+ headers[header.lower()] = value
+
+ # Toss body so connection state-machine is ready for next request/response
+ resp.read()
+
# NOTE(sirp): httplib under python2.4 won't accept a file-like object
# to request
conn.putrequest('PUT', '/v1/images/%s' % image_id)
@@ -260,7 +276,7 @@ def _upload_tarball(staging_path, image_id, glance_host, glance_port, os_type,
# 2. We're currently uploading a vanilla tarball. In order to be OVF/OVA
# compliant, we'll need to embed a minimal OVF manifest as the first
# file.
- headers = {
+ ovf_headers = {
'content-type': 'application/octet-stream',
'transfer-encoding': 'chunked',
'x-image-meta-is-public': 'True',
@@ -271,7 +287,9 @@ def _upload_tarball(staging_path, image_id, glance_host, glance_port, os_type,
# If we have an auth_token, set an x-auth-token header
if auth_token:
- headers['x-auth-token'] = auth_token
+ ovf_headers['x-auth-token'] = auth_token
+
+ headers.update(ovf_headers)
for header, value in headers.iteritems():
conn.putheader(header, value)
diff --git a/plugins/xenserver/xenapi/etc/xapi.d/plugins/xenhost b/plugins/xenserver/xenapi/etc/xapi.d/plugins/xenhost
index 292bbce12..cd9694ce1 100755
--- a/plugins/xenserver/xenapi/etc/xapi.d/plugins/xenhost
+++ b/plugins/xenserver/xenapi/etc/xapi.d/plugins/xenhost
@@ -39,6 +39,7 @@ import pluginlib_nova as pluginlib
pluginlib.configure_logging("xenhost")
host_data_pattern = re.compile(r"\s*(\S+) \([^\)]+\) *: ?(.*)")
+config_file_path = "/usr/etc/xenhost.conf"
def jsonify(fnc):
@@ -103,6 +104,104 @@ def set_host_enabled(self, arg_dict):
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, e:
+ 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, e:
+ 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 _power_action(action):
+ host_uuid = _get_host_uuid()
+ # Host must be disabled first
+ result = _run_command("xe host-disable")
+ if result:
+ raise pluginlib.PluginError(result)
+ # All running VMs must be shutdown
+ result = _run_command("xe vm-shutdown --multiple power-state=running")
+ if result:
+ raise pluginlib.PluginError(result)
+ cmds = {"reboot": "xe host-reboot", "startup": "xe host-power-on",
+ "shutdown": "xe host-shutdown"}
+ result = _run_command(cmds[action])
+ # 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")
+
+
+@jsonify
+def host_shutdown(self, arg_dict):
+ """Reboots the host."""
+ return _power_action("shutdown")
+
+
+@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")
+
+
@jsonify
def host_data(self, arg_dict):
"""Runs the commands on the xenstore host to return the current status
@@ -115,6 +214,9 @@ def host_data(self, arg_dict):
# 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
@@ -217,4 +319,9 @@ def cleanup(dct):
if __name__ == "__main__":
XenAPIPlugin.dispatch(
{"host_data": host_data,
- "set_host_enabled": set_host_enabled})
+ "set_host_enabled": set_host_enabled,
+ "host_shutdown": host_shutdown,
+ "host_reboot": host_reboot,
+ "host_start": host_start,
+ "get_config": get_config,
+ "set_config": set_config})