server: create, update VPC offering for domain(s) & zone(s)

Signed-off-by: Abhishek Kumar <abhishek.kumar@shapeblue.com>
This commit is contained in:
Abhishek Kumar 2019-04-12 12:24:23 +05:30 committed by Abhishek Kumar
parent de79fbdb70
commit 366b253bf2
18 changed files with 907 additions and 60 deletions

View File

@ -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();
}

View File

@ -20,16 +20,21 @@ 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 com.cloud.utils.Pair;
public interface VpcProvisioningService {
public VpcOffering getVpcOffering(long vpcOfferingId);
VpcOffering getVpcOffering(long vpcOfferingId);
public VpcOffering createVpcOffering(String name, String displayText, List<String> supportedServices,
Map<String, List<String>> serviceProviders,
Map serviceCapabilitystList,
Long serviceOfferingId);
VpcOffering createVpcOffering(CreateVPCOfferingCmd cmd);
VpcOffering createVpcOffering(String name, String displayText, List<String> supportedServices,
Map<String, List<String>> serviceProviders,
Map serviceCapabilitystList,
Long serviceOfferingId, List<Long> domainIds, List<Long> zoneIds);
Pair<List<? extends VpcOffering>,Integer> listVpcOfferings(Long id, String name, String displayText, List<String> supportedServicesStr, Boolean isDefault, String keyword,
String state, Long startIndex, Long pageSizeVal);
@ -41,12 +46,9 @@ public interface VpcProvisioningService {
public boolean deleteVpcOffering(long offId);
/**
* @param vpcOffId
* @param vpcOfferingName
* @param displayText
* @param state
* @param cmd
* @return
*/
public VpcOffering updateVpcOffering(long vpcOffId, String vpcOfferingName, String displayText, String state);
public VpcOffering updateVpcOffering(UpdateVPCOfferingCmd cmd);
}

View File

@ -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<Long> 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<Long> zoneIds;
/////////////////////////////////////////////////////
/////////////////// Accessors ///////////////////////
/////////////////////////////////////////////////////
@ -127,10 +147,27 @@ public class CreateVPCOfferingCmd extends BaseAsyncCreateCmd {
return serviceOfferingId;
}
public List<Long> getDomainIds() {
if (CollectionUtils.isNotEmpty(domainIds)) {
Set<Long> set = new LinkedHashSet<>(domainIds);
domainIds.clear();
domainIds.addAll(set);
}
return domainIds;
}
public List<Long> getZoneIds() {
if (CollectionUtils.isNotEmpty(zoneIds)) {
Set<Long> 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());

View File

@ -16,6 +16,13 @@
// under the License.
package org.apache.cloudstack.api.command.admin.vpc;
import java.util.LinkedHashSet;
import java.util.List;
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;
@ -52,6 +59,21 @@ 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.LIST,
collectionType = CommandType.UUID,
entityType = DomainResponse.class,
description = "the ID of the containing domain(s), null for public offerings")
private List<Long> 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<Long> zoneIds;
/////////////////////////////////////////////////////
/////////////////// Accessors ///////////////////////
/////////////////////////////////////////////////////
@ -72,6 +94,24 @@ public class UpdateVPCOfferingCmd extends BaseAsyncCmd {
return state;
}
public List<Long> getDomainIds() {
if (CollectionUtils.isNotEmpty(domainIds)) {
Set<Long> set = new LinkedHashSet<>(domainIds);
domainIds.clear();
domainIds.addAll(set);
}
return domainIds;
}
public List<Long> getZoneIds() {
if (CollectionUtils.isNotEmpty(zoneIds)) {
Set<Long> set = new LinkedHashSet<>(zoneIds);
zoneIds.clear();
zoneIds.addAll(set);
}
return zoneIds;
}
/////////////////////////////////////////////////////
/////////////// API Implementation///////////////////
/////////////////////////////////////////////////////
@ -87,7 +127,7 @@ public class UpdateVPCOfferingCmd extends BaseAsyncCmd {
@Override
public void execute() {
VpcOffering result = _vpcProvSvc.updateVpcOffering(getId(), getVpcOfferingName(), getDisplayText(), getState());
VpcOffering result = _vpcProvSvc.updateVpcOffering(this);
if (result != null) {
VpcOfferingResponse response = _responseGenerator.createVpcOfferingResponse(result);
response.setResponseName(getCommandName());

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -163,23 +163,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;
}

View File

@ -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<VpcOfferingDetailsVO, Long>, ResourceDetailsDao<VpcOfferingDetailsVO> {
List<Long> findDomainIds(final long resourceId);
List<Long> findZoneIds(final long resourceId);
}

View File

@ -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<VpcOfferingDetailsVO> 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<Long> findDomainIds(long resourceId) {
final List<Long> 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<Long> findZoneIds(long resourceId) {
final List<Long> 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;
}
}

View File

@ -324,12 +324,14 @@
<bean id="vpcDaoImpl" class="com.cloud.network.vpc.dao.VpcDaoImpl" />
<bean id="vpcGatewayDaoImpl" class="com.cloud.network.vpc.dao.VpcGatewayDaoImpl" />
<bean id="vpcOfferingDaoImpl" class="com.cloud.network.vpc.dao.VpcOfferingDaoImpl" />
<bean id="vpcOfferingJoinDaoImpl" class="com.cloud.api.query.dao.VpcOfferingJoinDaoImpl" />
<bean id="vpcOfferingServiceMapDaoImpl" class="com.cloud.network.vpc.dao.VpcOfferingServiceMapDaoImpl" />
<bean id="vpcServiceMapDaoImpl" class="com.cloud.network.vpc.dao.VpcServiceMapDaoImpl" />
<bean id="vpnUserDaoImpl" class="com.cloud.network.dao.VpnUserDaoImpl" />
<bean id="applicationLbRuleDaoImpl" class="org.apache.cloudstack.lb.dao.ApplicationLoadBalancerRuleDaoImpl" />
<bean id="networkOfferingDetailsDaoImpl" class="com.cloud.offerings.dao.NetworkOfferingDetailsDaoImpl" />
<bean id="serviceOfferingDetailsDaoImpl" class="com.cloud.service.dao.ServiceOfferingDetailsDaoImpl"/>
<bean id="vpcOfferingDetailsDaoImpl" class="com.cloud.network.vpc.dao.VpcOfferingDetailsDaoImpl"/>
<bean id="networkDetailsDaoImpl" class="com.cloud.network.dao.NetworkDetailsDaoImpl" />
<bean id="vlanDetailsDaoImpl" class="com.cloud.dc.dao.VlanDetailsDaoImpl" />
<bean id="hostGpuGroupsDaoImpl" class="com.cloud.gpu.dao.HostGpuGroupsDaoImpl" />

View File

@ -218,4 +218,53 @@ CREATE VIEW `cloud`.`network_offering_view` AS
LEFT JOIN
`cloud`.`data_center` AS `zone` ON FIND_IN_SET(`zone`.`id`, `zone_details`.`value`)
GROUP BY
`network_offerings`.`id`;
`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`,
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`;

View File

@ -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);

View File

@ -61,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;
@ -97,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;
@ -121,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;
@ -425,6 +428,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;
@ -644,6 +648,8 @@ public class ApiDBUtils {
@Inject
private VpcOfferingDao vpcOfferingDao;
@Inject
private VpcOfferingJoinDao vpcOfferingJoinDao;
@Inject
private SnapshotPolicyDao snapshotPolicyDao;
@Inject
private AsyncJobDao asyncJobDao;
@ -780,6 +786,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;
@ -1542,6 +1549,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);
}

View File

@ -187,6 +187,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;
@ -2799,15 +2800,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<Service, Set<Provider>> serviceProviderMap = ApiDBUtils.listVpcOffServices(offering.getId());
List<ServiceResponse> serviceResponses = new ArrayList<ServiceResponse>();
for (Map.Entry<Service, Set<Provider>> entry : serviceProviderMap.entrySet()) {
@ -2833,7 +2829,6 @@ public class ApiResponseHelper implements ResponseGenerator {
serviceResponses.add(svcRsp);
}
response.setServices(serviceResponses);
response.setObjectName("vpcoffering");
return response;
}

View File

@ -0,0 +1,35 @@
// 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 com.cloud.api.query.vo.VpcOfferingJoinVO;
import com.cloud.network.vpc.VpcOffering;
import com.cloud.utils.db.GenericDao;
public interface VpcOfferingJoinDao extends GenericDao<VpcOfferingJoinVO, Long> {
List<VpcOfferingJoinVO> findByDomainId(long domainId);
VpcOfferingResponse newVpcOfferingResponse(VpcOffering offering);
VpcOfferingJoinVO newVpcOfferingView(VpcOffering offering);
}

View File

@ -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<VpcOfferingJoinVO, Long> implements VpcOfferingJoinDao {
public static final Logger s_logger = Logger.getLogger(VpcOfferingJoinDaoImpl.class);
private SearchBuilder<VpcOfferingJoinVO> 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<VpcOfferingJoinVO> findByDomainId(long domainId) {
SearchBuilder<VpcOfferingJoinVO> sb = createSearchBuilder();
sb.and("domainId", sb.entity().getDomainId(), SearchCriteria.Op.FIND_IN_SET);
sb.done();
SearchCriteria<VpcOfferingJoinVO> 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<VpcOfferingJoinVO> sc = sofIdSearch.create();
sc.setParameters("id", offering.getId());
List<VpcOfferingJoinVO> 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);
}
}

View File

@ -0,0 +1,198 @@
// 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 = "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 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();
}
}

View File

@ -39,6 +39,9 @@ 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.context.CallContext;
@ -57,6 +60,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;
@ -97,6 +101,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;
@ -153,6 +158,8 @@ public class VpcManagerImpl extends ManagerBase implements VpcManager, VpcProvis
@Inject
VpcOfferingDao _vpcOffDao;
@Inject
VpcOfferingDetailsDao vpcOfferingDetailsDao;
@Inject
VpcOfferingServiceMapDao _vpcOffSvcMapDao;
@Inject
VpcDao _vpcDao;
@ -204,6 +211,8 @@ public class VpcManagerImpl extends ManagerBase implements VpcManager, VpcProvis
VpcVirtualNetworkApplianceManager _routerService;
@Inject
DomainRouterDao _routerDao;
@Inject
DomainDao domainDao;
@Inject
private VpcPrivateGatewayTransactionCallable vpcTxCallable;
@ -341,10 +350,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<String> supportedServices = cmd.getSupportedServices();
final Map<String, List<String>> serviceProviderList = cmd.getServiceProviders();
final Map<String, List<String>> serviceCapabilitystList = cmd.getServiceCapabilitystList();
final Long serviceOfferingId = cmd.getServiceOfferingId();
final List<Long> domainIds = cmd.getDomainIds();
final List<Long> 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,
serviceCapabilitystList, 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<String> supportedServices, final Map<String, List<String>> serviceProviders,
final Map serviceCapabilitystList, final Long serviceOfferingId) {
final Map serviceCapabilitystList, final Long serviceOfferingId, List<Long> domainIds, List<Long> zoneIds) {
// Filter child domains when both parent and child domains are present
List<Long> filteredDomainIds = filterChildSubDomains(domainIds);
final Map<Network.Service, Set<Network.Provider>> svcProviderMap = new HashMap<Network.Service, Set<Network.Provider>>();
final Set<Network.Provider> defaultProviders = new HashSet<Network.Provider>();
@ -423,6 +469,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<VpcOfferingDetailsVO> 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;
@ -692,44 +753,110 @@ public class VpcManagerImpl extends ManagerBase implements VpcManager, VpcProvis
@Override
@ActionEvent(eventType = EventTypes.EVENT_VPC_OFFERING_UPDATE, eventDescription = "updating vpc offering")
public VpcOffering updateVpcOffering(final long vpcOffId, final String vpcOfferingName, final String displayText, final String state) {
public VpcOffering updateVpcOffering(UpdateVPCOfferingCmd cmd) {
final Long offeringId = cmd.getId();
final String vpcOfferingName = cmd.getVpcOfferingName();
final String displayText = cmd.getDisplayText();
final String state = cmd.getState();
final List<Long> domainIds = cmd.getDomainIds();
final List<Long> 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 (_dcDao.findById(zoneId) == null)
throw new InvalidParameterValueException("Please specify a valid zone id");
}
}
return updateVpcOffering(offeringId, vpcOfferingName, displayText, state, domainIds, zoneIds);
}
private VpcOffering updateVpcOffering(final long vpcOffId,final String vpcOfferingName, final String displayText, final String state, final List<Long> domainIds, final List<Long> zoneIds) {
CallContext.current().setEventDetails(" Id: " + vpcOffId);
// Verify input parameters
final VpcOfferingVO offeringToUpdate = _vpcOffDao.findById(vpcOffId);
List<Long> existingDomainIds = vpcOfferingDetailsDao.findDomainIds(vpcOffId);
if (offeringToUpdate == null) {
throw new InvalidParameterValueException("Unable to find vpc offering " + vpcOffId);
}
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);
// Filter child domains when both parent and child domains are present
List<Long> filteredDomainIds = filterChildSubDomains(domainIds);
if (CollectionUtils.isNotEmpty(existingDomainIds) && CollectionUtils.isNotEmpty(filteredDomainIds)) {
filteredDomainIds.removeIf(existingDomainIds::contains);
for (Long domainId : filteredDomainIds) {
for (Long existingDomainId : existingDomainIds) {
if (domainDao.isChildDomain(existingDomainId, domainId)) {
throw new InvalidParameterValueException("Unable to update VPC offering for domain " + domainDao.findById(domainId).getUuid() + " as offering is already available for parent domain");
}
}
}
if (!validState) {
throw new InvalidParameterValueException("Incorrect state value: " + state);
}
List<Long> filteredZoneIds = new ArrayList<>();
if (CollectionUtils.isNotEmpty(zoneIds)) {
filteredZoneIds.addAll(zoneIds);
List<Long> existingZoneIds = vpcOfferingDetailsDao.findZoneIds(vpcOffId);
if (CollectionUtils.isNotEmpty(existingZoneIds)) {
filteredZoneIds.removeIf(existingZoneIds::contains);
}
}
if (_vpcOffDao.update(vpcOffId, offering)) {
s_logger.debug("Updated VPC offeirng id=" + vpcOffId);
return _vpcOffDao.findById(vpcOffId);
} else {
return null;
final boolean updateNeeded = vpcOfferingName != null || displayText != null || state != null;
final VpcOfferingVO offering = _vpcOffDao.createForUpdate(vpcOffId);
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 (!_vpcOffDao.update(vpcOffId, offering)) {
return null;
}
}
List<VpcOfferingDetailsVO> detailsVO = new ArrayList<>();
for (Long domainId : filteredDomainIds) {
detailsVO.add(new VpcOfferingDetailsVO(vpcOffId, ApiConstants.DOMAIN_ID, String.valueOf(domainId), false));
}
for (Long zoneId : filteredZoneIds) {
detailsVO.add(new VpcOfferingDetailsVO(vpcOffId, ApiConstants.ZONE_ID, String.valueOf(zoneId), false));
}
if (!detailsVO.isEmpty()) {
for (VpcOfferingDetailsVO detailVO : detailsVO) {
vpcOfferingDetailsDao.persist(detailVO);
}
}
s_logger.debug("Updated VPC offeirng id=" + vpcOffId);
return _vpcOffDao.findById(vpcOffId);
}
@Override
@ -757,7 +884,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");
}
@ -786,9 +913,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);
}
@ -2502,4 +2629,27 @@ public class VpcManagerImpl extends ManagerBase implements VpcManager, VpcProvis
return _ntwkMgr.areRoutersRunning(_routerDao.listByVpcId(vpc.getId()));
}
private List<Long> filterChildSubDomains(final List<Long> domainIds) {
List<Long> 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;
}
}