diff --git a/api/src/main/java/com/cloud/configuration/ConfigurationService.java b/api/src/main/java/com/cloud/configuration/ConfigurationService.java index 5af44ed18f4..8b419027f70 100644 --- a/api/src/main/java/com/cloud/configuration/ConfigurationService.java +++ b/api/src/main/java/com/cloud/configuration/ConfigurationService.java @@ -106,6 +106,20 @@ public interface ConfigurationService { */ boolean deleteServiceOffering(DeleteServiceOfferingCmd cmd); + /** + * Retrieve ID of domains for a service offering + * + * @param serviceOfferingId + */ + List getServiceOfferingDomains(Long serviceOfferingId); + + /** + * Retrieve ID of domains for a service offering + * + * @param serviceOfferingId + */ + List getServiceOfferingZones(Long serviceOfferingId); + /** * Updates a disk offering * @@ -139,6 +153,20 @@ public interface ConfigurationService { */ DiskOffering createDiskOffering(CreateDiskOfferingCmd cmd); + /** + * Retrieve ID of domains for a disk offering + * + * @param diskOfferingId + */ + List getDiskOfferingDomains(Long diskOfferingId); + + /** + * Retrieve ID of domains for a disk offering + * + * @param diskOfferingId + */ + List getDiskOfferingZones(Long diskOfferingId); + /** * Creates a new pod based on the parameters specified in the command object * @@ -269,6 +297,20 @@ public interface ConfigurationService { boolean deleteNetworkOffering(DeleteNetworkOfferingCmd cmd); + /** + * Retrieve ID of domains for a network offering + * + * @param networkOfferingId + */ + List getNetworkOfferingDomains(Long networkOfferingId); + + /** + * Retrieve ID of domains for a network offering + * + * @param networkOfferingId + */ + List getNetworkOfferingZones(Long networkOfferingId); + Account getVlanAccount(long vlanId); Domain getVlanDomain(long vlanId); diff --git a/api/src/main/java/com/cloud/network/vpc/VpcOffering.java b/api/src/main/java/com/cloud/network/vpc/VpcOffering.java index c0da6bf967a..b4df8e38dba 100644 --- a/api/src/main/java/com/cloud/network/vpc/VpcOffering.java +++ b/api/src/main/java/com/cloud/network/vpc/VpcOffering.java @@ -16,6 +16,8 @@ // under the License. package com.cloud.network.vpc; +import java.util.Date; + import org.apache.cloudstack.api.Identity; import org.apache.cloudstack.api.InternalIdentity; @@ -59,13 +61,16 @@ public interface VpcOffering extends InternalIdentity, Identity { /** * @return true if the offering provides a distributed router capable of one-hop forwarding */ - boolean supportsDistributedRouter(); + boolean isSupportsDistributedRouter(); /** * @return true if VPC created with the offering can span multiple zones in the region */ - boolean offersRegionLevelVPC(); + boolean isOffersRegionLevelVPC(); - boolean getRedundantRouter(); + boolean isRedundantRouter(); + Date getRemoved(); + + Date getCreated(); } diff --git a/api/src/main/java/com/cloud/network/vpc/VpcProvisioningService.java b/api/src/main/java/com/cloud/network/vpc/VpcProvisioningService.java index e682d9f99d4..8bba19c6c91 100644 --- a/api/src/main/java/com/cloud/network/vpc/VpcProvisioningService.java +++ b/api/src/main/java/com/cloud/network/vpc/VpcProvisioningService.java @@ -20,21 +20,24 @@ package com.cloud.network.vpc; import java.util.List; import java.util.Map; +import org.apache.cloudstack.api.command.admin.vpc.CreateVPCOfferingCmd; import org.apache.cloudstack.api.command.admin.vpc.UpdateVPCOfferingCmd; +import org.apache.cloudstack.api.command.user.vpc.ListVPCOfferingsCmd; import com.cloud.utils.Pair; public interface VpcProvisioningService { - public VpcOffering getVpcOffering(long vpcOfferingId); + VpcOffering getVpcOffering(long vpcOfferingId); - public VpcOffering createVpcOffering(String name, String displayText, List supportedServices, - Map> serviceProviders, - Map serviceCapabilitystList, - Long serviceOfferingId); + VpcOffering createVpcOffering(CreateVPCOfferingCmd cmd); - Pair,Integer> listVpcOfferings(Long id, String name, String displayText, List supportedServicesStr, Boolean isDefault, String keyword, - String state, Long startIndex, Long pageSizeVal); + VpcOffering createVpcOffering(String name, String displayText, List supportedServices, + Map> serviceProviders, + Map serviceCapabilitystList, + Long serviceOfferingId, List domainIds, List zoneIds); + + Pair,Integer> listVpcOfferings(ListVPCOfferingsCmd cmd); /** * @param offId @@ -46,9 +49,22 @@ public interface VpcProvisioningService { public VpcOffering updateVpcOffering(long vpcOffId, String vpcOfferingName, String displayText, String state); /** - * @param vpcOfferingCmd + * @param cmd * @return */ - public VpcOffering updateVpcOffering(final UpdateVPCOfferingCmd vpcOfferingCmd); + VpcOffering updateVpcOffering(final UpdateVPCOfferingCmd cmd); + /** + * Retrieve ID of domains for a VPC offering + * + * @param vpcOfferingId + */ + List getVpcOfferingDomains(Long vpcOfferingId); + + /** + * Retrieve ID of domains for a VPC offering + * + * @param vpcOfferingId + */ + List getVpcOfferingZones(Long vpcOfferingId); } diff --git a/api/src/main/java/com/cloud/offering/DiskOffering.java b/api/src/main/java/com/cloud/offering/DiskOffering.java index 98ba6c0f46d..fd21118e4a2 100644 --- a/api/src/main/java/com/cloud/offering/DiskOffering.java +++ b/api/src/main/java/com/cloud/offering/DiskOffering.java @@ -34,13 +34,13 @@ public interface DiskOffering extends InfrastructureEntity, Identity, InternalId Inactive, Active, } - public enum Type { + enum Type { Disk, Service }; State getState(); - public enum DiskCacheMode { + enum DiskCacheMode { NONE("none"), WRITEBACK("writeback"), WRITETHROUGH("writethrough"); private final String _diskCacheMode; @@ -59,19 +59,17 @@ public interface DiskOffering extends InfrastructureEntity, Identity, InternalId boolean isUseLocalStorage(); - Long getDomainId(); - String getName(); boolean isSystemUse(); String getDisplayText(); - public ProvisioningType getProvisioningType(); + ProvisioningType getProvisioningType(); - public String getTags(); + String getTags(); - public String[] getTagsArray(); + String[] getTagsArray(); Date getCreated(); diff --git a/api/src/main/java/com/cloud/offering/NetworkOffering.java b/api/src/main/java/com/cloud/offering/NetworkOffering.java index 97db87bb0a8..45450745df1 100644 --- a/api/src/main/java/com/cloud/offering/NetworkOffering.java +++ b/api/src/main/java/com/cloud/offering/NetworkOffering.java @@ -38,7 +38,7 @@ public interface NetworkOffering extends InfrastructureEntity, InternalIdentity, } public enum Detail { - InternalLbProvider, PublicLbProvider, servicepackageuuid, servicepackagedescription, PromiscuousMode, MacAddressChanges, ForgedTransmits, RelatedNetworkOffering + InternalLbProvider, PublicLbProvider, servicepackageuuid, servicepackagedescription, PromiscuousMode, MacAddressChanges, ForgedTransmits, RelatedNetworkOffering, domainid, zoneid } public final static String SystemPublicNetwork = "System-Public-Network"; diff --git a/api/src/main/java/com/cloud/offering/ServiceOffering.java b/api/src/main/java/com/cloud/offering/ServiceOffering.java index 6f0116d1a4a..2a80ba5bd61 100644 --- a/api/src/main/java/com/cloud/offering/ServiceOffering.java +++ b/api/src/main/java/com/cloud/offering/ServiceOffering.java @@ -104,9 +104,6 @@ public interface ServiceOffering extends DiskOffering, InfrastructureEntity, Int @Override boolean isUseLocalStorage(); - @Override - Long getDomainId(); - /** * @return tag that should be present on the host needed, optional parameter */ diff --git a/api/src/main/java/com/cloud/user/AccountService.java b/api/src/main/java/com/cloud/user/AccountService.java index 060861d1809..4e3733bb5a4 100644 --- a/api/src/main/java/com/cloud/user/AccountService.java +++ b/api/src/main/java/com/cloud/user/AccountService.java @@ -25,9 +25,12 @@ import org.apache.cloudstack.api.command.admin.user.GetUserKeysCmd; import org.apache.cloudstack.api.command.admin.user.RegisterCmd; import org.apache.cloudstack.api.command.admin.user.UpdateUserCmd; +import com.cloud.dc.DataCenter; import com.cloud.domain.Domain; import com.cloud.exception.PermissionDeniedException; +import com.cloud.network.vpc.VpcOffering; import com.cloud.offering.DiskOffering; +import com.cloud.offering.NetworkOffering; import com.cloud.offering.ServiceOffering; public interface AccountService { @@ -96,9 +99,13 @@ public interface AccountService { void checkAccess(Account account, AccessType accessType, boolean sameOwner, ControlledEntity... entities) throws PermissionDeniedException; - void checkAccess(Account account, ServiceOffering so) throws PermissionDeniedException; + void checkAccess(Account account, ServiceOffering so, DataCenter zone) throws PermissionDeniedException; - void checkAccess(Account account, DiskOffering dof) throws PermissionDeniedException; + void checkAccess(Account account, DiskOffering dof, DataCenter zone) throws PermissionDeniedException; + + void checkAccess(Account account, NetworkOffering nof, DataCenter zone) throws PermissionDeniedException; + + void checkAccess(Account account, VpcOffering vof, DataCenter zone) throws PermissionDeniedException; void checkAccess(User user, ControlledEntity entity); diff --git a/api/src/main/java/org/apache/cloudstack/acl/SecurityChecker.java b/api/src/main/java/org/apache/cloudstack/acl/SecurityChecker.java index 41708717548..82a8ec5fe93 100644 --- a/api/src/main/java/org/apache/cloudstack/acl/SecurityChecker.java +++ b/api/src/main/java/org/apache/cloudstack/acl/SecurityChecker.java @@ -19,7 +19,9 @@ package org.apache.cloudstack.acl; import com.cloud.dc.DataCenter; import com.cloud.domain.Domain; import com.cloud.exception.PermissionDeniedException; +import com.cloud.network.vpc.VpcOffering; import com.cloud.offering.DiskOffering; +import com.cloud.offering.NetworkOffering; import com.cloud.offering.ServiceOffering; import com.cloud.user.Account; import com.cloud.user.User; @@ -136,7 +138,11 @@ public interface SecurityChecker extends Adapter { boolean checkAccess(Account account, DataCenter zone) throws PermissionDeniedException; - public boolean checkAccess(Account account, ServiceOffering so) throws PermissionDeniedException; + boolean checkAccess(Account account, ServiceOffering so, DataCenter zone) throws PermissionDeniedException; - boolean checkAccess(Account account, DiskOffering dof) throws PermissionDeniedException; + boolean checkAccess(Account account, DiskOffering dof, DataCenter zone) throws PermissionDeniedException; + + boolean checkAccess(Account account, NetworkOffering nof, DataCenter zone) throws PermissionDeniedException; + + boolean checkAccess(Account account, VpcOffering vof, DataCenter zone) throws PermissionDeniedException; } diff --git a/api/src/main/java/org/apache/cloudstack/api/ApiConstants.java b/api/src/main/java/org/apache/cloudstack/api/ApiConstants.java index 8714d50bae5..d9e2e7f1fee 100644 --- a/api/src/main/java/org/apache/cloudstack/api/ApiConstants.java +++ b/api/src/main/java/org/apache/cloudstack/api/ApiConstants.java @@ -358,6 +358,7 @@ public class ApiConstants { public static final String VNET = "vnet"; public static final String IS_VOLATILE = "isvolatile"; public static final String VOLUME_ID = "volumeid"; + public static final String ZONE = "zone"; public static final String ZONE_ID = "zoneid"; public static final String ZONE_NAME = "zonename"; public static final String NETWORK_TYPE = "networktype"; diff --git a/api/src/main/java/org/apache/cloudstack/api/command/admin/network/CreateNetworkOfferingCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/admin/network/CreateNetworkOfferingCmd.java index 7c8c46a9c9e..39c443ccfdb 100644 --- a/api/src/main/java/org/apache/cloudstack/api/command/admin/network/CreateNetworkOfferingCmd.java +++ b/api/src/main/java/org/apache/cloudstack/api/command/admin/network/CreateNetworkOfferingCmd.java @@ -20,9 +20,14 @@ import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; import java.util.Iterator; +import java.util.LinkedHashSet; import java.util.List; import java.util.Map; +import java.util.Set; +import org.apache.cloudstack.api.response.DomainResponse; +import org.apache.cloudstack.api.response.ZoneResponse; +import org.apache.commons.collections.CollectionUtils; import org.apache.log4j.Logger; import org.apache.cloudstack.api.APICommand; @@ -58,9 +63,9 @@ public class CreateNetworkOfferingCmd extends BaseCmd { private String displayText; @Parameter(name = ApiConstants.TRAFFIC_TYPE, - type = CommandType.STRING, - required = true, - description = "the traffic type for the network offering. Supported type in current release is GUEST only") + type = CommandType.STRING, + required = true, + description = "the traffic type for the network offering. Supported type in current release is GUEST only") private String traffictype; @Parameter(name = ApiConstants.TAGS, type = CommandType.STRING, description = "the tags for the network offering.", length = 4096) @@ -79,37 +84,37 @@ public class CreateNetworkOfferingCmd extends BaseCmd { private Boolean conserveMode; @Parameter(name = ApiConstants.SERVICE_OFFERING_ID, - type = CommandType.UUID, - entityType = ServiceOfferingResponse.class, - description = "the service offering ID used by virtual router provider") + type = CommandType.UUID, + entityType = ServiceOfferingResponse.class, + description = "the service offering ID used by virtual router provider") private Long serviceOfferingId; @Parameter(name = ApiConstants.GUEST_IP_TYPE, type = CommandType.STRING, required = true, description = "guest type of the network offering: Shared or Isolated") private String guestIptype; @Parameter(name = ApiConstants.SUPPORTED_SERVICES, - type = CommandType.LIST, - required = true, - collectionType = CommandType.STRING, - description = "services supported by the network offering") + type = CommandType.LIST, + required = true, + collectionType = CommandType.STRING, + description = "services supported by the network offering") private List supportedServices; @Parameter(name = ApiConstants.SERVICE_PROVIDER_LIST, - type = CommandType.MAP, - description = "provider to service mapping. If not specified, the provider for the service will be mapped to the default provider on the physical network") + type = CommandType.MAP, + description = "provider to service mapping. If not specified, the provider for the service will be mapped to the default provider on the physical network") private Map serviceProviderList; @Parameter(name = ApiConstants.SERVICE_CAPABILITY_LIST, type = CommandType.MAP, description = "desired service capabilities as part of network offering") private Map serviceCapabilitystList; @Parameter(name = ApiConstants.SPECIFY_IP_RANGES, - type = CommandType.BOOLEAN, - description = "true if network offering supports specifying ip ranges; defaulted to false if not specified") + type = CommandType.BOOLEAN, + description = "true if network offering supports specifying ip ranges; defaulted to false if not specified") private Boolean specifyIpRanges; @Parameter(name = ApiConstants.IS_PERSISTENT, - type = CommandType.BOOLEAN, - description = "true if network offering supports persistent networks; defaulted to false if not specified") + type = CommandType.BOOLEAN, + description = "true if network offering supports persistent networks; defaulted to false if not specified") private Boolean isPersistent; @Parameter(name = ApiConstants.FOR_VPC, @@ -118,26 +123,41 @@ public class CreateNetworkOfferingCmd extends BaseCmd { private Boolean forVpc; @Parameter(name = ApiConstants.DETAILS, type = CommandType.MAP, since = "4.2.0", description = "Network offering details in key/value pairs." - + " Supported keys are internallbprovider/publiclbprovider with service provider as a value, and" - + " promiscuousmode/macaddresschanges/forgedtransmits with true/false as value to accept/reject the security settings if available for a nic/portgroup") + + " Supported keys are internallbprovider/publiclbprovider with service provider as a value, and" + + " promiscuousmode/macaddresschanges/forgedtransmits with true/false as value to accept/reject the security settings if available for a nic/portgroup") protected Map details; @Parameter(name = ApiConstants.EGRESS_DEFAULT_POLICY, - type = CommandType.BOOLEAN, - description = "true if guest network default egress policy is allow; false if default egress policy is deny") + type = CommandType.BOOLEAN, + description = "true if guest network default egress policy is allow; false if default egress policy is deny") private Boolean egressDefaultPolicy; @Parameter(name = ApiConstants.KEEPALIVE_ENABLED, - type = CommandType.BOOLEAN, - required = false, - description = "if true keepalive will be turned on in the loadbalancer. At the time of writing this has only an effect on haproxy; the mode http and httpclose options are unset in the haproxy conf file.") + type = CommandType.BOOLEAN, + required = false, + description = "if true keepalive will be turned on in the loadbalancer. At the time of writing this has only an effect on haproxy; the mode http and httpclose options are unset in the haproxy conf file.") private Boolean keepAliveEnabled; @Parameter(name = ApiConstants.MAX_CONNECTIONS, - type = CommandType.INTEGER, - description = "maximum number of concurrent connections supported by the network offering") + type = CommandType.INTEGER, + description = "maximum number of concurrent connections supported by the network offering") private Integer maxConnections; + @Parameter(name = ApiConstants.DOMAIN_ID, + type = CommandType.LIST, + collectionType = CommandType.UUID, + entityType = DomainResponse.class, + description = "the ID of the containing domain(s), null for public offerings") + private List domainIds; + + @Parameter(name = ApiConstants.ZONE_ID, + type = CommandType.LIST, + collectionType = CommandType.UUID, + entityType = ZoneResponse.class, + description = "the ID of the containing zone(s), null for public offerings", + since = "4.13") + private List zoneIds; + ///////////////////////////////////////////////////// /////////////////// Accessors /////////////////////// ///////////////////////////////////////////////////// @@ -227,7 +247,7 @@ public class CreateNetworkOfferingCmd extends BaseCmd { Collection servicesCollection = serviceProviderList.values(); Iterator iter = servicesCollection.iterator(); while (iter.hasNext()) { - HashMap services = (HashMap)iter.next(); + HashMap services = (HashMap) iter.next(); String service = services.get("service"); String provider = services.get("provider"); List providerList = null; @@ -252,7 +272,7 @@ public class CreateNetworkOfferingCmd extends BaseCmd { Collection serviceCapabilityCollection = serviceCapabilitystList.values(); Iterator iter = serviceCapabilityCollection.iterator(); while (iter.hasNext()) { - HashMap svcCapabilityMap = (HashMap)iter.next(); + HashMap svcCapabilityMap = (HashMap) iter.next(); Capability capability = null; String svc = svcCapabilityMap.get("service"); String capabilityName = svcCapabilityMap.get("capabilitytype"); @@ -283,11 +303,10 @@ public class CreateNetworkOfferingCmd extends BaseCmd { } Collection paramsCollection = details.values(); - Object objlist[]= paramsCollection.toArray(); - Map params = (Map)(objlist[0]); - for(int i=1; i< objlist.length; i++) - { - params.putAll((Map)(objlist[i])); + Object objlist[] = paramsCollection.toArray(); + Map params = (Map) (objlist[0]); + for (int i = 1; i < objlist.length; i++) { + params.putAll((Map) (objlist[i])); } return params; @@ -297,7 +316,25 @@ public class CreateNetworkOfferingCmd extends BaseCmd { Map data = getDetails(); if (data == null) return null; - return data.get(NetworkOffering.Detail.servicepackageuuid+ ""); + return data.get(NetworkOffering.Detail.servicepackageuuid + ""); + } + + public List getDomainIds() { + if (CollectionUtils.isNotEmpty(domainIds)) { + Set set = new LinkedHashSet<>(domainIds); + domainIds.clear(); + domainIds.addAll(set); + } + return domainIds; + } + + public List getZoneIds() { + if (CollectionUtils.isNotEmpty(zoneIds)) { + Set set = new LinkedHashSet<>(zoneIds); + zoneIds.clear(); + zoneIds.addAll(set); + } + return zoneIds; } ///////////////////////////////////////////////////// diff --git a/api/src/main/java/org/apache/cloudstack/api/command/admin/network/UpdateNetworkOfferingCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/admin/network/UpdateNetworkOfferingCmd.java index 5c58530fe1f..83c82741ab2 100644 --- a/api/src/main/java/org/apache/cloudstack/api/command/admin/network/UpdateNetworkOfferingCmd.java +++ b/api/src/main/java/org/apache/cloudstack/api/command/admin/network/UpdateNetworkOfferingCmd.java @@ -16,7 +16,8 @@ // under the License. package org.apache.cloudstack.api.command.admin.network; -import org.apache.log4j.Logger; +import java.util.ArrayList; +import java.util.List; import org.apache.cloudstack.api.APICommand; import org.apache.cloudstack.api.ApiConstants; @@ -25,9 +26,14 @@ import org.apache.cloudstack.api.BaseCmd; import org.apache.cloudstack.api.Parameter; import org.apache.cloudstack.api.ServerApiException; import org.apache.cloudstack.api.response.NetworkOfferingResponse; +import org.apache.log4j.Logger; +import com.cloud.dc.DataCenter; +import com.cloud.domain.Domain; +import com.cloud.exception.InvalidParameterValueException; import com.cloud.offering.NetworkOffering; import com.cloud.user.Account; +import com.google.common.base.Strings; @APICommand(name = "updateNetworkOffering", description = "Updates a network offering.", responseObject = NetworkOfferingResponse.class, requestHasSensitiveInfo = false, responseHasSensitiveInfo = false) @@ -49,7 +55,7 @@ public class UpdateNetworkOfferingCmd extends BaseCmd { private String displayText; @Parameter(name = ApiConstants.AVAILABILITY, type = CommandType.STRING, description = "the availability of network offering." - + " Default value is Required for Guest Virtual network offering; Optional for Guest Direct network offering") + + " Default value is Required for Guest Virtual network offering; Optional for Guest Direct network offering") private String availability; @Parameter(name = ApiConstants.SORT_KEY, type = CommandType.INTEGER, description = "sort key of the network offering, integer") @@ -59,19 +65,30 @@ public class UpdateNetworkOfferingCmd extends BaseCmd { private String state; @Parameter(name = ApiConstants.KEEPALIVE_ENABLED, - type = CommandType.BOOLEAN, - required = false, - description = "if true keepalive will be turned on in the loadbalancer. At the time of writing this has only an effect on haproxy; the mode http and httpclose options are unset in the haproxy conf file.") + type = CommandType.BOOLEAN, + required = false, + description = "if true keepalive will be turned on in the loadbalancer. At the time of writing this has only an effect on haproxy; the mode http and httpclose options are unset in the haproxy conf file.") private Boolean keepAliveEnabled; @Parameter(name = ApiConstants.MAX_CONNECTIONS, - type = CommandType.INTEGER, - description = "maximum number of concurrent connections supported by the network offering") + type = CommandType.INTEGER, + description = "maximum number of concurrent connections supported by the network offering") private Integer maxConnections; @Parameter(name = ApiConstants.TAGS, type = CommandType.STRING, description = "the tags for the network offering.", length = 4096) private String tags; + @Parameter(name = ApiConstants.DOMAIN_ID, + type = CommandType.STRING, + description = "the ID of the containing domain(s) as comma separated string, public for public offerings") + private String domainIds; + + @Parameter(name = ApiConstants.ZONE_ID, + type = CommandType.STRING, + description = "the ID of the containing zone(s) as comma separated string, all for all zones offerings", + since = "4.13") + private String zoneIds; + ///////////////////////////////////////////////////// /////////////////// Accessors /////////////////////// ///////////////////////////////////////////////////// @@ -112,6 +129,66 @@ public class UpdateNetworkOfferingCmd extends BaseCmd { return tags; } + public List getDomainIds() { + List validDomainIds = new ArrayList<>(); + if (!Strings.isNullOrEmpty(domainIds)) { + if (domainIds.contains(",")) { + String[] domains = domainIds.split(","); + for (String domain : domains) { + Domain validDomain = _entityMgr.findByUuid(Domain.class, domain.trim()); + if (validDomain != null) { + validDomainIds.add(validDomain.getId()); + } else { + throw new InvalidParameterValueException("Failed to create network offering because invalid domain has been specified."); + } + } + } else { + domainIds = domainIds.trim(); + if (!domainIds.matches("public")) { + Domain validDomain = _entityMgr.findByUuid(Domain.class, domainIds.trim()); + if (validDomain != null) { + validDomainIds.add(validDomain.getId()); + } else { + throw new InvalidParameterValueException("Failed to create network offering because invalid domain has been specified."); + } + } + } + } else { + validDomainIds.addAll(_configService.getNetworkOfferingDomains(id)); + } + return validDomainIds; + } + + public List getZoneIds() { + List validZoneIds = new ArrayList<>(); + if (!Strings.isNullOrEmpty(zoneIds)) { + if (zoneIds.contains(",")) { + String[] zones = zoneIds.split(","); + for (String zone : zones) { + DataCenter validZone = _entityMgr.findByUuid(DataCenter.class, zone.trim()); + if (validZone != null) { + validZoneIds.add(validZone.getId()); + } else { + throw new InvalidParameterValueException("Failed to create network offering because invalid zone has been specified."); + } + } + } else { + zoneIds = zoneIds.trim(); + if (!zoneIds.matches("all")) { + DataCenter validZone = _entityMgr.findByUuid(DataCenter.class, zoneIds.trim()); + if (validZone != null) { + validZoneIds.add(validZone.getId()); + } else { + throw new InvalidParameterValueException("Failed to create network offering because invalid zone has been specified."); + } + } + } + } else { + validZoneIds.addAll(_configService.getNetworkOfferingZones(id)); + } + return validZoneIds; + } + ///////////////////////////////////////////////////// /////////////// API Implementation/////////////////// ///////////////////////////////////////////////////// diff --git a/api/src/main/java/org/apache/cloudstack/api/command/admin/offering/CreateDiskOfferingCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/admin/offering/CreateDiskOfferingCmd.java index 469f714d028..3ff8f69568c 100644 --- a/api/src/main/java/org/apache/cloudstack/api/command/admin/offering/CreateDiskOfferingCmd.java +++ b/api/src/main/java/org/apache/cloudstack/api/command/admin/offering/CreateDiskOfferingCmd.java @@ -16,7 +16,9 @@ // under the License. package org.apache.cloudstack.api.command.admin.offering; -import org.apache.log4j.Logger; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Set; import org.apache.cloudstack.api.APICommand; import org.apache.cloudstack.api.ApiConstants; @@ -26,10 +28,13 @@ import org.apache.cloudstack.api.Parameter; import org.apache.cloudstack.api.ServerApiException; import org.apache.cloudstack.api.response.DiskOfferingResponse; import org.apache.cloudstack.api.response.DomainResponse; +import org.apache.cloudstack.api.response.ZoneResponse; +import org.apache.commons.collections.CollectionUtils; +import org.apache.log4j.Logger; -import com.cloud.storage.Storage.ProvisioningType; import com.cloud.offering.DiskOffering; import com.cloud.offering.ServiceOffering; +import com.cloud.storage.Storage.ProvisioningType; import com.cloud.user.Account; @APICommand(name = "createDiskOffering", description = "Creates a disk offering.", responseObject = DiskOfferingResponse.class, @@ -59,10 +64,19 @@ public class CreateDiskOfferingCmd extends BaseCmd { private Boolean customized; @Parameter(name = ApiConstants.DOMAIN_ID, - type = CommandType.UUID, - entityType = DomainResponse.class, - description = "the ID of the containing domain, null for public offerings") - private Long domainId; + type = CommandType.LIST, + collectionType = CommandType.UUID, + entityType = DomainResponse.class, + description = "the ID of the containing domain(s), null for public offerings") + private List domainIds; + + @Parameter(name = ApiConstants.ZONE_ID, + type = CommandType.LIST, + collectionType = CommandType.UUID, + entityType = ZoneResponse.class, + description = "the ID of the containing zone(s), null for public offerings", + since = "4.13") + private List zoneIds; @Parameter(name = ApiConstants.STORAGE_TYPE, type = CommandType.STRING, description = "the storage type of the disk offering. Values are local and shared.") private String storageType = ServiceOffering.StorageType.shared.toString(); @@ -166,8 +180,22 @@ public class CreateDiskOfferingCmd extends BaseCmd { return maxIops; } - public Long getDomainId() { - return domainId; + public List getDomainIds() { + if (CollectionUtils.isNotEmpty(domainIds)) { + Set set = new LinkedHashSet<>(domainIds); + domainIds.clear(); + domainIds.addAll(set); + } + return domainIds; + } + + public List getZoneIds() { + if (CollectionUtils.isNotEmpty(zoneIds)) { + Set set = new LinkedHashSet<>(zoneIds); + zoneIds.clear(); + zoneIds.addAll(set); + } + return zoneIds; } public Long getBytesReadRate() { @@ -222,7 +250,7 @@ public class CreateDiskOfferingCmd extends BaseCmd { return storageType; } - public String getProvisioningType(){ + public String getProvisioningType() { return provisioningType; } diff --git a/api/src/main/java/org/apache/cloudstack/api/command/admin/offering/CreateServiceOfferingCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/admin/offering/CreateServiceOfferingCmd.java index 60a55a5ffd7..c30b43745c5 100644 --- a/api/src/main/java/org/apache/cloudstack/api/command/admin/offering/CreateServiceOfferingCmd.java +++ b/api/src/main/java/org/apache/cloudstack/api/command/admin/offering/CreateServiceOfferingCmd.java @@ -18,7 +18,10 @@ package org.apache.cloudstack.api.command.admin.offering; import java.util.Collection; import java.util.HashMap; +import java.util.LinkedHashSet; +import java.util.List; import java.util.Map; +import java.util.Set; import org.apache.cloudstack.api.APICommand; import org.apache.cloudstack.api.ApiConstants; @@ -28,7 +31,9 @@ import org.apache.cloudstack.api.Parameter; import org.apache.cloudstack.api.ServerApiException; import org.apache.cloudstack.api.response.DomainResponse; import org.apache.cloudstack.api.response.ServiceOfferingResponse; +import org.apache.cloudstack.api.response.ZoneResponse; import org.apache.commons.collections.MapUtils; +import org.apache.commons.collections.CollectionUtils; import org.apache.log4j.Logger; import com.cloud.exception.InvalidParameterValueException; @@ -72,8 +77,8 @@ public class CreateServiceOfferingCmd extends BaseCmd { private Boolean limitCpuUse; @Parameter(name = ApiConstants.IS_VOLATILE, - type = CommandType.BOOLEAN, - description = "true if the virtual machine needs to be volatile so that on every reboot of VM, original root disk is dettached then destroyed and a fresh root disk is created and attached to VM") + type = CommandType.BOOLEAN, + description = "true if the virtual machine needs to be volatile so that on every reboot of VM, original root disk is dettached then destroyed and a fresh root disk is created and attached to VM") private Boolean isVolatile; @Parameter(name = ApiConstants.STORAGE_TYPE, type = CommandType.STRING, description = "the storage type of the service offering. Values are local and shared.") @@ -83,10 +88,19 @@ public class CreateServiceOfferingCmd extends BaseCmd { private String tags; @Parameter(name = ApiConstants.DOMAIN_ID, - type = CommandType.UUID, - entityType = DomainResponse.class, - description = "the ID of the containing domain, null for public offerings") - private Long domainId; + type = CommandType.LIST, + collectionType = CommandType.UUID, + entityType = DomainResponse.class, + description = "the ID of the containing domain(s), null for public offerings") + private List domainIds; + + @Parameter(name = ApiConstants.ZONE_ID, + type = CommandType.LIST, + collectionType = CommandType.UUID, + entityType = ZoneResponse.class, + description = "the ID of the containing zone(s), null for public offerings", + since = "4.13") + private List zoneIds; @Parameter(name = ApiConstants.HOST_TAGS, type = CommandType.STRING, description = "the host tag for this service offering.") private String hostTag; @@ -95,18 +109,18 @@ public class CreateServiceOfferingCmd extends BaseCmd { private Boolean isSystem; @Parameter(name = ApiConstants.SYSTEM_VM_TYPE, - type = CommandType.STRING, - description = "the system VM type. Possible types are \"domainrouter\", \"consoleproxy\" and \"secondarystoragevm\".") + type = CommandType.STRING, + description = "the system VM type. Possible types are \"domainrouter\", \"consoleproxy\" and \"secondarystoragevm\".") private String systemVmType; @Parameter(name = ApiConstants.NETWORKRATE, - type = CommandType.INTEGER, - description = "data transfer rate in megabits per second allowed. Supported only for non-System offering and system offerings having \"domainrouter\" systemvmtype") + type = CommandType.INTEGER, + description = "data transfer rate in megabits per second allowed. Supported only for non-System offering and system offerings having \"domainrouter\" systemvmtype") private Integer networkRate; @Parameter(name = ApiConstants.DEPLOYMENT_PLANNER, - type = CommandType.STRING, - description = "The deployment planner heuristics used to deploy a VM of this offering. If null, value of global config vm.deployment.planner is used") + type = CommandType.STRING, + description = "The deployment planner heuristics used to deploy a VM of this offering. If null, value of global config vm.deployment.planner is used") private String deploymentPlanner; @Parameter(name = ApiConstants.SERVICE_OFFERING_DETAILS, type = CommandType.MAP, description = "details for planner, used to store specific parameters") @@ -214,7 +228,7 @@ public class CreateServiceOfferingCmd extends BaseCmd { return displayText; } - public String getProvisioningType(){ + public String getProvisioningType() { return provisioningType; } @@ -249,8 +263,22 @@ public class CreateServiceOfferingCmd extends BaseCmd { return tags; } - public Long getDomainId() { - return domainId; + public List getDomainIds() { + if (CollectionUtils.isNotEmpty(domainIds)) { + Set set = new LinkedHashSet<>(domainIds); + domainIds.clear(); + domainIds.addAll(set); + } + return domainIds; + } + + public List getZoneIds() { + if (CollectionUtils.isNotEmpty(zoneIds)) { + Set set = new LinkedHashSet<>(zoneIds); + zoneIds.clear(); + zoneIds.addAll(set); + } + return zoneIds; } public String getHostTag() { diff --git a/api/src/main/java/org/apache/cloudstack/api/command/admin/offering/UpdateDiskOfferingCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/admin/offering/UpdateDiskOfferingCmd.java index 6e1fde55a30..903695307bb 100644 --- a/api/src/main/java/org/apache/cloudstack/api/command/admin/offering/UpdateDiskOfferingCmd.java +++ b/api/src/main/java/org/apache/cloudstack/api/command/admin/offering/UpdateDiskOfferingCmd.java @@ -16,7 +16,8 @@ // under the License. package org.apache.cloudstack.api.command.admin.offering; -import org.apache.log4j.Logger; +import java.util.ArrayList; +import java.util.List; import org.apache.cloudstack.api.APICommand; import org.apache.cloudstack.api.ApiConstants; @@ -25,9 +26,14 @@ import org.apache.cloudstack.api.BaseCmd; import org.apache.cloudstack.api.Parameter; import org.apache.cloudstack.api.ServerApiException; import org.apache.cloudstack.api.response.DiskOfferingResponse; +import org.apache.log4j.Logger; +import com.cloud.dc.DataCenter; +import com.cloud.domain.Domain; +import com.cloud.exception.InvalidParameterValueException; import com.cloud.offering.DiskOffering; import com.cloud.user.Account; +import com.google.common.base.Strings; @APICommand(name = "updateDiskOffering", description = "Updates a disk offering.", responseObject = DiskOfferingResponse.class, requestHasSensitiveInfo = false, responseHasSensitiveInfo = false) @@ -40,9 +46,9 @@ public class UpdateDiskOfferingCmd extends BaseCmd { ///////////////////////////////////////////////////// @Parameter(name = ApiConstants.DISPLAY_TEXT, - type = CommandType.STRING, - description = "updates alternate display text of the disk offering with this value", - length = 4096) + type = CommandType.STRING, + description = "updates alternate display text of the disk offering with this value", + length = 4096) private String displayText; @Parameter(name = ApiConstants.ID, type = CommandType.UUID, entityType = DiskOfferingResponse.class, required = true, description = "ID of the disk offering") @@ -55,10 +61,22 @@ public class UpdateDiskOfferingCmd extends BaseCmd { private Integer sortKey; @Parameter(name = ApiConstants.DISPLAY_OFFERING, - type = CommandType.BOOLEAN, - description = "an optional field, whether to display the offering to the end user or not.") + type = CommandType.BOOLEAN, + description = "an optional field, whether to display the offering to the end user or not.") private Boolean displayOffering; + @Parameter(name = ApiConstants.DOMAIN_ID, + type = CommandType.STRING, + description = "the ID of the containing domain(s) as comma separated string, public for public offerings", + since = "4.13") + private String domainIds; + + @Parameter(name = ApiConstants.ZONE_ID, + type = CommandType.STRING, + description = "the ID of the containing zone(s) as comma separated string, all for all zones offerings", + since = "4.13") + private String zoneIds; + ///////////////////////////////////////////////////// /////////////////// Accessors /////////////////////// ///////////////////////////////////////////////////// @@ -83,6 +101,66 @@ public class UpdateDiskOfferingCmd extends BaseCmd { return displayOffering; } + public List getDomainIds() { + List validDomainIds = new ArrayList<>(); + if (!Strings.isNullOrEmpty(domainIds)) { + if (domainIds.contains(",")) { + String[] domains = domainIds.split(","); + for (String domain : domains) { + Domain validDomain = _entityMgr.findByUuid(Domain.class, domain.trim()); + if (validDomain != null) { + validDomainIds.add(validDomain.getId()); + } else { + throw new InvalidParameterValueException("Failed to create disk offering because invalid domain has been specified."); + } + } + } else { + domainIds = domainIds.trim(); + if (!domainIds.matches("public")) { + Domain validDomain = _entityMgr.findByUuid(Domain.class, domainIds.trim()); + if (validDomain != null) { + validDomainIds.add(validDomain.getId()); + } else { + throw new InvalidParameterValueException("Failed to create disk offering because invalid domain has been specified."); + } + } + } + } else { + validDomainIds.addAll(_configService.getDiskOfferingDomains(id)); + } + return validDomainIds; + } + + public List getZoneIds() { + List validZoneIds = new ArrayList<>(); + if (!Strings.isNullOrEmpty(zoneIds)) { + if (zoneIds.contains(",")) { + String[] zones = zoneIds.split(","); + for (String zone : zones) { + DataCenter validZone = _entityMgr.findByUuid(DataCenter.class, zone.trim()); + if (validZone != null) { + validZoneIds.add(validZone.getId()); + } else { + throw new InvalidParameterValueException("Failed to create disk offering because invalid zone has been specified."); + } + } + } else { + zoneIds = zoneIds.trim(); + if (!zoneIds.matches("all")) { + DataCenter validZone = _entityMgr.findByUuid(DataCenter.class, zoneIds.trim()); + if (validZone != null) { + validZoneIds.add(validZone.getId()); + } else { + throw new InvalidParameterValueException("Failed to create disk offering because invalid zone has been specified."); + } + } + } + } else { + validZoneIds.addAll(_configService.getDiskOfferingZones(id)); + } + return validZoneIds; + } + ///////////////////////////////////////////////////// /////////////// API Implementation/////////////////// ///////////////////////////////////////////////////// diff --git a/api/src/main/java/org/apache/cloudstack/api/command/admin/offering/UpdateServiceOfferingCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/admin/offering/UpdateServiceOfferingCmd.java index f4f4bdfac88..43a0666e934 100644 --- a/api/src/main/java/org/apache/cloudstack/api/command/admin/offering/UpdateServiceOfferingCmd.java +++ b/api/src/main/java/org/apache/cloudstack/api/command/admin/offering/UpdateServiceOfferingCmd.java @@ -16,7 +16,8 @@ // under the License. package org.apache.cloudstack.api.command.admin.offering; -import org.apache.log4j.Logger; +import java.util.ArrayList; +import java.util.List; import org.apache.cloudstack.api.APICommand; import org.apache.cloudstack.api.ApiConstants; @@ -25,9 +26,14 @@ import org.apache.cloudstack.api.BaseCmd; import org.apache.cloudstack.api.Parameter; import org.apache.cloudstack.api.ServerApiException; import org.apache.cloudstack.api.response.ServiceOfferingResponse; +import org.apache.log4j.Logger; +import com.cloud.dc.DataCenter; +import com.cloud.domain.Domain; +import com.cloud.exception.InvalidParameterValueException; import com.cloud.offering.ServiceOffering; import com.cloud.user.Account; +import com.google.common.base.Strings; @APICommand(name = "updateServiceOffering", description = "Updates a service offering.", responseObject = ServiceOfferingResponse.class, requestHasSensitiveInfo = false, responseHasSensitiveInfo = false) @@ -39,10 +45,10 @@ public class UpdateServiceOfferingCmd extends BaseCmd { //////////////// API parameters ///////////////////// ///////////////////////////////////////////////////// @Parameter(name = ApiConstants.ID, - type = CommandType.UUID, - entityType = ServiceOfferingResponse.class, - required = true, - description = "the ID of the service offering to be updated") + type = CommandType.UUID, + entityType = ServiceOfferingResponse.class, + required = true, + description = "the ID of the service offering to be updated") private Long id; @Parameter(name = ApiConstants.DISPLAY_TEXT, type = CommandType.STRING, description = "the display text of the service offering to be updated") @@ -54,6 +60,17 @@ public class UpdateServiceOfferingCmd extends BaseCmd { @Parameter(name = ApiConstants.SORT_KEY, type = CommandType.INTEGER, description = "sort key of the service offering, integer") private Integer sortKey; + @Parameter(name = ApiConstants.DOMAIN_ID, + type = CommandType.STRING, + description = "the ID of the containing domain(s) as comma separated string, public for public offerings") + private String domainIds; + + @Parameter(name = ApiConstants.ZONE_ID, + type = CommandType.STRING, + description = "the ID of the containing zone(s) as comma separated string, all for all zones offerings", + since = "4.13") + private String zoneIds; + ///////////////////////////////////////////////////// /////////////////// Accessors /////////////////////// ///////////////////////////////////////////////////// @@ -74,6 +91,66 @@ public class UpdateServiceOfferingCmd extends BaseCmd { return sortKey; } + public List getDomainIds() { + List validDomainIds = new ArrayList<>(); + if (!Strings.isNullOrEmpty(domainIds)) { + if (domainIds.contains(",")) { + String[] domains = domainIds.split(","); + for (String domain : domains) { + Domain validDomain = _entityMgr.findByUuid(Domain.class, domain.trim()); + if (validDomain != null) { + validDomainIds.add(validDomain.getId()); + } else { + throw new InvalidParameterValueException("Failed to create service offering because invalid domain has been specified."); + } + } + } else { + domainIds = domainIds.trim(); + if (!domainIds.matches("public")) { + Domain validDomain = _entityMgr.findByUuid(Domain.class, domainIds.trim()); + if (validDomain != null) { + validDomainIds.add(validDomain.getId()); + } else { + throw new InvalidParameterValueException("Failed to create service offering because invalid domain has been specified."); + } + } + } + } else { + validDomainIds.addAll(_configService.getServiceOfferingDomains(id)); + } + return validDomainIds; + } + + public List getZoneIds() { + List validZoneIds = new ArrayList<>(); + if (!Strings.isNullOrEmpty(zoneIds)) { + if (zoneIds.contains(",")) { + String[] zones = zoneIds.split(","); + for (String zone : zones) { + DataCenter validZone = _entityMgr.findByUuid(DataCenter.class, zone.trim()); + if (validZone != null) { + validZoneIds.add(validZone.getId()); + } else { + throw new InvalidParameterValueException("Failed to create service offering because invalid zone has been specified."); + } + } + } else { + zoneIds = zoneIds.trim(); + if (!zoneIds.matches("all")) { + DataCenter validZone = _entityMgr.findByUuid(DataCenter.class, zoneIds.trim()); + if (validZone != null) { + validZoneIds.add(validZone.getId()); + } else { + throw new InvalidParameterValueException("Failed to create service offering because invalid zone has been specified."); + } + } + } + } else { + validZoneIds.addAll(_configService.getServiceOfferingZones(id)); + } + return validZoneIds; + } + ///////////////////////////////////////////////////// /////////////// API Implementation/////////////////// ///////////////////////////////////////////////////// diff --git a/api/src/main/java/org/apache/cloudstack/api/command/admin/vpc/CreateVPCOfferingCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/admin/vpc/CreateVPCOfferingCmd.java index 99c1719e1b6..d629a6e789c 100644 --- a/api/src/main/java/org/apache/cloudstack/api/command/admin/vpc/CreateVPCOfferingCmd.java +++ b/api/src/main/java/org/apache/cloudstack/api/command/admin/vpc/CreateVPCOfferingCmd.java @@ -20,9 +20,14 @@ import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; import java.util.Iterator; +import java.util.LinkedHashSet; import java.util.List; import java.util.Map; +import java.util.Set; +import org.apache.cloudstack.api.response.DomainResponse; +import org.apache.cloudstack.api.response.ZoneResponse; +import org.apache.commons.collections.CollectionUtils; import org.apache.log4j.Logger; import org.apache.cloudstack.api.APICommand; @@ -75,6 +80,21 @@ public class CreateVPCOfferingCmd extends BaseAsyncCreateCmd { description = "the ID of the service offering for the VPC router appliance") private Long serviceOfferingId; + @Parameter(name = ApiConstants.DOMAIN_ID, + type = CommandType.LIST, + collectionType = CommandType.UUID, + entityType = DomainResponse.class, + description = "the ID of the containing domain(s), null for public offerings") + private List domainIds; + + @Parameter(name = ApiConstants.ZONE_ID, + type = CommandType.LIST, + collectionType = CommandType.UUID, + entityType = ZoneResponse.class, + description = "the ID of the containing zone(s), null for public offerings", + since = "4.13") + private List zoneIds; + ///////////////////////////////////////////////////// /////////////////// Accessors /////////////////////// ///////////////////////////////////////////////////// @@ -127,10 +147,27 @@ public class CreateVPCOfferingCmd extends BaseAsyncCreateCmd { return serviceOfferingId; } + public List getDomainIds() { + if (CollectionUtils.isNotEmpty(domainIds)) { + Set set = new LinkedHashSet<>(domainIds); + domainIds.clear(); + domainIds.addAll(set); + } + return domainIds; + } + + public List getZoneIds() { + if (CollectionUtils.isNotEmpty(zoneIds)) { + Set set = new LinkedHashSet<>(zoneIds); + zoneIds.clear(); + zoneIds.addAll(set); + } + return zoneIds; + } + @Override public void create() throws ResourceAllocationException { - VpcOffering vpcOff = _vpcProvSvc.createVpcOffering(getVpcOfferingName(), getDisplayText(), - getSupportedServices(), getServiceProviders(), getServiceCapabilitystList(), getServiceOfferingId()); + VpcOffering vpcOff = _vpcProvSvc.createVpcOffering(this); if (vpcOff != null) { setEntityId(vpcOff.getId()); setEntityUuid(vpcOff.getUuid()); diff --git a/api/src/main/java/org/apache/cloudstack/api/command/admin/vpc/UpdateVPCOfferingCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/admin/vpc/UpdateVPCOfferingCmd.java index f681ca94e89..ce8f96c464d 100644 --- a/api/src/main/java/org/apache/cloudstack/api/command/admin/vpc/UpdateVPCOfferingCmd.java +++ b/api/src/main/java/org/apache/cloudstack/api/command/admin/vpc/UpdateVPCOfferingCmd.java @@ -16,7 +16,8 @@ // under the License. package org.apache.cloudstack.api.command.admin.vpc; -import org.apache.log4j.Logger; +import java.util.ArrayList; +import java.util.List; import org.apache.cloudstack.api.APICommand; import org.apache.cloudstack.api.ApiConstants; @@ -25,10 +26,15 @@ import org.apache.cloudstack.api.BaseAsyncCmd; import org.apache.cloudstack.api.Parameter; import org.apache.cloudstack.api.ServerApiException; import org.apache.cloudstack.api.response.VpcOfferingResponse; +import org.apache.log4j.Logger; +import com.cloud.dc.DataCenter; +import com.cloud.domain.Domain; import com.cloud.event.EventTypes; +import com.cloud.exception.InvalidParameterValueException; import com.cloud.network.vpc.VpcOffering; import com.cloud.user.Account; +import com.google.common.base.Strings; @APICommand(name = "updateVPCOffering", description = "Updates VPC offering", responseObject = VpcOfferingResponse.class, requestHasSensitiveInfo = false, responseHasSensitiveInfo = false) @@ -52,6 +58,17 @@ public class UpdateVPCOfferingCmd extends BaseAsyncCmd { @Parameter(name = ApiConstants.STATE, type = CommandType.STRING, description = "update state for the VPC offering; " + "supported states - Enabled/Disabled") private String state; + @Parameter(name = ApiConstants.DOMAIN_ID, + type = CommandType.STRING, + description = "the ID of the containing domain(s) as comma separated string, public for public offerings") + private String domainIds; + + @Parameter(name = ApiConstants.ZONE_ID, + type = CommandType.STRING, + description = "the ID of the containing zone(s) as comma separated string, all for all zones offerings", + since = "4.13") + private String zoneIds; + @Parameter(name = ApiConstants.SORT_KEY, type = CommandType.INTEGER, description = "sort key of the VPC offering, integer") private Integer sortKey; @@ -75,11 +92,70 @@ public class UpdateVPCOfferingCmd extends BaseAsyncCmd { return state; } + public List getDomainIds() { + List validDomainIds = new ArrayList<>(); + if (!Strings.isNullOrEmpty(domainIds)) { + if (domainIds.contains(",")) { + String[] domains = domainIds.split(","); + for (String domain : domains) { + Domain validDomain = _entityMgr.findByUuid(Domain.class, domain.trim()); + if (validDomain != null) { + validDomainIds.add(validDomain.getId()); + } else { + throw new InvalidParameterValueException("Failed to create VPC offering because invalid domain has been specified."); + } + } + } else { + domainIds = domainIds.trim(); + if (!domainIds.matches("public")) { + Domain validDomain = _entityMgr.findByUuid(Domain.class, domainIds.trim()); + if (validDomain != null) { + validDomainIds.add(validDomain.getId()); + } else { + throw new InvalidParameterValueException("Failed to create VPC offering because invalid domain has been specified."); + } + } + } + } else { + validDomainIds.addAll(_vpcProvSvc.getVpcOfferingDomains(id)); + } + return validDomainIds; + } + + public List getZoneIds() { + List validZoneIds = new ArrayList<>(); + if (!Strings.isNullOrEmpty(zoneIds)) { + if (zoneIds.contains(",")) { + String[] zones = zoneIds.split(","); + for (String zone : zones) { + DataCenter validZone = _entityMgr.findByUuid(DataCenter.class, zone.trim()); + if (validZone != null) { + validZoneIds.add(validZone.getId()); + } else { + throw new InvalidParameterValueException("Failed to create VPC offering because invalid zone has been specified."); + } + } + } else { + zoneIds = zoneIds.trim(); + if (!zoneIds.matches("all")) { + DataCenter validZone = _entityMgr.findByUuid(DataCenter.class, zoneIds.trim()); + if (validZone != null) { + validZoneIds.add(validZone.getId()); + } else { + throw new InvalidParameterValueException("Failed to create VPC offering because invalid zone has been specified."); + } + } + } + } else { + validZoneIds.addAll(_vpcProvSvc.getVpcOfferingZones(id)); + } + return validZoneIds; + } + public Integer getSortKey() { return sortKey; } - ///////////////////////////////////////////////////// /////////////// API Implementation/////////////////// ///////////////////////////////////////////////////// diff --git a/api/src/main/java/org/apache/cloudstack/api/command/user/network/ListNetworkOfferingsCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/user/network/ListNetworkOfferingsCmd.java index 0c57bf96c8f..e294d39251d 100644 --- a/api/src/main/java/org/apache/cloudstack/api/command/user/network/ListNetworkOfferingsCmd.java +++ b/api/src/main/java/org/apache/cloudstack/api/command/user/network/ListNetworkOfferingsCmd.java @@ -23,6 +23,7 @@ import org.apache.cloudstack.api.APICommand; import org.apache.cloudstack.api.ApiConstants; import org.apache.cloudstack.api.BaseListCmd; import org.apache.cloudstack.api.Parameter; +import org.apache.cloudstack.api.response.DomainResponse; import org.apache.cloudstack.api.response.ListResponse; import org.apache.cloudstack.api.response.NetworkOfferingResponse; import org.apache.cloudstack.api.response.NetworkResponse; @@ -62,6 +63,13 @@ public class ListNetworkOfferingsCmd extends BaseListCmd { @Parameter(name = ApiConstants.AVAILABILITY, type = CommandType.STRING, description = "the availability of network offering. Default value is required") private String availability; + @Parameter(name = ApiConstants.DOMAIN_ID, + type = CommandType.UUID, + entityType = DomainResponse.class, + description = "list network offerings available for network creation in specific domain", + since = "4.13") + private Long domainId; + @Parameter(name = ApiConstants.ZONE_ID, type = CommandType.UUID, entityType = ZoneResponse.class, @@ -137,6 +145,10 @@ public class ListNetworkOfferingsCmd extends BaseListCmd { return availability; } + public Long getDomainId() { + return domainId; + } + public Long getZoneId() { return zoneId; } diff --git a/api/src/main/java/org/apache/cloudstack/api/command/user/offering/ListDiskOfferingsCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/user/offering/ListDiskOfferingsCmd.java index e5f92c9e0de..92b8676b469 100644 --- a/api/src/main/java/org/apache/cloudstack/api/command/user/offering/ListDiskOfferingsCmd.java +++ b/api/src/main/java/org/apache/cloudstack/api/command/user/offering/ListDiskOfferingsCmd.java @@ -16,6 +16,7 @@ // under the License. package org.apache.cloudstack.api.command.user.offering; +import org.apache.cloudstack.api.response.ZoneResponse; import org.apache.log4j.Logger; import org.apache.cloudstack.api.APICommand; @@ -42,6 +43,13 @@ public class ListDiskOfferingsCmd extends BaseListDomainResourcesCmd { @Parameter(name = ApiConstants.NAME, type = CommandType.STRING, description = "name of the disk offering") private String diskOfferingName; + @Parameter(name = ApiConstants.ZONE_ID, + type = CommandType.UUID, + entityType = ZoneResponse.class, + description = "id of zone disk offering is associated with", + since = "4.13") + private Long zoneId; + ///////////////////////////////////////////////////// /////////////////// Accessors /////////////////////// ///////////////////////////////////////////////////// @@ -54,6 +62,10 @@ public class ListDiskOfferingsCmd extends BaseListDomainResourcesCmd { return diskOfferingName; } + public Long getZoneId() { + return zoneId; + } + ///////////////////////////////////////////////////// /////////////// API Implementation/////////////////// ///////////////////////////////////////////////////// diff --git a/api/src/main/java/org/apache/cloudstack/api/command/user/offering/ListServiceOfferingsCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/user/offering/ListServiceOfferingsCmd.java index 4b7481974f2..dcb1730cec6 100644 --- a/api/src/main/java/org/apache/cloudstack/api/command/user/offering/ListServiceOfferingsCmd.java +++ b/api/src/main/java/org/apache/cloudstack/api/command/user/offering/ListServiceOfferingsCmd.java @@ -16,6 +16,7 @@ // under the License. package org.apache.cloudstack.api.command.user.offering; +import org.apache.cloudstack.api.response.ZoneResponse; import org.apache.log4j.Logger; import org.apache.cloudstack.api.APICommand; @@ -57,6 +58,13 @@ public class ListServiceOfferingsCmd extends BaseListDomainResourcesCmd { description = "the system VM type. Possible types are \"consoleproxy\", \"secondarystoragevm\" or \"domainrouter\".") private String systemVmType; + @Parameter(name = ApiConstants.ZONE_ID, + type = CommandType.UUID, + entityType = ZoneResponse.class, + description = "id of zone disk offering is associated with", + since = "4.13") + private Long zoneId; + ///////////////////////////////////////////////////// /////////////////// Accessors /////////////////////// ///////////////////////////////////////////////////// @@ -81,6 +89,10 @@ public class ListServiceOfferingsCmd extends BaseListDomainResourcesCmd { return systemVmType; } + public Long getZoneId() { + return zoneId; + } + ///////////////////////////////////////////////////// /////////////// API Implementation/////////////////// ///////////////////////////////////////////////////// diff --git a/api/src/main/java/org/apache/cloudstack/api/command/user/vpc/ListVPCOfferingsCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/user/vpc/ListVPCOfferingsCmd.java index 69d7c8b8d1e..a58de577e2f 100644 --- a/api/src/main/java/org/apache/cloudstack/api/command/user/vpc/ListVPCOfferingsCmd.java +++ b/api/src/main/java/org/apache/cloudstack/api/command/user/vpc/ListVPCOfferingsCmd.java @@ -25,6 +25,7 @@ import org.apache.cloudstack.api.BaseListCmd; import org.apache.cloudstack.api.Parameter; import org.apache.cloudstack.api.response.ListResponse; import org.apache.cloudstack.api.response.VpcOfferingResponse; +import org.apache.cloudstack.api.response.ZoneResponse; import org.apache.log4j.Logger; import com.cloud.network.vpc.VpcOffering; @@ -60,6 +61,13 @@ public class ListVPCOfferingsCmd extends BaseListCmd { @Parameter(name = ApiConstants.STATE, type = CommandType.STRING, description = "list VPC offerings by state") private String state; + @Parameter(name = ApiConstants.ZONE_ID, + type = CommandType.UUID, + entityType = ZoneResponse.class, + description = "id of zone disk offering is associated with", + since = "4.13") + private Long zoneId; + ///////////////////////////////////////////////////// /////////////////// Accessors /////////////////////// ///////////////////////////////////////////////////// @@ -87,6 +95,10 @@ public class ListVPCOfferingsCmd extends BaseListCmd { return state; } + public Long getZoneId() { + return zoneId; + } + ///////////////////////////////////////////////////// /////////////// API Implementation/////////////////// ///////////////////////////////////////////////////// @@ -94,8 +106,7 @@ public class ListVPCOfferingsCmd extends BaseListCmd { @Override public void execute() { Pair, Integer> offerings = - _vpcProvSvc.listVpcOfferings(getId(), getVpcOffName(), getDisplayText(), getSupportedServices(), isDefault, this.getKeyword(), getState(), - this.getStartIndex(), this.getPageSizeVal()); + _vpcProvSvc.listVpcOfferings(this); ListResponse response = new ListResponse(); List offeringResponses = new ArrayList(); for (VpcOffering offering : offerings.first()) { diff --git a/api/src/main/java/org/apache/cloudstack/api/response/DiskOfferingResponse.java b/api/src/main/java/org/apache/cloudstack/api/response/DiskOfferingResponse.java index 5f22c91488e..8c0fd70ff98 100644 --- a/api/src/main/java/org/apache/cloudstack/api/response/DiskOfferingResponse.java +++ b/api/src/main/java/org/apache/cloudstack/api/response/DiskOfferingResponse.java @@ -18,14 +18,13 @@ package org.apache.cloudstack.api.response; import java.util.Date; -import com.google.gson.annotations.SerializedName; - import org.apache.cloudstack.api.ApiConstants; import org.apache.cloudstack.api.BaseResponse; import org.apache.cloudstack.api.EntityReference; import com.cloud.offering.DiskOffering; import com.cloud.serializer.Param; +import com.google.gson.annotations.SerializedName; @EntityReference(value = DiskOffering.class) public class DiskOfferingResponse extends BaseResponse { @@ -34,13 +33,21 @@ public class DiskOfferingResponse extends BaseResponse { private String id; @SerializedName(ApiConstants.DOMAIN_ID) - @Param(description = "the domain ID this disk offering belongs to. Ignore this information as it is not currently applicable.") + @Param(description = "the domain ID(s) this disk offering belongs to. Ignore this information as it is not currently applicable.") private String domainId; @SerializedName(ApiConstants.DOMAIN) - @Param(description = "the domain name this disk offering belongs to. Ignore this information as it is not currently applicable.") + @Param(description = "the domain name(s) this disk offering belongs to. Ignore this information as it is not currently applicable.") private String domain; + @SerializedName(ApiConstants.ZONE_ID) + @Param(description = "the zone ID(s) this disk offering belongs to. Ignore this information as it is not currently applicable.", since = "4.13.0") + private String zoneId; + + @SerializedName(ApiConstants.ZONE) + @Param(description = "the zone name(s) this disk offering belongs to. Ignore this information as it is not currently applicable.", since = "4.13.0") + private String zone; + @SerializedName(ApiConstants.NAME) @Param(description = "the name of the disk offering") private String name; @@ -177,6 +184,22 @@ public class DiskOfferingResponse extends BaseResponse { this.domain = domain; } + public String getZoneId() { + return zoneId; + } + + public void setZoneId(String zoneId) { + this.zoneId = zoneId; + } + + public String getZone() { + return zone; + } + + public void setZone(String zone) { + this.zone = zone; + } + public String getName() { return name; } diff --git a/api/src/main/java/org/apache/cloudstack/api/response/NetworkOfferingResponse.java b/api/src/main/java/org/apache/cloudstack/api/response/NetworkOfferingResponse.java index 93cbb12976b..e9bda5d37e7 100644 --- a/api/src/main/java/org/apache/cloudstack/api/response/NetworkOfferingResponse.java +++ b/api/src/main/java/org/apache/cloudstack/api/response/NetworkOfferingResponse.java @@ -20,14 +20,13 @@ import java.util.Date; import java.util.List; import java.util.Map; -import com.google.gson.annotations.SerializedName; - import org.apache.cloudstack.api.ApiConstants; import org.apache.cloudstack.api.BaseResponse; import org.apache.cloudstack.api.EntityReference; import com.cloud.offering.NetworkOffering; import com.cloud.serializer.Param; +import com.google.gson.annotations.SerializedName; @EntityReference(value = NetworkOffering.class) @SuppressWarnings("unused") @@ -124,6 +123,22 @@ public class NetworkOfferingResponse extends BaseResponse { @Param(description = "true if network offering supports public access for guest networks", since = "4.10.0") private Boolean supportsPublicAccess; + @SerializedName(ApiConstants.DOMAIN_ID) + @Param(description = "the domain ID(s) this disk offering belongs to. Ignore this information as it is not currently applicable.") + private String domainId; + + @SerializedName(ApiConstants.DOMAIN) + @Param(description = "the domain name(s) this disk offering belongs to. Ignore this information as it is not currently applicable.") + private String domain; + + @SerializedName(ApiConstants.ZONE_ID) + @Param(description = "the zone ID(s) this disk offering belongs to. Ignore this information as it is not currently applicable.", since = "4.13.0") + private String zoneId; + + @SerializedName(ApiConstants.ZONE) + @Param(description = "the zone name(s) this disk offering belongs to. Ignore this information as it is not currently applicable.", since = "4.13.0") + private String zone; + public void setId(String id) { this.id = id; } @@ -215,4 +230,36 @@ public class NetworkOfferingResponse extends BaseResponse { public void setSupportsPublicAccess(Boolean supportsPublicAccess) { this.supportsPublicAccess = supportsPublicAccess; } + + public String getDomainId() { + return domainId; + } + + public void setDomainId(String domainId) { + this.domainId = domainId; + } + + public String getDomain() { + return domain; + } + + public void setDomain(String domain) { + this.domain = domain; + } + + public String getZoneId() { + return zoneId; + } + + public void setZoneId(String zoneId) { + this.zoneId = zoneId; + } + + public String getZone() { + return zone; + } + + public void setZone(String zone) { + this.zone = zone; + } } diff --git a/api/src/main/java/org/apache/cloudstack/api/response/ServiceOfferingResponse.java b/api/src/main/java/org/apache/cloudstack/api/response/ServiceOfferingResponse.java index 51b5c1f6db8..41c8645029e 100644 --- a/api/src/main/java/org/apache/cloudstack/api/response/ServiceOfferingResponse.java +++ b/api/src/main/java/org/apache/cloudstack/api/response/ServiceOfferingResponse.java @@ -19,14 +19,13 @@ package org.apache.cloudstack.api.response; import java.util.Date; import java.util.Map; -import com.google.gson.annotations.SerializedName; - import org.apache.cloudstack.api.ApiConstants; import org.apache.cloudstack.api.BaseResponse; import org.apache.cloudstack.api.EntityReference; import com.cloud.offering.ServiceOffering; import com.cloud.serializer.Param; +import com.google.gson.annotations.SerializedName; @EntityReference(value = ServiceOffering.class) public class ServiceOfferingResponse extends BaseResponse { @@ -81,14 +80,22 @@ public class ServiceOfferingResponse extends BaseResponse { @Param(description = "the tags for the service offering") private String tags; - @SerializedName("domainid") - @Param(description = "the domain id of the service offering") + @SerializedName(ApiConstants.DOMAIN_ID) + @Param(description = "the domain ID(s) this disk offering belongs to. Ignore this information as it is not currently applicable.") private String domainId; @SerializedName(ApiConstants.DOMAIN) - @Param(description = "Domain name for the offering") + @Param(description = "the domain name(s) this disk offering belongs to. Ignore this information as it is not currently applicable.") private String domain; + @SerializedName(ApiConstants.ZONE_ID) + @Param(description = "the zone ID(s) this disk offering belongs to. Ignore this information as it is not currently applicable.", since = "4.13.0") + private String zoneId; + + @SerializedName(ApiConstants.ZONE) + @Param(description = "the zone name(s) this disk offering belongs to. Ignore this information as it is not currently applicable.", since = "4.13.0") + private String zone; + @SerializedName(ApiConstants.HOST_TAGS) @Param(description = "the host tag for the service offering") private String hostTag; @@ -324,6 +331,22 @@ public class ServiceOfferingResponse extends BaseResponse { this.domain = domain; } + public String getZoneId() { + return zoneId; + } + + public void setZoneId(String zoneId) { + this.zoneId = zoneId; + } + + public String getZone() { + return zone; + } + + public void setZone(String zone) { + this.zone = zone; + } + public String getHostTag() { return hostTag; } diff --git a/api/src/main/java/org/apache/cloudstack/api/response/VpcOfferingResponse.java b/api/src/main/java/org/apache/cloudstack/api/response/VpcOfferingResponse.java index 512746fb6af..b8483c3e3d2 100644 --- a/api/src/main/java/org/apache/cloudstack/api/response/VpcOfferingResponse.java +++ b/api/src/main/java/org/apache/cloudstack/api/response/VpcOfferingResponse.java @@ -19,14 +19,13 @@ package org.apache.cloudstack.api.response; import java.util.Date; import java.util.List; -import com.google.gson.annotations.SerializedName; - import org.apache.cloudstack.api.ApiConstants; import org.apache.cloudstack.api.BaseResponse; import org.apache.cloudstack.api.EntityReference; import com.cloud.network.vpc.VpcOffering; import com.cloud.serializer.Param; +import com.google.gson.annotations.SerializedName; @EntityReference(value = VpcOffering.class) @SuppressWarnings("unused") @@ -67,6 +66,22 @@ public class VpcOfferingResponse extends BaseResponse { @Param(description = " indicated if the offering can support region level vpc", since = "4.4") private Boolean supportsRegionLevelVpc; + @SerializedName(ApiConstants.DOMAIN_ID) + @Param(description = "the domain ID(s) this disk offering belongs to. Ignore this information as it is not currently applicable.") + private String domainId; + + @SerializedName(ApiConstants.DOMAIN) + @Param(description = "the domain name(s) this disk offering belongs to. Ignore this information as it is not currently applicable.") + private String domain; + + @SerializedName(ApiConstants.ZONE_ID) + @Param(description = "the zone ID(s) this disk offering belongs to. Ignore this information as it is not currently applicable.", since = "4.13.0") + private String zoneId; + + @SerializedName(ApiConstants.ZONE) + @Param(description = "the zone name(s) this disk offering belongs to. Ignore this information as it is not currently applicable.", since = "4.13.0") + private String zone; + public void setId(String id) { this.id = id; } @@ -102,4 +117,36 @@ public class VpcOfferingResponse extends BaseResponse { public void setSupportsRegionLevelVpc(Boolean supports) { this.supportsRegionLevelVpc = supports; } + + public String getDomainId() { + return domainId; + } + + public void setDomainId(String domainId) { + this.domainId = domainId; + } + + public String getDomain() { + return domain; + } + + public void setDomain(String domain) { + this.domain = domain; + } + + public String getZoneId() { + return zoneId; + } + + public void setZoneId(String zoneId) { + this.zoneId = zoneId; + } + + public String getZone() { + return zone; + } + + public void setZone(String zone) { + this.zone = zone; + } } diff --git a/engine/components-api/src/main/java/com/cloud/configuration/ConfigurationManager.java b/engine/components-api/src/main/java/com/cloud/configuration/ConfigurationManager.java index 235b241264c..162a61e4737 100644 --- a/engine/components-api/src/main/java/com/cloud/configuration/ConfigurationManager.java +++ b/engine/components-api/src/main/java/com/cloud/configuration/ConfigurationManager.java @@ -16,6 +16,7 @@ // under the License. package com.cloud.configuration; +import java.util.List; import java.util.Map; import java.util.Set; @@ -177,7 +178,7 @@ public interface ConfigurationManager { void checkZoneAccess(Account caller, DataCenter zone); - void checkDiskOfferingAccess(Account caller, DiskOffering dof); + void checkDiskOfferingAccess(Account caller, DiskOffering dof, DataCenter zone); /** * Creates a new network offering @@ -205,13 +206,15 @@ public interface ConfigurationManager { * ; * @param details TODO * @param forVpc + * @param domainIds + * @param zoneIds * @return network offering object */ NetworkOfferingVO createNetworkOffering(String name, String displayText, TrafficType trafficType, String tags, boolean specifyVlan, Availability availability, - Integer networkRate, Map> serviceProviderMap, boolean isDefault, Network.GuestType type, boolean systemOnly, Long serviceOfferingId, - boolean conserveMode, Map> serviceCapabilityMap, boolean specifyIpRanges, boolean isPersistent, - Map details, boolean egressDefaultPolicy, Integer maxconn, boolean enableKeepAlive, Boolean forVpc); + Integer networkRate, Map> serviceProviderMap, boolean isDefault, Network.GuestType type, boolean systemOnly, Long serviceOfferingId, + boolean conserveMode, Map> serviceCapabilityMap, boolean specifyIpRanges, boolean isPersistent, + Map details, boolean egressDefaultPolicy, Integer maxconn, boolean enableKeepAlive, Boolean forVpc, List domainIds, List zoneIds); Vlan createVlanAndPublicIpRange(long zoneId, long networkId, long physicalNetworkId, boolean forVirtualNetwork, boolean forSystemVms, Long podId, String startIP, String endIP, String vlanGateway, String vlanNetmask, String vlanId, boolean bypassVlanOverlapCheck, Domain domain, Account vlanOwner, String startIPv6, String endIPv6, String vlanIp6Gateway, String vlanIp6Cidr) diff --git a/engine/orchestration/src/main/java/org/apache/cloudstack/engine/orchestration/NetworkOrchestrator.java b/engine/orchestration/src/main/java/org/apache/cloudstack/engine/orchestration/NetworkOrchestrator.java index 2b2460ea76a..51b71d911ce 100644 --- a/engine/orchestration/src/main/java/org/apache/cloudstack/engine/orchestration/NetworkOrchestrator.java +++ b/engine/orchestration/src/main/java/org/apache/cloudstack/engine/orchestration/NetworkOrchestrator.java @@ -442,7 +442,7 @@ public class NetworkOrchestrator extends ManagerBase implements NetworkOrchestra if (_networkOfferingDao.findByUniqueName(NetworkOffering.QuickCloudNoServices) == null) { offering = _configMgr.createNetworkOffering(NetworkOffering.QuickCloudNoServices, "Offering for QuickCloud with no services", TrafficType.Guest, null, true, Availability.Optional, null, new HashMap>(), true, Network.GuestType.Shared, false, null, true, null, true, - false, null, false, null, true, false); + false, null, false, null, true, false, null, null); offering.setState(NetworkOffering.State.Enabled); _networkOfferingDao.update(offering.getId(), offering); } @@ -451,7 +451,7 @@ public class NetworkOrchestrator extends ManagerBase implements NetworkOrchestra if (_networkOfferingDao.findByUniqueName(NetworkOffering.DefaultSharedNetworkOfferingWithSGService) == null) { offering = _configMgr.createNetworkOffering(NetworkOffering.DefaultSharedNetworkOfferingWithSGService, "Offering for Shared Security group enabled networks", TrafficType.Guest, null, true, Availability.Optional, null, defaultSharedNetworkOfferingProviders, true, Network.GuestType.Shared, false, null, true, - null, true, false, null, false, null, true, false); + null, true, false, null, false, null, true, false, null, null); offering.setState(NetworkOffering.State.Enabled); _networkOfferingDao.update(offering.getId(), offering); } @@ -460,7 +460,7 @@ public class NetworkOrchestrator extends ManagerBase implements NetworkOrchestra if (_networkOfferingDao.findByUniqueName(NetworkOffering.DefaultSharedNetworkOffering) == null) { offering = _configMgr.createNetworkOffering(NetworkOffering.DefaultSharedNetworkOffering, "Offering for Shared networks", TrafficType.Guest, null, true, Availability.Optional, null, defaultSharedNetworkOfferingProviders, true, Network.GuestType.Shared, false, null, true, null, true, false, null, false, - null, true, false); + null, true, false, null, null); offering.setState(NetworkOffering.State.Enabled); _networkOfferingDao.update(offering.getId(), offering); } @@ -470,7 +470,7 @@ public class NetworkOrchestrator extends ManagerBase implements NetworkOrchestra offering = _configMgr.createNetworkOffering(NetworkOffering.DefaultIsolatedNetworkOfferingWithSourceNatService, "Offering for Isolated networks with Source Nat service enabled", TrafficType.Guest, null, false, Availability.Required, null, defaultIsolatedSourceNatEnabledNetworkOfferingProviders, true, Network.GuestType.Isolated, false, null, true, null, false, false, null, false, null, - true, false); + true, false, null, null); offering.setState(NetworkOffering.State.Enabled); _networkOfferingDao.update(offering.getId(), offering); @@ -480,7 +480,7 @@ public class NetworkOrchestrator extends ManagerBase implements NetworkOrchestra if (_networkOfferingDao.findByUniqueName(NetworkOffering.DefaultIsolatedNetworkOfferingForVpcNetworks) == null) { offering = _configMgr.createNetworkOffering(NetworkOffering.DefaultIsolatedNetworkOfferingForVpcNetworks, "Offering for Isolated VPC networks with Source Nat service enabled", TrafficType.Guest, null, false, Availability.Optional, null, - defaultVPCOffProviders, true, Network.GuestType.Isolated, false, null, false, null, false, false, null, false, null, true, true); + defaultVPCOffProviders, true, Network.GuestType.Isolated, false, null, false, null, false, false, null, false, null, true, true, null, null); offering.setState(NetworkOffering.State.Enabled); _networkOfferingDao.update(offering.getId(), offering); } @@ -491,7 +491,7 @@ public class NetworkOrchestrator extends ManagerBase implements NetworkOrchestra defaultVPCOffProviders.remove(Service.Lb); offering = _configMgr.createNetworkOffering(NetworkOffering.DefaultIsolatedNetworkOfferingForVpcNetworksNoLB, "Offering for Isolated VPC networks with Source Nat service enabled and LB service disabled", TrafficType.Guest, null, false, Availability.Optional, - null, defaultVPCOffProviders, true, Network.GuestType.Isolated, false, null, false, null, false, false, null, false, null, true, true); + null, defaultVPCOffProviders, true, Network.GuestType.Isolated, false, null, false, null, false, false, null, false, null, true, true, null, null); offering.setState(NetworkOffering.State.Enabled); _networkOfferingDao.update(offering.getId(), offering); } @@ -500,7 +500,7 @@ public class NetworkOrchestrator extends ManagerBase implements NetworkOrchestra if (_networkOfferingDao.findByUniqueName(NetworkOffering.DefaultIsolatedNetworkOffering) == null) { offering = _configMgr.createNetworkOffering(NetworkOffering.DefaultIsolatedNetworkOffering, "Offering for Isolated networks with no Source Nat service", TrafficType.Guest, null, true, Availability.Optional, null, defaultIsolatedNetworkOfferingProviders, true, Network.GuestType.Isolated, false, null, - true, null, true, false, null, false, null, true, false); + true, null, true, false, null, false, null, true, false, null, null); offering.setState(NetworkOffering.State.Enabled); _networkOfferingDao.update(offering.getId(), offering); } @@ -524,7 +524,7 @@ public class NetworkOrchestrator extends ManagerBase implements NetworkOrchestra if (_networkOfferingDao.findByUniqueName(NetworkOffering.DefaultIsolatedNetworkOfferingForVpcNetworksWithInternalLB) == null) { offering = _configMgr.createNetworkOffering(NetworkOffering.DefaultIsolatedNetworkOfferingForVpcNetworksWithInternalLB, "Offering for Isolated VPC networks with Internal Lb support", TrafficType.Guest, null, false, Availability.Optional, null, internalLbOffProviders, - true, Network.GuestType.Isolated, false, null, false, null, false, false, null, false, null, true, true); + true, Network.GuestType.Isolated, false, null, false, null, false, false, null, false, null, true, true, null, null); offering.setState(NetworkOffering.State.Enabled); offering.setInternalLb(true); offering.setPublicLb(false); @@ -556,7 +556,7 @@ public class NetworkOrchestrator extends ManagerBase implements NetworkOrchestra if (_networkOfferingDao.findByUniqueName(NetworkOffering.DefaultSharedEIPandELBNetworkOffering) == null) { offering = _configMgr.createNetworkOffering(NetworkOffering.DefaultSharedEIPandELBNetworkOffering, "Offering for Shared networks with Elastic IP and Elastic LB capabilities", TrafficType.Guest, null, true, Availability.Optional, null, - netscalerServiceProviders, true, Network.GuestType.Shared, false, null, true, serviceCapabilityMap, true, false, null, false, null, true, false); + netscalerServiceProviders, true, Network.GuestType.Shared, false, null, true, serviceCapabilityMap, true, false, null, false, null, true, false, null, null); offering.setState(NetworkOffering.State.Enabled); offering.setDedicatedLB(false); _networkOfferingDao.update(offering.getId(), offering); @@ -2162,6 +2162,7 @@ public class NetworkOrchestrator extends ManagerBase implements NetworkOrchestra final Boolean isDisplayNetworkEnabled, final String isolatedPvlan, String externalId) throws ConcurrentOperationException, InsufficientCapacityException, ResourceAllocationException { final NetworkOfferingVO ntwkOff = _networkOfferingDao.findById(networkOfferingId); + final DataCenterVO zone = _dcDao.findById(zoneId); // this method supports only guest network creation if (ntwkOff.getTrafficType() != TrafficType.Guest) { s_logger.warn("Only guest networks can be created using this method"); @@ -2196,7 +2197,6 @@ public class NetworkOrchestrator extends ManagerBase implements NetworkOrchestra ipv6 = true; } // Validate zone - final DataCenterVO zone = _dcDao.findById(zoneId); if (zone.getNetworkType() == NetworkType.Basic) { // In Basic zone the network should have aclType=Domain, domainId=1, subdomainAccess=true if (aclType == null || aclType != ACLType.Domain) { diff --git a/engine/schema/src/main/java/com/cloud/domain/dao/DomainDao.java b/engine/schema/src/main/java/com/cloud/domain/dao/DomainDao.java index 297fbfad6de..88445136c29 100644 --- a/engine/schema/src/main/java/com/cloud/domain/dao/DomainDao.java +++ b/engine/schema/src/main/java/com/cloud/domain/dao/DomainDao.java @@ -27,7 +27,7 @@ public interface DomainDao extends GenericDao { public DomainVO findDomainByPath(String domainPath); - public boolean isChildDomain(Long parentId, Long childId); + boolean isChildDomain(Long parentId, Long childId); DomainVO findImmediateChildForParent(Long parentId); diff --git a/engine/schema/src/main/java/com/cloud/domain/dao/DomainDaoImpl.java b/engine/schema/src/main/java/com/cloud/domain/dao/DomainDaoImpl.java index 4316e3bc8ed..6b6255a3ca9 100644 --- a/engine/schema/src/main/java/com/cloud/domain/dao/DomainDaoImpl.java +++ b/engine/schema/src/main/java/com/cloud/domain/dao/DomainDaoImpl.java @@ -290,5 +290,4 @@ public class DomainDaoImpl extends GenericDaoBase implements Dom return parentDomains; } - } diff --git a/engine/schema/src/main/java/com/cloud/network/vpc/VpcOfferingDetailsVO.java b/engine/schema/src/main/java/com/cloud/network/vpc/VpcOfferingDetailsVO.java new file mode 100644 index 00000000000..3197ffc10ca --- /dev/null +++ b/engine/schema/src/main/java/com/cloud/network/vpc/VpcOfferingDetailsVO.java @@ -0,0 +1,87 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +package com.cloud.network.vpc; + +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.GenerationType; +import javax.persistence.Id; +import javax.persistence.Table; + +import org.apache.cloudstack.api.ResourceDetail; + +@Entity +@Table(name = "vpc_offering_details") +public class VpcOfferingDetailsVO implements ResourceDetail { + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + @Column(name = "id") + private long id; + + @Column(name = "offering_id") + private long resourceId; + + @Column(name = "name") + private String name; + + @Column(name = "value") + private String value; + + @Column(name = "display") + private boolean display = true; + + protected VpcOfferingDetailsVO() { + } + + public VpcOfferingDetailsVO(long vpcOfferingId, String name, String value, boolean display) { + this.resourceId = vpcOfferingId; + this.name = name; + this.value = value; + this.display = display; + } + + @Override + public long getResourceId() { + return resourceId; + } + + public void setResourceId(long vpcOfferingId) { + this.resourceId = vpcOfferingId; + } + + @Override + public String getName() { + return name; + } + + @Override + public String getValue() { + return value; + } + + @Override + public long getId() { + return id; + } + + @Override + public boolean isDisplay() { + return display; + } +} diff --git a/engine/schema/src/main/java/com/cloud/network/vpc/VpcOfferingVO.java b/engine/schema/src/main/java/com/cloud/network/vpc/VpcOfferingVO.java index 60961e5ac5a..aa26f16568a 100644 --- a/engine/schema/src/main/java/com/cloud/network/vpc/VpcOfferingVO.java +++ b/engine/schema/src/main/java/com/cloud/network/vpc/VpcOfferingVO.java @@ -166,23 +166,33 @@ public class VpcOfferingVO implements VpcOffering { this.state = state; } + @Override + public Date getRemoved() { + return removed; + } + + @Override + public Date getCreated() { + return created; + } + @Override public Long getServiceOfferingId() { return serviceOfferingId; } @Override - public boolean supportsDistributedRouter() { + public boolean isSupportsDistributedRouter() { return supportsDistributedRouter; } @Override - public boolean offersRegionLevelVPC() { + public boolean isOffersRegionLevelVPC() { return offersRegionLevelVPC; } @Override - public boolean getRedundantRouter() { + public boolean isRedundantRouter() { return this.redundantRouter; } diff --git a/engine/schema/src/main/java/com/cloud/network/vpc/dao/VpcOfferingDetailsDao.java b/engine/schema/src/main/java/com/cloud/network/vpc/dao/VpcOfferingDetailsDao.java new file mode 100644 index 00000000000..da5bf52f764 --- /dev/null +++ b/engine/schema/src/main/java/com/cloud/network/vpc/dao/VpcOfferingDetailsDao.java @@ -0,0 +1,30 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +package com.cloud.network.vpc.dao; + +import java.util.List; + +import org.apache.cloudstack.resourcedetail.ResourceDetailsDao; + +import com.cloud.network.vpc.VpcOfferingDetailsVO; +import com.cloud.utils.db.GenericDao; + +public interface VpcOfferingDetailsDao extends GenericDao, ResourceDetailsDao { + List findDomainIds(final long resourceId); + List findZoneIds(final long resourceId); +} diff --git a/engine/schema/src/main/java/com/cloud/network/vpc/dao/VpcOfferingDetailsDaoImpl.java b/engine/schema/src/main/java/com/cloud/network/vpc/dao/VpcOfferingDetailsDaoImpl.java new file mode 100644 index 00000000000..0feacd99160 --- /dev/null +++ b/engine/schema/src/main/java/com/cloud/network/vpc/dao/VpcOfferingDetailsDaoImpl.java @@ -0,0 +1,58 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +package com.cloud.network.vpc.dao; + +import java.util.ArrayList; +import java.util.List; + +import org.apache.cloudstack.api.ApiConstants; +import org.apache.cloudstack.resourcedetail.ResourceDetailsDaoBase; + +import com.cloud.network.vpc.VpcOfferingDetailsVO; + +public class VpcOfferingDetailsDaoImpl extends ResourceDetailsDaoBase implements VpcOfferingDetailsDao { + + @Override + public void addDetail(long resourceId, String key, String value, boolean display) { + super.addDetail(new VpcOfferingDetailsVO(resourceId, key, value, display)); + } + + @Override + public List findDomainIds(long resourceId) { + final List domainIds = new ArrayList<>(); + for (final VpcOfferingDetailsVO detail: findDetails(resourceId, ApiConstants.DOMAIN_ID)) { + final Long domainId = Long.valueOf(detail.getValue()); + if (domainId > 0) { + domainIds.add(domainId); + } + } + return domainIds; + } + + @Override + public List findZoneIds(long resourceId) { + final List zoneIds = new ArrayList<>(); + for (final VpcOfferingDetailsVO detail: findDetails(resourceId, ApiConstants.ZONE_ID)) { + final Long zoneId = Long.valueOf(detail.getValue()); + if (zoneId > 0) { + zoneIds.add(zoneId); + } + } + return zoneIds; + } +} \ No newline at end of file diff --git a/engine/schema/src/main/java/com/cloud/offerings/NetworkOfferingDetailsVO.java b/engine/schema/src/main/java/com/cloud/offerings/NetworkOfferingDetailsVO.java index d28e150da7c..545371afeff 100644 --- a/engine/schema/src/main/java/com/cloud/offerings/NetworkOfferingDetailsVO.java +++ b/engine/schema/src/main/java/com/cloud/offerings/NetworkOfferingDetailsVO.java @@ -25,9 +25,10 @@ import javax.persistence.GenerationType; import javax.persistence.Id; import javax.persistence.Table; +import org.apache.cloudstack.api.ResourceDetail; + import com.cloud.offering.NetworkOffering; import com.cloud.offering.NetworkOffering.Detail; -import org.apache.cloudstack.api.ResourceDetail; @Entity @Table(name = "network_offering_details") @@ -47,13 +48,17 @@ public class NetworkOfferingDetailsVO implements ResourceDetail { @Column(name = "value", length = 1024) private String value; + @Column(name = "display") + private boolean display; + public NetworkOfferingDetailsVO() { } - public NetworkOfferingDetailsVO(long resourceId, Detail detailName, String value) { + public NetworkOfferingDetailsVO(long resourceId, Detail detailName, String value, boolean display) { this.resourceId = resourceId; this.name = detailName; this.value = value; + this.display = display; } @Override @@ -84,7 +89,7 @@ public class NetworkOfferingDetailsVO implements ResourceDetail { @Override public boolean isDisplay() { - return false; + return display; } public void setId(long id) { diff --git a/engine/schema/src/main/java/com/cloud/offerings/dao/NetworkOfferingDaoImpl.java b/engine/schema/src/main/java/com/cloud/offerings/dao/NetworkOfferingDaoImpl.java index dd607edcac7..93fe2480bbe 100644 --- a/engine/schema/src/main/java/com/cloud/offerings/dao/NetworkOfferingDaoImpl.java +++ b/engine/schema/src/main/java/com/cloud/offerings/dao/NetworkOfferingDaoImpl.java @@ -23,7 +23,6 @@ import java.util.Map; import javax.inject.Inject; import javax.persistence.EntityExistsException; -import com.cloud.offerings.NetworkOfferingServiceMapVO; import org.apache.commons.collections.CollectionUtils; import org.springframework.stereotype.Component; @@ -33,6 +32,7 @@ import com.cloud.offering.NetworkOffering; import com.cloud.offering.NetworkOffering.Availability; import com.cloud.offering.NetworkOffering.Detail; import com.cloud.offerings.NetworkOfferingDetailsVO; +import com.cloud.offerings.NetworkOfferingServiceMapVO; import com.cloud.offerings.NetworkOfferingVO; import com.cloud.utils.db.DB; import com.cloud.utils.db.Filter; @@ -187,7 +187,7 @@ public class NetworkOfferingDaoImpl extends GenericDaoBase { - Map getNtwkOffDetails(long offeringId); - String getDetail(long offeringId, Detail detailName); + List findDomainIds(final long resourceId); + List findZoneIds(final long resourceId); } diff --git a/engine/schema/src/main/java/com/cloud/offerings/dao/NetworkOfferingDetailsDaoImpl.java b/engine/schema/src/main/java/com/cloud/offerings/dao/NetworkOfferingDetailsDaoImpl.java index 786b71c17c4..65742d0a8c7 100644 --- a/engine/schema/src/main/java/com/cloud/offerings/dao/NetworkOfferingDetailsDaoImpl.java +++ b/engine/schema/src/main/java/com/cloud/offerings/dao/NetworkOfferingDetailsDaoImpl.java @@ -16,12 +16,14 @@ // under the License. package com.cloud.offerings.dao; -import org.apache.cloudstack.resourcedetail.ResourceDetailsDaoBase; - +import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; +import org.apache.cloudstack.api.ApiConstants; +import org.apache.cloudstack.resourcedetail.ResourceDetailsDaoBase; + import com.cloud.offering.NetworkOffering; import com.cloud.offering.NetworkOffering.Detail; import com.cloud.offerings.NetworkOfferingDetailsVO; @@ -41,12 +43,14 @@ public class NetworkOfferingDetailsDaoImpl extends ResourceDetailsDaoBase getNtwkOffDetails(long offeringId) { SearchCriteria sc = DetailSearch.create(); sc.setParameters("resourceId", offeringId); + sc.setParameters("display", true); List results = search(sc, null); Map details = new HashMap(results.size()); @@ -77,7 +82,32 @@ public class NetworkOfferingDetailsDaoImpl extends ResourceDetailsDaoBase findDomainIds(long resourceId) { + final List domainIds = new ArrayList<>(); + for (final NetworkOfferingDetailsVO detail: findDetails(resourceId, ApiConstants.DOMAIN_ID)) { + final Long domainId = Long.valueOf(detail.getValue()); + if (domainId > 0) { + domainIds.add(domainId); + } + } + return domainIds; + } + + @Override + public List findZoneIds(long resourceId) { + final List zoneIds = new ArrayList<>(); + for (final NetworkOfferingDetailsVO detail: findDetails(resourceId, ApiConstants.ZONE_ID)) { + final Long zoneId = Long.valueOf(detail.getValue()); + if (zoneId > 0) { + zoneIds.add(zoneId); + } + } + return zoneIds; } } diff --git a/engine/schema/src/main/java/com/cloud/service/ServiceOfferingVO.java b/engine/schema/src/main/java/com/cloud/service/ServiceOfferingVO.java index 8cc834cecff..3a5f3182b73 100644 --- a/engine/schema/src/main/java/com/cloud/service/ServiceOfferingVO.java +++ b/engine/schema/src/main/java/com/cloud/service/ServiceOfferingVO.java @@ -35,6 +35,7 @@ import com.cloud.vm.VirtualMachine; @DiscriminatorValue(value = "Service") @PrimaryKeyJoinColumn(name = "id") public class ServiceOfferingVO extends DiskOfferingVO implements ServiceOffering { + @Column(name = "cpu") private Integer cpu; @@ -105,8 +106,8 @@ public class ServiceOfferingVO extends DiskOfferingVO implements ServiceOffering } public ServiceOfferingVO(String name, Integer cpu, Integer ramSize, Integer speed, Integer rateMbps, Integer multicastRateMbps, boolean offerHA, boolean limitCpuUse, - boolean volatileVm, String displayText, ProvisioningType provisioningType, boolean useLocalStorage, boolean recreatable, String tags, boolean systemUse, VirtualMachine.Type vmType, Long domainId) { - super(name, displayText, provisioningType, false, tags, recreatable, useLocalStorage, systemUse, true, domainId); + boolean volatileVm, String displayText, ProvisioningType provisioningType, boolean useLocalStorage, boolean recreatable, String tags, boolean systemUse, VirtualMachine.Type vmType) { + super(name, displayText, provisioningType, false, tags, recreatable, useLocalStorage, systemUse, true); this.cpu = cpu; this.ramSize = ramSize; this.speed = speed; @@ -119,8 +120,8 @@ public class ServiceOfferingVO extends DiskOfferingVO implements ServiceOffering } public ServiceOfferingVO(String name, Integer cpu, Integer ramSize, Integer speed, Integer rateMbps, Integer multicastRateMbps, boolean offerHA, - boolean limitResourceUse, boolean volatileVm, String displayText, ProvisioningType provisioningType, boolean useLocalStorage, boolean recreatable, String tags, boolean systemUse, - VirtualMachine.Type vmType, Long domainId, String hostTag) { + boolean limitResourceUse, boolean volatileVm, String displayText, ProvisioningType provisioningType, boolean useLocalStorage, boolean recreatable, String tags, boolean systemUse, + VirtualMachine.Type vmType, String hostTag) { this(name, cpu, ramSize, @@ -136,14 +137,14 @@ public class ServiceOfferingVO extends DiskOfferingVO implements ServiceOffering recreatable, tags, systemUse, - vmType, - domainId); + vmType + ); this.hostTag = hostTag; } public ServiceOfferingVO(String name, Integer cpu, Integer ramSize, Integer speed, Integer rateMbps, Integer multicastRateMbps, boolean offerHA, - boolean limitResourceUse, boolean volatileVm, String displayText, ProvisioningType provisioningType, boolean useLocalStorage, boolean recreatable, String tags, boolean systemUse, - VirtualMachine.Type vmType, Long domainId, String hostTag, String deploymentPlanner) { + boolean limitResourceUse, boolean volatileVm, String displayText, ProvisioningType provisioningType, boolean useLocalStorage, boolean recreatable, String tags, boolean systemUse, + VirtualMachine.Type vmType, String hostTag, String deploymentPlanner) { this(name, cpu, ramSize, @@ -160,8 +161,7 @@ public class ServiceOfferingVO extends DiskOfferingVO implements ServiceOffering tags, systemUse, vmType, - domainId, - hostTag); + hostTag); this.deploymentPlanner = deploymentPlanner; } @@ -177,7 +177,6 @@ public class ServiceOfferingVO extends DiskOfferingVO implements ServiceOffering offering.isSystemUse(), true, offering.isCustomizedIops()== null ? false:offering.isCustomizedIops(), - offering.getDomainId(), offering.getMinIops(), offering.getMaxIops()); cpu = offering.getCpu(); diff --git a/engine/schema/src/main/java/com/cloud/service/dao/ServiceOfferingDao.java b/engine/schema/src/main/java/com/cloud/service/dao/ServiceOfferingDao.java index aae61a12094..74728f826ce 100644 --- a/engine/schema/src/main/java/com/cloud/service/dao/ServiceOfferingDao.java +++ b/engine/schema/src/main/java/com/cloud/service/dao/ServiceOfferingDao.java @@ -36,12 +36,6 @@ public interface ServiceOfferingDao extends GenericDao ServiceOfferingVO persistSystemServiceOffering(ServiceOfferingVO vo); - List findPublicServiceOfferings(); - - List findServiceOfferingByDomainId(Long domainId); - - List findSystemOffering(Long domainId, Boolean isSystem, String vmType); - ServiceOfferingVO persistDeafultServiceOffering(ServiceOfferingVO offering); void loadDetails(ServiceOfferingVO serviceOffering); diff --git a/engine/schema/src/main/java/com/cloud/service/dao/ServiceOfferingDaoImpl.java b/engine/schema/src/main/java/com/cloud/service/dao/ServiceOfferingDaoImpl.java index 81ecc677e6f..96b0c350a74 100644 --- a/engine/schema/src/main/java/com/cloud/service/dao/ServiceOfferingDaoImpl.java +++ b/engine/schema/src/main/java/com/cloud/service/dao/ServiceOfferingDaoImpl.java @@ -50,10 +50,7 @@ public class ServiceOfferingDaoImpl extends GenericDaoBase UniqueNameSearch; - protected final SearchBuilder ServiceOfferingsByDomainIdSearch; - protected final SearchBuilder SystemServiceOffering; protected final SearchBuilder ServiceOfferingsByKeywordSearch; - protected final SearchBuilder PublicServiceOfferingSearch; public ServiceOfferingDaoImpl() { super(); @@ -63,23 +60,6 @@ public class ServiceOfferingDaoImpl extends GenericDaoBase findServiceOfferingByDomainId(Long domainId) { - SearchCriteria sc = ServiceOfferingsByDomainIdSearch.create(); - sc.setParameters("domainId", domainId); - return listBy(sc); - } - - @Override - public List findSystemOffering(Long domainId, Boolean isSystem, String vmType) { - SearchCriteria sc = SystemServiceOffering.create(); - sc.setParameters("domainId", domainId); - sc.setParameters("system", isSystem); - sc.setParameters("vm_type", vmType); - return listBy(sc); - } - - @Override - public List findPublicServiceOfferings() { - SearchCriteria sc = PublicServiceOfferingSearch.create(); - sc.setParameters("system", false); - return listBy(sc); - } - @Override @DB public ServiceOfferingVO persistDeafultServiceOffering(ServiceOfferingVO offering) { diff --git a/engine/schema/src/main/java/com/cloud/service/dao/ServiceOfferingDetailsDao.java b/engine/schema/src/main/java/com/cloud/service/dao/ServiceOfferingDetailsDao.java index b377e6c502a..f905ab98dd5 100644 --- a/engine/schema/src/main/java/com/cloud/service/dao/ServiceOfferingDetailsDao.java +++ b/engine/schema/src/main/java/com/cloud/service/dao/ServiceOfferingDetailsDao.java @@ -16,10 +16,14 @@ // under the License. package com.cloud.service.dao; +import java.util.List; + import org.apache.cloudstack.resourcedetail.ResourceDetailsDao; import com.cloud.service.ServiceOfferingDetailsVO; import com.cloud.utils.db.GenericDao; public interface ServiceOfferingDetailsDao extends GenericDao, ResourceDetailsDao { + List findDomainIds(final long resourceId); + List findZoneIds(final long resourceId); } \ No newline at end of file diff --git a/engine/schema/src/main/java/com/cloud/service/dao/ServiceOfferingDetailsDaoImpl.java b/engine/schema/src/main/java/com/cloud/service/dao/ServiceOfferingDetailsDaoImpl.java index fa64389d7ec..76840267461 100644 --- a/engine/schema/src/main/java/com/cloud/service/dao/ServiceOfferingDetailsDaoImpl.java +++ b/engine/schema/src/main/java/com/cloud/service/dao/ServiceOfferingDetailsDaoImpl.java @@ -17,9 +17,12 @@ package com.cloud.service.dao; -import org.springframework.stereotype.Component; +import java.util.ArrayList; +import java.util.List; +import org.apache.cloudstack.api.ApiConstants; import org.apache.cloudstack.resourcedetail.ResourceDetailsDaoBase; +import org.springframework.stereotype.Component; import com.cloud.service.ServiceOfferingDetailsVO; @@ -31,4 +34,28 @@ public class ServiceOfferingDetailsDaoImpl extends ResourceDetailsDaoBase findDomainIds(long resourceId) { + final List domainIds = new ArrayList<>(); + for (final ServiceOfferingDetailsVO detail: findDetails(resourceId, ApiConstants.DOMAIN_ID)) { + final Long domainId = Long.valueOf(detail.getValue()); + if (domainId > 0) { + domainIds.add(domainId); + } + } + return domainIds; + } + + @Override + public List findZoneIds(long resourceId) { + final List zoneIds = new ArrayList<>(); + for (final ServiceOfferingDetailsVO detail: findDetails(resourceId, ApiConstants.ZONE_ID)) { + final Long zoneId = Long.valueOf(detail.getValue()); + if (zoneId > 0) { + zoneIds.add(zoneId); + } + } + return zoneIds; + } + } diff --git a/engine/schema/src/main/java/com/cloud/storage/DiskOfferingVO.java b/engine/schema/src/main/java/com/cloud/storage/DiskOfferingVO.java index e8e91ea3781..7f91537f7cb 100644 --- a/engine/schema/src/main/java/com/cloud/storage/DiskOfferingVO.java +++ b/engine/schema/src/main/java/com/cloud/storage/DiskOfferingVO.java @@ -50,9 +50,6 @@ public class DiskOfferingVO implements DiskOffering { @Column(name = "id") long id; - @Column(name = "domain_id") - Long domainId; - @Column(name = "unique_name") private String uniqueName; @@ -163,9 +160,8 @@ public class DiskOfferingVO implements DiskOffering { uuid = UUID.randomUUID().toString(); } - public DiskOfferingVO(Long domainId, String name, String displayText, Storage.ProvisioningType provisioningType, long diskSize, String tags, boolean isCustomized, Boolean isCustomizedIops, + public DiskOfferingVO(String name, String displayText, Storage.ProvisioningType provisioningType, long diskSize, String tags, boolean isCustomized, Boolean isCustomizedIops, Long minIops, Long maxIops, DiskCacheMode cacheMode) { - this.domainId = domainId; this.name = name; this.displayText = displayText; this.provisioningType = provisioningType; @@ -182,9 +178,8 @@ public class DiskOfferingVO implements DiskOffering { this.cacheMode = cacheMode; } - public DiskOfferingVO(Long domainId, String name, String displayText, Storage.ProvisioningType provisioningType, long diskSize, String tags, boolean isCustomized, Boolean isCustomizedIops, - Long minIops, Long maxIops) { - this.domainId = domainId; + public DiskOfferingVO(String name, String displayText, Storage.ProvisioningType provisioningType, long diskSize, String tags, boolean isCustomized, Boolean isCustomizedIops, + Long minIops, Long maxIops) { this.name = name; this.displayText = displayText; this.provisioningType = provisioningType; @@ -203,7 +198,6 @@ public class DiskOfferingVO implements DiskOffering { public DiskOfferingVO(String name, String displayText, Storage.ProvisioningType provisioningType, boolean mirrored, String tags, boolean recreatable, boolean useLocalStorage, boolean systemUse, boolean customized) { - domainId = null; type = Type.Service; this.name = name; this.displayText = displayText; @@ -217,26 +211,8 @@ public class DiskOfferingVO implements DiskOffering { state = State.Active; } - // domain specific offerings constructor (null domainId implies public - // offering) - public DiskOfferingVO(String name, String displayText, Storage.ProvisioningType provisioningType, boolean mirrored, String tags, boolean recreatable, boolean useLocalStorage, boolean systemUse, - boolean customized, Long domainId) { - type = Type.Service; - this.name = name; - this.displayText = displayText; - this.provisioningType = provisioningType; - this.tags = tags; - this.recreatable = recreatable; - this.useLocalStorage = useLocalStorage; - this.systemUse = systemUse; - this.customized = customized; - this.domainId = domainId; - uuid = UUID.randomUUID().toString(); - state = State.Active; - } - public DiskOfferingVO(long id, String name, String displayText, Storage.ProvisioningType provisioningType, boolean mirrored, String tags, boolean recreatable, boolean useLocalStorage, - boolean systemUse, boolean customized, boolean customizedIops, Long domainId, Long minIops, Long maxIops) { + boolean systemUse, boolean customized, boolean customizedIops, Long minIops, Long maxIops) { this.id = id; type = Type.Service; this.name = name; @@ -248,7 +224,6 @@ public class DiskOfferingVO implements DiskOffering { this.systemUse = systemUse; this.customized = customized; this.customizedIops = customizedIops; - this.domainId = domainId; uuid = UUID.randomUUID().toString(); state = State.Active; this.minIops = minIops; @@ -328,11 +303,6 @@ public class DiskOfferingVO implements DiskOffering { return useLocalStorage; } - @Override - public Long getDomainId() { - return domainId; - } - @Override public Type getType() { return type; @@ -343,10 +313,6 @@ public class DiskOfferingVO implements DiskOffering { return recreatable; } - public void setDomainId(Long domainId) { - this.domainId = domainId; - } - @Override public String getName() { return name; diff --git a/engine/schema/src/main/java/com/cloud/storage/dao/DiskOfferingDao.java b/engine/schema/src/main/java/com/cloud/storage/dao/DiskOfferingDao.java index 0a348f55ae8..89e2c832836 100644 --- a/engine/schema/src/main/java/com/cloud/storage/dao/DiskOfferingDao.java +++ b/engine/schema/src/main/java/com/cloud/storage/dao/DiskOfferingDao.java @@ -22,7 +22,6 @@ import com.cloud.storage.DiskOfferingVO; import com.cloud.utils.db.GenericDao; public interface DiskOfferingDao extends GenericDao { - List listByDomainId(long domainId); List findPrivateDiskOffering(); diff --git a/engine/schema/src/main/java/com/cloud/storage/dao/DiskOfferingDaoImpl.java b/engine/schema/src/main/java/com/cloud/storage/dao/DiskOfferingDaoImpl.java index 2957b68e6e9..d93a05200f6 100644 --- a/engine/schema/src/main/java/com/cloud/storage/dao/DiskOfferingDaoImpl.java +++ b/engine/schema/src/main/java/com/cloud/storage/dao/DiskOfferingDaoImpl.java @@ -19,12 +19,14 @@ package com.cloud.storage.dao; import java.util.Date; import java.util.List; +import javax.inject.Inject; import javax.persistence.EntityExistsException; +import org.apache.cloudstack.resourcedetail.dao.DiskOfferingDetailsDao; import org.springframework.stereotype.Component; -import com.cloud.storage.DiskOfferingVO; import com.cloud.offering.DiskOffering.Type; +import com.cloud.storage.DiskOfferingVO; import com.cloud.utils.db.Attribute; import com.cloud.utils.db.Filter; import com.cloud.utils.db.GenericDaoBase; @@ -34,24 +36,21 @@ import com.cloud.utils.db.SearchCriteria.Op; @Component public class DiskOfferingDaoImpl extends GenericDaoBase implements DiskOfferingDao { - private final SearchBuilder DomainIdSearch; + + @Inject + protected DiskOfferingDetailsDao detailsDao; + private final SearchBuilder PrivateDiskOfferingSearch; private final SearchBuilder PublicDiskOfferingSearch; protected final SearchBuilder UniqueNameSearch; private final Attribute _typeAttr; protected DiskOfferingDaoImpl() { - DomainIdSearch = createSearchBuilder(); - DomainIdSearch.and("domainId", DomainIdSearch.entity().getDomainId(), SearchCriteria.Op.EQ); - DomainIdSearch.and("removed", DomainIdSearch.entity().getRemoved(), SearchCriteria.Op.NULL); - DomainIdSearch.done(); - PrivateDiskOfferingSearch = createSearchBuilder(); PrivateDiskOfferingSearch.and("diskSize", PrivateDiskOfferingSearch.entity().getDiskSize(), SearchCriteria.Op.EQ); PrivateDiskOfferingSearch.done(); PublicDiskOfferingSearch = createSearchBuilder(); - PublicDiskOfferingSearch.and("domainId", PublicDiskOfferingSearch.entity().getDomainId(), SearchCriteria.Op.NULL); PublicDiskOfferingSearch.and("system", PublicDiskOfferingSearch.entity().isSystemUse(), SearchCriteria.Op.EQ); PublicDiskOfferingSearch.and("removed", PublicDiskOfferingSearch.entity().getRemoved(), SearchCriteria.Op.NULL); PublicDiskOfferingSearch.done(); @@ -63,15 +62,6 @@ public class DiskOfferingDaoImpl extends GenericDaoBase im _typeAttr = _allAttributes.get("type"); } - @Override - public List listByDomainId(long domainId) { - SearchCriteria sc = DomainIdSearch.create(); - sc.setParameters("domainId", domainId); - // FIXME: this should not be exact match, but instead should find all - // available disk offerings from parent domains - return listBy(sc); - } - @Override public List findPrivateDiskOffering() { SearchCriteria sc = PrivateDiskOfferingSearch.create(); @@ -108,7 +98,11 @@ public class DiskOfferingDaoImpl extends GenericDaoBase im public List findPublicDiskOfferings() { SearchCriteria sc = PublicDiskOfferingSearch.create(); sc.setParameters("system", false); - return listBy(sc); + List offerings = listBy(sc); + if(offerings!=null) { + offerings.removeIf(o -> (!detailsDao.findDomainIds(o.getId()).isEmpty())); + } + return offerings; } @Override diff --git a/engine/schema/src/main/java/org/apache/cloudstack/resourcedetail/ResourceDetailsDao.java b/engine/schema/src/main/java/org/apache/cloudstack/resourcedetail/ResourceDetailsDao.java index 3f340455bab..52d901293ad 100644 --- a/engine/schema/src/main/java/org/apache/cloudstack/resourcedetail/ResourceDetailsDao.java +++ b/engine/schema/src/main/java/org/apache/cloudstack/resourcedetail/ResourceDetailsDao.java @@ -30,7 +30,15 @@ public interface ResourceDetailsDao extends GenericDao * @param name * @return */ - public R findDetail(long resourceId, String name); + R findDetail(long resourceId, String name); + + /** + * Find details by resourceId and key + * @param resourceId + * @param key + * @return + */ + List findDetails(long resourceId, String key); /** * Find details by key,value pair @@ -39,7 +47,7 @@ public interface ResourceDetailsDao extends GenericDao * @param display * @return */ - public List findDetails(String key, String value, Boolean display); + List findDetails(String key, String value, Boolean display); /** * Removes all details for the resource specified @@ -47,12 +55,21 @@ public interface ResourceDetailsDao extends GenericDao */ public void removeDetails(long resourceId); + /** * Removes detail having resourceId and key specified (unique combination) * @param resourceId * @param key */ - public void removeDetail(long resourceId, String key); + void removeDetail(long resourceId, String key); + + /** + * Removes detail having resourceId and key, value specified (unique combination) + * @param resourceId + * @param key + * @param value + */ + void removeDetail(long resourceId, String key, String value); /** * Lists all details for the resourceId diff --git a/engine/schema/src/main/java/org/apache/cloudstack/resourcedetail/ResourceDetailsDaoBase.java b/engine/schema/src/main/java/org/apache/cloudstack/resourcedetail/ResourceDetailsDaoBase.java index 7110541e3fc..0f153dbbf08 100644 --- a/engine/schema/src/main/java/org/apache/cloudstack/resourcedetail/ResourceDetailsDaoBase.java +++ b/engine/schema/src/main/java/org/apache/cloudstack/resourcedetail/ResourceDetailsDaoBase.java @@ -50,6 +50,13 @@ public abstract class ResourceDetailsDaoBase extends G return findOneBy(sc); } + public List findDetails(long resourceId, String key) { + SearchCriteria sc = AllFieldsSearch.create(); + sc.setParameters("resourceId", resourceId); + sc.setParameters("name", key); + return listBy(sc); + } + public List findDetails(String name, String value, Boolean display) { SearchCriteria sc = AllFieldsSearch.create(); @@ -107,6 +114,16 @@ public abstract class ResourceDetailsDaoBase extends G remove(sc); } + public void removeDetail(long resourceId, String key, String value) { + if (key != null) { + SearchCriteria sc = AllFieldsSearch.create(); + sc.setParameters("resourceId", resourceId); + sc.setParameters("name", key); + sc.setParameters("value", value); + remove(sc); + } + } + public void removeDetail(long resourceId, String key) { if (key != null) { SearchCriteria sc = AllFieldsSearch.create(); diff --git a/engine/schema/src/main/java/org/apache/cloudstack/resourcedetail/dao/DiskOfferingDetailsDao.java b/engine/schema/src/main/java/org/apache/cloudstack/resourcedetail/dao/DiskOfferingDetailsDao.java index 68a8614c93b..e201ae27fdc 100644 --- a/engine/schema/src/main/java/org/apache/cloudstack/resourcedetail/dao/DiskOfferingDetailsDao.java +++ b/engine/schema/src/main/java/org/apache/cloudstack/resourcedetail/dao/DiskOfferingDetailsDao.java @@ -16,11 +16,14 @@ // under the License. package org.apache.cloudstack.resourcedetail.dao; +import java.util.List; + import org.apache.cloudstack.resourcedetail.DiskOfferingDetailVO; import org.apache.cloudstack.resourcedetail.ResourceDetailsDao; import com.cloud.utils.db.GenericDao; public interface DiskOfferingDetailsDao extends GenericDao, ResourceDetailsDao { - + List findDomainIds(final long resourceId); + List findZoneIds(final long resourceId); } \ No newline at end of file diff --git a/engine/schema/src/main/java/org/apache/cloudstack/resourcedetail/dao/DiskOfferingDetailsDaoImpl.java b/engine/schema/src/main/java/org/apache/cloudstack/resourcedetail/dao/DiskOfferingDetailsDaoImpl.java index f13cc7bf8d8..da0ec5bc580 100644 --- a/engine/schema/src/main/java/org/apache/cloudstack/resourcedetail/dao/DiskOfferingDetailsDaoImpl.java +++ b/engine/schema/src/main/java/org/apache/cloudstack/resourcedetail/dao/DiskOfferingDetailsDaoImpl.java @@ -17,6 +17,10 @@ package org.apache.cloudstack.resourcedetail.dao; +import java.util.ArrayList; +import java.util.List; + +import org.apache.cloudstack.api.ApiConstants; import org.apache.cloudstack.resourcedetail.DiskOfferingDetailVO; import org.apache.cloudstack.resourcedetail.ResourceDetailsDaoBase; import org.springframework.stereotype.Component; @@ -28,4 +32,28 @@ public class DiskOfferingDetailsDaoImpl extends ResourceDetailsDaoBase findDomainIds(long resourceId) { + final List domainIds = new ArrayList<>(); + for (final DiskOfferingDetailVO detail: findDetails(resourceId, ApiConstants.DOMAIN_ID)) { + final Long domainId = Long.valueOf(detail.getValue()); + if (domainId > 0) { + domainIds.add(domainId); + } + } + return domainIds; + } + + @Override + public List findZoneIds(long resourceId) { + final List zoneIds = new ArrayList<>(); + for (final DiskOfferingDetailVO detail: findDetails(resourceId, ApiConstants.ZONE_ID)) { + final Long zoneId = Long.valueOf(detail.getValue()); + if (zoneId > 0) { + zoneIds.add(zoneId); + } + } + return zoneIds; + } } \ No newline at end of file diff --git a/engine/schema/src/main/resources/META-INF/cloudstack/core/spring-engine-schema-core-daos-context.xml b/engine/schema/src/main/resources/META-INF/cloudstack/core/spring-engine-schema-core-daos-context.xml index b7a4fe896cd..fc2a752307d 100644 --- a/engine/schema/src/main/resources/META-INF/cloudstack/core/spring-engine-schema-core-daos-context.xml +++ b/engine/schema/src/main/resources/META-INF/cloudstack/core/spring-engine-schema-core-daos-context.xml @@ -136,6 +136,7 @@ + @@ -249,12 +250,14 @@ + + diff --git a/engine/schema/src/main/resources/META-INF/db/schema-41200to41300.sql b/engine/schema/src/main/resources/META-INF/db/schema-41200to41300.sql index 445c893c8d0..8b60592f275 100644 --- a/engine/schema/src/main/resources/META-INF/db/schema-41200to41300.sql +++ b/engine/schema/src/main/resources/META-INF/db/schema-41200to41300.sql @@ -39,6 +39,257 @@ ALTER TABLE `cloud`.`vpc_offerings` ADD COLUMN `sort_key` int(32) NOT NULL defau -- Add `sort_key` column to data_center ALTER TABLE `cloud`.`data_center` ADD COLUMN `sort_key` INT(32) NOT NULL DEFAULT 0; +-- Move domain_id to disk offering details and drop the domain_id column +INSERT INTO `cloud`.`disk_offering_details` (offering_id, name, value, display) SELECT id, 'domainid', domain_id, 0 FROM `cloud`.`disk_offering` WHERE domain_id IS NOT NULL AND type='Disk'; +INSERT INTO `cloud`.`service_offering_details` (service_offering_id, name, value, display) SELECT id, 'domainid', domain_id, 0 FROM `cloud`.`disk_offering` WHERE domain_id IS NOT NULL AND type='Service'; + +ALTER TABLE `cloud`.`disk_offering` DROP COLUMN `domain_id`; + +ALTER TABLE `cloud`.`service_offering_details` DROP FOREIGN KEY `fk_service_offering_details__service_offering_id`, DROP KEY `uk_service_offering_id_name`; +ALTER TABLE `cloud`.`service_offering_details` ADD CONSTRAINT `fk_service_offering_details__service_offering_id` FOREIGN KEY (`service_offering_id`) REFERENCES `service_offering`(`id`) ON DELETE CASCADE; + +-- Disk offering with multi-domains and multi-zones +DROP VIEW IF EXISTS `cloud`.`disk_offering_view`; +CREATE VIEW `cloud`.`disk_offering_view` AS + SELECT + `disk_offering`.`id` AS `id`, + `disk_offering`.`uuid` AS `uuid`, + `disk_offering`.`name` AS `name`, + `disk_offering`.`display_text` AS `display_text`, + `disk_offering`.`provisioning_type` AS `provisioning_type`, + `disk_offering`.`disk_size` AS `disk_size`, + `disk_offering`.`min_iops` AS `min_iops`, + `disk_offering`.`max_iops` AS `max_iops`, + `disk_offering`.`created` AS `created`, + `disk_offering`.`tags` AS `tags`, + `disk_offering`.`customized` AS `customized`, + `disk_offering`.`customized_iops` AS `customized_iops`, + `disk_offering`.`removed` AS `removed`, + `disk_offering`.`use_local_storage` AS `use_local_storage`, + `disk_offering`.`system_use` AS `system_use`, + `disk_offering`.`hv_ss_reserve` AS `hv_ss_reserve`, + `disk_offering`.`bytes_read_rate` AS `bytes_read_rate`, + `disk_offering`.`bytes_read_rate_max` AS `bytes_read_rate_max`, + `disk_offering`.`bytes_read_rate_max_length` AS `bytes_read_rate_max_length`, + `disk_offering`.`bytes_write_rate` AS `bytes_write_rate`, + `disk_offering`.`bytes_write_rate_max` AS `bytes_write_rate_max`, + `disk_offering`.`bytes_write_rate_max_length` AS `bytes_write_rate_max_length`, + `disk_offering`.`iops_read_rate` AS `iops_read_rate`, + `disk_offering`.`iops_read_rate_max` AS `iops_read_rate_max`, + `disk_offering`.`iops_read_rate_max_length` AS `iops_read_rate_max_length`, + `disk_offering`.`iops_write_rate` AS `iops_write_rate`, + `disk_offering`.`iops_write_rate_max` AS `iops_write_rate_max`, + `disk_offering`.`iops_write_rate_max_length` AS `iops_write_rate_max_length`, + `disk_offering`.`cache_mode` AS `cache_mode`, + `disk_offering`.`sort_key` AS `sort_key`, + `disk_offering`.`type` AS `type`, + `disk_offering`.`display_offering` AS `display_offering`, + `disk_offering`.`state` AS `state`, + GROUP_CONCAT(DISTINCT(domain.id)) AS domain_id, + GROUP_CONCAT(DISTINCT(domain.uuid)) AS domain_uuid, + GROUP_CONCAT(DISTINCT(domain.name)) AS domain_name, + GROUP_CONCAT(DISTINCT(domain.path)) AS domain_path, + GROUP_CONCAT(DISTINCT(zone.id)) AS zone_id, + GROUP_CONCAT(DISTINCT(zone.uuid)) AS zone_uuid, + GROUP_CONCAT(DISTINCT(zone.name)) AS zone_name + FROM + `cloud`.`disk_offering` + LEFT JOIN + `cloud`.`disk_offering_details` AS `domain_details` ON `domain_details`.`offering_id` = `disk_offering`.`id` AND `domain_details`.`name`='domainid' + LEFT JOIN + `cloud`.`domain` AS `domain` ON FIND_IN_SET(`domain`.`id`, `domain_details`.`value`) + LEFT JOIN + `cloud`.`disk_offering_details` AS `zone_details` ON `zone_details`.`offering_id` = `disk_offering`.`id` AND `zone_details`.`name`='zoneid' + LEFT JOIN + `cloud`.`data_center` AS `zone` ON FIND_IN_SET(`zone`.`id`, `zone_details`.`value`) + WHERE + `disk_offering`.`state`='Active' + GROUP BY + `disk_offering`.`id`; + +-- Service offering with multi-domains and multi-zones +DROP VIEW IF EXISTS `cloud`.`service_offering_view`; +CREATE VIEW `cloud`.`service_offering_view` AS + SELECT + `service_offering`.`id` AS `id`, + `disk_offering`.`uuid` AS `uuid`, + `disk_offering`.`name` AS `name`, + `disk_offering`.`display_text` AS `display_text`, + `disk_offering`.`provisioning_type` AS `provisioning_type`, + `disk_offering`.`created` AS `created`, + `disk_offering`.`tags` AS `tags`, + `disk_offering`.`removed` AS `removed`, + `disk_offering`.`use_local_storage` AS `use_local_storage`, + `disk_offering`.`system_use` AS `system_use`, + `disk_offering`.`customized_iops` AS `customized_iops`, + `disk_offering`.`min_iops` AS `min_iops`, + `disk_offering`.`max_iops` AS `max_iops`, + `disk_offering`.`hv_ss_reserve` AS `hv_ss_reserve`, + `disk_offering`.`bytes_read_rate` AS `bytes_read_rate`, + `disk_offering`.`bytes_read_rate_max` AS `bytes_read_rate_max`, + `disk_offering`.`bytes_read_rate_max_length` AS `bytes_read_rate_max_length`, + `disk_offering`.`bytes_write_rate` AS `bytes_write_rate`, + `disk_offering`.`bytes_write_rate_max` AS `bytes_write_rate_max`, + `disk_offering`.`bytes_write_rate_max_length` AS `bytes_write_rate_max_length`, + `disk_offering`.`iops_read_rate` AS `iops_read_rate`, + `disk_offering`.`iops_read_rate_max` AS `iops_read_rate_max`, + `disk_offering`.`iops_read_rate_max_length` AS `iops_read_rate_max_length`, + `disk_offering`.`iops_write_rate` AS `iops_write_rate`, + `disk_offering`.`iops_write_rate_max` AS `iops_write_rate_max`, + `disk_offering`.`iops_write_rate_max_length` AS `iops_write_rate_max_length`, + `disk_offering`.`cache_mode` AS `cache_mode`, + `service_offering`.`cpu` AS `cpu`, + `service_offering`.`speed` AS `speed`, + `service_offering`.`ram_size` AS `ram_size`, + `service_offering`.`nw_rate` AS `nw_rate`, + `service_offering`.`mc_rate` AS `mc_rate`, + `service_offering`.`ha_enabled` AS `ha_enabled`, + `service_offering`.`limit_cpu_use` AS `limit_cpu_use`, + `service_offering`.`host_tag` AS `host_tag`, + `service_offering`.`default_use` AS `default_use`, + `service_offering`.`vm_type` AS `vm_type`, + `service_offering`.`sort_key` AS `sort_key`, + `service_offering`.`is_volatile` AS `is_volatile`, + `service_offering`.`deployment_planner` AS `deployment_planner`, + GROUP_CONCAT(DISTINCT(domain.id)) AS domain_id, + GROUP_CONCAT(DISTINCT(domain.uuid)) AS domain_uuid, + GROUP_CONCAT(DISTINCT(domain.name)) AS domain_name, + GROUP_CONCAT(DISTINCT(domain.path)) AS domain_path, + GROUP_CONCAT(DISTINCT(zone.id)) AS zone_id, + GROUP_CONCAT(DISTINCT(zone.uuid)) AS zone_uuid, + GROUP_CONCAT(DISTINCT(zone.name)) AS zone_name + FROM + `cloud`.`service_offering` + INNER JOIN + `cloud`.`disk_offering_view` AS `disk_offering` ON service_offering.id = disk_offering.id + LEFT JOIN + `cloud`.`service_offering_details` AS `domain_details` ON `domain_details`.`service_offering_id` = `disk_offering`.`id` AND `domain_details`.`name`='domainid' + LEFT JOIN + `cloud`.`domain` AS `domain` ON FIND_IN_SET(`domain`.`id`, `domain_details`.`value`) + LEFT JOIN + `cloud`.`service_offering_details` AS `zone_details` ON `zone_details`.`service_offering_id` = `disk_offering`.`id` AND `zone_details`.`name`='zoneid' + LEFT JOIN + `cloud`.`data_center` AS `zone` ON FIND_IN_SET(`zone`.`id`, `zone_details`.`value`) + WHERE + `disk_offering`.`state`='Active' + GROUP BY + `service_offering`.`id`; + +-- Add display column for network offering details table +ALTER TABLE `cloud`.`network_offering_details` ADD COLUMN `display` tinyint(1) NOT NULL DEFAULT '1' COMMENT 'True if the detail can be displayed to the end user'; + +-- Network offering with multi-domains and multi-zones +DROP VIEW IF EXISTS `cloud`.`network_offering_view`; +CREATE VIEW `cloud`.`network_offering_view` AS + SELECT + `network_offerings`.`id` AS `id`, + `network_offerings`.`uuid` AS `uuid`, + `network_offerings`.`name` AS `name`, + `network_offerings`.`unique_name` AS `unique_name`, + `network_offerings`.`display_text` AS `display_text`, + `network_offerings`.`nw_rate` AS `nw_rate`, + `network_offerings`.`mc_rate` AS `mc_rate`, + `network_offerings`.`traffic_type` AS `traffic_type`, + `network_offerings`.`tags` AS `tags`, + `network_offerings`.`system_only` AS `system_only`, + `network_offerings`.`specify_vlan` AS `specify_vlan`, + `network_offerings`.`service_offering_id` AS `service_offering_id`, + `network_offerings`.`conserve_mode` AS `conserve_mode`, + `network_offerings`.`created` AS `created`, + `network_offerings`.`removed` AS `removed`, + `network_offerings`.`default` AS `default`, + `network_offerings`.`availability` AS `availability`, + `network_offerings`.`dedicated_lb_service` AS `dedicated_lb_service`, + `network_offerings`.`shared_source_nat_service` AS `shared_source_nat_service`, + `network_offerings`.`sort_key` AS `sort_key`, + `network_offerings`.`redundant_router_service` AS `redundant_router_service`, + `network_offerings`.`state` AS `state`, + `network_offerings`.`guest_type` AS `guest_type`, + `network_offerings`.`elastic_ip_service` AS `elastic_ip_service`, + `network_offerings`.`eip_associate_public_ip` AS `eip_associate_public_ip`, + `network_offerings`.`elastic_lb_service` AS `elastic_lb_service`, + `network_offerings`.`specify_ip_ranges` AS `specify_ip_ranges`, + `network_offerings`.`inline` AS `inline`, + `network_offerings`.`is_persistent` AS `is_persistent`, + `network_offerings`.`internal_lb` AS `internal_lb`, + `network_offerings`.`public_lb` AS `public_lb`, + `network_offerings`.`egress_default_policy` AS `egress_default_policy`, + `network_offerings`.`concurrent_connections` AS `concurrent_connections`, + `network_offerings`.`keep_alive_enabled` AS `keep_alive_enabled`, + `network_offerings`.`supports_streched_l2` AS `supports_streched_l2`, + `network_offerings`.`supports_public_access` AS `supports_public_access`, + `network_offerings`.`for_vpc` AS `for_vpc`, + `network_offerings`.`service_package_id` AS `service_package_id`, + GROUP_CONCAT(DISTINCT(domain.id)) AS domain_id, + GROUP_CONCAT(DISTINCT(domain.uuid)) AS domain_uuid, + GROUP_CONCAT(DISTINCT(domain.name)) AS domain_name, + GROUP_CONCAT(DISTINCT(domain.path)) AS domain_path, + GROUP_CONCAT(DISTINCT(zone.id)) AS zone_id, + GROUP_CONCAT(DISTINCT(zone.uuid)) AS zone_uuid, + GROUP_CONCAT(DISTINCT(zone.name)) AS zone_name + FROM + `cloud`.`network_offerings` + LEFT JOIN + `cloud`.`network_offering_details` AS `domain_details` ON `domain_details`.`network_offering_id` = `network_offerings`.`id` AND `domain_details`.`name`='domainid' + LEFT JOIN + `cloud`.`domain` AS `domain` ON FIND_IN_SET(`domain`.`id`, `domain_details`.`value`) + LEFT JOIN + `cloud`.`network_offering_details` AS `zone_details` ON `zone_details`.`network_offering_id` = `network_offerings`.`id` AND `zone_details`.`name`='zoneid' + LEFT JOIN + `cloud`.`data_center` AS `zone` ON FIND_IN_SET(`zone`.`id`, `zone_details`.`value`) + GROUP BY + `network_offerings`.`id`; + +-- Create VPC offering details table +CREATE TABLE `vpc_offering_details` ( + `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT, + `offering_id` bigint(20) unsigned NOT NULL COMMENT 'vpc offering id', + `name` varchar(255) NOT NULL, + `value` varchar(1024) NOT NULL, + `display` tinyint(1) NOT NULL DEFAULT '1' COMMENT 'True if the detail can be displayed to the end user', + PRIMARY KEY (`id`), + KEY `fk_vpc_offering_details__vpc_offering_id` (`offering_id`), + CONSTRAINT `fk_vpc_offering_details__vpc_offering_id` FOREIGN KEY (`offering_id`) REFERENCES `vpc_offerings` (`id`) ON DELETE CASCADE +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + +-- VPC offering with multi-domains and multi-zones +DROP VIEW IF EXISTS `cloud`.`vpc_offering_view`; +CREATE VIEW `cloud`.`vpc_offering_view` AS + SELECT + `vpc_offerings`.`id` AS `id`, + `vpc_offerings`.`uuid` AS `uuid`, + `vpc_offerings`.`name` AS `name`, + `vpc_offerings`.`unique_name` AS `unique_name`, + `vpc_offerings`.`display_text` AS `display_text`, + `vpc_offerings`.`state` AS `state`, + `vpc_offerings`.`default` AS `default`, + `vpc_offerings`.`created` AS `created`, + `vpc_offerings`.`removed` AS `removed`, + `vpc_offerings`.`service_offering_id` AS `service_offering_id`, + `vpc_offerings`.`supports_distributed_router` AS `supports_distributed_router`, + `vpc_offerings`.`supports_region_level_vpc` AS `supports_region_level_vpc`, + `vpc_offerings`.`redundant_router_service` AS `redundant_router_service`, + `vpc_offerings`.`sort_key` AS `sort_key`, + GROUP_CONCAT(DISTINCT(domain.id)) AS domain_id, + GROUP_CONCAT(DISTINCT(domain.uuid)) AS domain_uuid, + GROUP_CONCAT(DISTINCT(domain.name)) AS domain_name, + GROUP_CONCAT(DISTINCT(domain.path)) AS domain_path, + GROUP_CONCAT(DISTINCT(zone.id)) AS zone_id, + GROUP_CONCAT(DISTINCT(zone.uuid)) AS zone_uuid, + GROUP_CONCAT(DISTINCT(zone.name)) AS zone_name + FROM + `cloud`.`vpc_offerings` + LEFT JOIN + `cloud`.`vpc_offering_details` AS `domain_details` ON `domain_details`.`offering_id` = `vpc_offerings`.`id` AND `domain_details`.`name`='domainid' + LEFT JOIN + `cloud`.`domain` AS `domain` ON FIND_IN_SET(`domain`.`id`, `domain_details`.`value`) + LEFT JOIN + `cloud`.`vpc_offering_details` AS `zone_details` ON `zone_details`.`offering_id` = `vpc_offerings`.`id` AND `zone_details`.`name`='zoneid' + LEFT JOIN + `cloud`.`data_center` AS `zone` ON FIND_IN_SET(`zone`.`id`, `zone_details`.`value`) + GROUP BY + `vpc_offerings`.`id`; + -- Recreate data_center_view DROP VIEW IF EXISTS `cloud`.`data_center_view`; CREATE VIEW `cloud`.`data_center_view` AS diff --git a/framework/db/src/main/java/com/cloud/utils/db/SearchBase.java b/framework/db/src/main/java/com/cloud/utils/db/SearchBase.java index d19918a3d55..6861b844dbf 100644 --- a/framework/db/src/main/java/com/cloud/utils/db/SearchBase.java +++ b/framework/db/src/main/java/com/cloud/utils/db/SearchBase.java @@ -28,15 +28,15 @@ import java.util.Map; import javax.persistence.Column; import javax.persistence.Transient; -import net.sf.cglib.proxy.Factory; -import net.sf.cglib.proxy.MethodInterceptor; -import net.sf.cglib.proxy.MethodProxy; - import com.cloud.utils.db.SearchCriteria.Func; import com.cloud.utils.db.SearchCriteria.Op; import com.cloud.utils.db.SearchCriteria.SelectType; import com.cloud.utils.exception.CloudRuntimeException; +import net.sf.cglib.proxy.Factory; +import net.sf.cglib.proxy.MethodInterceptor; +import net.sf.cglib.proxy.MethodProxy; + /** * SearchBase contains the methods that are used to build up search * queries. While this class is public it's not really meant for public @@ -410,6 +410,10 @@ public abstract class SearchBase, T, K> { return; } + if (op == Op.FIND_IN_SET) { + sql.append(" FIND_IN_SET(?, "); + } + sql.append(attr.table).append(".").append(attr.columnName).append(op.toString()); if (op == Op.IN && params.length == 1) { sql.delete(sql.length() - op.toString().length(), sql.length()); diff --git a/framework/db/src/main/java/com/cloud/utils/db/SearchCriteria.java b/framework/db/src/main/java/com/cloud/utils/db/SearchCriteria.java index b7f8a93b2c8..608f715018c 100644 --- a/framework/db/src/main/java/com/cloud/utils/db/SearchCriteria.java +++ b/framework/db/src/main/java/com/cloud/utils/db/SearchCriteria.java @@ -36,7 +36,7 @@ public class SearchCriteria { " NOT BETWEEN ? AND ? ", 2), IN(" IN () ", -1), NOTIN(" NOT IN () ", -1), LIKE(" LIKE ? ", 1), NLIKE(" NOT LIKE ? ", 1), NIN(" NOT IN () ", -1), NULL(" IS NULL ", 0), NNULL( " IS NOT NULL ", - 0), SC(" () ", 1), TEXT(" () ", 1), RP("", 0), AND(" AND ", 0), OR(" OR ", 0), NOT(" NOT ", 0); + 0), SC(" () ", 1), TEXT(" () ", 1), RP("", 0), AND(" AND ", 0), OR(" OR ", 0), NOT(" NOT ", 0), FIND_IN_SET(" ) ", 1); private final String op; int params; diff --git a/framework/quota/src/main/java/org/apache/cloudstack/quota/vo/ServiceOfferingVO.java b/framework/quota/src/main/java/org/apache/cloudstack/quota/vo/ServiceOfferingVO.java index 00bdb82cdec..5ac401e80d6 100644 --- a/framework/quota/src/main/java/org/apache/cloudstack/quota/vo/ServiceOfferingVO.java +++ b/framework/quota/src/main/java/org/apache/cloudstack/quota/vo/ServiceOfferingVO.java @@ -103,7 +103,7 @@ public class ServiceOfferingVO extends DiskOfferingVO implements ServiceOffering public ServiceOfferingVO(String name, Integer cpu, Integer ramSize, Integer speed, Integer rateMbps, Integer multicastRateMbps, boolean offerHA, boolean limitCpuUse, boolean volatileVm, String displayText, ProvisioningType provisioningType, boolean useLocalStorage, boolean recreatable, String tags, boolean systemUse, VirtualMachine.Type vmType, Long domainId) { - super(name, displayText, provisioningType, false, tags, recreatable, useLocalStorage, systemUse, true, domainId); + super(name, displayText, provisioningType, false, tags, recreatable, useLocalStorage, systemUse, true); this.cpu = cpu; this.ramSize = ramSize; this.speed = speed; @@ -133,7 +133,7 @@ public class ServiceOfferingVO extends DiskOfferingVO implements ServiceOffering public ServiceOfferingVO(ServiceOfferingVO offering) { super(offering.getId(), offering.getName(), offering.getDisplayText(), offering.getProvisioningType(), false, offering.getTags(), offering.isRecreatable(), - offering.isUseLocalStorage(), offering.isSystemUse(), true, offering.isCustomizedIops() == null ? false : offering.isCustomizedIops(), offering.getDomainId(), + offering.isUseLocalStorage(), offering.isSystemUse(), true, offering.isCustomizedIops() == null ? false : offering.isCustomizedIops(), offering.getMinIops(), offering.getMaxIops()); cpu = offering.getCpu(); ramSize = offering.getRamSize(); diff --git a/plugins/network-elements/juniper-contrail/src/main/java/org/apache/cloudstack/network/contrail/management/ContrailManagerImpl.java b/plugins/network-elements/juniper-contrail/src/main/java/org/apache/cloudstack/network/contrail/management/ContrailManagerImpl.java index 9a076c6733f..aee24b05d57 100644 --- a/plugins/network-elements/juniper-contrail/src/main/java/org/apache/cloudstack/network/contrail/management/ContrailManagerImpl.java +++ b/plugins/network-elements/juniper-contrail/src/main/java/org/apache/cloudstack/network/contrail/management/ContrailManagerImpl.java @@ -219,7 +219,7 @@ public class ContrailManagerImpl extends ManagerBase implements ContrailManager ConfigurationManager configMgr = (ConfigurationManager) _configService; NetworkOfferingVO voffer = configMgr.createNetworkOffering(offeringName, offeringDisplayText, TrafficType.Public, null, true, Availability.Optional, null, serviceProviderMap, true, - Network.GuestType.Shared, false, null, false, null, true, false, null, true, null, false, false); + Network.GuestType.Shared, false, null, false, null, true, false, null, true, null, false, false, null, null); voffer.setState(NetworkOffering.State.Enabled); long id = voffer.getId(); @@ -256,7 +256,7 @@ public class ContrailManagerImpl extends ManagerBase implements ContrailManager ConfigurationManager configMgr = (ConfigurationManager)_configService; NetworkOfferingVO voffer = configMgr.createNetworkOffering(offeringName, offeringDisplayText, TrafficType.Guest, null, false, Availability.Optional, null, serviceProviderMap, true, - Network.GuestType.Isolated, false, null, false, null, false, true, null, true, null, false, offeringName.equals(vpcRouterOfferingName)); + Network.GuestType.Isolated, false, null, false, null, false, true, null, true, null, false, offeringName.equals(vpcRouterOfferingName), null, null); voffer.setState(NetworkOffering.State.Enabled); if (offeringName.equals(vpcRouterOfferingName)) { @@ -299,7 +299,7 @@ public class ContrailManagerImpl extends ManagerBase implements ContrailManager } serviceProviderMap.put(svc, providerSet); } - vpcOffer = _vpcProvSvc.createVpcOffering(juniperVPCOfferingName, juniperVPCOfferingDisplayText, services, serviceProviderMap, null, null); + vpcOffer = _vpcProvSvc.createVpcOffering(juniperVPCOfferingName, juniperVPCOfferingDisplayText, services, serviceProviderMap, null, null, null, null); ((VpcOfferingVO)vpcOffer).setState(VpcOffering.State.Enabled); long id = vpcOffer.getId(); _vpcOffDao.update(id, (VpcOfferingVO)vpcOffer); diff --git a/plugins/network-elements/juniper-contrail/src/test/java/org/apache/cloudstack/network/contrail/management/ManagementServerMock.java b/plugins/network-elements/juniper-contrail/src/test/java/org/apache/cloudstack/network/contrail/management/ManagementServerMock.java index db06c88cff4..64a036a2c62 100644 --- a/plugins/network-elements/juniper-contrail/src/test/java/org/apache/cloudstack/network/contrail/management/ManagementServerMock.java +++ b/plugins/network-elements/juniper-contrail/src/test/java/org/apache/cloudstack/network/contrail/management/ManagementServerMock.java @@ -21,6 +21,7 @@ import static org.junit.Assert.assertNotNull; import java.lang.reflect.Field; import java.util.ArrayList; +import java.util.Collections; import java.util.List; import java.util.UUID; @@ -307,7 +308,7 @@ public class ManagementServerMock { } private ServiceOffering getServiceByName(String name) { - List service_list = _serviceOfferingDao.findPublicServiceOfferings(); + List service_list = Collections.emptyList(); for (ServiceOfferingVO service : service_list) { if (service.getName().equals(name)) { return service; diff --git a/plugins/network-elements/juniper-contrail/src/test/java/org/apache/cloudstack/network/contrail/management/MockAccountManager.java b/plugins/network-elements/juniper-contrail/src/test/java/org/apache/cloudstack/network/contrail/management/MockAccountManager.java index f07a7435231..68ff2e80378 100644 --- a/plugins/network-elements/juniper-contrail/src/test/java/org/apache/cloudstack/network/contrail/management/MockAccountManager.java +++ b/plugins/network-elements/juniper-contrail/src/test/java/org/apache/cloudstack/network/contrail/management/MockAccountManager.java @@ -41,11 +41,14 @@ import org.apache.cloudstack.context.CallContext; import com.cloud.api.query.vo.ControlledViewEntity; import com.cloud.configuration.ResourceLimit; import com.cloud.configuration.dao.ResourceCountDao; +import com.cloud.dc.DataCenter; import com.cloud.domain.Domain; import com.cloud.exception.ConcurrentOperationException; import com.cloud.exception.PermissionDeniedException; import com.cloud.exception.ResourceUnavailableException; +import com.cloud.network.vpc.VpcOffering; import com.cloud.offering.DiskOffering; +import com.cloud.offering.NetworkOffering; import com.cloud.offering.ServiceOffering; import com.cloud.projects.Project.ListProjectResourcesCriteria; import com.cloud.user.Account; @@ -430,12 +433,22 @@ public class MockAccountManager extends ManagerBase implements AccountManager { } @Override - public void checkAccess(Account account, ServiceOffering so) throws PermissionDeniedException { + public void checkAccess(Account account, ServiceOffering so, DataCenter zone) throws PermissionDeniedException { // TODO Auto-generated method stub } @Override - public void checkAccess(Account account, DiskOffering dof) throws PermissionDeniedException { + public void checkAccess(Account account, DiskOffering dof, DataCenter zone) throws PermissionDeniedException { + // TODO Auto-generated method stub + } + + @Override + public void checkAccess(Account account, NetworkOffering nof, DataCenter zone) throws PermissionDeniedException { + // TODO Auto-generated method stub + } + + @Override + public void checkAccess(Account account, VpcOffering vof, DataCenter zone) throws PermissionDeniedException { // TODO Auto-generated method stub } diff --git a/server/src/main/java/com/cloud/acl/DomainChecker.java b/server/src/main/java/com/cloud/acl/DomainChecker.java index c9e4087f6ba..5184d660e9b 100644 --- a/server/src/main/java/com/cloud/acl/DomainChecker.java +++ b/server/src/main/java/com/cloud/acl/DomainChecker.java @@ -16,13 +16,15 @@ // under the License. package com.cloud.acl; -import javax.inject.Inject; +import java.util.List; -import org.springframework.stereotype.Component; +import javax.inject.Inject; import org.apache.cloudstack.acl.ControlledEntity; import org.apache.cloudstack.acl.SecurityChecker; import org.apache.cloudstack.affinity.AffinityGroup; +import org.apache.cloudstack.resourcedetail.dao.DiskOfferingDetailsDao; +import org.springframework.stereotype.Component; import com.cloud.dc.DataCenter; import com.cloud.dc.DedicatedResourceVO; @@ -32,10 +34,15 @@ import com.cloud.domain.dao.DomainDao; import com.cloud.exception.PermissionDeniedException; import com.cloud.network.Network; import com.cloud.network.NetworkModel; +import com.cloud.network.vpc.VpcOffering; +import com.cloud.network.vpc.dao.VpcOfferingDetailsDao; import com.cloud.offering.DiskOffering; +import com.cloud.offering.NetworkOffering; import com.cloud.offering.ServiceOffering; +import com.cloud.offerings.dao.NetworkOfferingDetailsDao; import com.cloud.projects.ProjectManager; import com.cloud.projects.dao.ProjectAccountDao; +import com.cloud.service.dao.ServiceOfferingDetailsDao; import com.cloud.storage.LaunchPermissionVO; import com.cloud.storage.dao.LaunchPermissionDao; import com.cloud.template.VirtualMachineTemplate; @@ -64,6 +71,14 @@ public class DomainChecker extends AdapterBase implements SecurityChecker { private DedicatedResourceDao _dedicatedDao; @Inject AccountService _accountService; + @Inject + DiskOfferingDetailsDao diskOfferingDetailsDao; + @Inject + ServiceOfferingDetailsDao serviceOfferingDetailsDao; + @Inject + NetworkOfferingDetailsDao networkOfferingDetailsDao; + @Inject + VpcOfferingDetailsDao vpcOfferingDetailsDao; protected DomainChecker() { super(); @@ -167,81 +182,155 @@ public class DomainChecker extends AdapterBase implements SecurityChecker { } @Override - public boolean checkAccess(Account account, DiskOffering dof) throws PermissionDeniedException { - if (account == null || dof == null || dof.getDomainId() == null) {//public offering - return true; + public boolean checkAccess(Account account, DiskOffering dof, DataCenter zone) throws PermissionDeniedException { + boolean hasAccess = false; + // Check for domains + if (account == null || dof == null) { + hasAccess = true; } else { //admin has all permissions if (_accountService.isRootAdmin(account.getId())) { - return true; + hasAccess = true; } //if account is normal user or domain admin - //check if account's domain is a child of zone's domain (Note: This is made consistent with the list command for disk offering) + //check if account's domain is a child of offering's domain (Note: This is made consistent with the list command for disk offering) else if (_accountService.isNormalUser(account.getId()) || account.getType() == Account.ACCOUNT_TYPE_RESOURCE_DOMAIN_ADMIN || _accountService.isDomainAdmin(account.getId()) || account.getType() == Account.ACCOUNT_TYPE_PROJECT) { - if (account.getDomainId() == dof.getDomainId()) { - return true; //disk offering and account at exact node + final List doDomainIds = diskOfferingDetailsDao.findDomainIds(dof.getId()); + if (doDomainIds.isEmpty()) { + hasAccess = true; } else { - Domain domainRecord = _domainDao.findById(account.getDomainId()); - if (domainRecord != null) { - while (true) { - if (domainRecord.getId() == dof.getDomainId()) { - //found as a child - return true; - } - if (domainRecord.getParent() != null) { - domainRecord = _domainDao.findById(domainRecord.getParent()); - } else { - break; - } + for (Long domainId : doDomainIds) { + if (_domainDao.isChildDomain(domainId, account.getDomainId())) { + hasAccess = true; + break; } } } } } - //not found - return false; + // Check for zones + if (hasAccess && dof != null && zone != null) { + final List doZoneIds = diskOfferingDetailsDao.findZoneIds(dof.getId()); + hasAccess = doZoneIds.isEmpty() || doZoneIds.contains(zone.getId()); + } + return hasAccess; } @Override - public boolean checkAccess(Account account, ServiceOffering so) throws PermissionDeniedException { - if (account == null || so.getDomainId() == null) {//public offering - return true; + public boolean checkAccess(Account account, ServiceOffering so, DataCenter zone) throws PermissionDeniedException { + boolean hasAccess = false; + // Check for domains + if (account == null || so == null) { + hasAccess = true; } else { //admin has all permissions if (_accountService.isRootAdmin(account.getId())) { - return true; + hasAccess = true; } //if account is normal user or domain admin - //check if account's domain is a child of zone's domain (Note: This is made consistent with the list command for service offering) + //check if account's domain is a child of offering's domain (Note: This is made consistent with the list command for service offering) else if (_accountService.isNormalUser(account.getId()) || account.getType() == Account.ACCOUNT_TYPE_RESOURCE_DOMAIN_ADMIN || _accountService.isDomainAdmin(account.getId()) || account.getType() == Account.ACCOUNT_TYPE_PROJECT) { - if (account.getDomainId() == so.getDomainId()) { - return true; //service offering and account at exact node + final List soDomainIds = serviceOfferingDetailsDao.findDomainIds(so.getId()); + if (soDomainIds.isEmpty()) { + hasAccess = true; } else { - Domain domainRecord = _domainDao.findById(account.getDomainId()); - if (domainRecord != null) { - while (true) { - if (domainRecord.getId() == so.getDomainId()) { - //found as a child - return true; - } - if (domainRecord.getParent() != null) { - domainRecord = _domainDao.findById(domainRecord.getParent()); - } else { - break; - } + for (Long domainId : soDomainIds) { + if (_domainDao.isChildDomain(domainId, account.getDomainId())) { + hasAccess = true; + break; } } } } } - //not found - return false; + // Check for zones + if (hasAccess && so != null && zone != null) { + final List soZoneIds = serviceOfferingDetailsDao.findZoneIds(so.getId()); + hasAccess = soZoneIds.isEmpty() || soZoneIds.contains(zone.getId()); + } + return hasAccess; + } + + @Override + public boolean checkAccess(Account account, NetworkOffering nof, DataCenter zone) throws PermissionDeniedException { + boolean hasAccess = false; + // Check for domains + if (account == null || nof == null) { + hasAccess = true; + } else { + //admin has all permissions + if (_accountService.isRootAdmin(account.getId())) { + hasAccess = true; + } + //if account is normal user or domain admin + //check if account's domain is a child of offering's domain (Note: This is made consistent with the list command for disk offering) + else if (_accountService.isNormalUser(account.getId()) + || account.getType() == Account.ACCOUNT_TYPE_RESOURCE_DOMAIN_ADMIN + || _accountService.isDomainAdmin(account.getId()) + || account.getType() == Account.ACCOUNT_TYPE_PROJECT) { + final List noDomainIds = networkOfferingDetailsDao.findDomainIds(nof.getId()); + if (noDomainIds.isEmpty()) { + hasAccess = true; + } else { + for (Long domainId : noDomainIds) { + if (_domainDao.isChildDomain(domainId, account.getDomainId())) { + hasAccess = true; + break; + } + } + } + } + } + // Check for zones + if (hasAccess && nof != null && zone != null) { + final List doZoneIds = networkOfferingDetailsDao.findZoneIds(nof.getId()); + hasAccess = doZoneIds.isEmpty() || doZoneIds.contains(zone.getId()); + } + return hasAccess; + } + + @Override + public boolean checkAccess(Account account, VpcOffering vof, DataCenter zone) throws PermissionDeniedException { + boolean hasAccess = false; + // Check for domains + if (account == null || vof == null) { + hasAccess = true; + } else { + //admin has all permissions + if (_accountService.isRootAdmin(account.getId())) { + hasAccess = true; + } + //if account is normal user or domain admin + //check if account's domain is a child of offering's domain (Note: This is made consistent with the list command for disk offering) + else if (_accountService.isNormalUser(account.getId()) + || account.getType() == Account.ACCOUNT_TYPE_RESOURCE_DOMAIN_ADMIN + || _accountService.isDomainAdmin(account.getId()) + || account.getType() == Account.ACCOUNT_TYPE_PROJECT) { + final List voDomainIds = vpcOfferingDetailsDao.findDomainIds(vof.getId()); + if (voDomainIds.isEmpty()) { + hasAccess = true; + } else { + for (Long domainId : voDomainIds) { + if (_domainDao.isChildDomain(domainId, account.getDomainId())) { + hasAccess = true; + break; + } + } + } + } + } + // Check for zones + if (hasAccess && vof != null && zone != null) { + final List doZoneIds = vpcOfferingDetailsDao.findZoneIds(vof.getId()); + hasAccess = doZoneIds.isEmpty() || doZoneIds.contains(zone.getId()); + } + return hasAccess; } @Override diff --git a/server/src/main/java/com/cloud/api/ApiDBUtils.java b/server/src/main/java/com/cloud/api/ApiDBUtils.java index 45acbf34f80..acd73622642 100644 --- a/server/src/main/java/com/cloud/api/ApiDBUtils.java +++ b/server/src/main/java/com/cloud/api/ApiDBUtils.java @@ -48,6 +48,7 @@ import org.apache.cloudstack.api.response.HostResponse; import org.apache.cloudstack.api.response.HostTagResponse; import org.apache.cloudstack.api.response.ImageStoreResponse; import org.apache.cloudstack.api.response.InstanceGroupResponse; +import org.apache.cloudstack.api.response.NetworkOfferingResponse; import org.apache.cloudstack.api.response.ProjectAccountResponse; import org.apache.cloudstack.api.response.ProjectInvitationResponse; import org.apache.cloudstack.api.response.ProjectResponse; @@ -60,6 +61,7 @@ import org.apache.cloudstack.api.response.TemplateResponse; import org.apache.cloudstack.api.response.UserResponse; import org.apache.cloudstack.api.response.UserVmResponse; import org.apache.cloudstack.api.response.VolumeResponse; +import org.apache.cloudstack.api.response.VpcOfferingResponse; import org.apache.cloudstack.api.response.ZoneResponse; import org.apache.cloudstack.context.CallContext; import org.apache.cloudstack.engine.orchestration.service.NetworkOrchestrationService; @@ -68,6 +70,7 @@ import org.apache.cloudstack.framework.config.dao.ConfigurationDao; import org.apache.cloudstack.framework.jobs.AsyncJob; import org.apache.cloudstack.framework.jobs.AsyncJobManager; import org.apache.cloudstack.framework.jobs.dao.AsyncJobDao; +import org.apache.cloudstack.resourcedetail.dao.DiskOfferingDetailsDao; import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao; import org.apache.cloudstack.storage.datastore.db.StoragePoolVO; @@ -83,6 +86,7 @@ import com.cloud.api.query.dao.HostJoinDao; import com.cloud.api.query.dao.HostTagDao; import com.cloud.api.query.dao.ImageStoreJoinDao; import com.cloud.api.query.dao.InstanceGroupJoinDao; +import com.cloud.api.query.dao.NetworkOfferingJoinDao; import com.cloud.api.query.dao.ProjectAccountJoinDao; import com.cloud.api.query.dao.ProjectInvitationJoinDao; import com.cloud.api.query.dao.ProjectJoinDao; @@ -94,6 +98,7 @@ import com.cloud.api.query.dao.TemplateJoinDao; import com.cloud.api.query.dao.UserAccountJoinDao; import com.cloud.api.query.dao.UserVmJoinDao; import com.cloud.api.query.dao.VolumeJoinDao; +import com.cloud.api.query.dao.VpcOfferingJoinDao; import com.cloud.api.query.vo.AccountJoinVO; import com.cloud.api.query.vo.AffinityGroupJoinVO; import com.cloud.api.query.vo.AsyncJobJoinVO; @@ -106,6 +111,7 @@ import com.cloud.api.query.vo.HostJoinVO; import com.cloud.api.query.vo.HostTagVO; import com.cloud.api.query.vo.ImageStoreJoinVO; import com.cloud.api.query.vo.InstanceGroupJoinVO; +import com.cloud.api.query.vo.NetworkOfferingJoinVO; import com.cloud.api.query.vo.ProjectAccountJoinVO; import com.cloud.api.query.vo.ProjectInvitationJoinVO; import com.cloud.api.query.vo.ProjectJoinVO; @@ -117,6 +123,7 @@ import com.cloud.api.query.vo.TemplateJoinVO; import com.cloud.api.query.vo.UserAccountJoinVO; import com.cloud.api.query.vo.UserVmJoinVO; import com.cloud.api.query.vo.VolumeJoinVO; +import com.cloud.api.query.vo.VpcOfferingJoinVO; import com.cloud.capacity.CapacityManager; import com.cloud.capacity.CapacityVO; import com.cloud.capacity.dao.CapacityDao; @@ -185,6 +192,7 @@ import com.cloud.network.dao.AccountGuestVlanMapDao; import com.cloud.network.dao.AccountGuestVlanMapVO; import com.cloud.network.dao.FirewallRulesCidrsDao; import com.cloud.network.dao.FirewallRulesDao; +import com.cloud.network.dao.FirewallRulesDcidrsDao; import com.cloud.network.dao.IPAddressDao; import com.cloud.network.dao.IPAddressVO; import com.cloud.network.dao.LoadBalancerDao; @@ -225,6 +233,7 @@ import com.cloud.network.vpc.dao.VpcDao; import com.cloud.network.vpc.dao.VpcGatewayDao; import com.cloud.network.vpc.dao.VpcOfferingDao; import com.cloud.offering.DiskOffering; +import com.cloud.offering.NetworkOffering; import com.cloud.offering.ServiceOffering; import com.cloud.offerings.NetworkOfferingVO; import com.cloud.offerings.dao.NetworkOfferingDao; @@ -277,6 +286,7 @@ import com.cloud.template.TemplateManager; import com.cloud.template.VirtualMachineTemplate; import com.cloud.user.Account; import com.cloud.user.AccountDetailsDao; +import com.cloud.user.AccountManager; import com.cloud.user.AccountService; import com.cloud.user.AccountVO; import com.cloud.user.ResourceLimitService; @@ -313,8 +323,6 @@ import com.cloud.vm.dao.UserVmDetailsDao; import com.cloud.vm.dao.VMInstanceDao; import com.cloud.vm.snapshot.VMSnapshot; import com.cloud.vm.snapshot.dao.VMSnapshotDao; -import com.cloud.user.AccountManager; -import com.cloud.network.dao.FirewallRulesDcidrsDao; public class ApiDBUtils { private static ManagementServer s_ms; @@ -336,6 +344,7 @@ public class ApiDBUtils { static CapacityDao s_capacityDao; static DiskOfferingDao s_diskOfferingDao; static DiskOfferingJoinDao s_diskOfferingJoinDao; + static DiskOfferingDetailsDao s_diskOfferingDetailsDao; static DataCenterJoinDao s_dcJoinDao; static DomainDao s_domainDao; static DomainJoinDao s_domainJoinDao; @@ -369,6 +378,7 @@ public class ApiDBUtils { static Site2SiteCustomerGatewayDao s_site2SiteCustomerGatewayDao; static DataCenterDao s_zoneDao; static NetworkOfferingDao s_networkOfferingDao; + static NetworkOfferingJoinDao s_networkOfferingJoinDao; static NetworkDao s_networkDao; static PhysicalNetworkDao s_physicalNetworkDao; static ConfigurationService s_configSvc; @@ -419,6 +429,7 @@ public class ApiDBUtils { static VpcGatewayDao s_vpcGatewayDao; static VpcDao s_vpcDao; static VpcOfferingDao s_vpcOfferingDao; + static VpcOfferingJoinDao s_vpcOfferingJoinDao; static SnapshotPolicyDao s_snapshotPolicyDao; static AsyncJobDao s_asyncJobDao; static HostDetailsDao s_hostDetailsDao; @@ -472,6 +483,8 @@ public class ApiDBUtils { @Inject private DiskOfferingJoinDao diskOfferingJoinDao; @Inject + private DiskOfferingDetailsDao diskOfferingDetailsDao; + @Inject private DomainDao domainDao; @Inject private DomainJoinDao domainJoinDao; @@ -536,6 +549,8 @@ public class ApiDBUtils { @Inject private NetworkOfferingDao networkOfferingDao; @Inject + private NetworkOfferingJoinDao networkOfferingJoinDao; + @Inject private NetworkDao networkDao; @Inject private PhysicalNetworkDao physicalNetworkDao; @@ -634,6 +649,8 @@ public class ApiDBUtils { @Inject private VpcOfferingDao vpcOfferingDao; @Inject + private VpcOfferingJoinDao vpcOfferingJoinDao; + @Inject private SnapshotPolicyDao snapshotPolicyDao; @Inject private AsyncJobDao asyncJobDao; @@ -689,6 +706,7 @@ public class ApiDBUtils { s_dcJoinDao = dcJoinDao; s_diskOfferingDao = diskOfferingDao; s_diskOfferingJoinDao = diskOfferingJoinDao; + s_diskOfferingDetailsDao = diskOfferingDetailsDao; s_domainDao = domainDao; s_domainJoinDao = domainJoinDao; s_domainRouterDao = domainRouterDao; @@ -720,6 +738,7 @@ public class ApiDBUtils { s_securityGroupDao = securityGroupDao; s_securityGroupJoinDao = securityGroupJoinDao; s_networkOfferingDao = networkOfferingDao; + s_networkOfferingJoinDao = networkOfferingJoinDao; s_networkDao = networkDao; s_physicalNetworkDao = physicalNetworkDao; s_configDao = configDao; @@ -768,6 +787,7 @@ public class ApiDBUtils { s_asVmGroupDao = asVmGroupDao; s_vpcDao = vpcDao; s_vpcOfferingDao = vpcOfferingDao; + s_vpcOfferingJoinDao = vpcOfferingJoinDao; s_snapshotPolicyDao = snapshotPolicyDao; s_asyncJobDao = asyncJobDao; s_hostDetailsDao = hostDetailsDao; @@ -1238,6 +1258,14 @@ public class ApiDBUtils { return s_networkMgr.convertNetworkToNetworkProfile(networkId); } + public static NetworkOfferingResponse newNetworkOfferingResponse(NetworkOffering offering) { + return s_networkOfferingJoinDao.newNetworkOfferingResponse(offering); + } + + public static NetworkOfferingJoinVO newNetworkOfferingView(NetworkOffering offering) { + return s_networkOfferingJoinDao.newNetworkOfferingView(offering); + } + public static NetworkOfferingVO findNetworkOfferingById(long networkOfferingId) { return s_networkOfferingDao.findByIdIncludingRemoved(networkOfferingId); } @@ -1522,6 +1550,14 @@ public class ApiDBUtils { return s_vpcOfferingDao.findById(offeringId); } + public static VpcOfferingResponse newVpcOfferingResponse(VpcOffering offering) { + return s_vpcOfferingJoinDao.newVpcOfferingResponse(offering); + } + + public static VpcOfferingJoinVO newVpcOfferingView(VpcOffering offering) { + return s_vpcOfferingJoinDao.newVpcOfferingView(offering); + } + public static NetworkACL findByNetworkACLId(long aclId) { return s_networkACLDao.findById(aclId); } diff --git a/server/src/main/java/com/cloud/api/ApiResponseHelper.java b/server/src/main/java/com/cloud/api/ApiResponseHelper.java index b4c92367577..524e109a2b1 100644 --- a/server/src/main/java/com/cloud/api/ApiResponseHelper.java +++ b/server/src/main/java/com/cloud/api/ApiResponseHelper.java @@ -176,6 +176,7 @@ import com.cloud.api.query.vo.EventJoinVO; import com.cloud.api.query.vo.HostJoinVO; import com.cloud.api.query.vo.ImageStoreJoinVO; import com.cloud.api.query.vo.InstanceGroupJoinVO; +import com.cloud.api.query.vo.NetworkOfferingJoinVO; import com.cloud.api.query.vo.ProjectAccountJoinVO; import com.cloud.api.query.vo.ProjectInvitationJoinVO; import com.cloud.api.query.vo.ProjectJoinVO; @@ -187,6 +188,7 @@ import com.cloud.api.query.vo.TemplateJoinVO; import com.cloud.api.query.vo.UserAccountJoinVO; import com.cloud.api.query.vo.UserVmJoinVO; import com.cloud.api.query.vo.VolumeJoinVO; +import com.cloud.api.query.vo.VpcOfferingJoinVO; import com.cloud.api.response.ApiResponseSerializer; import com.cloud.capacity.Capacity; import com.cloud.capacity.CapacityVO; @@ -1926,23 +1928,11 @@ public class ApiResponseHelper implements ResponseGenerator { @Override public NetworkOfferingResponse createNetworkOfferingResponse(NetworkOffering offering) { - NetworkOfferingResponse response = new NetworkOfferingResponse(); - response.setId(offering.getUuid()); - response.setName(offering.getName()); - response.setDisplayText(offering.getDisplayText()); - response.setTags(offering.getTags()); - response.setTrafficType(offering.getTrafficType().toString()); - response.setIsDefault(offering.isDefault()); - response.setSpecifyVlan(offering.isSpecifyVlan()); - response.setConserveMode(offering.isConserveMode()); - response.setSpecifyIpRanges(offering.isSpecifyIpRanges()); - response.setAvailability(offering.getAvailability().toString()); - response.setIsPersistent(offering.isPersistent()); + if (!(offering instanceof NetworkOfferingJoinVO)) { + offering = ApiDBUtils.newNetworkOfferingView(offering); + } + NetworkOfferingResponse response = ApiDBUtils.newNetworkOfferingResponse(offering); response.setNetworkRate(ApiDBUtils.getNetworkRate(offering.getId())); - response.setEgressDefaultPolicy(offering.isEgressDefaultPolicy()); - response.setConcurrentConnections(offering.getConcurrentConnections()); - response.setSupportsStrechedL2Subnet(offering.isSupportingStrechedL2()); - response.setSupportsPublicAccess(offering.isSupportingPublicAccess()); Long so = null; if (offering.getServiceOfferingId() != null) { so = offering.getServiceOfferingId(); @@ -1955,13 +1945,6 @@ public class ApiResponseHelper implements ResponseGenerator { response.setServiceOfferingId(soffering.getUuid()); } } - - if (offering.getGuestType() != null) { - response.setGuestIpType(offering.getGuestType().toString()); - } - - response.setState(offering.getState().name()); - Map> serviceProviderMap = ApiDBUtils.listNetworkOfferingServices(offering.getId()); List serviceResponses = new ArrayList(); for (Map.Entry> entry : serviceProviderMap.entrySet()) { @@ -1982,7 +1965,6 @@ public class ApiResponseHelper implements ResponseGenerator { } } svcRsp.setProviders(providers); - if (Service.Lb == service) { List lbCapResponse = new ArrayList(); @@ -2030,20 +2012,15 @@ public class ApiResponseHelper implements ResponseGenerator { svcRsp.setCapabilities(staticNatCapResponse); } - serviceResponses.add(svcRsp); } response.setForVpc(_configMgr.isOfferingForVpc(offering)); - response.setServices(serviceResponses); - //set network offering details Map details = _ntwkModel.getNtwkOffDetails(offering.getId()); if (details != null && !details.isEmpty()) { response.setDetails(details); } - - response.setObjectName("networkoffering"); return response; } @@ -2845,15 +2822,10 @@ public class ApiResponseHelper implements ResponseGenerator { @Override public VpcOfferingResponse createVpcOfferingResponse(VpcOffering offering) { - VpcOfferingResponse response = new VpcOfferingResponse(); - response.setId(offering.getUuid()); - response.setName(offering.getName()); - response.setDisplayText(offering.getDisplayText()); - response.setIsDefault(offering.isDefault()); - response.setState(offering.getState().name()); - response.setSupportsDistributedRouter(offering.supportsDistributedRouter()); - response.setSupportsRegionLevelVpc(offering.offersRegionLevelVPC()); - + if (!(offering instanceof VpcOfferingJoinVO)) { + offering = ApiDBUtils.newVpcOfferingView(offering); + } + VpcOfferingResponse response = ApiDBUtils.newVpcOfferingResponse(offering); Map> serviceProviderMap = ApiDBUtils.listVpcOffServices(offering.getId()); List serviceResponses = new ArrayList(); for (Map.Entry> entry : serviceProviderMap.entrySet()) { @@ -2879,7 +2851,6 @@ public class ApiResponseHelper implements ResponseGenerator { serviceResponses.add(svcRsp); } response.setServices(serviceResponses); - response.setObjectName("vpcoffering"); return response; } diff --git a/server/src/main/java/com/cloud/api/query/QueryManagerImpl.java b/server/src/main/java/com/cloud/api/query/QueryManagerImpl.java index 69758087258..92a110b83a9 100644 --- a/server/src/main/java/com/cloud/api/query/QueryManagerImpl.java +++ b/server/src/main/java/com/cloud/api/query/QueryManagerImpl.java @@ -23,6 +23,7 @@ import java.util.Date; import java.util.HashMap; import java.util.HashSet; import java.util.List; +import java.util.ListIterator; import java.util.Map; import java.util.Set; import java.util.stream.Collectors; @@ -112,6 +113,8 @@ import org.apache.cloudstack.framework.config.ConfigKey; import org.apache.cloudstack.framework.config.Configurable; import org.apache.cloudstack.framework.config.dao.ConfigurationDao; import org.apache.cloudstack.query.QueryService; +import org.apache.cloudstack.resourcedetail.dao.DiskOfferingDetailsDao; +import org.apache.commons.collections.CollectionUtils; import org.apache.log4j.Logger; import org.springframework.stereotype.Component; @@ -328,6 +331,9 @@ public class QueryManagerImpl extends MutualExclusiveIdsManagerBase implements Q @Inject private DiskOfferingJoinDao _diskOfferingJoinDao; + @Inject + private DiskOfferingDetailsDao diskOfferingDetailsDao; + @Inject private ServiceOfferingJoinDao _srvOfferingJoinDao; @@ -2530,6 +2536,7 @@ public class QueryManagerImpl extends MutualExclusiveIdsManagerBase implements Q Long domainId = cmd.getDomainId(); Boolean isRootAdmin = _accountMgr.isRootAdmin(account.getAccountId()); Boolean isRecursive = cmd.isRecursive(); + Long zoneId = cmd.getZoneId(); // Keeping this logic consistent with domain specific zones // if a domainId is provided, we just return the disk offering // associated with this domain @@ -2537,7 +2544,7 @@ public class QueryManagerImpl extends MutualExclusiveIdsManagerBase implements Q if (_accountMgr.isRootAdmin(account.getId()) || isPermissible(account.getDomainId(), domainId)) { // check if the user's domain == do's domain || user's domain is // a child of so's domain for non-root users - sc.addAnd("domainId", SearchCriteria.Op.EQ, domainId); + sc.addAnd("domainId", Op.FIND_IN_SET, String.valueOf(domainId)); if (!isRootAdmin) { sc.addAnd("displayOffering", SearchCriteria.Op.EQ, 1); } @@ -2547,7 +2554,6 @@ public class QueryManagerImpl extends MutualExclusiveIdsManagerBase implements Q } } - List domainIds = null; // For non-root users, only return all offerings for the user's domain, // and everything above till root if ((_accountMgr.isNormalUser(account.getId()) || _accountMgr.isDomainAdmin(account.getId())) || account.getType() == Account.ACCOUNT_TYPE_RESOURCE_DOMAIN_ADMIN) { @@ -2555,27 +2561,7 @@ public class QueryManagerImpl extends MutualExclusiveIdsManagerBase implements Q if (account.getType() == Account.ACCOUNT_TYPE_NORMAL) { throw new InvalidParameterValueException("Only ROOT admins and Domain admins can list disk offerings with isrecursive=true"); } - DomainVO domainRecord = _domainDao.findById(account.getDomainId()); - sc.addAnd("domainPath", SearchCriteria.Op.LIKE, domainRecord.getPath() + "%"); } else { // domain + all ancestors - // find all domain Id up to root domain for this account - domainIds = new ArrayList(); - DomainVO domainRecord = _domainDao.findById(account.getDomainId()); - if (domainRecord == null) { - s_logger.error("Could not find the domainId for account:" + account.getAccountName()); - throw new CloudAuthenticationException("Could not find the domainId for account:" + account.getAccountName()); - } - domainIds.add(domainRecord.getId()); - while (domainRecord.getParent() != null) { - domainRecord = _domainDao.findById(domainRecord.getParent()); - domainIds.add(domainRecord.getId()); - } - - SearchCriteria spc = _diskOfferingJoinDao.createSearchCriteria(); - - spc.addOr("domainId", SearchCriteria.Op.IN, domainIds.toArray()); - spc.addOr("domainId", SearchCriteria.Op.NULL); // include public offering as where - sc.addAnd("domainId", SearchCriteria.Op.SC, spc); sc.addAnd("systemUse", SearchCriteria.Op.EQ, false); // non-root users should not see system offering at all } @@ -2597,6 +2583,16 @@ public class QueryManagerImpl extends MutualExclusiveIdsManagerBase implements Q sc.addAnd("name", SearchCriteria.Op.EQ, name); } + if (zoneId != null) { + SearchBuilder sb = _diskOfferingJoinDao.createSearchBuilder(); + sb.and("zoneId", sb.entity().getZoneId(), Op.FIND_IN_SET); + sb.or("zId", sb.entity().getZoneId(), Op.NULL); + sb.done(); + SearchCriteria zoneSC = sb.create(); + zoneSC.setParameters("zoneId", String.valueOf(zoneId)); + sc.addAnd("zoneId", SearchCriteria.Op.SC, zoneSC); + } + // FIXME: disk offerings should search back up the hierarchy for // available disk offerings... /* @@ -2619,7 +2615,36 @@ public class QueryManagerImpl extends MutualExclusiveIdsManagerBase implements Q * domain.getPath() + "%"); // } */ - return _diskOfferingJoinDao.searchAndCount(sc, searchFilter); + Pair, Integer> result = _diskOfferingJoinDao.searchAndCount(sc, searchFilter); + // Remove offerings that are not associated with caller's domain + if (account.getType() != Account.ACCOUNT_TYPE_ADMIN && CollectionUtils.isNotEmpty(result.first())) { + ListIterator it = result.first().listIterator(); + while (it.hasNext()) { + DiskOfferingJoinVO offering = it.next(); + if(!Strings.isNullOrEmpty(offering.getDomainId())) { + boolean toRemove = true; + String[] domainIdsArray = offering.getDomainId().split(","); + for (String domainIdString : domainIdsArray) { + Long dId = Long.valueOf(domainIdString.trim()); + if (isRecursive) { + if (_domainDao.isChildDomain(account.getDomainId(), dId)) { + toRemove = false; + break; + } + } else { + if (_domainDao.isChildDomain(dId, account.getDomainId())) { + toRemove = false; + break; + } + } + } + if (toRemove) { + it.remove(); + } + } + } + } + return new Pair<>(result.first(), result.first().size()); } private List filterOfferingsOnCurrentTags(List offerings, ServiceOfferingVO currentVmOffering) { @@ -2671,6 +2696,7 @@ public class QueryManagerImpl extends MutualExclusiveIdsManagerBase implements Q String vmTypeStr = cmd.getSystemVmType(); ServiceOfferingVO currentVmOffering = null; Boolean isRecursive = cmd.isRecursive(); + Long zoneId = cmd.getZoneId(); SearchCriteria sc = _srvOfferingJoinDao.createSearchCriteria(); if (!_accountMgr.isRootAdmin(caller.getId()) && isSystem) { @@ -2722,9 +2748,7 @@ public class QueryManagerImpl extends MutualExclusiveIdsManagerBase implements Q if (caller.getType() == Account.ACCOUNT_TYPE_NORMAL) { throw new InvalidParameterValueException("Only ROOT admins and Domain admins can list service offerings with isrecursive=true"); } - DomainVO domainRecord = _domainDao.findById(caller.getDomainId()); - sc.addAnd("domainPath", SearchCriteria.Op.LIKE, domainRecord.getPath() + "%"); - } else { // domain + all ancestors + }/* else { // domain + all ancestors // find all domain Id up to root domain for this account List domainIds = new ArrayList(); DomainVO domainRecord; @@ -2752,14 +2776,14 @@ public class QueryManagerImpl extends MutualExclusiveIdsManagerBase implements Q spc.addOr("domainId", SearchCriteria.Op.IN, domainIds.toArray()); spc.addOr("domainId", SearchCriteria.Op.NULL); // include public offering as well sc.addAnd("domainId", SearchCriteria.Op.SC, spc); - } + }*/ } else { // for root users if (caller.getDomainId() != 1 && isSystem) { // NON ROOT admin throw new InvalidParameterValueException("Non ROOT admins cannot access system's offering"); } if (domainId != null) { - sc.addAnd("domainId", SearchCriteria.Op.EQ, domainId); + sc.addAnd("domainId", Op.FIND_IN_SET, String.valueOf(domainId)); } } @@ -2789,11 +2813,49 @@ public class QueryManagerImpl extends MutualExclusiveIdsManagerBase implements Q sc.addAnd("vmType", SearchCriteria.Op.EQ, vmTypeStr); } + if (zoneId != null) { + SearchBuilder sb = _srvOfferingJoinDao.createSearchBuilder(); + sb.and("zoneId", sb.entity().getZoneId(), Op.FIND_IN_SET); + sb.or("zId", sb.entity().getZoneId(), Op.NULL); + sb.done(); + SearchCriteria zoneSC = sb.create(); + zoneSC.setParameters("zoneId", String.valueOf(zoneId)); + sc.addAnd("zoneId", SearchCriteria.Op.SC, zoneSC); + } + Pair, Integer> result = _srvOfferingJoinDao.searchAndCount(sc, searchFilter); //Couldn't figure out a smart way to filter offerings based on tags in sql so doing it in Java. List filteredOfferings = filterOfferingsOnCurrentTags(result.first(), currentVmOffering); - return new Pair<>(filteredOfferings, result.second()); + // Remove offerings that are not associated with caller's domain + if (caller.getType() != Account.ACCOUNT_TYPE_ADMIN && CollectionUtils.isNotEmpty(filteredOfferings)) { + ListIterator it = filteredOfferings.listIterator(); + while (it.hasNext()) { + ServiceOfferingJoinVO offering = it.next(); + if(!Strings.isNullOrEmpty(offering.getDomainId())) { + boolean toRemove = true; + String[] domainIdsArray = offering.getDomainId().split(","); + for (String domainIdString : domainIdsArray) { + Long dId = Long.valueOf(domainIdString.trim()); + if (isRecursive) { + if (_domainDao.isChildDomain(caller.getDomainId(), dId)) { + toRemove = false; + break; + } + } else { + if (_domainDao.isChildDomain(dId, caller.getDomainId())) { + toRemove = false; + break; + } + } + } + if (toRemove) { + it.remove(); + } + } + } + } + return new Pair<>(filteredOfferings, filteredOfferings.size()); } @Override diff --git a/server/src/main/java/com/cloud/api/query/dao/DiskOfferingJoinDao.java b/server/src/main/java/com/cloud/api/query/dao/DiskOfferingJoinDao.java index 3d8247e3f04..3d612c63d38 100644 --- a/server/src/main/java/com/cloud/api/query/dao/DiskOfferingJoinDao.java +++ b/server/src/main/java/com/cloud/api/query/dao/DiskOfferingJoinDao.java @@ -16,6 +16,8 @@ // under the License. package com.cloud.api.query.dao; +import java.util.List; + import org.apache.cloudstack.api.response.DiskOfferingResponse; import com.cloud.api.query.vo.DiskOfferingJoinVO; @@ -24,6 +26,10 @@ import com.cloud.utils.db.GenericDao; public interface DiskOfferingJoinDao extends GenericDao { + List findByDomainId(long domainId); + + List findByZoneId(long zoneId); + DiskOfferingResponse newDiskOfferingResponse(DiskOfferingJoinVO dof); DiskOfferingJoinVO newDiskOfferingView(DiskOffering dof); diff --git a/server/src/main/java/com/cloud/api/query/dao/DiskOfferingJoinDaoImpl.java b/server/src/main/java/com/cloud/api/query/dao/DiskOfferingJoinDaoImpl.java index b46fbd0deb6..9220974897c 100644 --- a/server/src/main/java/com/cloud/api/query/dao/DiskOfferingJoinDaoImpl.java +++ b/server/src/main/java/com/cloud/api/query/dao/DiskOfferingJoinDaoImpl.java @@ -18,12 +18,10 @@ package com.cloud.api.query.dao; import java.util.List; - +import org.apache.cloudstack.api.response.DiskOfferingResponse; import org.apache.log4j.Logger; import org.springframework.stereotype.Component; -import org.apache.cloudstack.api.response.DiskOfferingResponse; - import com.cloud.api.query.vo.DiskOfferingJoinVO; import com.cloud.offering.DiskOffering; import com.cloud.offering.ServiceOffering; @@ -50,6 +48,28 @@ public class DiskOfferingJoinDaoImpl extends GenericDaoBase findByDomainId(long domainId) { + SearchBuilder sb = createSearchBuilder(); + sb.and("domainId", sb.entity().getDomainId(), SearchCriteria.Op.FIND_IN_SET); + sb.done(); + + SearchCriteria sc = sb.create(); + sc.setParameters("domainId", String.valueOf(domainId)); + return listBy(sc); + } + + @Override + public List findByZoneId(long zoneId) { + SearchBuilder sb = createSearchBuilder(); + sb.and("zoneId", sb.entity().getZoneId(), SearchCriteria.Op.FIND_IN_SET); + sb.done(); + + SearchCriteria sc = sb.create(); + sc.setParameters("zoneId", String.valueOf(zoneId)); + return listBy(sc); + } + @Override public DiskOfferingResponse newDiskOfferingResponse(DiskOfferingJoinVO offering) { @@ -63,9 +83,11 @@ public class DiskOfferingJoinDaoImpl extends GenericDaoBase { + + List findByDomainId(long domainId); + + List findByZoneId(long zoneId); + + NetworkOfferingResponse newNetworkOfferingResponse(NetworkOffering nof); + + NetworkOfferingJoinVO newNetworkOfferingView(NetworkOffering nof); +} diff --git a/server/src/main/java/com/cloud/api/query/dao/NetworkOfferingJoinDaoImpl.java b/server/src/main/java/com/cloud/api/query/dao/NetworkOfferingJoinDaoImpl.java new file mode 100644 index 00000000000..b53aef85d46 --- /dev/null +++ b/server/src/main/java/com/cloud/api/query/dao/NetworkOfferingJoinDaoImpl.java @@ -0,0 +1,108 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +package com.cloud.api.query.dao; + +import java.util.List; + +import org.apache.cloudstack.api.response.NetworkOfferingResponse; +import org.apache.log4j.Logger; + +import com.cloud.api.query.vo.NetworkOfferingJoinVO; +import com.cloud.offering.NetworkOffering; +import com.cloud.utils.db.GenericDaoBase; +import com.cloud.utils.db.SearchBuilder; +import com.cloud.utils.db.SearchCriteria; + +public class NetworkOfferingJoinDaoImpl extends GenericDaoBase implements NetworkOfferingJoinDao { + public static final Logger s_logger = Logger.getLogger(NetworkOfferingJoinDaoImpl.class); + + private final SearchBuilder nofIdSearch; + + protected NetworkOfferingJoinDaoImpl() { + + nofIdSearch = createSearchBuilder(); + nofIdSearch.and("id", nofIdSearch.entity().getId(), SearchCriteria.Op.EQ); + nofIdSearch.done(); + + _count = "select count(distinct id) from network_offering_view WHERE "; + } + + @Override + public List findByDomainId(long domainId) { + SearchBuilder sb = createSearchBuilder(); + sb.and("domainId", sb.entity().getDomainId(), SearchCriteria.Op.FIND_IN_SET); + sb.done(); + + SearchCriteria sc = sb.create(); + sc.setParameters("domainId", String.valueOf(domainId)); + return listBy(sc); + } + + @Override + public List findByZoneId(long zoneId) { + SearchBuilder sb = createSearchBuilder(); + sb.and("zoneId", sb.entity().getZoneId(), SearchCriteria.Op.FIND_IN_SET); + sb.done(); + + SearchCriteria sc = sb.create(); + sc.setParameters("zoneId", String.valueOf(zoneId)); + return listBy(sc); + } + + @Override + public NetworkOfferingResponse newNetworkOfferingResponse(NetworkOffering offering) { + NetworkOfferingResponse networkOfferingResponse = new NetworkOfferingResponse(); + networkOfferingResponse.setId(offering.getUuid()); + networkOfferingResponse.setName(offering.getName()); + networkOfferingResponse.setDisplayText(offering.getDisplayText()); + networkOfferingResponse.setTags(offering.getTags()); + networkOfferingResponse.setTrafficType(offering.getTrafficType().toString()); + networkOfferingResponse.setIsDefault(offering.isDefault()); + networkOfferingResponse.setSpecifyVlan(offering.isSpecifyVlan()); + networkOfferingResponse.setConserveMode(offering.isConserveMode()); + networkOfferingResponse.setSpecifyIpRanges(offering.isSpecifyIpRanges()); + networkOfferingResponse.setAvailability(offering.getAvailability().toString()); + networkOfferingResponse.setIsPersistent(offering.isPersistent()); + networkOfferingResponse.setEgressDefaultPolicy(offering.isEgressDefaultPolicy()); + networkOfferingResponse.setConcurrentConnections(offering.getConcurrentConnections()); + networkOfferingResponse.setSupportsStrechedL2Subnet(offering.isSupportingStrechedL2()); + networkOfferingResponse.setSupportsPublicAccess(offering.isSupportingPublicAccess()); + if (offering.getGuestType() != null) { + networkOfferingResponse.setGuestIpType(offering.getGuestType().toString()); + } + networkOfferingResponse.setState(offering.getState().name()); + if (offering instanceof NetworkOfferingJoinVO) { + networkOfferingResponse.setDomainId(((NetworkOfferingJoinVO) offering).getDomainUuid()); + networkOfferingResponse.setDomain(((NetworkOfferingJoinVO) offering).getDomainPath()); + networkOfferingResponse.setZoneId(((NetworkOfferingJoinVO) offering).getZoneUuid()); + networkOfferingResponse.setZone(((NetworkOfferingJoinVO) offering).getZoneName()); + } + networkOfferingResponse.setObjectName("networkoffering"); + + return networkOfferingResponse; + } + + @Override + public NetworkOfferingJoinVO newNetworkOfferingView(NetworkOffering offering) { + SearchCriteria sc = nofIdSearch.create(); + sc.setParameters("id", offering.getId()); + List offerings = searchIncludingRemoved(sc, null, null, false); + assert offerings != null && offerings.size() == 1 : "No network offering found for offering id " + offering.getId(); + return offerings.get(0); + } +} diff --git a/server/src/main/java/com/cloud/api/query/dao/ServiceOfferingJoinDao.java b/server/src/main/java/com/cloud/api/query/dao/ServiceOfferingJoinDao.java index a797125a18d..94cc943a812 100644 --- a/server/src/main/java/com/cloud/api/query/dao/ServiceOfferingJoinDao.java +++ b/server/src/main/java/com/cloud/api/query/dao/ServiceOfferingJoinDao.java @@ -16,6 +16,8 @@ // under the License. package com.cloud.api.query.dao; +import java.util.List; + import org.apache.cloudstack.api.response.ServiceOfferingResponse; import com.cloud.api.query.vo.ServiceOfferingJoinVO; @@ -24,6 +26,8 @@ import com.cloud.utils.db.GenericDao; public interface ServiceOfferingJoinDao extends GenericDao { + List findByDomainId(long domainId); + ServiceOfferingResponse newServiceOfferingResponse(ServiceOfferingJoinVO offering); ServiceOfferingJoinVO newServiceOfferingView(ServiceOffering offering); diff --git a/server/src/main/java/com/cloud/api/query/dao/ServiceOfferingJoinDaoImpl.java b/server/src/main/java/com/cloud/api/query/dao/ServiceOfferingJoinDaoImpl.java index f30bfad5cf0..13980441471 100644 --- a/server/src/main/java/com/cloud/api/query/dao/ServiceOfferingJoinDaoImpl.java +++ b/server/src/main/java/com/cloud/api/query/dao/ServiceOfferingJoinDaoImpl.java @@ -18,12 +18,10 @@ package com.cloud.api.query.dao; import java.util.List; - +import org.apache.cloudstack.api.response.ServiceOfferingResponse; import org.apache.log4j.Logger; import org.springframework.stereotype.Component; -import org.apache.cloudstack.api.response.ServiceOfferingResponse; - import com.cloud.api.ApiDBUtils; import com.cloud.api.query.vo.ServiceOfferingJoinVO; import com.cloud.offering.ServiceOffering; @@ -47,6 +45,17 @@ public class ServiceOfferingJoinDaoImpl extends GenericDaoBase findByDomainId(long domainId) { + SearchBuilder sb = createSearchBuilder(); + sb.and("domainId", sb.entity().getDomainId(), SearchCriteria.Op.FIND_IN_SET); + sb.done(); + + SearchCriteria sc = sb.create(); + sc.setParameters("domainId", String.valueOf(domainId)); + return listBy(sc); + } + @Override public ServiceOfferingResponse newServiceOfferingResponse(ServiceOfferingJoinVO offering) { @@ -69,6 +78,8 @@ public class ServiceOfferingJoinDaoImpl extends GenericDaoBase { + + List findByDomainId(long domainId); + + VpcOfferingResponse newVpcOfferingResponse(VpcOffering offering); + + VpcOfferingJoinVO newVpcOfferingView(VpcOffering offering); +} diff --git a/server/src/main/java/com/cloud/api/query/dao/VpcOfferingJoinDaoImpl.java b/server/src/main/java/com/cloud/api/query/dao/VpcOfferingJoinDaoImpl.java new file mode 100644 index 00000000000..cc427b52333 --- /dev/null +++ b/server/src/main/java/com/cloud/api/query/dao/VpcOfferingJoinDaoImpl.java @@ -0,0 +1,87 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +package com.cloud.api.query.dao; + +import java.util.List; + +import org.apache.cloudstack.api.response.VpcOfferingResponse; +import org.apache.log4j.Logger; + +import com.cloud.api.query.vo.VpcOfferingJoinVO; +import com.cloud.network.vpc.VpcOffering; +import com.cloud.utils.db.GenericDaoBase; +import com.cloud.utils.db.SearchBuilder; +import com.cloud.utils.db.SearchCriteria; + +public class VpcOfferingJoinDaoImpl extends GenericDaoBase implements VpcOfferingJoinDao { + public static final Logger s_logger = Logger.getLogger(VpcOfferingJoinDaoImpl.class); + + private SearchBuilder sofIdSearch; + + protected VpcOfferingJoinDaoImpl() { + + sofIdSearch = createSearchBuilder(); + sofIdSearch.and("id", sofIdSearch.entity().getId(), SearchCriteria.Op.EQ); + sofIdSearch.done(); + + this._count = "select count(distinct service_offering_view.id) from service_offering_view WHERE "; + } + + @Override + public List findByDomainId(long domainId) { + SearchBuilder sb = createSearchBuilder(); + sb.and("domainId", sb.entity().getDomainId(), SearchCriteria.Op.FIND_IN_SET); + sb.done(); + + SearchCriteria sc = sb.create(); + sc.setParameters("domainId", String.valueOf(domainId)); + return listBy(sc); + } + + @Override + public VpcOfferingResponse newVpcOfferingResponse(VpcOffering offering) { + VpcOfferingResponse offeringResponse = new VpcOfferingResponse(); + offeringResponse.setId(offering.getUuid()); + offeringResponse.setName(offering.getName()); + offeringResponse.setDisplayText(offering.getDisplayText()); + offeringResponse.setIsDefault(offering.isDefault()); + offeringResponse.setState(offering.getState().name()); + offeringResponse.setSupportsDistributedRouter(offering.isSupportsDistributedRouter()); + offeringResponse.setSupportsRegionLevelVpc(offering.isOffersRegionLevelVPC()); + offeringResponse.setCreated(offering.getCreated()); + if (offering instanceof VpcOfferingJoinVO) { + VpcOfferingJoinVO offeringJoinVO = (VpcOfferingJoinVO) offering; + offeringResponse.setDomainId(offeringJoinVO.getDomainUuid()); + offeringResponse.setDomain(offeringJoinVO.getDomainPath()); + offeringResponse.setZoneId(offeringJoinVO.getZoneUuid()); + offeringResponse.setZone(offeringJoinVO.getZoneName()); + } + offeringResponse.setObjectName("vpcoffering"); + + return offeringResponse; + } + + @Override + public VpcOfferingJoinVO newVpcOfferingView(VpcOffering offering) { + SearchCriteria sc = sofIdSearch.create(); + sc.setParameters("id", offering.getId()); + List offerings = searchIncludingRemoved(sc, null, null, false); + assert offerings != null && offerings.size() == 1 : "No VPC offering found for offering id " + offering.getId(); + return offerings.get(0); + } +} \ No newline at end of file diff --git a/server/src/main/java/com/cloud/api/query/vo/DiskOfferingJoinVO.java b/server/src/main/java/com/cloud/api/query/vo/DiskOfferingJoinVO.java index 7651b1989cd..50559c7fd93 100644 --- a/server/src/main/java/com/cloud/api/query/vo/DiskOfferingJoinVO.java +++ b/server/src/main/java/com/cloud/api/query/vo/DiskOfferingJoinVO.java @@ -20,14 +20,17 @@ import java.util.Date; import javax.persistence.Column; import javax.persistence.Entity; +import javax.persistence.EnumType; +import javax.persistence.Enumerated; import javax.persistence.Id; import javax.persistence.Table; -import com.cloud.storage.Storage; import org.apache.cloudstack.api.Identity; import org.apache.cloudstack.api.InternalIdentity; +import com.cloud.offering.DiskOffering; import com.cloud.offering.DiskOffering.Type; +import com.cloud.storage.Storage; import com.cloud.utils.db.GenericDao; @Entity @@ -129,10 +132,10 @@ public class DiskOfferingJoinVO extends BaseViewVO implements InternalIdentity, private Date removed; @Column(name = "domain_id") - private long domainId; + private String domainId = null; @Column(name = "domain_uuid") - private String domainUuid; + private String domainUuid = null; @Column(name = "domain_name") private String domainName = null; @@ -140,9 +143,22 @@ public class DiskOfferingJoinVO extends BaseViewVO implements InternalIdentity, @Column(name = "domain_path") private String domainPath = null; + @Column(name = "zone_id") + private String zoneId = null; + + @Column(name = "zone_uuid") + private String zoneUuid = null; + + @Column(name = "zone_name") + private String zoneName = null; + @Column(name = "display_offering") boolean displayOffering; + @Enumerated(EnumType.STRING) + @Column(name = "state") + DiskOffering.State state; + public DiskOfferingJoinVO() { } @@ -224,22 +240,6 @@ public class DiskOfferingJoinVO extends BaseViewVO implements InternalIdentity, return removed; } - public long getDomainId() { - return domainId; - } - - public String getDomainUuid() { - return domainUuid; - } - - public String getDomainName() { - return domainName; - } - - public String getDomainPath() { - return domainPath; - } - public int getSortKey() { return sortKey; } @@ -279,4 +279,68 @@ public class DiskOfferingJoinVO extends BaseViewVO implements InternalIdentity, public Long getIopsWriteRateMax() { return iopsWriteRateMax; } public Long getIopsWriteRateMaxLength() { return iopsWriteRateMaxLength; } + + public String getDomainId() { + return domainId; + } + + public void setDomainId(String domainId) { + this.domainId = domainId; + } + + public String getDomainUuid() { + return domainUuid; + } + + public void setDomainUuid(String domainUuid) { + this.domainUuid = domainUuid; + } + + public String getDomainName() { + return domainName; + } + + public void setDomainName(String domainName) { + this.domainName = domainName; + } + + public String getDomainPath() { + return domainPath; + } + + public void setDomainPath(String domainPath) { + this.domainPath = domainPath; + } + + public String getZoneId() { + return zoneId; + } + + public void setZoneId(String zoneId) { + this.zoneId = zoneId; + } + + public String getZoneUuid() { + return zoneUuid; + } + + public void setZoneUuid(String zoneUuid) { + this.zoneUuid = zoneUuid; + } + + public String getZoneName() { + return zoneName; + } + + public void setZoneName(String zoneName) { + this.zoneName = zoneName; + } + + public DiskOffering.State getState() { + return state; + } + + public void setState(DiskOffering.State state) { + this.state = state; + } } diff --git a/server/src/main/java/com/cloud/api/query/vo/NetworkOfferingJoinVO.java b/server/src/main/java/com/cloud/api/query/vo/NetworkOfferingJoinVO.java new file mode 100644 index 00000000000..ae416dde955 --- /dev/null +++ b/server/src/main/java/com/cloud/api/query/vo/NetworkOfferingJoinVO.java @@ -0,0 +1,398 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +package com.cloud.api.query.vo; + +import java.util.Date; + +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.EnumType; +import javax.persistence.Enumerated; +import javax.persistence.Id; +import javax.persistence.Table; + +import com.cloud.network.Network; +import com.cloud.network.Networks; +import com.cloud.offering.NetworkOffering; +import com.cloud.utils.db.GenericDao; + +@Entity +@Table(name = "network_offering_view") +public class NetworkOfferingJoinVO extends BaseViewVO implements NetworkOffering { + + @Id + @Column(name = "id", updatable = false, nullable = false) + private long id; + + @Column(name = "uuid") + private String uuid; + + @Column(name = "name") + private String name; + + @Column(name = "unique_name") + private String uniqueName; + + @Column(name = "display_text") + private String displayText; + + @Column(name = "nw_rate") + private Integer rateMbps; + + @Column(name = "mc_rate") + private Integer multicastRateMbps; + + @Column(name = "traffic_type") + @Enumerated(value = EnumType.STRING) + private Networks.TrafficType trafficType; + + @Column(name = "tags", length = 4096) + private String tags; + + @Column(name = "system_only") + private boolean systemOnly; + + @Column(name = "specify_vlan") + private boolean specifyVlan; + + @Column(name = "service_offering_id") + private Long serviceOfferingId; + + @Column(name = "conserve_mode") + private boolean conserveMode; + + @Column(name = GenericDao.REMOVED_COLUMN) + private Date removed; + + @Column(name = GenericDao.CREATED_COLUMN) + private Date created; + + @Column(name = "default") + private boolean isDefault; + + @Column(name = "availability") + @Enumerated(value = EnumType.STRING) + NetworkOffering.Availability availability; + + @Column(name = "dedicated_lb_service") + private boolean dedicatedLB; + + @Column(name = "shared_source_nat_service") + private boolean sharedSourceNat; + + @Column(name = "sort_key") + private int sortKey; + + @Column(name = "redundant_router_service") + private boolean redundantRouter; + + @Column(name = "state") + @Enumerated(value = EnumType.STRING) + private NetworkOffering.State state = NetworkOffering.State.Disabled; + + @Column(name = "guest_type") + @Enumerated(value = EnumType.STRING) + private Network.GuestType guestType; + + @Column(name = "elastic_ip_service") + private boolean elasticIp; + + @Column(name = "eip_associate_public_ip") + private boolean eipAssociatePublicIp; + + @Column(name = "elastic_lb_service") + private boolean elasticLb; + + @Column(name = "specify_ip_ranges") + private boolean specifyIpRanges = false; + + @Column(name = "inline") + private boolean inline; + + @Column(name = "is_persistent") + private boolean persistent; + + @Column(name = "internal_lb") + private boolean internalLb; + + @Column(name = "public_lb") + private boolean publicLb; + + @Column(name = "egress_default_policy") + private boolean egressdefaultpolicy; + + @Column(name = "concurrent_connections") + private Integer concurrentConnections; + + @Column(name = "keep_alive_enabled") + private boolean keepAliveEnabled = false; + + @Column(name = "supports_streched_l2") + private boolean supportsStrechedL2 = false; + + @Column(name = "supports_public_access") + private boolean supportsPublicAccess = false; + + @Column(name = "for_vpc") + private boolean forVpc; + + @Column(name = "service_package_id") + private String servicePackageUuid = null; + + @Column(name = "domain_id") + private String domainId = null; + + @Column(name = "domain_uuid") + private String domainUuid = null; + + @Column(name = "domain_name") + private String domainName = null; + + @Column(name = "domain_path") + private String domainPath = null; + + @Column(name = "zone_id") + private String zoneId = null; + + @Column(name = "zone_uuid") + private String zoneUuid = null; + + @Column(name = "zone_name") + private String zoneName = null; + + public NetworkOfferingJoinVO() { + } + + @Override + public long getId() { + return id; + } + + @Override + public String getUuid() { + return uuid; + } + + public String getName() { + return name; + } + + public String getUniqueName() { + return uniqueName; + } + + public String getDisplayText() { + return displayText; + } + + public Integer getRateMbps() { + return rateMbps; + } + + public Integer getMulticastRateMbps() { + return multicastRateMbps; + } + + public Networks.TrafficType getTrafficType() { + return trafficType; + } + + public String getTags() { + return tags; + } + + public boolean isSystemOnly() { + return systemOnly; + } + + public boolean isSpecifyVlan() { + return specifyVlan; + } + + public Long getServiceOfferingId() { + return serviceOfferingId; + } + + public boolean isConserveMode() { + return conserveMode; + } + + public Date getCreated() { + return created; + } + + public Date getRemoved() { + return removed; + } + + public boolean isDefault() { + return isDefault; + } + + public NetworkOffering.Availability getAvailability() { + return availability; + } + + public boolean isDedicatedLB() { + return dedicatedLB; + } + + public boolean isSharedSourceNat() { + return sharedSourceNat; + } + + public int getSortKey() { + return sortKey; + } + + public boolean isRedundantRouter() { + return redundantRouter; + } + + public NetworkOffering.State getState() { + return state; + } + + @Override + public void setState(State state) { + this.state = state; + } + + public Network.GuestType getGuestType() { + return guestType; + } + + public boolean isElasticIp() { + return elasticIp; + } + + public boolean isAssociatePublicIP() { + return eipAssociatePublicIp; + } + + public boolean isElasticLb() { + return elasticLb; + } + + public boolean isSpecifyIpRanges() { + return specifyIpRanges; + } + + public boolean isInline() { + return inline; + } + + public boolean isPersistent() { + return persistent; + } + + public boolean isInternalLb() { + return internalLb; + } + + public boolean isPublicLb() { + return publicLb; + } + + public boolean isEgressDefaultPolicy() { + return egressdefaultpolicy; + } + + public Integer getConcurrentConnections() { + return this.concurrentConnections; + } + + public boolean isKeepAliveEnabled() { + return keepAliveEnabled; + } + + public boolean isSupportingStrechedL2() { + return supportsStrechedL2; + } + + public boolean isSupportingPublicAccess() { + return supportsPublicAccess; + } + + public boolean isForVpc() { + return forVpc; + } + + public void setForVpc(boolean forVpc) { this.forVpc = forVpc; } + + public String getServicePackage() { + return servicePackageUuid; + } + + public String getDomainId() { + return domainId; + } + + public void setDomainId(String domainId) { + this.domainId = domainId; + } + + public String getDomainUuid() { + return domainUuid; + } + + public void setDomainUuid(String domainUuid) { + this.domainUuid = domainUuid; + } + + public String getDomainName() { + return domainName; + } + + public void setDomainName(String domainName) { + this.domainName = domainName; + } + + public String getDomainPath() { + return domainPath; + } + + public void setDomainPath(String domainPath) { + this.domainPath = domainPath; + } + + public String getZoneId() { + return zoneId; + } + + public void setZoneId(String zoneId) { + this.zoneId = zoneId; + } + + public String getZoneUuid() { + return zoneUuid; + } + + public void setZoneUuid(String zoneUuid) { + this.zoneUuid = zoneUuid; + } + + public String getZoneName() { + return zoneName; + } + + public void setZoneName(String zoneName) { + this.zoneName = zoneName; + } + +} diff --git a/server/src/main/java/com/cloud/api/query/vo/ServiceOfferingJoinVO.java b/server/src/main/java/com/cloud/api/query/vo/ServiceOfferingJoinVO.java index 9ea2d9af5bc..fa16308029e 100644 --- a/server/src/main/java/com/cloud/api/query/vo/ServiceOfferingJoinVO.java +++ b/server/src/main/java/com/cloud/api/query/vo/ServiceOfferingJoinVO.java @@ -23,11 +23,10 @@ import javax.persistence.Entity; import javax.persistence.Id; import javax.persistence.Table; -import com.cloud.storage.Storage; - import org.apache.cloudstack.api.Identity; import org.apache.cloudstack.api.InternalIdentity; +import com.cloud.storage.Storage; import com.cloud.utils.db.GenericDao; @Entity @@ -150,7 +149,7 @@ public class ServiceOfferingJoinVO extends BaseViewVO implements InternalIdentit private Date removed; @Column(name = "domain_id") - private long domainId; + private String domainId; @Column(name = "domain_uuid") private String domainUuid; @@ -161,6 +160,15 @@ public class ServiceOfferingJoinVO extends BaseViewVO implements InternalIdentit @Column(name = "domain_path") private String domainPath = null; + @Column(name = "zone_id") + private String zoneId = null; + + @Column(name = "zone_uuid") + private String zoneUuid = null; + + @Column(name = "zone_name") + private String zoneName = null; + @Column(name = "deployment_planner") private String deploymentPlanner; @@ -209,7 +217,7 @@ public class ServiceOfferingJoinVO extends BaseViewVO implements InternalIdentit return removed; } - public long getDomainId() { + public String getDomainId() { return domainId; } @@ -225,6 +233,18 @@ public class ServiceOfferingJoinVO extends BaseViewVO implements InternalIdentit return domainPath; } + public String getZoneId() { + return zoneId; + } + + public String getZoneUuid() { + return zoneUuid; + } + + public String getZoneName() { + return zoneName; + } + public Boolean isCustomizedIops() { return customizedIops; } diff --git a/server/src/main/java/com/cloud/api/query/vo/VpcOfferingJoinVO.java b/server/src/main/java/com/cloud/api/query/vo/VpcOfferingJoinVO.java new file mode 100644 index 00000000000..6cc5c225379 --- /dev/null +++ b/server/src/main/java/com/cloud/api/query/vo/VpcOfferingJoinVO.java @@ -0,0 +1,205 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +package com.cloud.api.query.vo; + +import java.util.Date; + +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.EnumType; +import javax.persistence.Enumerated; +import javax.persistence.Id; +import javax.persistence.Table; + +import com.cloud.network.vpc.VpcOffering; +import com.cloud.utils.db.GenericDao; + +@Entity +@Table(name = "vpc_offering_view") +public class VpcOfferingJoinVO implements VpcOffering { + + @Id + @Column(name = "id", updatable = false, nullable = false) + private long id; + + @Column(name = "uuid") + private String uuid; + + @Column(name = "name") + String name; + + @Column(name = "unique_name") + String uniqueName; + + @Column(name = "display_text") + String displayText; + + @Column(name = "state") + @Enumerated(value = EnumType.STRING) + VpcOffering.State state = VpcOffering.State.Disabled; + + @Column(name = "default") + boolean isDefault = false; + + @Column(name = GenericDao.REMOVED_COLUMN) + Date removed; + + @Column(name = GenericDao.CREATED_COLUMN) + Date created; + + @Column(name = "service_offering_id") + Long serviceOfferingId; + + @Column(name = "supports_distributed_router") + boolean supportsDistributedRouter=false; + + @Column(name = "supports_region_level_vpc") + boolean offersRegionLevelVPC = false; + + @Column(name = "redundant_router_service") + boolean redundantRouter = false; + + @Column(name = "sort_key") + int sortKey; + + @Column(name = "domain_id") + private String domainId; + + @Column(name = "domain_uuid") + private String domainUuid; + + @Column(name = "domain_name") + private String domainName = null; + + @Column(name = "domain_path") + private String domainPath = null; + + @Column(name = "zone_id") + private String zoneId = null; + + @Column(name = "zone_uuid") + private String zoneUuid = null; + + @Column(name = "zone_name") + private String zoneName = null; + + public VpcOfferingJoinVO() { + } + + @Override + public long getId() { + return id; + } + + @Override + public String getUuid() { + return uuid; + } + + @Override + public String getName() { + return name; + } + + public String getUniqueName() { + return uniqueName; + } + + @Override + public String getDisplayText() { + return displayText; + } + + @Override + public VpcOffering.State getState() { + return state; + } + + @Override + public boolean isDefault() { + return isDefault; + } + + @Override + public Date getRemoved() { + return removed; + } + + @Override + public Date getCreated() { + return created; + } + + @Override + public Long getServiceOfferingId() { + return serviceOfferingId; + } + + @Override + public boolean isSupportsDistributedRouter() { + return supportsDistributedRouter; + } + + @Override + public boolean isOffersRegionLevelVPC() { + return offersRegionLevelVPC; + } + + @Override + public boolean isRedundantRouter() { + return redundantRouter; + } + + public int getSortKey() { + return sortKey; + } + + public String getDomainId() { + return domainId; + } + + public String getDomainUuid() { + return domainUuid; + } + + public String getDomainName() { + return domainName; + } + + public String getDomainPath() { + return domainPath; + } + + public String getZoneId() { + return zoneId; + } + + public String getZoneUuid() { + return zoneUuid; + } + + public String getZoneName() { + return zoneName; + } + + @Override + public String toString() { + StringBuilder buf = new StringBuilder("[VPC Offering ["); + return buf.append(id).append("-").append(name).append("]").toString(); + } +} diff --git a/server/src/main/java/com/cloud/configuration/ConfigurationManagerImpl.java b/server/src/main/java/com/cloud/configuration/ConfigurationManagerImpl.java index 083d52bd57f..bf238b0a725 100755 --- a/server/src/main/java/com/cloud/configuration/ConfigurationManagerImpl.java +++ b/server/src/main/java/com/cloud/configuration/ConfigurationManagerImpl.java @@ -25,10 +25,12 @@ import java.sql.PreparedStatement; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; +import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.List; +import java.util.ListIterator; import java.util.Map; import java.util.Map.Entry; import java.util.Set; @@ -88,6 +90,8 @@ import org.apache.cloudstack.region.PortableIpVO; import org.apache.cloudstack.region.Region; import org.apache.cloudstack.region.RegionVO; import org.apache.cloudstack.region.dao.RegionDao; +import org.apache.cloudstack.resourcedetail.DiskOfferingDetailVO; +import org.apache.cloudstack.resourcedetail.dao.DiskOfferingDetailsDao; import org.apache.cloudstack.storage.datastore.db.ImageStoreDao; import org.apache.cloudstack.storage.datastore.db.ImageStoreDetailsDao; import org.apache.cloudstack.storage.datastore.db.ImageStoreVO; @@ -100,6 +104,8 @@ import org.apache.log4j.Logger; import com.cloud.alert.AlertManager; import com.cloud.api.ApiDBUtils; +import com.cloud.api.query.dao.NetworkOfferingJoinDao; +import com.cloud.api.query.vo.NetworkOfferingJoinVO; import com.cloud.capacity.CapacityManager; import com.cloud.capacity.dao.CapacityDao; import com.cloud.configuration.Resource.ResourceType; @@ -177,9 +183,11 @@ import com.cloud.offering.NetworkOffering; import com.cloud.offering.NetworkOffering.Availability; import com.cloud.offering.NetworkOffering.Detail; import com.cloud.offering.ServiceOffering; +import com.cloud.offerings.NetworkOfferingDetailsVO; import com.cloud.offerings.NetworkOfferingServiceMapVO; import com.cloud.offerings.NetworkOfferingVO; import com.cloud.offerings.dao.NetworkOfferingDao; +import com.cloud.offerings.dao.NetworkOfferingDetailsDao; import com.cloud.offerings.dao.NetworkOfferingServiceMapDao; import com.cloud.org.Grouping; import com.cloud.org.Grouping.AllocationState; @@ -215,6 +223,7 @@ import com.cloud.utils.db.DB; import com.cloud.utils.db.EntityManager; import com.cloud.utils.db.Filter; import com.cloud.utils.db.GlobalLock; +import com.cloud.utils.db.SearchBuilder; import com.cloud.utils.db.SearchCriteria; import com.cloud.utils.db.Transaction; import com.cloud.utils.db.TransactionCallback; @@ -269,8 +278,14 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati @Inject DiskOfferingDao _diskOfferingDao; @Inject + DiskOfferingDetailsDao diskOfferingDetailsDao; + @Inject NetworkOfferingDao _networkOfferingDao; @Inject + NetworkOfferingJoinDao networkOfferingJoinDao; + @Inject + NetworkOfferingDetailsDao networkOfferingDetailsDao; + @Inject VlanDao _vlanDao; @Inject IPAddressDao _publicIpAddressDao; @@ -529,7 +544,7 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati } if(name.equals(CapacityManager.StorageOverprovisioningFactor.key())) { if(!pool.getPoolType().supportsOverProvisioning() ) { - throw new InvalidParameterValueException("Unable to update storage pool with id " + resourceId + ". Overprovision not supported for " + pool.getPoolType()); + throw new InvalidParameterValueException("Unable to update storage pool with id " + resourceId + ". Overprovision not supported for " + pool.getPoolType()); } } @@ -2291,8 +2306,20 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati } // check if valid domain - if (cmd.getDomainId() != null && _domainDao.findById(cmd.getDomainId()) == null) { - throw new InvalidParameterValueException("Please specify a valid domain id"); + if (CollectionUtils.isNotEmpty(cmd.getDomainIds())) { + for (final Long domainId: cmd.getDomainIds()) { + if (_domainDao.findById(domainId) == null) { + throw new InvalidParameterValueException("Please specify a valid domain id"); + } + } + } + + // check if valid zone + if (CollectionUtils.isNotEmpty(cmd.getZoneIds())) { + for (Long zoneId : cmd.getZoneIds()) { + if (_zoneDao.findById(zoneId) == null) + throw new InvalidParameterValueException("Please specify a valid zone id"); + } } final Boolean offerHA = cmd.isOfferHa(); @@ -2369,7 +2396,7 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati } return createServiceOffering(userId, cmd.isSystem(), vmType, cmd.getServiceOfferingName(), cpuNumber, memory, cpuSpeed, cmd.getDisplayText(), - cmd.getProvisioningType(), localStorageRequired, offerHA, limitCpuUse, volatileVm, cmd.getTags(), cmd.getDomainId(), cmd.getHostTag(), + cmd.getProvisioningType(), localStorageRequired, offerHA, limitCpuUse, volatileVm, cmd.getTags(), cmd.getDomainIds(), cmd.getZoneIds(), cmd.getHostTag(), cmd.getNetworkRate(), cmd.getDeploymentPlanner(), details, isCustomizedIops, cmd.getMinIops(), cmd.getMaxIops(), cmd.getBytesReadRate(), cmd.getBytesReadRateMax(), cmd.getBytesReadRateMaxLength(), cmd.getBytesWriteRate(), cmd.getBytesWriteRateMax(), cmd.getBytesWriteRateMaxLength(), @@ -2380,13 +2407,15 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati protected ServiceOfferingVO createServiceOffering(final long userId, final boolean isSystem, final VirtualMachine.Type vmType, final String name, final Integer cpu, final Integer ramSize, final Integer speed, final String displayText, final String provisioningType, final boolean localStorageRequired, - final boolean offerHA, final boolean limitResourceUse, final boolean volatileVm, String tags, final Long domainId, final String hostTag, + final boolean offerHA, final boolean limitResourceUse, final boolean volatileVm, String tags, final List domainIds, List zoneIds, final String hostTag, final Integer networkRate, final String deploymentPlanner, final Map details, final Boolean isCustomizedIops, Long minIops, Long maxIops, Long bytesReadRate, Long bytesReadRateMax, Long bytesReadRateMaxLength, Long bytesWriteRate, Long bytesWriteRateMax, Long bytesWriteRateMaxLength, Long iopsReadRate, Long iopsReadRateMax, Long iopsReadRateMaxLength, Long iopsWriteRate, Long iopsWriteRateMax, Long iopsWriteRateMaxLength, final Integer hypervisorSnapshotReserve) { + // Filter child domains when both parent and child domains are present + List filteredDomainIds = filterChildSubDomains(domainIds); // Check if user exists in the system final User user = _userDao.findById(userId); @@ -2395,17 +2424,19 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati } final Account account = _accountDao.findById(user.getAccountId()); if (account.getType() == Account.ACCOUNT_TYPE_DOMAIN_ADMIN) { - if (domainId == null) { - throw new InvalidParameterValueException("Unable to create public service offering by id " + userId + " because it is domain-admin"); + if (filteredDomainIds.isEmpty()) { + throw new InvalidParameterValueException(String.format("Unable to create public service offering by admin: %s because it is domain-admin", user.getUuid())); } if (tags != null || hostTag != null) { - throw new InvalidParameterValueException("Unable to create service offering with storage tags or host tags by id " + userId + " because it is domain-admin"); + throw new InvalidParameterValueException(String.format("Unable to create service offering with storage tags or host tags by admin: %s because it is domain-admin", user.getUuid())); } - if (! _domainDao.isChildDomain(account.getDomainId(), domainId)) { - throw new InvalidParameterValueException("Unable to create service offering by another domain admin with id " + userId); + for (Long domainId : filteredDomainIds) { + if (!_domainDao.isChildDomain(account.getDomainId(), domainId)) { + throw new InvalidParameterValueException(String.format("Unable to create service offering by another domain-admin: %s for domain: %s", user.getUuid(), _entityMgr.findById(Domain.class, domainId).getUuid())); + } } } else if (account.getType() != Account.ACCOUNT_TYPE_ADMIN) { - throw new InvalidParameterValueException("Unable to create service offering by id " + userId + " because it is not root-admin or domain-admin"); + throw new InvalidParameterValueException(String.format("Unable to create service offering by user: %s because it is not root-admin or domain-admin", user.getUuid())); } final ProvisioningType typedProvisioningType = ProvisioningType.getProvisioningType(provisioningType); @@ -2414,7 +2445,7 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati ServiceOfferingVO offering = new ServiceOfferingVO(name, cpu, ramSize, speed, networkRate, null, offerHA, limitResourceUse, volatileVm, displayText, typedProvisioningType, localStorageRequired, false, tags, isSystem, vmType, - domainId, hostTag, deploymentPlanner); + hostTag, deploymentPlanner); if (Boolean.TRUE.equals(isCustomizedIops) || isCustomizedIops == null) { minIops = null; @@ -2486,7 +2517,7 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati offering.setHypervisorSnapshotReserve(hypervisorSnapshotReserve); - List detailsVO = null; + List detailsVO = new ArrayList(); if (details != null) { // To have correct input, either both gpu card name and VGPU type should be passed or nothing should be passed. // Use XOR condition to verify that. @@ -2495,7 +2526,6 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati if ((entry1 || entry2) && !(entry1 && entry2)) { throw new InvalidParameterValueException("Please specify the pciDevice and vgpuType correctly."); } - detailsVO = new ArrayList(); for (final Entry detailEntry : details.entrySet()) { String detailEntryValue = detailEntry.getValue(); if (detailEntry.getKey().equals(GPU.Keys.pciDevice.toString())) { @@ -2521,9 +2551,17 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati } if ((offering = _serviceOfferingDao.persist(offering)) != null) { - if (detailsVO != null && !detailsVO.isEmpty()) { - for (int index = 0; index < detailsVO.size(); index++) { - detailsVO.get(index).setResourceId(offering.getId()); + for (Long domainId : filteredDomainIds) { + detailsVO.add(new ServiceOfferingDetailsVO(offering.getId(), ApiConstants.DOMAIN_ID, String.valueOf(domainId), false)); + } + if (CollectionUtils.isNotEmpty(zoneIds)) { + for (Long zoneId : zoneIds) { + detailsVO.add(new ServiceOfferingDetailsVO(offering.getId(), ApiConstants.ZONE_ID, String.valueOf(zoneId), false)); + } + } + if (!detailsVO.isEmpty()) { + for (ServiceOfferingDetailsVO detail : detailsVO) { + detail.setResourceId(offering.getId()); } _serviceOfferingDetailsDao.saveDetails(detailsVO); } @@ -2542,6 +2580,8 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati final String name = cmd.getServiceOfferingName(); final Integer sortKey = cmd.getSortKey(); Long userId = CallContext.current().getCallingUserId(); + final List domainIds = cmd.getDomainIds(); + final List zoneIds = cmd.getZoneIds(); if (userId == null) { userId = Long.valueOf(User.UID_SYSTEM); @@ -2549,29 +2589,83 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati // Verify input parameters final ServiceOffering offeringHandle = _entityMgr.findById(ServiceOffering.class, id); - if (offeringHandle == null) { throw new InvalidParameterValueException("unable to find service offering " + id); } + List existingDomainIds = _serviceOfferingDetailsDao.findDomainIds(id); + Collections.sort(existingDomainIds); + + List existingZoneIds = _serviceOfferingDetailsDao.findZoneIds(id); + Collections.sort(existingZoneIds); + + // check if valid domain + if (CollectionUtils.isNotEmpty(domainIds)) { + for (final Long domainId: domainIds) { + if (_domainDao.findById(domainId) == null) { + throw new InvalidParameterValueException("Please specify a valid domain id"); + } + } + } + + // check if valid zone + if (CollectionUtils.isNotEmpty(zoneIds)) { + for (Long zoneId : zoneIds) { + if (_zoneDao.findById(zoneId) == null) + throw new InvalidParameterValueException("Please specify a valid zone id"); + } + } + final User user = _userDao.findById(userId); if (user == null || user.getRemoved() != null) { throw new InvalidParameterValueException("Unable to find active user by id " + userId); } final Account account = _accountDao.findById(user.getAccountId()); + + // Filter child domains when both parent and child domains are present + List filteredDomainIds = filterChildSubDomains(domainIds); + Collections.sort(filteredDomainIds); + + List filteredZoneIds = new ArrayList<>(); + if (CollectionUtils.isNotEmpty(zoneIds)) { + filteredZoneIds.addAll(zoneIds); + } + Collections.sort(filteredZoneIds); + if (account.getType() == Account.ACCOUNT_TYPE_DOMAIN_ADMIN) { - if (offeringHandle.getDomainId() == null) { - throw new InvalidParameterValueException("Unable to update public service offering by id " + userId + " because it is domain-admin"); + if (!filteredZoneIds.equals(existingZoneIds)) { // Domain-admins cannot update zone(s) for offerings + throw new InvalidParameterValueException(String.format("Unable to update zone(s) for service offering: %s by admin: %s as it is domain-admin", offeringHandle.getUuid(), user.getUuid())); } - if (! _domainDao.isChildDomain(account.getDomainId(), offeringHandle.getDomainId() )) { - throw new InvalidParameterValueException("Unable to update service offering by another domain admin with id " + userId); + if (existingDomainIds.isEmpty()) { + throw new InvalidParameterValueException(String.format("Unable to update public service offering: %s by user: %s because it is domain-admin", offeringHandle.getUuid(), user.getUuid())); + } else { + if (filteredDomainIds.isEmpty()) { + throw new InvalidParameterValueException(String.format("Unable to update service offering: %s to a public offering by user: %s because it is domain-admin", offeringHandle.getUuid(), user.getUuid())); + } } + List nonChildDomains = new ArrayList<>(); + for (Long domainId : existingDomainIds) { + if (!_domainDao.isChildDomain(account.getDomainId(), domainId)) { + if (name != null || displayText != null || sortKey != null) { // Domain-admins cannot update name, display text, sort key for offerings with domain which are not child domains for domain-admin + throw new InvalidParameterValueException(String.format("Unable to update service offering: %s as it has linked domain(s) which are not child domain for domain-admin: %s", offeringHandle.getUuid(), user.getUuid())); + } + nonChildDomains.add(domainId); + } + } + for (Long domainId : filteredDomainIds) { + if (!_domainDao.isChildDomain(account.getDomainId(), domainId)) { + Domain domain = _entityMgr.findById(Domain.class, domainId); + throw new InvalidParameterValueException(String.format("Unable to update service offering: %s by domain-admin: %s with domain: %3$s which is not a child domain", offeringHandle.getUuid(), user.getUuid(), domain.getUuid())); + } + } + filteredDomainIds.addAll(nonChildDomains); // Final list must include domains which were not child domain for domain-admin but specified for this offering prior to update } else if (account.getType() != Account.ACCOUNT_TYPE_ADMIN) { - throw new InvalidParameterValueException("Unable to update service offering by id " + userId + " because it is not root-admin or domain-admin"); + throw new InvalidParameterValueException(String.format("Unable to update service offering: %s by id user: %s because it is not root-admin or domain-admin", offeringHandle.getUuid(), user.getUuid())); } final boolean updateNeeded = name != null || displayText != null || sortKey != null; - if (!updateNeeded) { + final boolean detailsUpdateNeeded = !filteredDomainIds.equals(existingDomainIds) || !filteredZoneIds.equals(existingZoneIds); + if (!updateNeeded && !detailsUpdateNeeded) { return _serviceOfferingDao.findById(id); } @@ -2613,23 +2707,68 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati // } // } - if (_serviceOfferingDao.update(id, offering)) { - offering = _serviceOfferingDao.findById(id); - CallContext.current().setEventDetails("Service offering id=" + offering.getId()); - return offering; - } else { + if (updateNeeded && !_serviceOfferingDao.update(id, offering)) { return null; } + List detailsVO = new ArrayList<>(); + if(detailsUpdateNeeded) { + SearchBuilder sb = _serviceOfferingDetailsDao.createSearchBuilder(); + sb.and("offeringId", sb.entity().getResourceId(), SearchCriteria.Op.EQ); + sb.and("detailName", sb.entity().getName(), SearchCriteria.Op.EQ); + sb.done(); + SearchCriteria sc = sb.create(); + sc.setParameters("offeringId", String.valueOf(id)); + if(!filteredDomainIds.equals(existingDomainIds)) { + sc.setParameters("detailName", ApiConstants.DOMAIN_ID); + _serviceOfferingDetailsDao.remove(sc); + for (Long domainId : filteredDomainIds) { + detailsVO.add(new ServiceOfferingDetailsVO(id, ApiConstants.DOMAIN_ID, String.valueOf(domainId), false)); + } + } + if(!filteredZoneIds.equals(existingZoneIds)) { + sc.setParameters("detailName", ApiConstants.ZONE_ID); + _serviceOfferingDetailsDao.remove(sc); + for (Long zoneId : filteredZoneIds) { + detailsVO.add(new ServiceOfferingDetailsVO(id, ApiConstants.ZONE_ID, String.valueOf(zoneId), false)); + } + } + } + if (!detailsVO.isEmpty()) { + for (ServiceOfferingDetailsVO detailVO : detailsVO) { + _serviceOfferingDetailsDao.persist(detailVO); + } + } + offering = _serviceOfferingDao.findById(id); + CallContext.current().setEventDetails("Service offering id=" + offering.getId()); + return offering; } - protected DiskOfferingVO createDiskOffering(final Long userId, final Long domainId, final String name, final String description, final String provisioningType, - final Long numGibibytes, String tags, boolean isCustomized, final boolean localStorageRequired, - final boolean isDisplayOfferingEnabled, final Boolean isCustomizedIops, Long minIops, Long maxIops, - Long bytesReadRate, Long bytesReadRateMax, Long bytesReadRateMaxLength, - Long bytesWriteRate, Long bytesWriteRateMax, Long bytesWriteRateMaxLength, - Long iopsReadRate, Long iopsReadRateMax, Long iopsReadRateMaxLength, - Long iopsWriteRate, Long iopsWriteRateMax, Long iopsWriteRateMaxLength, - final Integer hypervisorSnapshotReserve) { + @Override + public List getServiceOfferingDomains(Long serviceOfferingId) { + final ServiceOffering offeringHandle = _entityMgr.findById(ServiceOffering.class, serviceOfferingId); + if (offeringHandle == null) { + throw new InvalidParameterValueException("Unable to find service offering " + serviceOfferingId); + } + return _serviceOfferingDetailsDao.findDomainIds(serviceOfferingId); + } + + @Override + public List getServiceOfferingZones(Long serviceOfferingId) { + final ServiceOffering offeringHandle = _entityMgr.findById(ServiceOffering.class, serviceOfferingId); + if (offeringHandle == null) { + throw new InvalidParameterValueException("Unable to find service offering " + serviceOfferingId); + } + return _serviceOfferingDetailsDao.findZoneIds(serviceOfferingId); + } + + protected DiskOfferingVO createDiskOffering(final Long userId, final List domainIds, final List zoneIds, final String name, final String description, final String provisioningType, + final Long numGibibytes, String tags, boolean isCustomized, final boolean localStorageRequired, + final boolean isDisplayOfferingEnabled, final Boolean isCustomizedIops, Long minIops, Long maxIops, + Long bytesReadRate, Long bytesReadRateMax, Long bytesReadRateMaxLength, + Long bytesWriteRate, Long bytesWriteRateMax, Long bytesWriteRateMaxLength, + Long iopsReadRate, Long iopsReadRateMax, Long iopsReadRateMaxLength, + Long iopsWriteRate, Long iopsWriteRateMax, Long iopsWriteRateMaxLength, + final Integer hypervisorSnapshotReserve) { long diskSize = 0;// special case for custom disk offerings if (numGibibytes != null && numGibibytes <= 0) { throw new InvalidParameterValueException("Please specify a disk size of at least 1 Gb."); @@ -2668,6 +2807,8 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati } } + // Filter child domains when both parent and child domains are present + List filteredDomainIds = filterChildSubDomains(domainIds); // Check if user exists in the system final User user = _userDao.findById(userId); @@ -2676,21 +2817,23 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati } final Account account = _accountDao.findById(user.getAccountId()); if (account.getType() == Account.ACCOUNT_TYPE_DOMAIN_ADMIN) { - if (domainId == null) { - throw new InvalidParameterValueException("Unable to create public disk offering by id " + userId + " because it is domain-admin"); + if (filteredDomainIds.isEmpty()) { + throw new InvalidParameterValueException(String.format("Unable to create public disk offering by admin: %s because it is domain-admin", user.getUuid())); } if (tags != null) { - throw new InvalidParameterValueException("Unable to create disk offering with storage tags by id " + userId + " because it is domain-admin"); + throw new InvalidParameterValueException(String.format("Unable to create disk offering with storage tags by admin: %s because it is domain-admin", user.getUuid())); } - if (! _domainDao.isChildDomain(account.getDomainId(), domainId)) { - throw new InvalidParameterValueException("Unable to create disk offering by another domain admin with id " + userId); + for (Long domainId : filteredDomainIds) { + if (domainId == null || !_domainDao.isChildDomain(account.getDomainId(), domainId)) { + throw new InvalidParameterValueException(String.format("Unable to create disk offering by another domain-admin: %s for domain: %s", user.getUuid(), _entityMgr.findById(Domain.class, domainId).getUuid())); + } } } else if (account.getType() != Account.ACCOUNT_TYPE_ADMIN) { - throw new InvalidParameterValueException("Unable to create disk offering by id " + userId + " because it is not root-admin or domain-admin"); + throw new InvalidParameterValueException(String.format("Unable to create disk offering by user: %s because it is not root-admin or domain-admin", user.getUuid())); } tags = StringUtils.cleanupTags(tags); - final DiskOfferingVO newDiskOffering = new DiskOfferingVO(domainId, name, description, typedProvisioningType, diskSize, tags, isCustomized, + final DiskOfferingVO newDiskOffering = new DiskOfferingVO(name, description, typedProvisioningType, diskSize, tags, isCustomized, isCustomizedIops, minIops, maxIops); newDiskOffering.setUseLocalStorage(localStorageRequired); newDiskOffering.setDisplayOffering(isDisplayOfferingEnabled); @@ -2741,11 +2884,22 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati CallContext.current().setEventDetails("Disk offering id=" + newDiskOffering.getId()); final DiskOfferingVO offering = _diskOfferingDao.persist(newDiskOffering); if (offering != null) { + List detailsVO = new ArrayList<>(); + for (Long domainId : filteredDomainIds) { + detailsVO.add(new DiskOfferingDetailVO(offering.getId(), ApiConstants.DOMAIN_ID, String.valueOf(domainId), false)); + } + if (CollectionUtils.isNotEmpty(zoneIds)) { + for (Long zoneId : zoneIds) { + detailsVO.add(new DiskOfferingDetailVO(offering.getId(), ApiConstants.ZONE_ID, String.valueOf(zoneId), false)); + } + } + if (!detailsVO.isEmpty()) { + diskOfferingDetailsDao.saveDetails(detailsVO); + } CallContext.current().setEventDetails("Disk offering id=" + newDiskOffering.getId()); return offering; - } else { - return null; } + return null; } @Override @@ -2757,14 +2911,26 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati final Long numGibibytes = cmd.getDiskSize(); final boolean isDisplayOfferingEnabled = cmd.getDisplayOffering() != null ? cmd.getDisplayOffering() : true; final boolean isCustomized = cmd.isCustomized() != null ? cmd.isCustomized() : false; // false - // by - // default final String tags = cmd.getTags(); - // Long domainId = cmd.getDomainId() != null ? cmd.getDomainId() : - // Long.valueOf(DomainVO.ROOT_DOMAIN); // disk offering - // always gets created under the root domain.Bug # 6055 if not passed in - // cmd - final Long domainId = cmd.getDomainId(); + final List domainIds = cmd.getDomainIds(); + final List zoneIds = cmd.getZoneIds(); + + // check if valid domain + if (CollectionUtils.isNotEmpty(domainIds)) { + for (final Long domainId: domainIds) { + if (_domainDao.findById(domainId) == null) { + throw new InvalidParameterValueException("Please specify a valid domain id"); + } + } + } + + // check if valid zone + if (CollectionUtils.isNotEmpty(zoneIds)) { + for (Long zoneId : zoneIds) { + if (_zoneDao.findById(zoneId) == null) + throw new InvalidParameterValueException("Please specify a valid zone id"); + } + } if (!isCustomized && numGibibytes == null) { throw new InvalidParameterValueException("Disksize is required for a non-customized disk offering"); @@ -2802,7 +2968,7 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati final Integer hypervisorSnapshotReserve = cmd.getHypervisorSnapshotReserve(); final Long userId = CallContext.current().getCallingUserId(); - return createDiskOffering(userId, domainId, name, description, provisioningType, numGibibytes, tags, isCustomized, + return createDiskOffering(userId, domainIds, zoneIds, name, description, provisioningType, numGibibytes, tags, isCustomized, localStorageRequired, isDisplayOfferingEnabled, isCustomizedIops, minIops, maxIops, bytesReadRate, bytesReadRateMax, bytesReadRateMaxLength, bytesWriteRate, bytesWriteRateMax, bytesWriteRateMaxLength, iopsReadRate, iopsReadRateMax, iopsReadRateMaxLength, iopsWriteRate, iopsWriteRateMax, iopsWriteRateMaxLength, @@ -2817,14 +2983,38 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati final String displayText = cmd.getDisplayText(); final Integer sortKey = cmd.getSortKey(); final Boolean displayDiskOffering = cmd.getDisplayOffering(); + final List domainIds = cmd.getDomainIds(); + final List zoneIds = cmd.getZoneIds(); // Check if diskOffering exists final DiskOffering diskOfferingHandle = _entityMgr.findById(DiskOffering.class, diskOfferingId); - if (diskOfferingHandle == null) { throw new InvalidParameterValueException("Unable to find disk offering by id " + diskOfferingId); } + List existingDomainIds = diskOfferingDetailsDao.findDomainIds(diskOfferingId); + Collections.sort(existingDomainIds); + + List existingZoneIds = diskOfferingDetailsDao.findZoneIds(diskOfferingId); + Collections.sort(existingZoneIds); + + // check if valid domain + if (CollectionUtils.isNotEmpty(domainIds)) { + for (final Long domainId: domainIds) { + if (_domainDao.findById(domainId) == null) { + throw new InvalidParameterValueException("Please specify a valid domain id"); + } + } + } + + // check if valid zone + if (CollectionUtils.isNotEmpty(zoneIds)) { + for (Long zoneId : zoneIds) { + if (_zoneDao.findById(zoneId) == null) + throw new InvalidParameterValueException("Please specify a valid zone id"); + } + } + Long userId = CallContext.current().getCallingUserId(); if (userId == null) { userId = Long.valueOf(User.UID_SYSTEM); @@ -2834,19 +3024,51 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati throw new InvalidParameterValueException("Unable to find active user by id " + userId); } final Account account = _accountDao.findById(user.getAccountId()); + + // Filter child domains when both parent and child domains are present + List filteredDomainIds = filterChildSubDomains(domainIds); + Collections.sort(filteredDomainIds); + + List filteredZoneIds = new ArrayList<>(); + if (CollectionUtils.isNotEmpty(zoneIds)) { + filteredZoneIds.addAll(zoneIds); + } + Collections.sort(filteredZoneIds); + if (account.getType() == Account.ACCOUNT_TYPE_DOMAIN_ADMIN) { - if (diskOfferingHandle.getDomainId() == null) { - throw new InvalidParameterValueException("Unable to update public disk offering by id " + userId + " because it is domain-admin"); + if (!filteredZoneIds.equals(existingZoneIds)) { // Domain-admins cannot update zone(s) for offerings + throw new InvalidParameterValueException(String.format("Unable to update zone(s) for disk offering: %s by admin: %s as it is domain-admin", diskOfferingHandle.getUuid(), user.getUuid())); } - if (! _domainDao.isChildDomain(account.getDomainId(), diskOfferingHandle.getDomainId() )) { - throw new InvalidParameterValueException("Unable to update disk offering by another domain admin with id " + userId); + if (existingDomainIds.isEmpty()) { + throw new InvalidParameterValueException(String.format("Unable to update public disk offering: %s by user: %s because it is domain-admin", diskOfferingHandle.getUuid(), user.getUuid())); + } else { + if (filteredDomainIds.isEmpty()) { + throw new InvalidParameterValueException(String.format("Unable to update disk offering: %s to a public offering by user: %s because it is domain-admin", diskOfferingHandle.getUuid(), user.getUuid())); + } } + List nonChildDomains = new ArrayList<>(); + for (Long domainId : existingDomainIds) { + if (!_domainDao.isChildDomain(account.getDomainId(), domainId)) { + if (name != null || displayText != null || sortKey != null) { // Domain-admins cannot update name, display text, sort key for offerings with domain which are not child domains for domain-admin + throw new InvalidParameterValueException(String.format("Unable to update disk offering: %s as it has linked domain(s) which are not child domain for domain-admin: %s", diskOfferingHandle.getUuid(), user.getUuid())); + } + nonChildDomains.add(domainId); + } + } + for (Long domainId : filteredDomainIds) { + if (!_domainDao.isChildDomain(account.getDomainId(), domainId)) { + Domain domain = _entityMgr.findById(Domain.class, domainId); + throw new InvalidParameterValueException(String.format("Unable to update disk offering: %s by domain-admin: %s with domain: %3$s which is not a child domain", diskOfferingHandle.getUuid(), user.getUuid(), domain.getUuid())); + } + } + filteredDomainIds.addAll(nonChildDomains); // Final list must include domains which were not child domain for domain-admin but specified for this offering prior to update } else if (account.getType() != Account.ACCOUNT_TYPE_ADMIN) { - throw new InvalidParameterValueException("Unable to update disk offering by id " + userId + " because it is not root-admin or domain-admin"); + throw new InvalidParameterValueException(String.format("Unable to update disk offering: %s by id user: %s because it is not root-admin or domain-admin", diskOfferingHandle.getUuid(), user.getUuid())); } final boolean updateNeeded = name != null || displayText != null || sortKey != null || displayDiskOffering != null; - if (!updateNeeded) { + final boolean detailsUpdateNeeded = !filteredDomainIds.equals(existingDomainIds) || !filteredZoneIds.equals(existingZoneIds); + if (!updateNeeded && !detailsUpdateNeeded) { return _diskOfferingDao.findById(diskOfferingId); } @@ -2893,12 +3115,39 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati // } // } - if (_diskOfferingDao.update(diskOfferingId, diskOffering)) { - CallContext.current().setEventDetails("Disk offering id=" + diskOffering.getId()); - return _diskOfferingDao.findById(diskOfferingId); - } else { + if (updateNeeded && !_diskOfferingDao.update(diskOfferingId, diskOffering)) { return null; } + List detailsVO = new ArrayList<>(); + if(detailsUpdateNeeded) { + SearchBuilder sb = diskOfferingDetailsDao.createSearchBuilder(); + sb.and("offeringId", sb.entity().getResourceId(), SearchCriteria.Op.EQ); + sb.and("detailName", sb.entity().getName(), SearchCriteria.Op.EQ); + sb.done(); + SearchCriteria sc = sb.create(); + sc.setParameters("offeringId", String.valueOf(diskOfferingId)); + if(!filteredDomainIds.equals(existingDomainIds)) { + sc.setParameters("detailName", ApiConstants.DOMAIN_ID); + diskOfferingDetailsDao.remove(sc); + for (Long domainId : filteredDomainIds) { + detailsVO.add(new DiskOfferingDetailVO(diskOfferingId, ApiConstants.DOMAIN_ID, String.valueOf(domainId), false)); + } + } + if(!filteredZoneIds.equals(existingZoneIds)) { + sc.setParameters("detailName", ApiConstants.ZONE_ID); + diskOfferingDetailsDao.remove(sc); + for (Long zoneId : filteredZoneIds) { + detailsVO.add(new DiskOfferingDetailVO(diskOfferingId, ApiConstants.ZONE_ID, String.valueOf(zoneId), false)); + } + } + } + if (!detailsVO.isEmpty()) { + for (DiskOfferingDetailVO detailVO : detailsVO) { + diskOfferingDetailsDao.persist(detailVO); + } + } + CallContext.current().setEventDetails("Disk offering id=" + diskOffering.getId()); + return _diskOfferingDao.findById(diskOfferingId); } @Override @@ -2922,14 +3171,17 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati } final Account account = _accountDao.findById(user.getAccountId()); if (account.getType() == Account.ACCOUNT_TYPE_DOMAIN_ADMIN) { - if (offering.getDomainId() == null) { - throw new InvalidParameterValueException("Unable to delete public disk offering by id " + userId + " because it is domain-admin"); + List existingDomainIds = diskOfferingDetailsDao.findDomainIds(diskOfferingId); + if (existingDomainIds.isEmpty()) { + throw new InvalidParameterValueException(String.format("Unable to delete public disk offering: %s by admin: %s because it is domain-admin", offering.getUuid(), user.getUuid())); } - if (! _domainDao.isChildDomain(account.getDomainId(), offering.getDomainId() )) { - throw new InvalidParameterValueException("Unable to delete disk offering by another domain admin with id " + userId); + for (Long domainId : existingDomainIds) { + if (!_domainDao.isChildDomain(account.getDomainId(), domainId)) { + throw new InvalidParameterValueException(String.format("Unable to delete disk offering: %s as it has linked domain(s) which are not child domain for domain-admin: %s", offering.getUuid(), user.getUuid())); + } } } else if (account.getType() != Account.ACCOUNT_TYPE_ADMIN) { - throw new InvalidParameterValueException("Unable to delete disk offering by id " + userId + " because it is not root-admin or domain-admin"); + throw new InvalidParameterValueException(String.format("Unable to delete disk offering: %s by user: %s because it is not root-admin or domain-admin", offering.getUuid(), user.getUuid())); } offering.setState(DiskOffering.State.Inactive); @@ -2941,6 +3193,24 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati } } + @Override + public List getDiskOfferingDomains(Long diskOfferingId) { + final DiskOffering offeringHandle = _entityMgr.findById(DiskOffering.class, diskOfferingId); + if (offeringHandle == null) { + throw new InvalidParameterValueException("Unable to find disk offering " + diskOfferingId); + } + return diskOfferingDetailsDao.findDomainIds(diskOfferingId); + } + + @Override + public List getDiskOfferingZones(Long diskOfferingId) { + final DiskOffering offeringHandle = _entityMgr.findById(DiskOffering.class, diskOfferingId); + if (offeringHandle == null) { + throw new InvalidParameterValueException("Unable to find disk offering " + diskOfferingId); + } + return diskOfferingDetailsDao.findZoneIds(diskOfferingId); + } + @Override @ActionEvent(eventType = EventTypes.EVENT_SERVICE_OFFERING_DELETE, eventDescription = "deleting service offering") public boolean deleteServiceOffering(final DeleteServiceOfferingCmd cmd) { @@ -2968,14 +3238,17 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati } final Account account = _accountDao.findById(user.getAccountId()); if (account.getType() == Account.ACCOUNT_TYPE_DOMAIN_ADMIN) { - if (offering.getDomainId() == null) { - throw new InvalidParameterValueException("Unable to delete public service offering by id " + userId + " because it is domain-admin"); + List existingDomainIds = _serviceOfferingDetailsDao.findDomainIds(offeringId); + if (existingDomainIds.isEmpty()) { + throw new InvalidParameterValueException(String.format("Unable to delete public service offering: %s by admin: %s because it is domain-admin", offering.getUuid(), user.getUuid())); } - if (! _domainDao.isChildDomain(account.getDomainId(), offering.getDomainId() )) { - throw new InvalidParameterValueException("Unable to delete service offering by another domain admin with id " + userId); + for (Long domainId : existingDomainIds) { + if (!_domainDao.isChildDomain(account.getDomainId(), domainId)) { + throw new InvalidParameterValueException(String.format("Unable to delete service offering: %s as it has linked domain(s) which are not child domain for domain-admin: %s", offering.getUuid(), user.getUuid())); + } } } else if (account.getType() != Account.ACCOUNT_TYPE_ADMIN) { - throw new InvalidParameterValueException("Unable to delete service offering by id " + userId + " because it is not root-admin or domain-admin"); + throw new InvalidParameterValueException(String.format("Unable to delete service offering: %s by user: %s because it is not root-admin or domain-admin", offering.getUuid(), user.getUuid())); } offering.setState(DiskOffering.State.Inactive); @@ -4243,15 +4516,15 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati } @Override - public void checkDiskOfferingAccess(final Account caller, final DiskOffering dof) { + public void checkDiskOfferingAccess(final Account caller, final DiskOffering dof, DataCenter zone) { for (final SecurityChecker checker : _secChecker) { - if (checker.checkAccess(caller, dof)) { + if (checker.checkAccess(caller, dof, zone)) { if (s_logger.isDebugEnabled()) { s_logger.debug("Access granted to " + caller + " to disk offering:" + dof.getId() + " by " + checker.getName()); } return; } else { - throw new PermissionDeniedException("Access denied to " + caller + " by " + checker.getName()); + throw new PermissionDeniedException(String.format("Access denied to %s for disk offering: %s, zone: %s by %s", caller, dof.getUuid(), zone.getUuid(), checker.getName())); } } @@ -4295,10 +4568,29 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati final Map detailsStr = cmd.getDetails(); final Boolean egressDefaultPolicy = cmd.getEgressDefaultPolicy(); Boolean forVpc = cmd.getForVpc(); - Integer maxconn = null; boolean enableKeepAlive = false; String servicePackageuuid = cmd.getServicePackageId(); + final List domainIds = cmd.getDomainIds(); + final List zoneIds = cmd.getZoneIds(); + + // check if valid domain + if (CollectionUtils.isNotEmpty(domainIds)) { + for (final Long domainId: domainIds) { + if (_domainDao.findById(domainId) == null) { + throw new InvalidParameterValueException("Please specify a valid domain id"); + } + } + } + + // check if valid zone + if (CollectionUtils.isNotEmpty(zoneIds)) { + for (Long zoneId : zoneIds) { + if (_zoneDao.findById(zoneId) == null) + throw new InvalidParameterValueException("Please specify a valid zone id"); + } + } + // Verify traffic type for (final TrafficType tType : TrafficType.values()) { if (tType.name().equalsIgnoreCase(trafficTypeString)) { @@ -4555,7 +4847,7 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati } final NetworkOffering offering = createNetworkOffering(name, displayText, trafficType, tags, specifyVlan, availability, networkRate, serviceProviderMap, false, guestType, false, - serviceOfferingId, conserveMode, serviceCapabilityMap, specifyIpRanges, isPersistent, details, egressDefaultPolicy, maxconn, enableKeepAlive, forVpc); + serviceOfferingId, conserveMode, serviceCapabilityMap, specifyIpRanges, isPersistent, details, egressDefaultPolicy, maxconn, enableKeepAlive, forVpc, domainIds, zoneIds); CallContext.current().setEventDetails(" Id: " + offering.getId() + " Name: " + name); return offering; } @@ -4692,7 +4984,8 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati final Integer networkRate, final Map> serviceProviderMap, final boolean isDefault, final GuestType type, final boolean systemOnly, final Long serviceOfferingId, final boolean conserveMode, final Map> serviceCapabilityMap, final boolean specifyIpRanges, final boolean isPersistent, - final Map details, final boolean egressDefaultPolicy, final Integer maxconn, final boolean enableKeepAlive, Boolean forVpc) { + final Map details, final boolean egressDefaultPolicy, final Integer maxconn, final boolean enableKeepAlive, Boolean forVpc, + final List domainIds, final List zoneIds) { String servicePackageUuid; String spDescription = null; @@ -4929,6 +5222,22 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati s_logger.trace("Added service for the network offering: " + offService + " with null provider"); } } + if (offering != null) { + // Filter child domains when both parent and child domains are present + List filteredDomainIds = filterChildSubDomains(domainIds); + List detailsVO = new ArrayList<>(); + for (Long domainId : filteredDomainIds) { + detailsVO.add(new NetworkOfferingDetailsVO(offering.getId(), Detail.domainid, String.valueOf(domainId), false)); + } + if (CollectionUtils.isNotEmpty(zoneIds)) { + for (Long zoneId : zoneIds) { + detailsVO.add(new NetworkOfferingDetailsVO(offering.getId(), Detail.zoneid, String.valueOf(zoneId), false)); + } + } + if (!detailsVO.isEmpty()) { + networkOfferingDetailsDao.saveDetails(detailsVO); + } + } } return offering; @@ -4977,9 +5286,9 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati public Pair, Integer> searchForNetworkOfferings(final ListNetworkOfferingsCmd cmd) { Boolean isAscending = Boolean.parseBoolean(_configDao.getValue("sortkey.algorithm")); isAscending = isAscending == null ? Boolean.TRUE : isAscending; - final Filter searchFilter = new Filter(NetworkOfferingVO.class, "sortKey", isAscending, null, null); + final Filter searchFilter = new Filter(NetworkOfferingJoinVO.class, "sortKey", isAscending, null, null); final Account caller = CallContext.current().getCallingAccount(); - final SearchCriteria sc = _networkOfferingDao.createSearchCriteria(); + final SearchCriteria sc = networkOfferingJoinDao.createSearchCriteria(); final Long id = cmd.getId(); final Object name = cmd.getNetworkOfferingName(); @@ -4989,6 +5298,7 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati final Object specifyVlan = cmd.getSpecifyVlan(); final Object availability = cmd.getAvailability(); final Object state = cmd.getState(); + final Long domainId = cmd.getDomainId(); final Long zoneId = cmd.getZoneId(); DataCenter zone = null; final Long networkId = cmd.getNetworkId(); @@ -4999,6 +5309,16 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati final Boolean isTagged = cmd.isTagged(); final Boolean forVpc = cmd.getForVpc(); + if (domainId != null) { + Domain domain = _entityMgr.findById(Domain.class, domainId); + if (domain == null) { + throw new InvalidParameterValueException("Unable to find the domain by id=" + domainId); + } + if (!_domainDao.isChildDomain(caller.getDomainId(), domainId)) { + throw new InvalidParameterValueException(String.format("Unable to list network offerings for domain: %s as caller does not have access for it", domain.getUuid())); + } + } + if (zoneId != null) { zone = _entityMgr.findById(DataCenter.class, zoneId); if (zone == null) { @@ -5106,7 +5426,43 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati } } - final List offerings = _networkOfferingDao.search(sc, searchFilter); + if (zoneId != null) { + SearchBuilder sb = networkOfferingJoinDao.createSearchBuilder(); + sb.and("zoneId", sb.entity().getZoneId(), SearchCriteria.Op.FIND_IN_SET); + sb.or("zId", sb.entity().getZoneId(), SearchCriteria.Op.NULL); + sb.done(); + SearchCriteria zoneSC = sb.create(); + zoneSC.setParameters("zoneId", String.valueOf(zoneId)); + sc.addAnd("zoneId", SearchCriteria.Op.SC, zoneSC); + } + + final List offerings = networkOfferingJoinDao.search(sc, searchFilter); + // Remove offerings that are not associated with caller's domain or domainId passed + if ((caller.getType() != Account.ACCOUNT_TYPE_ADMIN || domainId != null) && CollectionUtils.isNotEmpty(offerings)) { + ListIterator it = offerings.listIterator(); + while (it.hasNext()) { + NetworkOfferingJoinVO offering = it.next(); + if (!Strings.isNullOrEmpty(offering.getDomainId())) { + boolean toRemove = false; + String[] domainIdsArray = offering.getDomainId().split(","); + for (String domainIdString : domainIdsArray) { + Long dId = Long.valueOf(domainIdString.trim()); + if (caller.getType() != Account.ACCOUNT_TYPE_ADMIN && + !_domainDao.isChildDomain(dId, caller.getDomainId())) { + toRemove = true; + break; + } + if (domainId != null && !_domainDao.isChildDomain(dId, domainId)) { + toRemove = true; + break; + } + } + if (toRemove) { + it.remove(); + } + } + } + } final Boolean sourceNatSupported = cmd.getSourceNatSupported(); final List pNtwkTags = new ArrayList(); boolean checkForTags = false; @@ -5131,7 +5487,7 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati final boolean parseOfferings = listBySupportedServices || sourceNatSupported != null || checkIfProvidersAreEnabled || forVpc != null || network != null; if (parseOfferings) { - final List supportedOfferings = new ArrayList(); + final List supportedOfferings = new ArrayList<>(); Service[] supportedServices = null; if (listBySupportedServices) { @@ -5148,7 +5504,7 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati } } - for (final NetworkOfferingVO offering : offerings) { + for (final NetworkOfferingJoinVO offering : offerings) { boolean addOffering = true; List checkForProviders = new ArrayList(); @@ -5177,9 +5533,9 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati } if (forVpc != null) { - addOffering = addOffering && isOfferingForVpc(offering) == forVpc.booleanValue(); + addOffering = addOffering && offering.isForVpc() == forVpc.booleanValue(); } else if (network != null) { - addOffering = addOffering && isOfferingForVpc(offering) == (network.getVpcId() != null); + addOffering = addOffering && offering.isForVpc() == (network.getVpcId() != null); } if (addOffering) { @@ -5189,16 +5545,16 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati } // Now apply pagination - final List wPagination = StringUtils.applyPagination(supportedOfferings, cmd.getStartIndex(), cmd.getPageSizeVal()); + final List wPagination = StringUtils.applyPagination(supportedOfferings, cmd.getStartIndex(), cmd.getPageSizeVal()); if (wPagination != null) { final Pair, Integer> listWPagination = new Pair, Integer>(wPagination, supportedOfferings.size()); return listWPagination; } return new Pair, Integer>(supportedOfferings, supportedOfferings.size()); } else { - final List wPagination = StringUtils.applyPagination(offerings, cmd.getStartIndex(), cmd.getPageSizeVal()); + final List wPagination = StringUtils.applyPagination(offerings, cmd.getStartIndex(), cmd.getPageSizeVal()); if (wPagination != null) { - final Pair, Integer> listWPagination = new Pair, Integer>(wPagination, offerings.size()); + final Pair, Integer> listWPagination = new Pair<>(wPagination, offerings.size()); return listWPagination; } return new Pair, Integer>(offerings, offerings.size()); @@ -5258,6 +5614,8 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati Availability availability = null; final String state = cmd.getState(); final String tags = cmd.getTags(); + final List domainIds = cmd.getDomainIds(); + final List zoneIds = cmd.getZoneIds(); CallContext.current().setEventDetails(" Id: " + id); // Verify input parameters @@ -5266,96 +5624,181 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati throw new InvalidParameterValueException("unable to find network offering " + id); } + List existingDomainIds = networkOfferingDetailsDao.findDomainIds(id); + Collections.sort(existingDomainIds); + + List existingZoneIds = networkOfferingDetailsDao.findZoneIds(id); + Collections.sort(existingZoneIds); + // Don't allow to update system network offering if (offeringToUpdate.isSystemOnly()) { throw new InvalidParameterValueException("Can't update system network offerings"); } + // check if valid domain + if (CollectionUtils.isNotEmpty(domainIds)) { + for (final Long domainId: domainIds) { + if (_domainDao.findById(domainId) == null) { + throw new InvalidParameterValueException("Please specify a valid domain id"); + } + } + } + + // check if valid zone + if (CollectionUtils.isNotEmpty(zoneIds)) { + for (Long zoneId : zoneIds) { + if (_zoneDao.findById(zoneId) == null) + throw new InvalidParameterValueException("Please specify a valid zone id"); + } + } + + // Filter child domains when both parent and child domains are present + List filteredDomainIds = filterChildSubDomains(domainIds); + Collections.sort(filteredDomainIds); + + List filteredZoneIds = new ArrayList<>(); + if (CollectionUtils.isNotEmpty(zoneIds)) { + filteredZoneIds.addAll(zoneIds); + } + Collections.sort(filteredZoneIds); + final NetworkOfferingVO offering = _networkOfferingDao.createForUpdate(id); - if (name != null) { - offering.setName(name); - } + boolean updateNeeded = name != null || displayText != null || sortKey != null || + state != null || tags != null || availabilityStr != null || maxconn != null; - if (displayText != null) { - offering.setDisplayText(displayText); - } - - if (sortKey != null) { - offering.setSortKey(sortKey); - } - - if (state != null) { - boolean validState = false; - for (final NetworkOffering.State st : NetworkOffering.State.values()) { - if (st.name().equalsIgnoreCase(state)) { - validState = true; - offering.setState(st); - } + if(updateNeeded) { + if (name != null) { + offering.setName(name); } - if (!validState) { - throw new InvalidParameterValueException("Incorrect state value: " + state); + + if (displayText != null) { + offering.setDisplayText(displayText); } - } - if (tags != null) { - List dataCenters = _zoneDao.listAll(); - TrafficType trafficType = offeringToUpdate.getTrafficType(); - String oldTags = offeringToUpdate.getTags(); + if (sortKey != null) { + offering.setSortKey(sortKey); + } - for (DataCenterVO dataCenter : dataCenters) { - long zoneId = dataCenter.getId(); - long newPhysicalNetworkId = _networkModel.findPhysicalNetworkId(zoneId, tags, trafficType); - if (oldTags != null) { - long oldPhysicalNetworkId = _networkModel.findPhysicalNetworkId(zoneId, oldTags, trafficType); - if (newPhysicalNetworkId != oldPhysicalNetworkId) { - throw new InvalidParameterValueException("New tags: selects different physical network for zone " + zoneId); + if (state != null) { + boolean validState = false; + for (final NetworkOffering.State st : NetworkOffering.State.values()) { + if (st.name().equalsIgnoreCase(state)) { + validState = true; + offering.setState(st); } } - } - - offering.setTags(tags); - } - - // Verify availability - if (availabilityStr != null) { - for (final Availability avlb : Availability.values()) { - if (avlb.name().equalsIgnoreCase(availabilityStr)) { - availability = avlb; + if (!validState) { + throw new InvalidParameterValueException("Incorrect state value: " + state); } } - if (availability == null) { - throw new InvalidParameterValueException("Invalid value for Availability. Supported types: " + Availability.Required + ", " + Availability.Optional); - } else { - if (availability == NetworkOffering.Availability.Required) { - final boolean canOffBeRequired = offeringToUpdate.getGuestType() == GuestType.Isolated && _networkModel.areServicesSupportedByNetworkOffering( - offeringToUpdate.getId(), Service.SourceNat); - if (!canOffBeRequired) { - throw new InvalidParameterValueException("Availability can be " + NetworkOffering.Availability.Required + " only for networkOfferings of type " - + GuestType.Isolated + " and with " + Service.SourceNat.getName() + " enabled"); - } - // only one network offering in the system can be Required - final List offerings = _networkOfferingDao.listByAvailability(Availability.Required, false); - if (!offerings.isEmpty() && offerings.get(0).getId() != offeringToUpdate.getId()) { - throw new InvalidParameterValueException("System already has network offering id=" + offerings.get(0).getId() + " with availability " - + Availability.Required); + if (tags != null) { + List dataCenters = _zoneDao.listAll(); + TrafficType trafficType = offeringToUpdate.getTrafficType(); + String oldTags = offeringToUpdate.getTags(); + + for (DataCenterVO dataCenter : dataCenters) { + long zoneId = dataCenter.getId(); + long newPhysicalNetworkId = _networkModel.findPhysicalNetworkId(zoneId, tags, trafficType); + if (oldTags != null) { + long oldPhysicalNetworkId = _networkModel.findPhysicalNetworkId(zoneId, oldTags, trafficType); + if (newPhysicalNetworkId != oldPhysicalNetworkId) { + throw new InvalidParameterValueException("New tags: selects different physical network for zone " + zoneId); + } } } - offering.setAvailability(availability); + + offering.setTags(tags); } - } - if (_ntwkOffServiceMapDao.areServicesSupportedByNetworkOffering(offering.getId(), Service.Lb)) { - if (maxconn != null) { - offering.setConcurrentConnections(maxconn); + + // Verify availability + if (availabilityStr != null) { + for (final Availability avlb : Availability.values()) { + if (avlb.name().equalsIgnoreCase(availabilityStr)) { + availability = avlb; + } + } + if (availability == null) { + throw new InvalidParameterValueException("Invalid value for Availability. Supported types: " + Availability.Required + ", " + Availability.Optional); + } else { + if (availability == NetworkOffering.Availability.Required) { + final boolean canOffBeRequired = offeringToUpdate.getGuestType() == GuestType.Isolated && _networkModel.areServicesSupportedByNetworkOffering( + offeringToUpdate.getId(), Service.SourceNat); + if (!canOffBeRequired) { + throw new InvalidParameterValueException("Availability can be " + NetworkOffering.Availability.Required + " only for networkOfferings of type " + + GuestType.Isolated + " and with " + Service.SourceNat.getName() + " enabled"); + } + + // only one network offering in the system can be Required + final List offerings = _networkOfferingDao.listByAvailability(Availability.Required, false); + if (!offerings.isEmpty() && offerings.get(0).getId() != offeringToUpdate.getId()) { + throw new InvalidParameterValueException("System already has network offering id=" + offerings.get(0).getId() + " with availability " + + Availability.Required); + } + } + offering.setAvailability(availability); + } + } + if (_ntwkOffServiceMapDao.areServicesSupportedByNetworkOffering(offering.getId(), Service.Lb)) { + if (maxconn != null) { + offering.setConcurrentConnections(maxconn); + } + } + + if (!_networkOfferingDao.update(id, offering)) { + return null; } } - if (_networkOfferingDao.update(id, offering)) { - return _networkOfferingDao.findById(id); - } else { - return null; + List detailsVO = new ArrayList<>(); + if(!filteredDomainIds.equals(existingDomainIds) || !filteredZoneIds.equals(existingZoneIds)) { + SearchBuilder sb = networkOfferingDetailsDao.createSearchBuilder(); + sb.and("offeringId", sb.entity().getResourceId(), SearchCriteria.Op.EQ); + sb.and("detailName", sb.entity().getName(), SearchCriteria.Op.EQ); + sb.done(); + SearchCriteria sc = sb.create(); + sc.setParameters("offeringId", String.valueOf(id)); + if(!filteredDomainIds.equals(existingDomainIds)) { + sc.setParameters("detailName", ApiConstants.DOMAIN_ID); + networkOfferingDetailsDao.remove(sc); + for (Long domainId : filteredDomainIds) { + detailsVO.add(new NetworkOfferingDetailsVO(id, Detail.domainid, String.valueOf(domainId), false)); + } + } + if(!filteredZoneIds.equals(existingZoneIds)) { + sc.setParameters("detailName", ApiConstants.ZONE_ID); + networkOfferingDetailsDao.remove(sc); + for (Long zoneId : filteredZoneIds) { + detailsVO.add(new NetworkOfferingDetailsVO(id, Detail.zoneid, String.valueOf(zoneId), false)); + } + } } + if (!detailsVO.isEmpty()) { + for (NetworkOfferingDetailsVO detailVO : detailsVO) { + networkOfferingDetailsDao.persist(detailVO); + } + } + + return _networkOfferingDao.findById(id); + } + + @Override + public List getNetworkOfferingDomains(Long networkOfferingId) { + final NetworkOffering offeringHandle = _entityMgr.findById(NetworkOffering.class, networkOfferingId); + if (offeringHandle == null) { + throw new InvalidParameterValueException("Unable to find network offering " + networkOfferingId); + } + return networkOfferingDetailsDao.findDomainIds(networkOfferingId); + } + + @Override + public List getNetworkOfferingZones(Long networkOfferingId) { + final NetworkOffering offeringHandle = _entityMgr.findById(NetworkOffering.class, networkOfferingId); + if (offeringHandle == null) { + throw new InvalidParameterValueException("Unable to find network offering " + networkOfferingId); + } + return networkOfferingDetailsDao.findZoneIds(networkOfferingId); } @Override @@ -5772,6 +6215,30 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati return false; } + private List filterChildSubDomains(final List domainIds) { + List filteredDomainIds = new ArrayList<>(); + if (domainIds != null) { + filteredDomainIds.addAll(domainIds); + } + if (filteredDomainIds.size() > 1) { + for (int i = filteredDomainIds.size() - 1; i >= 1; i--) { + long first = filteredDomainIds.get(i); + for (int j = i - 1; j >= 0; j--) { + long second = filteredDomainIds.get(j); + if (_domainDao.isChildDomain(filteredDomainIds.get(i), filteredDomainIds.get(j))) { + filteredDomainIds.remove(j); + i--; + } + if (_domainDao.isChildDomain(filteredDomainIds.get(j), filteredDomainIds.get(i))) { + filteredDomainIds.remove(i); + break; + } + } + } + } + return filteredDomainIds; + } + public List getSecChecker() { return _secChecker; } diff --git a/server/src/main/java/com/cloud/network/NetworkServiceImpl.java b/server/src/main/java/com/cloud/network/NetworkServiceImpl.java index bdfba47a116..3359b2773ac 100644 --- a/server/src/main/java/com/cloud/network/NetworkServiceImpl.java +++ b/server/src/main/java/com/cloud/network/NetworkServiceImpl.java @@ -1063,6 +1063,14 @@ public class NetworkServiceImpl extends ManagerBase implements NetworkService { } throw ex; } + + Account owner = null; + if ((cmd.getAccountName() != null && domainId != null) || cmd.getProjectId() != null) { + owner = _accountMgr.finalizeOwner(caller, cmd.getAccountName(), domainId, cmd.getProjectId()); + } else { + owner = caller; + } + // validate physical network and zone // Check if physical network exists PhysicalNetwork pNtwk = null; @@ -1086,6 +1094,8 @@ public class NetworkServiceImpl extends ManagerBase implements NetworkService { throw new InvalidParameterValueException("Specified zone id was not found"); } + _accountMgr.checkAccess(owner, ntwkOff, zone); + if (Grouping.AllocationState.Disabled == zone.getAllocationState() && !_accountMgr.isRootAdmin(caller.getId())) { // See DataCenterVO.java PermissionDeniedException ex = new PermissionDeniedException("Cannot perform this operation since specified Zone is currently disabled"); @@ -1154,12 +1164,6 @@ public class NetworkServiceImpl extends ManagerBase implements NetworkService { } else if (subdomainAccess != null) { throw new InvalidParameterValueException("Parameter subDomainAccess can be specified only with aclType=Domain"); } - Account owner = null; - if ((cmd.getAccountName() != null && domainId != null) || cmd.getProjectId() != null) { - owner = _accountMgr.finalizeOwner(caller, cmd.getAccountName(), domainId, cmd.getProjectId()); - } else { - owner = caller; - } boolean ipv4 = true, ipv6 = false; if (startIP != null) { @@ -2037,6 +2041,7 @@ public class NetworkServiceImpl extends ManagerBase implements NetworkService { } _accountMgr.checkAccess(callerAccount, null, true, network); + _accountMgr.checkAccess(_accountMgr.getActiveAccountById(network.getAccountId()), offering, _dcDao.findById(network.getDataCenterId())); if (cmd instanceof UpdateNetworkCmdByAdmin) { final Boolean hideIpAddressUsage = ((UpdateNetworkCmdByAdmin) cmd).getHideIpAddressUsage(); @@ -2556,6 +2561,7 @@ public class NetworkServiceImpl extends ManagerBase implements NetworkService { Vpc vpc = _vpcDao.findById(vpcId); _accountMgr.checkAccess(account, null, true, vpc); + _accountMgr.checkAccess(account, _vpcOfferingDao.findById(vpcOfferingId), _dcDao.findById(vpc.getZoneId())); if (vpc.getVpcOfferingId() == vpcOfferingId) { return vpc; diff --git a/server/src/main/java/com/cloud/network/vpc/VpcManagerImpl.java b/server/src/main/java/com/cloud/network/vpc/VpcManagerImpl.java index 33ae1cc08cd..b1b1059c123 100644 --- a/server/src/main/java/com/cloud/network/vpc/VpcManagerImpl.java +++ b/server/src/main/java/com/cloud/network/vpc/VpcManagerImpl.java @@ -24,6 +24,7 @@ import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.List; +import java.util.ListIterator; import java.util.Map; import java.util.Map.Entry; import java.util.Set; @@ -39,9 +40,12 @@ import javax.inject.Inject; import javax.naming.ConfigurationException; import org.apache.cloudstack.acl.ControlledEntity.ACLType; +import org.apache.cloudstack.api.ApiConstants; +import org.apache.cloudstack.api.command.admin.vpc.CreateVPCOfferingCmd; import org.apache.cloudstack.api.command.admin.vpc.UpdateVPCOfferingCmd; import org.apache.cloudstack.api.command.user.vpc.ListPrivateGatewaysCmd; import org.apache.cloudstack.api.command.user.vpc.ListStaticRoutesCmd; +import org.apache.cloudstack.api.command.user.vpc.ListVPCOfferingsCmd; import org.apache.cloudstack.context.CallContext; import org.apache.cloudstack.engine.orchestration.service.NetworkOrchestrationService; import org.apache.cloudstack.framework.config.dao.ConfigurationDao; @@ -49,6 +53,8 @@ import org.apache.cloudstack.managed.context.ManagedContextRunnable; import org.apache.commons.collections.CollectionUtils; import org.apache.log4j.Logger; +import com.cloud.api.query.dao.VpcOfferingJoinDao; +import com.cloud.api.query.vo.VpcOfferingJoinVO; import com.cloud.configuration.Config; import com.cloud.configuration.Resource.ResourceType; import com.cloud.dc.DataCenter; @@ -58,6 +64,7 @@ import com.cloud.dc.VlanVO; import com.cloud.dc.dao.DataCenterDao; import com.cloud.dc.dao.VlanDao; import com.cloud.deploy.DeployDestination; +import com.cloud.domain.dao.DomainDao; import com.cloud.event.ActionEvent; import com.cloud.event.EventTypes; import com.cloud.exception.ConcurrentOperationException; @@ -98,6 +105,7 @@ import com.cloud.network.vpc.dao.StaticRouteDao; import com.cloud.network.vpc.dao.VpcDao; import com.cloud.network.vpc.dao.VpcGatewayDao; import com.cloud.network.vpc.dao.VpcOfferingDao; +import com.cloud.network.vpc.dao.VpcOfferingDetailsDao; import com.cloud.network.vpc.dao.VpcOfferingServiceMapDao; import com.cloud.network.vpc.dao.VpcServiceMapDao; import com.cloud.network.vpn.Site2SiteVpnManager; @@ -139,6 +147,7 @@ import com.cloud.vm.DomainRouterVO; import com.cloud.vm.ReservationContext; import com.cloud.vm.ReservationContextImpl; import com.cloud.vm.dao.DomainRouterDao; +import com.google.common.base.Strings; public class VpcManagerImpl extends ManagerBase implements VpcManager, VpcProvisioningService, VpcService { private static final Logger s_logger = Logger.getLogger(VpcManagerImpl.class); @@ -154,6 +163,10 @@ public class VpcManagerImpl extends ManagerBase implements VpcManager, VpcProvis @Inject VpcOfferingDao _vpcOffDao; @Inject + VpcOfferingJoinDao vpcOfferingJoinDao; + @Inject + VpcOfferingDetailsDao vpcOfferingDetailsDao; + @Inject VpcOfferingServiceMapDao _vpcOffSvcMapDao; @Inject VpcDao _vpcDao; @@ -205,6 +218,8 @@ public class VpcManagerImpl extends ManagerBase implements VpcManager, VpcProvis VpcVirtualNetworkApplianceManager _routerService; @Inject DomainRouterDao _routerDao; + @Inject + DomainDao domainDao; @Inject private VpcPrivateGatewayTransactionCallable vpcTxCallable; @@ -342,10 +357,47 @@ public class VpcManagerImpl extends ManagerBase implements VpcManager, VpcProvis return _vpcOffDao.findById(vpcOffId); } + @Override + @ActionEvent(eventType = EventTypes.EVENT_VPC_OFFERING_CREATE, eventDescription = "creating vpc offering", create = true) + public VpcOffering createVpcOffering(CreateVPCOfferingCmd cmd) { + final String vpcOfferingName = cmd.getVpcOfferingName(); + final String displayText = cmd.getDisplayText(); + final List supportedServices = cmd.getSupportedServices(); + final Map> serviceProviderList = cmd.getServiceProviders(); + final Map serviceCapabilitystList = cmd.getServiceCapabilitystList(); + final Long serviceOfferingId = cmd.getServiceOfferingId(); + final List domainIds = cmd.getDomainIds(); + final List zoneIds = cmd.getZoneIds(); + + // check if valid domain + if (CollectionUtils.isNotEmpty(cmd.getDomainIds())) { + for (final Long domainId: cmd.getDomainIds()) { + if (domainDao.findById(domainId) == null) { + throw new InvalidParameterValueException("Please specify a valid domain id"); + } + } + } + + // check if valid zone + if (CollectionUtils.isNotEmpty(cmd.getZoneIds())) { + for (Long zoneId : cmd.getZoneIds()) { + if (_dcDao.findById(zoneId) == null) + throw new InvalidParameterValueException("Please specify a valid zone id"); + } + } + + return createVpcOffering(vpcOfferingName, displayText, supportedServices, + serviceProviderList, serviceCapabilitystList, serviceOfferingId, + domainIds, zoneIds); + } + @Override @ActionEvent(eventType = EventTypes.EVENT_VPC_OFFERING_CREATE, eventDescription = "creating vpc offering", create = true) public VpcOffering createVpcOffering(final String name, final String displayText, final List supportedServices, final Map> serviceProviders, - final Map serviceCapabilitystList, final Long serviceOfferingId) { + final Map serviceCapabilitystList, final Long serviceOfferingId, List domainIds, List zoneIds) { + + // Filter child domains when both parent and child domains are present + List filteredDomainIds = filterChildSubDomains(domainIds); final Map> svcProviderMap = new HashMap>(); final Set defaultProviders = new HashSet(); @@ -424,6 +476,21 @@ public class VpcManagerImpl extends ManagerBase implements VpcManager, VpcProvis final boolean redundantRouter = isVpcOfferingRedundantRouter(serviceCapabilitystList); final VpcOffering offering = createVpcOffering(name, displayText, svcProviderMap, false, null, serviceOfferingId, supportsDistributedRouter, offersRegionLevelVPC, redundantRouter); + + if (offering != null) { + List detailsVO = new ArrayList<>(); + for (Long domainId : filteredDomainIds) { + detailsVO.add(new VpcOfferingDetailsVO(offering.getId(), ApiConstants.DOMAIN_ID, String.valueOf(domainId), false)); + } + if (CollectionUtils.isNotEmpty(zoneIds)) { + for (Long zoneId : zoneIds) { + detailsVO.add(new VpcOfferingDetailsVO(offering.getId(), ApiConstants.ZONE_ID, String.valueOf(zoneId), false)); + } + } + if (!detailsVO.isEmpty()) { + vpcOfferingDetailsDao.saveDetails(detailsVO); + } + } CallContext.current().setEventDetails(" Id: " + offering.getId() + " Name: " + name); return offering; @@ -578,15 +645,25 @@ public class VpcManagerImpl extends ManagerBase implements VpcManager, VpcProvis } @Override - public Pair, Integer> listVpcOfferings(final Long id, final String name, final String displayText, final List supportedServicesStr, - final Boolean isDefault, final String keyword, final String state, final Long startIndex, final Long pageSizeVal) { + public Pair, Integer> listVpcOfferings(ListVPCOfferingsCmd cmd) { + Account caller = CallContext.current().getCallingAccount(); + final Long id = cmd.getId(); + final String name = cmd.getVpcOffName(); + final String displayText = cmd.getDisplayText(); + final List supportedServicesStr = cmd.getSupportedServices(); + final Boolean isDefault = cmd.getIsDefault(); + final String keyword = cmd.getKeyword(); + final String state = cmd.getState(); + final Long startIndex = cmd.getStartIndex(); + final Long pageSizeVal = cmd.getPageSizeVal(); + final Long zoneId = cmd.getZoneId(); Boolean isAscending = Boolean.parseBoolean(_configDao.getValue("sortkey.algorithm")); isAscending = isAscending == null ? Boolean.TRUE : isAscending; - final Filter searchFilter = new Filter(VpcOfferingVO.class, "sortKey", isAscending, null, null); - final SearchCriteria sc = _vpcOffDao.createSearchCriteria(); + final Filter searchFilter = new Filter(VpcOfferingJoinVO.class, "sortKey", isAscending, null, null); + final SearchCriteria sc = vpcOfferingJoinDao.createSearchCriteria(); if (keyword != null) { - final SearchCriteria ssc = _vpcOffDao.createSearchCriteria(); + final SearchCriteria ssc = vpcOfferingJoinDao.createSearchCriteria(); ssc.addOr("displayText", SearchCriteria.Op.LIKE, "%" + keyword + "%"); ssc.addOr("name", SearchCriteria.Op.LIKE, "%" + keyword + "%"); @@ -613,13 +690,45 @@ public class VpcManagerImpl extends ManagerBase implements VpcManager, VpcProvis sc.addAnd("id", SearchCriteria.Op.EQ, id); } - final List offerings = _vpcOffDao.search(sc, searchFilter); + if (zoneId != null) { + SearchBuilder sb = vpcOfferingJoinDao.createSearchBuilder(); + sb.and("zoneId", sb.entity().getZoneId(), Op.FIND_IN_SET); + sb.or("zId", sb.entity().getZoneId(), Op.NULL); + sb.done(); + SearchCriteria zoneSC = sb.create(); + zoneSC.setParameters("zoneId", String.valueOf(zoneId)); + sc.addAnd("zoneId", SearchCriteria.Op.SC, zoneSC); + } + final List offerings = vpcOfferingJoinDao.search(sc, searchFilter); + + // Remove offerings that are not associated with caller's domain + // TODO: Better approach + if (caller.getType() != Account.ACCOUNT_TYPE_ADMIN && CollectionUtils.isNotEmpty(offerings)) { + ListIterator it = offerings.listIterator(); + while (it.hasNext()) { + VpcOfferingJoinVO offering = it.next(); + if(!Strings.isNullOrEmpty(offering.getDomainId())) { + boolean toRemove = true; + String[] domainIdsArray = offering.getDomainId().split(","); + for (String domainIdString : domainIdsArray) { + Long dId = Long.valueOf(domainIdString.trim()); + if (domainDao.isChildDomain(dId, caller.getDomainId())) { + toRemove = false; + break; + } + } + if (toRemove) { + it.remove(); + } + } + } + } // filter by supported services final boolean listBySupportedServices = supportedServicesStr != null && !supportedServicesStr.isEmpty() && !offerings.isEmpty(); if (listBySupportedServices) { - final List supportedOfferings = new ArrayList(); + final List supportedOfferings = new ArrayList<>(); Service[] supportedServices = null; if (listBySupportedServices) { @@ -636,7 +745,7 @@ public class VpcManagerImpl extends ManagerBase implements VpcManager, VpcProvis } } - for (final VpcOfferingVO offering : offerings) { + for (final VpcOfferingJoinVO offering : offerings) { if (areServicesSupportedByVpcOffering(offering.getId(), supportedServices)) { supportedOfferings.add(offering); } @@ -644,15 +753,13 @@ public class VpcManagerImpl extends ManagerBase implements VpcManager, VpcProvis final List wPagination = StringUtils.applyPagination(supportedOfferings, startIndex, pageSizeVal); if (wPagination != null) { - final Pair, Integer> listWPagination = new Pair, Integer>(wPagination, supportedOfferings.size()); - return listWPagination; + return new Pair<>(wPagination, supportedOfferings.size()); } return new Pair, Integer>(supportedOfferings, supportedOfferings.size()); } else { final List wPagination = StringUtils.applyPagination(offerings, startIndex, pageSizeVal); if (wPagination != null) { - final Pair, Integer> listWPagination = new Pair, Integer>(wPagination, offerings.size()); - return listWPagination; + return new Pair<>(wPagination, offerings.size()); } return new Pair, Integer>(offerings, offerings.size()); } @@ -696,22 +803,41 @@ public class VpcManagerImpl extends ManagerBase implements VpcManager, VpcProvis @Override @ActionEvent(eventType = EventTypes.EVENT_VPC_OFFERING_UPDATE, eventDescription = "updating vpc offering") public VpcOffering updateVpcOffering(long vpcOffId, String vpcOfferingName, String displayText, String state) { - return updateVpcOfferingInternal(vpcOffId, vpcOfferingName, displayText, state, null); + return updateVpcOfferingInternal(vpcOffId, vpcOfferingName, displayText, state, null, null, null); } @Override @ActionEvent(eventType = EventTypes.EVENT_VPC_OFFERING_UPDATE, eventDescription = "updating vpc offering") - public VpcOffering updateVpcOffering(final UpdateVPCOfferingCmd vpcOfferingCmd) { - final long vpcOffId = vpcOfferingCmd.getId(); - final String vpcOfferingName = vpcOfferingCmd.getVpcOfferingName(); - final String displayText = vpcOfferingCmd.getDisplayText(); - final String state = vpcOfferingCmd.getState(); - final Integer sortKey = vpcOfferingCmd.getSortKey(); + public VpcOffering updateVpcOffering(final UpdateVPCOfferingCmd cmd) { + final Long offeringId = cmd.getId(); + final String vpcOfferingName = cmd.getVpcOfferingName(); + final String displayText = cmd.getDisplayText(); + final String state = cmd.getState(); + final List domainIds = cmd.getDomainIds(); + final List zoneIds = cmd.getZoneIds(); + final Integer sortKey = cmd.getSortKey(); - return updateVpcOfferingInternal(vpcOffId, vpcOfferingName, displayText, state, sortKey); + // check if valid domain + if (CollectionUtils.isNotEmpty(domainIds)) { + for (final Long domainId: domainIds) { + if (domainDao.findById(domainId) == null) { + throw new InvalidParameterValueException("Please specify a valid domain id"); + } + } + } + + // check if valid zone + if (CollectionUtils.isNotEmpty(zoneIds)) { + for (Long zoneId : zoneIds) { + if (_dcDao.findById(zoneId) == null) + throw new InvalidParameterValueException("Please specify a valid zone id"); + } + } + + return updateVpcOfferingInternal(offeringId, vpcOfferingName, displayText, state, sortKey, domainIds, zoneIds); } - private VpcOffering updateVpcOfferingInternal(long vpcOffId, String vpcOfferingName, String displayText, String state, Integer sortKey) { + private VpcOffering updateVpcOfferingInternal(long vpcOffId, String vpcOfferingName, String displayText, String state, Integer sortKey, final List domainIds, final List zoneIds) { CallContext.current().setEventDetails(" Id: " + vpcOffId); // Verify input parameters @@ -720,39 +846,102 @@ public class VpcManagerImpl extends ManagerBase implements VpcManager, VpcProvis throw new InvalidParameterValueException("Unable to find vpc offering " + vpcOffId); } + List existingDomainIds = vpcOfferingDetailsDao.findDomainIds(vpcOffId); + Collections.sort(existingDomainIds); + + List existingZoneIds = vpcOfferingDetailsDao.findZoneIds(vpcOffId); + Collections.sort(existingZoneIds); + + + // Filter child domains when both parent and child domains are present + List filteredDomainIds = filterChildSubDomains(domainIds); + Collections.sort(filteredDomainIds); + + List filteredZoneIds = new ArrayList<>(); + if (CollectionUtils.isNotEmpty(zoneIds)) { + filteredZoneIds.addAll(zoneIds); + } + Collections.sort(filteredZoneIds); + + final boolean updateNeeded = vpcOfferingName != null || displayText != null || state != null || sortKey != null; + final VpcOfferingVO offering = _vpcOffDao.createForUpdate(vpcOffId); - if (vpcOfferingName != null) { - offering.setName(vpcOfferingName); - } - - if (displayText != null) { - offering.setDisplayText(displayText); - } - - if (state != null) { - boolean validState = false; - for (final VpcOffering.State st : VpcOffering.State.values()) { - if (st.name().equalsIgnoreCase(state)) { - validState = true; - offering.setState(st); + if (updateNeeded) { + if (vpcOfferingName != null) { + offering.setName(vpcOfferingName); + } + if (displayText != null) { + offering.setDisplayText(displayText); + } + if (state != null) { + boolean validState = false; + for (final VpcOffering.State st : VpcOffering.State.values()) { + if (st.name().equalsIgnoreCase(state)) { + validState = true; + offering.setState(st); + } + } + if (!validState) { + throw new InvalidParameterValueException("Incorrect state value: " + state); } } - if (!validState) { - throw new InvalidParameterValueException("Incorrect state value: " + state); + if (sortKey != null) { + offering.setSortKey(sortKey); + } + + if (!_vpcOffDao.update(vpcOffId, offering)) { + return null; } } - - if (sortKey != null) { - offering.setSortKey(sortKey); + List detailsVO = new ArrayList<>(); + if(!filteredDomainIds.equals(existingDomainIds) || !filteredZoneIds.equals(existingZoneIds)) { + SearchBuilder sb = vpcOfferingDetailsDao.createSearchBuilder(); + sb.and("offeringId", sb.entity().getResourceId(), SearchCriteria.Op.EQ); + sb.and("detailName", sb.entity().getName(), SearchCriteria.Op.EQ); + sb.done(); + SearchCriteria sc = sb.create(); + sc.setParameters("offeringId", String.valueOf(vpcOffId)); + if(!filteredDomainIds.equals(existingDomainIds)) { + sc.setParameters("detailName", ApiConstants.DOMAIN_ID); + vpcOfferingDetailsDao.remove(sc); + for (Long domainId : filteredDomainIds) { + detailsVO.add(new VpcOfferingDetailsVO(vpcOffId, ApiConstants.DOMAIN_ID, String.valueOf(domainId), false)); + } + } + if(!filteredZoneIds.equals(existingZoneIds)) { + sc.setParameters("detailName", ApiConstants.ZONE_ID); + vpcOfferingDetailsDao.remove(sc); + for (Long zoneId : filteredZoneIds) { + detailsVO.add(new VpcOfferingDetailsVO(vpcOffId, ApiConstants.ZONE_ID, String.valueOf(zoneId), false)); + } + } } - - if (_vpcOffDao.update(vpcOffId, offering)) { - s_logger.debug("Updated VPC offeirng id=" + vpcOffId); - return _vpcOffDao.findById(vpcOffId); - } else { - return null; + if (!detailsVO.isEmpty()) { + for (VpcOfferingDetailsVO detailVO : detailsVO) { + vpcOfferingDetailsDao.persist(detailVO); + } } + s_logger.debug("Updated VPC offeirng id=" + vpcOffId); + return _vpcOffDao.findById(vpcOffId); + } + + @Override + public List getVpcOfferingDomains(Long vpcOfferingId) { + final VpcOffering offeringHandle = _entityMgr.findById(VpcOffering.class, vpcOfferingId); + if (offeringHandle == null) { + throw new InvalidParameterValueException("Unable to find VPC offering " + vpcOfferingId); + } + return vpcOfferingDetailsDao.findDomainIds(vpcOfferingId); + } + + @Override + public List getVpcOfferingZones(Long vpcOfferingId) { + final VpcOffering offeringHandle = _entityMgr.findById(VpcOffering.class, vpcOfferingId); + if (offeringHandle == null) { + throw new InvalidParameterValueException("Unable to find VPC offering " + vpcOfferingId); + } + return vpcOfferingDetailsDao.findZoneIds(vpcOfferingId); } @Override @@ -770,6 +959,7 @@ public class VpcManagerImpl extends ManagerBase implements VpcManager, VpcProvis // Validate vpc offering final VpcOfferingVO vpcOff = _vpcOffDao.findById(vpcOffId); + _accountMgr.checkAccess(owner, vpcOff, _dcDao.findById(zoneId)); if (vpcOff == null || vpcOff.getState() != State.Enabled) { final InvalidParameterValueException ex = new InvalidParameterValueException("Unable to find vpc offering in " + State.Enabled + " state by specified id"); if (vpcOff == null) { @@ -780,7 +970,7 @@ public class VpcManagerImpl extends ManagerBase implements VpcManager, VpcProvis throw ex; } - final boolean isRegionLevelVpcOff = vpcOff.offersRegionLevelVPC(); + final boolean isRegionLevelVpcOff = vpcOff.isOffersRegionLevelVPC(); if (isRegionLevelVpcOff && networkDomain == null) { throw new InvalidParameterValueException("Network domain must be specified for region level VPC"); } @@ -809,9 +999,9 @@ public class VpcManagerImpl extends ManagerBase implements VpcManager, VpcProvis } } - final boolean useDistributedRouter = vpcOff.supportsDistributedRouter(); + final boolean useDistributedRouter = vpcOff.isSupportsDistributedRouter(); final VpcVO vpc = new VpcVO(zoneId, vpcName, displayText, owner.getId(), owner.getDomainId(), vpcOffId, cidr, networkDomain, useDistributedRouter, isRegionLevelVpcOff, - vpcOff.getRedundantRouter()); + vpcOff.isRedundantRouter()); return createVpc(displayVpc, vpc); } @@ -2525,4 +2715,27 @@ public class VpcManagerImpl extends ManagerBase implements VpcManager, VpcProvis return _ntwkMgr.areRoutersRunning(_routerDao.listByVpcId(vpc.getId())); } + private List filterChildSubDomains(final List domainIds) { + List filteredDomainIds = new ArrayList<>(); + if (domainIds != null) { + filteredDomainIds.addAll(domainIds); + } + if (filteredDomainIds.size() > 1) { + for (int i = filteredDomainIds.size() - 1; i >= 1; i--) { + long first = filteredDomainIds.get(i); + for (int j = i - 1; j >= 0; j--) { + long second = filteredDomainIds.get(j); + if (domainDao.isChildDomain(filteredDomainIds.get(i), filteredDomainIds.get(j))) { + filteredDomainIds.remove(j); + i--; + } + if (domainDao.isChildDomain(filteredDomainIds.get(j), filteredDomainIds.get(i))) { + filteredDomainIds.remove(i); + break; + } + } + } + } + return filteredDomainIds; + } } diff --git a/server/src/main/java/com/cloud/server/ConfigurationServerImpl.java b/server/src/main/java/com/cloud/server/ConfigurationServerImpl.java index c4bcb4ecfb4..88a0dc3bf54 100644 --- a/server/src/main/java/com/cloud/server/ConfigurationServerImpl.java +++ b/server/src/main/java/com/cloud/server/ConfigurationServerImpl.java @@ -225,11 +225,11 @@ public class ConfigurationServerImpl extends ManagerBase implements Configuratio createServiceOffering(User.UID_SYSTEM, "Small Instance", 1, 512, 500, "Small Instance", ProvisioningType.THIN, false, false, null); createServiceOffering(User.UID_SYSTEM, "Medium Instance", 1, 1024, 1000, "Medium Instance", ProvisioningType.THIN, false, false, null); // Save default disk offerings - createdefaultDiskOffering(null, "Small", "Small Disk, 5 GB", ProvisioningType.THIN, 5, null, false, false); - createdefaultDiskOffering(null, "Medium", "Medium Disk, 20 GB", ProvisioningType.THIN, 20, null, false, false); - createdefaultDiskOffering(null, "Large", "Large Disk, 100 GB", ProvisioningType.THIN, 100, null, false, false); - createdefaultDiskOffering(null, "Large", "Large Disk, 100 GB", ProvisioningType.THIN, 100, null, false, false); - createdefaultDiskOffering(null, "Custom", "Custom Disk", ProvisioningType.THIN, 0, null, true, false); + createDefaultDiskOffering("Small", "Small Disk, 5 GB", ProvisioningType.THIN, 5, null, false, false); + createDefaultDiskOffering("Medium", "Medium Disk, 20 GB", ProvisioningType.THIN, 20, null, false, false); + createDefaultDiskOffering("Large", "Large Disk, 100 GB", ProvisioningType.THIN, 100, null, false, false); + createDefaultDiskOffering("Large", "Large Disk, 100 GB", ProvisioningType.THIN, 100, null, false, false); + createDefaultDiskOffering("Custom", "Custom Disk", ProvisioningType.THIN, 0, null, true, false); // Save the mount parent to the configuration table String mountParent = getMountParent(); @@ -920,13 +920,13 @@ public class ConfigurationServerImpl extends ManagerBase implements Configuratio return pod; } - private DiskOfferingVO createdefaultDiskOffering(Long domainId, String name, String description, ProvisioningType provisioningType, - int numGibibytes, String tags, boolean isCustomized, boolean isSystemUse) { + private DiskOfferingVO createDefaultDiskOffering(String name, String description, ProvisioningType provisioningType, + int numGibibytes, String tags, boolean isCustomized, boolean isSystemUse) { long diskSize = numGibibytes; diskSize = diskSize * 1024 * 1024 * 1024; tags = cleanupTags(tags); - DiskOfferingVO newDiskOffering = new DiskOfferingVO(domainId, name, description, provisioningType, diskSize, tags, isCustomized, null, null, null); + DiskOfferingVO newDiskOffering = new DiskOfferingVO(name, description, provisioningType, diskSize, tags, isCustomized, null, null, null); newDiskOffering.setUniqueName("Cloud.Com-" + name); // leaving the above reference to cloud.com in as it is an identifyer and has no real world relevance newDiskOffering.setSystemUse(isSystemUse); diff --git a/server/src/main/java/com/cloud/storage/VolumeApiServiceImpl.java b/server/src/main/java/com/cloud/storage/VolumeApiServiceImpl.java index 2022d5b5be1..5f3ab4c8116 100644 --- a/server/src/main/java/com/cloud/storage/VolumeApiServiceImpl.java +++ b/server/src/main/java/com/cloud/storage/VolumeApiServiceImpl.java @@ -440,11 +440,7 @@ public class VolumeApiServiceImpl extends ManagerBase implements VolumeApiServic throw new InvalidParameterValueException("Please specify a custom sized disk offering."); } - if (diskOffering.getDomainId() == null) { - // do nothing as offering is public - } else { - _configMgr.checkDiskOfferingAccess(volumeOwner, diskOffering); - } + _configMgr.checkDiskOfferingAccess(volumeOwner, diskOffering, zone); } return false; @@ -617,11 +613,7 @@ public class VolumeApiServiceImpl extends ManagerBase implements VolumeApiServic throw new InvalidParameterValueException("This disk offering does not allow custom size"); } - if (diskOffering.getDomainId() == null) { - // do nothing as offering is public - } else { - _configMgr.checkDiskOfferingAccess(caller, diskOffering); - } + _configMgr.checkDiskOfferingAccess(owner, diskOffering, _dcDao.findById(zoneId)); if (diskOffering.getDiskSize() > 0) { size = diskOffering.getDiskSize(); @@ -679,6 +671,8 @@ public class VolumeApiServiceImpl extends ManagerBase implements VolumeApiServic zoneId = snapshotCheck.getDataCenterId(); } + _configMgr.checkDiskOfferingAccess(null, diskOffering, _dcDao.findById(zoneId)); + if (diskOffering == null) { // Pure snapshot is being used to create volume. diskOfferingId = snapshotCheck.getDiskOfferingId(); diskOffering = _diskOfferingDao.findById(diskOfferingId); @@ -968,10 +962,7 @@ public class VolumeApiServiceImpl extends ManagerBase implements VolumeApiServic throw new InvalidParameterValueException("There are no tags on the current disk offering. The new disk offering needs to have no tags, as well."); } - if (newDiskOffering.getDomainId() != null) { - // not a public offering; check access - _configMgr.checkDiskOfferingAccess(CallContext.current().getCallingAccount(), newDiskOffering); - } + _configMgr.checkDiskOfferingAccess(_accountMgr.getActiveAccountById(volume.getAccountId()), newDiskOffering, _dcDao.findById(volume.getDataCenterId())); if (newDiskOffering.isCustomized()) { newSize = cmd.getSize(); @@ -2205,7 +2196,12 @@ public class VolumeApiServiceImpl extends ManagerBase implements VolumeApiServic throw new InvalidParameterValueException(String.format("We cannot assign a removed disk offering [id=%s] to a volume. ", newDiskOffering.getUuid())); } Account caller = CallContext.current().getCallingAccount(); - _accountMgr.checkAccess(caller, newDiskOffering); + DataCenter zone = null; + Volume volume = _volsDao.findById(cmd.getId()); + if (volume != null) { + zone = _dcDao.findById(volume.getDataCenterId()); + } + _accountMgr.checkAccess(caller, newDiskOffering, zone); return newDiskOffering; } diff --git a/server/src/main/java/com/cloud/test/DatabaseConfig.java b/server/src/main/java/com/cloud/test/DatabaseConfig.java index 657eb4e4ce5..9a40543faea 100644 --- a/server/src/main/java/com/cloud/test/DatabaseConfig.java +++ b/server/src/main/java/com/cloud/test/DatabaseConfig.java @@ -37,6 +37,16 @@ import javax.xml.parsers.ParserConfigurationException; import javax.xml.parsers.SAXParser; import javax.xml.parsers.SAXParserFactory; +import org.apache.cloudstack.utils.security.DigestHelper; +import org.apache.log4j.Logger; +import org.apache.log4j.xml.DOMConfigurator; +import org.w3c.dom.Document; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; +import org.xml.sax.Attributes; +import org.xml.sax.SAXException; +import org.xml.sax.helpers.DefaultHandler; + import com.cloud.host.Status; import com.cloud.service.ServiceOfferingVO; import com.cloud.service.dao.ServiceOfferingDaoImpl; @@ -52,15 +62,6 @@ import com.cloud.utils.db.TransactionCallbackWithExceptionNoReturn; import com.cloud.utils.db.TransactionLegacy; import com.cloud.utils.db.TransactionStatus; import com.cloud.utils.net.NfsUtils; -import org.apache.cloudstack.utils.security.DigestHelper; -import org.apache.log4j.Logger; -import org.apache.log4j.xml.DOMConfigurator; -import org.w3c.dom.Document; -import org.w3c.dom.Node; -import org.w3c.dom.NodeList; -import org.xml.sax.Attributes; -import org.xml.sax.SAXException; -import org.xml.sax.helpers.DefaultHandler; public class DatabaseConfig { private static final Logger s_logger = Logger.getLogger(DatabaseConfig.class.getName()); @@ -983,7 +984,6 @@ public class DatabaseConfig { @DB protected void saveDiskOffering() { long id = Long.parseLong(_currentObjectParams.get("id")); - long domainId = Long.parseLong(_currentObjectParams.get("domainId")); String name = _currentObjectParams.get("name"); String displayText = _currentObjectParams.get("displayText"); ProvisioningType provisioningType = ProvisioningType.valueOf(_currentObjectParams.get("provisioningtype")); @@ -1006,7 +1006,7 @@ public class DatabaseConfig { newTags.delete(newTags.length() - 1, newTags.length()); tags = newTags.toString(); } - DiskOfferingVO diskOffering = new DiskOfferingVO(domainId, name, displayText, provisioningType, diskSpace, tags, false, null, null, null); + DiskOfferingVO diskOffering = new DiskOfferingVO(name, displayText, provisioningType, diskSpace, tags, false, null, null, null); diskOffering.setUseLocalStorage(local); Long bytesReadRate = Long.parseLong(_currentObjectParams.get("bytesReadRate")); diff --git a/server/src/main/java/com/cloud/user/AccountManagerImpl.java b/server/src/main/java/com/cloud/user/AccountManagerImpl.java index b71d548c4d5..20d769f09ef 100644 --- a/server/src/main/java/com/cloud/user/AccountManagerImpl.java +++ b/server/src/main/java/com/cloud/user/AccountManagerImpl.java @@ -77,6 +77,7 @@ import com.cloud.configuration.ResourceCountVO; import com.cloud.configuration.ResourceLimit; import com.cloud.configuration.dao.ResourceCountDao; import com.cloud.configuration.dao.ResourceLimitDao; +import com.cloud.dc.DataCenter; import com.cloud.dc.DataCenterVO; import com.cloud.dc.DedicatedResourceVO; import com.cloud.dc.dao.DataCenterDao; @@ -114,9 +115,11 @@ import com.cloud.network.security.SecurityGroupManager; import com.cloud.network.security.dao.SecurityGroupDao; import com.cloud.network.vpc.Vpc; import com.cloud.network.vpc.VpcManager; +import com.cloud.network.vpc.VpcOffering; import com.cloud.network.vpn.RemoteAccessVpnService; import com.cloud.network.vpn.Site2SiteVpnManager; import com.cloud.offering.DiskOffering; +import com.cloud.offering.NetworkOffering; import com.cloud.offering.ServiceOffering; import com.cloud.projects.Project; import com.cloud.projects.Project.ListProjectResourcesCriteria; @@ -2828,9 +2831,9 @@ public class AccountManagerImpl extends ManagerBase implements AccountManager, M } @Override - public void checkAccess(Account account, ServiceOffering so) throws PermissionDeniedException { + public void checkAccess(Account account, ServiceOffering so, DataCenter zone) throws PermissionDeniedException { for (SecurityChecker checker : _securityCheckers) { - if (checker.checkAccess(account, so)) { + if (checker.checkAccess(account, so, zone)) { if (s_logger.isDebugEnabled()) { s_logger.debug("Access granted to " + account + " to " + so + " by " + checker.getName()); } @@ -2843,9 +2846,9 @@ public class AccountManagerImpl extends ManagerBase implements AccountManager, M } @Override - public void checkAccess(Account account, DiskOffering dof) throws PermissionDeniedException { + public void checkAccess(Account account, DiskOffering dof, DataCenter zone) throws PermissionDeniedException { for (SecurityChecker checker : _securityCheckers) { - if (checker.checkAccess(account, dof)) { + if (checker.checkAccess(account, dof, zone)) { if (s_logger.isDebugEnabled()) { s_logger.debug("Access granted to " + account + " to " + dof + " by " + checker.getName()); } @@ -2857,6 +2860,36 @@ public class AccountManagerImpl extends ManagerBase implements AccountManager, M throw new PermissionDeniedException("There's no way to confirm " + account + " has access to " + dof); } + @Override + public void checkAccess(Account account, NetworkOffering nof, DataCenter zone) throws PermissionDeniedException { + for (SecurityChecker checker : _securityCheckers) { + if (checker.checkAccess(account, nof, zone)) { + if (s_logger.isDebugEnabled()) { + s_logger.debug("Access granted to " + account + " to " + nof + " by " + checker.getName()); + } + return; + } + } + + assert false : "How can all of the security checkers pass on checking this caller?"; + throw new PermissionDeniedException("There's no way to confirm " + account + " has access to " + nof); + } + + @Override + public void checkAccess(Account account, VpcOffering vof, DataCenter zone) throws PermissionDeniedException { + for (SecurityChecker checker : _securityCheckers) { + if (checker.checkAccess(account, vof, zone)) { + if (s_logger.isDebugEnabled()) { + s_logger.debug("Access granted to " + account + " to " + vof + " by " + checker.getName()); + } + return; + } + } + + assert false : "How can all of the security checkers pass on checking this caller?"; + throw new PermissionDeniedException("There's no way to confirm " + account + " has access to " + vof); + } + @Override public void checkAccess(User user, ControlledEntity entity) throws PermissionDeniedException { for (SecurityChecker checker : _securityCheckers) { diff --git a/server/src/main/java/com/cloud/user/DomainManagerImpl.java b/server/src/main/java/com/cloud/user/DomainManagerImpl.java index 60c48fa574e..4c2955925b9 100644 --- a/server/src/main/java/com/cloud/user/DomainManagerImpl.java +++ b/server/src/main/java/com/cloud/user/DomainManagerImpl.java @@ -16,6 +16,7 @@ // under the License. package com.cloud.user; +import java.util.ArrayList; import java.util.HashSet; import java.util.List; import java.util.Set; @@ -23,6 +24,7 @@ import java.util.UUID; import javax.inject.Inject; +import org.apache.cloudstack.api.ApiConstants; import org.apache.cloudstack.api.command.admin.domain.ListDomainChildrenCmd; import org.apache.cloudstack.api.command.admin.domain.ListDomainsCmd; import org.apache.cloudstack.api.command.admin.domain.UpdateDomainCmd; @@ -31,11 +33,16 @@ import org.apache.cloudstack.engine.orchestration.service.NetworkOrchestrationSe import org.apache.cloudstack.framework.messagebus.MessageBus; import org.apache.cloudstack.framework.messagebus.PublishScope; import org.apache.cloudstack.region.RegionManager; +import org.apache.cloudstack.resourcedetail.dao.DiskOfferingDetailsDao; import org.apache.commons.collections.CollectionUtils; import org.apache.commons.lang.BooleanUtils; import org.apache.log4j.Logger; import org.springframework.stereotype.Component; +import com.cloud.api.query.dao.DiskOfferingJoinDao; +import com.cloud.api.query.dao.ServiceOfferingJoinDao; +import com.cloud.api.query.vo.DiskOfferingJoinVO; +import com.cloud.api.query.vo.ServiceOfferingJoinVO; import com.cloud.configuration.ConfigurationManager; import com.cloud.configuration.Resource.ResourceOwnerType; import com.cloud.configuration.ResourceLimit; @@ -56,9 +63,8 @@ import com.cloud.network.dao.NetworkDomainDao; import com.cloud.projects.ProjectManager; import com.cloud.projects.ProjectVO; import com.cloud.projects.dao.ProjectDao; -import com.cloud.service.ServiceOfferingVO; import com.cloud.service.dao.ServiceOfferingDao; -import com.cloud.storage.DiskOfferingVO; +import com.cloud.service.dao.ServiceOfferingDetailsDao; import com.cloud.storage.dao.DiskOfferingDao; import com.cloud.user.dao.AccountDao; import com.cloud.utils.Pair; @@ -91,9 +97,17 @@ public class DomainManagerImpl extends ManagerBase implements DomainManager, Dom @Inject private AccountDao _accountDao; @Inject - private DiskOfferingDao _diskOfferingDao; + private DiskOfferingJoinDao diskOfferingJoinDao; @Inject - private ServiceOfferingDao _offeringsDao; + private DiskOfferingDao diskOfferingDao; + @Inject + private DiskOfferingDetailsDao diskOfferingDetailsDao; + @Inject + private ServiceOfferingJoinDao serviceOfferingJoinDao; + @Inject + private ServiceOfferingDao serviceOfferingDao; + @Inject + private ServiceOfferingDetailsDao serviceOfferingDetailsDao; @Inject private ProjectDao _projectDao; @Inject @@ -434,15 +448,38 @@ public class DomainManagerImpl extends ManagerBase implements DomainManager, Dom } protected void cleanupDomainOfferings(Long domainId) { - // delete the service and disk offerings associated with this domain - List diskOfferingsForThisDomain = _diskOfferingDao.listByDomainId(domainId); - for (DiskOfferingVO diskOffering : diskOfferingsForThisDomain) { - _diskOfferingDao.remove(diskOffering.getId()); + if (domainId == null) { + return; } - List serviceOfferingsForThisDomain = _offeringsDao.findServiceOfferingByDomainId(domainId); - for (ServiceOfferingVO serviceOffering : serviceOfferingsForThisDomain) { - _offeringsDao.remove(serviceOffering.getId()); + String domainIdString = String.valueOf(domainId); + List diskOfferingsDetailsToRemove = new ArrayList<>(); + List serviceOfferingsDetailsToRemove = new ArrayList<>(); + + // delete the service and disk offerings associated with this domain + List diskOfferingsForThisDomain = diskOfferingJoinDao.findByDomainId(domainId); + for (DiskOfferingJoinVO diskOffering : diskOfferingsForThisDomain) { + if (domainIdString.equals(diskOffering.getDomainId())) { + diskOfferingDao.remove(diskOffering.getId()); + } else { + diskOfferingsDetailsToRemove.add(diskOffering.getId()); + } + } + List serviceOfferingsForThisDomain = serviceOfferingJoinDao.findByDomainId(domainId); + for (ServiceOfferingJoinVO serviceOffering : serviceOfferingsForThisDomain) { + if (domainIdString.equals(serviceOffering.getDomainId())) { + serviceOfferingDao.remove(serviceOffering.getId()); + } else { + serviceOfferingsDetailsToRemove.add(serviceOffering.getId()); + } + } + + // Remove domain IDs for offerings which may be multi-domain + for (final Long diskOfferingId : diskOfferingsDetailsToRemove) { + diskOfferingDetailsDao.removeDetail(diskOfferingId, ApiConstants.DOMAIN_ID, domainIdString); + } + for (final Long serviceOfferingId : serviceOfferingsDetailsToRemove) { + serviceOfferingDetailsDao.removeDetail(serviceOfferingId, ApiConstants.DOMAIN_ID, domainIdString); } } diff --git a/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java b/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java index a1a552db8d5..2843d6e456d 100644 --- a/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java +++ b/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java @@ -1125,7 +1125,7 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir // Check if the new service offering can be applied to vm instance ServiceOffering newSvcOffering = _offeringDao.findById(svcOffId); Account owner = _accountMgr.getActiveAccountById(vmInstance.getAccountId()); - _accountMgr.checkAccess(owner, newSvcOffering); + _accountMgr.checkAccess(owner, newSvcOffering, _dcDao.findById(vmInstance.getDataCenterId())); _itMgr.upgradeVmDb(vmId, svcOffId); if (newServiceOffering.isDynamic()) { @@ -3067,8 +3067,8 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir _accountMgr.checkAccess(caller, null, true, owner); // Verify that owner can use the service offering - _accountMgr.checkAccess(owner, serviceOffering); - _accountMgr.checkAccess(owner, _diskOfferingDao.findById(diskOfferingId)); + _accountMgr.checkAccess(owner, serviceOffering, zone); + _accountMgr.checkAccess(owner, _diskOfferingDao.findById(diskOfferingId), zone); // Get default guest network in Basic zone Network defaultNetwork = _networkModel.getExclusiveGuestNetwork(zone.getId()); @@ -3126,8 +3126,8 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir _accountMgr.checkAccess(caller, null, true, owner); // Verify that owner can use the service offering - _accountMgr.checkAccess(owner, serviceOffering); - _accountMgr.checkAccess(owner, _diskOfferingDao.findById(diskOfferingId)); + _accountMgr.checkAccess(owner, serviceOffering, zone); + _accountMgr.checkAccess(owner, _diskOfferingDao.findById(diskOfferingId), zone); // If no network is specified, find system security group enabled network if (networkIdList == null || networkIdList.isEmpty()) { @@ -3234,8 +3234,8 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir _accountMgr.checkAccess(caller, null, true, owner); // Verify that owner can use the service offering - _accountMgr.checkAccess(owner, serviceOffering); - _accountMgr.checkAccess(owner, _diskOfferingDao.findById(diskOfferingId)); + _accountMgr.checkAccess(owner, serviceOffering, zone); + _accountMgr.checkAccess(owner, _diskOfferingDao.findById(diskOfferingId), zone); List vpcSupportedHTypes = _vpcMgr.getSupportedVpcHypervisors(); if (networkIdList == null || networkIdList.isEmpty()) { diff --git a/server/src/test/java/com/cloud/configuration/ConfigurationManagerTest.java b/server/src/test/java/com/cloud/configuration/ConfigurationManagerTest.java index 8648033c9b0..a7a9d2aae53 100644 --- a/server/src/test/java/com/cloud/configuration/ConfigurationManagerTest.java +++ b/server/src/test/java/com/cloud/configuration/ConfigurationManagerTest.java @@ -17,6 +17,18 @@ package com.cloud.configuration; +import static org.hamcrest.CoreMatchers.is; +import static org.junit.Assert.assertThat; +import static org.mockito.Matchers.any; +import static org.mockito.Matchers.anyBoolean; +import static org.mockito.Matchers.anyInt; +import static org.mockito.Matchers.anyLong; +import static org.mockito.Matchers.anyString; +import static org.mockito.Mockito.doNothing; +import static org.mockito.Mockito.doThrow; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + import java.lang.reflect.Field; import java.util.ArrayList; import java.util.Arrays; @@ -26,16 +38,6 @@ import java.util.Map; import java.util.Random; import java.util.UUID; -import org.apache.log4j.Logger; -import org.junit.After; -import org.junit.Assert; -import org.junit.Before; -import org.junit.Test; -import org.mockito.InjectMocks; -import org.mockito.Mock; -import org.mockito.Mockito; -import org.mockito.MockitoAnnotations; - import org.apache.cloudstack.api.command.admin.vlan.DedicatePublicIpRangeCmd; import org.apache.cloudstack.api.command.admin.vlan.ReleasePublicIpRangeCmd; import org.apache.cloudstack.api.command.user.network.ListNetworkOfferingsCmd; @@ -45,7 +47,18 @@ import org.apache.cloudstack.engine.subsystem.api.storage.ZoneScope; import org.apache.cloudstack.framework.config.dao.ConfigurationDao; import org.apache.cloudstack.storage.datastore.db.ImageStoreDao; import org.apache.cloudstack.storage.datastore.db.ImageStoreVO; +import org.apache.log4j.Logger; +import org.junit.After; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.Mockito; +import org.mockito.MockitoAnnotations; +import com.cloud.api.query.dao.NetworkOfferingJoinDao; +import com.cloud.api.query.vo.NetworkOfferingJoinVO; import com.cloud.configuration.Resource.ResourceType; import com.cloud.dc.AccountVlanMapVO; import com.cloud.dc.ClusterVO; @@ -68,15 +81,11 @@ import com.cloud.network.IpAddressManager; import com.cloud.network.Network; import com.cloud.network.Network.Capability; import com.cloud.network.NetworkModel; -import com.cloud.network.Networks; import com.cloud.network.dao.FirewallRulesDao; import com.cloud.network.dao.IPAddressDao; import com.cloud.network.dao.IPAddressVO; import com.cloud.network.dao.PhysicalNetworkDao; import com.cloud.network.dao.PhysicalNetworkVO; -import com.cloud.offering.NetworkOffering; -import com.cloud.offerings.NetworkOfferingVO; -import com.cloud.offerings.dao.NetworkOfferingDao; import com.cloud.projects.ProjectManager; import com.cloud.storage.VolumeVO; import com.cloud.storage.dao.VolumeDao; @@ -95,18 +104,6 @@ import com.cloud.utils.net.Ip; import com.cloud.vm.VMInstanceVO; import com.cloud.vm.dao.VMInstanceDao; -import static org.hamcrest.CoreMatchers.is; -import static org.hamcrest.MatcherAssert.assertThat; -import static org.mockito.Matchers.any; -import static org.mockito.Matchers.anyBoolean; -import static org.mockito.Matchers.anyInt; -import static org.mockito.Matchers.anyLong; -import static org.mockito.Matchers.anyString; -import static org.mockito.Mockito.doNothing; -import static org.mockito.Mockito.doThrow; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; - public class ConfigurationManagerTest { private static final Logger s_logger = Logger.getLogger(ConfigurationManagerTest.class); @@ -129,7 +126,7 @@ public class ConfigurationManagerTest { @Mock NetworkOrchestrationService _networkMgr; @Mock - NetworkOfferingDao _networkOfferingDao; + NetworkOfferingJoinDao networkOfferingJoinDao; @Mock AccountDao _accountDao; @Mock @@ -490,14 +487,16 @@ public class ConfigurationManagerTest { @Test public void searchForNetworkOfferingsTest() { - List offerings = Arrays.asList( - new NetworkOfferingVO("off1", "off1", Networks.TrafficType.Guest, false, false, null, null, false, NetworkOffering.Availability.Optional, null, Network.GuestType.Isolated, true, false, false, false, false, false), - new NetworkOfferingVO("off2", "off2", Networks.TrafficType.Guest, false, false, null, null, false, NetworkOffering.Availability.Optional, null, Network.GuestType.Isolated, true, false, false, false, false, false), - new NetworkOfferingVO("off3", "off3", Networks.TrafficType.Guest, false, false, null, null, false, NetworkOffering.Availability.Optional, null, Network.GuestType.Isolated, true, false, false, false, false, true) + NetworkOfferingJoinVO forVpcOfferingJoinVO = new NetworkOfferingJoinVO(); + forVpcOfferingJoinVO.setForVpc(true); + List offerings = Arrays.asList( + new NetworkOfferingJoinVO(), + new NetworkOfferingJoinVO(), + forVpcOfferingJoinVO ); - Mockito.when(_networkOfferingDao.createSearchCriteria()).thenReturn(Mockito.mock(SearchCriteria.class)); - Mockito.when(_networkOfferingDao.search(Mockito.any(SearchCriteria.class), Mockito.any(Filter.class))).thenReturn(offerings); + Mockito.when(networkOfferingJoinDao.createSearchCriteria()).thenReturn(Mockito.mock(SearchCriteria.class)); + Mockito.when(networkOfferingJoinDao.search(Mockito.any(SearchCriteria.class), Mockito.any(Filter.class))).thenReturn(offerings); ListNetworkOfferingsCmd cmd = Mockito.spy(ListNetworkOfferingsCmd.class); Mockito.when(cmd.getPageSize()).thenReturn(10); diff --git a/server/src/test/java/com/cloud/user/AccountManagerImplTest.java b/server/src/test/java/com/cloud/user/AccountManagerImplTest.java index e730277bd54..9bf0ae82ecb 100644 --- a/server/src/test/java/com/cloud/user/AccountManagerImplTest.java +++ b/server/src/test/java/com/cloud/user/AccountManagerImplTest.java @@ -94,7 +94,7 @@ public class AccountManagerImplTest extends AccountManagetImplTestBase { @Test public void disableAccountNotexisting() throws ConcurrentOperationException, ResourceUnavailableException { - Mockito.when(accountDaoMock.findById(42l)).thenReturn(null); + Mockito.when(_accountDao.findById(42l)).thenReturn(null); Assert.assertTrue(accountManagerImpl.disableAccount(42)); } @@ -102,7 +102,7 @@ public class AccountManagerImplTest extends AccountManagetImplTestBase { public void disableAccountDisabled() throws ConcurrentOperationException, ResourceUnavailableException { AccountVO disabledAccount = new AccountVO(); disabledAccount.setState(State.disabled); - Mockito.when(accountDaoMock.findById(42l)).thenReturn(disabledAccount); + Mockito.when(_accountDao.findById(42l)).thenReturn(disabledAccount); Assert.assertTrue(accountManagerImpl.disableAccount(42)); } @@ -110,12 +110,12 @@ public class AccountManagerImplTest extends AccountManagetImplTestBase { public void disableAccount() throws ConcurrentOperationException, ResourceUnavailableException { AccountVO account = new AccountVO(); account.setState(State.enabled); - Mockito.when(accountDaoMock.findById(42l)).thenReturn(account); - Mockito.when(accountDaoMock.createForUpdate()).thenReturn(new AccountVO()); - Mockito.when(accountDaoMock.update(Mockito.eq(42l), Mockito.any(AccountVO.class))).thenReturn(true); + Mockito.when(_accountDao.findById(42l)).thenReturn(account); + Mockito.when(_accountDao.createForUpdate()).thenReturn(new AccountVO()); + Mockito.when(_accountDao.update(Mockito.eq(42l), Mockito.any(AccountVO.class))).thenReturn(true); Mockito.when(_vmDao.listByAccountId(42l)).thenReturn(Arrays.asList(Mockito.mock(VMInstanceVO.class))); Assert.assertTrue(accountManagerImpl.disableAccount(42)); - Mockito.verify(accountDaoMock, Mockito.atLeastOnce()).update(Mockito.eq(42l), Mockito.any(AccountVO.class)); + Mockito.verify(_accountDao, Mockito.atLeastOnce()).update(Mockito.eq(42l), Mockito.any(AccountVO.class)); } @Test @@ -123,9 +123,9 @@ public class AccountManagerImplTest extends AccountManagetImplTestBase { AccountVO account = new AccountVO(); account.setId(42l); DomainVO domain = new DomainVO(); - Mockito.when(accountDaoMock.findById(42l)).thenReturn(account); + Mockito.when(_accountDao.findById(42l)).thenReturn(account); Mockito.when(securityChecker.checkAccess(Mockito.any(Account.class), Mockito.any(ControlledEntity.class), Mockito.any(AccessType.class), Mockito.anyString())).thenReturn(true); - Mockito.when(accountDaoMock.remove(42l)).thenReturn(true); + Mockito.when(_accountDao.remove(42l)).thenReturn(true); Mockito.when(_configMgr.releaseAccountSpecificVirtualRanges(42l)).thenReturn(true); Mockito.when(_domainMgr.getDomain(Mockito.anyLong())).thenReturn(domain); Mockito.when(securityChecker.checkAccess(Mockito.any(Account.class), Mockito.any(Domain.class))).thenReturn(true); @@ -140,7 +140,7 @@ public class AccountManagerImplTest extends AccountManagetImplTestBase { Assert.assertTrue(accountManagerImpl.deleteUserAccount(42)); // assert that this was a clean delete - Mockito.verify(accountDaoMock, Mockito.never()).markForCleanup(Mockito.eq(42l)); + Mockito.verify(_accountDao, Mockito.never()).markForCleanup(Mockito.eq(42l)); } @Test @@ -148,9 +148,9 @@ public class AccountManagerImplTest extends AccountManagetImplTestBase { AccountVO account = new AccountVO(); account.setId(42l); DomainVO domain = new DomainVO(); - Mockito.when(accountDaoMock.findById(42l)).thenReturn(account); + Mockito.when(_accountDao.findById(42l)).thenReturn(account); Mockito.when(securityChecker.checkAccess(Mockito.any(Account.class), Mockito.any(ControlledEntity.class), Mockito.any(AccessType.class), Mockito.anyString())).thenReturn(true); - Mockito.when(accountDaoMock.remove(42l)).thenReturn(true); + Mockito.when(_accountDao.remove(42l)).thenReturn(true); Mockito.when(_configMgr.releaseAccountSpecificVirtualRanges(42l)).thenReturn(true); Mockito.when(_userVmDao.listByAccountId(42l)).thenReturn(Arrays.asList(Mockito.mock(UserVmVO.class))); Mockito.when(_vmMgr.expunge(Mockito.any(UserVmVO.class), Mockito.anyLong(), Mockito.any(Account.class))).thenReturn(false); @@ -159,7 +159,7 @@ public class AccountManagerImplTest extends AccountManagetImplTestBase { Assert.assertTrue(accountManagerImpl.deleteUserAccount(42)); // assert that this was NOT a clean delete - Mockito.verify(accountDaoMock, Mockito.atLeastOnce()).markForCleanup(Mockito.eq(42l)); + Mockito.verify(_accountDao, Mockito.atLeastOnce()).markForCleanup(Mockito.eq(42l)); } @Test @@ -204,7 +204,7 @@ public class AccountManagerImplTest extends AccountManagetImplTestBase { Mockito.when(accountManagerImpl.getAccount(Mockito.anyLong())).thenReturn(accountMock); // Queried account - admin account Mockito.when(callingUser.getAccountId()).thenReturn(1L); - Mockito.when(accountDaoMock.findById(1L)).thenReturn(callingAccount); + Mockito.when(_accountDao.findById(1L)).thenReturn(callingAccount); Mockito.when(accountService.isNormalUser(Mockito.anyLong())).thenReturn(Boolean.TRUE); Mockito.when(accountMock.getAccountId()).thenReturn(2L); @@ -277,7 +277,7 @@ public class AccountManagerImplTest extends AccountManagetImplTestBase { public void validateAndUpdatApiAndSecretKeyIfNeededTestNoKeys() { accountManagerImpl.validateAndUpdateApiAndSecretKeyIfNeeded(UpdateUserCmdMock, userVoMock); - Mockito.verify(accountDaoMock, Mockito.times(0)).findUserAccountByApiKey(Mockito.anyString()); + Mockito.verify(_accountDao, Mockito.times(0)).findUserAccountByApiKey(Mockito.anyString()); } @Test(expected = InvalidParameterValueException.class) @@ -306,7 +306,7 @@ public class AccountManagerImplTest extends AccountManagetImplTestBase { Mockito.doReturn(2L).when(otherUserMock).getId(); Pair pairUserAccountMock = new Pair(otherUserMock, Mockito.mock(Account.class)); - Mockito.doReturn(pairUserAccountMock).when(accountDaoMock).findUserAccountByApiKey(apiKey); + Mockito.doReturn(pairUserAccountMock).when(_accountDao).findUserAccountByApiKey(apiKey); accountManagerImpl.validateAndUpdateApiAndSecretKeyIfNeeded(UpdateUserCmdMock, userVoMock); } @@ -325,11 +325,11 @@ public class AccountManagerImplTest extends AccountManagetImplTestBase { Mockito.doReturn(1L).when(otherUserMock).getId(); Pair pairUserAccountMock = new Pair(otherUserMock, Mockito.mock(Account.class)); - Mockito.doReturn(pairUserAccountMock).when(accountDaoMock).findUserAccountByApiKey(apiKey); + Mockito.doReturn(pairUserAccountMock).when(_accountDao).findUserAccountByApiKey(apiKey); accountManagerImpl.validateAndUpdateApiAndSecretKeyIfNeeded(UpdateUserCmdMock, userVoMock); - Mockito.verify(accountDaoMock).findUserAccountByApiKey(apiKey); + Mockito.verify(_accountDao).findUserAccountByApiKey(apiKey); Mockito.verify(userVoMock).setApiKey(apiKey); Mockito.verify(userVoMock).setSecretKey(secretKey); } @@ -338,7 +338,7 @@ public class AccountManagerImplTest extends AccountManagetImplTestBase { public void retrieveAndValidateAccountTestAccountNotFound() { Mockito.doReturn(accountMockId).when(userVoMock).getAccountId(); - Mockito.doReturn(null).when(accountDaoMock).findById(accountMockId); + Mockito.doReturn(null).when(_accountDao).findById(accountMockId); accountManagerImpl.retrieveAndValidateAccount(userVoMock); } @@ -347,7 +347,7 @@ public class AccountManagerImplTest extends AccountManagetImplTestBase { public void retrieveAndValidateAccountTestAccountTypeEqualsProjectType() { Mockito.doReturn(accountMockId).when(userVoMock).getAccountId(); Mockito.doReturn(Account.ACCOUNT_TYPE_PROJECT).when(accountMock).getType(); - Mockito.doReturn(accountMock).when(accountDaoMock).findById(accountMockId); + Mockito.doReturn(accountMock).when(_accountDao).findById(accountMockId); accountManagerImpl.retrieveAndValidateAccount(userVoMock); } @@ -356,7 +356,7 @@ public class AccountManagerImplTest extends AccountManagetImplTestBase { public void retrieveAndValidateAccountTestAccountTypeEqualsSystemType() { Mockito.doReturn(Account.ACCOUNT_ID_SYSTEM).when(userVoMock).getAccountId(); Mockito.doReturn(Account.ACCOUNT_ID_SYSTEM).when(accountMock).getId(); - Mockito.doReturn(accountMock).when(accountDaoMock).findById(Account.ACCOUNT_ID_SYSTEM); + Mockito.doReturn(accountMock).when(_accountDao).findById(Account.ACCOUNT_ID_SYSTEM); accountManagerImpl.retrieveAndValidateAccount(userVoMock); } @@ -364,7 +364,7 @@ public class AccountManagerImplTest extends AccountManagetImplTestBase { @Test public void retrieveAndValidateAccountTest() { Mockito.doReturn(accountMockId).when(userVoMock).getAccountId(); - Mockito.doReturn(accountMock).when(accountDaoMock).findById(accountMockId); + Mockito.doReturn(accountMock).when(_accountDao).findById(accountMockId); Mockito.doNothing().when(accountManagerImpl).checkAccess(Mockito.eq(accountMock), Mockito.eq(AccessType.OperateEntry), Mockito.anyBoolean(), Mockito.any(Account.class)); accountManagerImpl.retrieveAndValidateAccount(userVoMock); @@ -468,8 +468,8 @@ public class AccountManagerImplTest extends AccountManagetImplTestBase { Mockito.doReturn(usersWithSameUserName).when(userDaoMock).findUsersByName(userName); - Mockito.doReturn(accountMock).when(accountDaoMock).findById(accountMockId); - Mockito.doReturn(accountUserDuplicatedMock).when(accountDaoMock).findById(accountIdUserDuplicated); + Mockito.doReturn(accountMock).when(_accountDao).findById(accountMockId); + Mockito.doReturn(accountUserDuplicatedMock).when(_accountDao).findById(accountIdUserDuplicated); Mockito.doReturn(Mockito.mock(DomainVO.class)).when(_domainDao).findById(Mockito.anyLong()); @@ -503,8 +503,8 @@ public class AccountManagerImplTest extends AccountManagetImplTestBase { Mockito.doReturn(usersWithSameUserName).when(userDaoMock).findUsersByName(userName); - Mockito.doReturn(accountMock).when(accountDaoMock).findById(accountMockId); - Mockito.doReturn(accountUserDuplicatedMock).when(accountDaoMock).findById(accountIdUserDuplicated); + Mockito.doReturn(accountMock).when(_accountDao).findById(accountMockId); + Mockito.doReturn(accountUserDuplicatedMock).when(_accountDao).findById(accountIdUserDuplicated); accountManagerImpl.validateAndUpdateUsernameIfNeeded(UpdateUserCmdMock, userVoMock, accountMock); @@ -524,7 +524,7 @@ public class AccountManagerImplTest extends AccountManagetImplTestBase { Mockito.doReturn(usersWithSameUserName).when(userDaoMock).findUsersByName(userName); - Mockito.doReturn(accountMock).when(accountDaoMock).findById(accountMockId); + Mockito.doReturn(accountMock).when(_accountDao).findById(accountMockId); accountManagerImpl.validateAndUpdateUsernameIfNeeded(UpdateUserCmdMock, userVoMock, accountMock); @@ -634,7 +634,7 @@ public class AccountManagerImplTest extends AccountManagetImplTestBase { @Test(expected = InvalidParameterValueException.class) public void validateCurrentPasswordTestUserNotAuthenticatedWithProvidedCurrentPassword() { - Mockito.doReturn(Mockito.mock(AccountVO.class)).when(accountDaoMock).findById(accountMockId); + Mockito.doReturn(Mockito.mock(AccountVO.class)).when(_accountDao).findById(accountMockId); String newPassword = "newPassword"; configureUserMockAuthenticators(newPassword); @@ -647,7 +647,7 @@ public class AccountManagerImplTest extends AccountManagetImplTestBase { long domainId = 14l; Mockito.doReturn(domainId).when(accountVoMock).getDomainId(); - Mockito.doReturn(accountVoMock).when(accountDaoMock).findById(accountMockId); + Mockito.doReturn(accountVoMock).when(_accountDao).findById(accountMockId); String username = "username"; Mockito.doReturn(username).when(userVoMock).getUsername(); @@ -676,7 +676,7 @@ public class AccountManagerImplTest extends AccountManagetImplTestBase { long domainId = 14l; Mockito.doReturn(domainId).when(accountVoMock).getDomainId(); - Mockito.doReturn(accountVoMock).when(accountDaoMock).findById(accountMockId); + Mockito.doReturn(accountVoMock).when(_accountDao).findById(accountMockId); String username = "username"; Mockito.doReturn(username).when(userVoMock).getUsername(); diff --git a/server/src/test/java/com/cloud/user/AccountManagerImplVolumeDeleteEventTest.java b/server/src/test/java/com/cloud/user/AccountManagerImplVolumeDeleteEventTest.java index 48eb4738fef..ff97a0f1be2 100644 --- a/server/src/test/java/com/cloud/user/AccountManagerImplVolumeDeleteEventTest.java +++ b/server/src/test/java/com/cloud/user/AccountManagerImplVolumeDeleteEventTest.java @@ -106,8 +106,8 @@ public class AccountManagerImplVolumeDeleteEventTest extends AccountManagetImplT AccountVO account = new AccountVO(); account.setId(ACCOUNT_ID); - when(accountDaoMock.remove(ACCOUNT_ID)).thenReturn(true); - when(accountDaoMock.findById(ACCOUNT_ID)).thenReturn(account); + when(_accountDao.remove(ACCOUNT_ID)).thenReturn(true); + when(_accountDao.findById(ACCOUNT_ID)).thenReturn(account); DomainVO domain = new DomainVO(); VirtualMachineEntity vmEntity = mock(VirtualMachineEntity.class); diff --git a/server/src/test/java/com/cloud/user/AccountManagetImplTestBase.java b/server/src/test/java/com/cloud/user/AccountManagetImplTestBase.java index 885a23d5a99..cdade178332 100644 --- a/server/src/test/java/com/cloud/user/AccountManagetImplTestBase.java +++ b/server/src/test/java/com/cloud/user/AccountManagetImplTestBase.java @@ -83,7 +83,7 @@ import com.cloud.vm.snapshot.dao.VMSnapshotDao; public class AccountManagetImplTestBase { @Mock - AccountDao accountDaoMock; + AccountDao _accountDao; @Mock ConfigurationDao _configDao; @Mock diff --git a/server/src/test/java/com/cloud/user/DomainManagerImplTest.java b/server/src/test/java/com/cloud/user/DomainManagerImplTest.java index 03ab340a2dc..dfd1e48618e 100644 --- a/server/src/test/java/com/cloud/user/DomainManagerImplTest.java +++ b/server/src/test/java/com/cloud/user/DomainManagerImplTest.java @@ -18,6 +18,7 @@ package com.cloud.user; import java.util.ArrayList; +import java.util.Collections; import java.util.List; import java.util.UUID; @@ -37,6 +38,8 @@ import org.mockito.Mockito; import org.mockito.Spy; import org.mockito.runners.MockitoJUnitRunner; +import com.cloud.api.query.dao.DiskOfferingJoinDao; +import com.cloud.api.query.dao.ServiceOfferingJoinDao; import com.cloud.configuration.ConfigurationManager; import com.cloud.configuration.Resource.ResourceOwnerType; import com.cloud.configuration.dao.ResourceCountDao; @@ -51,10 +54,6 @@ import com.cloud.exception.PermissionDeniedException; import com.cloud.network.dao.NetworkDomainDao; import com.cloud.projects.ProjectManager; import com.cloud.projects.dao.ProjectDao; -import com.cloud.service.ServiceOfferingVO; -import com.cloud.service.dao.ServiceOfferingDao; -import com.cloud.storage.DiskOfferingVO; -import com.cloud.storage.dao.DiskOfferingDao; import com.cloud.user.dao.AccountDao; import com.cloud.utils.db.Filter; import com.cloud.utils.db.GlobalLock; @@ -72,9 +71,9 @@ public class DomainManagerImplTest { @Mock AccountDao _accountDao; @Mock - DiskOfferingDao _diskOfferingDao; + DiskOfferingJoinDao _diskOfferingDao; @Mock - ServiceOfferingDao _offeringsDao; + ServiceOfferingJoinDao _offeringsDao; @Mock ProjectDao _projectDao; @Mock @@ -253,8 +252,8 @@ public class DomainManagerImplTest { Mockito.when(_dedicatedDao.listByDomainId(Mockito.anyLong())).thenReturn(new ArrayList()); Mockito.when(_domainDao.remove(Mockito.anyLong())).thenReturn(true); Mockito.when(_configMgr.releaseDomainSpecificVirtualRanges(Mockito.anyLong())).thenReturn(true); - Mockito.when(_diskOfferingDao.listByDomainId(Mockito.anyLong())).thenReturn(new ArrayList()); - Mockito.when(_offeringsDao.findServiceOfferingByDomainId(Mockito.anyLong())).thenReturn(new ArrayList()); + Mockito.when(_diskOfferingDao.findByDomainId(Mockito.anyLong())).thenReturn(Collections.emptyList()); + Mockito.when(_offeringsDao.findByDomainId(Mockito.anyLong())).thenReturn(Collections.emptyList()); try { Assert.assertTrue(domainManager.deleteDomain(20l, false)); @@ -286,8 +285,8 @@ public class DomainManagerImplTest { Mockito.when(_resourceCountDao.removeEntriesByOwner(Mockito.anyLong(), Mockito.eq(ResourceOwnerType.Domain))).thenReturn(1l); Mockito.when(_resourceLimitDao.removeEntriesByOwner(Mockito.anyLong(), Mockito.eq(ResourceOwnerType.Domain))).thenReturn(1l); Mockito.when(_configMgr.releaseDomainSpecificVirtualRanges(Mockito.anyLong())).thenReturn(true); - Mockito.when(_diskOfferingDao.listByDomainId(Mockito.anyLong())).thenReturn(new ArrayList()); - Mockito.when(_offeringsDao.findServiceOfferingByDomainId(Mockito.anyLong())).thenReturn(new ArrayList()); + Mockito.when(_diskOfferingDao.findByDomainId(Mockito.anyLong())).thenReturn(Collections.emptyList()); + Mockito.when(_offeringsDao.findByDomainId(Mockito.anyLong())).thenReturn(Collections.emptyList()); try { Assert.assertTrue(domainManager.deleteDomain(20l, true)); diff --git a/server/src/test/java/com/cloud/user/MockAccountManagerImpl.java b/server/src/test/java/com/cloud/user/MockAccountManagerImpl.java index 9fece09f357..ea6287d2bcc 100644 --- a/server/src/test/java/com/cloud/user/MockAccountManagerImpl.java +++ b/server/src/test/java/com/cloud/user/MockAccountManagerImpl.java @@ -36,11 +36,14 @@ import org.apache.cloudstack.api.command.admin.user.RegisterCmd; import org.apache.cloudstack.api.command.admin.user.UpdateUserCmd; import com.cloud.api.query.vo.ControlledViewEntity; +import com.cloud.dc.DataCenter; import com.cloud.domain.Domain; import com.cloud.exception.ConcurrentOperationException; import com.cloud.exception.PermissionDeniedException; import com.cloud.exception.ResourceUnavailableException; +import com.cloud.network.vpc.VpcOffering; import com.cloud.offering.DiskOffering; +import com.cloud.offering.NetworkOffering; import com.cloud.offering.ServiceOffering; import com.cloud.projects.Project.ListProjectResourcesCriteria; import com.cloud.utils.Pair; @@ -212,12 +215,22 @@ public class MockAccountManagerImpl extends ManagerBase implements Manager, Acco } @Override - public void checkAccess(Account account, ServiceOffering so) throws PermissionDeniedException { + public void checkAccess(Account account, ServiceOffering so, DataCenter zone) throws PermissionDeniedException { // TODO Auto-generated method stub } @Override - public void checkAccess(Account account, DiskOffering dof) throws PermissionDeniedException { + public void checkAccess(Account account, DiskOffering dof, DataCenter zone) throws PermissionDeniedException { + // TODO Auto-generated method stub + } + + @Override + public void checkAccess(Account account, NetworkOffering nof, DataCenter zone) throws PermissionDeniedException { + // TODO Auto-generated method stub + } + + @Override + public void checkAccess(Account account, VpcOffering vof, DataCenter zone) throws PermissionDeniedException { // TODO Auto-generated method stub } diff --git a/server/src/test/java/com/cloud/vm/DeploymentPlanningManagerImplTest.java b/server/src/test/java/com/cloud/vm/DeploymentPlanningManagerImplTest.java index 5d8f9ad2159..1d1ab89d835 100644 --- a/server/src/test/java/com/cloud/vm/DeploymentPlanningManagerImplTest.java +++ b/server/src/test/java/com/cloud/vm/DeploymentPlanningManagerImplTest.java @@ -143,7 +143,6 @@ public class DeploymentPlanningManagerImplTest { @Mock Host host; - private static long domainId = 5L; private static long dataCenterId = 1L; private static long hostId = 1l; @@ -186,8 +185,8 @@ public class DeploymentPlanningManagerImplTest { public void dataCenterAvoidTest() throws InsufficientServerCapacityException, AffinityConflictException { ServiceOfferingVO svcOffering = new ServiceOfferingVO("testOffering", 1, 512, 500, 1, 1, false, false, false, "test dpm", - ProvisioningType.THIN, false, false, null, false, VirtualMachine.Type.User, domainId, - null, "FirstFitPlanner"); + ProvisioningType.THIN, false, false, null, false, VirtualMachine.Type.User, + null, "FirstFitPlanner"); Mockito.when(vmProfile.getServiceOffering()).thenReturn(svcOffering); DataCenterDeployment plan = new DataCenterDeployment(dataCenterId); @@ -201,8 +200,8 @@ public class DeploymentPlanningManagerImplTest { public void plannerCannotHandleTest() throws InsufficientServerCapacityException, AffinityConflictException { ServiceOfferingVO svcOffering = new ServiceOfferingVO("testOffering", 1, 512, 500, 1, 1, false, false, false, "test dpm", - ProvisioningType.THIN, false, false, null, false, VirtualMachine.Type.User, domainId, - null, "UserDispersingPlanner"); + ProvisioningType.THIN, false, false, null, false, VirtualMachine.Type.User, + null, "UserDispersingPlanner"); Mockito.when(vmProfile.getServiceOffering()).thenReturn(svcOffering); DataCenterDeployment plan = new DataCenterDeployment(dataCenterId); @@ -217,8 +216,8 @@ public class DeploymentPlanningManagerImplTest { public void emptyClusterListTest() throws InsufficientServerCapacityException, AffinityConflictException { ServiceOfferingVO svcOffering = new ServiceOfferingVO("testOffering", 1, 512, 500, 1, 1, false, false, false, "test dpm", - ProvisioningType.THIN, false, false, null, false, VirtualMachine.Type.User, domainId, - null, "FirstFitPlanner"); + ProvisioningType.THIN, false, false, null, false, VirtualMachine.Type.User, + null, "FirstFitPlanner"); Mockito.when(vmProfile.getServiceOffering()).thenReturn(svcOffering); DataCenterDeployment plan = new DataCenterDeployment(dataCenterId); diff --git a/server/src/test/java/com/cloud/vpc/MockConfigurationManagerImpl.java b/server/src/test/java/com/cloud/vpc/MockConfigurationManagerImpl.java index 9057241cc78..b42996bb02b 100644 --- a/server/src/test/java/com/cloud/vpc/MockConfigurationManagerImpl.java +++ b/server/src/test/java/com/cloud/vpc/MockConfigurationManagerImpl.java @@ -125,6 +125,18 @@ public class MockConfigurationManagerImpl extends ManagerBase implements Configu return false; } + @Override + public List getServiceOfferingDomains(Long serviceOfferingId) { + // TODO Auto-generated method stub + return null; + } + + @Override + public List getServiceOfferingZones(Long serviceOfferingId) { + // TODO Auto-generated method stub + return null; + } + /* (non-Javadoc) * @see com.cloud.configuration.ConfigurationService#updateDiskOffering(org.apache.cloudstack.api.commands.UpdateDiskOfferingCmd) */ @@ -152,6 +164,18 @@ public class MockConfigurationManagerImpl extends ManagerBase implements Configu return null; } + @Override + public List getDiskOfferingDomains(Long diskOfferingId) { + // TODO Auto-generated method stub + return null; + } + + @Override + public List getDiskOfferingZones(Long diskOfferingId) { + // TODO Auto-generated method stub + return null; + } + /* (non-Javadoc) * @see com.cloud.configuration.ConfigurationService#createPod(long, java.lang.String, java.lang.String, java.lang.String, java.lang.String, java.lang.String, java.lang.String) */ @@ -288,6 +312,18 @@ public class MockConfigurationManagerImpl extends ManagerBase implements Configu return false; } + @Override + public List getNetworkOfferingDomains(Long networkOfferingId) { + // TODO Auto-generated method stub + return null; + } + + @Override + public List getNetworkOfferingZones(Long networkOfferingId) { + // TODO Auto-generated method stub + return null; + } + /* (non-Javadoc) * @see com.cloud.configuration.ConfigurationService#getNetworkOfferingNetworkRate(long) */ @@ -438,7 +474,7 @@ public class MockConfigurationManagerImpl extends ManagerBase implements Configu * @see com.cloud.configuration.ConfigurationManager#checkDiskOfferingAccess(com.cloud.user.Account, com.cloud.offering.DiskOffering) */ @Override - public void checkDiskOfferingAccess(Account caller, DiskOffering dof) { + public void checkDiskOfferingAccess(Account caller, DiskOffering dof, DataCenter zone) { // TODO Auto-generated method stub } @@ -448,9 +484,9 @@ public class MockConfigurationManagerImpl extends ManagerBase implements Configu */ @Override public NetworkOfferingVO createNetworkOffering(String name, String displayText, TrafficType trafficType, String tags, boolean specifyVlan, Availability availability, - Integer networkRate, Map> serviceProviderMap, boolean isDefault, GuestType type, boolean systemOnly, Long serviceOfferingId, - boolean conserveMode, Map> serviceCapabilityMap, boolean specifyIpRanges, boolean isPersistent, - Map details, boolean egressDefaultPolicy, Integer maxconn, boolean enableKeepAlive, Boolean forVpc) { + Integer networkRate, Map> serviceProviderMap, boolean isDefault, GuestType type, boolean systemOnly, Long serviceOfferingId, + boolean conserveMode, Map> serviceCapabilityMap, boolean specifyIpRanges, boolean isPersistent, + Map details, boolean egressDefaultPolicy, Integer maxconn, boolean enableKeepAlive, Boolean forVpc, List domainIds, List zoneIds) { // TODO Auto-generated method stub return null; } diff --git a/server/src/test/java/org/apache/cloudstack/networkoffering/CreateNetworkOfferingTest.java b/server/src/test/java/org/apache/cloudstack/networkoffering/CreateNetworkOfferingTest.java index 4a198226c10..4f808cb6d39 100644 --- a/server/src/test/java/org/apache/cloudstack/networkoffering/CreateNetworkOfferingTest.java +++ b/server/src/test/java/org/apache/cloudstack/networkoffering/CreateNetworkOfferingTest.java @@ -125,7 +125,7 @@ public class CreateNetworkOfferingTest extends TestCase { public void createSharedNtwkOffWithVlan() { NetworkOfferingVO off = configMgr.createNetworkOffering("shared", "shared", TrafficType.Guest, null, true, Availability.Optional, 200, null, false, Network.GuestType.Shared, false, - null, false, null, true, false, null, false, null, true, false); + null, false, null, true, false, null, false, null, true, false, null, null); assertNotNull("Shared network offering with specifyVlan=true failed to create ", off); } @@ -133,7 +133,7 @@ public class CreateNetworkOfferingTest extends TestCase { public void createSharedNtwkOffWithNoVlan() { NetworkOfferingVO off = configMgr.createNetworkOffering("shared", "shared", TrafficType.Guest, null, false, Availability.Optional, 200, null, false, Network.GuestType.Shared, - false, null, false, null, true, false, null, false, null, true, false); + false, null, false, null, true, false, null, false, null, true, false, null, null); assertNull("Shared network offering with specifyVlan=false was created", off); } @@ -141,7 +141,7 @@ public class CreateNetworkOfferingTest extends TestCase { public void createSharedNtwkOffWithSpecifyIpRanges() { NetworkOfferingVO off = configMgr.createNetworkOffering("shared", "shared", TrafficType.Guest, null, true, Availability.Optional, 200, null, false, Network.GuestType.Shared, false, - null, false, null, true, false, null, false, null, true, false); + null, false, null, true, false, null, false, null, true, false, null, null); assertNotNull("Shared network offering with specifyIpRanges=true failed to create ", off); } @@ -150,7 +150,7 @@ public class CreateNetworkOfferingTest extends TestCase { public void createSharedNtwkOffWithoutSpecifyIpRanges() { NetworkOfferingVO off = configMgr.createNetworkOffering("shared", "shared", TrafficType.Guest, null, true, Availability.Optional, 200, null, false, Network.GuestType.Shared, - false, null, false, null, false, false, null, false, null, true, false); + false, null, false, null, false, false, null, false, null, true, false, null, null); assertNull("Shared network offering with specifyIpRanges=false was created", off); } @@ -163,7 +163,7 @@ public class CreateNetworkOfferingTest extends TestCase { serviceProviderMap.put(Network.Service.SourceNat, vrProvider); NetworkOfferingVO off = configMgr.createNetworkOffering("isolated", "isolated", TrafficType.Guest, null, false, Availability.Optional, 200, serviceProviderMap, false, - Network.GuestType.Isolated, false, null, false, null, false, false, null, false, null, true, false); + Network.GuestType.Isolated, false, null, false, null, false, false, null, false, null, true, false, null, null); assertNotNull("Isolated network offering with specifyIpRanges=false failed to create ", off); } @@ -176,7 +176,7 @@ public class CreateNetworkOfferingTest extends TestCase { serviceProviderMap.put(Network.Service.SourceNat, vrProvider); NetworkOfferingVO off = configMgr.createNetworkOffering("isolated", "isolated", TrafficType.Guest, null, true, Availability.Optional, 200, serviceProviderMap, false, - Network.GuestType.Isolated, false, null, false, null, false, false, null, false, null, true, false); + Network.GuestType.Isolated, false, null, false, null, false, false, null, false, null, true, false, null, null); assertNotNull("Isolated network offering with specifyVlan=true wasn't created", off); } @@ -189,7 +189,7 @@ public class CreateNetworkOfferingTest extends TestCase { serviceProviderMap.put(Network.Service.SourceNat, vrProvider); NetworkOfferingVO off = configMgr.createNetworkOffering("isolated", "isolated", TrafficType.Guest, null, false, Availability.Optional, 200, serviceProviderMap, false, - Network.GuestType.Isolated, false, null, false, null, true, false, null, false, null, true, false); + Network.GuestType.Isolated, false, null, false, null, true, false, null, false, null, true, false, null, null); assertNull("Isolated network offering with specifyIpRanges=true and source nat service enabled, was created", off); } @@ -200,7 +200,7 @@ public class CreateNetworkOfferingTest extends TestCase { Set vrProvider = new HashSet(); NetworkOfferingVO off = configMgr.createNetworkOffering("isolated", "isolated", TrafficType.Guest, null, false, Availability.Optional, 200, serviceProviderMap, false, - Network.GuestType.Isolated, false, null, false, null, true, false, null, false, null, true, false); + Network.GuestType.Isolated, false, null, false, null, true, false, null, false, null, true, false, null, null); assertNotNull("Isolated network offering with specifyIpRanges=true and with no sourceNatService, failed to create", off); } @@ -218,7 +218,7 @@ public class CreateNetworkOfferingTest extends TestCase { serviceProviderMap.put(Network.Service.Lb, vrProvider); NetworkOfferingVO off = configMgr.createNetworkOffering("isolated", "isolated", TrafficType.Guest, null, true, Availability.Optional, 200, serviceProviderMap, false, - Network.GuestType.Isolated, false, null, false, null, false, false, null, false, null, true, true); + Network.GuestType.Isolated, false, null, false, null, false, false, null, false, null, true, true, null, null); // System.out.println("Creating Vpc Network Offering"); assertNotNull("Vpc Isolated network offering with Vpc provider ", off); } @@ -238,7 +238,7 @@ public class CreateNetworkOfferingTest extends TestCase { serviceProviderMap.put(Network.Service.Lb, lbProvider); NetworkOfferingVO off = configMgr.createNetworkOffering("isolated", "isolated", TrafficType.Guest, null, true, Availability.Optional, 200, serviceProviderMap, false, - Network.GuestType.Isolated, false, null, false, null, false, false, null, false, null, true, true); + Network.GuestType.Isolated, false, null, false, null, false, false, null, false, null, true, true, null, null); // System.out.println("Creating Vpc Network Offering"); assertNotNull("Vpc Isolated network offering with Vpc and Netscaler provider ", off); } diff --git a/server/src/test/resources/createNetworkOffering.xml b/server/src/test/resources/createNetworkOffering.xml index 68ff007cdbf..6aac8e18aa8 100644 --- a/server/src/test/resources/createNetworkOffering.xml +++ b/server/src/test/resources/createNetworkOffering.xml @@ -54,5 +54,8 @@ - + + + + diff --git a/test/integration/smoke/test_domain_disk_offerings.py b/test/integration/smoke/test_domain_disk_offerings.py new file mode 100644 index 00000000000..953d68034b8 --- /dev/null +++ b/test/integration/smoke/test_domain_disk_offerings.py @@ -0,0 +1,364 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +""" BVT tests for Disk offerings""" + +#Import Local Modules +from marvin.codes import FAILED +from marvin.cloudstackTestCase import cloudstackTestCase +from marvin.cloudstackAPI import updateDiskOffering +from marvin.lib.utils import (isAlmostEqual, + cleanup_resources, + random_gen) +from marvin.lib.base import (Domain, + DiskOffering, + Account, + Volume) +from marvin.lib.common import (list_disk_offering, + get_domain, + get_zone, + list_hosts) +from nose.plugins.attrib import attr + +import time +from marvin.sshClient import SshClient +from marvin.cloudstackException import CloudstackAPIException +from marvin.lib.decoratorGenerators import skipTestIf + + +_multiprocess_shared_ = True + +class TestCreateDomainsDiskOffering(cloudstackTestCase): + + def setUp(self): + self.services = self.testClient.getParsedTestDataConfig() + self.apiclient = self.testClient.getApiClient() + self.dbclient = self.testClient.getDbConnection() + self.cleanup = [] + return + + def tearDown(self): + try: + #Clean up, terminate the created templates + cleanup_resources(self.apiclient, self.cleanup) + + except Exception as e: + raise Exception("Warning: Exception during cleanup : %s" % e) + return + + @classmethod + def setUpClass(cls): + testClient = super(TestCreateDomainsDiskOffering, cls).getClsTestClient() + cls.apiclient = testClient.getApiClient() + cls.services = testClient.getParsedTestDataConfig() + # Create domains + cls.domain_1 = Domain.create( + cls.apiclient, + cls.services["acl"]["domain1"] + ) + cls.domain_11 = Domain.create( + cls.apiclient, + cls.services["acl"]["domain11"], + parentdomainid=cls.domain_1.id + ) + cls.domain_2 = Domain.create( + cls.apiclient, + cls.services["acl"]["domain2"] + ) + cls._cleanup = [ + cls.domain_11, + cls.domain_1, + cls.domain_2 + ] + return + + @classmethod + def tearDownClass(cls): + try: + cls.apiclient = super( + TestCreateDomainsDiskOffering, + cls).getClsTestClient().getApiClient() + # Clean up, terminate the created templates + cleanup_resources(cls.apiclient, cls._cleanup) + + except Exception as e: + raise + + @attr( + tags=[ + "advanced", + "basic", + "eip", + "sg", + "advancedns", + "smoke"], + required_hardware="false") + def test_01_create_disk_offering(self): + """Test to create disk offering + + # Validate the following: + # 1. createDiskOfferings should return valid info for new offering + # 2. The Cloud Database contains the valid information + """ + offering_data_domainid = "{0},{1}".format(self.domain_11.id, self.domain_2.id) + + disk_offering = DiskOffering.create( + self.apiclient, + self.services["disk_offering"], + domainid=offering_data_domainid + ) + self.cleanup.append(disk_offering) + + self.debug("Created Disk offering with ID: %s" % disk_offering.id) + + list_disk_response = list_disk_offering( + self.apiclient, + id=disk_offering.id + ) + self.assertEqual( + isinstance(list_disk_response, list), + True, + "Check list response returns a valid list" + ) + self.assertNotEqual( + len(list_disk_response), + 0, + "Check Disk offering is created" + ) + disk_response = list_disk_response[0] + + self.assertEqual( + disk_response.displaytext, + self.services["disk_offering"]["displaytext"], + "Check server displaytext in createDiskOffering" + ) + self.assertEqual( + disk_response.name, + self.services["disk_offering"]["name"], + "Check name in createDiskOffering" + ) + self.assertItemsEqual( + disk_response.domainid.split(","), + offering_data_domainid.split(","), + "Check domainid in createDiskOffering" + ) + return + +class TestDomainsDiskOfferings(cloudstackTestCase): + + def setUp(self): + self.apiclient = self.testClient.getApiClient() + self.dbclient = self.testClient.getDbConnection() + self.cleanup = [] + + def tearDown(self): + + try: + #Clean up, terminate the created templates + cleanup_resources(self.apiclient, self.cleanup) + + except Exception as e: + raise Exception("Warning: Exception during cleanup : %s" % e) + return + + @classmethod + def setUpClass(cls): + testClient = super(TestDomainsDiskOfferings, cls).getClsTestClient() + cls.apiclient = cls.testClient.getApiClient() + cls.services = cls.testClient.getParsedTestDataConfig() + # Create domains + cls.domain_1 = Domain.create( + cls.apiclient, + cls.services["acl"]["domain1"] + ) + cls.domain_11 = Domain.create( + cls.apiclient, + cls.services["acl"]["domain11"], + parentdomainid=cls.domain_1.id + ) + cls.domain_2 = Domain.create( + cls.apiclient, + cls.services["acl"]["domain2"] + ) + cls.domain_3 = Domain.create( + cls.apiclient, + cls.services["acl"]["domain12"] + ) + + cls.zone = get_zone(cls.apiclient, testClient.getZoneForTests()) + + cls.disk_offering = DiskOffering.create( + cls.apiclient, + cls.services["disk_offering"], + domainid=cls.domain_1.id + ) + cls._cleanup = [ + cls.disk_offering, + cls.domain_11, + cls.domain_1, + cls.domain_2, + cls.domain_3 + ] + return + + @classmethod + def tearDownClass(cls): + try: + cls.apiclient = super(TestDomainsDiskOfferings, cls).getClsTestClient().getApiClient() + cleanup_resources(cls.apiclient, cls._cleanup) + except Exception as e: + raise Exception("Warning: Exception during cleanup : %s" % e) + return + + @attr(tags=["advanced", "basic", "eip", "sg", "advancedns", "smoke"], required_hardware="false") + def test_02_edit_disk_offering(self): + """Test to update existing disk offering""" + + # 1. updateDiskOffering should return a valid information for the updated offering + # 2. updateDiskOffering should fail when trying to add child domain but parent domain is + # also passed + # 3. updateDiskOffering should be able to add new domain to the offering + self.debug("Updating disk offering with ID: %s" % + self.disk_offering.id) + + cmd = updateDiskOffering.updateDiskOfferingCmd() + # Add parameters for API call + cmd.id = self.disk_offering.id + input_domainid ="{0},{1},{2}".format(self.domain_1.id, self.domain_11.id, self.domain_2.id) + result_domainid = "{0},{1}".format(self.domain_1.id, self.domain_2.id) + cmd.domainid = input_domainid + self.apiclient.updateDiskOffering(cmd) + + list_disk_response = list_disk_offering( + self.apiclient, + id=self.disk_offering.id + ) + self.assertEqual( + isinstance(list_disk_response, list), + True, + "Check list response returns a valid list" + ) + + self.assertNotEqual( + len(list_disk_response), + 0, + "Check Disk offering is updated" + ) + + try: + self.assertItemsEqual( + list_disk_response[0].domainid.split(","), + input_domainid.split(","), + "Check child domainid in updateDiskOffering, should fail" + ) + self.fail("Child domain added to offering when parent domain already exist. Must be an error.") + except AssertionError: + self.debug("Child domain check successful") + + self.assertItemsEqual( + list_disk_response[0].domainid.split(","), + result_domainid.split(","), + "Check domainid in updateDiskOffering" + ) + return + + @attr( + tags=[ + "advanced", + "basic", + "eip", + "sg", + "advancedns", + "smoke"], + required_hardware="false") + def test_03_create_volume_domain_disk_offering(self): + """Test to creating volume for an existing domain specified disk offering""" + + # Validate the following: + # 1. Volume creation should fail for the user from a different domain + # 2. Volume creation should work for users from domains for which offering is specified + self.debug("Deploying VM using disk offering with ID: %s" % + self.disk_offering.id) + + self.invalid_account = Account.create( + self.apiclient, + self.services["account"], + domainid=self.domain_3.id + ) + self.cleanup.append(self.invalid_account) + + try: + Volume.create( + self.apiclient, + self.services["volume"], + zoneid=self.zone.id, + account=self.invalid_account.name, + domainid=self.invalid_account.domainid, + diskofferingid=self.disk_offering.id + ) + self.fail("Volume created for a user from domain which has not been specified for service offering. Must be an error.") + except CloudstackAPIException: + self.debug("Volume creation for invalid user check") + + self.valid_account_1 = Account.create( + self.apiclient, + self.services["account"], + domainid=self.domain_1.id + ) + self.cleanup.append(self.valid_account_1) + Volume.create( + self.apiclient, + self.services["volume"], + zoneid=self.zone.id, + account=self.valid_account_1.name, + domainid=self.valid_account_1.domainid, + diskofferingid=self.disk_offering.id + ) + self.debug("Volume created for first subdomain %s" % self.valid_account_1.domainid) + + self.valid_account_2 = Account.create( + self.apiclient, + self.services["account2"], + domainid=self.domain_2.id + ) + self.cleanup.append(self.valid_account_2) + Volume.create( + self.apiclient, + self.services["volume"], + zoneid=self.zone.id, + account=self.valid_account_2.name, + domainid=self.valid_account_2.domainid, + diskofferingid=self.disk_offering.id + ) + self.debug("Volume created for second subdomain %s" % self.valid_account_2.domainid) + + self.valid_account_3 = Account.create( + self.apiclient, + self.services["user"], + domainid=self.domain_11.id + ) + self.cleanup.append(self.valid_account_3) + Volume.create( + self.apiclient, + self.services["volume"], + zoneid=self.zone.id, + account=self.valid_account_3.name, + domainid=self.valid_account_3.domainid, + diskofferingid=self.disk_offering.id + ) + self.debug("Volume created for first child subdomain %s" % self.valid_account_3.domainid) + + return diff --git a/test/integration/smoke/test_domain_network_offerings.py b/test/integration/smoke/test_domain_network_offerings.py new file mode 100644 index 00000000000..a1014e2ae23 --- /dev/null +++ b/test/integration/smoke/test_domain_network_offerings.py @@ -0,0 +1,360 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +""" BVT tests for Network offerings""" + +#Import Local Modules +from marvin.codes import FAILED +from marvin.cloudstackTestCase import cloudstackTestCase +from marvin.cloudstackAPI import (listNetworkOfferings, + updateNetworkOffering) +from marvin.lib.utils import (isAlmostEqual, + cleanup_resources, + random_gen) +from marvin.lib.base import (Domain, + NetworkOffering, + Account, + Network) +from marvin.lib.common import (get_domain, + get_zone, + list_hosts) +from nose.plugins.attrib import attr + +import time +from marvin.sshClient import SshClient +from marvin.cloudstackException import CloudstackAPIException +from marvin.lib.decoratorGenerators import skipTestIf + + +_multiprocess_shared_ = True + +class TestCreateDomainsNetworkOffering(cloudstackTestCase): + + def setUp(self): + self.services = self.testClient.getParsedTestDataConfig() + self.apiclient = self.testClient.getApiClient() + self.dbclient = self.testClient.getDbConnection() + self.cleanup = [] + return + + def tearDown(self): + try: + #Clean up, terminate the created templates + cleanup_resources(self.apiclient, self.cleanup) + + except Exception as e: + raise Exception("Warning: Exception during cleanup : %s" % e) + return + + @classmethod + def setUpClass(cls): + testClient = super(TestCreateDomainsNetworkOffering, cls).getClsTestClient() + cls.apiclient = testClient.getApiClient() + cls.services = testClient.getParsedTestDataConfig() + # Create domains + cls.domain_1 = Domain.create( + cls.apiclient, + cls.services["acl"]["domain1"] + ) + cls.domain_11 = Domain.create( + cls.apiclient, + cls.services["acl"]["domain11"], + parentdomainid=cls.domain_1.id + ) + cls.domain_2 = Domain.create( + cls.apiclient, + cls.services["acl"]["domain2"] + ) + cls._cleanup = [ + cls.domain_11, + cls.domain_1, + cls.domain_2 + ] + return + + @classmethod + def tearDownClass(cls): + try: + cls.apiclient = super( + TestCreateDomainsNetworkOffering, + cls).getClsTestClient().getApiClient() + # Clean up, terminate the created templates + cleanup_resources(cls.apiclient, cls._cleanup) + + except Exception as e: + raise + + @attr( + tags=[ + "advanced", + "basic", + "eip", + "sg", + "advancedns", + "smoke"], + required_hardware="false") + def test_01_create_network_offering(self): + """Test to create network offering + + # Validate the following: + # 1. createNetworkOfferings should return valid info for new offering + # 2. The Cloud Database contains the valid information + """ + offering_data_domainid = "{0},{1}".format(self.domain_11.id, self.domain_2.id) + + network_offering = NetworkOffering.create( + self.apiclient, + self.services["network_offering"], + domainid=offering_data_domainid + ) + self.cleanup.append(network_offering) + + self.debug("Created Network offering with ID: %s" % network_offering.id) + + cmd = listNetworkOfferings.listNetworkOfferingsCmd() + cmd.id = network_offering.id + list_network_response = self.apiclient.listNetworkOfferings(cmd) + self.assertEqual( + isinstance(list_network_response, list), + True, + "Check list response returns a valid list" + ) + self.assertNotEqual( + len(list_network_response), + 0, + "Check Network offering is created" + ) + network_response = list_network_response[0] + + self.assertEqual( + network_response.id, + network_offering.id, + "Check server id in createNetworkOffering" + ) + self.assertItemsEqual( + network_response.domainid.split(","), + offering_data_domainid.split(","), + "Check domainid in createNetworkOffering" + ) + return + +class TestDomainsNetworkOfferings(cloudstackTestCase): + + def setUp(self): + self.apiclient = self.testClient.getApiClient() + self.dbclient = self.testClient.getDbConnection() + self.cleanup = [] + + def tearDown(self): + + try: + #Clean up, terminate the created templates + cleanup_resources(self.apiclient, self.cleanup) + + except Exception as e: + raise Exception("Warning: Exception during cleanup : %s" % e) + return + + @classmethod + def setUpClass(cls): + testClient = super(TestDomainsNetworkOfferings, cls).getClsTestClient() + cls.apiclient = cls.testClient.getApiClient() + cls.services = cls.testClient.getParsedTestDataConfig() + # Create domains + cls.domain_1 = Domain.create( + cls.apiclient, + cls.services["acl"]["domain1"] + ) + cls.domain_11 = Domain.create( + cls.apiclient, + cls.services["acl"]["domain11"], + parentdomainid=cls.domain_1.id + ) + cls.domain_2 = Domain.create( + cls.apiclient, + cls.services["acl"]["domain2"] + ) + cls.domain_3 = Domain.create( + cls.apiclient, + cls.services["acl"]["domain12"] + ) + + cls.zone = get_zone(cls.apiclient, testClient.getZoneForTests()) + + cls.network_offering = NetworkOffering.create( + cls.apiclient, + cls.services["network_offering"], + domainid=cls.domain_1.id + ) + # Enable Network offering + cls.network_offering.update(cls.apiclient, state='Enabled') + cls._cleanup = [ + cls.network_offering, + cls.domain_11, + cls.domain_1, + cls.domain_2, + cls.domain_3 + ] + return + + @classmethod + def tearDownClass(cls): + try: + cls.apiclient = super(TestDomainsNetworkOfferings, cls).getClsTestClient().getApiClient() + cleanup_resources(cls.apiclient, cls._cleanup) + except Exception as e: + raise Exception("Warning: Exception during cleanup : %s" % e) + return + + @attr(tags=["advanced", "basic", "eip", "sg", "advancedns", "smoke"], required_hardware="false") + def test_02_edit_network_offering(self): + """Test to update existing network offering""" + + # 1. updateNetworkOffering should return a valid information for the updated offering + # 2. updateNetworkOffering should fail while trying to add child domain but parent domain + # is also passed + # 3. updateNetworkOffering should be able to add new domain to the offering + self.debug("Updating network offering with ID: %s" % + self.network_offering.id) + + cmd = updateNetworkOffering.updateNetworkOfferingCmd() + # Add parameters for API call + cmd.id = self.network_offering.id + input_domainid ="{0},{1},{2}".format(self.domain_1.id, self.domain_11.id, self.domain_2.id) + result_domainid = "{0},{1}".format(self.domain_1.id, self.domain_2.id) + cmd.domainid = input_domainid + self.apiclient.updateNetworkOffering(cmd) + + cmd = listNetworkOfferings.listNetworkOfferingsCmd() + cmd.id = self.network_offering.id + list_network_response = self.apiclient.listNetworkOfferings(cmd) + self.assertEqual( + isinstance(list_network_response, list), + True, + "Check list response returns a valid list" + ) + + self.assertNotEqual( + len(list_network_response), + 0, + "Check Network offering is updated" + ) + + try: + self.assertItemsEqual( + list_network_response[0].domainid.split(","), + input_domainid.split(","), + "Check child domainid in updateServiceOffering, should fail" + ) + self.fail("Child domain added to offering when parent domain already exist. Must be an error.") + except AssertionError: + self.debug("Child domain check successful") + + domainid = "{0},{1}".format(self.domain_1.id, self.domain_2.id) + self.assertItemsEqual( + list_network_response[0].domainid.split(","), + result_domainid.split(","), + "Check domainid in createNetworkOffering" + ) + return + + @attr( + tags=[ + "advanced", + "basic", + "eip", + "sg", + "advancedns", + "smoke"], + required_hardware="false") + def test_03_create_network_domain_network_offering(self): + """Test to creating network for an existing domain specified network offering""" + + # Validate the following: + # 1. Network creation should fail for the user from a different domain + # 2. Network creation should work for users from domains for which offering is specified + self.debug("Deploying VM using network offering with ID: %s" % + self.network_offering.id) + + self.invalid_account = Account.create( + self.apiclient, + self.services["account"], + domainid=self.domain_3.id + ) + self.cleanup.append(self.invalid_account) + + try: + Network.create( + self.apiclient, + self.services["network"], + self.invalid_account.name, + self.invalid_account.domainid, + zoneid=self.zone.id, + networkofferingid=self.network_offering.id + ) + self.fail("Network created for a user from domain which has not been specified for service offering. Must be an error.") + except CloudstackAPIException: + self.debug("Network creation for invalid user check") + + self.valid_account_1 = Account.create( + self.apiclient, + self.services["account"], + domainid=self.domain_1.id + ) + self.cleanup.append(self.valid_account_1) + Network.create( + self.apiclient, + self.services["network"], + self.valid_account_1.name, + self.valid_account_1.domainid, + zoneid=self.zone.id, + networkofferingid=self.network_offering.id + ) + self.debug("Network created for first subdomain %s" % self.valid_account_1.domainid) + + self.valid_account_2 = Account.create( + self.apiclient, + self.services["account2"], + domainid=self.domain_2.id + ) + self.cleanup.append(self.valid_account_2) + Network.create( + self.apiclient, + self.services["network"], + self.valid_account_2.name, + self.valid_account_2.domainid, + zoneid=self.zone.id, + networkofferingid=self.network_offering.id + ) + self.debug("Network created for second subdomain %s" % self.valid_account_2.domainid) + + self.valid_account_3 = Account.create( + self.apiclient, + self.services["user"], + domainid=self.domain_11.id + ) + self.cleanup.append(self.valid_account_3) + Network.create( + self.apiclient, + self.services["network"], + self.valid_account_3.name, + self.valid_account_3.domainid, + zoneid=self.zone.id, + networkofferingid=self.network_offering.id + ) + self.debug("Network created for first child subdomain %s" % self.valid_account_3.domainid) + + return diff --git a/test/integration/smoke/test_domain_service_offerings.py b/test/integration/smoke/test_domain_service_offerings.py new file mode 100644 index 00000000000..0f71f8c4f64 --- /dev/null +++ b/test/integration/smoke/test_domain_service_offerings.py @@ -0,0 +1,410 @@ +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +""" BVT tests for Service offerings""" + +# Import Local Modules +from marvin.codes import FAILED +from marvin.cloudstackTestCase import cloudstackTestCase +from marvin.cloudstackAPI import updateServiceOffering +from marvin.lib.utils import (isAlmostEqual, + cleanup_resources, + random_gen) +from marvin.lib.base import (Domain, + ServiceOffering, + Account, + VirtualMachine) +from marvin.lib.common import (list_service_offering, + list_virtual_machines, + get_domain, + get_zone, + get_test_template, + list_hosts) +from nose.plugins.attrib import attr + +import time +from marvin.sshClient import SshClient +from marvin.cloudstackException import CloudstackAPIException +from marvin.lib.decoratorGenerators import skipTestIf + +_multiprocess_shared_ = True + + +class TestCreateDomainsServiceOffering(cloudstackTestCase): + + def setUp(self): + self.apiclient = self.testClient.getApiClient() + self.dbclient = self.testClient.getDbConnection() + self.cleanup = [] + self.services = self.testClient.getParsedTestDataConfig() + + def tearDown(self): + try: + # Clean up, terminate the created templates + cleanup_resources(self.apiclient, self.cleanup) + + except Exception as e: + raise Exception("Warning: Exception during cleanup : %s" % e) + + return + + @classmethod + def setUpClass(cls): + testClient = super(TestCreateDomainsServiceOffering, cls).getClsTestClient() + cls.apiclient = testClient.getApiClient() + cls.services = testClient.getParsedTestDataConfig() + # Create domains + cls.domain_1 = Domain.create( + cls.apiclient, + cls.services["acl"]["domain1"] + ) + cls.domain_11 = Domain.create( + cls.apiclient, + cls.services["acl"]["domain11"], + parentdomainid=cls.domain_1.id + ) + cls.domain_2 = Domain.create( + cls.apiclient, + cls.services["acl"]["domain2"] + ) + cls._cleanup = [ + cls.domain_11, + cls.domain_1, + cls.domain_2 + ] + return + + @classmethod + def tearDownClass(cls): + try: + cls.apiclient = super( + TestCreateDomainsServiceOffering, + cls).getClsTestClient().getApiClient() + # Clean up, terminate the created templates + cleanup_resources(cls.apiclient, cls._cleanup) + + except Exception as e: + raise + + @attr( + tags=[ + "advanced", + "advancedns", + "smoke", + "basic", + "eip", + "sg"], + required_hardware="false") + def test_01_create_domain_service_offering(self): + """Test to create service offering for specified domain""" + + # Validate the following: + # 1. createServiceOfferings should return a valid information + # for newly created offering + # 2. The Cloud Database contains the valid information + offering_data_domainid = "{0},{1}".format(self.domain_11.id, self.domain_2.id) + + service_offering = ServiceOffering.create( + self.apiclient, + self.services["service_offerings"]["tiny"], + domainid=offering_data_domainid + ) + self.cleanup.append(service_offering) + + self.debug( + "Created service offering with ID: %s" % + service_offering.id) + + list_service_response = list_service_offering( + self.apiclient, + id=service_offering.id + ) + self.assertEqual( + isinstance(list_service_response, list), + True, + "Check list response returns a valid list" + ) + + self.assertNotEqual( + len(list_service_response), + 0, + "Check Service offering is created" + ) + + self.assertEqual( + list_service_response[0].cpunumber, + self.services["service_offerings"]["tiny"]["cpunumber"], + "Check cpunumber in createServiceOffering" + ) + self.assertEqual( + list_service_response[0].cpuspeed, + self.services["service_offerings"]["tiny"]["cpuspeed"], + "Check cpuspeed in createServiceOffering" + ) + self.assertEqual( + list_service_response[0].displaytext, + self.services["service_offerings"]["tiny"]["displaytext"], + "Check server displaytext in createServiceOfferings" + ) + self.assertEqual( + list_service_response[0].memory, + self.services["service_offerings"]["tiny"]["memory"], + "Check memory in createServiceOffering" + ) + self.assertEqual( + list_service_response[0].name, + self.services["service_offerings"]["tiny"]["name"], + "Check name in createServiceOffering" + ) + self.assertItemsEqual( + list_service_response[0].domainid.split(","), + offering_data_domainid.split(","), + "Check domainid in createServiceOffering" + ) + return + + +class TestDomainsServiceOfferings(cloudstackTestCase): + + def setUp(self): + self.apiclient = self.testClient.getApiClient() + self.dbclient = self.testClient.getDbConnection() + self.cleanup = [] + + def tearDown(self): + try: + # Clean up, terminate the created templates + cleanup_resources(self.apiclient, self.cleanup) + + except Exception as e: + raise Exception("Warning: Exception during cleanup : %s" % e) + + return + + @classmethod + def setUpClass(cls): + testClient = super(TestDomainsServiceOfferings, cls).getClsTestClient() + cls.apiclient = testClient.getApiClient() + cls.services = testClient.getParsedTestDataConfig() + cls.hypervisor = testClient.getHypervisorInfo() + # Create domains + cls.domain_1 = Domain.create( + cls.apiclient, + cls.services["acl"]["domain1"] + ) + cls.domain_11 = Domain.create( + cls.apiclient, + cls.services["acl"]["domain11"], + parentdomainid=cls.domain_1.id + ) + cls.domain_2 = Domain.create( + cls.apiclient, + cls.services["acl"]["domain2"] + ) + cls.domain_3 = Domain.create( + cls.apiclient, + cls.services["acl"]["domain12"] + ) + cls.zone = get_zone(cls.apiclient, testClient.getZoneForTests()) + cls.services['mode'] = cls.zone.networktype + + cls.service_offering = ServiceOffering.create( + cls.apiclient, + cls.services["service_offerings"]["tiny"], + domainid=cls.domain_1.id + ) + template = get_test_template( + cls.apiclient, + cls.zone.id, + cls.hypervisor + ) + if template == FAILED: + assert False, "get_test_template() failed to return template" + + # Set Zones and disk offerings + cls.services["small"]["zoneid"] = cls.zone.id + cls.services["small"]["template"] = template.id + + cls._cleanup = [ + cls.service_offering, + cls.domain_11, + cls.domain_1, + cls.domain_2, + cls.domain_3 + ] + return + + @classmethod + def tearDownClass(cls): + try: + cls.apiclient = super( + TestDomainsServiceOfferings, + cls).getClsTestClient().getApiClient() + # Clean up, terminate the created templates + cleanup_resources(cls.apiclient, cls._cleanup) + + except Exception as e: + raise Exception("Warning: Exception during cleanup : %s" % e) + return + + @attr( + tags=[ + "advanced", + "advancedns", + "smoke", + "basic", + "eip", + "sg"], + required_hardware="false") + def test_02_edit_domain_service_offering(self): + """Test to update existing service offering""" + + # Validate the following: + # 1. updateServiceOffering should return a valid information for the updated offering + # 2. updateServiceOffering should fail when trying to add child domain but parent domain is + # also passed + # 3. updateServiceOffering should be able to add new domain to the offering + self.debug("Updating service offering with ID: %s" % + self.service_offering.id) + + cmd = updateServiceOffering.updateServiceOfferingCmd() + # Add parameters for API call + cmd.id = self.service_offering.id + input_domainid ="{0},{1},{2}".format(self.domain_1.id, self.domain_11.id, self.domain_2.id) + result_domainid = "{0},{1}".format(self.domain_1.id, self.domain_2.id) + cmd.domainid = input_domainid + self.apiclient.updateServiceOffering(cmd) + + list_service_response = list_service_offering( + self.apiclient, + id=self.service_offering.id + ) + self.assertEqual( + isinstance(list_service_response, list), + True, + "Check list response returns a valid list" + ) + + self.assertNotEqual( + len(list_service_response), + 0, + "Check Service offering is updated" + ) + + try: + self.assertItemsEqual( + list_service_response[0].domainid.split(","), + input_domainid.split(","), + "Check child domainid in updateServiceOffering, should fail" + ) + self.fail("Child domain added to offering when parent domain already exist. Must be an error.") + except AssertionError: + self.debug("Child domain check successful") + + self.assertItemsEqual( + list_service_response[0].domainid.split(","), + result_domainid.split(","), + "Check domainid in updateServiceOffering" + ) + + return + + @attr( + tags=[ + "advanced", + "advancedns", + "smoke", + "basic", + "eip", + "sg"], + required_hardware="false") + def test_03_deploy_vm_domain_service_offering(self): + """Test to deploying VM for an existing domain specified service offering""" + + # Validate the following: + # 1. VM deployment should fail for the user from a different domain + # 2. VM deployment should work for users from domains for which offering is specified + self.debug("Deploying VM using service offering with ID: %s" % + self.service_offering.id) + + self.invalid_account = Account.create( + self.apiclient, + self.services["account"], + domainid=self.domain_3.id + ) + self.cleanup.append(self.invalid_account) + + try: + VirtualMachine.create( + self.apiclient, + self.services["small"], + accountid=self.invalid_account.name, + domainid=self.invalid_account.domainid, + serviceofferingid=self.service_offering.id, + mode=self.services["mode"] + ) + self.fail("VM deployed for a user from domain which has not been specified for service offering. Must be an error.") + except CloudstackAPIException: + self.debug("VM deployment for invalid user check") + + self.valid_account_1 = Account.create( + self.apiclient, + self.services["account"], + domainid=self.domain_1.id + ) + self.cleanup.append(self.valid_account_1) + self.vm_1 = VirtualMachine.create( + self.apiclient, + self.services["small"], + accountid=self.valid_account_1.name, + domainid=self.valid_account_1.domainid, + serviceofferingid=self.service_offering.id, + mode=self.services["mode"] + ) + self.debug("VM deployed for first subdomain %s" % self.valid_account_1.domainid) + + self.valid_account_2 = Account.create( + self.apiclient, + self.services["account2"], + domainid=self.domain_2.id + ) + self.cleanup.append(self.valid_account_2) + self.vm_2 = VirtualMachine.create( + self.apiclient, + self.services["small"], + accountid=self.valid_account_2.name, + domainid=self.valid_account_2.domainid, + serviceofferingid=self.service_offering.id, + mode=self.services["mode"] + ) + self.debug("VM deployed for second subdomain %s" % self.valid_account_2.domainid) + + self.valid_account_3 = Account.create( + self.apiclient, + self.services["user"], + domainid=self.domain_11.id + ) + self.cleanup.append(self.valid_account_3) + self.vm_3 = VirtualMachine.create( + self.apiclient, + self.services["small"], + accountid=self.valid_account_3.name, + domainid=self.valid_account_3.domainid, + serviceofferingid=self.service_offering.id, + mode=self.services["mode"] + ) + self.debug("VM deployed for first child subdomain %s" % self.valid_account_3.domainid) + + return diff --git a/test/integration/smoke/test_domain_vpc_offerings.py b/test/integration/smoke/test_domain_vpc_offerings.py new file mode 100644 index 00000000000..d24e05bd7d7 --- /dev/null +++ b/test/integration/smoke/test_domain_vpc_offerings.py @@ -0,0 +1,405 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +""" BVT tests for Vpc offerings""" + +#Import Local Modules +from marvin.codes import FAILED +from marvin.cloudstackTestCase import cloudstackTestCase +from marvin.cloudstackAPI import (createVPCOffering, + listVPCOfferings, + updateVPCOffering) +from marvin.lib.utils import (isAlmostEqual, + cleanup_resources, + random_gen) +from marvin.lib.base import (Domain, + VpcOffering, + Account, + VPC) +from marvin.lib.common import (get_domain, + get_zone) +from nose.plugins.attrib import attr + +import time +from marvin.sshClient import SshClient +from marvin.cloudstackException import CloudstackAPIException +from marvin.lib.decoratorGenerators import skipTestIf + + +_multiprocess_shared_ = True + +class Services: + """Test VPC network services - Port Forwarding Rules Test Data Class. + """ + + def __init__(self): + self.services = { + "vpc_offering": { + "name": 'Redundant VPC off', + "displaytext": 'Redundant VPC off', + "supportedservices": 'Dhcp,Dns,SourceNat,PortForwarding,Vpn,Lb,UserData,StaticNat', + "serviceProviderList": { + "Vpn": 'VpcVirtualRouter', + "Dhcp": 'VpcVirtualRouter', + "Dns": 'VpcVirtualRouter', + "SourceNat": 'VpcVirtualRouter', + "PortForwarding": 'VpcVirtualRouter', + "Lb": 'VpcVirtualRouter', + "UserData": 'VpcVirtualRouter', + "StaticNat": 'VpcVirtualRouter', + "NetworkACL": 'VpcVirtualRouter' + }, + }, + "vpc": { + "name": "TestVPC", + "displaytext": "TestVPC", + "cidr": '10.0.0.0/16' + } + } + +class TestCreateDomainsVpcOffering(cloudstackTestCase): + + def setUp(self): + self.services = self.testClient.getParsedTestDataConfig() + self.localservices = Services().services + self.apiclient = self.testClient.getApiClient() + self.dbclient = self.testClient.getDbConnection() + self.cleanup = [] + return + + def tearDown(self): + try: + #Clean up, terminate the created templates + cleanup_resources(self.apiclient, self.cleanup) + + except Exception as e: + raise Exception("Warning: Exception during cleanup : %s" % e) + return + + @classmethod + def setUpClass(cls): + testClient = super(TestCreateDomainsVpcOffering, cls).getClsTestClient() + cls.apiclient = testClient.getApiClient() + cls.services = testClient.getParsedTestDataConfig() + # Create domains + cls.domain_1 = Domain.create( + cls.apiclient, + cls.services["acl"]["domain1"] + ) + cls.domain_11 = Domain.create( + cls.apiclient, + cls.services["acl"]["domain11"], + parentdomainid=cls.domain_1.id + ) + cls.domain_2 = Domain.create( + cls.apiclient, + cls.services["acl"]["domain2"] + ) + cls._cleanup = [ + cls.domain_11, + cls.domain_1, + cls.domain_2 + ] + return + + @classmethod + def tearDownClass(cls): + try: + cls.apiclient = super( + TestCreateDomainsVpcOffering, + cls).getClsTestClient().getApiClient() + # Clean up, terminate the created templates + cleanup_resources(cls.apiclient, cls._cleanup) + + except Exception as e: + raise + + @attr( + tags=[ + "advanced", + "basic", + "eip", + "sg", + "advancedns", + "smoke"], + required_hardware="false") + def test_01_create_vpc_offering(self): + """Test to create vpc offering + + # Validate the following: + # 1. createVPCOfferings should return valid info for new offering + # 2. The Cloud Database contains the valid information + """ + offering_data_domainid = "{0},{1}".format(self.domain_11.id, self.domain_2.id) + offering_data = self.localservices["vpc_offering"] + cmd = createVPCOffering.createVPCOfferingCmd() + cmd.name = "-".join([offering_data["name"], random_gen()]) + cmd.displaytext = offering_data["displaytext"] + cmd.supportedServices = offering_data["supportedservices"] + cmd.domainid = offering_data_domainid + if "serviceProviderList" in offering_data: + for service, provider in offering_data["serviceProviderList"].items(): + providers = provider + if isinstance(provider, str): + providers = [provider] + + for provider_item in providers: + cmd.serviceproviderlist.append({ + 'service': service, + 'provider': provider_item + }) + + vpc_offering = VpcOffering(self.apiclient.createVPCOffering(cmd).__dict__) + self.cleanup.append(vpc_offering) + + self.debug("Created Vpc offering with ID: %s" % vpc_offering.id) + + cmd = listVPCOfferings.listVPCOfferingsCmd() + cmd.id = vpc_offering.id + list_vpc_response = self.apiclient.listVPCOfferings(cmd) + self.assertEqual( + isinstance(list_vpc_response, list), + True, + "Check list response returns a valid list" + ) + self.assertNotEqual( + len(list_vpc_response), + 0, + "Check Vpc offering is created" + ) + vpc_response = list_vpc_response[0] + + self.assertEqual( + vpc_response.id, + vpc_offering.id, + "Check server id in createVPCOffering" + ) + self.assertEqual( + vpc_response.displaytext, + self.localservices["vpc_offering"]["displaytext"], + "Check server displaytext in createVPCOffering" + ) + self.assertItemsEqual( + vpc_response.domainid.split(","), + offering_data_domainid.split(","), + "Check domainid in createVPCOffering" + ) + return + +class TestDomainsVpcOfferings(cloudstackTestCase): + + def setUp(self): + self.apiclient = self.testClient.getApiClient() + self.dbclient = self.testClient.getDbConnection() + self.cleanup = [] + + def tearDown(self): + + try: + #Clean up, terminate the created templates + cleanup_resources(self.apiclient, self.cleanup) + + except Exception as e: + raise Exception("Warning: Exception during cleanup : %s" % e) + return + + @classmethod + def setUpClass(cls): + testClient = super(TestDomainsVpcOfferings, cls).getClsTestClient() + cls.apiclient = testClient.getApiClient() + cls.localservices = Services().services + cls.services = testClient.getParsedTestDataConfig() + # Create domains + cls.domain_1 = Domain.create( + cls.apiclient, + cls.services["acl"]["domain1"] + ) + cls.domain_11 = Domain.create( + cls.apiclient, + cls.services["acl"]["domain11"], + parentdomainid=cls.domain_1.id + ) + cls.domain_2 = Domain.create( + cls.apiclient, + cls.services["acl"]["domain2"] + ) + cls.domain_3 = Domain.create( + cls.apiclient, + cls.services["acl"]["domain12"] + ) + + cls.zone = get_zone(cls.apiclient, testClient.getZoneForTests()) + + cls.vpc_offering = VpcOffering.create( + cls.apiclient, + cls.services["vpc_offering"] + ) + # Enable Vpc offering + cls.vpc_offering.update(cls.apiclient, state='Enabled') + cls._cleanup = [ + cls.vpc_offering, + cls.domain_11, + cls.domain_1, + cls.domain_2, + cls.domain_3 + ] + return + + @classmethod + def tearDownClass(cls): + try: + cls.apiclient = super(TestDomainsVpcOfferings, cls).getClsTestClient().getApiClient() + cleanup_resources(cls.apiclient, cls._cleanup) + except Exception as e: + raise Exception("Warning: Exception during cleanup : %s" % e) + return + + @attr(tags=["advanced", "basic", "eip", "sg", "advancedns", "smoke"], required_hardware="false") + def test_02_edit_vpc_offering(self): + """Test to update existing vpc offering""" + + # 1. updateVPCOffering should return a valid information for the updated offering + # 2. updateVPCOffering should fail while tring to add child domain but parent domain + # is already present + # 3. updateVPCOffering should be able to add new domain to the offering + self.debug("Updating vpc offering with ID: %s" % + self.vpc_offering.id) + + cmd = updateVPCOffering.updateVPCOfferingCmd() + cmd.id = self.vpc_offering.id + input_domainid ="{0},{1},{2}".format(self.domain_1.id, self.domain_11.id, self.domain_2.id) + result_domainid = "{0},{1}".format(self.domain_1.id, self.domain_2.id) + cmd.domainid = input_domainid + self.apiclient.updateVPCOffering(cmd) + + cmd = listVPCOfferings.listVPCOfferingsCmd() + cmd.id = self.vpc_offering.id + list_vpc_response = self.apiclient.listVPCOfferings(cmd) + self.assertEqual( + isinstance(list_vpc_response, list), + True, + "Check list response returns a valid list" + ) + + self.assertNotEqual( + len(list_vpc_response), + 0, + "Check Vpc offering is updated" + ) + + try: + self.assertItemsEqual( + list_vpc_response[0].domainid.split(","), + input_domainid.split(","), + "Check child domainid in updateServiceOffering, should fail" + ) + self.fail("Child domain added to offering when parent domain already exist. Must be an error.") + except AssertionError: + self.debug("Child domain check successful") + + self.assertItemsEqual( + list_vpc_response[0].domainid.split(","), + result_domainid.split(","), + "Check domainid in createVPCOffering" + ) + + @attr( + tags=[ + "advanced", + "basic", + "eip", + "sg", + "advancedns", + "smoke"], + required_hardware="false") + def test_03_create_vpc_domain_vpc_offering(self): + """Test to creating vpc for an existing domain specified vpc offering""" + + # Validate the following: + # 1. Vpc creation should fail for the user from a different domain + # 2. Vpc creation should work for users from domains for which offering is specified + self.debug("Deploying VM using vpc offering with ID: %s" % + self.vpc_offering.id) + + self.invalid_account = Account.create( + self.apiclient, + self.services["account"], + domainid=self.domain_3.id + ) + self.cleanup.append(self.invalid_account) + + try: + VPC.create( + apiclient=self.apiclient, + services=self.services["vpc"], + account=self.invalid_account.name, + domainid=self.invalid_account.domainid, + zoneid=self.zone.id, + vpcofferingid=self.vpc_offering.id + ) + self.fail("Vpc created for a user from domain which has not been specified for service offering. Must be an error.") + except CloudstackAPIException: + self.debug("Vpc creation for invalid user check") + + self.valid_account_1 = Account.create( + self.apiclient, + self.services["account"], + domainid=self.domain_1.id + ) + self.cleanup.append(self.valid_account_1) + VPC.create( + apiclient=self.apiclient, + services=self.services["vpc"], + account=self.valid_account_1.name, + domainid=self.valid_account_1.domainid, + zoneid=self.zone.id, + vpcofferingid=self.vpc_offering.id + ) + self.debug("Vpc created for first subdomain %s" % self.valid_account_1.domainid) + + self.valid_account_2 = Account.create( + self.apiclient, + self.services["account2"], + domainid=self.domain_2.id + ) + self.cleanup.append(self.valid_account_2) + VPC.create( + apiclient=self.apiclient, + services=self.services["vpc"], + account=self.valid_account_2.name, + domainid=self.valid_account_2.domainid, + zoneid=self.zone.id, + vpcofferingid=self.vpc_offering.id + ) + self.debug("Vpc created for second subdomain %s" % self.valid_account_2.domainid) + + self.valid_account_3 = Account.create( + self.apiclient, + self.services["user"], + domainid=self.domain_11.id + ) + self.cleanup.append(self.valid_account_3) + VPC.create( + apiclient=self.apiclient, + services=self.services["vpc"], + account=self.valid_account_3.name, + domainid=self.valid_account_3.domainid, + zoneid=self.zone.id, + vpcofferingid=self.vpc_offering.id + ) + self.debug("Vpc created for first child subdomain %s" % self.valid_account_3.domainid) + + return diff --git a/ui/css/cloudstack3.css b/ui/css/cloudstack3.css index 6f74b97f6dd..76ba97c038f 100644 --- a/ui/css/cloudstack3.css +++ b/ui/css/cloudstack3.css @@ -12860,6 +12860,14 @@ div.ui-dialog div.autoscaler div.field-group div.form-container form div.form-it background-position: -197px -647px; } +.updateOfferingAccess .icon { + background-position: -165px -122px; +} + +.updateOfferingAccess:hover .icon { + background-position: -165px -704px; +} + .accounts-wizard table { width: 100%; margin: 0; diff --git a/ui/l10n/en.js b/ui/l10n/en.js index 1e88ee4ded9..6a4bba9e3a3 100644 --- a/ui/l10n/en.js +++ b/ui/l10n/en.js @@ -294,6 +294,7 @@ var dictionary = { "label.action.take.snapshot.processing":"Taking Snapshot....", "label.action.unmanage.cluster":"Unmanage Cluster", "label.action.unmanage.cluster.processing":"Unmanaging Cluster....", +"label.action.update.offering.access":"Update Offering Access", "label.action.update.OS.preference":"Update OS Preference", "label.action.update.OS.preference.processing":"Updating OS Preference....", "label.action.update.resource.count":"Update Resource Count", @@ -554,6 +555,7 @@ var dictionary = { "label.compute":"Compute", "label.compute.and.storage":"Compute and Storage", "label.compute.offering":"Compute offering", +"label.compute.offering.access":"Compute offering access", "label.compute.offering.type":"Compute offering type", "label.compute.offering.custom.constrained":"Custom Constrained", "label.compute.offering.custom.unconstrained":"Custom Unconstrained", @@ -685,6 +687,7 @@ var dictionary = { "label.disk.iops.allocated":"IOPS Allocated", "label.disk.iops.write.rate":"Disk Write Rate (IOPS)", "label.disk.offering":"Disk Offering", +"label.disk.offering.access":"Disk offering access", "label.disk.offering.details":"Disk offering details", "label.disk.newOffering": "New Disk Offering", "label.disk.newOffering.description": "New disk offering to be used by this volume after the migration.", @@ -708,6 +711,7 @@ var dictionary = { "label.dns.1":"DNS 1", "label.dns.2":"DNS 2", "label.domain":"Domain", +"label.domains":"Domains", "label.domain.admin":"Domain Admin", "label.domain.details":"Domain details", "label.domain.id":"Domain ID", @@ -1185,6 +1189,7 @@ var dictionary = { "label.network.limits":"Network limits", "label.network.name":"Network Name", "label.network.offering":"Network Offering", +"label.network.offering.access":"Network offering access", "label.network.offering.details":"Network offering details", "label.network.offering.display.text":"Network Offering Display Text", "label.network.offering.id":"Network Offering ID", @@ -1837,6 +1842,7 @@ var dictionary = { "label.vpc.distributedvpcrouter":"Distributed VPC Router", "label.vpc.id":"VPC ID", "label.vpc.offering":"VPC Offering", +"label.vpc.offering.access":"VPC offering access", "label.vpc.offering.details":"VPC offering details", "label.vpc.router.details":"VPC Router Details", "label.vpc.supportsregionlevelvpc":"Supports Region Level VPC", diff --git a/ui/scripts/configuration.js b/ui/scripts/configuration.js index e9670a6b6f0..4f523370207 100644 --- a/ui/scripts/configuration.js +++ b/ui/scripts/configuration.js @@ -73,6 +73,7 @@ preFilter: function(args) { if (isAdmin()) { } else { + args.$form.find('.form-item[rel=isPublic]').find('input[name=isPublic]').prop('checked', false); args.$form.find('.form-item[rel=isPublic]').hide(); args.$form.find('.form-item[rel=domainId]').css('display', 'inline-block'); //shown args.$form.find('.form-item[rel=deploymentPlanner]').hide(); @@ -646,14 +647,21 @@ }); } }, - domainId: { label: 'label.domain', docID: 'helpComputeOfferingDomain', dependsOn: 'isPublic', + isMultiple: true, + validation: { + required: true + }, select: function(args) { $.ajax({ - url: createURL("listDomains&listAll=true"), + url: createURL('listDomains'), + data: { + listAll: true, + details: 'min' + }, dataType: "json", async: false, success: function(json) { @@ -675,6 +683,42 @@ }); }, isHidden: true + }, + zoneId: { + label: 'label.zone', + docID: 'helpComputeOfferingZone', + isMultiple: true, + validation: { + allzonesonly: true + }, + select: function(args) { + $.ajax({ + url: createURL("listZones"), + data: {available: 'true'}, + dataType: "json", + async: true, + success: function(json) { + var items = []; + var zoneObjs = json.listzonesresponse.zone; + $(zoneObjs).each(function() { + items.push({ + id: this.id, + description: this.name + }); + }); + items.sort(function(a, b) { + return a.description.localeCompare(b.description); + }); + items.unshift({ + id: -1, + description: "All Zones" + }); + args.response.success({ + data: items + }); + } + }); + } } } }, @@ -827,8 +871,18 @@ }); if (args.data.isPublic != "on") { + var domainId = (args.data.domainId && Array.isArray(args.data.domainId)) ? args.data.domainId.join(',') : args.data.domainId; + if (domainId) { + $.extend(data, { + domainid: domainId + }); + } + } + + var zoneId = (args.data.zoneId && Array.isArray(args.data.zoneId)) ? args.data.zoneId.join(',') : args.data.zoneId != -1 ? args.data.zoneId : undefined; + if (zoneId) { $.extend(data, { - domainid: args.data.domainId + zoneid: zoneId }); } @@ -937,6 +991,204 @@ args.complete(); } } + }, + + updateOfferingAccess: { + label: 'label.action.update.offering.access', + messages: { + notification: function(args) { + return 'label.action.update.offering.access'; + } + }, + createForm: { + title: 'label.compute.offering.access', + desc: '', + preFilter: function(args) { + if (isAdmin()) { + } else { + args.$form.find('.form-item[rel=isPublic]').find('input[name=isPublic]').prop('checked', false); + args.$form.find('.form-item[rel=isPublic]').hide(); + args.$form.find('.form-item[rel=domainId]').css('display', 'inline-block'); //shown + args.$form.find('.form-item[rel=zoneId]').hide(); + } + var formOffering = args.context.serviceOfferings[0]; + $.ajax({ + url: createURL('listServiceOfferings&isrecursive=true'), + data: { + id: args.context.serviceOfferings[0].id + }, + dataType: "json", + async: false, + success: function (json) { + var item = json.listserviceofferingsresponse.serviceoffering[0]; + formOffering = item; + args.response.success({ + data: item + }); + } + }); //end ajax + var offeringDomainIds = formOffering.domainid; + if (offeringDomainIds) { + args.$form.find('.form-item[rel=isPublic]').find('input[name=isPublic]').prop('checked', false); + args.$form.find('.form-item[rel=domainId]').css('display', 'inline-block'); //shown + offeringDomainIds = offeringDomainIds.indexOf(",") != -1 ? offeringDomainIds.split(",") : [offeringDomainIds]; + var options = args.$form.find('.form-item[rel=domainId]').find('option'); + $.each(options, function(optionIndex, option) { + $.each(offeringDomainIds, function(domainIdIndex, domainId) { + domainId = domainId.toString().trim(); + if ($(option).val() === domainId) { + $(option).attr('selected','selected'); + } + }); + }); + } else { + if (isAdmin()) { + args.$form.find('.form-item[rel=isPublic]').find('input[name=isPublic]').prop('checked', true); + } + } + var offeringZoneIds = formOffering.zoneid; + if (offeringZoneIds) { + offeringZoneIds = offeringZoneIds.indexOf(",") != -1 ? offeringZoneIds.split(",") : [offeringZoneIds]; + var options = args.$form.find('.form-item[rel=zoneId]').find('option'); + $.each(options, function(optionIndex, option) { + $.each(offeringZoneIds, function(zoneIdIndex, zoneId) { + zoneId = zoneId.toString().trim(); + if ($(option).val() === zoneId) { + $(option).attr('selected','selected'); + } + }); + }); + } + }, + fields: { + isPublic: { + label: 'label.public', + isBoolean: true, + isReverse: true, + isChecked: false, + docID: 'helpComputeOfferingPublic' + }, + domainId: { + label: 'label.domain', + docID: 'helpComputeOfferingDomain', + dependsOn: 'isPublic', + isMultiple: true, + isHidden: true, + validation: { + required: true + }, + select: function(args) { + $.ajax({ + url: createURL('listDomains'), + data: { + listAll: true, + details: 'min' + }, + dataType: "json", + async: false, + success: function(json) { + var items = []; + var domainObjs = json.listdomainsresponse.domain; + $(domainObjs).each(function() { + items.push({ + id: this.id, + description: this.path + }); + }); + items.sort(function(a, b) { + return a.description.localeCompare(b.description); + }); + args.response.success({ + data: items + }); + var options = args.$form.find('.form-item[rel=domainId]').children('option'); + $.each(options, function() { + console.log($(this).val()); + }); + console.log("Hello! "+options); + } + }); + } + }, + zoneId: { + label: 'label.zone', + docID: 'helpComputeOfferingZone', + isMultiple: true, + validation: { + allzonesonly: true + }, + select: function(args) { + $.ajax({ + url: createURL("listZones"), + data: {available: 'true'}, + dataType: "json", + async: true, + success: function(json) { + var items = []; + var zoneObjs = json.listzonesresponse.zone; + $(zoneObjs).each(function() { + items.push({ + id: this.id, + description: this.name + }); + }); + items.sort(function(a, b) { + return a.description.localeCompare(b.description); + }); + items.unshift({ + id: -1, + description: "All Zones", + selected: true + }); + args.response.success({ + data: items + }); + } + }); + } + } + } + }, + action: function(args) { + var data = { + id: args.context.serviceOfferings[0].id + }; + if (args.data.isPublic != "on") { + var domainId = (args.data.domainId && Array.isArray(args.data.domainId)) ? args.data.domainId.join(',') : args.data.domainId; + if (domainId) { + $.extend(data, { + domainid: domainId + }); + } + } else { + $.extend(data, { + domainid: "public" + }); + } + var zoneId = (args.data.zoneId && Array.isArray(args.data.zoneId)) ? args.data.zoneId.join(',') : args.data.zoneId != -1 ? args.data.zoneId : "all"; + if (zoneId) { + $.extend(data, { + zoneid: zoneId + }); + } + $.ajax({ + url: createURL('updateServiceOffering'), + data: data, + dataType: "json", + async: false, + success: function (json) { + var item = json.updateserviceofferingresponse.serviceoffering; + args.response.success({ + data: item + }); + } + }); //end ajax + }, + notification: { + poll: function(args) { + args.complete(); + } + } } }, @@ -1066,6 +1318,9 @@ domain: { label: 'label.domain' }, + zone: { + label: 'label.zone' + }, created: { label: 'label.created', converter: cloudStack.converters.toLocalDate @@ -1144,6 +1399,7 @@ preFilter: function(args) { if (isAdmin()) { } else { + args.$form.find('.form-item[rel=isPublic]').find('input[name=isPublic]').prop('checked', false); args.$form.find('.form-item[rel=isPublic]').hide(); args.$form.find('.form-item[rel=domainId]').css('display', 'inline-block'); //shown } @@ -1825,6 +2081,7 @@ preFilter: function(args) { if (isAdmin()) { } else { + args.$form.find('.form-item[rel=isPublic]').find('input[name=isPublic]').prop('checked', false); args.$form.find('.form-item[rel=isPublic]').hide(); args.$form.find('.form-item[rel=domainId]').css('display', 'inline-block'); //shown args.$form.find('.form-item[rel=tags]').hide(); @@ -2109,6 +2366,10 @@ label: 'label.domain', docID: 'helpDiskOfferingDomain', dependsOn: 'isPublic', + isMultiple: true, + validation: { + required: true + }, select: function(args) { $.ajax({ url: createURL('listDomains'), @@ -2137,6 +2398,42 @@ }); }, isHidden: true + }, + zoneId: { + label: 'label.zone', + docID: 'helpDiskOfferingZone', + isMultiple: true, + validation: { + allzonesonly: true + }, + select: function(args) { + $.ajax({ + url: createURL("listZones"), + data: {available: 'true'}, + dataType: "json", + async: true, + success: function(json) { + var items = []; + var zoneObjs = json.listzonesresponse.zone; + $(zoneObjs).each(function() { + items.push({ + id: this.id, + description: this.name + }); + }); + items.sort(function(a, b) { + return a.description.localeCompare(b.description); + }); + items.unshift({ + id: -1, + description: "All Zones" + }); + args.response.success({ + data: items + }); + } + }); + } } } }, @@ -2217,8 +2514,18 @@ } if (args.data.isPublic != "on") { + var domainId = (args.data.domainId && Array.isArray(args.data.domainId)) ? args.data.domainId.join(',') : args.data.domainId; + if (domainId) { + $.extend(data, { + domainid: domainId + }); + } + } + + var zoneId = (args.data.zoneId && Array.isArray(args.data.zoneId)) ? args.data.zoneId.join(',') : args.data.zoneId != -1 ? args.data.zoneId : undefined; + if (zoneId) { $.extend(data, { - domainid: args.data.domainId + zoneid: zoneId }); } @@ -2302,6 +2609,198 @@ args.complete(); } } + }, + + updateOfferingAccess: { + label: 'label.action.update.offering.access', + messages: { + notification: function(args) { + return 'label.action.update.offering.access'; + } + }, + createForm: { + title: 'label.disk.offering.access', + desc: '', + preFilter: function(args) { + if (isAdmin()) { + } else { + args.$form.find('.form-item[rel=isPublic]').find('input[name=isPublic]').prop('checked', false); + args.$form.find('.form-item[rel=isPublic]').hide(); + args.$form.find('.form-item[rel=domainId]').css('display', 'inline-block'); //shown + args.$form.find('.form-item[rel=zoneId]').hide(); + } + var formOffering = args.context.diskOfferings[0]; + $.ajax({ + url: createURL('listDiskOfferings'), + data: { + id: args.context.diskOfferings[0].id + }, + dataType: "json", + async: false, + success: function (json) { + var item = json.listdiskofferingsresponse.diskoffering[0]; + formOffering = item; + args.response.success({ + data: item + }); + } + }); //end ajax + var offeringDomainIds = formOffering.domainid; + if (offeringDomainIds) { + args.$form.find('.form-item[rel=isPublic]').find('input[name=isPublic]').prop('checked', false); + args.$form.find('.form-item[rel=domainId]').css('display', 'inline-block'); //shown + offeringDomainIds = offeringDomainIds.indexOf(",") != -1 ? offeringDomainIds.split(",") : [offeringDomainIds]; + var options = args.$form.find('.form-item[rel=domainId]').find('option'); + $.each(options, function(optionIndex, option) { + $.each(offeringDomainIds, function(domainIdIndex, domainId) { + domainId = domainId.toString().trim(); + if ($(option).val() === domainId) { + $(option).attr('selected','selected'); + } + }); + }); + } else { + if (isAdmin()) { + args.$form.find('.form-item[rel=isPublic]').find('input[name=isPublic]').prop('checked', true); + } + } + var offeringZoneIds = formOffering.zoneid; + if (offeringZoneIds) { + offeringZoneIds = offeringZoneIds.indexOf(",") != -1 ? offeringZoneIds.split(",") : [offeringZoneIds]; + var options = args.$form.find('.form-item[rel=zoneId]').find('option'); + $.each(options, function(optionIndex, option) { + $.each(offeringZoneIds, function(zoneIdIndex, zoneId) { + zoneId = zoneId.toString().trim(); + if ($(option).val() === zoneId) { + $(option).attr('selected','selected'); + } + }); + }); + } + }, + fields: { + isPublic: { + label: 'label.public', + isBoolean: true, + isReverse: true, + isChecked: false, + docID: 'helpDiskOfferingPublic' + }, + domainId: { + label: 'label.domain', + docID: 'helpDiskOfferingDomain', + dependsOn: 'isPublic', + isMultiple: true, + validation: { + required: true + }, + select: function(args) { + $.ajax({ + url: createURL('listDomains'), + data: { + listAll: true, + details: 'min' + }, + dataType: "json", + async: false, + success: function(json) { + var items = []; + var domainObjs = json.listdomainsresponse.domain; + $(domainObjs).each(function() { + items.push({ + id: this.id, + description: this.path + }); + }); + items.sort(function(a, b) { + return a.description.localeCompare(b.description); + }); + args.response.success({ + data: items + }); + } + }); + }, + isHidden: true + }, + zoneId: { + label: 'label.zone', + docID: 'helpDiskOfferingZone', + isMultiple: true, + validation: { + allzonesonly: true + }, + select: function(args) { + $.ajax({ + url: createURL("listZones"), + data: {available: 'true'}, + dataType: "json", + async: true, + success: function(json) { + var items = []; + var zoneObjs = json.listzonesresponse.zone; + $(zoneObjs).each(function() { + items.push({ + id: this.id, + description: this.name + }); + }); + items.sort(function(a, b) { + return a.description.localeCompare(b.description); + }); + items.unshift({ + id: -1, + description: "All Zones" + }); + args.response.success({ + data: items + }); + } + }); + } + } + } + }, + action: function(args) { + var data = { + id: args.context.diskOfferings[0].id + }; + if (args.data.isPublic != "on") { + var domainId = (args.data.domainId && Array.isArray(args.data.domainId)) ? args.data.domainId.join(',') : args.data.domainId; + if (domainId) { + $.extend(data, { + domainid: domainId + }); + } + } else { + $.extend(data, { + domainid: "public" + }); + } + var zoneId = (args.data.zoneId && Array.isArray(args.data.zoneId)) ? args.data.zoneId.join(',') : args.data.zoneId != -1 ? args.data.zoneId : "all"; + if (zoneId) { + $.extend(data, { + zoneid: zoneId + }); + } + $.ajax({ + url: createURL('updateDiskOffering'), + data: data, + dataType: "json", + async: false, + success: function (json) { + var item = json.updatediskofferingresponse.diskoffering; + args.response.success({ + data: item + }); + } + }); //end ajax + }, + notification: { + poll: function(args) { + args.complete(); + } + } } }, @@ -2393,6 +2892,9 @@ domain: { label: 'label.domain' }, + zone: { + label: 'label.zone' + }, storagetype: { label: 'label.storage.type' }, @@ -3351,6 +3853,86 @@ ] }); } + }, + isPublic: { + label: 'label.public', + isBoolean: true, + isReverse: true, + isChecked: false, + docID: 'helpNetworkOfferingPublic' + }, + domainId: { + label: 'label.domain', + docID: 'helpNetworkOfferingDomain', + dependsOn: 'isPublic', + isMultiple: true, + validation: { + required: true + }, + select: function(args) { + $.ajax({ + url: createURL('listDomains'), + data: { + listAll: true, + details: 'min' + }, + dataType: "json", + async: false, + success: function(json) { + var items = []; + var domainObjs = json.listdomainsresponse.domain; + $(domainObjs).each(function() { + items.push({ + id: this.id, + description: this.path + }); + }); + items.sort(function(a, b) { + return a.description.localeCompare(b.description); + }); + args.response.success({ + data: items + }); + } + }); + }, + isHidden: true + }, + zoneId: { + label: 'label.zone', + docID: 'helpNetworkOfferingZone', + isMultiple: true, + validation: { + allzonesonly: true + }, + select: function(args) { + $.ajax({ + url: createURL("listZones"), + data: {available: 'true'}, + dataType: "json", + async: true, + success: function(json) { + var items = []; + var zoneObjs = json.listzonesresponse.zone; + $(zoneObjs).each(function() { + items.push({ + id: this.id, + description: this.name + }); + }); + items.sort(function(a, b) { + return a.description.localeCompare(b.description); + }); + items.unshift({ + id: -1, + description: "All Zones" + }); + args.response.success({ + data: items + }); + } + }); + } } } }, @@ -3424,7 +4006,7 @@ } else if (value != '') { // normal data (serviceData.length ==1), e.g. "name", "displayText", "networkRate", "guestIpType", "lbType" (unwanted), "availability" (unwated when value is "Optional"), "egressdefaultpolicy", "state" (unwanted), "status" (unwanted), "allocationstate" (unwanted) if (key == "useVpc") { inputData['forvpc'] = value; - } else if (!(key == "lbType" || (key == "availability" && value == "Optional") || key == "state" || key == "status" || key == "allocationstate" || key == "useVpc" )) { + } else if (!(key == "lbType" || (key == "availability" && value == "Optional") || key == "state" || key == "status" || key == "allocationstate" || key == "useVpc" || key == "isPublic" || key == "domainId" || key == "zoneId")) { inputData[key] = value; } } @@ -3566,6 +4148,22 @@ if (args.$form.find('.form-item[rel=serviceofferingid]').css("display") == "none") delete inputData.serviceofferingid; + if (args.data.isPublic != "on") { + var domainId = (args.data.domainId && Array.isArray(args.data.domainId)) ? args.data.domainId.join(',') : args.data.domainId; + if (domainId) { + $.extend(inputData, { + domainid: domainId + }); + } + } + + var zoneId = (args.data.zoneId && Array.isArray(args.data.zoneId)) ? args.data.zoneId.join(',') : args.data.zoneId != -1 ? args.data.zoneId : undefined; + if (zoneId) { + $.extend(inputData, { + zoneid: zoneId + }); + } + inputData['traffictype'] = 'GUEST'; //traffic type dropdown has been removed since it has only one option ('Guest'). Hardcode traffic type value here. $.ajax({ @@ -3751,6 +4349,191 @@ }); } } + }, + + updateOfferingAccess: { + label: 'label.action.update.offering.access', + messages: { + notification: function(args) { + return 'label.action.update.offering.access'; + } + }, + createForm: { + title: 'label.network.offering.access', + desc: '', + preFilter: function(args) { + var formOffering = args.context.networkOfferings[0]; + $.ajax({ + url: createURL('listNetworkOfferings'), + data: { + id: args.context.networkOfferings[0].id + }, + dataType: "json", + async: false, + success: function (json) { + var item = json.listnetworkofferingsresponse.networkoffering[0]; + formOffering = item; + args.response.success({ + data: item + }); + } + }); //end ajax + var offeringDomainIds = formOffering.domainid; + if (offeringDomainIds) { + args.$form.find('.form-item[rel=isPublic]').find('input[name=isPublic]').prop('checked', false); + args.$form.find('.form-item[rel=domainId]').css('display', 'inline-block'); //shown + offeringDomainIds = offeringDomainIds.indexOf(",") != -1 ? offeringDomainIds.split(",") : [offeringDomainIds]; + var options = args.$form.find('.form-item[rel=domainId]').find('option'); + $.each(options, function(optionIndex, option) { + $.each(offeringDomainIds, function(domainIdIndex, domainId) { + domainId = domainId.toString().trim(); + if ($(option).val() === domainId) { + $(option).attr('selected','selected'); + } + }); + }); + } else { + if (isAdmin()) { + args.$form.find('.form-item[rel=isPublic]').find('input[name=isPublic]').prop('checked', true); + } + } + var offeringZoneIds = formOffering.zoneid; + if (offeringZoneIds) { + offeringZoneIds = offeringZoneIds.indexOf(",") != -1 ? offeringZoneIds.split(",") : [offeringZoneIds]; + var options = args.$form.find('.form-item[rel=zoneId]').find('option'); + $.each(options, function(optionIndex, option) { + $.each(offeringZoneIds, function(zoneIdIndex, zoneId) { + zoneId = zoneId.toString().trim(); + if ($(option).val() === zoneId) { + $(option).attr('selected','selected'); + } + }); + }); + } + }, + fields: { + isPublic: { + label: 'label.public', + isBoolean: true, + isReverse: true, + isChecked: false, + docID: 'helpNetworkOfferingPublic' + }, + domainId: { + label: 'label.domain', + docID: 'helpNetworkOfferingDomain', + dependsOn: 'isPublic', + isMultiple: true, + validation: { + required: true + }, + select: function(args) { + $.ajax({ + url: createURL('listDomains'), + data: { + listAll: true, + details: 'min' + }, + dataType: "json", + async: false, + success: function(json) { + var items = []; + var domainObjs = json.listdomainsresponse.domain; + $(domainObjs).each(function() { + items.push({ + id: this.id, + description: this.path + }); + }); + items.sort(function(a, b) { + return a.description.localeCompare(b.description); + }); + args.response.success({ + data: items + }); + } + }); + }, + isHidden: true + }, + zoneId: { + label: 'label.zone', + docID: 'helpNetworkOfferingZone', + isMultiple: true, + validation: { + allzonesonly: true + }, + select: function(args) { + $.ajax({ + url: createURL("listZones"), + data: {available: 'true'}, + dataType: "json", + async: true, + success: function(json) { + var items = []; + var zoneObjs = json.listzonesresponse.zone; + $(zoneObjs).each(function() { + items.push({ + id: this.id, + description: this.name + }); + }); + items.sort(function(a, b) { + return a.description.localeCompare(b.description); + }); + items.unshift({ + id: -1, + description: "All Zones" + }); + args.response.success({ + data: items + }); + } + }); + } + } + } + }, + action: function(args) { + var data = { + id: args.context.networkOfferings[0].id + }; + if (args.data.isPublic != "on") { + var domainId = (args.data.domainId && Array.isArray(args.data.domainId)) ? args.data.domainId.join(',') : args.data.domainId; + if (domainId) { + $.extend(data, { + domainid: domainId + }); + } + } else { + $.extend(data, { + domainid: "public" + }); + } + var zoneId = (args.data.zoneId && Array.isArray(args.data.zoneId)) ? args.data.zoneId.join(',') : args.data.zoneId != -1 ? args.data.zoneId : "all"; + if (zoneId) { + $.extend(data, { + zoneid: zoneId + }); + } + $.ajax({ + url: createURL('updateNetworkOffering'), + data: data, + dataType: "json", + async: false, + success: function (json) { + var item = json.updatenetworkofferingresponse.networkoffering; + args.response.success({ + data: item + }); + } + }); //end ajax + }, + notification: { + poll: function(args) { + args.complete(); + } + } } }, tabs: { @@ -3859,6 +4642,12 @@ serviceCapabilities: { label: 'label.service.capabilities' }, + domain: { + label: 'label.domain' + }, + zone: { + label: 'label.zone' + }, tags: { label: 'label.tags' }, @@ -4170,6 +4959,86 @@ isHidden: true, dependsOn: 'service.SourceNat.isEnabled', isBoolean: true + }, + isPublic: { + label: 'label.public', + isBoolean: true, + isReverse: true, + isChecked: false, + docID: 'helpVpcOfferingPublic' + }, + domainId: { + label: 'label.domain', + docID: 'helpVpcOfferingDomain', + dependsOn: 'isPublic', + isMultiple: true, + validation: { + required: true + }, + select: function(args) { + $.ajax({ + url: createURL('listDomains'), + data: { + listAll: true, + details: 'min' + }, + dataType: "json", + async: false, + success: function(json) { + var items = []; + var domainObjs = json.listdomainsresponse.domain; + $(domainObjs).each(function() { + items.push({ + id: this.id, + description: this.path + }); + }); + items.sort(function(a, b) { + return a.description.localeCompare(b.description); + }); + args.response.success({ + data: items + }); + } + }); + }, + isHidden: true + }, + zoneId: { + label: 'label.zone', + docID: 'helpVpcOfferingZone', + isMultiple: true, + validation: { + allzonesonly: true + }, + select: function(args) { + $.ajax({ + url: createURL("listZones"), + data: {available: 'true'}, + dataType: "json", + async: true, + success: function(json) { + var items = []; + var zoneObjs = json.listzonesresponse.zone; + $(zoneObjs).each(function() { + items.push({ + id: this.id, + description: this.name + }); + }); + items.sort(function(a, b) { + return a.description.localeCompare(b.description); + }); + items.unshift({ + id: -1, + description: "All Zones" + }); + args.response.success({ + data: items + }); + } + }); + } } }//end of fields }, //end of createForm @@ -4179,6 +5048,7 @@ var inputData = {}; var serviceProviderMap = {}; var serviceCapabilityIndex = 0; + var excludedKeys = ['isPublic', 'domainId', 'zoneId', 'state', 'status', 'allocationstate'] $.each(formData, function(key, value) { var serviceData = key.split('.'); if (serviceData.length > 1) { @@ -4206,7 +5076,7 @@ serviceCapabilityIndex++; } - } else if (value != '') { // Normal data + } else if (value != '' && $.inArray(key, excludedKeys) == -1) { // Normal data inputData[key] = value; } }); @@ -4225,6 +5095,22 @@ serviceProviderIndex++; }); + if (args.data.isPublic != "on") { + var domainId = (args.data.domainId && Array.isArray(args.data.domainId)) ? args.data.domainId.join(',') : args.data.domainId; + if (domainId) { + $.extend(inputData, { + domainid: domainId + }); + } + } + + var zoneId = (args.data.zoneId && Array.isArray(args.data.zoneId)) ? args.data.zoneId.join(',') : args.data.zoneId != -1 ? args.data.zoneId : undefined; + if (zoneId) { + $.extend(inputData, { + zoneid: zoneId + }); + } + $.ajax({ url: createURL('createVPCOffering'), data: inputData, @@ -4371,7 +5257,15 @@ id: args.context.vpcOfferings[0].id }, success: function(json) { - args.response.success(); + var jid = json.deletevpcofferingresponse.jobid; + args.response.success({ + _custom: { + jobId: jid, + getActionFilter: function() { + return vpcOfferingActionfilter; + } + } + }); }, error: function(data) { args.response.error(parseXMLHttpResponse(data)); @@ -4387,14 +5281,192 @@ } }, notification: { - poll: function(args) { - args.complete({ + poll: pollAsyncJobResult + } + }, + + updateOfferingAccess: { + label: 'label.action.update.offering.access', + messages: { + notification: function(args) { + return 'label.action.update.offering.access'; + } + }, + createForm: { + title: 'label.vpc.offering.access', + desc: '', + preFilter: function(args) { + var formOffering = args.context.vpcOfferings[0]; + $.ajax({ + url: createURL('listVPCOfferings'), data: { - state: 'Destroyed' + id: args.context.vpcOfferings[0].id }, - actionFilter: vpcOfferingActionfilter + dataType: "json", + async: false, + success: function (json) { + var item = json.listvpcofferingsresponse.vpcoffering[0]; + formOffering = item; + args.response.success({ + data: item + }); + } + }); //end ajax + var offeringDomainIds = formOffering.domainid; + if (offeringDomainIds) { + args.$form.find('.form-item[rel=isPublic]').find('input[name=isPublic]').prop('checked', false); + args.$form.find('.form-item[rel=domainId]').css('display', 'inline-block'); //shown + offeringDomainIds = offeringDomainIds.indexOf(",") != -1 ? offeringDomainIds.split(",") : [offeringDomainIds]; + var options = args.$form.find('.form-item[rel=domainId]').find('option'); + $.each(options, function(optionIndex, option) { + $.each(offeringDomainIds, function(domainIdIndex, domainId) { + domainId = domainId.toString().trim(); + if ($(option).val() === domainId) { + $(option).attr('selected','selected'); + } + }); + }); + } else { + if (isAdmin()) { + args.$form.find('.form-item[rel=isPublic]').find('input[name=isPublic]').prop('checked', true); + } + } + var offeringZoneIds = formOffering.zoneid; + if (offeringZoneIds) { + offeringZoneIds = offeringZoneIds.indexOf(",") != -1 ? offeringZoneIds.split(",") : [offeringZoneIds]; + var options = args.$form.find('.form-item[rel=zoneId]').find('option'); + $.each(options, function(optionIndex, option) { + $.each(offeringZoneIds, function(zoneIdIndex, zoneId) { + zoneId = zoneId.toString().trim(); + if ($(option).val() === zoneId) { + $(option).attr('selected','selected'); + } + }); + }); + } + }, + fields: { + isPublic: { + label: 'label.public', + isBoolean: true, + isReverse: true, + isChecked: false, + docID: 'helpVpcOfferingPublic' + }, + domainId: { + label: 'label.domain', + docID: 'helpVpcOfferingDomain', + dependsOn: 'isPublic', + isMultiple: true, + validation: { + required: true + }, + select: function(args) { + $.ajax({ + url: createURL('listDomains'), + data: { + listAll: true, + details: 'min' + }, + dataType: "json", + async: false, + success: function(json) { + var items = []; + var domainObjs = json.listdomainsresponse.domain; + $(domainObjs).each(function() { + items.push({ + id: this.id, + description: this.path + }); + }); + items.sort(function(a, b) { + return a.description.localeCompare(b.description); + }); + args.response.success({ + data: items + }); + } + }); + }, + isHidden: true + }, + zoneId: { + label: 'label.zone', + docID: 'helpVpcOfferingZone', + isMultiple: true, + validation: { + allzonesonly: true + }, + select: function(args) { + $.ajax({ + url: createURL("listZones"), + data: {available: 'true'}, + dataType: "json", + async: true, + success: function(json) { + var items = []; + var zoneObjs = json.listzonesresponse.zone; + $(zoneObjs).each(function() { + items.push({ + id: this.id, + description: this.name + }); + }); + items.sort(function(a, b) { + return a.description.localeCompare(b.description); + }); + items.unshift({ + id: -1, + description: "All Zones" + }); + args.response.success({ + data: items + }); + } + }); + } + } + } + }, + action: function(args) { + var data = { + id: args.context.vpcOfferings[0].id + }; + if (args.data.isPublic != "on") { + var domainId = (args.data.domainId && Array.isArray(args.data.domainId)) ? args.data.domainId.join(',') : args.data.domainId; + if (domainId) { + $.extend(data, { + domainid: domainId + }); + } + } else { + $.extend(data, { + domainid: "public" }); } + var zoneId = (args.data.zoneId && Array.isArray(args.data.zoneId)) ? args.data.zoneId.join(',') : args.data.zoneId != -1 ? args.data.zoneId : "all"; + if (zoneId) { + $.extend(data, { + zoneid: zoneId + }); + } + $.ajax({ + url: createURL('updateVPCOffering'), + data: data, + dataType: "json", + async: false, + success: function (json) { + var item = json.updatevpcofferingresponse.vpcoffering; + args.response.success({ + data: item + }); + } + }); //end ajax + }, + notification: { + poll: function(args) { + args.complete(); + } } } }, @@ -4447,6 +5519,12 @@ serviceCapabilities: { label: 'label.service.capabilities' }, + domain: { + label: 'label.domain' + }, + zone: { + label: 'label.zone' + }, tags: { label: 'label.tags' } @@ -4491,6 +5569,7 @@ var allowedActions = []; allowedActions.push("edit"); allowedActions.push("remove"); + allowedActions.push("updateOfferingAccess"); return allowedActions; }; @@ -4507,6 +5586,7 @@ var allowedActions = []; allowedActions.push("edit"); allowedActions.push("remove"); + allowedActions.push("updateOfferingAccess"); return allowedActions; }; @@ -4526,6 +5606,7 @@ if (jsonObj.isdefault == false) allowedActions.push("remove"); + allowedActions.push("updateOfferingAccess"); return allowedActions; }; @@ -4546,6 +5627,7 @@ if (jsonObj.isdefault == false) allowedActions.push("remove"); + allowedActions.push("updateOfferingAccess"); return allowedActions; }; diff --git a/ui/scripts/docs.js b/ui/scripts/docs.js index b032d4eaf3e..ec0b32a15aa 100755 --- a/ui/scripts/docs.js +++ b/ui/scripts/docs.js @@ -298,7 +298,11 @@ cloudStack.docs = { externalLink: '' }, helpComputeOfferingDomain: { - desc: 'The domain to associate this compute offering with' + desc: 'Select the domains in which this offering is available (Tip: Use Ctrl to choose multiple domains)', + }, + helpComputeOfferingZone: { + desc: 'Select the zones in which this offering is available (Tip: Use Ctrl to choose multiple zones)', + externalLink: '' }, // Create Instance Snapshot helpCreateInstanceSnapshotName: { @@ -390,7 +394,11 @@ cloudStack.docs = { externalLink: '' }, helpDiskOfferingDomain: { - desc: 'Select the subdomain in which this offering is available', + desc: 'Select the domains in which this offering is available (Tip: Use Ctrl to choose multiple domains)', + externalLink: '' + }, + helpDiskOfferingZone: { + desc: 'Select the zones in which this offering is available (Tip: Use Ctrl to choose multiple zones)', externalLink: '' }, // Add domain @@ -644,6 +652,17 @@ cloudStack.docs = { desc: 'Network tag to specify which physical network to use', externalLink: '' }, + helpNetworkOfferingPublic: { + desc: 'Yes makes the offering available to all domains. No limits the scope to a subdomain; you will be prompted for the subdomain\'s name.', + externalLink: '' + }, + helpNetworkOfferingDomain: { + desc: 'Select the domains in which this offering is available (Tip: Use Ctrl to choose multiple domains)', + }, + helpNetworkOfferingZone: { + desc: 'Select the zones in which this offering is available (Tip: Use Ctrl to choose multiple zones)', + externalLink: '' + }, // Add pod helpPodZone: { desc: 'The zone where you want to add the pod', @@ -1308,6 +1327,17 @@ cloudStack.docs = { desc: 'A short description of the offering that can be displayed to users', externalLink: '' }, + helpVpcOfferingPublic: { + desc: 'Yes makes the offering available to all domains. No limits the scope to a subdomain; you will be prompted for the subdomain\'s name.', + externalLink: '' + }, + helpVpcOfferingDomain: { + desc: 'Select the domains in which this offering is available (Tip: Use Ctrl to choose multiple domains)', + }, + helpVpcOfferingZone: { + desc: 'Select the zones in which this offering is available (Tip: Use Ctrl to choose multiple zones)', + externalLink: '' + }, helpOvm3pool: { desc: 'Pool the Ovm3 nodes in this cluster, required for vm node migrations', externalLink: '' diff --git a/ui/scripts/instanceWizard.js b/ui/scripts/instanceWizard.js index d2ed9bccc03..1513d84955c 100644 --- a/ui/scripts/instanceWizard.js +++ b/ui/scripts/instanceWizard.js @@ -535,6 +535,7 @@ // get serviceOfferingObjs + var zoneid = args.currentData["zoneid"]; $(window).removeData("cloudStack.module.instanceWizard.serviceOfferingObjs"); $(window).trigger("cloudStack.module.instanceWizard.serviceOffering.dataProvider", { context: args.context, @@ -545,6 +546,9 @@ url: createURL("listServiceOfferings&issystem=false"), dataType: "json", async: false, + data: { + zoneid: zoneid + }, success: function(json) { serviceOfferingObjs = json.listserviceofferingsresponse.serviceoffering; } @@ -568,6 +572,7 @@ // Step 4: Data disk offering function(args) { var isRequired = (args.currentData["select-template"] == "select-iso" ? true : false); + var zoneid = args.currentData["zoneid"]; var templateFilter = 'executable' if (isAdmin()) { templateFilter = 'all' @@ -575,6 +580,9 @@ $.ajax({ url: createURL("listDiskOfferings"), dataType: "json", + data: { + zoneid: zoneid + }, async: true, success: function(json) { diskOfferingObjs = json.listdiskofferingsresponse.diskoffering; @@ -835,6 +843,7 @@ // get networkObjsToPopulate + var zoneid = args.currentData["zoneid"]; $(window).removeData("cloudStack.module.instanceWizard.networkObjs"); $(window).trigger("cloudStack.module.instanceWizard.network.dataProvider", { context: args.context, @@ -851,6 +860,9 @@ $.ajax({ url: createURL("listNetworkOfferings"), dataType: "json", + data: { + zoneid: zoneid + }, data: { forvpc: false, zoneid: selectedZoneObj.id, diff --git a/ui/scripts/network.js b/ui/scripts/network.js index 24a6c7dfc91..7e5f554d08a 100644 --- a/ui/scripts/network.js +++ b/ui/scripts/network.js @@ -504,12 +504,60 @@ }); } }, + domain: { + label: 'label.domain', + isHidden: function(args) { + if (isAdmin() || isDomainAdmin()) + return false; + else + return true; + }, + select: function(args) { + if (isAdmin() || isDomainAdmin()) { + $.ajax({ + url: createURL("listDomains&listAll=true"), + success: function(json) { + var items = []; + items.push({ + id: "", + description: "" + }); + var domainObjs = json.listdomainsresponse.domain; + $(domainObjs).each(function() { + items.push({ + id: this.id, + description: this.path + }); + }); + items.sort(function(a, b) { + return a.description.localeCompare(b.description); + }); + args.response.success({ + data: items + }); + } + }); + args.$select.change(function() { + var $form = $(this).closest('form'); + if ($(this).val() == "") { + $form.find('.form-item[rel=account]').hide(); + } else { + $form.find('.form-item[rel=account]').css('display', 'inline-block'); + } + }); + } else { + args.response.success({ + data: null + }); + } + } + }, networkOfferingId: { label: 'label.network.offering', validation: { required: true }, - dependsOn: 'zoneId', + dependsOn: (isAdmin() || isDomainAdmin()) ? ['zoneId', 'domain'] : 'zoneId', // domain is visible only for admins docID: 'helpGuestNetworkNetworkOffering', select: function(args) { var data = { @@ -519,6 +567,12 @@ state: 'Enabled' }; + if ((isAdmin() || isDomainAdmin())) { // domain is visible only for admins + $.extend(data, { + domainid: args.domain + }); + } + if ('vpc' in args.context) { //from VPC section $.extend(data, { forVpc: true @@ -657,54 +711,6 @@ networkDomain: { label: 'label.network.domain' }, - domain: { - label: 'label.domain', - isHidden: function(args) { - if (isAdmin() || isDomainAdmin()) - return false; - else - return true; - }, - select: function(args) { - if (isAdmin() || isDomainAdmin()) { - $.ajax({ - url: createURL("listDomains&listAll=true"), - success: function(json) { - var items = []; - items.push({ - id: "", - description: "" - }); - var domainObjs = json.listdomainsresponse.domain; - $(domainObjs).each(function() { - items.push({ - id: this.id, - description: this.path - }); - }); - items.sort(function(a, b) { - return a.description.localeCompare(b.description); - }); - args.response.success({ - data: items - }); - } - }); - args.$select.change(function() { - var $form = $(this).closest('form'); - if ($(this).val() == "") { - $form.find('.form-item[rel=account]').hide(); - } else { - $form.find('.form-item[rel=account]').css('display', 'inline-block'); - } - }); - } else { - args.response.success({ - data: null - }); - } - } - }, account: { label: 'label.account', validation: { @@ -5197,14 +5203,17 @@ }, vpcoffering: { label: 'label.vpc.offering', + dependsOn: 'zoneid', validation: { required: true }, select: function(args) { - var data = {}; + var data = { + zoneid: args.zoneid + }; $.ajax({ url: createURL('listVPCOfferings'), - data: {}, + data: data, success: function(json) { var offerings = json.listvpcofferingsresponse.vpcoffering ? json.listvpcofferingsresponse.vpcoffering : []; var filteredofferings = $.grep(offerings, function(offering) { diff --git a/ui/scripts/sharedFunctions.js b/ui/scripts/sharedFunctions.js index 4218bffec95..9fe51515338 100644 --- a/ui/scripts/sharedFunctions.js +++ b/ui/scripts/sharedFunctions.js @@ -534,7 +534,7 @@ var addGuestNetworkDialog = { networkOfferingId: { label: 'label.network.offering', docID: 'helpGuestNetworkZoneNetworkOffering', - dependsOn: ['zoneId', 'physicalNetworkId', 'scope'], + dependsOn: ['zoneId', 'physicalNetworkId', 'scope', 'domainId'], select: function(args) { if(args.$form.find('.form-item[rel=zoneId]').find('select').val() == null || args.$form.find('.form-item[rel=zoneId]').find('select').val().length == 0) { args.response.success({ @@ -570,6 +570,11 @@ var addGuestNetworkDialog = { $.extend(data, { guestiptype: 'Shared' }); + if (args.scope == "domain-specific") { + $.extend(data, { + domainid: args.domainId + }); + } } var items = []; @@ -889,12 +894,60 @@ var addL2GuestNetwork = { }); } }, + domain: { + label: 'label.domain', + isHidden: function(args) { + if (isAdmin() || isDomainAdmin()) + return false; + else + return true; + }, + select: function(args) { + if (isAdmin() || isDomainAdmin()) { + $.ajax({ + url: createURL("listDomains&listAll=true"), + success: function(json) { + var items = []; + items.push({ + id: "", + description: "" + }); + var domainObjs = json.listdomainsresponse.domain; + $(domainObjs).each(function() { + items.push({ + id: this.id, + description: this.path + }); + }); + items.sort(function(a, b) { + return a.description.localeCompare(b.description); + }); + args.response.success({ + data: items + }); + } + }); + args.$select.change(function() { + var $form = $(this).closest('form'); + if ($(this).val() == "") { + $form.find('.form-item[rel=account]').hide(); + } else { + $form.find('.form-item[rel=account]').css('display', 'inline-block'); + } + }); + } else { + args.response.success({ + data: null + }); + } + } + }, networkOfferingId: { label: 'label.network.offering', validation: { required: true }, - dependsOn: 'zoneId', + dependsOn: (isAdmin() || isDomainAdmin()) ? ['zoneId', 'domain'] : 'zoneId', // domain is visible only for admins docID: 'helpGuestNetworkNetworkOffering', select: function(args) { var data = { @@ -903,6 +956,12 @@ var addL2GuestNetwork = { state: 'Enabled' }; + if ((isAdmin() || isDomainAdmin())) { // domain is visible only for admins + $.extend(data, { + domainid: args.domain + }); + } + if ('vpc' in args.context) { //from VPC section $.extend(data, { forVpc: true @@ -983,55 +1042,6 @@ var addL2GuestNetwork = { label: 'label.bypass.vlan.overlap.check', isBoolean: true, isHidden: true - }, - - domain: { - label: 'label.domain', - isHidden: function(args) { - if (isAdmin() || isDomainAdmin()) - return false; - else - return true; - }, - select: function(args) { - if (isAdmin() || isDomainAdmin()) { - $.ajax({ - url: createURL("listDomains&listAll=true"), - success: function(json) { - var items = []; - items.push({ - id: "", - description: "" - }); - var domainObjs = json.listdomainsresponse.domain; - $(domainObjs).each(function() { - items.push({ - id: this.id, - description: this.path - }); - }); - items.sort(function(a, b) { - return a.description.localeCompare(b.description); - }); - args.response.success({ - data: items - }); - } - }); - args.$select.change(function() { - var $form = $(this).closest('form'); - if ($(this).val() == "") { - $form.find('.form-item[rel=account]').hide(); - } else { - $form.find('.form-item[rel=account]').css('display', 'inline-block'); - } - }); - } else { - args.response.success({ - data: null - }); - } - } }, account: { label: 'label.account', diff --git a/ui/scripts/storage.js b/ui/scripts/storage.js index 3066fff4349..a51e8f33492 100644 --- a/ui/scripts/storage.js +++ b/ui/scripts/storage.js @@ -168,7 +168,7 @@ }); } - var selectedDiskOfferingObj = null; + var diskOfferingsObjList, selectedDiskOfferingObj = null; cloudStack.sections.storage = { title: 'label.storage', @@ -274,6 +274,21 @@ }); } }); + args.$select.change(function() { + var diskOfferingSelect = $(this).closest('form').find('select[name=diskOffering]'); + if(diskOfferingSelect) { + $(diskOfferingSelect).find('option').remove().end(); + var data = { + zoneid: $(this).val(), + }; + console.log(data); + var diskOfferings = cloudStack.listDiskOfferings({ data: data }); + diskOfferingsObjList = diskOfferings; + $(diskOfferings).each(function() { + $(diskOfferingSelect).append(new Option(this.displaytext, this.id)); + }); + } + }); } }, diskOffering: { @@ -281,6 +296,7 @@ docID: 'helpVolumeDiskOffering', select: function(args) { var diskOfferings = cloudStack.listDiskOfferings({}); + diskOfferingsObjList = diskOfferings; var items = []; $(diskOfferings).each(function() { items.push({ @@ -293,7 +309,7 @@ }); args.$select.change(function() { var diskOfferingId = $(this).val(); - $(diskOfferings).each(function() { + $(diskOfferingsObjList).each(function() { if (this.id == diskOfferingId) { selectedDiskOfferingObj = this; return false; //break the $.each() loop