~ubuntu-branches/ubuntu/natty/nova/natty

« back to all changes in this revision

Viewing changes to plugins/xenserver/xenapi/etc/xapi.d/plugins/objectstore

  • Committer: Bazaar Package Importer
  • Author(s): Chuck Short, Chuck Short, Soren Hansen, Thierry Carrez
  • Date: 2011-02-18 09:36:22 UTC
  • mfrom: (1.1.9 upstream)
  • Revision ID: james.westby@ubuntu.com-20110218093622-w13dzywbd7vq2qh7
Tags: 2011.2~bzr700-0ubuntu1
[ Chuck Short ]
* New upstream version.

[ Soren Hansen ]
* Rely on --logdir to find and use the correct logfile.
* Remove the postrotate magic for all but nova-objectstore. It is not
  needed anymore due to using RotatingFileHandler for logging.

[ Thierry Carrez ]
* Ship adminclient in a separate package.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
#!/usr/bin/env python
 
2
 
 
3
# Copyright (c) 2010 Citrix Systems, Inc.
 
4
# Copyright 2010 United States Government as represented by the
 
5
# Administrator of the National Aeronautics and Space Administration.
 
6
# All Rights Reserved.
 
7
#
 
8
#    Licensed under the Apache License, Version 2.0 (the "License"); you may
 
9
#    not use this file except in compliance with the License. You may obtain
 
10
#    a copy of the License at
 
11
#
 
12
#         http://www.apache.org/licenses/LICENSE-2.0
 
13
#
 
14
#    Unless required by applicable law or agreed to in writing, software
 
15
#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 
16
#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 
17
#    License for the specific language governing permissions and limitations
 
18
#    under the License.
 
19
 
 
20
#
 
21
# XenAPI plugin for fetching images from nova-objectstore.
 
22
#
 
23
 
 
24
import base64
 
25
import errno
 
26
import hmac
 
27
import os
 
28
import os.path
 
29
import sha
 
30
import time
 
31
import urlparse
 
32
 
 
33
import XenAPIPlugin
 
34
 
 
35
from pluginlib_nova import *
 
36
configure_logging('objectstore')
 
37
 
 
38
 
 
39
KERNEL_DIR = '/boot/guest'
 
40
 
 
41
DOWNLOAD_CHUNK_SIZE = 2 * 1024 * 1024
 
42
SECTOR_SIZE = 512
 
43
MBR_SIZE_SECTORS = 63
 
44
MBR_SIZE_BYTES = MBR_SIZE_SECTORS * SECTOR_SIZE
 
45
 
 
46
 
 
47
def is_vdi_pv(session, args):
 
48
    logging.debug("Checking wheter VDI has PV kernel")
 
49
    vdi = exists(args, 'vdi-ref')
 
50
    pv = with_vdi_in_dom0(session, vdi, False,
 
51
                     lambda dev: _is_vdi_pv('/dev/%s' % dev))
 
52
    if pv:
 
53
        return 'true'
 
54
    else:
 
55
        return 'false'
 
56
 
 
57
 
 
58
def _is_vdi_pv(dest):
 
59
    logging.debug("Running pygrub against %s", dest)
 
60
    output = os.popen('pygrub -qn %s' % dest)
 
61
    pv = False
 
62
    for line in output.readlines():
 
63
        #try to find kernel string
 
64
        m = re.search('(?<=kernel:)/.*(?:>)', line)
 
65
        if m:
 
66
            if m.group(0).find('xen') != -1:
 
67
                pv = True
 
68
    logging.debug("PV:%d", pv)
 
69
    return pv
 
70
 
 
71
 
 
72
def get_vdi(session, args):
 
73
    src_url = exists(args, 'src_url')
 
74
    username = exists(args, 'username')
 
75
    password = exists(args, 'password')
 
76
    raw_image = validate_bool(args, 'raw', 'false')
 
77
    add_partition = validate_bool(args, 'add_partition', 'false')
 
78
    (proto, netloc, url_path, _, _, _) = urlparse.urlparse(src_url)
 
79
    sr = find_sr(session)
 
80
    if sr is None:
 
81
        raise Exception('Cannot find SR to write VDI to')
 
82
    virtual_size = \
 
83
        get_content_length(proto, netloc, url_path, username, password)
 
84
    if virtual_size < 0:
 
85
        raise Exception('Cannot get VDI size')
 
86
    vdi_size = virtual_size
 
87
    if add_partition:
 
88
        # Make room for MBR.
 
89
        vdi_size += MBR_SIZE_BYTES
 
90
 
 
91
    vdi = create_vdi(session, sr, src_url, vdi_size, False)
 
92
    with_vdi_in_dom0(session, vdi, False,
 
93
                     lambda dev: get_vdi_(proto, netloc, url_path,
 
94
                                          username, password,
 
95
                                          add_partition, raw_image,
 
96
                                          virtual_size, '/dev/%s' % dev))
 
97
    return session.xenapi.VDI.get_uuid(vdi)
 
98
 
 
99
 
 
100
def get_vdi_(proto, netloc, url_path, username, password,
 
101
             add_partition, raw_image, virtual_size, dest):
 
102
 
 
103
    #vdi should not be partitioned for raw images
 
104
    if add_partition and not raw_image:
 
105
        write_partition(virtual_size, dest)
 
106
 
 
107
    offset = (add_partition and not raw_image and MBR_SIZE_BYTES) or 0
 
108
    get(proto, netloc, url_path, username, password, dest, offset)
 
109
 
 
110
 
 
111
def write_partition(virtual_size, dest):
 
112
    mbr_last = MBR_SIZE_SECTORS - 1
 
113
    primary_first = MBR_SIZE_SECTORS
 
114
    primary_last = MBR_SIZE_SECTORS + (virtual_size / SECTOR_SIZE) - 1
 
115
 
 
116
    logging.debug('Writing partition table %d %d to %s...',
 
117
                  primary_first, primary_last, dest)
 
118
 
 
119
    result = os.system('parted --script %s mklabel msdos' % dest)
 
120
    if result != 0:
 
121
        raise Exception('Failed to mklabel')
 
122
    result = os.system('parted --script %s mkpart primary %ds %ds' %
 
123
                       (dest, primary_first, primary_last))
 
124
    if result != 0:
 
125
        raise Exception('Failed to mkpart')
 
126
 
 
127
    logging.debug('Writing partition table %s done.', dest)
 
128
 
 
129
 
 
130
def find_sr(session):
 
131
    host = get_this_host(session)
 
132
    srs = session.xenapi.SR.get_all()
 
133
    for sr in srs:
 
134
        sr_rec = session.xenapi.SR.get_record(sr)
 
135
        if not ('i18n-key' in sr_rec['other_config'] and
 
136
                sr_rec['other_config']['i18n-key'] == 'local-storage'):
 
137
            continue
 
138
        for pbd in sr_rec['PBDs']:
 
139
            pbd_rec = session.xenapi.PBD.get_record(pbd)
 
140
            if pbd_rec['host'] == host:
 
141
                return sr
 
142
    return None
 
143
 
 
144
 
 
145
def get_kernel(session, args):
 
146
    src_url = exists(args, 'src_url')
 
147
    username = exists(args, 'username')
 
148
    password = exists(args, 'password')
 
149
 
 
150
    (proto, netloc, url_path, _, _, _) = urlparse.urlparse(src_url)
 
151
 
 
152
    dest = os.path.join(KERNEL_DIR, url_path[1:])
 
153
 
 
154
    # Paranoid check against people using ../ to do rude things.
 
155
    if os.path.commonprefix([KERNEL_DIR, dest]) != KERNEL_DIR:
 
156
        raise Exception('Illegal destination %s %s', (url_path, dest))
 
157
 
 
158
    dirname = os.path.dirname(dest)
 
159
    try:
 
160
        os.makedirs(dirname)
 
161
    except os.error, e:
 
162
        if e.errno != errno.EEXIST:
 
163
            raise
 
164
        if not os.path.isdir(dirname):
 
165
            raise Exception('Cannot make directory %s', dirname)
 
166
 
 
167
    try:
 
168
        os.remove(dest)
 
169
    except:
 
170
        pass
 
171
 
 
172
    get(proto, netloc, url_path, username, password, dest, 0)
 
173
 
 
174
    return dest
 
175
 
 
176
 
 
177
def get_content_length(proto, netloc, url_path, username, password):
 
178
    headers = make_headers('HEAD', url_path, username, password)
 
179
    return with_http_connection(
 
180
        proto, netloc,
 
181
        lambda conn: get_content_length_(url_path, headers, conn))
 
182
 
 
183
 
 
184
def get_content_length_(url_path, headers, conn):
 
185
    conn.request('HEAD', url_path, None, headers)
 
186
    response = conn.getresponse()
 
187
    if response.status != 200:
 
188
        raise Exception('%d %s' % (response.status, response.reason))
 
189
 
 
190
    return long(response.getheader('Content-Length', -1))
 
191
 
 
192
 
 
193
def get(proto, netloc, url_path, username, password, dest, offset):
 
194
    headers = make_headers('GET', url_path, username, password)
 
195
    download(proto, netloc, url_path, headers, dest, offset)
 
196
 
 
197
 
 
198
def make_headers(verb, url_path, username, password):
 
199
    headers = {}
 
200
    headers['Date'] = \
 
201
        time.strftime("%a, %d %b %Y %H:%M:%S GMT", time.gmtime())
 
202
    headers['Authorization'] = \
 
203
        'AWS %s:%s' % (username,
 
204
                       s3_authorization(verb, url_path, password, headers))
 
205
    return headers
 
206
 
 
207
 
 
208
def s3_authorization(verb, path, password, headers):
 
209
    sha1 = hmac.new(password, digestmod=sha)
 
210
    sha1.update(plaintext(verb, path, headers))
 
211
    return base64.encodestring(sha1.digest()).strip()
 
212
 
 
213
 
 
214
def plaintext(verb, path, headers):
 
215
    return '%s\n\n\n%s\n%s' % (verb,
 
216
                           "\n".join([headers[h] for h in headers]),
 
217
                           path)
 
218
 
 
219
 
 
220
def download(proto, netloc, url_path, headers, dest, offset):
 
221
    with_http_connection(
 
222
        proto, netloc,
 
223
        lambda conn: download_(url_path, dest, offset, headers, conn))
 
224
 
 
225
 
 
226
def download_(url_path, dest, offset, headers, conn):
 
227
    conn.request('GET', url_path, None, headers)
 
228
    response = conn.getresponse()
 
229
    if response.status != 200:
 
230
        raise Exception('%d %s' % (response.status, response.reason))
 
231
 
 
232
    length = response.getheader('Content-Length', -1)
 
233
 
 
234
    with_file(
 
235
        dest, 'a',
 
236
        lambda dest_file: download_all(response, length, dest_file, offset))
 
237
 
 
238
 
 
239
def download_all(response, length, dest_file, offset):
 
240
    dest_file.seek(offset)
 
241
    i = 0
 
242
    while True:
 
243
        buf = response.read(DOWNLOAD_CHUNK_SIZE)
 
244
        if buf:
 
245
            dest_file.write(buf)
 
246
        else:
 
247
            return
 
248
        i += len(buf)
 
249
        if length != -1 and i >= length:
 
250
            return
 
251
 
 
252
 
 
253
if __name__ == '__main__':
 
254
    XenAPIPlugin.dispatch({'get_vdi': get_vdi,
 
255
                           'get_kernel': get_kernel,
 
256
                           'is_vdi_pv': is_vdi_pv})