From f80bfb35f54bdfe37256c3d6eb18253f303b54ca Mon Sep 17 00:00:00 2001 From: Alena Prokharchyk Date: Wed, 1 Aug 2012 16:15:06 -0700 Subject: [PATCH] VPC: CS-15798 - added vpc resource limit. Check vpc functional spec for more details: http://wiki.cloudstack.org/display/RelOps/Inter-VLAN+Routing+functional+spec --- .../cloud/api/response/AccountResponse.java | 12 +++++- api/src/com/cloud/configuration/Resource.java | 3 +- api/src/com/cloud/network/vpc/VpcService.java | 3 +- .../src/com/cloud/api/ApiResponseHelper.java | 9 ++++ .../src/com/cloud/configuration/Config.java | 3 ++ .../src/com/cloud/network/vpc/Dao/VpcDao.java | 2 + .../com/cloud/network/vpc/Dao/VpcDaoImpl.java | 15 +++++++ .../com/cloud/network/vpc/VpcManagerImpl.java | 43 +++++++++++++------ .../ResourceLimitManagerImpl.java | 9 +++- 9 files changed, 83 insertions(+), 16 deletions(-) diff --git a/api/src/com/cloud/api/response/AccountResponse.java b/api/src/com/cloud/api/response/AccountResponse.java index 016a0e77a64..1770477110c 100755 --- a/api/src/com/cloud/api/response/AccountResponse.java +++ b/api/src/com/cloud/api/response/AccountResponse.java @@ -16,10 +16,11 @@ import java.util.List; import java.util.Map; import com.cloud.api.ApiConstants; -import com.cloud.utils.IdentityProxy; import com.cloud.serializer.Param; +import com.cloud.utils.IdentityProxy; import com.google.gson.annotations.SerializedName; +@SuppressWarnings("unused") public class AccountResponse extends BaseResponse { @SerializedName(ApiConstants.ID) @Param(description="the id of the account") private IdentityProxy id = new IdentityProxy("account"); @@ -114,6 +115,15 @@ public class AccountResponse extends BaseResponse { @SerializedName("networkavailable") @Param(description="the total number of networks available to be created for this account", since="3.0.1") private String networkAvailable; + @SerializedName("vpclimit") @Param(description="the total number of vpcs the account can own", since="3.0.5") + private String vpcLimit; + + @SerializedName("vpctotal") @Param(description="the total number of vpcs owned by account", since="3.0.5") + private Long vpcTotal; + + @SerializedName("vpcavailable") @Param(description="the total number of vpcs available to be created for this account", since="3.0.5") + private String vpcAvailable; + @SerializedName(ApiConstants.STATE) @Param(description="the state of the account") private String state; diff --git a/api/src/com/cloud/configuration/Resource.java b/api/src/com/cloud/configuration/Resource.java index 4c50f1e58c6..eb6294dfd39 100644 --- a/api/src/com/cloud/configuration/Resource.java +++ b/api/src/com/cloud/configuration/Resource.java @@ -23,7 +23,8 @@ public interface Resource { snapshot("snapshot", 3, ResourceOwnerType.Account, ResourceOwnerType.Domain), template("template", 4, ResourceOwnerType.Account, ResourceOwnerType.Domain), project("project", 5, ResourceOwnerType.Account, ResourceOwnerType.Domain), - network("network", 6, ResourceOwnerType.Account, ResourceOwnerType.Domain); + network("network", 6, ResourceOwnerType.Account, ResourceOwnerType.Domain), + vpc("vpc", 7, ResourceOwnerType.Account, ResourceOwnerType.Domain); private String name; private ResourceOwnerType[] supportedOwners; diff --git a/api/src/com/cloud/network/vpc/VpcService.java b/api/src/com/cloud/network/vpc/VpcService.java index 278551de70a..e478ec0b3df 100644 --- a/api/src/com/cloud/network/vpc/VpcService.java +++ b/api/src/com/cloud/network/vpc/VpcService.java @@ -75,8 +75,9 @@ public interface VpcService { * @param cidr * @param networkDomain TODO * @return + * @throws ResourceAllocationException TODO */ - public Vpc createVpc(long zoneId, long vpcOffId, long vpcOwnerId, String vpcName, String displayText, String cidr, String networkDomain); + public Vpc createVpc(long zoneId, long vpcOffId, long vpcOwnerId, String vpcName, String displayText, String cidr, String networkDomain) throws ResourceAllocationException; /** * @param vpcId diff --git a/server/src/com/cloud/api/ApiResponseHelper.java b/server/src/com/cloud/api/ApiResponseHelper.java index d57f637a46d..3395a29c697 100755 --- a/server/src/com/cloud/api/ApiResponseHelper.java +++ b/server/src/com/cloud/api/ApiResponseHelper.java @@ -388,6 +388,15 @@ public class ApiResponseHelper implements ResponseGenerator { accountResponse.setNetworkLimit(networkLimitDisplay); accountResponse.setNetworkTotal(networkTotal); accountResponse.setNetworkAvailable(networkAvail); + + //get resource limits for vpcs + Long vpcLimit = ApiDBUtils.findCorrectResourceLimit(ResourceType.vpc, account.getId()); + String vpcLimitDisplay = (accountIsAdmin || vpcLimit == -1) ? "Unlimited" : String.valueOf(vpcLimit); + Long vpcTotal = ApiDBUtils.getResourceCount(ResourceType.vpc, account.getId()); + String vpcAvail = (accountIsAdmin || vpcLimit == -1) ? "Unlimited" : String.valueOf(vpcLimit - vpcTotal); + accountResponse.setNetworkLimit(vpcLimitDisplay); + accountResponse.setNetworkTotal(vpcTotal); + accountResponse.setNetworkAvailable(vpcAvail); // adding all the users for an account as part of the response obj List usersForAccount = ApiDBUtils.listUsersByAccount(account.getAccountId()); diff --git a/server/src/com/cloud/configuration/Config.java b/server/src/com/cloud/configuration/Config.java index ad2493cb360..5a8a24cc524 100755 --- a/server/src/com/cloud/configuration/Config.java +++ b/server/src/com/cloud/configuration/Config.java @@ -297,6 +297,8 @@ public enum Config { DefaultMaxAccountSnapshots("Account Defaults", ManagementServer.class, Long.class, "max.account.snapshots", "20", "The default maximum number of snapshots that can be created for an account", null), DefaultMaxAccountVolumes("Account Defaults", ManagementServer.class, Long.class, "max.account.volumes", "20", "The default maximum number of volumes that can be created for an account", null), DefaultMaxAccountNetworks("Account Defaults", ManagementServer.class, Long.class, "max.account.networks", "20", "The default maximum number of networks that can be created for an account", null), + DefaultMaxAccountVpcs("Account Defaults", ManagementServer.class, Long.class, "max.account.vpcs", "20", "The default maximum number of vpcs that can be created for an account", null), + ResourceCountCheckInterval("Advanced", ManagementServer.class, Long.class, "resourcecount.check.interval", "0", "Time (in seconds) to wait before retrying resource count check task. Default is 0 which is to never run the task", "Seconds"), DirectAgentLoadSize("Advanced", ManagementServer.class, Integer.class, "direct.agent.load.size", "16", "The number of direct agents to load each time", null), @@ -319,6 +321,7 @@ public enum Config { DefaultMaxProjectSnapshots("Project Defaults", ManagementServer.class, Long.class, "max.project.snapshots", "20", "The default maximum number of snapshots that can be created for a project", null), DefaultMaxProjectVolumes("Project Defaults", ManagementServer.class, Long.class, "max.project.volumes", "20", "The default maximum number of volumes that can be created for a project", null), DefaultMaxProjectNetworks("Project Defaults", ManagementServer.class, Long.class, "max.project.networks", "20", "The default maximum number of networks that can be created for a project", null), + DefaultMaxProjectVpcs("Project Defaults", ManagementServer.class, Long.class, "max.project.vpcs", "20", "The default maximum number of vpcs that can be created for a project", null), ProjectInviteRequired("Project Defaults", ManagementServer.class, Boolean.class, "project.invite.required", "false", "If invitation confirmation is required when add account to project. Default value is false", null), ProjectInvitationExpirationTime("Project Defaults", ManagementServer.class, Long.class, "project.invite.timeout", "86400", "Invitation expiration time (in seconds). Default is 1 day - 86400 seconds", null), diff --git a/server/src/com/cloud/network/vpc/Dao/VpcDao.java b/server/src/com/cloud/network/vpc/Dao/VpcDao.java index ac8b0d4ad51..fdc6d79fa49 100644 --- a/server/src/com/cloud/network/vpc/Dao/VpcDao.java +++ b/server/src/com/cloud/network/vpc/Dao/VpcDao.java @@ -34,5 +34,7 @@ public interface VpcDao extends GenericDao{ List listByAccountId(long accountId); List listInactiveVpcs(); + + long countByAccountId(long accountId); } diff --git a/server/src/com/cloud/network/vpc/Dao/VpcDaoImpl.java b/server/src/com/cloud/network/vpc/Dao/VpcDaoImpl.java index b2d1aab64ea..cc815548289 100644 --- a/server/src/com/cloud/network/vpc/Dao/VpcDaoImpl.java +++ b/server/src/com/cloud/network/vpc/Dao/VpcDaoImpl.java @@ -39,6 +39,7 @@ import com.cloud.utils.db.Transaction; public class VpcDaoImpl extends GenericDaoBase implements VpcDao{ final GenericSearchBuilder CountByOfferingId; final SearchBuilder AllFieldsSearch; + final GenericSearchBuilder CountByAccountId; ResourceTagsDaoImpl _tagsDao = ComponentLocator.inject(ResourceTagsDaoImpl.class); protected VpcDaoImpl() { @@ -55,6 +56,12 @@ public class VpcDaoImpl extends GenericDaoBase implements VpcDao{ AllFieldsSearch.and("state", AllFieldsSearch.entity().getState(), Op.EQ); AllFieldsSearch.and("accountId", AllFieldsSearch.entity().getAccountId(), Op.EQ); AllFieldsSearch.done(); + + CountByAccountId = createSearchBuilder(Long.class); + CountByAccountId.select(null, Func.COUNT, CountByAccountId.entity().getId()); + CountByAccountId.and("offeringId", CountByAccountId.entity().getAccountId(), Op.EQ); + CountByAccountId.and("removed", CountByAccountId.entity().getRemoved(), Op.NULL); + CountByAccountId.done(); } @@ -101,5 +108,13 @@ public class VpcDaoImpl extends GenericDaoBase implements VpcDao{ txn.commit(); return result; } + + @Override + public long countByAccountId(long accountId) { + SearchCriteria sc = CountByAccountId.create(); + sc.setParameters("accountId", accountId); + List results = customSearch(sc, null); + return results.get(0); + } } diff --git a/server/src/com/cloud/network/vpc/VpcManagerImpl.java b/server/src/com/cloud/network/vpc/VpcManagerImpl.java index 0e325f66071..ee7d769f480 100644 --- a/server/src/com/cloud/network/vpc/VpcManagerImpl.java +++ b/server/src/com/cloud/network/vpc/VpcManagerImpl.java @@ -32,6 +32,7 @@ import com.cloud.api.commands.ListPrivateGatewaysCmd; import com.cloud.api.commands.ListStaticRoutesCmd; import com.cloud.configuration.Config; import com.cloud.configuration.ConfigurationManager; +import com.cloud.configuration.Resource.ResourceType; import com.cloud.configuration.dao.ConfigurationDao; import com.cloud.dc.DataCenter; import com.cloud.dc.Vlan.VlanType; @@ -84,6 +85,7 @@ import com.cloud.tags.ResourceTagVO; import com.cloud.tags.dao.ResourceTagDao; import com.cloud.user.Account; import com.cloud.user.AccountManager; +import com.cloud.user.ResourceLimitService; import com.cloud.user.User; import com.cloud.user.UserContext; import com.cloud.utils.IdentityProxy; @@ -156,6 +158,8 @@ public class VpcManagerImpl implements VpcManager, Manager{ FirewallRulesDao _firewallDao; @Inject VlanDao _vlanDao = null; + @Inject + ResourceLimitService _resourceLimitMgr; private final ScheduledExecutorService _executor = Executors.newScheduledThreadPool(1, new NamedThreadFactory("VpcChecker")); private VpcProvider vpcElement = null; @@ -508,12 +512,15 @@ public class VpcManagerImpl implements VpcManager, Manager{ @Override @ActionEvent(eventType = EventTypes.EVENT_VPC_CREATE, eventDescription = "creating vpc", create=true) public Vpc createVpc(long zoneId, long vpcOffId, long vpcOwnerId, String vpcName, String displayText, String cidr, - String networkDomain) { + String networkDomain) throws ResourceAllocationException { Account caller = UserContext.current().getCaller(); Account owner = _accountMgr.getAccount(vpcOwnerId); //Verify that caller can perform actions in behalf of vpc owner _accountMgr.checkAccess(caller, null, false, owner); + + //check resource limit + _resourceLimitMgr.checkResourceLimit(owner, ResourceType.vpc); // Validate vpc offering VpcOfferingVO vpcOff = _vpcOffDao.findById(vpcOffId); @@ -559,6 +566,7 @@ public class VpcManagerImpl implements VpcManager, Manager{ return false; } + @DB protected Vpc createVpc(long zoneId, long vpcOffId, Account vpcOwner, String vpcName, String displayText, String cidr, String networkDomain) { @@ -591,15 +599,16 @@ public class VpcManagerImpl implements VpcManager, Manager{ } } + Transaction txn = Transaction.currentTxn(); + txn.start(); VpcVO vpc = new VpcVO (zoneId, vpcName, displayText, vpcOwner.getId(), vpcOwner.getDomainId(), vpcOffId, cidr, networkDomain); vpc = _vpcDao.persist(vpc); + _resourceLimitMgr.incrementResourceCount(vpcOwner.getId(), ResourceType.vpc); + txn.commit(); + + s_logger.debug("Created VPC " + vpc); - if (vpc != null) { - s_logger.debug("Created VPC " + vpc); - } else { - s_logger.debug("Failed to create VPC"); - } return vpc; } @@ -622,6 +631,7 @@ public class VpcManagerImpl implements VpcManager, Manager{ } @Override + @DB public boolean destroyVpc(Vpc vpc) throws ConcurrentOperationException, ResourceUnavailableException { UserContext ctx = UserContext.current(); @@ -633,12 +643,21 @@ public class VpcManagerImpl implements VpcManager, Manager{ throw new InvalidParameterValueException("Can't delete VPC of specified id as it is used by " + networksCount + " networks", idList); } - //mark VPC as disabled - s_logger.debug("Updating VPC " + vpc + " with state " + Vpc.State.Inactive + " as a part of vpc delete"); - VpcVO vpcVO = _vpcDao.findById(vpc.getId()); - vpcVO.setState(Vpc.State.Inactive); - _vpcDao.update(vpc.getId(), vpcVO); - + //mark VPC as inactive + if (vpc.getState() != Vpc.State.Inactive) { + s_logger.debug("Updating VPC " + vpc + " with state " + Vpc.State.Inactive + " as a part of vpc delete"); + VpcVO vpcVO = _vpcDao.findById(vpc.getId()); + vpcVO.setState(Vpc.State.Inactive); + + Transaction txn = Transaction.currentTxn(); + txn.start(); + _vpcDao.update(vpc.getId(), vpcVO); + + //decrement resource count + _resourceLimitMgr.decrementResourceCount(vpc.getAccountId(), ResourceType.vpc); + txn.commit(); + } + //shutdown VPC if (!shutdownVpc(vpc.getId())) { s_logger.warn("Failed to shutdown vpc " + vpc + " as a part of vpc destroy process"); diff --git a/server/src/com/cloud/resourcelimit/ResourceLimitManagerImpl.java b/server/src/com/cloud/resourcelimit/ResourceLimitManagerImpl.java index 55e389e0f20..7f2172a4a2c 100755 --- a/server/src/com/cloud/resourcelimit/ResourceLimitManagerImpl.java +++ b/server/src/com/cloud/resourcelimit/ResourceLimitManagerImpl.java @@ -48,6 +48,7 @@ import com.cloud.exception.PermissionDeniedException; import com.cloud.exception.ResourceAllocationException; import com.cloud.network.dao.IPAddressDao; import com.cloud.network.dao.NetworkDao; +import com.cloud.network.vpc.Dao.VpcDao; import com.cloud.projects.Project; import com.cloud.projects.ProjectAccount.Role; import com.cloud.projects.dao.ProjectAccountDao; @@ -116,6 +117,8 @@ public class ResourceLimitManagerImpl implements ResourceLimitService, Manager { private ProjectAccountDao _projectAccountDao; @Inject private NetworkDao _networkDao; + @Inject + private VpcDao _vpcDao; protected SearchBuilder ResourceCountSearch; ScheduledExecutorService _rcExecutor; @@ -162,6 +165,7 @@ public class ResourceLimitManagerImpl implements ResourceLimitService, Manager { projectResourceLimitMap.put(Resource.ResourceType.user_vm, Long.parseLong(_configDao.getValue(Config.DefaultMaxProjectUserVms.key()))); projectResourceLimitMap.put(Resource.ResourceType.volume, Long.parseLong(_configDao.getValue(Config.DefaultMaxProjectVolumes.key()))); projectResourceLimitMap.put(Resource.ResourceType.network, Long.parseLong(_configDao.getValue(Config.DefaultMaxProjectNetworks.key()))); + projectResourceLimitMap.put(Resource.ResourceType.vpc, Long.parseLong(_configDao.getValue(Config.DefaultMaxProjectVpcs.key()))); accountResourceLimitMap.put(Resource.ResourceType.public_ip, Long.parseLong(_configDao.getValue(Config.DefaultMaxAccountPublicIPs.key()))); accountResourceLimitMap.put(Resource.ResourceType.snapshot, Long.parseLong(_configDao.getValue(Config.DefaultMaxAccountSnapshots.key()))); @@ -169,6 +173,7 @@ public class ResourceLimitManagerImpl implements ResourceLimitService, Manager { accountResourceLimitMap.put(Resource.ResourceType.user_vm, Long.parseLong(_configDao.getValue(Config.DefaultMaxAccountUserVms.key()))); accountResourceLimitMap.put(Resource.ResourceType.volume, Long.parseLong(_configDao.getValue(Config.DefaultMaxAccountVolumes.key()))); accountResourceLimitMap.put(Resource.ResourceType.network, Long.parseLong(_configDao.getValue(Config.DefaultMaxAccountNetworks.key()))); + accountResourceLimitMap.put(Resource.ResourceType.vpc, Long.parseLong(_configDao.getValue(Config.DefaultMaxAccountVpcs.key()))); return true; } @@ -737,7 +742,9 @@ public class ResourceLimitManagerImpl implements ResourceLimitService, Manager { newCount = _projectAccountDao.countByAccountIdAndRole(accountId, Role.Admin); } else if (type == Resource.ResourceType.network) { newCount = _networkDao.countNetworksUserCanCreate(accountId); - } else { + } else if (type == Resource.ResourceType.vpc) { + newCount = _vpcDao.countByAccountId(accountId); + }else { throw new InvalidParameterValueException("Unsupported resource type " + type, null); } _resourceCountDao.setResourceCount(accountId, ResourceOwnerType.Account, type, (newCount == null) ? 0 : newCount.longValue());