Skip to content

Commit 2c53ede

Browse files
Harikrishna PatnalaKishan Kavala
authored andcommitted
CLOUDSTACK-3848: Usage events for dynamic scaling of cpu/ram operation on VM
1 parent fee7a86 commit 2c53ede

6 files changed

Lines changed: 154 additions & 37 deletions

File tree

api/src/com/cloud/event/EventTypes.java

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ public class EventTypes {
7070
public static final String EVENT_VM_REBOOT = "VM.REBOOT";
7171
public static final String EVENT_VM_UPDATE = "VM.UPDATE";
7272
public static final String EVENT_VM_UPGRADE = "VM.UPGRADE";
73-
public static final String EVENT_VM_SCALE = "VM.SCALE";
73+
public static final String EVENT_VM_DYNAMIC_SCALE = "VM.DYNAMIC.SCALE";
7474
public static final String EVENT_VM_RESETPASSWORD = "VM.RESETPASSWORD";
7575
public static final String EVENT_VM_RESETSSHKEY = "VM.RESETSSHKEY";
7676
public static final String EVENT_VM_MIGRATE = "VM.MIGRATE";
@@ -93,7 +93,6 @@ public class EventTypes {
9393
public static final String EVENT_PROXY_STOP = "PROXY.STOP";
9494
public static final String EVENT_PROXY_REBOOT = "PROXY.REBOOT";
9595
public static final String EVENT_PROXY_HA = "PROXY.HA";
96-
public static final String EVENT_PROXY_SCALE = "PROXY.SCALE";
9796

9897

9998
// VNC Console Events
@@ -218,7 +217,6 @@ public class EventTypes {
218217
public static final String EVENT_SSVM_STOP = "SSVM.STOP";
219218
public static final String EVENT_SSVM_REBOOT = "SSVM.REBOOT";
220219
public static final String EVENT_SSVM_HA = "SSVM.HA";
221-
public static final String EVENT_SSVM_SCALE = "SSVM.SCALE";
222220

223221
// Service Offerings
224222
public static final String EVENT_SERVICE_OFFERING_CREATE = "SERVICE.OFFERING.CREATE";

api/src/org/apache/cloudstack/api/command/admin/systemvm/ScaleSystemVMCmd.java

Lines changed: 3 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -111,23 +111,17 @@ public void execute(){
111111
response.setResponseName(getCommandName());
112112
this.setResponseObject(response);
113113
} else {
114-
throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Failed to scale system vm");
114+
throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Failed to upgrade system vm");
115115
}
116116
}
117117

118118
@Override
119119
public String getEventType() {
120-
VirtualMachine.Type type = _mgr.findSystemVMTypeById(getId());
121-
if(type == VirtualMachine.Type.ConsoleProxy){
122-
return EventTypes.EVENT_PROXY_SCALE;
123-
}
124-
else{
125-
return EventTypes.EVENT_SSVM_SCALE;
126-
}
120+
return EventTypes.EVENT_VM_UPGRADE;
127121
}
128122

129123
@Override
130124
public String getEventDescription() {
131-
return "scaling system vm: " + getId() + " to service offering: " + getServiceOfferingId();
125+
return "Upgrading system vm: " + getId() + " to service offering: " + getServiceOfferingId();
132126
}
133127
}

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

Lines changed: 10 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -86,9 +86,18 @@ public long getEntityOwnerId() {
8686
return Account.ACCOUNT_ID_SYSTEM; // no account info given, parent this command to SYSTEM so ERROR events are tracked
8787
}
8888

89+
@Override
90+
public String getEventType() {
91+
return EventTypes.EVENT_VM_UPGRADE;
92+
}
93+
94+
@Override
95+
public String getEventDescription() {
96+
return "upgrading vm: " + getId() + " to service offering: " + getServiceOfferingId();
97+
}
98+
8999
@Override
90100
public void execute(){
91-
//UserContext.current().setEventDetails("Vm Id: "+getId());
92101
UserVm result;
93102
try {
94103
result = _userVmService.upgradeVirtualMachine(this);
@@ -114,14 +123,4 @@ public void execute(){
114123
throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Failed to scale vm");
115124
}
116125
}
117-
118-
@Override
119-
public String getEventType() {
120-
return EventTypes.EVENT_VM_SCALE;
121-
}
122-
123-
@Override
124-
public String getEventDescription() {
125-
return "scaling volume: " + getId() + " to service offering: " + getServiceOfferingId();
126-
}
127126
}

server/src/com/cloud/server/ManagementServerImpl.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3202,6 +3202,7 @@ public ArrayList<String> getCloudIdentifierResponse(long userId) {
32023202
public Map<String, Object> listCapabilities(ListCapabilitiesCmd cmd) {
32033203
Map<String, Object> capabilities = new HashMap<String, Object>();
32043204

3205+
Account caller = CallContext.current().getCallingAccount();
32053206
boolean securityGroupsEnabled = false;
32063207
boolean elasticLoadBalancerEnabled = false;
32073208
String supportELB = "false";
@@ -3729,6 +3730,7 @@ public HypervisorCapabilities updateHypervisorCapabilities(Long id, Long maxGues
37293730
}
37303731

37313732
@Override
3733+
@ActionEvent(eventType = EventTypes.EVENT_VM_UPGRADE, eventDescription = "Upgrading system VM", async = true)
37323734
public VirtualMachine upgradeSystemVM(ScaleSystemVMCmd cmd) throws ResourceUnavailableException, ManagementServerException, VirtualMachineMigrationException, ConcurrentOperationException {
37333735

37343736
VMInstanceVO vmInstance = _vmInstanceDao.findById(cmd.getId());
@@ -3740,7 +3742,7 @@ public VirtualMachine upgradeSystemVM(ScaleSystemVMCmd cmd) throws ResourceUnava
37403742
VirtualMachine vm = _vmInstanceDao.findById(cmd.getId());
37413743
return vm;
37423744
}else{
3743-
return null;
3745+
throw new CloudRuntimeException("Failed to upgrade System VM");
37443746
}
37453747
}
37463748

server/src/com/cloud/vm/UserVmManagerImpl.java

Lines changed: 92 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -758,14 +758,10 @@ private UserVm rebootVirtualMachine(long userId, long vmId)
758758
/*
759759
* TODO: cleanup eventually - Refactored API call
760760
*/
761+
// This method will be deprecated as we use ScaleVMCmd for both stopped VMs and running VMs
761762
public UserVm upgradeVirtualMachine(UpgradeVMCmd cmd) throws ResourceAllocationException {
762763
Long vmId = cmd.getId();
763764
Long svcOffId = cmd.getServiceOfferingId();
764-
return upgradeStoppedVirtualMachine(vmId, svcOffId);
765-
}
766-
767-
768-
private UserVm upgradeStoppedVirtualMachine(Long vmId, Long svcOffId) throws ResourceAllocationException {
769765
Account caller = CallContext.current().getCallingAccount();
770766

771767
// Verify input parameters
@@ -831,6 +827,70 @@ private UserVm upgradeStoppedVirtualMachine(Long vmId, Long svcOffId) throws Res
831827
vmInstance.getServiceOfferingId(), vmInstance.getTemplateId(), vmInstance.getHypervisorType().toString(), VirtualMachine.class.getName(), vmInstance.getUuid());
832828

833829
return _vmDao.findById(vmInstance.getId());
830+
}
831+
832+
private UserVm upgradeStoppedVirtualMachine(Long vmId, Long svcOffId) throws ResourceAllocationException {
833+
Account caller = CallContext.current().getCallingAccount();
834+
835+
// Verify input parameters
836+
//UserVmVO vmInstance = _vmDao.findById(vmId);
837+
VMInstanceVO vmInstance = _vmInstanceDao.findById(vmId);
838+
if (vmInstance == null) {
839+
throw new InvalidParameterValueException(
840+
"unable to find a virtual machine with id " + vmId);
841+
}
842+
843+
_accountMgr.checkAccess(caller, null, true, vmInstance);
844+
845+
// Check resource limits for CPU and Memory.
846+
ServiceOfferingVO newServiceOffering = _offeringDao.findById(svcOffId);
847+
ServiceOfferingVO currentServiceOffering = _offeringDao.findByIdIncludingRemoved(vmInstance.getServiceOfferingId());
848+
849+
int newCpu = newServiceOffering.getCpu();
850+
int newMemory = newServiceOffering.getRamSize();
851+
int currentCpu = currentServiceOffering.getCpu();
852+
int currentMemory = currentServiceOffering.getRamSize();
853+
854+
if (newCpu > currentCpu) {
855+
_resourceLimitMgr.checkResourceLimit(caller, ResourceType.cpu,
856+
newCpu - currentCpu);
857+
}
858+
if (newMemory > currentMemory) {
859+
_resourceLimitMgr.checkResourceLimit(caller, ResourceType.memory,
860+
newMemory - currentMemory);
861+
}
862+
863+
// Check that the specified service offering ID is valid
864+
_itMgr.checkIfCanUpgrade(vmInstance, svcOffId);
865+
866+
// remove diskAndMemory VM snapshots
867+
List<VMSnapshotVO> vmSnapshots = _vmSnapshotDao.findByVm(vmId);
868+
for (VMSnapshotVO vmSnapshotVO : vmSnapshots) {
869+
if(vmSnapshotVO.getType() == VMSnapshot.Type.DiskAndMemory){
870+
if(!_vmSnapshotMgr.deleteAllVMSnapshots(vmId, VMSnapshot.Type.DiskAndMemory)){
871+
String errMsg = "Failed to remove VM snapshot during upgrading, snapshot id " + vmSnapshotVO.getId();
872+
s_logger.debug(errMsg);
873+
throw new CloudRuntimeException(errMsg);
874+
}
875+
876+
}
877+
}
878+
879+
_itMgr.upgradeVmDb(vmId, svcOffId);
880+
881+
// Increment or decrement CPU and Memory count accordingly.
882+
if (newCpu > currentCpu) {
883+
_resourceLimitMgr.incrementResourceCount(caller.getAccountId(), ResourceType.cpu, new Long (newCpu - currentCpu));
884+
} else if (currentCpu > newCpu) {
885+
_resourceLimitMgr.decrementResourceCount(caller.getAccountId(), ResourceType.cpu, new Long (currentCpu - newCpu));
886+
}
887+
if (newMemory > currentMemory) {
888+
_resourceLimitMgr.incrementResourceCount(caller.getAccountId(), ResourceType.memory, new Long (newMemory - currentMemory));
889+
} else if (currentMemory > newMemory) {
890+
_resourceLimitMgr.decrementResourceCount(caller.getAccountId(), ResourceType.memory, new Long (currentMemory - newMemory));
891+
}
892+
893+
return _vmDao.findById(vmInstance.getId());
834894

835895
}
836896

@@ -1083,17 +1143,30 @@ public UserVm updateDefaultNicForVirtualMachine(UpdateDefaultNicForVMCmd cmd) th
10831143
}
10841144

10851145
@Override
1086-
@ActionEvent(eventType = EventTypes.EVENT_VM_SCALE, eventDescription = "scaling Vm")
1146+
@ActionEvent(eventType = EventTypes.EVENT_VM_UPGRADE, eventDescription = "Upgrading VM", async = true)
10871147
public UserVm
10881148
upgradeVirtualMachine(ScaleVMCmd cmd) throws ResourceUnavailableException, ConcurrentOperationException, ManagementServerException, VirtualMachineMigrationException{
10891149

10901150
Long vmId = cmd.getId();
10911151
Long newServiceOfferingId = cmd.getServiceOfferingId();
1152+
CallContext.current().setEventDetails("Vm Id: " + vmId);
1153+
10921154
boolean result = upgradeVirtualMachine(vmId, newServiceOfferingId);
10931155
if(result){
1094-
return _vmDao.findById(vmId);
1095-
}else{
1096-
return null;
1156+
UserVmVO vmInstance = _vmDao.findById(vmId);
1157+
if(vmInstance.getState().equals(State.Stopped)){
1158+
// Generate usage event for VM upgrade
1159+
UsageEventUtils.publishUsageEvent(EventTypes.EVENT_VM_UPGRADE, vmInstance.getAccountId(), vmInstance.getDataCenterId(), vmInstance.getId(), vmInstance.getHostName(),
1160+
vmInstance.getServiceOfferingId(), vmInstance.getTemplateId(), vmInstance.getHypervisorType().toString(), VirtualMachine.class.getName(), vmInstance.getUuid());
1161+
}
1162+
if(vmInstance.getState().equals(State.Running)){
1163+
// Generate usage event for Dynamic scaling of VM
1164+
UsageEventUtils.publishUsageEvent(EventTypes.EVENT_VM_DYNAMIC_SCALE, vmInstance.getAccountId(), vmInstance.getDataCenterId(), vmInstance.getId(), vmInstance.getHostName(),
1165+
vmInstance.getServiceOfferingId(), vmInstance.getTemplateId(), vmInstance.getHypervisorType().toString(), VirtualMachine.class.getName(), vmInstance.getUuid());
1166+
}
1167+
return vmInstance;
1168+
} else {
1169+
throw new CloudRuntimeException("Failed to scale the VM");
10971170
}
10981171

10991172
}
@@ -1135,7 +1208,6 @@ public HashMap<Long, List<VmDiskStatsEntry>> getVmDiskStatistics(long hostId, St
11351208

11361209
@Override
11371210
public boolean upgradeVirtualMachine(Long vmId, Long newServiceOfferingId) throws ResourceUnavailableException, ConcurrentOperationException, ManagementServerException, VirtualMachineMigrationException{
1138-
Account caller = CallContext.current().getCallingAccount();
11391211

11401212
// Verify input parameters
11411213
VMInstanceVO vmInstance = _vmInstanceDao.findById(vmId);
@@ -1144,7 +1216,16 @@ public boolean upgradeVirtualMachine(Long vmId, Long newServiceOfferingId) throw
11441216
upgradeStoppedVirtualMachine(vmId, newServiceOfferingId);
11451217
return true;
11461218
}
1219+
if(vmInstance.getState().equals(State.Running)){
1220+
return upgradeRunningVirtualMachine(vmId, newServiceOfferingId);
1221+
}
1222+
return false;
1223+
}
11471224

1225+
private boolean upgradeRunningVirtualMachine(Long vmId, Long newServiceOfferingId) throws ResourceUnavailableException, ConcurrentOperationException, ManagementServerException, VirtualMachineMigrationException{
1226+
1227+
Account caller = CallContext.current().getCallingAccount();
1228+
VMInstanceVO vmInstance = _vmInstanceDao.findById(vmId);
11481229
if(vmInstance.getHypervisorType() != HypervisorType.XenServer && vmInstance.getHypervisorType() != HypervisorType.VMware){
11491230
throw new InvalidParameterValueException("This operation not permitted for this hypervisor of the vm");
11501231
}
@@ -1237,13 +1318,11 @@ public boolean upgradeVirtualMachine(Long vmId, Long newServiceOfferingId) throw
12371318
// Decrement CPU and Memory count accordingly.
12381319
if (newCpu > currentCpu) {
12391320
_resourceLimitMgr.decrementResourceCount(caller.getAccountId(), ResourceType.cpu, new Long (newCpu - currentCpu));
1240-
}
1321+
}
12411322
if (newMemory > currentMemory) {
12421323
_resourceLimitMgr.decrementResourceCount(caller.getAccountId(), ResourceType.memory, new Long (newMemory - currentMemory));
12431324
}
12441325
}
1245-
1246-
12471326
}
12481327
}
12491328
}

usage/src/com/cloud/usage/UsageManagerImpl.java

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1080,6 +1080,51 @@ private void createVMHelperEvent(UsageEventVO event) {
10801080
UsageVMInstanceVO usageInstanceNew = new UsageVMInstanceVO(UsageTypes.ALLOCATED_VM, zoneId, event.getAccountId(), vmId, vmName,
10811081
soId, templateId, hypervisorType, event.getCreateDate(), null);
10821082
m_usageInstanceDao.persist(usageInstanceNew);
1083+
} else if (EventTypes.EVENT_VM_DYNAMIC_SCALE.equals(event.getType())) {
1084+
// Ending the running vm event
1085+
SearchCriteria<UsageVMInstanceVO> sc = m_usageInstanceDao.createSearchCriteria();
1086+
sc.addAnd("vmInstanceId", SearchCriteria.Op.EQ, Long.valueOf(vmId));
1087+
sc.addAnd("endDate", SearchCriteria.Op.NULL);
1088+
sc.addAnd("usageType", SearchCriteria.Op.EQ, UsageTypes.RUNNING_VM);
1089+
List<UsageVMInstanceVO> usageInstances = m_usageInstanceDao.search(sc, null);
1090+
if (usageInstances != null) {
1091+
if (usageInstances.size() > 1) {
1092+
s_logger.warn("found multiple entries for a vm running with id: " + vmId + ", ending them all...");
1093+
}
1094+
for (UsageVMInstanceVO usageInstance : usageInstances) {
1095+
usageInstance.setEndDate(event.getCreateDate());
1096+
m_usageInstanceDao.update(usageInstance);
1097+
}
1098+
}
1099+
1100+
sc = m_usageInstanceDao.createSearchCriteria();
1101+
sc.addAnd("vmInstanceId", SearchCriteria.Op.EQ, Long.valueOf(vmId));
1102+
sc.addAnd("endDate", SearchCriteria.Op.NULL);
1103+
sc.addAnd("usageType", SearchCriteria.Op.EQ, UsageTypes.ALLOCATED_VM);
1104+
usageInstances = m_usageInstanceDao.search(sc, null);
1105+
if (usageInstances == null || (usageInstances.size() == 0)) {
1106+
s_logger.error("Cannot find allocated vm entry for a vm running with id: " + vmId);
1107+
} else if (usageInstances.size() == 1) {
1108+
UsageVMInstanceVO usageInstance = usageInstances.get(0);
1109+
if(usageInstance.getSerivceOfferingId() != soId){
1110+
//Service Offering changed after Vm creation
1111+
//End current Allocated usage and create new Allocated Vm entry with new soId
1112+
usageInstance.setEndDate(event.getCreateDate());
1113+
m_usageInstanceDao.update(usageInstance);
1114+
usageInstance.setServiceOfferingId(soId);
1115+
usageInstance.setStartDate(event.getCreateDate());
1116+
usageInstance.setEndDate(null);
1117+
m_usageInstanceDao.persist(usageInstance);
1118+
}
1119+
}
1120+
1121+
Long templateId = event.getTemplateId();
1122+
String hypervisorType = event.getResourceType();
1123+
1124+
// add this VM to the usage helper table with new service offering Id
1125+
UsageVMInstanceVO usageInstanceNew = new UsageVMInstanceVO(UsageTypes.RUNNING_VM, zoneId, event.getAccountId(), vmId, vmName,
1126+
soId, templateId, hypervisorType, event.getCreateDate(), null);
1127+
m_usageInstanceDao.persist(usageInstanceNew);
10831128
}
10841129
}
10851130

0 commit comments

Comments
 (0)