Skip to content

Instance lease: Allow deployment of instances with lease duration and leaseexpiry action #10560

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 23 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
d737cea
FR-248: Instance lease, WIP commit
sudo87 Feb 21, 2025
9bef279
insert lease expiry into db and use that to filter exiring vms, add a…
sudo87 Feb 22, 2025
759f1fa
Add leaseDuration and leaseExpiryAction in Service offering create flow
sudo87 Feb 24, 2025
8c7a9f2
Update listVM cmd to allow listing only leased instances
sudo87 Feb 24, 2025
1495b08
Add methods to fetch instances for which lease is expiring in next days
sudo87 Feb 24, 2025
e2da246
Changes included:
sudo87 Feb 25, 2025
0969bf0
Update UI screens for leased properties coming from config and servic…
sudo87 Feb 28, 2025
f239e92
use global lock before running scheduler
sudo87 Mar 1, 2025
e7ce8ae
Unit tests
sudo87 Mar 4, 2025
0cf2fe8
Flow changes done in UI based on discussion
sudo87 Mar 5, 2025
7bc5f2a
Include view changes in schema upgrade files and use feature in vario…
sudo87 Mar 5, 2025
aff544f
Added integration test for vm deployment, UI enhancements for user pe…
sudo87 Mar 6, 2025
62397cc
validate integration tests, minor ui changes and log messages
sudo87 Mar 13, 2025
faf484f
fix build: moving configkey from setup to test itself
sudo87 Mar 17, 2025
410a882
Disable testAlert to unblock build and trim whitespaces in integratio…
sudo87 Mar 17, 2025
f4aa2bc
Address review comments
sudo87 Mar 18, 2025
f77f3ab
Merge latest from main
sudo87 Mar 18, 2025
337401b
Minor changes in EditVM screen
sudo87 Mar 19, 2025
009e0b4
Use ExecutorService instead of Timer and TimerTask
sudo87 Mar 19, 2025
bd10721
Additional review comments
sudo87 Mar 22, 2025
78fc3e0
Incorporate following changes:
sudo87 Mar 27, 2025
b042167
Handle pr review comments
sudo87 Apr 7, 2025
89db8a2
merge latest changes from main
sudo87 Apr 7, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -164,7 +164,8 @@ jobs:
component/test_cpu_limits
component/test_cpu_max_limits
component/test_cpu_project_limits
component/test_deploy_vm_userdata_multi_nic",
component/test_deploy_vm_userdata_multi_nic
component/test_deploy_vm_lease",
"component/test_egress_fw_rules
component/test_invalid_gw_nm
component/test_ip_reservation",
Expand Down
11 changes: 11 additions & 0 deletions api/src/main/java/com/cloud/event/EventTypes.java
Original file line number Diff line number Diff line change
Expand Up @@ -795,6 +795,11 @@ public class EventTypes {
// Resource Limit
public static final String EVENT_RESOURCE_LIMIT_UPDATE = "RESOURCE.LIMIT.UPDATE";

public static final String VM_LEASE_EXPIRED = "VM.LEASE.EXPIRED";
public static final String VM_LEASE_DISABLED = "VM.LEASE.DISABLED";
public static final String VM_LEASE_CANCELLED = "VM.LEASE.CANCELLED";
public static final String VM_LEASE_EXPIRING = "VM.LEASE.EXPIRING";

static {

// TODO: need a way to force author adding event types to declare the entity details as well, with out braking
Expand Down Expand Up @@ -1289,6 +1294,12 @@ public class EventTypes {
entityEventDetails.put(EVENT_SHAREDFS_DESTROY, SharedFS.class);
entityEventDetails.put(EVENT_SHAREDFS_EXPUNGE, SharedFS.class);
entityEventDetails.put(EVENT_SHAREDFS_RECOVER, SharedFS.class);

// VM Lease
entityEventDetails.put(VM_LEASE_EXPIRED, VirtualMachine.class);
entityEventDetails.put(VM_LEASE_EXPIRING, VirtualMachine.class);
entityEventDetails.put(VM_LEASE_DISABLED, VirtualMachine.class);
entityEventDetails.put(VM_LEASE_CANCELLED, VirtualMachine.class);
}

public static boolean isNetworkEvent(String eventType) {
Expand Down
4 changes: 4 additions & 0 deletions api/src/main/java/com/cloud/vm/VmDetailConstants.java
Original file line number Diff line number Diff line change
Expand Up @@ -101,4 +101,8 @@ public interface VmDetailConstants {
String VMWARE_HOST_NAME = String.format("%s-host", VMWARE_TO_KVM_PREFIX);
String VMWARE_DISK = String.format("%s-disk", VMWARE_TO_KVM_PREFIX);
String VMWARE_MAC_ADDRESSES = String.format("%s-mac-addresses", VMWARE_TO_KVM_PREFIX);

String INSTANCE_LEASE_EXPIRY_DATE = "leaseexpirydate";
String INSTANCE_LEASE_EXPIRY_ACTION = "leaseexpiryaction";
String INSTANCE_LEASE_EXECUTION = "leaseactionexecution";
}
5 changes: 5 additions & 0 deletions api/src/main/java/org/apache/cloudstack/api/ApiConstants.java
Original file line number Diff line number Diff line change
Expand Up @@ -269,6 +269,7 @@ public class ApiConstants {
public static final String INTERNAL_DNS2 = "internaldns2";
public static final String INTERNET_PROTOCOL = "internetprotocol";
public static final String INTERVAL_TYPE = "intervaltype";
public static final String INSTANCE_LEASE_ENABLED = "instanceleaseenabled";
public static final String LOCATION_TYPE = "locationtype";
public static final String IOPS_READ_RATE = "iopsreadrate";
public static final String IOPS_READ_RATE_MAX = "iopsreadratemax";
Expand Down Expand Up @@ -520,6 +521,10 @@ public class ApiConstants {
public static final String USED_SUBNETS = "usedsubnets";
public static final String USED_IOPS = "usediops";
public static final String USER_DATA = "userdata";
public static final String INSTANCE_LEASE_DURATION = "leaseduration";
public static final String INSTANCE_LEASE_EXPIRY_DATE= "leaseexpirydate";
public static final String INSTANCE_LEASE_EXPIRY_ACTION = "leaseexpiryaction";
public static final String LEASED = "leased";

public static final String USER_DATA_NAME = "userdataname";
public static final String USER_DATA_ID = "userdataid";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -251,7 +251,15 @@ public class CreateServiceOfferingCmd extends BaseCmd {
since="4.20")
private Boolean purgeResources;

@Parameter(name = ApiConstants.INSTANCE_LEASE_DURATION,
type = CommandType.INTEGER,
description = "Number of days instance is leased for.",
since = "4.21.0")
private Integer leaseDuration;

@Parameter(name = ApiConstants.INSTANCE_LEASE_EXPIRY_ACTION, type = CommandType.STRING, since = "4.21.0",
description = "Lease expiry action, valid values are STOP and DESTROY")
private String leaseExpiryAction;

/////////////////////////////////////////////////////
/////////////////// Accessors ///////////////////////
Expand Down Expand Up @@ -487,6 +495,14 @@ public boolean getEncryptRoot() {
return false;
}

public String getLeaseExpiryAction() {
return leaseExpiryAction;
}

public Integer getLeaseDuration() {
return leaseDuration;
}

public boolean isPurgeResources() {
return Boolean.TRUE.equals(purgeResources);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@
response.setInstancesDisksStatsRetentionTime((Integer) capabilities.get(ApiConstants.INSTANCES_DISKS_STATS_RETENTION_TIME));
response.setSharedFsVmMinCpuCount((Integer)capabilities.get(ApiConstants.SHAREDFSVM_MIN_CPU_COUNT));
response.setSharedFsVmMinRamSize((Integer)capabilities.get(ApiConstants.SHAREDFSVM_MIN_RAM_SIZE));
response.setInstanceLeaseEnabled((Boolean) capabilities.get(ApiConstants.INSTANCE_LEASE_ENABLED));

Check warning on line 75 in api/src/main/java/org/apache/cloudstack/api/command/user/config/ListCapabilitiesCmd.java

View check run for this annotation

Codecov / codecov/patch

api/src/main/java/org/apache/cloudstack/api/command/user/config/ListCapabilitiesCmd.java#L75

Added line #L75 was not covered by tests
response.setObjectName("capability");
response.setResponseName(getCommandName());
this.setResponseObject(response);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,17 +16,24 @@
// under the License.
package org.apache.cloudstack.api.command.user.vm;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

import javax.annotation.Nonnull;

import com.cloud.agent.api.LogLevel;
import com.cloud.event.EventTypes;
import com.cloud.exception.ConcurrentOperationException;
import com.cloud.exception.InsufficientCapacityException;
import com.cloud.exception.InsufficientServerCapacityException;
import com.cloud.exception.InvalidParameterValueException;
import com.cloud.exception.ResourceAllocationException;
import com.cloud.exception.ResourceUnavailableException;
import com.cloud.hypervisor.Hypervisor.HypervisorType;
import com.cloud.network.Network;
import com.cloud.network.Network.IpAddresses;
import com.cloud.offering.DiskOffering;
import com.cloud.template.VirtualMachineTemplate;
import com.cloud.uservm.UserVm;
import com.cloud.utils.net.Dhcp;
import com.cloud.utils.net.NetUtils;
import com.cloud.vm.VirtualMachine;
import com.cloud.vm.VmDetailConstants;
import org.apache.cloudstack.acl.RoleType;
import org.apache.cloudstack.affinity.AffinityGroupResponse;
import org.apache.cloudstack.api.ACL;
Expand Down Expand Up @@ -58,24 +65,15 @@
import org.apache.commons.lang3.BooleanUtils;
import org.apache.commons.lang3.StringUtils;

import com.cloud.agent.api.LogLevel;
import com.cloud.event.EventTypes;
import com.cloud.exception.ConcurrentOperationException;
import com.cloud.exception.InsufficientCapacityException;
import com.cloud.exception.InsufficientServerCapacityException;
import com.cloud.exception.InvalidParameterValueException;
import com.cloud.exception.ResourceAllocationException;
import com.cloud.exception.ResourceUnavailableException;
import com.cloud.hypervisor.Hypervisor.HypervisorType;
import com.cloud.network.Network;
import com.cloud.network.Network.IpAddresses;
import com.cloud.offering.DiskOffering;
import com.cloud.template.VirtualMachineTemplate;
import com.cloud.uservm.UserVm;
import com.cloud.utils.net.Dhcp;
import com.cloud.utils.net.NetUtils;
import com.cloud.vm.VirtualMachine;
import com.cloud.vm.VmDetailConstants;
import javax.annotation.Nonnull;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

@APICommand(name = "deployVirtualMachine", description = "Creates and automatically starts a virtual machine based on a service offering, disk offering, and template.", responseObject = UserVmResponse.class, responseView = ResponseView.Restricted, entityType = {VirtualMachine.class},
requestHasSensitiveInfo = false, responseHasSensitiveInfo = true)
Expand Down Expand Up @@ -278,6 +276,14 @@
description = "Enable packed virtqueues or not.")
private Boolean nicPackedVirtQueues;

@Parameter(name = ApiConstants.INSTANCE_LEASE_DURATION, type = CommandType.INTEGER, since = "4.21.0",
description = "Number of days instance is leased for.")
private Integer leaseDuration;

@Parameter(name = ApiConstants.INSTANCE_LEASE_EXPIRY_ACTION, type = CommandType.STRING, since = "4.21.0",
description = "Lease expiry action, valid values are STOP and DESTROY")
private String leaseExpiryAction;

/////////////////////////////////////////////////////
/////////////////// Accessors ///////////////////////
/////////////////////////////////////////////////////
Expand Down Expand Up @@ -475,6 +481,14 @@
return password;
}

public Integer getLeaseDuration() {

Check warning on line 484 in api/src/main/java/org/apache/cloudstack/api/command/user/vm/DeployVMCmd.java

View check run for this annotation

Codecov / codecov/patch

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

Added line #L484 was not covered by tests
return leaseDuration;
}

Check warning on line 486 in api/src/main/java/org/apache/cloudstack/api/command/user/vm/DeployVMCmd.java

View check run for this annotation

Codecov / codecov/patch

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

Added line #L486 was not covered by tests

public String getLeaseExpiryAction() {

Check warning on line 488 in api/src/main/java/org/apache/cloudstack/api/command/user/vm/DeployVMCmd.java

View check run for this annotation

Codecov / codecov/patch

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

Added line #L488 was not covered by tests
return leaseExpiryAction;
}

Check warning on line 490 in api/src/main/java/org/apache/cloudstack/api/command/user/vm/DeployVMCmd.java

View check run for this annotation

Codecov / codecov/patch

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

Added line #L490 was not covered by tests

public List<Long> getNetworkIds() {
if (MapUtils.isNotEmpty(vAppNetworks)) {
if (CollectionUtils.isNotEmpty(networkIds) || ipAddress != null || getIp6Address() != null || MapUtils.isNotEmpty(ipToNetworkList)) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,11 @@
@Parameter(name = ApiConstants.USER_DATA_ID, type = CommandType.UUID, entityType = UserDataResponse.class, required = false, description = "the instances by userdata", since = "4.20.1")
private Long userdataId;

@Parameter(name = ApiConstants.LEASED, type = CommandType.BOOLEAN,

Check warning on line 156 in api/src/main/java/org/apache/cloudstack/api/command/user/vm/ListVMsCmd.java

View check run for this annotation

Codecov / codecov/patch

api/src/main/java/org/apache/cloudstack/api/command/user/vm/ListVMsCmd.java#L156

Added line #L156 was not covered by tests
description = "Whether to return only leased instances",
since = "4.21.0")
private Boolean onlyLeasedInstances = false;

Check warning on line 159 in api/src/main/java/org/apache/cloudstack/api/command/user/vm/ListVMsCmd.java

View check run for this annotation

Codecov / codecov/patch

api/src/main/java/org/apache/cloudstack/api/command/user/vm/ListVMsCmd.java#L159

Added line #L159 was not covered by tests

/////////////////////////////////////////////////////
/////////////////// Accessors ///////////////////////
/////////////////////////////////////////////////////
Expand Down Expand Up @@ -330,4 +335,8 @@
vmResponse.setResourceIconResponse(iconResponse);
}
}

public boolean getOnlyLeasedInstances() {
return BooleanUtils.toBoolean(onlyLeasedInstances);
}

Check warning on line 341 in api/src/main/java/org/apache/cloudstack/api/command/user/vm/ListVMsCmd.java

View check run for this annotation

Codecov / codecov/patch

api/src/main/java/org/apache/cloudstack/api/command/user/vm/ListVMsCmd.java#L339-L341

Added lines #L339 - L341 were not covered by tests
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,20 +16,18 @@
// under the License.
package org.apache.cloudstack.api.command.user.vm;

import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import com.cloud.exception.InsufficientCapacityException;
import com.cloud.exception.ResourceUnavailableException;
import com.cloud.user.Account;
import com.cloud.uservm.UserVm;
import com.cloud.utils.exception.CloudRuntimeException;

import org.apache.cloudstack.api.ApiArgValidator;
import org.apache.cloudstack.api.response.UserDataResponse;

import com.cloud.utils.net.Dhcp;
import com.cloud.vm.VirtualMachine;
import org.apache.cloudstack.acl.RoleType;
import org.apache.cloudstack.acl.SecurityChecker.AccessType;
import org.apache.cloudstack.api.ACL;
import org.apache.cloudstack.api.APICommand;
import org.apache.cloudstack.api.ApiArgValidator;
import org.apache.cloudstack.api.ApiCommandResourceType;
import org.apache.cloudstack.api.ApiConstants;
import org.apache.cloudstack.api.ApiErrorCode;
Expand All @@ -40,15 +38,14 @@
import org.apache.cloudstack.api.command.user.UserCmd;
import org.apache.cloudstack.api.response.GuestOSResponse;
import org.apache.cloudstack.api.response.SecurityGroupResponse;
import org.apache.cloudstack.api.response.UserDataResponse;
import org.apache.cloudstack.api.response.UserVmResponse;
import org.apache.cloudstack.context.CallContext;

import com.cloud.exception.InsufficientCapacityException;
import com.cloud.exception.ResourceUnavailableException;
import com.cloud.user.Account;
import com.cloud.uservm.UserVm;
import com.cloud.utils.net.Dhcp;
import com.cloud.vm.VirtualMachine;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@APICommand(name = "updateVirtualMachine", description="Updates properties of a virtual machine. The VM has to be stopped and restarted for the " +
"new properties to take effect. UpdateVirtualMachine does not first check whether the VM is stopped. " +
Expand Down Expand Up @@ -154,6 +151,14 @@
" autoscaling groups or CKS, delete protection will be ignored.")
private Boolean deleteProtection;

@Parameter(name = ApiConstants.INSTANCE_LEASE_DURATION, type = CommandType.INTEGER, since = "4.21.0",
description = "Number of days instance is leased for.")
private Integer leaseDuration;

@Parameter(name = ApiConstants.INSTANCE_LEASE_EXPIRY_ACTION, type = CommandType.STRING, since = "4.21.0",
description = "Lease expiry action, valid values are STOP and DESTROY")
private String leaseExpiryAction;

/////////////////////////////////////////////////////
/////////////////// Accessors ///////////////////////
/////////////////////////////////////////////////////
Expand Down Expand Up @@ -324,4 +329,13 @@
public ApiCommandResourceType getApiResourceType() {
return ApiCommandResourceType.VirtualMachine;
}

public Integer getLeaseDuration() {
return leaseDuration;
}

Check warning on line 335 in api/src/main/java/org/apache/cloudstack/api/command/user/vm/UpdateVMCmd.java

View check run for this annotation

Codecov / codecov/patch

api/src/main/java/org/apache/cloudstack/api/command/user/vm/UpdateVMCmd.java#L333-L335

Added lines #L333 - L335 were not covered by tests

public String getLeaseExpiryAction() {
return leaseExpiryAction;
}

Check warning on line 339 in api/src/main/java/org/apache/cloudstack/api/command/user/vm/UpdateVMCmd.java

View check run for this annotation

Codecov / codecov/patch

api/src/main/java/org/apache/cloudstack/api/command/user/vm/UpdateVMCmd.java#L337-L339

Added lines #L337 - L339 were not covered by tests

}
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,10 @@
@Param(description = "the min Ram size for the service offering used by the shared filesystem instance", since = "4.20.0")
private Integer sharedFsVmMinRamSize;

@SerializedName(ApiConstants.INSTANCE_LEASE_ENABLED)
@Param(description = "true if instance lease feature is enabled", since = "4.21.0")
private Boolean instanceLeaseEnabled;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is this response param required, this can be checked using config response (if implemented as global setting/config key)

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Only admin can access listConfiguration API, this helps to decide when to enable UI components for other users.


public void setSecurityGroupsEnabled(boolean securityGroupsEnabled) {
this.securityGroupsEnabled = securityGroupsEnabled;
}
Expand Down Expand Up @@ -247,4 +251,8 @@
public void setSharedFsVmMinRamSize(Integer sharedFsVmMinRamSize) {
this.sharedFsVmMinRamSize = sharedFsVmMinRamSize;
}

public void setInstanceLeaseEnabled(Boolean instanceLeaseEnabled) {
this.instanceLeaseEnabled = instanceLeaseEnabled;
}

Check warning on line 257 in api/src/main/java/org/apache/cloudstack/api/response/CapabilitiesResponse.java

View check run for this annotation

Codecov / codecov/patch

api/src/main/java/org/apache/cloudstack/api/response/CapabilitiesResponse.java#L255-L257

Added lines #L255 - L257 were not covered by tests
}
Original file line number Diff line number Diff line change
Expand Up @@ -238,6 +238,14 @@
@Param(description = "Whether to cleanup VM and its associated resource upon expunge", since = "4.20")
private Boolean purgeResources;

@SerializedName(ApiConstants.INSTANCE_LEASE_DURATION)
@Param(description = "Instance lease duration for service offering", since = "4.21.0")
private Integer leaseDuration;

@SerializedName(ApiConstants.INSTANCE_LEASE_EXPIRY_ACTION)
@Param(description = "Action to be taken once lease is over", since = "4.21.0")
private String leaseExpiryAction;

public ServiceOfferingResponse() {
}

Expand Down Expand Up @@ -505,6 +513,22 @@
this.cacheMode = cacheMode;
}

public Integer getLeaseDuration() {
return leaseDuration;
}

Check warning on line 518 in api/src/main/java/org/apache/cloudstack/api/response/ServiceOfferingResponse.java

View check run for this annotation

Codecov / codecov/patch

api/src/main/java/org/apache/cloudstack/api/response/ServiceOfferingResponse.java#L516-L518

Added lines #L516 - L518 were not covered by tests

public void setLeaseDuration(Integer leaseDuration) {
this.leaseDuration = leaseDuration;
}

Check warning on line 522 in api/src/main/java/org/apache/cloudstack/api/response/ServiceOfferingResponse.java

View check run for this annotation

Codecov / codecov/patch

api/src/main/java/org/apache/cloudstack/api/response/ServiceOfferingResponse.java#L520-L522

Added lines #L520 - L522 were not covered by tests

public String getLeaseExpiryAction() {
return leaseExpiryAction;
}

Check warning on line 526 in api/src/main/java/org/apache/cloudstack/api/response/ServiceOfferingResponse.java

View check run for this annotation

Codecov / codecov/patch

api/src/main/java/org/apache/cloudstack/api/response/ServiceOfferingResponse.java#L524-L526

Added lines #L524 - L526 were not covered by tests

public void setLeaseExpiryAction(String leaseExpiryAction) {
this.leaseExpiryAction = leaseExpiryAction;
}

Check warning on line 530 in api/src/main/java/org/apache/cloudstack/api/response/ServiceOfferingResponse.java

View check run for this annotation

Codecov / codecov/patch

api/src/main/java/org/apache/cloudstack/api/response/ServiceOfferingResponse.java#L528-L530

Added lines #L528 - L530 were not covered by tests

public String getVsphereStoragePolicy() {
return vsphereStoragePolicy;
}
Expand Down
Loading
Loading