Merge lp:~use/nova/shared-storage into lp:~hudson-openstack/nova/trunk

Proposed by USE Team
Status: Superseded
Proposed branch: lp:~use/nova/shared-storage
Merge into: lp:~hudson-openstack/nova/trunk
Diff against target: 192 lines (+90/-7)
3 files modified
Authors (+1/-0)
nova/virt/xenapi/vm_utils.py (+42/-0)
plugins/xenserver/xenapi/etc/xapi.d/plugins/glance (+47/-7)
To merge this branch: bzr merge lp:~use/nova/shared-storage
Reviewer Review Type Date Requested Status
Christopher MacGown (community) Needs Fixing
Review via email: mp+72931@code.launchpad.net

This proposal has been superseded by a proposal from 2011-08-29.

Description of the change

The current openstack+glance+xenserver environment is not (HBA) shared storage friendly. We can get around this for Linux by (mis-)labelling the HBA LUN local-storage. Unfortunately this does not work for Windows images as they are uploaded in VHD format and XenServer expects them to be VDIs.

This adds a parameter 'staging_path', to the upload_vhd xenapi call which causes the VHD to be loaded into an NFS share that has been labelled 'other-config:i18n-key=scratchnfs_storage', and uses the internal VDI.copy to transfer it to the HBA LUN labelled as local-storage.

This functionality leaves everything else the same, unless there is a share with the scratchnfs_storage label.

To post a comment you must log in.
Revision history for this message
Christopher MacGown (0x44) wrote :

LGTM, but you need to add yourself to AUTHORS.

review: Needs Fixing
lp:~use/nova/shared-storage updated
1493. By USE Team

Added myself to Authors file

1494. By USE Team

Removed Infospace Copyright

Unmerged revisions

1494. By USE Team

Removed Infospace Copyright

1493. By USE Team

Added myself to Authors file

1492. By USE Team

Cleaned up variable names

1491. By USE Team

Provide option to load Windows VHD into a shared storage LUN for a XenServer cluster.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'Authors'
2--- Authors 2011-08-26 02:18:46 +0000
3+++ Authors 2011-08-29 15:11:24 +0000
4@@ -59,6 +59,7 @@
5 Joshua McKenty <jmckenty@gmail.com>
6 Justin Santa Barbara <justin@fathomdb.com>
7 Justin Shepherd <jshepher@rackspace.com>
8+Jeff Williams <use@infospace.com>
9 Kei Masumoto <masumotok@nttdata.co.jp>
10 masumoto<masumotok@nttdata.co.jp>
11 Ken Pepple <ken.pepple@gmail.com>
12
13=== modified file 'nova/virt/xenapi/vm_utils.py'
14--- nova/virt/xenapi/vm_utils.py 2011-08-23 05:17:51 +0000
15+++ nova/virt/xenapi/vm_utils.py 2011-08-29 15:11:24 +0000
16@@ -2,6 +2,7 @@
17
18 # Copyright (c) 2010 Citrix Systems, Inc.
19 # Copyright 2011 Piston Cloud Computing, Inc.
20+# Copyright (c) 2011 Infospace, Inc.
21 #
22 # Licensed under the Apache License, Version 2.0 (the "License"); you may
23 # not use this file except in compliance with the License. You may obtain
24@@ -372,6 +373,18 @@
25 return os.path.join(FLAGS.xenapi_sr_base_path, sr_uuid)
26
27 @classmethod
28+ def get_staging_path(cls, session):
29+ """Return the path to our storage repository
30+
31+ This is used when we're dealing with VHDs directly, either by taking
32+ snapshots or by restoring an image in the DISK_VHD format.
33+ """
34+ sr_ref = safe_find_scratchnfs_sr(session)
35+ sr_rec = session.get_xenapi().SR.get_record(sr_ref)
36+ sr_uuid = sr_rec["uuid"]
37+ return os.path.join(FLAGS.xenapi_sr_base_path, sr_uuid)
38+
39+ @classmethod
40 def upload_image(cls, context, session, instance, vdi_uuids, image_id):
41 """ Requests that the Glance plugin bundle the specified VDIs and
42 push them into Glance using the specified human-friendly name.
43@@ -454,6 +467,7 @@
44 'glance_port': glance_port,
45 'uuid_stack': uuid_stack,
46 'sr_path': cls.get_sr_path(session),
47+ 'staging_path': cls.get_staging_path(session),
48 'auth_token': getattr(context, 'auth_token', None)}
49
50 kwargs = {'params': pickle.dumps(params)}
51@@ -950,6 +964,34 @@
52 return None
53
54
55+def safe_find_scratchnfs_sr(session):
56+ """Same as find_sr except raises a NotFound exception if SR cannot be
57+ determined
58+ """
59+ sr_ref = find_scratchnfs_sr(session)
60+ if sr_ref is None:
61+ sr_ref = find_sr(session)
62+ if sr_ref is None:
63+ raise exception.StorageRepositoryNotFound()
64+ return sr_ref
65+
66+
67+def find_scratchnfs_sr(session):
68+ """Return the storage repository to hold VM images"""
69+ host = session.get_xenapi_host()
70+ sr_refs = session.get_xenapi().SR.get_all()
71+ for sr_ref in sr_refs:
72+ sr_rec = session.get_xenapi().SR.get_record(sr_ref)
73+ if not ('i18n-key' in sr_rec['other_config'] and
74+ sr_rec['other_config']['i18n-key'] == 'scratchnfs-storage'):
75+ continue
76+ for pbd_ref in sr_rec['PBDs']:
77+ pbd_rec = session.get_xenapi().PBD.get_record(pbd_ref)
78+ if pbd_rec['host'] == host:
79+ return sr_ref
80+ return None
81+
82+
83 def safe_find_iso_sr(session):
84 """Same as find_iso_sr except raises a NotFound exception if SR cannot be
85 determined
86
87=== modified file 'plugins/xenserver/xenapi/etc/xapi.d/plugins/glance'
88--- plugins/xenserver/xenapi/etc/xapi.d/plugins/glance 2011-08-05 00:12:19 +0000
89+++ plugins/xenserver/xenapi/etc/xapi.d/plugins/glance 2011-08-29 15:11:24 +0000
90@@ -3,6 +3,7 @@
91 # Copyright (c) 2010 Citrix Systems, Inc.
92 # Copyright 2010 United States Government as represented by the
93 # Administrator of the National Aeronautics and Space Administration.
94+# Copyright (c) 2011 Infospace, Inc.
95 # All Rights Reserved.
96 #
97 # Licensed under the Apache License, Version 2.0 (the "License"); you may
98@@ -96,7 +97,7 @@
99 conn.close()
100
101
102-def _import_vhds(sr_path, staging_path, uuid_stack):
103+def _import_vhds(session, sr_path, staging_sr_path, staging_path, uuid_stack):
104 """Import the VHDs found in the staging path.
105
106 We cannot extract VHDs directly into the SR since they don't yet have
107@@ -158,6 +159,35 @@
108 os.rename(orig_path, new_path)
109 return new_path
110
111+ def move_into_lvmsr(orig_path):
112+ """
113+ This will move a VHD from a local or NFS SR labeled with scratchnfs-storage to a shared
114+ HBA LUN, using the built in VDI.copy functionality.
115+ """
116+
117+ """ Move from our tar extraction tmp directory, into the SR root directory """
118+ vdi_file = os.path.basename(orig_path)
119+ vdi_uuid = os.path.splitext(vdi_file)[0]
120+ new_path = os.path.join(staging_sr_path, vdi_file)
121+ os.rename(orig_path, new_path)
122+
123+ """ Force rescan to find new VHD """
124+ vhd_sr_uuid = os.path.basename(staging_sr_path)
125+ sr_ref = session.xenapi.SR.get_by_uuid(vhd_sr_uuid)
126+ session.xenapi.SR.scan(sr_ref)
127+
128+ """ Convert VHD on scratchnfs to VDI on shared LUN """
129+ dest_sr_uuid = os.path.basename(sr_path)
130+ dest_sr_ref = session.xenapi.SR.get_by_uuid(dest_sr_uuid)
131+ src_vdi_ref = session.xenapi.VDI.get_by_uuid(vdi_uuid)
132+ dest_vdi_ref = session.xenapi.VDI.copy(src_vdi_ref, dest_sr_ref)
133+
134+ """ Cleanup """
135+ os.remove(new_path);
136+ session.xenapi.SR.scan(sr_ref)
137+
138+ return session.xenapi.VDI.get_uuid(dest_vdi_ref)
139+
140 def assert_vhd_not_hidden(path):
141 """
142 This is a sanity check on the image; if a snap.vhd isn't
143@@ -214,10 +244,12 @@
144 paths_to_move.append(snap_info[0])
145 # We return this snap as the VDI instead of image.vhd
146 vdi_return_list.append(dict(vdi_type="os", vdi_uuid=snap_info[1]))
147+
148 else:
149- assert_vhd_not_hidden(image_info[0])
150- # If there's no snap, we return the image.vhd UUID
151- vdi_return_list.append(dict(vdi_type="os", vdi_uuid=image_info[1]))
152+ if sr_path == staging_sr_path:
153+ assert_vhd_not_hidden(image_info[0])
154+ # If there's no snap, we return the image.vhd UUID
155+ vdi_return_list.append(dict(vdi_type="os", vdi_uuid=image_info[1]))
156
157 swap_info = prepare_if_exists(staging_path, 'swap.vhd')
158 if swap_info:
159@@ -226,7 +258,10 @@
160 vdi_return_list.append(dict(vdi_type="swap", vdi_uuid=swap_info[1]))
161
162 for path in paths_to_move:
163- move_into_sr(path)
164+ if sr_path != staging_sr_path:
165+ vdi_return_list.append(dict(vdi_type="os", vdi_uuid=move_into_lvmsr(path)))
166+ else:
167+ move_into_sr(path)
168
169 return vdi_return_list
170
171@@ -392,15 +427,20 @@
172 glance_port = params["glance_port"]
173 uuid_stack = params["uuid_stack"]
174 sr_path = params["sr_path"]
175+ staging_sr_path = params["staging_path"]
176 auth_token = params["auth_token"]
177
178- staging_path = _make_staging_area(sr_path)
179+ if staging_sr_path == sr_path:
180+ staging_path = _make_staging_area(sr_path)
181+ else:
182+ staging_path = _make_staging_area(staging_sr_path)
183+
184 try:
185 _download_tarball(sr_path, staging_path, image_id, glance_host,
186 glance_port, auth_token)
187 # Right now, it's easier to return a single string via XenAPI,
188 # so we'll json encode the list of VHDs.
189- return json.dumps(_import_vhds(sr_path, staging_path, uuid_stack))
190+ return json.dumps(_import_vhds(session, sr_path, staging_sr_path, staging_path, uuid_stack))
191 finally:
192 _cleanup_staging_area(staging_path)
193