diff --git a/api/src/com/cloud/api/response/AccountResponse.java b/api/src/com/cloud/api/response/AccountResponse.java index 90abaa83532..dd69024dfbe 100755 --- a/api/src/com/cloud/api/response/AccountResponse.java +++ b/api/src/com/cloud/api/response/AccountResponse.java @@ -20,10 +20,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"); @@ -118,6 +119,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 24bb669c4e2..7f551d6b52c 100644 --- a/api/src/com/cloud/configuration/Resource.java +++ b/api/src/com/cloud/configuration/Resource.java @@ -27,7 +27,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 b869a9d0bce..3d46c9e0da0 100644 --- a/api/src/com/cloud/network/vpc/VpcService.java +++ b/api/src/com/cloud/network/vpc/VpcService.java @@ -76,8 +76,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 5138af1cadc..a9e991087a7 100755 --- a/server/src/com/cloud/api/ApiResponseHelper.java +++ b/server/src/com/cloud/api/ApiResponseHelper.java @@ -265,6 +265,7 @@ public class ApiResponseHelper implements ResponseGenerator { accountResponse.setDomainName(ApiDBUtils.findDomainById(account.getDomainId()).getName()); accountResponse.setState(account.getState().toString()); accountResponse.setNetworkDomain(account.getNetworkDomain()); + accountResponse.setDefaultZone(account.getDefaultZoneId()); // get network stat List stats = ApiDBUtils.listUserStatsBy(account.getId()); @@ -361,7 +362,7 @@ public class ApiResponseHelper implements ResponseGenerator { accountResponse.setVmStopped(vmStopped); accountResponse.setVmRunning(vmRunning); accountResponse.setObjectName("account"); - + //get resource limits for projects Long projectLimit = ApiDBUtils.findCorrectResourceLimit(ResourceType.project, account.getId()); String projectLimitDisplay = (accountIsAdmin || projectLimit == -1) ? "Unlimited" : String.valueOf(projectLimit); @@ -370,7 +371,7 @@ public class ApiResponseHelper implements ResponseGenerator { accountResponse.setProjectLimit(projectLimitDisplay); accountResponse.setProjectTotal(projectTotal); accountResponse.setProjectAvailable(projectAvail); - + //get resource limits for networks Long networkLimit = ApiDBUtils.findCorrectResourceLimit(ResourceType.network, account.getId()); String networkLimitDisplay = (accountIsAdmin || networkLimit == -1) ? "Unlimited" : String.valueOf(networkLimit); @@ -379,7 +380,16 @@ 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()); List userResponseList = new ArrayList(); @@ -392,7 +402,8 @@ public class ApiResponseHelper implements ResponseGenerator { accountResponse.setDetails(ApiDBUtils.getAccountDetails(account.getId())); return accountResponse; } - + + @Override public UserResponse createUserResponse(UserAccount user) { UserResponse userResponse = new UserResponse(); @@ -3876,4 +3887,4 @@ public class ApiResponseHelper implements ResponseGenerator { response.setObjectName("vpnconnection"); return response; } -} +} \ No newline at end of file diff --git a/server/src/com/cloud/configuration/Config.java b/server/src/com/cloud/configuration/Config.java index fb521681a87..7144f60086c 100755 --- a/server/src/com/cloud/configuration/Config.java +++ b/server/src/com/cloud/configuration/Config.java @@ -299,6 +299,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), @@ -321,6 +323,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 c6b3e588c7d..73aa27ee853 100644 --- a/server/src/com/cloud/network/vpc/Dao/VpcDao.java +++ b/server/src/com/cloud/network/vpc/Dao/VpcDao.java @@ -36,5 +36,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 048571f9734..fcca6dc401a 100644 --- a/server/src/com/cloud/network/vpc/Dao/VpcDaoImpl.java +++ b/server/src/com/cloud/network/vpc/Dao/VpcDaoImpl.java @@ -40,6 +40,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() { @@ -56,6 +57,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(); } @@ -102,5 +109,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 56a75ac4ffd..c52fb00666d 100644 --- a/server/src/com/cloud/network/vpc/VpcManagerImpl.java +++ b/server/src/com/cloud/network/vpc/VpcManagerImpl.java @@ -36,6 +36,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; @@ -89,6 +90,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.NumbersUtil; @@ -158,6 +160,8 @@ public class VpcManagerImpl implements VpcManager, Manager{ Site2SiteVpnManager _s2sVpnMgr; @Inject VlanDao _vlanDao = null; + @Inject + ResourceLimitService _resourceLimitMgr; private final ScheduledExecutorService _executor = Executors.newScheduledThreadPool(1, new NamedThreadFactory("VpcChecker")); @@ -510,13 +514,16 @@ 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); if (vpcOff == null) { @@ -561,7 +568,8 @@ 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) { @@ -593,16 +601,17 @@ public class VpcManagerImpl implements VpcManager, Manager{ " that overlaps the cidr specified: " + cidr); } } - + + Transaction txn = Transaction.currentTxn(); + txn.start(); VpcVO vpc = new VpcVO (zoneId, vpcName, displayText, vpcOwner.getId(), vpcOwner.getDomainId(), vpcOffId, cidr, networkDomain); vpc = _vpcDao.persist(vpc); - - if (vpc != null) { - s_logger.debug("Created VPC " + vpc); - } else { - s_logger.debug("Failed to create VPC"); - } + _resourceLimitMgr.incrementResourceCount(vpcOwner.getId(), ResourceType.vpc); + txn.commit(); + + s_logger.debug("Created VPC " + vpc); + return vpc; } @@ -625,6 +634,7 @@ public class VpcManagerImpl implements VpcManager, Manager{ } @Override + @DB public boolean destroyVpc(Vpc vpc) throws ConcurrentOperationException, ResourceUnavailableException { UserContext ctx = UserContext.current(); @@ -633,13 +643,22 @@ public class VpcManagerImpl implements VpcManager, Manager{ if (networksCount > 0) { throw new InvalidParameterValueException("Can't delete VPC " + vpc + " as its used by " + networksCount + " networks"); } - - //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 b285d2ce8fb..26da588e1b3 100755 --- a/server/src/com/cloud/resourcelimit/ResourceLimitManagerImpl.java +++ b/server/src/com/cloud/resourcelimit/ResourceLimitManagerImpl.java @@ -52,6 +52,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; @@ -119,6 +120,8 @@ public class ResourceLimitManagerImpl implements ResourceLimitService, Manager { private ProjectAccountDao _projectAccountDao; @Inject private NetworkDao _networkDao; + @Inject + private VpcDao _vpcDao; protected SearchBuilder ResourceCountSearch; ScheduledExecutorService _rcExecutor; @@ -165,6 +168,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()))); @@ -172,6 +176,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,6 +742,8 @@ public class ResourceLimitManagerImpl implements ResourceLimitService, Manager { newCount = _projectAccountDao.countByAccountIdAndRole(accountId, Role.Admin); } else if (type == Resource.ResourceType.network) { newCount = _networkDao.countNetworksUserCanCreate(accountId); + } else if (type == Resource.ResourceType.vpc) { + newCount = _vpcDao.countByAccountId(accountId); } else { throw new InvalidParameterValueException("Unsupported resource type " + type); }