mirror of
				https://github.com/apache/cloudstack.git
				synced 2025-11-04 00:02:37 +01:00 
			
		
		
		
	Summary: adding resizeVolume api call
Detail: This merges the resizevolume feature branch, which provides the ability to migrate a disk between disk offerings, thereby changing its size, or specifying a new size if current disk offering is custom. BUG-ID: CLOUDSTACK-644 Signed-off-by: Marcus Sorensen <marcus@betterservers.com> 1358358209 -0700
This commit is contained in:
		
							parent
							
								
									a22bfd7e7b
								
							
						
					
					
						commit
						975021dda1
					
				
							
								
								
									
										40
									
								
								api/src/com/cloud/agent/api/storage/ResizeVolumeAnswer.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										40
									
								
								api/src/com/cloud/agent/api/storage/ResizeVolumeAnswer.java
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,40 @@
 | 
				
			|||||||
 | 
					// Licensed to the Apache Software Foundation (ASF) under one
 | 
				
			||||||
 | 
					// or more contributor license agreements.  See the NOTICE file
 | 
				
			||||||
 | 
					// distributed with this work for additional information
 | 
				
			||||||
 | 
					// regarding copyright ownership.  The ASF licenses this file
 | 
				
			||||||
 | 
					// to you 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.
 | 
				
			||||||
 | 
					package com.cloud.agent.api.storage;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import com.cloud.agent.api.Answer;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					public class ResizeVolumeAnswer extends Answer {
 | 
				
			||||||
 | 
					    private long newSize;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    protected ResizeVolumeAnswer() {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public ResizeVolumeAnswer(ResizeVolumeCommand cmd, boolean result, String details, long newSize) {
 | 
				
			||||||
 | 
					        super(cmd, result, details);
 | 
				
			||||||
 | 
					        this.newSize = newSize;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public ResizeVolumeAnswer(ResizeVolumeCommand cmd, boolean result, String details) {
 | 
				
			||||||
 | 
					        super(cmd, result, details);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public long getNewSize() {
 | 
				
			||||||
 | 
					        return newSize;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										86
									
								
								api/src/com/cloud/agent/api/storage/ResizeVolumeCommand.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										86
									
								
								api/src/com/cloud/agent/api/storage/ResizeVolumeCommand.java
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,86 @@
 | 
				
			|||||||
 | 
					// Licensed to the Apache Software Foundation (ASF) under one
 | 
				
			||||||
 | 
					// or more contributor license agreements.  See the NOTICE file
 | 
				
			||||||
 | 
					// distributed with this work for additional information
 | 
				
			||||||
 | 
					// regarding copyright ownership.  The ASF licenses this file
 | 
				
			||||||
 | 
					// to you 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.
 | 
				
			||||||
 | 
					package com.cloud.agent.api.storage;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import com.cloud.agent.api.Command;
 | 
				
			||||||
 | 
					import com.cloud.agent.api.to.StorageFilerTO;
 | 
				
			||||||
 | 
					import com.cloud.storage.StoragePool;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					public class ResizeVolumeCommand extends Command {
 | 
				
			||||||
 | 
					    private String path;
 | 
				
			||||||
 | 
					    private StorageFilerTO pool;
 | 
				
			||||||
 | 
					    private String vmInstance;
 | 
				
			||||||
 | 
					    private Long newSize;
 | 
				
			||||||
 | 
					    private Long currentSize;
 | 
				
			||||||
 | 
					    private boolean shrinkOk;
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    protected ResizeVolumeCommand() {
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    public ResizeVolumeCommand(String path,
 | 
				
			||||||
 | 
					                           StorageFilerTO pool,
 | 
				
			||||||
 | 
					                           Long currentSize,
 | 
				
			||||||
 | 
					                           Long newSize,
 | 
				
			||||||
 | 
					                           boolean shrinkOk,
 | 
				
			||||||
 | 
					                           String vmInstance) 
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        this.path = path;
 | 
				
			||||||
 | 
					        this.pool = pool;
 | 
				
			||||||
 | 
					        this.vmInstance = vmInstance;
 | 
				
			||||||
 | 
					        this.currentSize = currentSize;
 | 
				
			||||||
 | 
					        this.newSize = newSize;
 | 
				
			||||||
 | 
					        this.shrinkOk = shrinkOk;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public String getPath() {
 | 
				
			||||||
 | 
					    	return path;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public String getPoolUuid() {
 | 
				
			||||||
 | 
					        return pool.getUuid();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public StorageFilerTO getPool() {
 | 
				
			||||||
 | 
					        return pool;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    public long getNewSize() {
 | 
				
			||||||
 | 
					        return newSize;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public long getCurrentSize() {
 | 
				
			||||||
 | 
					        return currentSize;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public boolean getShrinkOk() {
 | 
				
			||||||
 | 
					        return shrinkOk;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public String getInstanceName() {
 | 
				
			||||||
 | 
					        return vmInstance;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * {@inheritDoc}
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    @Override
 | 
				
			||||||
 | 
					    public boolean executeInSequence() {
 | 
				
			||||||
 | 
					        return false;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@ -108,6 +108,7 @@ public class EventTypes {
 | 
				
			|||||||
    public static final String EVENT_VOLUME_EXTRACT = "VOLUME.EXTRACT";
 | 
					    public static final String EVENT_VOLUME_EXTRACT = "VOLUME.EXTRACT";
 | 
				
			||||||
    public static final String EVENT_VOLUME_UPLOAD = "VOLUME.UPLOAD";
 | 
					    public static final String EVENT_VOLUME_UPLOAD = "VOLUME.UPLOAD";
 | 
				
			||||||
    public static final String EVENT_VOLUME_MIGRATE = "VOLUME.MIGRATE";
 | 
					    public static final String EVENT_VOLUME_MIGRATE = "VOLUME.MIGRATE";
 | 
				
			||||||
 | 
					    public static final String EVENT_VOLUME_RESIZE = "VOLUME.RESIZE";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // Domains
 | 
					    // Domains
 | 
				
			||||||
    public static final String EVENT_DOMAIN_CREATE = "DOMAIN.CREATE";
 | 
					    public static final String EVENT_DOMAIN_CREATE = "DOMAIN.CREATE";
 | 
				
			||||||
 | 
				
			|||||||
@ -54,7 +54,6 @@ public class CloudException extends Exception {
 | 
				
			|||||||
		return;
 | 
							return;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 | 
				
			||||||
	public ArrayList<String> getIdProxyList() {
 | 
						public ArrayList<String> getIdProxyList() {
 | 
				
			||||||
		return idList;
 | 
							return idList;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
				
			|||||||
@ -23,6 +23,7 @@ import org.apache.cloudstack.api.command.admin.storage.CancelPrimaryStorageMaint
 | 
				
			|||||||
import org.apache.cloudstack.api.command.admin.storage.UpdateStoragePoolCmd;
 | 
					import org.apache.cloudstack.api.command.admin.storage.UpdateStoragePoolCmd;
 | 
				
			||||||
import org.apache.cloudstack.api.command.user.volume.CreateVolumeCmd;
 | 
					import org.apache.cloudstack.api.command.user.volume.CreateVolumeCmd;
 | 
				
			||||||
import org.apache.cloudstack.api.command.user.volume.UploadVolumeCmd;
 | 
					import org.apache.cloudstack.api.command.user.volume.UploadVolumeCmd;
 | 
				
			||||||
 | 
					import org.apache.cloudstack.api.command.user.volume.ResizeVolumeCmd;
 | 
				
			||||||
import com.cloud.exception.ConcurrentOperationException;
 | 
					import com.cloud.exception.ConcurrentOperationException;
 | 
				
			||||||
import com.cloud.exception.InsufficientCapacityException;
 | 
					import com.cloud.exception.InsufficientCapacityException;
 | 
				
			||||||
import com.cloud.exception.PermissionDeniedException;
 | 
					import com.cloud.exception.PermissionDeniedException;
 | 
				
			||||||
@ -70,6 +71,15 @@ public interface StorageService{
 | 
				
			|||||||
    Volume createVolume(CreateVolumeCmd cmd);
 | 
					    Volume createVolume(CreateVolumeCmd cmd);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Resizes the volume based on the given criteria
 | 
				
			||||||
 | 
					     * 
 | 
				
			||||||
 | 
					     * @param cmd
 | 
				
			||||||
 | 
					     *            the API command wrapping the criteria
 | 
				
			||||||
 | 
					     * @return the volume object
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    Volume resizeVolume(ResizeVolumeCmd cmd);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
     * Delete the storage pool
 | 
					     * Delete the storage pool
 | 
				
			||||||
     *
 | 
					     *
 | 
				
			||||||
 | 
				
			|||||||
@ -36,6 +36,7 @@ public interface Volume extends ControlledEntity, Identity, InternalIdentity, Ba
 | 
				
			|||||||
        Ready("The volume is ready to be used."),
 | 
					        Ready("The volume is ready to be used."),
 | 
				
			||||||
        Migrating("The volume is migrating to other storage pool"),
 | 
					        Migrating("The volume is migrating to other storage pool"),
 | 
				
			||||||
        Snapshotting("There is a snapshot created on this volume, not backed up to secondary storage yet"),
 | 
					        Snapshotting("There is a snapshot created on this volume, not backed up to secondary storage yet"),
 | 
				
			||||||
 | 
					        Resizing("The volume is being resized"),
 | 
				
			||||||
        Expunging("The volume is being expunging"),
 | 
					        Expunging("The volume is being expunging"),
 | 
				
			||||||
        Destroy("The volume is destroyed, and can't be recovered."),
 | 
					        Destroy("The volume is destroyed, and can't be recovered."),
 | 
				
			||||||
        UploadOp ("The volume upload operation is in progress or in short the volume is on secondary storage");
 | 
					        UploadOp ("The volume upload operation is in progress or in short the volume is on secondary storage");
 | 
				
			||||||
@ -63,6 +64,9 @@ public interface Volume extends ControlledEntity, Identity, InternalIdentity, Ba
 | 
				
			|||||||
            s_fsm.addTransition(Creating, Event.OperationSucceeded, Ready);
 | 
					            s_fsm.addTransition(Creating, Event.OperationSucceeded, Ready);
 | 
				
			||||||
            s_fsm.addTransition(Creating, Event.DestroyRequested, Destroy);
 | 
					            s_fsm.addTransition(Creating, Event.DestroyRequested, Destroy);
 | 
				
			||||||
            s_fsm.addTransition(Creating, Event.CreateRequested, Creating);  
 | 
					            s_fsm.addTransition(Creating, Event.CreateRequested, Creating);  
 | 
				
			||||||
 | 
					            s_fsm.addTransition(Ready, Event.ResizeRequested, Resizing);
 | 
				
			||||||
 | 
					            s_fsm.addTransition(Resizing, Event.OperationSucceeded, Ready);
 | 
				
			||||||
 | 
					            s_fsm.addTransition(Resizing, Event.OperationFailed, Ready);          
 | 
				
			||||||
            s_fsm.addTransition(Allocated, Event.UploadRequested, UploadOp);
 | 
					            s_fsm.addTransition(Allocated, Event.UploadRequested, UploadOp);
 | 
				
			||||||
            s_fsm.addTransition(UploadOp, Event.CopyRequested, Creating);// CopyRequested for volume from sec to primary storage
 | 
					            s_fsm.addTransition(UploadOp, Event.CopyRequested, Creating);// CopyRequested for volume from sec to primary storage
 | 
				
			||||||
            s_fsm.addTransition(Creating, Event.CopySucceeded, Ready);
 | 
					            s_fsm.addTransition(Creating, Event.CopySucceeded, Ready);
 | 
				
			||||||
@ -92,7 +96,8 @@ public interface Volume extends ControlledEntity, Identity, InternalIdentity, Ba
 | 
				
			|||||||
        MigrationRequested,
 | 
					        MigrationRequested,
 | 
				
			||||||
        SnapshotRequested,
 | 
					        SnapshotRequested,
 | 
				
			||||||
        DestroyRequested,
 | 
					        DestroyRequested,
 | 
				
			||||||
        ExpungingRequested;
 | 
					        ExpungingRequested,
 | 
				
			||||||
 | 
					        ResizeRequested;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
 | 
				
			|||||||
@ -387,6 +387,7 @@ public class ApiConstants {
 | 
				
			|||||||
    public static final String ESP_LIFETIME = "esplifetime";
 | 
					    public static final String ESP_LIFETIME = "esplifetime";
 | 
				
			||||||
    public static final String DPD = "dpd";
 | 
					    public static final String DPD = "dpd";
 | 
				
			||||||
    public static final String FOR_VPC = "forvpc";
 | 
					    public static final String FOR_VPC = "forvpc";
 | 
				
			||||||
 | 
					    public static final String SHRINK_OK = "shrinkok";
 | 
				
			||||||
    public static final String NICIRA_NVP_DEVICE_ID = "nvpdeviceid";
 | 
					    public static final String NICIRA_NVP_DEVICE_ID = "nvpdeviceid";
 | 
				
			||||||
    public static final String NICIRA_NVP_TRANSPORT_ZONE_UUID = "transportzoneuuid";
 | 
					    public static final String NICIRA_NVP_TRANSPORT_ZONE_UUID = "transportzoneuuid";
 | 
				
			||||||
    public static final String NICIRA_NVP_DEVICE_NAME = "niciradevicename";
 | 
					    public static final String NICIRA_NVP_DEVICE_NAME = "niciradevicename";
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										0
									
								
								api/src/org/apache/cloudstack/api/BaseUpdateTemplateOrIsoCmd.java
									
									
									
									
									
										
										
										Executable file → Normal file
									
								
							
							
						
						
									
										0
									
								
								api/src/org/apache/cloudstack/api/BaseUpdateTemplateOrIsoCmd.java
									
									
									
									
									
										
										
										Executable file → Normal file
									
								
							
							
								
								
									
										0
									
								
								api/src/org/apache/cloudstack/api/BaseUpdateTemplateOrIsoPermissionsCmd.java
									
									
									
									
									
										
										
										Executable file → Normal file
									
								
							
							
						
						
									
										0
									
								
								api/src/org/apache/cloudstack/api/BaseUpdateTemplateOrIsoPermissionsCmd.java
									
									
									
									
									
										
										
										Executable file → Normal file
									
								
							@ -0,0 +1,153 @@
 | 
				
			|||||||
 | 
					// Licensed to the Apache Software Foundation (ASF) under one
 | 
				
			||||||
 | 
					// or more contributor license agreements.  See the NOTICE file
 | 
				
			||||||
 | 
					// distributed with this work for additional information
 | 
				
			||||||
 | 
					// regarding copyright ownership.  The ASF licenses this file
 | 
				
			||||||
 | 
					// to you 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.
 | 
				
			||||||
 | 
					package org.apache.cloudstack.api.command.user.volume;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import org.apache.cloudstack.api.response.*;
 | 
				
			||||||
 | 
					import org.apache.log4j.Logger;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import org.apache.cloudstack.api.ApiConstants;
 | 
				
			||||||
 | 
					import org.apache.cloudstack.api.BaseAsyncCmd;
 | 
				
			||||||
 | 
					import org.apache.cloudstack.api.BaseCmd;
 | 
				
			||||||
 | 
					import org.apache.cloudstack.api.BaseListTaggedResourcesCmd;
 | 
				
			||||||
 | 
					import org.apache.cloudstack.api.APICommand;
 | 
				
			||||||
 | 
					import org.apache.cloudstack.api.Parameter;
 | 
				
			||||||
 | 
					import org.apache.cloudstack.api.ServerApiException;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import java.util.ArrayList;
 | 
				
			||||||
 | 
					import java.util.List;
 | 
				
			||||||
 | 
					import java.util.regex.Pattern;
 | 
				
			||||||
 | 
					import java.util.regex.Matcher;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import com.cloud.exception.InvalidParameterValueException;
 | 
				
			||||||
 | 
					import com.cloud.exception.PermissionDeniedException;
 | 
				
			||||||
 | 
					import com.cloud.exception.ResourceAllocationException;
 | 
				
			||||||
 | 
					import com.cloud.async.AsyncJob;
 | 
				
			||||||
 | 
					import com.cloud.event.EventTypes;
 | 
				
			||||||
 | 
					import com.cloud.projects.Project;
 | 
				
			||||||
 | 
					import com.cloud.storage.Volume;
 | 
				
			||||||
 | 
					import com.cloud.user.Account;
 | 
				
			||||||
 | 
					import com.cloud.user.UserContext;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@APICommand(name="resizeVolume", description="Resizes a volume", responseObject=VolumeResponse.class)
 | 
				
			||||||
 | 
					public class ResizeVolumeCmd extends BaseAsyncCmd {
 | 
				
			||||||
 | 
					    public static final Logger s_logger = Logger.getLogger(ResizeVolumeCmd.class.getName());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private static final String s_name = "resizevolumeresponse";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /////////////////////////////////////////////////////
 | 
				
			||||||
 | 
					    //////////////// API parameters /////////////////////
 | 
				
			||||||
 | 
					    /////////////////////////////////////////////////////
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @Parameter(name=ApiConstants.ID, entityType=VolumeResponse.class, type=CommandType.UUID, description="the ID of the disk volume")
 | 
				
			||||||
 | 
					    private Long id;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @Parameter(name=ApiConstants.SIZE, type=CommandType.LONG, required=false, description="New volume size in G")
 | 
				
			||||||
 | 
					    private Long size;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @Parameter(name=ApiConstants.SHRINK_OK, type=CommandType.BOOLEAN, required=false, description="Verify OK to Shrink")
 | 
				
			||||||
 | 
					    private boolean shrinkOk;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @Parameter(name=ApiConstants.DISK_OFFERING_ID, entityType=DiskOfferingResponse.class, type=CommandType.UUID, required=false, description="new disk offering id")
 | 
				
			||||||
 | 
					    private Long newDiskOfferingId;
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    /////////////////////////////////////////////////////
 | 
				
			||||||
 | 
					    /////////////////// Accessors ///////////////////////
 | 
				
			||||||
 | 
					    /////////////////////////////////////////////////////
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public Long getEntityId() {
 | 
				
			||||||
 | 
					        return id;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    public Long getSize() {
 | 
				
			||||||
 | 
					        return size;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public boolean getShrinkOk() {
 | 
				
			||||||
 | 
					        return shrinkOk;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public Long getNewDiskOfferingId() {
 | 
				
			||||||
 | 
					        return newDiskOfferingId;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    /////////////////////////////////////////////////////
 | 
				
			||||||
 | 
					    /////////////// API Implementation///////////////////
 | 
				
			||||||
 | 
					    /////////////////////////////////////////////////////
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @Override
 | 
				
			||||||
 | 
					    public String getCommandName() {
 | 
				
			||||||
 | 
					        return s_name;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    @Override
 | 
				
			||||||
 | 
					    public AsyncJob.Type getInstanceType() {
 | 
				
			||||||
 | 
					    	return AsyncJob.Type.Volume;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public static String getResultObjectName() {
 | 
				
			||||||
 | 
					        return "volume";
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					   @Override
 | 
				
			||||||
 | 
					    public long getEntityOwnerId() {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        Volume volume = _entityMgr.findById(Volume.class, getEntityId());
 | 
				
			||||||
 | 
					        if (volume == null) {
 | 
				
			||||||
 | 
					                throw new InvalidParameterValueException("Unable to find volume by id=" + id);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        Account account = _accountService.getAccount(volume.getAccountId());
 | 
				
			||||||
 | 
					        //Can resize volumes for enabled projects/accounts only
 | 
				
			||||||
 | 
					        if (account.getType() == Account.ACCOUNT_TYPE_PROJECT) {
 | 
				
			||||||
 | 
					                Project project = _projectService.findByProjectAccountId(volume.getAccountId());
 | 
				
			||||||
 | 
					            if (project.getState() != Project.State.Active) {
 | 
				
			||||||
 | 
					                throw new PermissionDeniedException("Can't add resources to  project id=" + project.getId() + " in state=" + project.getState() + " as it's no longer active");
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        } else if (account.getState() == Account.State.disabled) {
 | 
				
			||||||
 | 
					            throw new PermissionDeniedException("The owner of volume " + id + "  is disabled: " + account);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return volume.getAccountId();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @Override
 | 
				
			||||||
 | 
					    public String getEventType() {
 | 
				
			||||||
 | 
					        return EventTypes.EVENT_VOLUME_RESIZE;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @Override
 | 
				
			||||||
 | 
					    public String getEventDescription() {
 | 
				
			||||||
 | 
					        return "Volume Id: " + getEntityId() + " to size " + getSize() + "G" ;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    @Override
 | 
				
			||||||
 | 
					    public void execute(){
 | 
				
			||||||
 | 
					        UserContext.current().setEventDetails("Volume Id: " + getEntityId() + " to size " + getSize() + "G");
 | 
				
			||||||
 | 
					    	Volume volume = _storageService.resizeVolume(this);
 | 
				
			||||||
 | 
					    	if (volume != null) {
 | 
				
			||||||
 | 
					            VolumeResponse response = _responseGenerator.createVolumeResponse(volume);
 | 
				
			||||||
 | 
					            //FIXME - have to be moved to ApiResponseHelper
 | 
				
			||||||
 | 
					            response.setResponseName(getCommandName());
 | 
				
			||||||
 | 
					            this.setResponseObject(response);
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					            throw new ServerApiException(BaseCmd.INTERNAL_ERROR, "Failed to resize volume");
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@ -0,0 +1,199 @@
 | 
				
			|||||||
 | 
					// Licensed to the Apache Software Foundation (ASF) under one
 | 
				
			||||||
 | 
					// or more contributor license agreements.  See the NOTICE file
 | 
				
			||||||
 | 
					// distributed with this work for additional information
 | 
				
			||||||
 | 
					// regarding copyright ownership.  The ASF licenses this file
 | 
				
			||||||
 | 
					// to you 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.
 | 
				
			||||||
 | 
					package src.com.cloud.agent.api.test;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import static org.junit.Assert.assertEquals;
 | 
				
			||||||
 | 
					import static org.junit.Assert.assertTrue;
 | 
				
			||||||
 | 
					import static org.junit.Assert.assertFalse;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import java.text.ParseException;
 | 
				
			||||||
 | 
					import java.text.SimpleDateFormat;
 | 
				
			||||||
 | 
					import java.util.Date;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import org.junit.Test;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import com.cloud.agent.api.storage.ResizeVolumeCommand;
 | 
				
			||||||
 | 
					import com.cloud.agent.api.to.StorageFilerTO;
 | 
				
			||||||
 | 
					import com.cloud.storage.StoragePool;
 | 
				
			||||||
 | 
					import com.cloud.storage.Storage.StoragePoolType;
 | 
				
			||||||
 | 
					import com.cloud.storage.StoragePoolStatus;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					public class ResizeVolumeCommandTest {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public StoragePool dummypool = new StoragePool() {
 | 
				
			||||||
 | 
					        public long getId() {
 | 
				
			||||||
 | 
					            return 1L;
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        public String getName() {
 | 
				
			||||||
 | 
					            return "name";
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        public String getUuid() {
 | 
				
			||||||
 | 
					            return "bed9f83e-cac3-11e1-ac8a-0050568b007e";
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        public StoragePoolType getPoolType() {
 | 
				
			||||||
 | 
					            return StoragePoolType.Filesystem;
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        public Date getCreated() {
 | 
				
			||||||
 | 
					            Date date = null;
 | 
				
			||||||
 | 
					            try {
 | 
				
			||||||
 | 
					                date = new SimpleDateFormat("MM/dd/yyyy HH:mm:ss")
 | 
				
			||||||
 | 
					                        .parse("01/01/1970 12:12:12");
 | 
				
			||||||
 | 
					            } catch (ParseException e) {
 | 
				
			||||||
 | 
					                e.printStackTrace();
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            return date;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        public Date getUpdateTime() {
 | 
				
			||||||
 | 
					            return new Date();
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        public long getDataCenterId() {
 | 
				
			||||||
 | 
					            return 0L;
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        public long getCapacityBytes() {
 | 
				
			||||||
 | 
					            return 0L;
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        public long getAvailableBytes() {
 | 
				
			||||||
 | 
					            return 0L;
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        public Long getClusterId() {
 | 
				
			||||||
 | 
					            return 0L;
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        public String getHostAddress() {
 | 
				
			||||||
 | 
					            return "hostAddress";
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        public String getPath() {
 | 
				
			||||||
 | 
					            return "path";
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        public String getUserInfo() {
 | 
				
			||||||
 | 
					            return "userInfo";
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        public boolean isShared() {
 | 
				
			||||||
 | 
					            return false;
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        public boolean isLocal() {
 | 
				
			||||||
 | 
					            return false;
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        public StoragePoolStatus getStatus() {
 | 
				
			||||||
 | 
					            return StoragePoolStatus.Up;
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        public int getPort() {
 | 
				
			||||||
 | 
					            return 25;
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        public Long getPodId() {
 | 
				
			||||||
 | 
					            return 0L;
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    Long newSize = 4194304L;
 | 
				
			||||||
 | 
					    Long currentSize = 1048576L;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    ResizeVolumeCommand rv = new ResizeVolumeCommand("dummydiskpath", 
 | 
				
			||||||
 | 
					            new StorageFilerTO(dummypool), currentSize, newSize, false, 
 | 
				
			||||||
 | 
					            "vmName");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @Test
 | 
				
			||||||
 | 
					    public void testExecuteInSequence() {
 | 
				
			||||||
 | 
					        boolean b = rv.executeInSequence();
 | 
				
			||||||
 | 
					        assertFalse(b);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @Test
 | 
				
			||||||
 | 
					    public void testGetPath() {
 | 
				
			||||||
 | 
					        String path = rv.getPath();
 | 
				
			||||||
 | 
					        assertTrue(path.equals("dummydiskpath"));
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @Test
 | 
				
			||||||
 | 
					    public void testGetPoolUuid() {
 | 
				
			||||||
 | 
					        String poolUuid = rv.getPoolUuid();
 | 
				
			||||||
 | 
					        assertTrue(poolUuid.equals("bed9f83e-cac3-11e1-ac8a-0050568b007e"));
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @Test
 | 
				
			||||||
 | 
					    public void testGetPool() {
 | 
				
			||||||
 | 
					        StorageFilerTO pool = rv.getPool();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        Long id = pool.getId();
 | 
				
			||||||
 | 
					        Long expectedL = 1L;
 | 
				
			||||||
 | 
					        assertEquals(expectedL, id);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        String uuid = pool.getUuid();
 | 
				
			||||||
 | 
					        assertTrue(uuid.equals("bed9f83e-cac3-11e1-ac8a-0050568b007e"));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        String host = pool.getHost();
 | 
				
			||||||
 | 
					        assertTrue(host.equals("hostAddress"));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        String path = pool.getPath();
 | 
				
			||||||
 | 
					        assertTrue(path.equals("path"));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        String userInfo = pool.getUserInfo();
 | 
				
			||||||
 | 
					        assertTrue(userInfo.equals("userInfo"));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        Integer port = pool.getPort();
 | 
				
			||||||
 | 
					        Integer expectedI = 25;
 | 
				
			||||||
 | 
					        assertEquals(expectedI, port);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        StoragePoolType type = pool.getType();
 | 
				
			||||||
 | 
					        assertEquals(StoragePoolType.Filesystem, type);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        String str = pool.toString();
 | 
				
			||||||
 | 
					        assertTrue(str.equals("Pool[" + id.toString() + "|" + host + ":"
 | 
				
			||||||
 | 
					                + port.toString() + "|" + path + "]"));
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @Test
 | 
				
			||||||
 | 
					    public void testGetNewSize() {
 | 
				
			||||||
 | 
					        long newSize = rv.getNewSize();
 | 
				
			||||||
 | 
					        assertTrue(newSize == 4194304L);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @Test
 | 
				
			||||||
 | 
					    public void testGetCurrentSize() {
 | 
				
			||||||
 | 
					        long currentSize = rv.getCurrentSize();
 | 
				
			||||||
 | 
					        assertTrue(currentSize == 1048576L);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @Test
 | 
				
			||||||
 | 
					    public void testGetShrinkOk() {
 | 
				
			||||||
 | 
					        assertFalse(rv.getShrinkOk());
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @Test
 | 
				
			||||||
 | 
					    public void testGetInstanceName() {
 | 
				
			||||||
 | 
					        String vmName = rv.getInstanceName();
 | 
				
			||||||
 | 
					        assertTrue(vmName.equals("vmName"));
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@ -255,6 +255,7 @@ deleteVolume=15
 | 
				
			|||||||
listVolumes=15
 | 
					listVolumes=15
 | 
				
			||||||
extractVolume=15
 | 
					extractVolume=15
 | 
				
			||||||
migrateVolume=15
 | 
					migrateVolume=15
 | 
				
			||||||
 | 
					resizeVolume=15
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#### registration command:  FIXME -- this really should be something in management server that
 | 
					#### registration command:  FIXME -- this really should be something in management server that
 | 
				
			||||||
####                                 generates a new key for the user and they just have to
 | 
					####                                 generates a new key for the user and they just have to
 | 
				
			||||||
 | 
				
			|||||||
@ -162,6 +162,8 @@ import com.cloud.agent.api.storage.CreatePrivateTemplateAnswer;
 | 
				
			|||||||
import com.cloud.agent.api.storage.DestroyCommand;
 | 
					import com.cloud.agent.api.storage.DestroyCommand;
 | 
				
			||||||
import com.cloud.agent.api.storage.PrimaryStorageDownloadAnswer;
 | 
					import com.cloud.agent.api.storage.PrimaryStorageDownloadAnswer;
 | 
				
			||||||
import com.cloud.agent.api.storage.PrimaryStorageDownloadCommand;
 | 
					import com.cloud.agent.api.storage.PrimaryStorageDownloadCommand;
 | 
				
			||||||
 | 
					import com.cloud.agent.api.storage.ResizeVolumeCommand;
 | 
				
			||||||
 | 
					import com.cloud.agent.api.storage.ResizeVolumeAnswer;
 | 
				
			||||||
import com.cloud.agent.api.to.IpAddressTO;
 | 
					import com.cloud.agent.api.to.IpAddressTO;
 | 
				
			||||||
import com.cloud.agent.api.to.NicTO;
 | 
					import com.cloud.agent.api.to.NicTO;
 | 
				
			||||||
import com.cloud.agent.api.to.StorageFilerTO;
 | 
					import com.cloud.agent.api.to.StorageFilerTO;
 | 
				
			||||||
@ -255,6 +257,7 @@ public class LibvirtComputingResource extends ServerResourceBase implements
 | 
				
			|||||||
    private String _patchdomrPath;
 | 
					    private String _patchdomrPath;
 | 
				
			||||||
    private String _createvmPath;
 | 
					    private String _createvmPath;
 | 
				
			||||||
    private String _manageSnapshotPath;
 | 
					    private String _manageSnapshotPath;
 | 
				
			||||||
 | 
					    private String _resizeVolumePath;
 | 
				
			||||||
    private String _createTmplPath;
 | 
					    private String _createTmplPath;
 | 
				
			||||||
    private String _heartBeatPath;
 | 
					    private String _heartBeatPath;
 | 
				
			||||||
    private String _securityGroupPath;
 | 
					    private String _securityGroupPath;
 | 
				
			||||||
@ -534,6 +537,12 @@ public class LibvirtComputingResource extends ServerResourceBase implements
 | 
				
			|||||||
                    "Unable to find the managesnapshot.sh");
 | 
					                    "Unable to find the managesnapshot.sh");
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        _resizeVolumePath = Script.findScript(storageScriptsDir, "resizevolume.sh");
 | 
				
			||||||
 | 
					        if (_resizeVolumePath == null) {
 | 
				
			||||||
 | 
					            throw new ConfigurationException(
 | 
				
			||||||
 | 
					                    "Unable to find the resizevolume.sh");
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        _createTmplPath = Script
 | 
					        _createTmplPath = Script
 | 
				
			||||||
                .findScript(storageScriptsDir, "createtmplt.sh");
 | 
					                .findScript(storageScriptsDir, "createtmplt.sh");
 | 
				
			||||||
        if (_createTmplPath == null) {
 | 
					        if (_createTmplPath == null) {
 | 
				
			||||||
@ -1062,6 +1071,8 @@ public class LibvirtComputingResource extends ServerResourceBase implements
 | 
				
			|||||||
                return execute((CleanupNetworkRulesCmd) cmd);
 | 
					                return execute((CleanupNetworkRulesCmd) cmd);
 | 
				
			||||||
            } else if (cmd instanceof CopyVolumeCommand) {
 | 
					            } else if (cmd instanceof CopyVolumeCommand) {
 | 
				
			||||||
                return execute((CopyVolumeCommand) cmd);
 | 
					                return execute((CopyVolumeCommand) cmd);
 | 
				
			||||||
 | 
					            } else if (cmd instanceof ResizeVolumeCommand) {
 | 
				
			||||||
 | 
					                return execute((ResizeVolumeCommand) cmd);
 | 
				
			||||||
            } else if (cmd instanceof CheckNetworkCommand) {
 | 
					            } else if (cmd instanceof CheckNetworkCommand) {
 | 
				
			||||||
                return execute((CheckNetworkCommand) cmd);
 | 
					                return execute((CheckNetworkCommand) cmd);
 | 
				
			||||||
            } else {
 | 
					            } else {
 | 
				
			||||||
@ -1268,6 +1279,72 @@ public class LibvirtComputingResource extends ServerResourceBase implements
 | 
				
			|||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private String getResizeScriptType (KVMStoragePool pool, KVMPhysicalDisk vol) {
 | 
				
			||||||
 | 
					        StoragePoolType poolType = pool.getType();
 | 
				
			||||||
 | 
					        PhysicalDiskFormat volFormat = vol.getFormat();
 | 
				
			||||||
 | 
					         
 | 
				
			||||||
 | 
					        if(pool.getType() == StoragePoolType.CLVM && volFormat == KVMPhysicalDisk.PhysicalDiskFormat.RAW) {
 | 
				
			||||||
 | 
					            return "CLVM";
 | 
				
			||||||
 | 
					        } else if ((poolType == StoragePoolType.NetworkFilesystem
 | 
				
			||||||
 | 
					                  || poolType == StoragePoolType.SharedMountPoint
 | 
				
			||||||
 | 
					                  || poolType == StoragePoolType.Filesystem)
 | 
				
			||||||
 | 
					                  && volFormat == KVMPhysicalDisk.PhysicalDiskFormat.QCOW2 ) {
 | 
				
			||||||
 | 
					            return "QCOW2";
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        return null;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /* uses a local script now, eventually support for virStorageVolResize() will maybe work on 
 | 
				
			||||||
 | 
					       qcow2 and lvm and we can do this in libvirt calls */
 | 
				
			||||||
 | 
					    public Answer execute(ResizeVolumeCommand cmd) {
 | 
				
			||||||
 | 
					        String volid = cmd.getPath();
 | 
				
			||||||
 | 
					        long newSize = cmd.getNewSize();
 | 
				
			||||||
 | 
					        long currentSize = cmd.getCurrentSize();
 | 
				
			||||||
 | 
					        String vmInstanceName = cmd.getInstanceName();
 | 
				
			||||||
 | 
					        boolean shrinkOk = cmd.getShrinkOk();
 | 
				
			||||||
 | 
					        StorageFilerTO spool = cmd.getPool();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        try {
 | 
				
			||||||
 | 
					            KVMStoragePool pool = _storagePoolMgr.getStoragePool(spool.getType(), spool.getUuid());
 | 
				
			||||||
 | 
					            KVMPhysicalDisk vol = pool.getPhysicalDisk(volid);
 | 
				
			||||||
 | 
					            String path = vol.getPath();
 | 
				
			||||||
 | 
					            String type = getResizeScriptType(pool, vol);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if (type == null) {
 | 
				
			||||||
 | 
					                return new ResizeVolumeAnswer(cmd, false, "Unsupported volume format: pool type '" 
 | 
				
			||||||
 | 
					                                + pool.getType() + "' and volume format '" + vol.getFormat() + "'");
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            s_logger.debug("got to the stage where we execute the volume resize, params:" 
 | 
				
			||||||
 | 
					                           + path + "," + currentSize + "," + newSize + "," + type + "," + vmInstanceName + "," + shrinkOk);
 | 
				
			||||||
 | 
					            final Script resizecmd = new Script(_resizeVolumePath,
 | 
				
			||||||
 | 
					                        _cmdsTimeout, s_logger); 
 | 
				
			||||||
 | 
					            resizecmd.add("-s",String.valueOf(newSize));
 | 
				
			||||||
 | 
					            resizecmd.add("-c",String.valueOf(currentSize));
 | 
				
			||||||
 | 
					            resizecmd.add("-p",path);
 | 
				
			||||||
 | 
					            resizecmd.add("-t",type);
 | 
				
			||||||
 | 
					            resizecmd.add("-r",String.valueOf(shrinkOk));
 | 
				
			||||||
 | 
					            resizecmd.add("-v",vmInstanceName);
 | 
				
			||||||
 | 
					            String result = resizecmd.execute();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if (result == null) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                /* fetch new size as seen from libvirt, don't want to assume anything */
 | 
				
			||||||
 | 
					                pool = _storagePoolMgr.getStoragePool(spool.getType(), spool.getUuid());
 | 
				
			||||||
 | 
					                long finalSize = pool.getPhysicalDisk(volid).getVirtualSize();
 | 
				
			||||||
 | 
					                s_logger.debug("after resize, size reports as " + finalSize + ", requested " + newSize);
 | 
				
			||||||
 | 
					                return new ResizeVolumeAnswer(cmd, true, "success", finalSize);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            return new ResizeVolumeAnswer(cmd, false, result);
 | 
				
			||||||
 | 
					        } catch (CloudRuntimeException e) {
 | 
				
			||||||
 | 
					            String error = "failed to resize volume: " + e;
 | 
				
			||||||
 | 
					            s_logger.debug(error);
 | 
				
			||||||
 | 
					            return new ResizeVolumeAnswer(cmd, false, error);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					    } 
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public Answer execute(DestroyCommand cmd) {
 | 
					    public Answer execute(DestroyCommand cmd) {
 | 
				
			||||||
        VolumeTO vol = cmd.getVolume();
 | 
					        VolumeTO vol = cmd.getVolume();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -182,6 +182,8 @@ import com.cloud.agent.api.storage.CreatePrivateTemplateAnswer;
 | 
				
			|||||||
import com.cloud.agent.api.storage.DestroyCommand;
 | 
					import com.cloud.agent.api.storage.DestroyCommand;
 | 
				
			||||||
import com.cloud.agent.api.storage.PrimaryStorageDownloadAnswer;
 | 
					import com.cloud.agent.api.storage.PrimaryStorageDownloadAnswer;
 | 
				
			||||||
import com.cloud.agent.api.storage.PrimaryStorageDownloadCommand;
 | 
					import com.cloud.agent.api.storage.PrimaryStorageDownloadCommand;
 | 
				
			||||||
 | 
					import com.cloud.agent.api.storage.ResizeVolumeCommand;
 | 
				
			||||||
 | 
					import com.cloud.agent.api.storage.ResizeVolumeAnswer;
 | 
				
			||||||
import com.cloud.agent.api.to.IpAddressTO;
 | 
					import com.cloud.agent.api.to.IpAddressTO;
 | 
				
			||||||
import com.cloud.agent.api.to.NicTO;
 | 
					import com.cloud.agent.api.to.NicTO;
 | 
				
			||||||
import com.cloud.agent.api.to.PortForwardingRuleTO;
 | 
					import com.cloud.agent.api.to.PortForwardingRuleTO;
 | 
				
			||||||
@ -468,6 +470,8 @@ public abstract class CitrixResourceBase implements ServerResource, HypervisorRe
 | 
				
			|||||||
            return execute((DeleteStoragePoolCommand) cmd);
 | 
					            return execute((DeleteStoragePoolCommand) cmd);
 | 
				
			||||||
        } else if (clazz == CopyVolumeCommand.class) {
 | 
					        } else if (clazz == CopyVolumeCommand.class) {
 | 
				
			||||||
            return execute((CopyVolumeCommand) cmd);
 | 
					            return execute((CopyVolumeCommand) cmd);
 | 
				
			||||||
 | 
					        } else if (clazz == ResizeVolumeCommand.class) {
 | 
				
			||||||
 | 
					            return execute((ResizeVolumeCommand) cmd);
 | 
				
			||||||
        } else if (clazz == AttachVolumeCommand.class) {
 | 
					        } else if (clazz == AttachVolumeCommand.class) {
 | 
				
			||||||
            return execute((AttachVolumeCommand) cmd);
 | 
					            return execute((AttachVolumeCommand) cmd);
 | 
				
			||||||
        } else if (clazz == AttachIsoCommand.class) {
 | 
					        } else if (clazz == AttachIsoCommand.class) {
 | 
				
			||||||
@ -5618,6 +5622,23 @@ public abstract class CitrixResourceBase implements ServerResource, HypervisorRe
 | 
				
			|||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public Answer execute(ResizeVolumeCommand cmd) {
 | 
				
			||||||
 | 
					        Connection conn = getConnection();
 | 
				
			||||||
 | 
					        StorageFilerTO pool = cmd.getPool();
 | 
				
			||||||
 | 
					        String volid = cmd.getPath();
 | 
				
			||||||
 | 
					        long newSize = cmd.getNewSize();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        try {
 | 
				
			||||||
 | 
					            VDI vdi = getVDIbyUuid(conn, volid);
 | 
				
			||||||
 | 
					            vdi.resize(conn, newSize);
 | 
				
			||||||
 | 
					            return new ResizeVolumeAnswer(cmd, true, "success", newSize);
 | 
				
			||||||
 | 
					        } catch (Exception e) {
 | 
				
			||||||
 | 
					            s_logger.warn("Unable to resize volume",e);
 | 
				
			||||||
 | 
					            String error = "failed to resize volume:"  +e;
 | 
				
			||||||
 | 
					            return new ResizeVolumeAnswer(cmd, false, error );
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    protected SR getISOSRbyVmName(Connection conn, String vmName) {
 | 
					    protected SR getISOSRbyVmName(Connection conn, String vmName) {
 | 
				
			||||||
        try {
 | 
					        try {
 | 
				
			||||||
            Set<SR> srs = SR.getByNameLabel(conn, vmName + "-ISO");
 | 
					            Set<SR> srs = SR.getByNameLabel(conn, vmName + "-ISO");
 | 
				
			||||||
@ -7684,4 +7705,5 @@ public abstract class CitrixResourceBase implements ServerResource, HypervisorRe
 | 
				
			|||||||
            return new SetStaticRouteAnswer(cmd, false, null);
 | 
					            return new SetStaticRouteAnswer(cmd, false, null);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										253
									
								
								scripts/storage/qcow2/resizevolume.sh
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										253
									
								
								scripts/storage/qcow2/resizevolume.sh
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,253 @@
 | 
				
			|||||||
 | 
					#!/usr/bin/env bash
 | 
				
			||||||
 | 
					# Licensed to the Apache Software Foundation (ASF) under one
 | 
				
			||||||
 | 
					# or more contributor license agreements.  See the NOTICE file
 | 
				
			||||||
 | 
					# distributed with this work for additional information
 | 
				
			||||||
 | 
					# regarding copyright ownership.  The ASF licenses this file
 | 
				
			||||||
 | 
					# to you 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.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# resizevolume.sh -- resize a volume
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					usage() {
 | 
				
			||||||
 | 
					  printf "Usage: %s: -c <current-volume-size> -s <new-volume-size> -p <volume path> -v <vm instance name> -t <storage-type> -r <shrink-bool>\n" $(basename $0) >&2
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					getdevmappername() {
 | 
				
			||||||
 | 
					  local path=$1
 | 
				
			||||||
 | 
					  local devmappername=`readlink -f $path |cut -d/ -f3`
 | 
				
			||||||
 | 
					  if [[ $devmappername =~ "dm-" ]]
 | 
				
			||||||
 | 
					  then
 | 
				
			||||||
 | 
					    dmname=$devmappername
 | 
				
			||||||
 | 
					    return 0
 | 
				
			||||||
 | 
					  else
 | 
				
			||||||
 | 
					    return 1;
 | 
				
			||||||
 | 
					  fi
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					getdevmappersize() {
 | 
				
			||||||
 | 
					  local dm=$1
 | 
				
			||||||
 | 
					  if [ ! -e "/sys/block/${dm}/size" ]
 | 
				
			||||||
 | 
					  then
 | 
				
			||||||
 | 
					    log "unable to find ${dm} in /sys/block" 1
 | 
				
			||||||
 | 
					    exit 1
 | 
				
			||||||
 | 
					  fi
 | 
				
			||||||
 | 
					  actualsize=$((`cat /sys/block/${dm}/size`*512));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  if [[ -z "$actualsize" ]]
 | 
				
			||||||
 | 
					  then
 | 
				
			||||||
 | 
					    log "unable to find actual size of ${dm}" 1
 | 
				
			||||||
 | 
					    exit 1
 | 
				
			||||||
 | 
					  fi
 | 
				
			||||||
 | 
					  return 0
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# log "message" 1  <-- prints to stdout as well as log, to pass error up to cloudstack
 | 
				
			||||||
 | 
					# log "message" prints only to log file
 | 
				
			||||||
 | 
					# variable shouldwelog controls whether we print to log file
 | 
				
			||||||
 | 
					log() {
 | 
				
			||||||
 | 
					  local d=`date`
 | 
				
			||||||
 | 
					  local msg=${1}
 | 
				
			||||||
 | 
					  local stdout=${2}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  if [ ! -z "$stdout" ]
 | 
				
			||||||
 | 
					  then
 | 
				
			||||||
 | 
					    echo $1
 | 
				
			||||||
 | 
					  fi
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  if [ $shouldwelog -eq 1 ]
 | 
				
			||||||
 | 
					  then
 | 
				
			||||||
 | 
					    echo "$d - $1" >> /var/log/cloud/agent/resizevolume.log
 | 
				
			||||||
 | 
					  fi
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					failshrink() {
 | 
				
			||||||
 | 
					  # if this is a shrink operation, fail if commands will shrink the volume and we haven't signed of on shrinking
 | 
				
			||||||
 | 
					  if [ $actualsize -gt $newsize ]
 | 
				
			||||||
 | 
					  then
 | 
				
			||||||
 | 
					    if [ "$shrink" == "false" ]
 | 
				
			||||||
 | 
					    then
 | 
				
			||||||
 | 
					      log "result would shrink the volume from $actualsize to $newsize, but confirmation to shrink wasn't passed. Shrink='$shrink'" 1
 | 
				
			||||||
 | 
					      exit 1
 | 
				
			||||||
 | 
					    fi
 | 
				
			||||||
 | 
					  fi
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					notifyqemu() {
 | 
				
			||||||
 | 
					  #move this back into cloudstack libvirt calls once the libvirt java bindings support block resize
 | 
				
			||||||
 | 
					  #we try to inform hypervisor of new size, but don't fail if we can't
 | 
				
			||||||
 | 
					  if `virsh help 2>/dev/null | grep -q blockresize`
 | 
				
			||||||
 | 
					  then
 | 
				
			||||||
 | 
					    if `virsh domstate $vmname >/dev/null 2>&1`
 | 
				
			||||||
 | 
					    then
 | 
				
			||||||
 | 
					      sizeinkb=$(($newsize/1024))
 | 
				
			||||||
 | 
					      virsh blockresize --domain $vmname --path $path --size $sizeinkb >/dev/null 2>&1
 | 
				
			||||||
 | 
					      retval=$?
 | 
				
			||||||
 | 
					      if [ -z $retval ] || [ $retval -ne 0 ]
 | 
				
			||||||
 | 
					      then
 | 
				
			||||||
 | 
					        log "failed to live resize $path to size of $sizeinkb kb" 1
 | 
				
			||||||
 | 
					      else
 | 
				
			||||||
 | 
					        liveresize='true'
 | 
				
			||||||
 | 
					      fi
 | 
				
			||||||
 | 
					    fi
 | 
				
			||||||
 | 
					  fi
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					resizelvm() {
 | 
				
			||||||
 | 
					  local dmname=''
 | 
				
			||||||
 | 
					  local actualsize=''
 | 
				
			||||||
 | 
					  local liveresize='false'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  ##### sanity checks #####
 | 
				
			||||||
 | 
					  if ! `lvresize --version > /dev/null 2>&1`
 | 
				
			||||||
 | 
					  then
 | 
				
			||||||
 | 
					    log "unable to resolve executable 'lvresize'" 1
 | 
				
			||||||
 | 
					    exit 1
 | 
				
			||||||
 | 
					  fi
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  if ! `virsh --version > /dev/null 2>&1`
 | 
				
			||||||
 | 
					  then
 | 
				
			||||||
 | 
					    log "unable to resolve executable 'virsh'" 1
 | 
				
			||||||
 | 
					    exit 1
 | 
				
			||||||
 | 
					  fi
 | 
				
			||||||
 | 
					  ##### end sanity #####
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  if ! getdevmappername $path
 | 
				
			||||||
 | 
					  then
 | 
				
			||||||
 | 
					    log "unable to resolve a device mapper dev from $path" 1
 | 
				
			||||||
 | 
					    exit 1
 | 
				
			||||||
 | 
					  fi
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  getdevmappersize $dmname
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  if [ $actualsize -ne $currentsize ]
 | 
				
			||||||
 | 
					  then
 | 
				
			||||||
 | 
					    log "disk isn't the size we think it is: cloudstack said $currentsize, disk said $actualsize."
 | 
				
			||||||
 | 
					  fi
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  # if this is a shrink operation, fail if commands will shrink the volume and we haven't signed of on shrinking
 | 
				
			||||||
 | 
					  failshrink
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  output=`lvresize -f -L ${newsize}B $path 2>&1`
 | 
				
			||||||
 | 
					  retval=$?
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  if [ -z $retval ] || [ $retval -ne 0 ]
 | 
				
			||||||
 | 
					  then
 | 
				
			||||||
 | 
					    log "lvresize failed: $output " 1
 | 
				
			||||||
 | 
					    exit 1
 | 
				
			||||||
 | 
					  fi
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  #move this back into cloudstack libvirt calls once the libvirt java bindings support block resize
 | 
				
			||||||
 | 
					  #we try to inform hypervisor of new size, but don't fail if we can't
 | 
				
			||||||
 | 
					  notifyqemu
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  log "performed successful resize - dm:$dmname currentsize:$currentsize newsize:$newsize path:$path type:$ptype vmname:$vmname live:$liveresize shrink:$shrink"
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					resizeqcow2() {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					   ##### sanity checks #####
 | 
				
			||||||
 | 
					  if [ ! -e "$path" ]
 | 
				
			||||||
 | 
					  then
 | 
				
			||||||
 | 
					    log "unable to find file $path" 1
 | 
				
			||||||
 | 
					    exit 1
 | 
				
			||||||
 | 
					  fi
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  if ! `qemu-img info /dev/null > /dev/null 2>&1`
 | 
				
			||||||
 | 
					  then
 | 
				
			||||||
 | 
					    log "unable to resolve executable 'qemu-img'" 1
 | 
				
			||||||
 | 
					    exit 1
 | 
				
			||||||
 | 
					  fi
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  if ! `virsh --version > /dev/null 2>&1`
 | 
				
			||||||
 | 
					  then
 | 
				
			||||||
 | 
					    log "unable to resolve executable 'virsh'" 1
 | 
				
			||||||
 | 
					    exit 1
 | 
				
			||||||
 | 
					  fi
 | 
				
			||||||
 | 
					  ##### end sanity #####
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  $actualsize=`qemu-img info $path | grep "virtual size" | sed -re  's/^.*\(([0-9]+).*$/\1/g'`
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  if [ $actualsize -ne $currentsize ]
 | 
				
			||||||
 | 
					  then
 | 
				
			||||||
 | 
					    log "disk isn't the size we think it is: cloudstack said $currentsize, disk said $actualsize."
 | 
				
			||||||
 | 
					  fi
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  # if this is a shrink operation, fail if commands will shrink the volume and we haven't signed of on shrinking
 | 
				
			||||||
 | 
					  failshrink
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  output=`qemu-img resize $path $newsize 2>&1`
 | 
				
			||||||
 | 
					  retval=$?
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  if [ -z $retval ] || [ $retval -ne 0 ]
 | 
				
			||||||
 | 
					  then
 | 
				
			||||||
 | 
					    log "qemu-img resize failed: $output" 1
 | 
				
			||||||
 | 
					    exit 1
 | 
				
			||||||
 | 
					  fi
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  #move this back into cloudstack libvirt calls once the libvirt java bindings support block resize
 | 
				
			||||||
 | 
					  #we try to inform hypervisor of new size, but don't fail if we can't
 | 
				
			||||||
 | 
					  notifyqemu
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  log "performed successful resize - currentsize:$currentsize newsize:$newsize path:$path type:$ptype vmname:$vmname live:$liveresize shrink:$shrink"
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					sflag=
 | 
				
			||||||
 | 
					cflag=
 | 
				
			||||||
 | 
					pflag=
 | 
				
			||||||
 | 
					vflag=
 | 
				
			||||||
 | 
					tflag=
 | 
				
			||||||
 | 
					rflag=
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					while getopts 'c:s:v:p:t:r:' OPTION
 | 
				
			||||||
 | 
					do
 | 
				
			||||||
 | 
					  case $OPTION in
 | 
				
			||||||
 | 
					  s)	sflag=1
 | 
				
			||||||
 | 
							newsize="$OPTARG"
 | 
				
			||||||
 | 
							;;
 | 
				
			||||||
 | 
					  c)    cflag=1
 | 
				
			||||||
 | 
					                currentsize="$OPTARG"
 | 
				
			||||||
 | 
					                ;;
 | 
				
			||||||
 | 
					  v)	vflag=1
 | 
				
			||||||
 | 
							vmname="$OPTARG"
 | 
				
			||||||
 | 
							;;
 | 
				
			||||||
 | 
					  p)	dflag=1
 | 
				
			||||||
 | 
							path="$OPTARG"
 | 
				
			||||||
 | 
							;;
 | 
				
			||||||
 | 
					  t)    tflag=1
 | 
				
			||||||
 | 
					                ptype="$OPTARG"
 | 
				
			||||||
 | 
					                ;;
 | 
				
			||||||
 | 
					  r)    rflag=1
 | 
				
			||||||
 | 
					                shrink="$OPTARG"
 | 
				
			||||||
 | 
					                ;;
 | 
				
			||||||
 | 
					  ?)	usage
 | 
				
			||||||
 | 
							exit 2
 | 
				
			||||||
 | 
							;;
 | 
				
			||||||
 | 
					  esac
 | 
				
			||||||
 | 
					done
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					shouldwelog=1 #set this to 1 while debugging to get output in /var/log/cloud/agent/resizevolume.log
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					if [ "$ptype" == "CLVM" ]
 | 
				
			||||||
 | 
					then
 | 
				
			||||||
 | 
					  resizelvm
 | 
				
			||||||
 | 
					elif [ "$ptype" == "QCOW2" ]
 | 
				
			||||||
 | 
					then
 | 
				
			||||||
 | 
					  resizeqcow2
 | 
				
			||||||
 | 
					else
 | 
				
			||||||
 | 
					  echo "unsupported type $ptype"
 | 
				
			||||||
 | 
					  exit 1;
 | 
				
			||||||
 | 
					fi
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					exit 0
 | 
				
			||||||
@ -47,6 +47,7 @@ import javax.naming.ConfigurationException;
 | 
				
			|||||||
import org.apache.cloudstack.api.command.admin.storage.*;
 | 
					import org.apache.cloudstack.api.command.admin.storage.*;
 | 
				
			||||||
import org.apache.cloudstack.api.command.user.volume.CreateVolumeCmd;
 | 
					import org.apache.cloudstack.api.command.user.volume.CreateVolumeCmd;
 | 
				
			||||||
import org.apache.cloudstack.api.command.user.volume.UploadVolumeCmd;
 | 
					import org.apache.cloudstack.api.command.user.volume.UploadVolumeCmd;
 | 
				
			||||||
 | 
					import org.apache.cloudstack.api.command.user.volume.ResizeVolumeCmd;
 | 
				
			||||||
import org.apache.log4j.Logger;
 | 
					import org.apache.log4j.Logger;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import com.cloud.agent.AgentManager;
 | 
					import com.cloud.agent.AgentManager;
 | 
				
			||||||
@ -69,6 +70,8 @@ import com.cloud.agent.api.storage.CreateCommand;
 | 
				
			|||||||
import com.cloud.agent.api.storage.DeleteTemplateCommand;
 | 
					import com.cloud.agent.api.storage.DeleteTemplateCommand;
 | 
				
			||||||
import com.cloud.agent.api.storage.DeleteVolumeCommand;
 | 
					import com.cloud.agent.api.storage.DeleteVolumeCommand;
 | 
				
			||||||
import com.cloud.agent.api.storage.DestroyCommand;
 | 
					import com.cloud.agent.api.storage.DestroyCommand;
 | 
				
			||||||
 | 
					import com.cloud.agent.api.storage.ResizeVolumeCommand;
 | 
				
			||||||
 | 
					import com.cloud.agent.api.storage.ResizeVolumeAnswer;
 | 
				
			||||||
import com.cloud.agent.api.to.StorageFilerTO;
 | 
					import com.cloud.agent.api.to.StorageFilerTO;
 | 
				
			||||||
import com.cloud.agent.api.to.VolumeTO;
 | 
					import com.cloud.agent.api.to.VolumeTO;
 | 
				
			||||||
import com.cloud.agent.manager.Commands;
 | 
					import com.cloud.agent.manager.Commands;
 | 
				
			||||||
@ -2098,6 +2101,183 @@ public class StorageManagerImpl implements StorageManager, Manager, ClusterManag
 | 
				
			|||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @Override
 | 
				
			||||||
 | 
					    @DB
 | 
				
			||||||
 | 
					    @ActionEvent(eventType = EventTypes.EVENT_VOLUME_RESIZE, eventDescription = "resizing volume", async = true)
 | 
				
			||||||
 | 
					    public VolumeVO resizeVolume(ResizeVolumeCmd cmd) {
 | 
				
			||||||
 | 
					        VolumeVO volume = _volsDao.findById(cmd.getEntityId());
 | 
				
			||||||
 | 
					        Long newSize = null;
 | 
				
			||||||
 | 
					        boolean shrinkOk = cmd.getShrinkOk();
 | 
				
			||||||
 | 
					        boolean success = false;
 | 
				
			||||||
 | 
					        DiskOfferingVO diskOffering = _diskOfferingDao.findById(volume.getDiskOfferingId());
 | 
				
			||||||
 | 
					        DiskOfferingVO newDiskOffering = null;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        newDiskOffering = _diskOfferingDao.findById(cmd.getNewDiskOfferingId());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        /* Volumes with no hypervisor have never been assigned, and can be resized by recreating.
 | 
				
			||||||
 | 
					           perhaps in the future we can just update the db entry for the volume */
 | 
				
			||||||
 | 
					        if(_volsDao.getHypervisorType(volume.getId()) == HypervisorType.None){
 | 
				
			||||||
 | 
					            throw new InvalidParameterValueException("Can't resize a volume that has never been attached, not sure which hypervisor type. Recreate volume to resize.");
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        /* Only works for KVM/Xen for now */
 | 
				
			||||||
 | 
					        if(_volsDao.getHypervisorType(volume.getId()) != HypervisorType.KVM 
 | 
				
			||||||
 | 
					           && _volsDao.getHypervisorType(volume.getId()) != HypervisorType.XenServer){
 | 
				
			||||||
 | 
					            throw new InvalidParameterValueException("Cloudstack currently only supports volumes marked as KVM or XenServer hypervisor for resize");
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (volume == null) {
 | 
				
			||||||
 | 
					            throw new InvalidParameterValueException("No such volume");
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (volume.getState() != Volume.State.Ready) {
 | 
				
			||||||
 | 
					            throw new InvalidParameterValueException("Volume should be in ready state before attempting a resize");
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (!volume.getVolumeType().equals(Volume.Type.DATADISK)) {
 | 
				
			||||||
 | 
					            throw new InvalidParameterValueException("Can only resize DATA volumes");
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        /* figure out whether or not a new disk offering or size parameter is required, get the correct size value */
 | 
				
			||||||
 | 
					        if (newDiskOffering == null) {
 | 
				
			||||||
 | 
					            if (diskOffering.isCustomized()) {
 | 
				
			||||||
 | 
					                newSize = cmd.getSize();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                if (newSize == null) {
 | 
				
			||||||
 | 
					                    throw new InvalidParameterValueException("new offering is of custom size, need to specify a size");
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                newSize = ( newSize << 30 );
 | 
				
			||||||
 | 
					            } else {
 | 
				
			||||||
 | 
					                throw new InvalidParameterValueException("current offering" + volume.getDiskOfferingId()  + " cannot be resized, need to specify a disk offering");
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if (newDiskOffering.getRemoved() != null || !DiskOfferingVO.Type.Disk.equals(newDiskOffering.getType())) {
 | 
				
			||||||
 | 
					                throw new InvalidParameterValueException("Disk offering ID is missing or invalid");
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if(diskOffering.getTags() != null) {
 | 
				
			||||||
 | 
					                if(!newDiskOffering.getTags().equals(diskOffering.getTags())){
 | 
				
			||||||
 | 
					                    throw new InvalidParameterValueException("Tags on new and old disk offerings must match");
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            } else if (newDiskOffering.getTags() != null ){
 | 
				
			||||||
 | 
					                throw new InvalidParameterValueException("There are no tags on current disk offering, new disk offering needs to have no tags");
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if (newDiskOffering.getDomainId() == null) {
 | 
				
			||||||
 | 
					                // do nothing as offering is public
 | 
				
			||||||
 | 
					            } else {
 | 
				
			||||||
 | 
					                _configMgr.checkDiskOfferingAccess(UserContext.current().getCaller(), newDiskOffering);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					 
 | 
				
			||||||
 | 
					            if (newDiskOffering.isCustomized()) {
 | 
				
			||||||
 | 
					                newSize = cmd.getSize();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                if (newSize == null) {
 | 
				
			||||||
 | 
					                    throw new InvalidParameterValueException("new offering is of custom size, need to specify a size");
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                newSize = ( newSize << 30 );
 | 
				
			||||||
 | 
					            } else {
 | 
				
			||||||
 | 
					                newSize = newDiskOffering.getDiskSize();
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (newSize == null) {
 | 
				
			||||||
 | 
					            throw new InvalidParameterValueException("could not detect a size parameter or fetch one from the diskofferingid parameter");
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (!validateVolumeSizeRange(newSize)) {
 | 
				
			||||||
 | 
					            throw new InvalidParameterValueException("Requested size out of range");
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        /* does the caller have the authority to act on this volume? */
 | 
				
			||||||
 | 
					        _accountMgr.checkAccess(UserContext.current().getCaller(), null, true, volume);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        UserVmVO userVm = _userVmDao.findById(volume.getInstanceId());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        StoragePool pool = _storagePoolDao.findById(volume.getPoolId());
 | 
				
			||||||
 | 
					        long currentSize = volume.getSize();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        /* lets make certain they (think they) know what they're doing if they 
 | 
				
			||||||
 | 
					        want to shrink, by forcing them to provide the shrinkok parameter. This will
 | 
				
			||||||
 | 
					        be checked again at the hypervisor level where we can see the actual disk size */
 | 
				
			||||||
 | 
					        if (currentSize > newSize && !shrinkOk) {
 | 
				
			||||||
 | 
					            throw new InvalidParameterValueException("Going from existing size of " + currentSize + " to size of " 
 | 
				
			||||||
 | 
					                      + newSize + " would shrink the volume, need to sign off by supplying the shrinkok parameter with value of true");
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        /* get a list of hosts to send the commands to, try the system the 
 | 
				
			||||||
 | 
					        associated vm is running on first, then the last known place it ran.
 | 
				
			||||||
 | 
					        If not attached to a userVm, we pass 'none' and resizevolume.sh is
 | 
				
			||||||
 | 
					        ok with that since it only needs the vm name to live resize */
 | 
				
			||||||
 | 
					        long[] hosts = null;
 | 
				
			||||||
 | 
					        String instanceName = "none";
 | 
				
			||||||
 | 
					        if (userVm != null) {
 | 
				
			||||||
 | 
					            instanceName = userVm.getInstanceName();
 | 
				
			||||||
 | 
					            if(userVm.getHostId() != null) {
 | 
				
			||||||
 | 
					                hosts = new long[] { userVm.getHostId() };
 | 
				
			||||||
 | 
					            } else if(userVm.getLastHostId() != null) {
 | 
				
			||||||
 | 
					                hosts = new long[] { userVm.getLastHostId() };
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            /*Xen only works offline, SR does not support VDI.resizeOnline*/
 | 
				
			||||||
 | 
					            if(_volsDao.getHypervisorType(volume.getId()) == HypervisorType.XenServer
 | 
				
			||||||
 | 
					               && ! userVm.getState().equals(State.Stopped)) {
 | 
				
			||||||
 | 
					                throw new InvalidParameterValueException("VM must be stopped or disk detached in order to resize with the Xen HV");
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        try {
 | 
				
			||||||
 | 
					            try {
 | 
				
			||||||
 | 
					                    stateTransitTo(volume, Volume.Event.ResizeRequested);
 | 
				
			||||||
 | 
					            } catch (NoTransitionException etrans) {
 | 
				
			||||||
 | 
					                    throw new CloudRuntimeException("Unable to change volume state for resize: " + etrans.toString());
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            ResizeVolumeCommand resizeCmd = new ResizeVolumeCommand(volume.getPath(), new StorageFilerTO(pool), 
 | 
				
			||||||
 | 
					                                                    currentSize, newSize, shrinkOk, instanceName);
 | 
				
			||||||
 | 
					            ResizeVolumeAnswer answer = (ResizeVolumeAnswer) sendToPool(pool, hosts, resizeCmd);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            /* need to fetch/store new volume size in database. This value comes from 
 | 
				
			||||||
 | 
					            hypervisor rather than trusting that a success means we have a volume of the 
 | 
				
			||||||
 | 
					            size we requested */
 | 
				
			||||||
 | 
					            if (answer != null && answer.getResult()) {
 | 
				
			||||||
 | 
					                long finalSize = answer.getNewSize();
 | 
				
			||||||
 | 
					                s_logger.debug("Resize: volume started at size " + currentSize + " and ended at size " + finalSize);
 | 
				
			||||||
 | 
					                volume.setSize(finalSize);
 | 
				
			||||||
 | 
					                if (newDiskOffering != null) {
 | 
				
			||||||
 | 
					                    volume.setDiskOfferingId(cmd.getNewDiskOfferingId());
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                _volsDao.update(volume.getId(), volume);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                success  = true;
 | 
				
			||||||
 | 
					                return volume;
 | 
				
			||||||
 | 
					            } else if (answer != null) {
 | 
				
			||||||
 | 
					                s_logger.debug("Resize: returned '" + answer.getDetails() + "'");
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        } catch (StorageUnavailableException e) {
 | 
				
			||||||
 | 
					            s_logger.debug("volume failed to resize: "+e);
 | 
				
			||||||
 | 
					            return null;
 | 
				
			||||||
 | 
					        } finally {
 | 
				
			||||||
 | 
					            if(success) {
 | 
				
			||||||
 | 
					                try {
 | 
				
			||||||
 | 
					                    stateTransitTo(volume, Volume.Event.OperationSucceeded);
 | 
				
			||||||
 | 
					                } catch (NoTransitionException etrans) {
 | 
				
			||||||
 | 
					                    throw new CloudRuntimeException("Failed to change volume state: " + etrans.toString());
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            } else {
 | 
				
			||||||
 | 
					                try {
 | 
				
			||||||
 | 
					                    stateTransitTo(volume, Volume.Event.OperationFailed);
 | 
				
			||||||
 | 
					                } catch (NoTransitionException etrans) {
 | 
				
			||||||
 | 
					                    throw new CloudRuntimeException("Failed to change volume state: " + etrans.toString());
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            } 
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        return null;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @Override
 | 
					    @Override
 | 
				
			||||||
    @DB
 | 
					    @DB
 | 
				
			||||||
    public boolean destroyVolume(VolumeVO volume) throws ConcurrentOperationException {
 | 
					    public boolean destroyVolume(VolumeVO volume) throws ConcurrentOperationException {
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										0
									
								
								setup/db/create-schema-view.sql
									
									
									
									
									
										
										
										Executable file → Normal file
									
								
							
							
						
						
									
										0
									
								
								setup/db/create-schema-view.sql
									
									
									
									
									
										
										
										Executable file → Normal file
									
								
							@ -54,12 +54,20 @@ class Services:
 | 
				
			|||||||
                                    "cpunumber": 1,
 | 
					                                    "cpunumber": 1,
 | 
				
			||||||
                                    "cpuspeed": 100,    # in MHz
 | 
					                                    "cpuspeed": 100,    # in MHz
 | 
				
			||||||
                                    "memory": 128,       # In MBs
 | 
					                                    "memory": 128,       # In MBs
 | 
				
			||||||
 | 
					                                    "storagetype": "local"
 | 
				
			||||||
                        },
 | 
					                        },
 | 
				
			||||||
                        "disk_offering": {
 | 
					                        "disk_offering": {
 | 
				
			||||||
                                    "displaytext": "Small",
 | 
					                                    "displaytext": "Small",
 | 
				
			||||||
                                    "name": "Small",
 | 
					                                    "name": "Small",
 | 
				
			||||||
 | 
					                                    "storagetype": "local",
 | 
				
			||||||
                                    "disksize": 1
 | 
					                                    "disksize": 1
 | 
				
			||||||
                        },
 | 
					                        },
 | 
				
			||||||
 | 
					                        'resized_disk_offering': {
 | 
				
			||||||
 | 
					                                    "displaytext": "Resized",
 | 
				
			||||||
 | 
					                                    "name": "Resized",
 | 
				
			||||||
 | 
					                                    "storagetype": "local",
 | 
				
			||||||
 | 
					                                    "disksize": 3
 | 
				
			||||||
 | 
					                        },
 | 
				
			||||||
                        "volume_offerings": {
 | 
					                        "volume_offerings": {
 | 
				
			||||||
                            0: {
 | 
					                            0: {
 | 
				
			||||||
                                "diskname": "TestDiskServ",
 | 
					                                "diskname": "TestDiskServ",
 | 
				
			||||||
@ -77,8 +85,8 @@ class Services:
 | 
				
			|||||||
                        "diskdevice": "/dev/xvdb",
 | 
					                        "diskdevice": "/dev/xvdb",
 | 
				
			||||||
                        "ostype": 'CentOS 5.3 (64-bit)',
 | 
					                        "ostype": 'CentOS 5.3 (64-bit)',
 | 
				
			||||||
                        "mode": 'basic',
 | 
					                        "mode": 'basic',
 | 
				
			||||||
                        "sleep": 60,
 | 
					                        "sleep": 10,
 | 
				
			||||||
                        "timeout": 10,
 | 
					                        "timeout": 600,
 | 
				
			||||||
                    }
 | 
					                    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -237,7 +245,7 @@ class TestCreateVolume(cloudstackTestCase):
 | 
				
			|||||||
                ssh = self.virtual_machine.get_ssh_client(
 | 
					                ssh = self.virtual_machine.get_ssh_client(
 | 
				
			||||||
                                                      reconnect=True
 | 
					                                                      reconnect=True
 | 
				
			||||||
                                                      )
 | 
					                                                      )
 | 
				
			||||||
                c = "fdisk -l"
 | 
					                c = "/sbin/fdisk -l"
 | 
				
			||||||
                res = ssh.execute(c)
 | 
					                res = ssh.execute(c)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            except Exception as e:
 | 
					            except Exception as e:
 | 
				
			||||||
@ -283,6 +291,16 @@ class TestVolumes(cloudstackTestCase):
 | 
				
			|||||||
                                    cls.api_client,
 | 
					                                    cls.api_client,
 | 
				
			||||||
                                    cls.services["disk_offering"]
 | 
					                                    cls.services["disk_offering"]
 | 
				
			||||||
                                    )
 | 
					                                    )
 | 
				
			||||||
 | 
					        cls.resized_disk_offering = DiskOffering.create(
 | 
				
			||||||
 | 
					                                    cls.api_client,
 | 
				
			||||||
 | 
					                                    cls.services["resized_disk_offering"]
 | 
				
			||||||
 | 
					                                    )
 | 
				
			||||||
 | 
					        cls.custom_resized_disk_offering = DiskOffering.create(
 | 
				
			||||||
 | 
					                                    cls.api_client,
 | 
				
			||||||
 | 
					                                    cls.services["resized_disk_offering"],
 | 
				
			||||||
 | 
					                                    custom=True
 | 
				
			||||||
 | 
					                                    )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        template = get_template(
 | 
					        template = get_template(
 | 
				
			||||||
                            cls.api_client,
 | 
					                            cls.api_client,
 | 
				
			||||||
                            cls.zone.id,
 | 
					                            cls.zone.id,
 | 
				
			||||||
@ -292,6 +310,8 @@ class TestVolumes(cloudstackTestCase):
 | 
				
			|||||||
        cls.services["zoneid"] = cls.zone.id
 | 
					        cls.services["zoneid"] = cls.zone.id
 | 
				
			||||||
        cls.services["template"] = template.id
 | 
					        cls.services["template"] = template.id
 | 
				
			||||||
        cls.services["diskofferingid"] = cls.disk_offering.id
 | 
					        cls.services["diskofferingid"] = cls.disk_offering.id
 | 
				
			||||||
 | 
					        cls.services['resizeddiskofferingid'] = cls.resized_disk_offering.id
 | 
				
			||||||
 | 
					        cls.services['customresizeddiskofferingid'] = cls.custom_resized_disk_offering.id
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        # Create VMs, VMs etc
 | 
					        # Create VMs, VMs etc
 | 
				
			||||||
        cls.account = Account.create(
 | 
					        cls.account = Account.create(
 | 
				
			||||||
@ -321,6 +341,8 @@ class TestVolumes(cloudstackTestCase):
 | 
				
			|||||||
                                   domainid=cls.account.account.domainid
 | 
					                                   domainid=cls.account.account.domainid
 | 
				
			||||||
                                   )
 | 
					                                   )
 | 
				
			||||||
        cls._cleanup = [
 | 
					        cls._cleanup = [
 | 
				
			||||||
 | 
					                        cls.resized_disk_offering,
 | 
				
			||||||
 | 
					                        cls.custom_resized_disk_offering,
 | 
				
			||||||
                        cls.service_offering,
 | 
					                        cls.service_offering,
 | 
				
			||||||
                        cls.disk_offering,
 | 
					                        cls.disk_offering,
 | 
				
			||||||
                        cls.account
 | 
					                        cls.account
 | 
				
			||||||
@ -500,7 +522,102 @@ class TestVolumes(cloudstackTestCase):
 | 
				
			|||||||
            )
 | 
					            )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @attr(tags = ["advanced", "advancedns", "smoke"])
 | 
					    @attr(tags = ["advanced", "advancedns", "smoke"])
 | 
				
			||||||
    def test_07_delete_detached_volume(self):
 | 
					    def test_07_resize_fail(self):
 | 
				
			||||||
 | 
					        """Verify invalid options fail to Resize a volume"""
 | 
				
			||||||
 | 
					        # Verify the size is the new size is what we wanted it to be.
 | 
				
			||||||
 | 
					        self.debug("Fail Resize Volume ID: %s" % self.volume.id)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        # first, an invalid id
 | 
				
			||||||
 | 
					        cmd                = resizeVolume.resizeVolumeCmd()
 | 
				
			||||||
 | 
					        cmd.id             = "invalid id"
 | 
				
			||||||
 | 
					        cmd.diskofferingid = self.services['resizeddiskofferingid']
 | 
				
			||||||
 | 
					        success            = False
 | 
				
			||||||
 | 
					        try:
 | 
				
			||||||
 | 
					            response = self.apiClient.resizeVolume(cmd)
 | 
				
			||||||
 | 
					        except Exception as ex:
 | 
				
			||||||
 | 
					            if str(ex) == "HTTP Error 431: 431":
 | 
				
			||||||
 | 
					                success = True
 | 
				
			||||||
 | 
					        self.assertEqual(success, True, "ResizeVolume - verify invalid id is handled appropriately")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        # Next, we'll try an invalid disk offering id
 | 
				
			||||||
 | 
					        cmd.id             = self.volume.id
 | 
				
			||||||
 | 
					        cmd.diskofferingid = "invalid id"
 | 
				
			||||||
 | 
					        success            = False
 | 
				
			||||||
 | 
					        try:
 | 
				
			||||||
 | 
					            response = self.apiClient.resizeVolume(cmd)
 | 
				
			||||||
 | 
					        except Exception as ex:
 | 
				
			||||||
 | 
					            if "need to specify a disk offering" in str(ex):
 | 
				
			||||||
 | 
					                success = True
 | 
				
			||||||
 | 
					        self.assertEqual(success, True, "ResizeVolume - verify disk offering is handled appropriately")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        # Ok, now let's try and resize a volume that is not custom.
 | 
				
			||||||
 | 
					        cmd.id             = self.volume.id
 | 
				
			||||||
 | 
					        cmd.diskofferingid = self.services['diskofferingid']
 | 
				
			||||||
 | 
					        cmd.size           = 4
 | 
				
			||||||
 | 
					        currentSize        = self.volume.size
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.apiClient.resizeVolume(cmd)
 | 
				
			||||||
 | 
					        count = 0
 | 
				
			||||||
 | 
					        success = True
 | 
				
			||||||
 | 
					        while count < 10:
 | 
				
			||||||
 | 
					            list_volume_response = list_volumes(
 | 
				
			||||||
 | 
					                                                self.apiClient,
 | 
				
			||||||
 | 
					                                                id=self.volume.id,
 | 
				
			||||||
 | 
					                                                type='DATADISK'
 | 
				
			||||||
 | 
					                                                )
 | 
				
			||||||
 | 
					            for vol in list_volume_response:
 | 
				
			||||||
 | 
					                if vol.id == self.volume.id and vol.size != currentSize:
 | 
				
			||||||
 | 
					                    success = False
 | 
				
			||||||
 | 
					            if success:
 | 
				
			||||||
 | 
					                break
 | 
				
			||||||
 | 
					            else:
 | 
				
			||||||
 | 
					                time.sleep(1)
 | 
				
			||||||
 | 
					                count += 1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.assertEqual(
 | 
				
			||||||
 | 
					                         success,
 | 
				
			||||||
 | 
					                         True,
 | 
				
			||||||
 | 
					                         "Verify the volume did not resize"
 | 
				
			||||||
 | 
					                         )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @attr(tags = ["advanced", "advancedns", "smoke"])
 | 
				
			||||||
 | 
					    def test_08_resize_volume(self):
 | 
				
			||||||
 | 
					        """Resize a volume"""
 | 
				
			||||||
 | 
					        # Verify the size is the new size is what we wanted it to be.
 | 
				
			||||||
 | 
					        self.debug("Resize Volume ID: %s" % self.volume.id)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        cmd                = resizeVolume.resizeVolumeCmd()
 | 
				
			||||||
 | 
					        cmd.id             = self.volume.id
 | 
				
			||||||
 | 
					        cmd.diskofferingid = self.services['resizeddiskofferingid']
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.apiClient.resizeVolume(cmd)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        count = 0
 | 
				
			||||||
 | 
					        success = False
 | 
				
			||||||
 | 
					        while count < 3:
 | 
				
			||||||
 | 
					            list_volume_response = list_volumes(
 | 
				
			||||||
 | 
					                                                self.apiClient,
 | 
				
			||||||
 | 
					                                                id=self.volume.id,
 | 
				
			||||||
 | 
					                                                type='DATADISK'
 | 
				
			||||||
 | 
					                                                )
 | 
				
			||||||
 | 
					            for vol in list_volume_response:
 | 
				
			||||||
 | 
					                if vol.id == self.volume.id and vol.size == 3221225472L:
 | 
				
			||||||
 | 
					                    success = True
 | 
				
			||||||
 | 
					            if success:
 | 
				
			||||||
 | 
					                break
 | 
				
			||||||
 | 
					            else:
 | 
				
			||||||
 | 
					                time.sleep(10)
 | 
				
			||||||
 | 
					                count += 1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.assertEqual(
 | 
				
			||||||
 | 
					                         success,
 | 
				
			||||||
 | 
					                         True,
 | 
				
			||||||
 | 
					                         "Check if the volume resized appropriately"
 | 
				
			||||||
 | 
					                         )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @attr(tags = ["advanced", "advancedns", "smoke"])
 | 
				
			||||||
 | 
					    def test_09_delete_detached_volume(self):
 | 
				
			||||||
        """Delete a Volume unattached to an VM
 | 
					        """Delete a Volume unattached to an VM
 | 
				
			||||||
        """
 | 
					        """
 | 
				
			||||||
        # Validate the following
 | 
					        # Validate the following
 | 
				
			||||||
 | 
				
			|||||||
@ -509,6 +509,12 @@ class Volume:
 | 
				
			|||||||
        [setattr(cmd, k, v) for k, v in kwargs.items()]
 | 
					        [setattr(cmd, k, v) for k, v in kwargs.items()]
 | 
				
			||||||
        return(apiclient.listVolumes(cmd))
 | 
					        return(apiclient.listVolumes(cmd))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def resize(cls, apiclient, **kwargs):
 | 
				
			||||||
 | 
					        """Resize a volume"""
 | 
				
			||||||
 | 
					        cmd = resizeVolume.resizeVolumeCmd()
 | 
				
			||||||
 | 
					        cmd.id = self.id
 | 
				
			||||||
 | 
					        [setattr(cmd, k, v) for k, v in kwargs.items()]
 | 
				
			||||||
 | 
					        return(apiclient.resizeVolume(cmd))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class Snapshot:
 | 
					class Snapshot:
 | 
				
			||||||
    """Manage Snapshot Lifecycle
 | 
					    """Manage Snapshot Lifecycle
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user