Skip to content

Commit b0caae6

Browse files
Vijayendra BhamidipatiPrasanna Santhanam
authored andcommitted
CLOUDSTACK-1086: DeployVirtualMachine userdata enhancements
Description: Currently, userdata sent over to the DeployVMCmd and updateVMCmd commands can be upto 2K in length, whether sent over GET or POST. We remove this limitation for POST to change this limit to 32K. Also enabling lazy load on userdata to improve performance during reads of large sized userdata from user VM records. Signed-off-by: Min Chen <min.chen@citrix.com>
1 parent 94d5d3d commit b0caae6

File tree

16 files changed

+501
-134
lines changed

16 files changed

+501
-134
lines changed

api/src/com/cloud/vm/UserVmService.java

Lines changed: 20 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -21,9 +21,22 @@
2121

2222
import javax.naming.InsufficientResourcesException;
2323

24+
import org.apache.cloudstack.api.BaseCmd.HTTPMethod;
2425
import org.apache.cloudstack.api.command.admin.vm.AssignVMCmd;
2526
import org.apache.cloudstack.api.command.admin.vm.RecoverVMCmd;
26-
import org.apache.cloudstack.api.command.user.vm.*;
27+
import org.apache.cloudstack.api.command.user.vm.AddNicToVMCmd;
28+
import org.apache.cloudstack.api.command.user.vm.DeployVMCmd;
29+
import org.apache.cloudstack.api.command.user.vm.DestroyVMCmd;
30+
import org.apache.cloudstack.api.command.user.vm.RebootVMCmd;
31+
import org.apache.cloudstack.api.command.user.vm.RemoveNicFromVMCmd;
32+
import org.apache.cloudstack.api.command.user.vm.ResetVMPasswordCmd;
33+
import org.apache.cloudstack.api.command.user.vm.ResetVMSSHKeyCmd;
34+
import org.apache.cloudstack.api.command.user.vm.RestoreVMCmd;
35+
import org.apache.cloudstack.api.command.user.vm.ScaleVMCmd;
36+
import org.apache.cloudstack.api.command.user.vm.StartVMCmd;
37+
import org.apache.cloudstack.api.command.user.vm.UpdateDefaultNicForVMCmd;
38+
import org.apache.cloudstack.api.command.user.vm.UpdateVMCmd;
39+
import org.apache.cloudstack.api.command.user.vm.UpgradeVMCmd;
2740
import org.apache.cloudstack.api.command.user.vmgroup.CreateVMGroupCmd;
2841
import org.apache.cloudstack.api.command.user.vmgroup.DeleteVMGroupCmd;
2942
import com.cloud.dc.DataCenter;
@@ -185,8 +198,8 @@ UserVm startVirtualMachine(StartVMCmd cmd) throws StorageUnavailableException, E
185198
*/
186199
UserVm createBasicSecurityGroupVirtualMachine(DataCenter zone, ServiceOffering serviceOffering, VirtualMachineTemplate template, List<Long> securityGroupIdList, Account owner, String hostName,
187200
String displayName, Long diskOfferingId, Long diskSize, String group, HypervisorType hypervisor,
188-
String userData, String sshKeyPair, Map<Long, IpAddresses> requestedIps, IpAddresses defaultIp,
189-
String keyboard, List<Long> affinityGroupIdList)
201+
HTTPMethod httpmethod, String userData, String sshKeyPair, Map<Long, IpAddresses> requestedIps,
202+
IpAddresses defaultIp, String keyboard, List<Long> affinityGroupIdList)
190203
throws InsufficientCapacityException, ConcurrentOperationException, ResourceUnavailableException, StorageUnavailableException, ResourceAllocationException;
191204

192205
/**
@@ -257,8 +270,8 @@ UserVm createBasicSecurityGroupVirtualMachine(DataCenter zone, ServiceOffering s
257270
* @throws InsufficientResourcesException
258271
*/
259272
UserVm createAdvancedSecurityGroupVirtualMachine(DataCenter zone, ServiceOffering serviceOffering, VirtualMachineTemplate template, List<Long> networkIdList, List<Long> securityGroupIdList,
260-
Account owner, String hostName, String displayName, Long diskOfferingId, Long diskSize, String group, HypervisorType hypervisor, String userData, String sshKeyPair, Map<Long, IpAddresses> requestedIps,
261-
IpAddresses defaultIps, String keyboard, List<Long> affinityGroupIdList)
273+
Account owner, String hostName, String displayName, Long diskOfferingId, Long diskSize, String group, HypervisorType hypervisor, HTTPMethod httpmethod, String userData, String sshKeyPair,
274+
Map<Long, IpAddresses> requestedIps, IpAddresses defaultIps, String keyboard, List<Long> affinityGroupIdList)
262275
throws InsufficientCapacityException, ConcurrentOperationException, ResourceUnavailableException, StorageUnavailableException, ResourceAllocationException;
263276

264277
/**
@@ -327,8 +340,8 @@ UserVm createAdvancedSecurityGroupVirtualMachine(DataCenter zone, ServiceOfferin
327340
*/
328341
UserVm createAdvancedVirtualMachine(DataCenter zone, ServiceOffering serviceOffering, VirtualMachineTemplate template, List<Long> networkIdList, Account owner, String hostName,
329342
String displayName, Long diskOfferingId, Long diskSize, String group, HypervisorType hypervisor,
330-
String userData, String sshKeyPair, Map<Long, IpAddresses> requestedIps, IpAddresses defaultIps,
331-
String keyboard, List<Long> affinityGroupIdList)
343+
HTTPMethod httpmethod, String userData, String sshKeyPair, Map<Long, IpAddresses> requestedIps,
344+
IpAddresses defaultIps, String keyboard, List<Long> affinityGroupIdList)
332345
throws InsufficientCapacityException, ConcurrentOperationException, ResourceUnavailableException, StorageUnavailableException, ResourceAllocationException;
333346

334347
/**

api/src/org/apache/cloudstack/api/BaseCmd.java

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,11 @@ public enum CommandType {
9595
private Object _responseObject = null;
9696
private Map<String, String> fullUrlParams;
9797

98+
public enum HTTPMethod {
99+
GET, POST, PUT, DELETE
100+
}
101+
private HTTPMethod httpMethod;
102+
98103
@Parameter(name = "response", type = CommandType.STRING)
99104
private String responseType;
100105

@@ -140,6 +145,25 @@ public enum CommandType {
140145
public void configure() {
141146
}
142147

148+
public HTTPMethod getHttpMethod() {
149+
return httpMethod;
150+
}
151+
152+
public void setHttpMethod(String method) {
153+
if (method != null) {
154+
if (method.equalsIgnoreCase("GET"))
155+
httpMethod = HTTPMethod.GET;
156+
else if (method.equalsIgnoreCase("PUT"))
157+
httpMethod = HTTPMethod.PUT;
158+
else if (method.equalsIgnoreCase("POST"))
159+
httpMethod = HTTPMethod.POST;
160+
else if (method.equalsIgnoreCase("DELETE"))
161+
httpMethod = HTTPMethod.DELETE;
162+
} else {
163+
httpMethod = HTTPMethod.GET;
164+
}
165+
}
166+
143167
public String getResponseType() {
144168
if (responseType == null) {
145169
return RESPONSE_TYPE_XML;

api/src/org/apache/cloudstack/api/command/user/vm/DeployVMCmd.java

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -128,7 +128,7 @@ public class DeployVMCmd extends BaseAsyncCreateCmd {
128128
@Parameter(name=ApiConstants.HYPERVISOR, type=CommandType.STRING, description="the hypervisor on which to deploy the virtual machine")
129129
private String hypervisor;
130130

131-
@Parameter(name=ApiConstants.USER_DATA, type=CommandType.STRING, description="an optional binary data that can be sent to the virtual machine upon a successful deployment. This binary data must be base64 encoded before adding it to the request. Currently only HTTP GET is supported. Using HTTP GET (via querystring), you can send up to 2KB of data after base64 encoding.", length=2048)
131+
@Parameter(name=ApiConstants.USER_DATA, type=CommandType.STRING, description="an optional binary data that can be sent to the virtual machine upon a successful deployment. This binary data must be base64 encoded before adding it to the request. Using HTTP GET (via querystring), you can send up to 2KB of data after base64 encoding. Using HTTP POST(via POST body), you can send up to 32K of data after base64 encoding.", length=32768)
132132
private String userData;
133133

134134
@Parameter(name=ApiConstants.SSH_KEYPAIR, type=CommandType.STRING, description="name of the ssh key pair used to login to the virtual machine")
@@ -312,8 +312,8 @@ private Map<Long, IpAddresses> getIpToNetworkMap() {
312312
throw new InvalidParameterValueException("Unable to translate and find entity with networkId: " + ips.get("networkid"));
313313
}
314314
}
315-
String requestedIp = (String) ips.get("ip");
316-
String requestedIpv6 = (String) ips.get("ipv6");
315+
String requestedIp = ips.get("ip");
316+
String requestedIpv6 = ips.get("ipv6");
317317
if (requestedIpv6 != null) {
318318
requestedIpv6 = requestedIpv6.toLowerCase();
319319
}
@@ -481,18 +481,18 @@ public void create() throws ResourceAllocationException{
481481
throw new InvalidParameterValueException("Can't specify network Ids in Basic zone");
482482
} else {
483483
vm = _userVmService.createBasicSecurityGroupVirtualMachine(zone, serviceOffering, template, getSecurityGroupIdList(), owner, name,
484-
displayName, diskOfferingId, size, group, getHypervisor(), userData, sshKeyPairName, getIpToNetworkMap(), addrs, keyboard, getAffinityGroupIdList());
484+
displayName, diskOfferingId, size, group, getHypervisor(), this.getHttpMethod(), userData, sshKeyPairName, getIpToNetworkMap(), addrs, keyboard, getAffinityGroupIdList());
485485
}
486486
} else {
487487
if (zone.isSecurityGroupEnabled()) {
488488
vm = _userVmService.createAdvancedSecurityGroupVirtualMachine(zone, serviceOffering, template, getNetworkIds(), getSecurityGroupIdList(),
489-
owner, name, displayName, diskOfferingId, size, group, getHypervisor(), userData, sshKeyPairName, getIpToNetworkMap(), addrs, keyboard, getAffinityGroupIdList());
489+
owner, name, displayName, diskOfferingId, size, group, getHypervisor(), this.getHttpMethod(), userData, sshKeyPairName, getIpToNetworkMap(), addrs, keyboard, getAffinityGroupIdList());
490490
} else {
491491
if (getSecurityGroupIdList() != null && !getSecurityGroupIdList().isEmpty()) {
492492
throw new InvalidParameterValueException("Can't create vm with security groups; security group feature is not enabled per zone");
493493
}
494494
vm = _userVmService.createAdvancedVirtualMachine(zone, serviceOffering, template, getNetworkIds(), owner, name, displayName,
495-
diskOfferingId, size, group, getHypervisor(), userData, sshKeyPairName, getIpToNetworkMap(), addrs, keyboard, getAffinityGroupIdList());
495+
diskOfferingId, size, group, getHypervisor(), this.getHttpMethod(), userData, sshKeyPairName, getIpToNetworkMap(), addrs, keyboard, getAffinityGroupIdList());
496496
}
497497
}
498498

api/src/org/apache/cloudstack/api/command/user/vm/UpdateVMCmd.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ public class UpdateVMCmd extends BaseCmd{
6161
description="the ID of the OS type that best represents this VM.")
6262
private Long osTypeId;
6363

64-
@Parameter(name=ApiConstants.USER_DATA, type=CommandType.STRING, description="an optional binary data that can be sent to the virtual machine upon a successful deployment. This binary data must be base64 encoded before adding it to the request. Currently only HTTP GET is supported. Using HTTP GET (via querystring), you can send up to 2KB of data after base64 encoding.", length=2048)
64+
@Parameter(name=ApiConstants.USER_DATA, type=CommandType.STRING, description="an optional binary data that can be sent to the virtual machine upon a successful deployment. This binary data must be base64 encoded before adding it to the request. Using HTTP GET (via querystring), you can send up to 2KB of data after base64 encoding. Using HTTP POST(via POST body), you can send up to 32K of data after base64 encoding.", length=32768)
6565
private String userData;
6666

6767

core/src/com/cloud/vm/UserVmVO.java

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,11 @@
1818

1919
import java.util.HashMap;
2020

21+
import javax.persistence.Basic;
2122
import javax.persistence.Column;
2223
import javax.persistence.DiscriminatorValue;
2324
import javax.persistence.Entity;
25+
import javax.persistence.FetchType;
2426
import javax.persistence.PrimaryKeyJoinColumn;
2527
import javax.persistence.Table;
2628

@@ -36,7 +38,8 @@ public class UserVmVO extends VMInstanceVO implements UserVm {
3638
@Column(name="iso_id", nullable=true, length=17)
3739
private Long isoId = null;
3840

39-
@Column(name="user_data", updatable=true, nullable=true, length=2048)
41+
@Column(name="user_data", updatable=true, nullable=true, length=32768)
42+
@Basic(fetch = FetchType.LAZY)
4043
private String userData;
4144

4245
@Column(name="display_name", updatable=true, nullable=true)
@@ -119,6 +122,7 @@ public String getDetail(String name) {
119122
return details != null ? details.get(name) : null;
120123
}
121124

125+
@Override
122126
public void setAccountId(long accountId){
123127
this.accountId = accountId;
124128
}

server/src/com/cloud/api/ApiDispatcher.java

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,6 @@
2727
import java.util.HashMap;
2828
import java.util.List;
2929
import java.util.Map;
30-
import java.util.Set;
3130
import java.util.StringTokenizer;
3231
import java.util.regex.Matcher;
3332

@@ -56,21 +55,14 @@
5655
import org.apache.log4j.Logger;
5756
import org.springframework.stereotype.Component;
5857

59-
import com.cloud.async.AsyncCommandQueued;
6058
import com.cloud.async.AsyncJobManager;
6159
import com.cloud.dao.EntityManager;
62-
import com.cloud.exception.AccountLimitException;
63-
import com.cloud.exception.InsufficientCapacityException;
6460
import com.cloud.exception.InvalidParameterValueException;
65-
import com.cloud.exception.PermissionDeniedException;
66-
import com.cloud.exception.ResourceAllocationException;
67-
import com.cloud.exception.ResourceUnavailableException;
6861
import com.cloud.user.Account;
6962
import com.cloud.user.AccountManager;
7063
import com.cloud.user.UserContext;
7164
import com.cloud.utils.DateUtil;
7265
import com.cloud.utils.ReflectUtil;
73-
import com.cloud.utils.component.ComponentContext;
7466
import com.cloud.utils.exception.CSExceptionErrorCode;
7567
import com.cloud.utils.exception.CloudRuntimeException;
7668

@@ -160,7 +152,6 @@ public void dispatch(BaseCmd cmd, Map<String, String> params) throws Exception {
160152
}
161153
}
162154
}
163-
164155
cmd.execute();
165156

166157
}

0 commit comments

Comments
 (0)