diff options
| author | Ryan Lane <rlane@wikimedia.org> | 2011-01-20 00:46:04 +0000 |
|---|---|---|
| committer | Ryan Lane <rlane@wikimedia.org> | 2011-01-20 00:46:04 +0000 |
| commit | 10bae7259abd6c663ff9513991f03c88555be1e6 (patch) | |
| tree | 7ee00422364b762c76a038b8d2d0785f00924e2f /plugins | |
| parent | 5177483ffed3a6a74bff07442f1b9f9f29c1d2c5 (diff) | |
| parent | 3466df5035b3cc6e376124d1caa72b0761341c4c (diff) | |
| download | nova-10bae7259abd6c663ff9513991f03c88555be1e6.tar.gz nova-10bae7259abd6c663ff9513991f03c88555be1e6.tar.xz nova-10bae7259abd6c663ff9513991f03c88555be1e6.zip | |
Merge from trunk
Diffstat (limited to 'plugins')
| -rwxr-xr-x | plugins/xenserver/xenapi/etc/xapi.d/plugins/agent | 126 | ||||
| -rw-r--r-- | plugins/xenserver/xenapi/etc/xapi.d/plugins/glance | 44 |
2 files changed, 162 insertions, 8 deletions
diff --git a/plugins/xenserver/xenapi/etc/xapi.d/plugins/agent b/plugins/xenserver/xenapi/etc/xapi.d/plugins/agent new file mode 100755 index 000000000..12c3a19c8 --- /dev/null +++ b/plugins/xenserver/xenapi/etc/xapi.d/plugins/agent @@ -0,0 +1,126 @@ +#!/usr/bin/env python + +# Copyright (c) 2011 Citrix Systems, Inc. +# Copyright 2011 OpenStack LLC. +# 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. + +# +# XenAPI plugin for reading/writing information to xenstore +# + +try: + import json +except ImportError: + import simplejson as json +import os +import random +import subprocess +import tempfile +import time + +import XenAPIPlugin + +from pluginlib_nova import * +configure_logging("xenstore") +import xenstore + +AGENT_TIMEOUT = 30 + + +def jsonify(fnc): + def wrapper(*args, **kwargs): + return json.dumps(fnc(*args, **kwargs)) + return wrapper + + +class TimeoutError(StandardError): + pass + + +@jsonify +def key_init(self, arg_dict): + """Handles the Diffie-Hellman key exchange with the agent to + establish the shared secret key used to encrypt/decrypt sensitive + info to be passed, such as passwords. Returns the shared + secret key value. + """ + pub = int(arg_dict["pub"]) + arg_dict["value"] = json.dumps({"name": "keyinit", "value": pub}) + request_id = arg_dict["id"] + arg_dict["path"] = "data/host/%s" % request_id + xenstore.write_record(self, arg_dict) + try: + resp = _wait_for_agent(self, request_id, arg_dict) + except TimeoutError, e: + raise PluginError("%s" % e) + return resp + + +@jsonify +def password(self, arg_dict): + """Writes a request to xenstore that tells the agent to set + the root password for the given VM. The password should be + encrypted using the shared secret key that was returned by a + previous call to key_init. The encrypted password value should + be passed as the value for the 'enc_pass' key in arg_dict. + """ + pub = int(arg_dict["pub"]) + enc_pass = arg_dict["enc_pass"] + arg_dict["value"] = json.dumps({"name": "password", "value": enc_pass}) + request_id = arg_dict["id"] + arg_dict["path"] = "data/host/%s" % request_id + xenstore.write_record(self, arg_dict) + try: + resp = _wait_for_agent(self, request_id, arg_dict) + except TimeoutError, e: + raise PluginError("%s" % e) + return resp + + +def _wait_for_agent(self, request_id, arg_dict): + """Periodically checks xenstore for a response from the agent. + The request is always written to 'data/host/{id}', and + the agent's response for that request will be in 'data/guest/{id}'. + If no value appears from the agent within the time specified by + AGENT_TIMEOUT, the original request is deleted and a TimeoutError + is returned. + """ + arg_dict["path"] = "data/guest/%s" % request_id + arg_dict["ignore_missing_path"] = True + start = time.time() + while True: + if time.time() - start > AGENT_TIMEOUT: + # No response within the timeout period; bail out + # First, delete the request record + arg_dict["path"] = "data/host/%s" % request_id + xenstore.delete_record(self, arg_dict) + raise TimeoutError("TIMEOUT: No response from agent within %s seconds." % + AGENT_TIMEOUT) + ret = xenstore.read_record(self, arg_dict) + # Note: the response for None with be a string that includes + # double quotes. + if ret != '"None"': + # The agent responded + return ret + else: + time.sleep(3) + + +if __name__ == "__main__": + XenAPIPlugin.dispatch( + {"key_init": key_init, + "password": password}) diff --git a/plugins/xenserver/xenapi/etc/xapi.d/plugins/glance b/plugins/xenserver/xenapi/etc/xapi.d/plugins/glance index 5e648b970..aadacce57 100644 --- a/plugins/xenserver/xenapi/etc/xapi.d/plugins/glance +++ b/plugins/xenserver/xenapi/etc/xapi.d/plugins/glance @@ -18,7 +18,7 @@ # under the License. # -# XenAPI plugin for putting images into glance +# XenAPI plugin for managing glance images # import base64 @@ -40,29 +40,57 @@ from pluginlib_nova import * configure_logging('glance') CHUNK_SIZE = 8192 +KERNEL_DIR = '/boot/guest' FILE_SR_PATH = '/var/run/sr-mount' +def copy_kernel_vdi(session,args): + vdi = exists(args, 'vdi-ref') + size = exists(args,'image-size') + #Use the uuid as a filename + vdi_uuid=session.xenapi.VDI.get_uuid(vdi) + copy_args={'vdi_uuid':vdi_uuid,'vdi_size':int(size)} + filename=with_vdi_in_dom0(session, vdi, False, + lambda dev: + _copy_kernel_vdi('/dev/%s' % dev,copy_args)) + return filename + +def _copy_kernel_vdi(dest,copy_args): + vdi_uuid=copy_args['vdi_uuid'] + vdi_size=copy_args['vdi_size'] + logging.debug("copying kernel/ramdisk file from %s to /boot/guest/%s",dest,vdi_uuid) + filename=KERNEL_DIR + '/' + vdi_uuid + #read data from /dev/ and write into a file on /boot/guest + of=open(filename,'wb') + f=open(dest,'rb') + #copy only vdi_size bytes + data=f.read(vdi_size) + of.write(data) + f.close() + of.close() + logging.debug("Done. Filename: %s",filename) + return filename + def put_vdis(session, args): params = pickle.loads(exists(args, 'params')) vdi_uuids = params["vdi_uuids"] - image_name = params["image_name"] + image_id = params["image_id"] glance_host = params["glance_host"] glance_port = params["glance_port"] sr_path = get_sr_path(session) #FIXME(sirp): writing to a temp file until Glance supports chunked-PUTs - tmp_file = "%s.tar.gz" % os.path.join('/tmp', image_name) + tmp_file = "%s.tar.gz" % os.path.join('/tmp', str(image_id)) tar_cmd = ['tar', '-zcf', tmp_file, '--directory=%s' % sr_path] paths = [ "%s.vhd" % vdi_uuid for vdi_uuid in vdi_uuids ] tar_cmd.extend(paths) logging.debug("Bundling image with cmd: %s", tar_cmd) subprocess.call(tar_cmd) logging.debug("Writing to test file %s", tmp_file) - put_bundle_in_glance(tmp_file, image_name, glance_host, glance_port) + put_bundle_in_glance(tmp_file, image_id, glance_host, glance_port) return "" # FIXME(sirp): return anything useful here? -def put_bundle_in_glance(tmp_file, image_name, glance_host, glance_port): +def put_bundle_in_glance(tmp_file, image_id, glance_host, glance_port): size = os.path.getsize(tmp_file) basename = os.path.basename(tmp_file) @@ -72,7 +100,6 @@ def put_bundle_in_glance(tmp_file, image_name, glance_host, glance_port): 'x-image-meta-store': 'file', 'x-image-meta-is_public': 'True', 'x-image-meta-type': 'raw', - 'x-image-meta-name': image_name, 'x-image-meta-size': size, 'content-length': size, 'content-type': 'application/octet-stream', @@ -80,7 +107,7 @@ def put_bundle_in_glance(tmp_file, image_name, glance_host, glance_port): conn = httplib.HTTPConnection(glance_host, glance_port) #NOTE(sirp): httplib under python2.4 won't accept a file-like object # to request - conn.putrequest('POST', '/images') + conn.putrequest('PUT', '/images/%s' % image_id) for header, value in headers.iteritems(): conn.putheader(header, value) @@ -129,4 +156,5 @@ def find_sr(session): if __name__ == '__main__': - XenAPIPlugin.dispatch({'put_vdis': put_vdis}) + XenAPIPlugin.dispatch({'put_vdis': put_vdis, + 'copy_kernel_vdi': copy_kernel_vdi}) |
