~ubuntu-branches/ubuntu/maverick/eucalyptus/maverick

« back to all changes in this revision

Viewing changes to clc/modules/image-manager/src/main/java/edu/ucsb/eucalyptus/cloud/ws/VolumeManager.java

  • Committer: Bazaar Package Importer
  • Author(s): Dave Walker (Daviey)
  • Date: 2010-07-21 17:27:10 UTC
  • mfrom: (1.1.38 upstream)
  • Revision ID: james.westby@ubuntu.com-20100721172710-7xv07dmdqgivc3t9
Tags: 2.0~bzr1211-0ubuntu1
* New major upstream version merge, 2.0 (r1211).
* debian/patches/:
  - 01-wsdl-stubs.patch, debian/wsdl.md5sums: wsdl stubs updated.
  - 02-Makefile.patch: Updated to reflect new code layout.
  - 07-local_support_euca_conf-in.patch: Updated to reflect new code layout.
  - 08-ubuntu-default-networking.patch: Refreshed.
  - 09-small-128-192MB.patch: Updated to point to new location.
  - 10-disable-iscsi.patch: Refreshed.
  - 11-state-cleanup-memleakfix.patch: Removed, fixed upstream.
  - 15-fix-default-ramdisk.patch: Updated to point to new location.
  - 16-kvm_libvirt_xml_default_use_kvm.patch: Updated to reflect changes.
  - 17-fix_walrus_OOM_errors.patch: Removed, fixed upstream.
  - 18-priv_security.patch: Updated to reflect upstream changes.
  - 20-brute-force-webui.patch: Updated to reflect upstream changes. 
  - 21-eucalyptus-1.7-with-gwt-1.6.4.patch: New patch, allows 
    eucalyptus-1.7 to be built against gwt 1.6.4. Based on patch courtesy 
    of Dmitrii Zagorodnov, upstream. (LP: #597330)
* debian/eucalyptus-java-common.links: 
  - Changed symlink for groovy, point to groovy.all.jar, making compatiable 
    with groovy versions >1.7. (LP: #595421)
  - Added ant.jar & jetty-rewrite-handler.jar as they are now required.
* debian/control
  - & debian/build-jars: Added libjavassist-java and libjetty-extra-java as 
    build dependencies.
  - Added libjetty-extra-java as a dependency of eucalyptus-java-common
* The binary resulting jar's have been renamed from eucalyptus-*-1.6.2.jar
  to eucalyptus-*-main.jar:    
  - debian/eucalyptus-cc.upstart
  - debian/eucalyptus-cloud.install
  - debian/eucalyptus-common.eucalyptus.upstart
  - debian/eucalyptus-java-common.install
  - debian/eucalyptus-network.upstart
  - debian/eucalyptus-sc.install
  - debian/eucalyptus-walrus.install
* debian/eucalyptus-java-common.install: New upstream jars that have been
  installed:
  - eucalyptus-db-hsqldb-ext-main.jar
  - eucalyptus-component-main.jar
* debian/control:
  - Updated Standards Version to 3.8.4 (no change)
  - Updated the upstream Homepage to: http://open.eucalyptus.com/
  - Changed Vcs-Bzr to reflect new location of Ubuntu hosted development branch.
  - Made the Build Dependency of groovy and the binary eucalyptus-java-common
    package depend on version >=1.7.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/*******************************************************************************
2
 
*Copyright (c) 2009  Eucalyptus Systems, Inc.
3
 
4
 
*  This program is free software: you can redistribute it and/or modify
5
 
*  it under the terms of the GNU General Public License as published by
6
 
*  the Free Software Foundation, only version 3 of the License.
7
 
8
 
9
 
*  This file is distributed in the hope that it will be useful, but WITHOUT
10
 
*  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11
 
*  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
12
 
*  for more details.
13
 
14
 
*  You should have received a copy of the GNU General Public License along
15
 
*  with this program.  If not, see <http://www.gnu.org/licenses/>.
16
 
17
 
*  Please contact Eucalyptus Systems, Inc., 130 Castilian
18
 
*  Dr., Goleta, CA 93101 USA or visit <http://www.eucalyptus.com/licenses/>
19
 
*  if you need additional information or have any questions.
20
 
21
 
*  This file may incorporate work covered under the following copyright and
22
 
*  permission notice:
23
 
24
 
*    Software License Agreement (BSD License)
25
 
26
 
*    Copyright (c) 2008, Regents of the University of California
27
 
*    All rights reserved.
28
 
29
 
*    Redistribution and use of this software in source and binary forms, with
30
 
*    or without modification, are permitted provided that the following
31
 
*    conditions are met:
32
 
33
 
*      Redistributions of source code must retain the above copyright notice,
34
 
*      this list of conditions and the following disclaimer.
35
 
36
 
*      Redistributions in binary form must reproduce the above copyright
37
 
*      notice, this list of conditions and the following disclaimer in the
38
 
*      documentation and/or other materials provided with the distribution.
39
 
40
 
*    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
41
 
*    IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
42
 
*    TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
43
 
*    PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
44
 
*    OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
45
 
*    EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
46
 
*    PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
47
 
*    PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
48
 
*    LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
49
 
*    NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
50
 
*    SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. USERS OF
51
 
*    THIS SOFTWARE ACKNOWLEDGE THE POSSIBLE PRESENCE OF OTHER OPEN SOURCE
52
 
*    LICENSED MATERIAL, COPYRIGHTED MATERIAL OR PATENTED MATERIAL IN THIS
53
 
*    SOFTWARE, AND IF ANY SUCH MATERIAL IS DISCOVERED THE PARTY DISCOVERING
54
 
*    IT MAY INFORM DR. RICH WOLSKI AT THE UNIVERSITY OF CALIFORNIA, SANTA
55
 
*    BARBARA WHO WILL THEN ASCERTAIN THE MOST APPROPRIATE REMEDY, WHICH IN
56
 
*    THE REGENTS’ DISCRETION MAY INCLUDE, WITHOUT LIMITATION, REPLACEMENT
57
 
*    OF THE CODE SO IDENTIFIED, LICENSING OF THE CODE SO IDENTIFIED, OR
58
 
*    WITHDRAWAL OF THE CODE CAPABILITY TO THE EXTENT NEEDED TO COMPLY WITH
59
 
*    ANY SUCH LICENSES OR RIGHTS.
60
 
*******************************************************************************/
61
 
/*
62
 
 *
63
 
 * Author: chris grzegorczyk <grze@eucalyptus.com>
64
 
 */
65
 
 
66
 
package edu.ucsb.eucalyptus.cloud.ws;
67
 
 
68
 
import java.util.HashMap;
69
 
import java.util.List;
70
 
import java.util.Map;
71
 
import java.util.NoSuchElementException;
72
 
 
73
 
import org.apache.log4j.Logger;
74
 
 
75
 
import com.eucalyptus.auth.util.Hashes;
76
 
import com.eucalyptus.cluster.Cluster;
77
 
import com.eucalyptus.cluster.Clusters;
78
 
import com.eucalyptus.config.Configuration;
79
 
import com.eucalyptus.config.StorageControllerConfiguration;
80
 
import com.eucalyptus.images.util.StorageUtil;
81
 
import com.eucalyptus.util.EntityWrapper;
82
 
import com.eucalyptus.util.EucalyptusCloudException;
83
 
 
84
 
import edu.ucsb.eucalyptus.cloud.cluster.QueuedEvent;
85
 
import edu.ucsb.eucalyptus.cloud.cluster.VmInstance;
86
 
import edu.ucsb.eucalyptus.cloud.cluster.VmInstances;
87
 
import edu.ucsb.eucalyptus.cloud.cluster.VolumeAttachCallback;
88
 
import edu.ucsb.eucalyptus.cloud.cluster.VolumeDetachCallback;
89
 
import edu.ucsb.eucalyptus.cloud.state.Snapshot;
90
 
import edu.ucsb.eucalyptus.cloud.state.State;
91
 
import edu.ucsb.eucalyptus.cloud.state.Volume;
92
 
import edu.ucsb.eucalyptus.msgs.AttachVolumeResponseType;
93
 
import edu.ucsb.eucalyptus.msgs.AttachVolumeType;
94
 
import edu.ucsb.eucalyptus.msgs.AttachedVolume;
95
 
import edu.ucsb.eucalyptus.msgs.CreateStorageVolumeResponseType;
96
 
import edu.ucsb.eucalyptus.msgs.CreateStorageVolumeType;
97
 
import edu.ucsb.eucalyptus.msgs.CreateVolumeResponseType;
98
 
import edu.ucsb.eucalyptus.msgs.CreateVolumeType;
99
 
import edu.ucsb.eucalyptus.msgs.DeleteStorageVolumeType;
100
 
import edu.ucsb.eucalyptus.msgs.DeleteVolumeResponseType;
101
 
import edu.ucsb.eucalyptus.msgs.DeleteVolumeType;
102
 
import edu.ucsb.eucalyptus.msgs.DescribeVolumesResponseType;
103
 
import edu.ucsb.eucalyptus.msgs.DescribeVolumesType;
104
 
import edu.ucsb.eucalyptus.msgs.DetachVolumeResponseType;
105
 
import edu.ucsb.eucalyptus.msgs.DetachVolumeType;
106
 
 
107
 
public class VolumeManager {
108
 
  static String PERSISTENCE_CONTEXT = "eucalyptus_images";
109
 
 
110
 
  private static String ID_PREFIX = "vol";
111
 
  private static Logger LOG = Logger.getLogger( VolumeManager.class );
112
 
 
113
 
  public static EntityWrapper<Volume> getEntityWrapper() {
114
 
    return new EntityWrapper<Volume>( PERSISTENCE_CONTEXT );
115
 
  }
116
 
 
117
 
  public CreateVolumeResponseType CreateVolume( CreateVolumeType request ) throws EucalyptusCloudException {
118
 
    if( ( request.getSnapshotId() == null && request.getSize() == null ) ) {
119
 
      throw new EucalyptusCloudException( "One of size or snapshotId is required as a parameter." );
120
 
    }
121
 
    try {
122
 
      Configuration.getClusterConfiguration( request.getAvailabilityZone( ) );
123
 
    } catch ( Exception e ) {
124
 
      throw new EucalyptusCloudException( "Zone does not exist: " + request.getAvailabilityZone(), e );
125
 
    }
126
 
    StorageControllerConfiguration sc;
127
 
    try {
128
 
      sc = Configuration.getStorageControllerConfiguration( request.getAvailabilityZone( ) );
129
 
    } catch ( Exception e ) {
130
 
      throw new EucalyptusCloudException("Storage services are not available for the requested availability zone.", e );
131
 
    }
132
 
    EntityWrapper<Volume> db = VolumeManager.getEntityWrapper();
133
 
    if ( request.getSnapshotId() != null ) {
134
 
      String userName = request.isAdministrator() ? null : request.getUserId();
135
 
      try {
136
 
        db.recast( Snapshot.class ).getUnique( Snapshot.named( userName, request.getSnapshotId() ) );
137
 
      } catch ( EucalyptusCloudException e ) {
138
 
        LOG.debug( e, e );
139
 
        db.rollback();
140
 
        throw new EucalyptusCloudException( "Snapshot does not exist: " + request.getSnapshotId() );
141
 
      }
142
 
    }    
143
 
    String newId = null;
144
 
    Volume newVol = null;
145
 
    while ( true ) {
146
 
      newId = Hashes.generateId( request.getUserId(), ID_PREFIX );
147
 
      try {
148
 
        db.getUnique( Volume.named( null, newId ) );
149
 
      } catch ( EucalyptusCloudException e ) {
150
 
        try {
151
 
          newVol = new Volume( request.getUserId(), newId, new Integer( request.getSize() != null ? request.getSize() : "-1" ),
152
 
                               request.getAvailabilityZone(), request.getSnapshotId() );
153
 
          db.add( newVol );
154
 
          db.commit();
155
 
          break;
156
 
        } catch ( Throwable e1 ) {
157
 
          db.rollback( );
158
 
          db = VolumeManager.getEntityWrapper();
159
 
        }
160
 
      }
161
 
    }
162
 
    newVol.setState( State.GENERATING );
163
 
    try {
164
 
      CreateStorageVolumeType req = new CreateStorageVolumeType( newId, request.getSize( ), request.getSnapshotId( ) );
165
 
      req.setUserId( request.getUserId( ) );
166
 
      req.setEffectiveUserId( request.getEffectiveUserId( ) );
167
 
      StorageUtil.lookup( sc.getHostName( ) ).send( req, CreateStorageVolumeResponseType.class );
168
 
    } catch ( EucalyptusCloudException e ) {
169
 
      LOG.debug( e, e );
170
 
      try {
171
 
        db = VolumeManager.getEntityWrapper();
172
 
        Volume d = db.getUnique( Volume.named( newVol.getUserName( ), newVol.getDisplayName( ) ) );
173
 
        db.delete( d );
174
 
        db.commit( );
175
 
      } catch ( Throwable e1 ) {
176
 
        db.rollback( );
177
 
        LOG.debug( e1, e1 );
178
 
      }
179
 
      throw new EucalyptusCloudException( "Error while communicating with Storage Controller: CreateStorageVolume:" + e.getMessage() );
180
 
    }
181
 
    CreateVolumeResponseType reply = ( CreateVolumeResponseType ) request.getReply();
182
 
    reply.setVolume( newVol.morph( new edu.ucsb.eucalyptus.msgs.Volume() ) );
183
 
    return reply;
184
 
  }
185
 
 
186
 
  public DeleteVolumeResponseType DeleteVolume( DeleteVolumeType request ) throws EucalyptusCloudException {
187
 
    DeleteVolumeResponseType reply = ( DeleteVolumeResponseType ) request.getReply();
188
 
    reply.set_return( false );
189
 
 
190
 
    EntityWrapper<Volume> db = VolumeManager.getEntityWrapper();
191
 
    String userName = request.isAdministrator() ? null : request.getUserId();
192
 
    try {
193
 
      Volume vol = db.getUnique( Volume.named( userName, request.getVolumeId() ) );
194
 
      for( VmInstance vm : VmInstances.getInstance().listValues() ) {
195
 
        for( AttachedVolume attachedVol : vm.getVolumes() ) {
196
 
          if( request.getVolumeId().equals( attachedVol.getVolumeId() ) ) {
197
 
            db.rollback( );
198
 
            return reply;
199
 
          }
200
 
        }
201
 
      }
202
 
      db.delete( vol );
203
 
      db.getSession( ).flush( );
204
 
      if( !vol.getState(  ).equals( State.ANNILATED ) ) {
205
 
        StorageUtil.dispatchAll( new DeleteStorageVolumeType( vol.getDisplayName() ) );
206
 
      }
207
 
      db.commit();
208
 
    } catch ( EucalyptusCloudException e ) {
209
 
      LOG.debug( e, e );
210
 
      db.rollback();
211
 
      return reply;
212
 
    }
213
 
    reply.set_return( true );
214
 
    return reply;
215
 
  }
216
 
 
217
 
  public DescribeVolumesResponseType DescribeVolumes( DescribeVolumesType request ) throws EucalyptusCloudException {
218
 
    DescribeVolumesResponseType reply = ( DescribeVolumesResponseType ) request.getReply();
219
 
    EntityWrapper<Volume> db = getEntityWrapper();
220
 
    try {
221
 
      String userName = request.isAdministrator() ? null : request.getUserId();
222
 
 
223
 
      Map<String, AttachedVolume> attachedVolumes = new HashMap<String, AttachedVolume>();
224
 
      for ( VmInstance vm : VmInstances.getInstance().listValues() ) {
225
 
        for ( AttachedVolume av : vm.getVolumes() ) {
226
 
          attachedVolumes.put( av.getVolumeId(), av );
227
 
        }
228
 
      }
229
 
      
230
 
      List<Volume> volumes = db.query( Volume.ownedBy( userName ) );
231
 
 
232
 
      for ( Volume v : volumes ) {
233
 
        if ( request.getVolumeSet().isEmpty() || request.getVolumeSet().contains( v.getDisplayName() ) ) {
234
 
          try {
235
 
            edu.ucsb.eucalyptus.msgs.Volume aVolume = StorageUtil.getVolumeReply( attachedVolumes, v );
236
 
            reply.getVolumeSet().add( aVolume );
237
 
          } catch ( Exception e ) {
238
 
            LOG.warn( "Error getting volume information from the Storage Controller: " + e );
239
 
            LOG.debug( e, e );
240
 
          }
241
 
        }
242
 
      }
243
 
      db.commit( );
244
 
    } catch (Throwable t ) {
245
 
      db.commit();
246
 
    }
247
 
    return reply;
248
 
  }
249
 
 
250
 
  public AttachVolumeResponseType AttachVolume( AttachVolumeType request ) throws EucalyptusCloudException {
251
 
    AttachVolumeResponseType reply = ( AttachVolumeResponseType ) request.getReply();
252
 
 
253
 
    if( request.getDevice( ) == null || request.getDevice().endsWith( "sda" ) ) {
254
 
      throw new EucalyptusCloudException( "Invalid device name specified: " + request.getDevice( ) );
255
 
    }
256
 
    VmInstance vm = null;
257
 
    try {
258
 
      vm = VmInstances.getInstance().lookup( request.getInstanceId() );
259
 
    } catch ( NoSuchElementException e ) {
260
 
      LOG.debug( e, e );
261
 
      throw new EucalyptusCloudException( "Instance does not exist: " + request.getInstanceId() );
262
 
    }
263
 
    for( AttachedVolume attachedVol : vm.getVolumes() ) {
264
 
      if( attachedVol.getDevice().replaceAll("unknown,requested:","").equals( request.getDevice() ) ) {
265
 
        throw new EucalyptusCloudException( "Already have a device attached to: " + request.getDevice() );
266
 
      }
267
 
    }
268
 
    Cluster cluster = null;
269
 
    try {
270
 
      cluster = Clusters.getInstance().lookup( vm.getPlacement() );
271
 
    } catch ( NoSuchElementException e ) {
272
 
      LOG.debug( e, e );
273
 
      throw new EucalyptusCloudException( "Cluster does not exist: " + vm.getPlacement() );
274
 
    }
275
 
 
276
 
    for ( VmInstance v : VmInstances.getInstance().listValues() ) {
277
 
      for ( AttachedVolume vol : v.getVolumes() ) {
278
 
        if ( vol.getVolumeId().equals( request.getVolumeId() ) ) {
279
 
          throw new EucalyptusCloudException( "Volume already attached: " + request.getVolumeId() );
280
 
        }
281
 
      }
282
 
    }
283
 
 
284
 
    EntityWrapper<Volume> db = VolumeManager.getEntityWrapper();
285
 
    String userName = request.isAdministrator() ? null : request.getUserId();
286
 
    Volume volume = null;
287
 
    try {
288
 
      volume = db.getUnique( Volume.named( userName, request.getVolumeId() ) );
289
 
      db.commit();
290
 
    } catch ( EucalyptusCloudException e ) {
291
 
      LOG.debug( e, e );
292
 
      db.rollback();
293
 
      throw new EucalyptusCloudException( "Volume does not exist: " + request.getVolumeId() );
294
 
    }
295
 
 
296
 
    if(!volume.getCluster().equals(cluster.getName())) {
297
 
        throw new EucalyptusCloudException("Can only attach volumes in the same cluster: " + request.getVolumeId());
298
 
    } else if("invalid".equals(volume.getRemoteDevice())) {
299
 
      throw new EucalyptusCloudException("Volume is not yet available: " + request.getVolumeId());
300
 
    }
301
 
    request.setRemoteDevice( volume.getRemoteDevice() );
302
 
    QueuedEvent<AttachVolumeType> event = QueuedEvent.make( new VolumeAttachCallback(  ), request );
303
 
    cluster.getMessageQueue().enqueue( event );
304
 
 
305
 
    AttachedVolume attachVol = new AttachedVolume( volume.getDisplayName(), vm.getInstanceId(), request.getDevice(), volume.getRemoteDevice() );
306
 
    vm.getVolumes().add( attachVol );
307
 
    volume.setState( State.BUSY );
308
 
    reply.setAttachedVolume( attachVol );
309
 
    return reply;
310
 
  }
311
 
 
312
 
  public DetachVolumeResponseType detach( DetachVolumeType request ) throws EucalyptusCloudException {
313
 
    DetachVolumeResponseType reply = ( DetachVolumeResponseType ) request.getReply();
314
 
 
315
 
    EntityWrapper<Volume> db = VolumeManager.getEntityWrapper();
316
 
    String userName = request.isAdministrator() ? null : request.getUserId();
317
 
    try {
318
 
      db.getUnique( Volume.named( userName, request.getVolumeId() ) );
319
 
    } catch ( EucalyptusCloudException e ) {
320
 
      LOG.debug( e, e );
321
 
      db.rollback();
322
 
      throw new EucalyptusCloudException( "Volume does not exist: " + request.getVolumeId() );
323
 
    }
324
 
    db.commit();
325
 
 
326
 
    VmInstance vm = null;
327
 
    AttachedVolume volume = null;
328
 
    for ( VmInstance v : VmInstances.getInstance().listValues() ) {
329
 
      for ( AttachedVolume vol : v.getVolumes() ) {
330
 
        if ( vol.getVolumeId().equals( request.getVolumeId() ) ) {
331
 
          volume = vol;
332
 
          vm = v;
333
 
        }
334
 
      }
335
 
    }
336
 
    if ( volume == null) {
337
 
      throw new EucalyptusCloudException( "Volume is not attached: " + request.getVolumeId() );
338
 
    }
339
 
    if( !vm.getInstanceId().equals( request.getInstanceId() ) && request.getInstanceId() != null && !request.getInstanceId().equals("" ) ) {
340
 
      throw new EucalyptusCloudException( "Volume is not attached to instance: " + request.getInstanceId() );
341
 
    }
342
 
    if ( request.getDevice() != null && !request.getDevice().equals("") && !volume.getDevice().equals( request.getDevice() ) ) {
343
 
      throw new EucalyptusCloudException( "Volume is not attached to device: " + request.getDevice() );
344
 
    }
345
 
 
346
 
    Cluster cluster = null;
347
 
    try {
348
 
      cluster = Clusters.getInstance().lookup( vm.getPlacement() );
349
 
    } catch ( NoSuchElementException e ) {
350
 
      LOG.debug( e, e );
351
 
      throw new EucalyptusCloudException( "Cluster does not exist: " + vm.getPlacement() );
352
 
    }
353
 
 
354
 
    request.setVolumeId( volume.getVolumeId() );
355
 
    request.setRemoteDevice( volume.getRemoteDevice() );
356
 
    request.setDevice( volume.getDevice().replaceAll("unknown,requested:","") );
357
 
    request.setInstanceId( vm.getInstanceId() );
358
 
    QueuedEvent<DetachVolumeType> event = QueuedEvent.make( new VolumeDetachCallback( ), request );
359
 
    cluster.getMessageQueue().enqueue( event );
360
 
 
361
 
    reply.setDetachedVolume( volume );
362
 
    return reply;
363
 
  }
364
 
 
365
 
}
366