From e66f3017373dcf9135c53ae4d510b0b2a5dcecf0 Mon Sep 17 00:00:00 2001 From: Ed Leafe Date: Thu, 6 Jan 2011 15:53:11 -0600 Subject: Got the basic 'set admin password' stuff working --- plugins/xenserver/xenapi/etc/xapi.d/plugins/agent | 235 +++++++++++++++++++++ .../xenserver/xenapi/etc/xapi.d/plugins/agent.py | 221 ------------------- 2 files changed, 235 insertions(+), 221 deletions(-) create mode 100755 plugins/xenserver/xenapi/etc/xapi.d/plugins/agent delete mode 100644 plugins/xenserver/xenapi/etc/xapi.d/plugins/agent.py (limited to 'plugins') 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..244509f3f --- /dev/null +++ b/plugins/xenserver/xenapi/etc/xapi.d/plugins/agent @@ -0,0 +1,235 @@ +#!/usr/bin/env python + +# Copyright (c) 2010 Citrix Systems, Inc. +# Copyright 2010 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 +# Used for simulating an external agent for testing +PRETEND_SECRET = 11111 + + +def jsonify(fnc): + def wrapper(*args, **kwargs): + return json.dumps(fnc(*args, **kwargs)) + return wrapper + + +class TimeoutError(StandardError): + pass + + +class SimpleDH(object): + """This class wraps all the functionality needed to implement + basic Diffie-Hellman-Merkle key exchange in Python. It features + intelligent defaults for the prime and base numbers needed for the + calculation, while allowing you to supply your own. It requires that + the openssl binary be installed on the system on which this is run, + as it uses that to handle the encryption and decryption. If openssl + is not available, a RuntimeError will be raised. + + Please note that nova already uses the M2Crypto library for most + cryptographic functions, and that it includes a Diffie-Hellman + implementation. However, that is a much more complex implementation, + and is not compatible with the DH algorithm that the agent uses. Hence + the need for this 'simple' version. + """ + def __init__(self, prime=None, base=None, secret=None): + """You can specify the values for prime and base if you wish; + otherwise, reasonable default values will be used. + """ + if prime is None: + self._prime = 162259276829213363391578010288127 + else: + self._prime = prime + if base is None: + self._base = 5 + else: + self._base = base + if secret is None: + self._secret = random.randint(5000, 15000) + else: + self._secret = secret + self._shared = self._public = None + + def get_public(self): + """Return the public key""" + self._public = (self._base ** self._secret) % self._prime + return self._public + + def compute_shared(self, other): + """Given the other end's public key, compute the + shared secret. + """ + self._shared = (other ** self._secret) % self._prime + return self._shared + + def _run_ssl(self, text, which): + """The encryption/decryption methods require running the openssl + installed on the system. This method abstracts out the common + code required. + """ + base_cmd = ("cat %(tmpfile)s | openssl enc -aes-128-cbc " + "-a -pass pass:%(shared)s -nosalt %(dec_flag)s") + if which.lower()[0] == "d": + dec_flag = " -d" + else: + dec_flag = "" + # Note: instead of using 'cat' and a tempfile, it is also + # possible to just 'echo' the value. However, we can not assume + # that the value is 'safe'; i.e., it may contain semi-colons, + # octothorpes, or other characters that would not be allowed + # in an 'echo' construct. + fd, tmpfile = tempfile.mkstemp() + os.close(fd) + file(tmpfile, "w").write(text) + shared = self._shared + cmd = base_cmd % locals() + try: + return _run_command(cmd) + except PluginError, e: + raise RuntimeError("OpenSSL error: %s" % e) + + def encrypt(self, text): + """Uses the shared key to encrypt the given text.""" + return self._run_ssl(text, "enc") + + def decrypt(self, text): + """Uses the shared key to decrypt the given text.""" + return self._run_ssl(text, "dec") + + +def _run_command(cmd): + """Abstracts out the basics of issuing system commands. If the command + returns anything in stderr, a PluginError is raised with that information. + Otherwise, the output from stdout is returned. + """ + pipe = subprocess.PIPE + proc = subprocess.Popen([cmd], shell=True, stdin=pipe, stdout=pipe, stderr=pipe, close_fds=True) + proc.wait() + err = proc.stderr.read() + if err: + raise PluginError(err) + return proc.stdout.read() + + +@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"] + if arg_dict.get("testing_mode"): + # Pretend! + pretend = SimpleDH(secret=PRETEND_SECRET) + shared = pretend.compute_shared(pub) + # Simulate the agent's response + ret = {"returncode": "D0", "message": "%s", "shared": "%s"} % (pretend.get_public(), shared) + return ret + 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"] + if arg_dict.get("testing_mode"): + # Decrypt the password, and send it back to verify + pretend = SimpleDH(secret=PRETEND_SECRET) + pretend.compute_shared(pub) + pw = pretend.decrypt(enc_pass) + ret = {"returncode": "0", "message": "%s"} % pw + return ret + 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/agent.py b/plugins/xenserver/xenapi/etc/xapi.d/plugins/agent.py deleted file mode 100644 index 4b072ce67..000000000 --- a/plugins/xenserver/xenapi/etc/xapi.d/plugins/agent.py +++ /dev/null @@ -1,221 +0,0 @@ -#!/usr/bin/env python - -# Copyright (c) 2010 Citrix Systems, Inc. -# Copyright 2010 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 -# Used for simulating an external agent for testing -PRETEND_SECRET = 11111 - - -class TimeoutError(StandardError): - pass - -class SimpleDH(object): - """This class wraps all the functionality needed to implement - basic Diffie-Hellman-Merkle key exchange in Python. It features - intelligent defaults for the prime and base numbers needed for the - calculation, while allowing you to supply your own. It requires that - the openssl binary be installed on the system on which this is run, - as it uses that to handle the encryption and decryption. If openssl - is not available, a RuntimeError will be raised. - - Please note that nova already uses the M2Crypto library for most - cryptographic functions, and that it includes a Diffie-Hellman - implementation. However, that is a much more complex implementation, - and is not compatible with the DH algorithm that the agent uses. Hence - the need for this 'simple' version. - """ - def __init__(self, prime=None, base=None, secret=None): - """You can specify the values for prime and base if you wish; - otherwise, reasonable default values will be used. - """ - if prime is None: - self._prime = 162259276829213363391578010288127 - else: - self._prime = prime - if base is None: - self._base = 5 - else: - self._base = base - if secret is None: - self._secret = random.randint(5000, 15000) - else: - self._secret = secret - self._shared = self._public = None - - def get_public(self): - """Return the public key""" - self._public = (self._base ** self._secret) % self._prime - return self._public - - def compute_shared(self, other): - """Given the other end's public key, compute the - shared secret. - """ - self._shared = (other ** self._secret) % self._prime - return self._shared - - def _run_ssl(self, text, which): - """The encryption/decryption methods require running the openssl - installed on the system. This method abstracts out the common - code required. - """ - base_cmd = ("cat %(tmpfile)s | openssl enc -aes-128-cbc " - "-a -pass pass:%(shared)s -nosalt %(dec_flag)s") - if which.lower()[0] == "d": - dec_flag = " -d" - else: - dec_flag = "" - # Note: instead of using 'cat' and a tempfile, it is also - # possible to just 'echo' the value. However, we can not assume - # that the value is 'safe'; i.e., it may contain semi-colons, - # octothorpes, or other characters that would not be allowed - # in an 'echo' construct. - fd, tmpfile = tempfile.mkstemp() - os.close(fd) - file(tmpfile, "w").write(text) - shared = self._shared - cmd = base_cmd % locals() - try: - return _run_command(cmd) - except PluginError, e: - raise RuntimeError("OpenSSL error: %s" % e) - - def encrypt(self, text): - """Uses the shared key to encrypt the given text.""" - return self._run_ssl(text, "enc") - - def decrypt(self, text): - """Uses the shared key to decrypt the given text.""" - return self._run_ssl(text, "dec") - - -def _run_command(cmd): - """Abstracts out the basics of issuing system commands. If the command - returns anything in stderr, a PluginError is raised with that information. - Otherwise, the output from stdout is returned. - """ - pipe = subprocess.PIPE - proc = subprocess.Popen([cmd], shell=True, stdin=pipe, stdout=pipe, stderr=pipe, close_fds=True) - proc.wait() - err = proc.stderr.read() - if err: - raise PluginError(err) - return proc.stdout.read() - -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"] - if arg_dict.get("testing_mode"): - # Pretend! - pretend = SimpleDH(secret=PRETEND_SECRET) - shared = pretend.compute_shared(pub) - # Simulate the agent's response - ret = '{ "returncode": "D0", "message": "%s", "shared": "%s" }' % (pretend.get_public(), shared) - return ret - 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 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"] - if arg_dict.get("testing_mode"): - # Decrypt the password, and send it back to verify - pretend = SimpleDH(secret=PRETEND_SECRET) - pretend.compute_shared(pub) - pw = pretend.decrypt(enc_pass) - ret = '{ "returncode": "0", "message": "%s" }' % pw - return ret - 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("No response from agent within %s seconds." % - AGENT_TIMEOUT) - ret = xenstore.read_record(self, arg_dict) - if ret != "None": - # The agent responded - return ret - else: - time.sleep(3) - - -if __name__ == "__main__": - XenAPIPlugin.dispatch( - {"key_init": key_init, - "password": password}) -- cgit From 3bf9bc6f6c0fbf90e3f4eab68a9bd99d85fcc422 Mon Sep 17 00:00:00 2001 From: Rick Harris Date: Thu, 6 Jan 2011 21:37:33 -0600 Subject: Reserving image before uploading --- plugins/xenserver/xenapi/etc/xapi.d/plugins/glance | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) (limited to 'plugins') diff --git a/plugins/xenserver/xenapi/etc/xapi.d/plugins/glance b/plugins/xenserver/xenapi/etc/xapi.d/plugins/glance index 5e648b970..cc34a1ec9 100644 --- a/plugins/xenserver/xenapi/etc/xapi.d/plugins/glance +++ b/plugins/xenserver/xenapi/etc/xapi.d/plugins/glance @@ -45,24 +45,24 @@ FILE_SR_PATH = '/var/run/sr-mount' 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 +72,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 +79,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) -- cgit From eaa5b5994891eee0280b750dff221a4b54932eb9 Mon Sep 17 00:00:00 2001 From: Ed Leafe Date: Fri, 7 Jan 2011 10:23:48 -0600 Subject: getting ready to push for merge prop --- plugins/xenserver/xenapi/etc/xapi.d/plugins/agent | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'plugins') diff --git a/plugins/xenserver/xenapi/etc/xapi.d/plugins/agent b/plugins/xenserver/xenapi/etc/xapi.d/plugins/agent index 244509f3f..ab5b98d1c 100755 --- a/plugins/xenserver/xenapi/etc/xapi.d/plugins/agent +++ b/plugins/xenserver/xenapi/etc/xapi.d/plugins/agent @@ -161,7 +161,7 @@ def key_init(self, arg_dict): pretend = SimpleDH(secret=PRETEND_SECRET) shared = pretend.compute_shared(pub) # Simulate the agent's response - ret = {"returncode": "D0", "message": "%s", "shared": "%s"} % (pretend.get_public(), shared) + ret = {"returncode": "D0", "message": pretend.get_public(), "shared": shared} return ret arg_dict["path"] = "data/host/%s" % request_id xenstore.write_record(self, arg_dict) @@ -187,7 +187,7 @@ def password(self, arg_dict): pretend = SimpleDH(secret=PRETEND_SECRET) pretend.compute_shared(pub) pw = pretend.decrypt(enc_pass) - ret = {"returncode": "0", "message": "%s"} % pw + ret = {"returncode": "0", "message": pw} return ret arg_dict["value"] = json.dumps({"name": "password", "value": enc_pass}) request_id = arg_dict["id"] -- cgit From 147693e45c7be174c54e39160869ca9a83bb4fff Mon Sep 17 00:00:00 2001 From: Ed Leafe Date: Fri, 7 Jan 2011 11:04:53 -0600 Subject: Additional cleanup prior to pushing --- plugins/xenserver/xenapi/etc/xapi.d/plugins/agent | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) (limited to 'plugins') diff --git a/plugins/xenserver/xenapi/etc/xapi.d/plugins/agent b/plugins/xenserver/xenapi/etc/xapi.d/plugins/agent index ab5b98d1c..70726bf6f 100755 --- a/plugins/xenserver/xenapi/etc/xapi.d/plugins/agent +++ b/plugins/xenserver/xenapi/etc/xapi.d/plugins/agent @@ -1,7 +1,8 @@ #!/usr/bin/env python -# Copyright (c) 2010 Citrix Systems, Inc. -# Copyright 2010 United States Government as represented by the +# 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. # @@ -138,7 +139,8 @@ def _run_command(cmd): Otherwise, the output from stdout is returned. """ pipe = subprocess.PIPE - proc = subprocess.Popen([cmd], shell=True, stdin=pipe, stdout=pipe, stderr=pipe, close_fds=True) + proc = subprocess.Popen([cmd], shell=True, stdin=pipe, stdout=pipe, + stderr=pipe, close_fds=True) proc.wait() err = proc.stderr.read() if err: -- cgit From 97ff39bd1d83f3cfa412f291087e025a91d147cd Mon Sep 17 00:00:00 2001 From: Salvatore Orlando Date: Mon, 10 Jan 2011 18:26:40 +0000 Subject: Can now correctly launch images with external kernels through glance. Further tests and Pep8 fixes to come. --- plugins/xenserver/xenapi/etc/xapi.d/plugins/glance | 30 +++++++++++++++++++++- .../xenapi/etc/xapi.d/plugins/pluginlib_nova.py | 4 +-- 2 files changed, 31 insertions(+), 3 deletions(-) (limited to 'plugins') diff --git a/plugins/xenserver/xenapi/etc/xapi.d/plugins/glance b/plugins/xenserver/xenapi/etc/xapi.d/plugins/glance index 5e648b970..7f0b375e1 100644 --- a/plugins/xenserver/xenapi/etc/xapi.d/plugins/glance +++ b/plugins/xenserver/xenapi/etc/xapi.d/plugins/glance @@ -40,8 +40,35 @@ 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') + 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"] @@ -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}) diff --git a/plugins/xenserver/xenapi/etc/xapi.d/plugins/pluginlib_nova.py b/plugins/xenserver/xenapi/etc/xapi.d/plugins/pluginlib_nova.py index 8e7a829d5..17fcd474e 100755 --- a/plugins/xenserver/xenapi/etc/xapi.d/plugins/pluginlib_nova.py +++ b/plugins/xenserver/xenapi/etc/xapi.d/plugins/pluginlib_nova.py @@ -154,7 +154,7 @@ def create_vdi(session, sr_ref, name_label, virtual_size, read_only): return vdi_ref -def with_vdi_in_dom0(session, vdi, read_only, f): +def with_vdi_in_dom0(session, vdi, read_only, f,args=None): dom0 = get_domain_0(session) vbd_rec = {} vbd_rec['VM'] = dom0 @@ -176,7 +176,7 @@ def with_vdi_in_dom0(session, vdi, read_only, f): logging.debug('Plugging VBD %s ... ', vbd) session.xenapi.VBD.plug(vbd) logging.debug('Plugging VBD %s done.', vbd) - return f(session.xenapi.VBD.get_device(vbd)) + return f(session.xenapi.VBD.get_device(vbd),args) finally: logging.debug('Destroying VBD for VDI %s ... ', vdi) vbd_unplug_with_retry(session, vbd) -- cgit From bae57e82767b4877bae5c2dcb6fe052291d16b32 Mon Sep 17 00:00:00 2001 From: Ed Leafe Date: Mon, 10 Jan 2011 15:33:10 -0600 Subject: Fixed issues raised by reviews --- plugins/xenserver/xenapi/etc/xapi.d/plugins/agent | 16 ---------------- 1 file changed, 16 deletions(-) (limited to 'plugins') diff --git a/plugins/xenserver/xenapi/etc/xapi.d/plugins/agent b/plugins/xenserver/xenapi/etc/xapi.d/plugins/agent index 70726bf6f..82dd5466e 100755 --- a/plugins/xenserver/xenapi/etc/xapi.d/plugins/agent +++ b/plugins/xenserver/xenapi/etc/xapi.d/plugins/agent @@ -39,8 +39,6 @@ configure_logging("xenstore") import xenstore AGENT_TIMEOUT = 30 -# Used for simulating an external agent for testing -PRETEND_SECRET = 11111 def jsonify(fnc): @@ -158,13 +156,6 @@ def key_init(self, arg_dict): pub = int(arg_dict["pub"]) arg_dict["value"] = json.dumps({"name": "keyinit", "value": pub}) request_id = arg_dict["id"] - if arg_dict.get("testing_mode"): - # Pretend! - pretend = SimpleDH(secret=PRETEND_SECRET) - shared = pretend.compute_shared(pub) - # Simulate the agent's response - ret = {"returncode": "D0", "message": pretend.get_public(), "shared": shared} - return ret arg_dict["path"] = "data/host/%s" % request_id xenstore.write_record(self, arg_dict) try: @@ -184,13 +175,6 @@ def password(self, arg_dict): """ pub = int(arg_dict["pub"]) enc_pass = arg_dict["enc_pass"] - if arg_dict.get("testing_mode"): - # Decrypt the password, and send it back to verify - pretend = SimpleDH(secret=PRETEND_SECRET) - pretend.compute_shared(pub) - pw = pretend.decrypt(enc_pass) - ret = {"returncode": "0", "message": pw} - return ret arg_dict["value"] = json.dumps({"name": "password", "value": enc_pass}) request_id = arg_dict["id"] arg_dict["path"] = "data/host/%s" % request_id -- cgit From 6ba35582eec774253d725ab7a6959fdc12cea215 Mon Sep 17 00:00:00 2001 From: Salvatore Orlando Date: Tue, 11 Jan 2011 01:50:14 +0000 Subject: Now removing kernel/ramdisk VDI after copy Code tested with PV and HVM guests Fixed pep8 errors Could not run tests - test environment broken on dev machine --- plugins/xenserver/xenapi/etc/xapi.d/plugins/glance | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'plugins') diff --git a/plugins/xenserver/xenapi/etc/xapi.d/plugins/glance b/plugins/xenserver/xenapi/etc/xapi.d/plugins/glance index 7f0b375e1..97cf32dcf 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 @@ -62,6 +62,7 @@ def _copy_kernel_vdi(dest,copy_args): #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() -- cgit From a96c12f13421a7c27e7cb1459f73ca4bd5cdf917 Mon Sep 17 00:00:00 2001 From: Salvatore Orlando Date: Tue, 11 Jan 2011 16:11:08 +0000 Subject: fixed issue in pluginlib_nova.py --- plugins/xenserver/xenapi/etc/xapi.d/plugins/pluginlib_nova.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'plugins') diff --git a/plugins/xenserver/xenapi/etc/xapi.d/plugins/pluginlib_nova.py b/plugins/xenserver/xenapi/etc/xapi.d/plugins/pluginlib_nova.py index 17fcd474e..8e7a829d5 100755 --- a/plugins/xenserver/xenapi/etc/xapi.d/plugins/pluginlib_nova.py +++ b/plugins/xenserver/xenapi/etc/xapi.d/plugins/pluginlib_nova.py @@ -154,7 +154,7 @@ def create_vdi(session, sr_ref, name_label, virtual_size, read_only): return vdi_ref -def with_vdi_in_dom0(session, vdi, read_only, f,args=None): +def with_vdi_in_dom0(session, vdi, read_only, f): dom0 = get_domain_0(session) vbd_rec = {} vbd_rec['VM'] = dom0 @@ -176,7 +176,7 @@ def with_vdi_in_dom0(session, vdi, read_only, f,args=None): logging.debug('Plugging VBD %s ... ', vbd) session.xenapi.VBD.plug(vbd) logging.debug('Plugging VBD %s done.', vbd) - return f(session.xenapi.VBD.get_device(vbd),args) + return f(session.xenapi.VBD.get_device(vbd)) finally: logging.debug('Destroying VBD for VDI %s ... ', vdi) vbd_unplug_with_retry(session, vbd) -- cgit From d91a06b4fea7e45fd2e9abe35803cd9deb5d8e92 Mon Sep 17 00:00:00 2001 From: Ed Leafe Date: Tue, 11 Jan 2011 12:17:39 -0600 Subject: Removed unneeded SimpleDH code from agent plugin. Improved handling of plugin call failures. --- plugins/xenserver/xenapi/etc/xapi.d/plugins/agent | 95 ----------------------- 1 file changed, 95 deletions(-) (limited to 'plugins') diff --git a/plugins/xenserver/xenapi/etc/xapi.d/plugins/agent b/plugins/xenserver/xenapi/etc/xapi.d/plugins/agent index 82dd5466e..12c3a19c8 100755 --- a/plugins/xenserver/xenapi/etc/xapi.d/plugins/agent +++ b/plugins/xenserver/xenapi/etc/xapi.d/plugins/agent @@ -51,101 +51,6 @@ class TimeoutError(StandardError): pass -class SimpleDH(object): - """This class wraps all the functionality needed to implement - basic Diffie-Hellman-Merkle key exchange in Python. It features - intelligent defaults for the prime and base numbers needed for the - calculation, while allowing you to supply your own. It requires that - the openssl binary be installed on the system on which this is run, - as it uses that to handle the encryption and decryption. If openssl - is not available, a RuntimeError will be raised. - - Please note that nova already uses the M2Crypto library for most - cryptographic functions, and that it includes a Diffie-Hellman - implementation. However, that is a much more complex implementation, - and is not compatible with the DH algorithm that the agent uses. Hence - the need for this 'simple' version. - """ - def __init__(self, prime=None, base=None, secret=None): - """You can specify the values for prime and base if you wish; - otherwise, reasonable default values will be used. - """ - if prime is None: - self._prime = 162259276829213363391578010288127 - else: - self._prime = prime - if base is None: - self._base = 5 - else: - self._base = base - if secret is None: - self._secret = random.randint(5000, 15000) - else: - self._secret = secret - self._shared = self._public = None - - def get_public(self): - """Return the public key""" - self._public = (self._base ** self._secret) % self._prime - return self._public - - def compute_shared(self, other): - """Given the other end's public key, compute the - shared secret. - """ - self._shared = (other ** self._secret) % self._prime - return self._shared - - def _run_ssl(self, text, which): - """The encryption/decryption methods require running the openssl - installed on the system. This method abstracts out the common - code required. - """ - base_cmd = ("cat %(tmpfile)s | openssl enc -aes-128-cbc " - "-a -pass pass:%(shared)s -nosalt %(dec_flag)s") - if which.lower()[0] == "d": - dec_flag = " -d" - else: - dec_flag = "" - # Note: instead of using 'cat' and a tempfile, it is also - # possible to just 'echo' the value. However, we can not assume - # that the value is 'safe'; i.e., it may contain semi-colons, - # octothorpes, or other characters that would not be allowed - # in an 'echo' construct. - fd, tmpfile = tempfile.mkstemp() - os.close(fd) - file(tmpfile, "w").write(text) - shared = self._shared - cmd = base_cmd % locals() - try: - return _run_command(cmd) - except PluginError, e: - raise RuntimeError("OpenSSL error: %s" % e) - - def encrypt(self, text): - """Uses the shared key to encrypt the given text.""" - return self._run_ssl(text, "enc") - - def decrypt(self, text): - """Uses the shared key to decrypt the given text.""" - return self._run_ssl(text, "dec") - - -def _run_command(cmd): - """Abstracts out the basics of issuing system commands. If the command - returns anything in stderr, a PluginError is raised with that information. - Otherwise, the output from stdout is returned. - """ - pipe = subprocess.PIPE - proc = subprocess.Popen([cmd], shell=True, stdin=pipe, stdout=pipe, - stderr=pipe, close_fds=True) - proc.wait() - err = proc.stderr.read() - if err: - raise PluginError(err) - return proc.stdout.read() - - @jsonify def key_init(self, arg_dict): """Handles the Diffie-Hellman key exchange with the agent to -- cgit From 13b4f32d1995a8c50bcf86786b6ee75d49bea701 Mon Sep 17 00:00:00 2001 From: "jaypipes@gmail.com" <> Date: Thu, 20 Jan 2011 12:52:02 -0500 Subject: i18n's strings that were missed or have been added since initial i18n strings branch. --- .../xenapi/etc/xapi.d/plugins/pluginlib_nova.py | 60 +++++++++++++--------- 1 file changed, 37 insertions(+), 23 deletions(-) (limited to 'plugins') diff --git a/plugins/xenserver/xenapi/etc/xapi.d/plugins/pluginlib_nova.py b/plugins/xenserver/xenapi/etc/xapi.d/plugins/pluginlib_nova.py index 8e7a829d5..cc0a196af 100755 --- a/plugins/xenserver/xenapi/etc/xapi.d/plugins/pluginlib_nova.py +++ b/plugins/xenserver/xenapi/etc/xapi.d/plugins/pluginlib_nova.py @@ -60,7 +60,7 @@ def ignore_failure(func, *args, **kwargs): try: return func(*args, **kwargs) except XenAPI.Failure, e: - logging.error('Ignoring XenAPI.Failure %s', e) + logging.error(_('Ignoring XenAPI.Failure %s'), e) return None @@ -78,19 +78,25 @@ def validate_exists(args, key, default=None): """ if key in args: if len(args[key]) == 0: - raise ArgumentError('Argument %r value %r is too short.' % - (key, args[key])) + raise ArgumentError(_('Argument %(key)s value %(value)s is too ' + 'short.') % + {'key': key, + 'value': args[key]}) if not ARGUMENT_PATTERN.match(args[key]): - raise ArgumentError('Argument %r value %r contains invalid ' - 'characters.' % (key, args[key])) + raise ArgumentError(_('Argument %(key)s value %(value)s contains ' + 'invalid characters.') % + {'key': key, + 'value': args[key]}) if args[key][0] == '-': - raise ArgumentError('Argument %r value %r starts with a hyphen.' - % (key, args[key])) + raise ArgumentError(_('Argument %(key)s value %(value)s starts ' + 'with a hyphen.') % + {'key': key, + 'value': args[key]}) return args[key] elif default is not None: return default else: - raise ArgumentError('Argument %s is required.' % key) + raise ArgumentError(_('Argument %s is required.') % key) def validate_bool(args, key, default=None): @@ -105,8 +111,10 @@ def validate_bool(args, key, default=None): elif value.lower() == 'false': return False else: - raise ArgumentError("Argument %s may not take value %r. " - "Valid values are ['true', 'false']." % (key, value)) + raise ArgumentError(_("Argument %(key)s may not take value %(value)s. " + "Valid values are ['true', 'false'].") + % {'key': key, + 'value': value}) def exists(args, key): @@ -116,7 +124,7 @@ def exists(args, key): if key in args: return args[key] else: - raise ArgumentError('Argument %s is required.' % key) + raise ArgumentError(_('Argument %s is required.') % key) def optional(args, key): @@ -149,8 +157,13 @@ def create_vdi(session, sr_ref, name_label, virtual_size, read_only): 'other_config': {}, 'sm_config': {}, 'tags': []}) - logging.debug('Created VDI %s (%s, %s, %s) on %s.', vdi_ref, name_label, - virtual_size, read_only, sr_ref) + logging.debug(_('Created VDI %(vdi_ref)s (%(label)s, %(size)s, ' + '%(read_only)s) on %(sr_ref)s.') % + {'vdi_ref': vdi_ref, + 'label': name_label, + 'size': virtual_size, + 'read_only': read_only, + 'sr_ref': sr_ref}) return vdi_ref @@ -169,19 +182,19 @@ def with_vdi_in_dom0(session, vdi, read_only, f): vbd_rec['qos_algorithm_type'] = '' vbd_rec['qos_algorithm_params'] = {} vbd_rec['qos_supported_algorithms'] = [] - logging.debug('Creating VBD for VDI %s ... ', vdi) + logging.debug(_('Creating VBD for VDI %s ... '), vdi) vbd = session.xenapi.VBD.create(vbd_rec) - logging.debug('Creating VBD for VDI %s done.', vdi) + logging.debug(_('Creating VBD for VDI %s done.'), vdi) try: - logging.debug('Plugging VBD %s ... ', vbd) + logging.debug(_('Plugging VBD %s ... '), vbd) session.xenapi.VBD.plug(vbd) - logging.debug('Plugging VBD %s done.', vbd) + logging.debug(_('Plugging VBD %s done.'), vbd) return f(session.xenapi.VBD.get_device(vbd)) finally: - logging.debug('Destroying VBD for VDI %s ... ', vdi) + logging.debug(_('Destroying VBD for VDI %s ... '), vdi) vbd_unplug_with_retry(session, vbd) ignore_failure(session.xenapi.VBD.destroy, vbd) - logging.debug('Destroying VBD for VDI %s done.', vdi) + logging.debug(_('Destroying VBD for VDI %s done.'), vdi) def vbd_unplug_with_retry(session, vbd): @@ -192,19 +205,20 @@ def vbd_unplug_with_retry(session, vbd): while True: try: session.xenapi.VBD.unplug(vbd) - logging.debug('VBD.unplug successful first time.') + logging.debug(_('VBD.unplug successful first time.')) return except XenAPI.Failure, e: if (len(e.details) > 0 and e.details[0] == 'DEVICE_DETACH_REJECTED'): - logging.debug('VBD.unplug rejected: retrying...') + logging.debug(_('VBD.unplug rejected: retrying...')) time.sleep(1) elif (len(e.details) > 0 and e.details[0] == 'DEVICE_ALREADY_DETACHED'): - logging.debug('VBD.unplug successful eventually.') + logging.debug(_('VBD.unplug successful eventually.')) return else: - logging.error('Ignoring XenAPI.Failure in VBD.unplug: %s', e) + logging.error(_('Ignoring XenAPI.Failure in VBD.unplug: %s'), + e) return -- cgit From b05f4f55f05d9b177ddde03da769cb95c8fbb72e Mon Sep 17 00:00:00 2001 From: Rick Harris Date: Fri, 21 Jan 2011 19:10:31 +0000 Subject: Adding getttext to pluginlib_nova --- plugins/xenserver/xenapi/etc/xapi.d/plugins/pluginlib_nova.py | 2 ++ 1 file changed, 2 insertions(+) (limited to 'plugins') diff --git a/plugins/xenserver/xenapi/etc/xapi.d/plugins/pluginlib_nova.py b/plugins/xenserver/xenapi/etc/xapi.d/plugins/pluginlib_nova.py index cc0a196af..7fea1136d 100755 --- a/plugins/xenserver/xenapi/etc/xapi.d/plugins/pluginlib_nova.py +++ b/plugins/xenserver/xenapi/etc/xapi.d/plugins/pluginlib_nova.py @@ -19,6 +19,8 @@ # that we need. # +import gettext +gettext.install('nova', unicode=1) import httplib import logging import logging.handlers -- cgit