diff --git a/api/src/com/cloud/async/AsyncJob.java b/api/src/com/cloud/async/AsyncJob.java index 866429b6547..d384a7ad920 100644 --- a/api/src/com/cloud/async/AsyncJob.java +++ b/api/src/com/cloud/async/AsyncJob.java @@ -50,7 +50,8 @@ public interface AsyncJob extends Identity, InternalIdentity { AutoScaleVmProfile, AutoScaleVmGroup, GlobalLoadBalancerRule, - AffinityGroup + AffinityGroup, + DedicatedGuestVlanRange } long getUserId(); diff --git a/api/src/com/cloud/event/EventTypes.java b/api/src/com/cloud/event/EventTypes.java index 0ee7f402fd7..26c40abb4fb 100755 --- a/api/src/com/cloud/event/EventTypes.java +++ b/api/src/com/cloud/event/EventTypes.java @@ -390,6 +390,10 @@ public class EventTypes { public static final String EVENT_AFFINITY_GROUP_REMOVE = "AG.REMOVE"; public static final String EVENT_VM_AFFINITY_GROUP_UPDATE = "VM.AG.UPDATE"; + // Dedicated guest vlan range + public static final String EVENT_GUEST_VLAN_RANGE_DEDICATE = "GUESTVLANRANGE.DEDICATE"; + public static final String EVENT_DEDICATED_GUEST_VLAN_RANGE_RELEASE = "GUESTVLANRANGE.RELEASE"; + static { // TODO: need a way to force author adding event types to declare the entity details as well, with out braking @@ -690,6 +694,9 @@ public class EventTypes { entityEventDetails.put(EVENT_AUTOSCALEVMGROUP_UPDATE, AutoScaleVmGroup.class.getName()); entityEventDetails.put(EVENT_AUTOSCALEVMGROUP_ENABLE, AutoScaleVmGroup.class.getName()); entityEventDetails.put(EVENT_AUTOSCALEVMGROUP_DISABLE, AutoScaleVmGroup.class.getName()); + + entityEventDetails.put(EVENT_GUEST_VLAN_RANGE_DEDICATE, GuestVlan.class.getName()); + entityEventDetails.put(EVENT_DEDICATED_GUEST_VLAN_RANGE_RELEASE, GuestVlan.class.getName()); } public static String getEntityForEvent (String eventName) { diff --git a/api/src/com/cloud/network/GuestVlan.java b/api/src/com/cloud/network/GuestVlan.java new file mode 100644 index 00000000000..a5173d87830 --- /dev/null +++ b/api/src/com/cloud/network/GuestVlan.java @@ -0,0 +1,31 @@ +// 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; + +import org.apache.cloudstack.api.Identity; +import org.apache.cloudstack.api.InternalIdentity; + +public interface GuestVlan extends InternalIdentity, Identity { + + public long getId(); + + public long getAccountId(); + + public String getGuestVlanRange(); + + public long getPhysicalNetworkId(); +} diff --git a/api/src/com/cloud/network/NetworkService.java b/api/src/com/cloud/network/NetworkService.java index bea92dc2481..5d4fd67d326 100755 --- a/api/src/com/cloud/network/NetworkService.java +++ b/api/src/com/cloud/network/NetworkService.java @@ -18,6 +18,8 @@ package com.cloud.network; import java.util.List; +import org.apache.cloudstack.api.command.admin.network.DedicateGuestVlanRangeCmd; +import org.apache.cloudstack.api.command.admin.network.ListDedicatedGuestVlanRangesCmd; import org.apache.cloudstack.api.command.admin.usage.ListTrafficTypeImplementorsCmd; import org.apache.cloudstack.api.command.user.network.RestartNetworkCmd; import org.apache.cloudstack.api.command.user.network.CreateNetworkCmd; @@ -29,6 +31,7 @@ import com.cloud.exception.InsufficientAddressCapacityException; import com.cloud.exception.InsufficientCapacityException; import com.cloud.exception.ResourceAllocationException; import com.cloud.exception.ResourceUnavailableException; +import com.cloud.network.GuestVlan; import com.cloud.network.Network.Service; import com.cloud.network.Networks.TrafficType; import com.cloud.user.Account; @@ -114,6 +117,12 @@ public interface NetworkService { boolean deletePhysicalNetworkTrafficType(Long id); + GuestVlan dedicateGuestVlanRange(DedicateGuestVlanRangeCmd cmd); + + Pair, Integer> listDedicatedGuestVlanRanges(ListDedicatedGuestVlanRangesCmd cmd); + + boolean releaseDedicatedGuestVlanRange(Long dedicatedGuestVlanRangeId); + Pair, Integer> listTrafficTypes(Long physicalNetworkId); diff --git a/api/src/org/apache/cloudstack/api/ApiConstants.java b/api/src/org/apache/cloudstack/api/ApiConstants.java index 1165c7b34f6..d57fe058d93 100755 --- a/api/src/org/apache/cloudstack/api/ApiConstants.java +++ b/api/src/org/apache/cloudstack/api/ApiConstants.java @@ -85,6 +85,7 @@ public class ApiConstants { public static final String GSLB_SERVICE_TYPE = "gslbservicetype"; public static final String GSLB_STICKY_SESSION_METHOD = "gslbstickysessionmethodname"; public static final String GUEST_CIDR_ADDRESS = "guestcidraddress"; + public static final String GUEST_VLAN_RANGE = "guestvlanrange"; public static final String HA_ENABLE = "haenable"; public static final String HOST_ID = "hostid"; public static final String HOST_NAME = "hostname"; @@ -221,6 +222,7 @@ public class ApiConstants { public static final String VIRTUAL_MACHINE_ID = "virtualmachineid"; public static final String VIRTUAL_MACHINE_IDS = "virtualmachineids"; public static final String VLAN = "vlan"; + public static final String VLAN_RANGE = "vlanrange"; public static final String REMOVE_VLAN="removevlan"; public static final String VLAN_ID = "vlanid"; public static final String VM_AVAILABLE = "vmavailable"; diff --git a/api/src/org/apache/cloudstack/api/ResponseGenerator.java b/api/src/org/apache/cloudstack/api/ResponseGenerator.java index cbf8bb27b90..8466bd8729e 100644 --- a/api/src/org/apache/cloudstack/api/ResponseGenerator.java +++ b/api/src/org/apache/cloudstack/api/ResponseGenerator.java @@ -198,6 +198,8 @@ public interface ResponseGenerator { IPAddressResponse createIPAddressResponse(IpAddress ipAddress); + GuestVlanRangeResponse createDedicatedGuestVlanRangeResponse(GuestVlan result); + GlobalLoadBalancerResponse createGlobalLoadBalancerResponse(GlobalLoadBalancerRule globalLoadBalancerRule); LoadBalancerResponse createLoadBalancerResponse(LoadBalancer loadBalancer); diff --git a/api/src/org/apache/cloudstack/api/command/admin/network/DedicateGuestVlanRangeCmd.java b/api/src/org/apache/cloudstack/api/command/admin/network/DedicateGuestVlanRangeCmd.java new file mode 100644 index 00000000000..532fd0be764 --- /dev/null +++ b/api/src/org/apache/cloudstack/api/command/admin/network/DedicateGuestVlanRangeCmd.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 org.apache.cloudstack.api.command.admin.network; + +import com.cloud.exception.ResourceAllocationException; +import com.cloud.exception.ResourceUnavailableException; +import com.cloud.network.GuestVlan; +import com.cloud.user.Account; +import org.apache.cloudstack.api.*; +import org.apache.cloudstack.api.response.*; +import org.apache.log4j.Logger; + +@APICommand(name = "dedicateGuestVlanRange", description="Dedicates a guest vlan range to an account", responseObject=GuestVlanRangeResponse.class) +public class DedicateGuestVlanRangeCmd extends BaseCmd { + public static final Logger s_logger = Logger.getLogger(DedicateGuestVlanRangeCmd.class.getName()); + + private static final String s_name = "dedicateguestvlanrangeresponse"; + + ///////////////////////////////////////////////////// + //////////////// API parameters ///////////////////// + ///////////////////////////////////////////////////// + + @Parameter(name=ApiConstants.VLAN_RANGE, type=CommandType.STRING, required=true, + description="guest vlan range to be dedicated") + private String vlan; + + @Parameter(name=ApiConstants.ACCOUNT, type=CommandType.STRING, required=true, + description="account who will own the VLAN") + private String accountName; + + @Parameter(name=ApiConstants.PROJECT_ID, type=CommandType.UUID, entityType = ProjectResponse.class, + description="project who will own the VLAN") + private Long projectId; + + @Parameter(name=ApiConstants.DOMAIN_ID, type=CommandType.UUID, entityType = DomainResponse.class, + required=true, description="domain ID of the account owning a VLAN") + private Long domainId; + + @Parameter(name=ApiConstants.PHYSICAL_NETWORK_ID, type=CommandType.UUID, entityType = PhysicalNetworkResponse.class, + required=true, description="physical network ID of the vlan") + private Long physicalNetworkId; + + ///////////////////////////////////////////////////// + /////////////////// Accessors /////////////////////// + ///////////////////////////////////////////////////// + + public String getVlan() { + return vlan; + } + + public String getAccountName() { + return accountName; + } + + public Long getDomainId() { + return domainId; + } + + public Long getPhysicalNetworkId() { + return physicalNetworkId; + } + + public Long getProjectId() { + return projectId; + } + + ///////////////////////////////////////////////////// + /////////////// API Implementation/////////////////// + ///////////////////////////////////////////////////// + + @Override + public String getCommandName() { + return s_name; + } + + @Override + public long getEntityOwnerId() { + return Account.ACCOUNT_ID_SYSTEM; + } + + @Override + public void execute() throws ResourceUnavailableException, ResourceAllocationException { + GuestVlan result = _networkService.dedicateGuestVlanRange(this); + if (result != null) { + GuestVlanRangeResponse response = _responseGenerator.createDedicatedGuestVlanRangeResponse(result); + response.setResponseName(getCommandName()); + response.setObjectName("dedicatedguestvlanrange"); + this.setResponseObject(response); + } else { + throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Failed to dedicate guest vlan range"); + } + } + +} diff --git a/api/src/org/apache/cloudstack/api/command/admin/network/ListDedicatedGuestVlanRangesCmd.java b/api/src/org/apache/cloudstack/api/command/admin/network/ListDedicatedGuestVlanRangesCmd.java new file mode 100644 index 00000000000..7f93efc780f --- /dev/null +++ b/api/src/org/apache/cloudstack/api/command/admin/network/ListDedicatedGuestVlanRangesCmd.java @@ -0,0 +1,129 @@ +// 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 org.apache.cloudstack.api.command.admin.network; + +import com.cloud.network.GuestVlan; +import com.cloud.user.Account; +import com.cloud.utils.Pair; +import org.apache.cloudstack.api.*; +import org.apache.cloudstack.api.response.*; +import org.apache.log4j.Logger; + +import java.util.ArrayList; +import java.util.List; + + +@APICommand(name = "listDedicatedGuestVlanRanges", description="Lists dedicated guest vlan ranges", responseObject=GuestVlanRangeResponse.class) +public class ListDedicatedGuestVlanRangesCmd extends BaseListCmd { + public static final Logger s_logger = Logger.getLogger(ListDedicatedGuestVlanRangesCmd.class.getName()); + + private static final String s_name = "listdedicatedguestvlanrangesresponse"; + + ///////////////////////////////////////////////////// + //////////////// API parameters ///////////////////// + ///////////////////////////////////////////////////// + + @Parameter(name=ApiConstants.ID, type=CommandType.UUID, entityType=GuestVlanRangeResponse.class, + description="list dedicated guest vlan ranges by id") + private Long id; + + @Parameter(name=ApiConstants.ACCOUNT, type=CommandType.STRING, description="the account with which the guest VLAN range is associated. Must be used with the domainId parameter.") + private String accountName; + + @Parameter(name=ApiConstants.PROJECT_ID, type=CommandType.UUID, entityType = ProjectResponse.class, + description="project who will own the guest VLAN range") + private Long projectId; + + @Parameter(name=ApiConstants.DOMAIN_ID, type=CommandType.UUID, entityType = DomainResponse.class, + description="the domain ID with which the guest VLAN range is associated. If used with the account parameter, returns all guest VLAN ranges for that account in the specified domain.") + private Long domainId; + + @Parameter(name=ApiConstants.GUEST_VLAN_RANGE, type=CommandType.STRING, description="the dedicated guest vlan range") + private String guestVlanRange; + + @Parameter(name=ApiConstants.PHYSICAL_NETWORK_ID, type=CommandType.UUID, entityType = PhysicalNetworkResponse.class, + description="physical network id of the guest VLAN range") + private Long physicalNetworkId; + + @Parameter(name=ApiConstants.ZONE_ID, type=CommandType.UUID, entityType = ZoneResponse.class, + description="zone of the guest VLAN range") + private Long zoneId; + + ///////////////////////////////////////////////////// + /////////////////// Accessors /////////////////////// + ///////////////////////////////////////////////////// + + public Long getId() { + return id; + } + + public String getAccountName() { + return accountName; + } + + public Long getDomainId() { + return domainId; + } + + public Long getProjectId() { + return projectId; + } + + public String getGuestVlanRange() { + return guestVlanRange; + } + + public Long getPhysicalNetworkId() { + return physicalNetworkId; + } + + public Long getZoneId() { + return zoneId; + } + + + ///////////////////////////////////////////////////// + /////////////// API Implementation/////////////////// + ///////////////////////////////////////////////////// + + @Override + public String getCommandName() { + return s_name; + } + + @Override + public long getEntityOwnerId() { + return Account.ACCOUNT_ID_SYSTEM; + } + + @Override + public void execute(){ + Pair, Integer> vlans = _networkService.listDedicatedGuestVlanRanges(this); + ListResponse response = new ListResponse(); + List guestVlanResponses = new ArrayList(); + for (GuestVlan vlan : vlans.first()) { + GuestVlanRangeResponse guestVlanResponse = _responseGenerator.createDedicatedGuestVlanRangeResponse(vlan); + guestVlanResponse.setObjectName("dedicatedguestvlanrange"); + guestVlanResponses.add(guestVlanResponse); + } + + response.setResponses(guestVlanResponses, vlans.second()); + response.setResponseName(getCommandName()); + this.setResponseObject(response); + } + +} diff --git a/api/src/org/apache/cloudstack/api/command/admin/network/ReleaseDedicatedGuestVlanRangeCmd.java b/api/src/org/apache/cloudstack/api/command/admin/network/ReleaseDedicatedGuestVlanRangeCmd.java new file mode 100644 index 00000000000..76cb42dab19 --- /dev/null +++ b/api/src/org/apache/cloudstack/api/command/admin/network/ReleaseDedicatedGuestVlanRangeCmd.java @@ -0,0 +1,94 @@ +// 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 org.apache.cloudstack.api.command.admin.network; + +import com.cloud.async.AsyncJob; +import com.cloud.event.EventTypes; +import com.cloud.exception.ResourceInUseException; +import com.cloud.user.Account; +import com.cloud.user.UserContext; +import org.apache.cloudstack.api.*; +import org.apache.cloudstack.api.response.CounterResponse; +import org.apache.cloudstack.api.response.GuestVlanRangeResponse; +import org.apache.cloudstack.api.response.SuccessResponse; +import org.apache.log4j.Logger; + +@APICommand(name = "releaseDedicatedGuestVlanRange", description = "Releases a dedicated guest vlan range to the system", responseObject = SuccessResponse.class) +public class ReleaseDedicatedGuestVlanRangeCmd extends BaseAsyncCmd { + public static final Logger s_logger = Logger.getLogger(ReleaseDedicatedGuestVlanRangeCmd.class.getName()); + private static final String s_name = "releasededicatedguestvlanrangeresponse"; + + // /////////////////////////////////////////////////// + // ////////////// API parameters ///////////////////// + // /////////////////////////////////////////////////// + + @Parameter(name=ApiConstants.ID, type=CommandType.UUID, entityType=GuestVlanRangeResponse.class, + required=true, description="the ID of the dedicated guest vlan range") + private Long id; + + // /////////////////////////////////////////////////// + // ///////////////// Accessors /////////////////////// + // /////////////////////////////////////////////////// + + @Override + public String getCommandName() { + return s_name; + } + + public Long getId() { + return id; + } + + @Override + public AsyncJob.Type getInstanceType() { + return AsyncJob.Type.DedicatedGuestVlanRange; + } + + @Override + public long getEntityOwnerId() { + return Account.ACCOUNT_ID_SYSTEM; + } + + @Override + public String getEventType() { + return EventTypes.EVENT_DEDICATED_GUEST_VLAN_RANGE_RELEASE; + } + + @Override + public String getEventDescription() { + return "Releasing a dedicated guest vlan range."; + } + + // /////////////////////////////////////////////////// + // ///////////// API Implementation/////////////////// + // /////////////////////////////////////////////////// + + + @Override + public void execute(){ + UserContext.current().setEventDetails("Dedicated guest vlan range Id: " + id); + boolean result = _networkService.releaseDedicatedGuestVlanRange(getId()); + if (result) { + SuccessResponse response = new SuccessResponse(getCommandName()); + this.setResponseObject(response); + } else { + throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Failed to release dedicated guest vlan range"); + } + } + +} diff --git a/api/src/org/apache/cloudstack/api/response/GuestVlanRangeResponse.java b/api/src/org/apache/cloudstack/api/response/GuestVlanRangeResponse.java new file mode 100644 index 00000000000..bf19688c13f --- /dev/null +++ b/api/src/org/apache/cloudstack/api/response/GuestVlanRangeResponse.java @@ -0,0 +1,94 @@ +// 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 org.apache.cloudstack.api.response; + +import com.cloud.serializer.Param; +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.GuestVlan; + +@EntityReference(value=GuestVlan.class) +@SuppressWarnings("unused") +public class GuestVlanRangeResponse extends BaseResponse implements ControlledEntityResponse { + @SerializedName(ApiConstants.ID) @Param(description="the ID of the guest VLAN range") + private String id; + + @SerializedName(ApiConstants.ACCOUNT) @Param(description="the account of the guest VLAN range") + private String accountName; + + @SerializedName(ApiConstants.DOMAIN_ID) @Param(description="the domain ID of the guest VLAN range") + private String domainId; + + @SerializedName(ApiConstants.DOMAIN) @Param(description="the domain name of the guest VLAN range") + private String domainName; + + @SerializedName(ApiConstants.GUEST_VLAN_RANGE) @Param(description="the guest VLAN range") + private String guestVlanRange; + + @SerializedName(ApiConstants.PROJECT_ID) @Param(description="the project id of the guest vlan range") + private String projectId; + + @SerializedName(ApiConstants.PROJECT) @Param(description="the project name of the guest vlan range") + private String projectName; + + @SerializedName(ApiConstants.PHYSICAL_NETWORK_ID) @Param(description="the physical network of the guest vlan range") + private Long physicalNetworkId; + + @SerializedName(ApiConstants.ZONE_ID) @Param(description="the zone of the guest vlan range") + private Long zoneId; + + + public void setId(String id) { + this.id = id; + } + + public void setAccountName(String accountName) { + this.accountName = accountName; + } + + public void setDomainId(String domainId) { + this.domainId = domainId; + } + + public void setDomainName(String domainName) { + this.domainName = domainName; + } + + public void setGuestVlanRange(String guestVlanRange) { + this.guestVlanRange = guestVlanRange; + } + + public void setProjectId(String projectId) { + this.projectId = projectId; + } + + public void setProjectName(String projectName) { + this.projectName = projectName; + } + + public void setPhysicalNetworkId(Long physicalNetworkId) { + this.physicalNetworkId = physicalNetworkId; + } + + public void setZoneId(Long zoneId) { + this.zoneId = zoneId; + } + +} diff --git a/client/tomcatconf/applicationContext.xml.in b/client/tomcatconf/applicationContext.xml.in index 2e340bfbfab..d78700b4b64 100644 --- a/client/tomcatconf/applicationContext.xml.in +++ b/client/tomcatconf/applicationContext.xml.in @@ -165,6 +165,7 @@ + diff --git a/server/src/com/cloud/api/ApiDBUtils.java b/server/src/com/cloud/api/ApiDBUtils.java index e291c844a8c..b8eea12b4cf 100755 --- a/server/src/com/cloud/api/ApiDBUtils.java +++ b/server/src/com/cloud/api/ApiDBUtils.java @@ -130,6 +130,8 @@ import com.cloud.host.HostVO; import com.cloud.host.dao.HostDao; import com.cloud.host.dao.HostDetailsDao; import com.cloud.hypervisor.Hypervisor.HypervisorType; +import com.cloud.network.dao.AccountGuestVlanMapDao; +import com.cloud.network.dao.AccountGuestVlanMapVO; import com.cloud.network.IpAddress; import com.cloud.network.Network; import com.cloud.network.Network.Capability; @@ -309,6 +311,7 @@ public class ApiDBUtils { static GuestOSDao _guestOSDao; static GuestOSCategoryDao _guestOSCategoryDao; static HostDao _hostDao; + static AccountGuestVlanMapDao _accountGuestVlanMapDao; static IPAddressDao _ipAddressDao; static LoadBalancerDao _loadBalancerDao; static SecurityGroupDao _securityGroupDao; @@ -416,6 +419,7 @@ public class ApiDBUtils { @Inject private GuestOSDao guestOSDao; @Inject private GuestOSCategoryDao guestOSCategoryDao; @Inject private HostDao hostDao; + @Inject private AccountGuestVlanMapDao accountGuestVlanMapDao; @Inject private IPAddressDao ipAddressDao; @Inject private LoadBalancerDao loadBalancerDao; @Inject private SecurityGroupDao securityGroupDao; @@ -512,6 +516,7 @@ public class ApiDBUtils { _templateMgr = templateMgr; _accountDao = accountDao; + _accountGuestVlanMapDao = accountGuestVlanMapDao; _accountVlanMapDao = accountVlanMapDao; _clusterDao = clusterDao; _capacityDao = capacityDao; @@ -945,6 +950,15 @@ public class ApiDBUtils { } } + public static Long getAccountIdForGuestVlan(long vlanDbId) { + List accountGuestVlanMaps = _accountGuestVlanMapDao.listAccountGuestVlanMapsByVlan(vlanDbId); + if (accountGuestVlanMaps.isEmpty()) { + return null; + } else { + return accountGuestVlanMaps.get(0).getAccountId(); + } + } + public static HypervisorType getVolumeHyperType(long volumeId) { return _volumeDao.getHypervisorType(volumeId); } diff --git a/server/src/com/cloud/api/ApiResponseHelper.java b/server/src/com/cloud/api/ApiResponseHelper.java index 790c366cb0d..2804d1e97f3 100755 --- a/server/src/com/cloud/api/ApiResponseHelper.java +++ b/server/src/com/cloud/api/ApiResponseHelper.java @@ -180,7 +180,9 @@ import com.cloud.event.Event; import com.cloud.host.Host; import com.cloud.host.HostVO; import com.cloud.hypervisor.HypervisorCapabilities; +import com.cloud.network.dao.AccountGuestVlanMapVO; import com.cloud.network.IpAddress; +import com.cloud.network.GuestVlan; import com.cloud.network.Network; import com.cloud.network.Network.Capability; import com.cloud.network.Network.Provider; @@ -2725,6 +2727,25 @@ public class ApiResponseHelper implements ResponseGenerator { return response; } + @Override + public GuestVlanRangeResponse createDedicatedGuestVlanRangeResponse(GuestVlan vlan) { + GuestVlanRangeResponse guestVlanRangeResponse = new GuestVlanRangeResponse(); + + guestVlanRangeResponse.setId(vlan.getUuid()); + Long accountId= ApiDBUtils.getAccountIdForGuestVlan(vlan.getId()); + Account owner = ApiDBUtils.findAccountById(accountId); + if (owner != null) { + populateAccount(guestVlanRangeResponse, owner.getId()); + populateDomain(guestVlanRangeResponse, owner.getDomainId()); + } + guestVlanRangeResponse.setGuestVlanRange(vlan.getGuestVlanRange()); + guestVlanRangeResponse.setPhysicalNetworkId(vlan.getPhysicalNetworkId()); + PhysicalNetworkVO physicalNetwork = ApiDBUtils.findPhysicalNetworkById(vlan.getPhysicalNetworkId()); + guestVlanRangeResponse.setZoneId(physicalNetwork.getDataCenterId()); + + return guestVlanRangeResponse; + } + @Override public ServiceResponse createNetworkServiceResponse(Service service) { ServiceResponse response = new ServiceResponse(); diff --git a/server/src/com/cloud/dc/DataCenterVnetVO.java b/server/src/com/cloud/dc/DataCenterVnetVO.java index 52d7ad2067b..9bae132fb16 100755 --- a/server/src/com/cloud/dc/DataCenterVnetVO.java +++ b/server/src/com/cloud/dc/DataCenterVnetVO.java @@ -56,6 +56,9 @@ public class DataCenterVnetVO implements InternalIdentity { @Column(name="reservation_id") protected String reservationId; + + @Column(name="account_vnet_map_id") + protected Long accountGuestVlanMapId; public Date getTakenAt() { return takenAt; @@ -103,6 +106,14 @@ public class DataCenterVnetVO implements InternalIdentity { public long getPhysicalNetworkId() { return physicalNetworkId; } + + public void setAccountGuestVlanMapId(Long accountGuestVlanMapId) { + this.accountGuestVlanMapId = accountGuestVlanMapId; + } + + public Long getAccountGuestVlanMapId() { + return accountGuestVlanMapId; + } protected DataCenterVnetVO() { } diff --git a/server/src/com/cloud/dc/dao/DataCenterDaoImpl.java b/server/src/com/cloud/dc/dao/DataCenterDaoImpl.java index 4afd640d314..4d9d01065ca 100755 --- a/server/src/com/cloud/dc/dao/DataCenterDaoImpl.java +++ b/server/src/com/cloud/dc/dao/DataCenterDaoImpl.java @@ -16,6 +16,7 @@ // under the License. package com.cloud.dc.dao; +import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.Random; @@ -33,6 +34,8 @@ import com.cloud.dc.DataCenterLinkLocalIpAddressVO; import com.cloud.dc.DataCenterVO; import com.cloud.dc.DataCenterVnetVO; import com.cloud.dc.PodVlanVO; +import com.cloud.network.dao.AccountGuestVlanMapDao; +import com.cloud.network.dao.AccountGuestVlanMapVO; import com.cloud.org.Grouping; import com.cloud.utils.NumbersUtil; import com.cloud.utils.Pair; @@ -68,6 +71,7 @@ public class DataCenterDaoImpl extends GenericDaoBase implem @Inject protected DataCenterVnetDao _vnetAllocDao = null; @Inject protected PodVlanDao _podVlanAllocDao = null; @Inject protected DcDetailsDao _detailsDao = null; + @Inject protected AccountGuestVlanMapDao _accountGuestVlanMapDao = null; protected long _prefix; protected Random _rand = new Random(System.currentTimeMillis()); @@ -189,11 +193,20 @@ public class DataCenterDaoImpl extends GenericDaoBase implem @Override public String allocateVnet(long dataCenterId, long physicalNetworkId, long accountId, String reservationId) { - DataCenterVnetVO vo = _vnetAllocDao.take(physicalNetworkId, accountId, reservationId); + ArrayList dedicatedVlanDbIds = new ArrayList(); + List maps = _accountGuestVlanMapDao.listAccountGuestVlanMapsByAccount(accountId); + for (AccountGuestVlanMapVO map : maps) { + dedicatedVlanDbIds.add(map.getId()); + } + if (dedicatedVlanDbIds != null && !dedicatedVlanDbIds.isEmpty()) { + DataCenterVnetVO vo = _vnetAllocDao.take(physicalNetworkId, accountId, reservationId, dedicatedVlanDbIds); + if (vo != null) + return vo.getVnet(); + } + DataCenterVnetVO vo = _vnetAllocDao.take(physicalNetworkId, accountId, reservationId, null); if (vo == null) { return null; } - return vo.getVnet(); } diff --git a/server/src/com/cloud/dc/dao/DataCenterVnetDao.java b/server/src/com/cloud/dc/dao/DataCenterVnetDao.java index 7fb68dcd7ac..778498d8898 100644 --- a/server/src/com/cloud/dc/dao/DataCenterVnetDao.java +++ b/server/src/com/cloud/dc/dao/DataCenterVnetDao.java @@ -37,8 +37,13 @@ public interface DataCenterVnetDao extends GenericDao { public void lockRange(long dcId, long physicalNetworkId, Integer start, Integer end); - public DataCenterVnetVO take(long physicalNetworkId, long accountId, String reservationId); + public DataCenterVnetVO take(long physicalNetworkId, long accountId, String reservationId, List vlanDbIds); public void release(String vnet, long physicalNetworkId, long accountId, String reservationId); + public void releaseDedicatedGuestVlans(Long dedicatedGuestVlanRangeId); + + public int countVnetsAllocatedToAccount(long dcId, long accountId); + + public int countVnetsDedicatedToAccount(long dcId, long accountId); } diff --git a/server/src/com/cloud/dc/dao/DataCenterVnetDaoImpl.java b/server/src/com/cloud/dc/dao/DataCenterVnetDaoImpl.java index 2e044394ddc..e97f2c62ee3 100755 --- a/server/src/com/cloud/dc/dao/DataCenterVnetDaoImpl.java +++ b/server/src/com/cloud/dc/dao/DataCenterVnetDaoImpl.java @@ -20,15 +20,22 @@ import java.sql.PreparedStatement; import java.sql.SQLException; import java.util.Date; import java.util.List; +import java.util.Map; + +import javax.inject.Inject; +import javax.naming.ConfigurationException; import com.cloud.exception.InvalidParameterValueException; import org.springframework.stereotype.Component; import com.cloud.dc.DataCenterVnetVO; +import com.cloud.network.dao.AccountGuestVlanMapDao; +import com.cloud.network.dao.AccountGuestVlanMapVO; import com.cloud.utils.db.DB; import com.cloud.utils.db.GenericDao; import com.cloud.utils.db.GenericDaoBase; import com.cloud.utils.db.GenericSearchBuilder; +import com.cloud.utils.db.JoinBuilder; import com.cloud.utils.db.SearchBuilder; import com.cloud.utils.db.SearchCriteria; import com.cloud.utils.db.SearchCriteria.Func; @@ -43,7 +50,9 @@ import com.cloud.utils.exception.CloudRuntimeException; @Component @DB(txn=false) public class DataCenterVnetDaoImpl extends GenericDaoBase implements DataCenterVnetDao { + private final SearchBuilder FreeVnetSearch; + private final SearchBuilder FreeDedicatedVnetSearch; private final SearchBuilder VnetDcSearch; private final SearchBuilder VnetDcSearchAllocated; private final SearchBuilder DcSearchAllocated; @@ -51,6 +60,12 @@ public class DataCenterVnetDaoImpl extends GenericDaoBase countZoneVlans; private final GenericSearchBuilder countAllocatedZoneVlans; private final SearchBuilder SearchRange; + private final SearchBuilder DedicatedGuestVlanRangeSearch; + private final GenericSearchBuilder countVnetsAllocatedToAccount; + protected GenericSearchBuilder countVnetsDedicatedToAccount; + protected SearchBuilder AccountGuestVlanMapSearch; + + @Inject protected AccountGuestVlanMapDao _accountGuestVlanMapDao; public List listAllocatedVnets(long physicalNetworkId) { SearchCriteria sc = DcSearchAllocated.create(); @@ -141,9 +156,15 @@ public class DataCenterVnetDaoImpl extends GenericDaoBase sc = FreeVnetSearch.create(); - sc.setParameters("physicalNetworkId", physicalNetworkId); + public DataCenterVnetVO take(long physicalNetworkId, long accountId, String reservationId, List vlanDbIds) { + SearchCriteria sc; + if (vlanDbIds != null) { + sc = FreeDedicatedVnetSearch.create(); + sc.setParameters("accountGuestVlanMapId", vlanDbIds.toArray()); + } else { + sc = FreeVnetSearch.create(); + } + sc.setParameters("physicalNetworkId", physicalNetworkId); Date now = new Date(); Transaction txn = Transaction.currentTxn(); txn.start(); @@ -160,6 +181,7 @@ public class DataCenterVnetDaoImpl extends GenericDaoBase sc = VnetDcSearchAllocated.create(); sc.setParameters("vnet", vnet); @@ -178,6 +200,51 @@ public class DataCenterVnetDaoImpl extends GenericDaoBase sc = DedicatedGuestVlanRangeSearch.create(); + sc.setParameters("dedicatedGuestVlanRangeId", dedicatedGuestVlanRangeId); + List vnets = listBy(sc); + for(DataCenterVnetVO vnet : vnets) { + vnet.setAccountGuestVlanMapId(null); + update(vnet.getId(), vnet); + } + } + + @Override + public int countVnetsAllocatedToAccount(long dcId, long accountId) { + SearchCriteria sc = countVnetsAllocatedToAccount.create(); + sc.setParameters("dc", dcId); + sc.setParameters("accountId", accountId); + return customSearch(sc, null).get(0); + } + + @Override + public int countVnetsDedicatedToAccount(long dcId, long accountId) { + SearchCriteria sc = countVnetsDedicatedToAccount.create(); + sc.setParameters("dc", dcId); + sc.setParameters("accountId", accountId); + return customSearch(sc, null).get(0); + } + + @Override + public boolean configure(String name, Map params) throws ConfigurationException { + boolean result = super.configure(name, params); + + countVnetsDedicatedToAccount = createSearchBuilder(Integer.class); + countVnetsDedicatedToAccount.and("dc", countVnetsDedicatedToAccount.entity().getDataCenterId(), SearchCriteria.Op.EQ); + countVnetsDedicatedToAccount.and("accountGuestVlanMapId", countVnetsDedicatedToAccount.entity().getAccountGuestVlanMapId(), Op.NNULL); + AccountGuestVlanMapSearch = _accountGuestVlanMapDao.createSearchBuilder(); + AccountGuestVlanMapSearch.and("accountId", AccountGuestVlanMapSearch.entity().getAccountId(), SearchCriteria.Op.EQ); + countVnetsDedicatedToAccount.join("AccountGuestVlanMapSearch", AccountGuestVlanMapSearch, countVnetsDedicatedToAccount.entity().getAccountGuestVlanMapId(), + AccountGuestVlanMapSearch.entity().getId(), JoinBuilder.JoinType.INNER); + countVnetsDedicatedToAccount.select(null, Func.COUNT, countVnetsDedicatedToAccount.entity().getId()); + countVnetsDedicatedToAccount.done(); + AccountGuestVlanMapSearch.done(); + + return result; + } + public DataCenterVnetDaoImpl() { super(); DcSearchAllocated = createSearchBuilder(); @@ -202,7 +269,15 @@ public class DataCenterVnetDaoImpl extends GenericDaoBase _networkGurus; public List getNetworkGurus() { @@ -1998,8 +2003,29 @@ public class NetworkManagerImpl extends ManagerBase implements NetworkManager, L // For Isolated networks, don't allow to create network with vlan that already exists in the zone if (ntwkOff.getGuestType() == GuestType.Isolated) { if (_networksDao.countByZoneAndUri(zoneId, uri) > 0) { - throw new InvalidParameterValueException("Network with vlan " + vlanId + " already exists in zone " + zoneId); - } + throw new InvalidParameterValueException("Network with vlan " + vlanId + " already exists in zone " + zoneId); + } else { + DataCenterVnetVO dcVnet = _datacenterVnetDao.findVnet(zoneId, vlanId.toString()).get(0); + // Fail network creation if specified vlan is dedicated to a different account + if (dcVnet.getAccountGuestVlanMapId() != null) { + Long accountGuestVlanMapId = dcVnet.getAccountGuestVlanMapId(); + AccountGuestVlanMapVO map = _accountGuestVlanMapDao.findById(accountGuestVlanMapId); + if (map.getAccountId() != owner.getAccountId()) { + throw new InvalidParameterValueException("Vlan " + vlanId + " is dedicated to a different account"); + } + // Fail network creation if owner has a dedicated range of vlans but the specified vlan belongs to the system pool + } else { + List maps = _accountGuestVlanMapDao.listAccountGuestVlanMapsByAccount(owner.getAccountId()); + if (maps != null && !maps.isEmpty()) { + int vnetsAllocatedToAccount = _datacenterVnetDao.countVnetsAllocatedToAccount(zoneId, owner.getAccountId()); + int vnetsDedicatedToAccount = _datacenterVnetDao.countVnetsDedicatedToAccount(zoneId, owner.getAccountId()); + if (vnetsAllocatedToAccount < vnetsDedicatedToAccount) { + throw new InvalidParameterValueException("Specified vlan " + vlanId + " doesn't belong" + + " to the vlan range dedicated to the owner "+ owner.getAccountName()); + } + } + } + } } else { // don't allow to creating shared network with given Vlan ID, if there already exists a isolated network or // shared network with same Vlan ID in the zone @@ -2008,7 +2034,10 @@ public class NetworkManagerImpl extends ManagerBase implements NetworkManager, L throw new InvalidParameterValueException("There is a isolated/shared network with vlan id: " + vlanId + " already exists " + "in zone " + zoneId); } - } + } + + + } // If networkDomain is not specified, take it from the global configuration diff --git a/server/src/com/cloud/network/NetworkServiceImpl.java b/server/src/com/cloud/network/NetworkServiceImpl.java index d8f8d5dea2d..230d907aaa3 100755 --- a/server/src/com/cloud/network/NetworkServiceImpl.java +++ b/server/src/com/cloud/network/NetworkServiceImpl.java @@ -85,6 +85,8 @@ import com.cloud.vm.dao.*; import org.apache.cloudstack.acl.ControlledEntity.ACLType; import org.apache.cloudstack.acl.SecurityChecker; import org.apache.cloudstack.acl.SecurityChecker.AccessType; +import org.apache.cloudstack.api.command.admin.network.DedicateGuestVlanRangeCmd; +import org.apache.cloudstack.api.command.admin.network.ListDedicatedGuestVlanRangesCmd; import org.apache.cloudstack.api.command.admin.usage.ListTrafficTypeImplementorsCmd; import org.apache.cloudstack.api.command.user.network.CreateNetworkCmd; import org.apache.cloudstack.api.command.user.network.ListNetworksCmd; @@ -203,6 +205,8 @@ public class NetworkServiceImpl extends ManagerBase implements NetworkService { HostPodDao _hostPodDao; @Inject DataCenterVnetDao _datacneter_vnet; + @Inject + AccountGuestVlanMapDao _accountGuestVlanMapDao; int _cidrLimit; boolean _allowSubdomainNetworkAccess; @@ -2534,6 +2538,19 @@ public class NetworkServiceImpl extends ManagerBase implements NetworkService { txn.close(); throw new InvalidParameterValueException("Some of the vnets from this range are allocated, can only remove a range which has no allocated vnets"); } + // If the range is partially dedicated to an account fail the request + List maps = _accountGuestVlanMapDao.listAccountGuestVlanMapsByPhysicalNetwork(network.getId()); + for (AccountGuestVlanMapVO map : maps) { + String[] vlans = map.getGuestVlanRange().split("-"); + Integer dedicatedStartVlan = Integer.parseInt(vlans[0]); + Integer dedicatedEndVlan = Integer.parseInt(vlans[1]); + if ((start >= dedicatedStartVlan && start <= dedicatedEndVlan) || (end >= dedicatedStartVlan && end <= dedicatedEndVlan)) { + txn.close(); + throw new InvalidParameterValueException("Vnet range " + map.getGuestVlanRange() + " is dedicated" + + " to an account. The specified range " + start + "-" + end + " overlaps with the dedicated range " + + " Please release the overlapping dedicated range before deleting the range"); + } + } for (i=0; i= end){ temp = existingRanges.get(i).second(); @@ -2564,6 +2581,7 @@ public class NetworkServiceImpl extends ManagerBase implements NetworkService { _physicalNetworkDao.update(network.getId(), network); txn.commit(); _physicalNetworkDao.releaseFromLockTable(network.getId()); + return true; } @@ -2700,6 +2718,260 @@ public class NetworkServiceImpl extends ManagerBase implements NetworkService { } + @Override + @DB + @ActionEvent(eventType = EventTypes.EVENT_GUEST_VLAN_RANGE_DEDICATE, eventDescription = "dedicating guest vlan range", async = false) + public GuestVlan dedicateGuestVlanRange(DedicateGuestVlanRangeCmd cmd) { + String vlan = cmd.getVlan(); + String accountName = cmd.getAccountName(); + Long domainId = cmd.getDomainId(); + Long physicalNetworkId = cmd.getPhysicalNetworkId(); + Long projectId = cmd.getProjectId(); + + int startVlan, endVlan; + String updatedVlanRange = null; + long guestVlanMapId = 0; + long guestVlanMapAccountId = 0; + + // Verify account is valid + Account vlanOwner = null; + if (projectId != null) { + if (accountName != null) { + throw new InvalidParameterValueException("accountName and projectId are mutually exclusive"); + } + Project project = _projectMgr.getProject(projectId); + if (project == null) { + throw new InvalidParameterValueException("Unable to find project by id " + projectId); + } + vlanOwner = _accountMgr.getAccount(project.getProjectAccountId()); + } + + if ((accountName != null) && (domainId != null)) { + vlanOwner = _accountDao.findActiveAccount(accountName, domainId); + if (vlanOwner == null) { + throw new InvalidParameterValueException("Unable to find account by name " + accountName); + } + } + + // Verify physical network isolation type is VLAN + PhysicalNetworkVO physicalNetwork = _physicalNetworkDao.findById(physicalNetworkId); + if (physicalNetwork == null ) { + throw new InvalidParameterValueException("Unable to find physical network by id " + physicalNetworkId); + } else if (physicalNetwork.getIsolationMethods() == null || !physicalNetwork.getIsolationMethods().contains("VLAN")) { + throw new InvalidParameterValueException("Cannot dedicate guest vlan range. " + + "Physical isolation type of network " + physicalNetworkId + " is not VLAN"); + } + + // Get the start and end vlan + String[] vlanRange = vlan.split("-"); + if (vlanRange.length != 2) { + throw new InvalidParameterValueException("Invalid format for parameter value vlan " + vlan + " .Vlan should be specified as 'startvlan-endvlan'"); + } + + try { + startVlan = Integer.parseInt(vlanRange[0]); + endVlan = Integer.parseInt(vlanRange[1]); + } catch (NumberFormatException e) { + s_logger.warn("Unable to parse guest vlan range:", e); + throw new InvalidParameterValueException("Please provide valid guest vlan range"); + } + + // Verify guest vlan range exists in the system + List > existingRanges = physicalNetwork.getVnet(); + Boolean exists = false; + if (!existingRanges.isEmpty()) { + for (int i=0 ; i < existingRanges.size(); i++){ + int existingStartVlan = existingRanges.get(i).first(); + int existingEndVlan = existingRanges.get(i).second(); + if (startVlan >= existingStartVlan && endVlan <= existingEndVlan) { + exists = true; + break; + } + } + if (!exists) { + throw new InvalidParameterValueException("Unable to find guest vlan by range " + vlan); + } + } + + // Verify guest vlans in the range don't belong to a network of a different account + for (int i = startVlan; i <= endVlan; i++) { + List allocatedVlans = _datacneter_vnet.listAllocatedVnetsInRange(physicalNetwork.getDataCenterId(), physicalNetwork.getId(), startVlan, endVlan); + if (allocatedVlans != null && !allocatedVlans.isEmpty()){ + for (DataCenterVnetVO allocatedVlan : allocatedVlans) { + if (allocatedVlan.getAccountId() != vlanOwner.getAccountId()) { + throw new InvalidParameterValueException("Guest vlan from this range " + allocatedVlan.getVnet() + " is allocated to a different account." + + " Can only dedicate a range which has no allocated vlans or has vlans allocated to the same account "); + } + } + } + } + + List guestVlanMaps = _accountGuestVlanMapDao.listAccountGuestVlanMapsByPhysicalNetwork(physicalNetworkId); + for (AccountGuestVlanMapVO guestVlanMap : guestVlanMaps) { + List vlanTokens = getVlanFromRange(guestVlanMap.getGuestVlanRange()); + int dedicatedStartVlan = vlanTokens.get(0).intValue(); + int dedicatedEndVlan = vlanTokens.get(1).intValue(); + guestVlanMapId = guestVlanMap.getId(); + guestVlanMapAccountId = guestVlanMap.getAccountId(); + + // Verify if range is already dedicated + if (startVlan >= dedicatedStartVlan && endVlan <= dedicatedEndVlan) { + if (guestVlanMap.getAccountId() != vlanOwner.getAccountId()) { + throw new InvalidParameterValueException("Vlan range is already dedicated to another account. Cannot dedicate guest vlan range " + vlan); + } else { + s_logger.debug("Vlan range " + vlan +" is already dedicated to the specified account" + accountName); + return guestVlanMap; + } + } + // Verify if range overlaps with an existing range + if (startVlan < dedicatedStartVlan & endVlan+1 >= dedicatedStartVlan & endVlan <= dedicatedEndVlan) { // extend to the left + updatedVlanRange = startVlan + "-" + dedicatedEndVlan; + break; + } else if (startVlan >= dedicatedStartVlan & startVlan-1 <= dedicatedEndVlan & endVlan > dedicatedEndVlan) { // extend to right + updatedVlanRange = dedicatedStartVlan + "-" + endVlan; + break; + } else if (startVlan < dedicatedStartVlan & endVlan > dedicatedEndVlan){ // extend to the left and right + updatedVlanRange = startVlan + "-" + endVlan; + break; + } + } + + AccountGuestVlanMapVO accountGuestVlanMapVO; + if (updatedVlanRange != null) { + if (guestVlanMapAccountId != vlanOwner.getAccountId()) { + throw new InvalidParameterValueException("Vlan range is partially dedicated to another account. Cannot dedicate guest vlan range " + vlan); + } + accountGuestVlanMapVO = _accountGuestVlanMapDao.findById(guestVlanMapId); + accountGuestVlanMapVO.setGuestVlanRange(updatedVlanRange); + _accountGuestVlanMapDao.update(guestVlanMapId, accountGuestVlanMapVO); + } else { + Transaction txn = Transaction.currentTxn(); + accountGuestVlanMapVO = new AccountGuestVlanMapVO(vlanOwner.getAccountId(), physicalNetworkId); + accountGuestVlanMapVO.setGuestVlanRange(startVlan + "-" + endVlan); + _accountGuestVlanMapDao.persist(accountGuestVlanMapVO); + txn.commit(); + } + // For every guest vlan set the corresponding account guest vlan map id + for (int i = startVlan; i <= endVlan; i++) { + List dataCenterVnet = _datacneter_vnet.findVnet(physicalNetwork.getDataCenterId(),((Integer)i).toString()); + dataCenterVnet.get(0).setAccountGuestVlanMapId(accountGuestVlanMapVO.getId()); + _datacneter_vnet.update(dataCenterVnet.get(0).getId(), dataCenterVnet.get(0)); + } + return accountGuestVlanMapVO; + } + + private List getVlanFromRange(String vlanRange) { + // Get the start and end vlan + String[] vlanTokens = vlanRange.split("-"); + List tokens = new ArrayList(); + try { + int startVlan = Integer.parseInt(vlanTokens[0]); + int endVlan = Integer.parseInt(vlanTokens[1]); + tokens.add(startVlan); + tokens.add(endVlan); + } catch (NumberFormatException e) { + s_logger.warn("Unable to parse guest vlan range:", e); + throw new InvalidParameterValueException("Please provide valid guest vlan range"); + } + return tokens; + } + + @Override + public Pair, Integer> listDedicatedGuestVlanRanges(ListDedicatedGuestVlanRangesCmd cmd) { + Long id = cmd.getId(); + String accountName = cmd.getAccountName(); + Long domainId = cmd.getDomainId(); + Long projectId = cmd.getProjectId(); + String guestVlanRange = cmd.getGuestVlanRange(); + Long physicalNetworkId = cmd.getPhysicalNetworkId(); + Long zoneId = cmd.getZoneId(); + + Long accountId = null; + if (accountName != null && domainId != null) { + if (projectId != null) { + throw new InvalidParameterValueException("Account and projectId can't be specified together"); + } + Account account = _accountDao.findActiveAccount(accountName, domainId); + if (account == null) { + InvalidParameterValueException ex = new InvalidParameterValueException("Unable to find account " + accountName); + ex.addProxyObject("domain", domainId, "domainId"); + throw ex; + } else { + accountId = account.getId(); + } + } + + // set project information + if (projectId != null) { + Project project = _projectMgr.getProject(projectId); + if (project == null) { + InvalidParameterValueException ex = new InvalidParameterValueException("Unable to find project by id " + projectId); + ex.addProxyObject(project, projectId, "projectId"); + throw ex; + } + accountId = project.getProjectAccountId(); + } + + + SearchBuilder sb = _accountGuestVlanMapDao.createSearchBuilder(); + sb.and("id", sb.entity().getId(), SearchCriteria.Op.EQ); + sb.and("accountId", sb.entity().getAccountId(), SearchCriteria.Op.EQ); + sb.and("guestVlanRange", sb.entity().getGuestVlanRange(), SearchCriteria.Op.EQ); + sb.and("physicalNetworkId", sb.entity().getPhysicalNetworkId(), SearchCriteria.Op.EQ); + + if (zoneId != null) { + SearchBuilder physicalnetworkSearch = _physicalNetworkDao.createSearchBuilder(); + physicalnetworkSearch.and("zoneId", physicalnetworkSearch.entity().getDataCenterId(), SearchCriteria.Op.EQ); + sb.join("physicalnetworkSearch", physicalnetworkSearch, sb.entity().getPhysicalNetworkId(), physicalnetworkSearch.entity().getId(), JoinBuilder.JoinType.INNER); + } + + SearchCriteria sc = sb.create(); + if (id != null) { + sc.setParameters("id", id); + } + + if (accountId != null) { + sc.setParameters("accountId", accountId); + } + + if (guestVlanRange != null) { + sc.setParameters("guestVlanRange", guestVlanRange); + } + + if (physicalNetworkId != null) { + sc.setParameters("physicalNetworkId", physicalNetworkId); + } + + if (zoneId != null) { + sc.setJoinParameters("physicalnetworkSearch", "zoneId", zoneId); + } + + Filter searchFilter = new Filter(AccountGuestVlanMapVO.class, "id", true, cmd.getStartIndex(), cmd.getPageSizeVal()); + Pair, Integer> result = _accountGuestVlanMapDao.searchAndCount(sc, searchFilter); + return new Pair, Integer>(result.first(), result.second()); + } + + @Override + @ActionEvent(eventType = EventTypes.EVENT_DEDICATED_GUEST_VLAN_RANGE_RELEASE, eventDescription = "releasing" + + " dedicated guest vlan range", async = true) + @DB + public boolean releaseDedicatedGuestVlanRange(Long dedicatedGuestVlanRangeId) { + // Verify dedicated range exists + AccountGuestVlanMapVO dedicatedGuestVlan = _accountGuestVlanMapDao.findById(dedicatedGuestVlanRangeId); + if (dedicatedGuestVlan == null) { + throw new InvalidParameterValueException("Dedicated guest vlan with specified" + + " id doesn't exist in the system"); + } + + // Remove dedication for the guest vlan + _datacneter_vnet.releaseDedicatedGuestVlans(dedicatedGuestVlan.getId()); + if (_accountGuestVlanMapDao.remove(dedicatedGuestVlanRangeId)) { + return true; + } else { + return false; + } + } + @Override public List listNetworkServices(String providerName) { diff --git a/server/src/com/cloud/network/dao/AccountGuestVlanMapDao.java b/server/src/com/cloud/network/dao/AccountGuestVlanMapDao.java new file mode 100644 index 00000000000..dc1ec895d80 --- /dev/null +++ b/server/src/com/cloud/network/dao/AccountGuestVlanMapDao.java @@ -0,0 +1,34 @@ +// 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.dao; + +import com.cloud.network.dao.AccountGuestVlanMapVO; +import com.cloud.utils.db.GenericDao; + +import java.util.List; + +public interface AccountGuestVlanMapDao extends GenericDao { + + public List listAccountGuestVlanMapsByAccount(long accountId); + + public List listAccountGuestVlanMapsByVlan(long guestVlanId); + + public List listAccountGuestVlanMapsByPhysicalNetwork(long physicalNetworkId); + + public int removeByAccountId(long accountId); + +} diff --git a/server/src/com/cloud/network/dao/AccountGuestVlanMapDaoImpl.java b/server/src/com/cloud/network/dao/AccountGuestVlanMapDaoImpl.java new file mode 100644 index 00000000000..e7a7b34d9bd --- /dev/null +++ b/server/src/com/cloud/network/dao/AccountGuestVlanMapDaoImpl.java @@ -0,0 +1,83 @@ +// 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.dao; + +import com.cloud.network.dao.AccountGuestVlanMapVO; +import com.cloud.network.dao.AccountGuestVlanMapDao; + +import java.util.List; +import javax.ejb.Local; +import org.springframework.stereotype.Component; + +import com.cloud.utils.db.DB; +import com.cloud.utils.db.GenericDaoBase; +import com.cloud.utils.db.SearchBuilder; +import com.cloud.utils.db.SearchCriteria; + +@Component +@Local(value={AccountGuestVlanMapDao.class}) +@DB(txn=false) +public class AccountGuestVlanMapDaoImpl extends GenericDaoBase implements AccountGuestVlanMapDao { + + protected SearchBuilder AccountSearch; + protected SearchBuilder GuestVlanSearch; + protected SearchBuilder PhysicalNetworkSearch; + + @Override + public List listAccountGuestVlanMapsByAccount(long accountId) { + SearchCriteria sc = AccountSearch.create(); + sc.setParameters("accountId", accountId); + return listIncludingRemovedBy(sc); + } + + @Override + public List listAccountGuestVlanMapsByVlan(long guestVlanId) { + SearchCriteria sc = GuestVlanSearch.create(); + sc.setParameters("guestVlanId", guestVlanId); + return listIncludingRemovedBy(sc); + } + + @Override + public List listAccountGuestVlanMapsByPhysicalNetwork(long physicalNetworkId) { + SearchCriteria sc = GuestVlanSearch.create(); + sc.setParameters("physicalNetworkId", physicalNetworkId); + return listIncludingRemovedBy(sc); + } + + @Override + public int removeByAccountId(long accountId) { + SearchCriteria sc = AccountSearch.create(); + sc.setParameters("accountId", accountId); + return expunge(sc); + } + + public AccountGuestVlanMapDaoImpl() { + super(); + AccountSearch = createSearchBuilder(); + AccountSearch.and("accountId", AccountSearch.entity().getAccountId(), SearchCriteria.Op.EQ); + AccountSearch.done(); + + GuestVlanSearch = createSearchBuilder(); + GuestVlanSearch.and("guestVlanId", GuestVlanSearch.entity().getId(), SearchCriteria.Op.EQ); + GuestVlanSearch.done(); + + PhysicalNetworkSearch = createSearchBuilder(); + PhysicalNetworkSearch.and("physicalNetworkId", PhysicalNetworkSearch.entity().getId(), SearchCriteria.Op.EQ); + PhysicalNetworkSearch.done(); + } + +} diff --git a/server/src/com/cloud/network/dao/AccountGuestVlanMapVO.java b/server/src/com/cloud/network/dao/AccountGuestVlanMapVO.java new file mode 100644 index 00000000000..17c941a7e36 --- /dev/null +++ b/server/src/com/cloud/network/dao/AccountGuestVlanMapVO.java @@ -0,0 +1,94 @@ +// 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.dao; + +import com.cloud.network.GuestVlan; + +import javax.persistence.*; +import java.util.UUID; + +@Entity +@Table(name="account_vnet_map") +public class AccountGuestVlanMapVO implements GuestVlan { + + @Id + @GeneratedValue(strategy=GenerationType.IDENTITY) + @Column(name="id") + private long id; + + @Column(name="account_id") + private long accountId; + + @Column(name="uuid") + private String uuid; + + @Column(name="vnet_range") + private String guestVlanRange; + + @Column(name="physical_network_id") + private long physicalNetworkId; + + public AccountGuestVlanMapVO(long accountId,long physicalNetworkId) { + this.accountId = accountId; + this.physicalNetworkId = physicalNetworkId; + this.guestVlanRange = null; + this.uuid = UUID.randomUUID().toString(); + } + + public AccountGuestVlanMapVO() { + + } + + @Override + public long getId() { + return id; + } + + @Override + public long getAccountId() { + return accountId; + } + + @Override + public String getGuestVlanRange() { + return guestVlanRange; + } + + + public void setGuestVlanRange(String guestVlanRange) { + this.guestVlanRange = guestVlanRange; + } + + @Override + public String getUuid() { + return this.uuid; + } + + public void setUuid(String uuid) { + this.uuid = uuid; + } + + @Override + public long getPhysicalNetworkId() { + return this.physicalNetworkId; + } + + public void setPhysicalNetworkId(long physicalNetworkId) { + this.physicalNetworkId = physicalNetworkId; + } + +} diff --git a/server/src/com/cloud/server/ManagementServerImpl.java b/server/src/com/cloud/server/ManagementServerImpl.java index efd51e61c5f..5ddae88f1dd 100755 --- a/server/src/com/cloud/server/ManagementServerImpl.java +++ b/server/src/com/cloud/server/ManagementServerImpl.java @@ -2258,6 +2258,9 @@ public class ManagementServerImpl extends ManagerBase implements ManagementServe cmdList.add(UpdateNetworkServiceProviderCmd.class); cmdList.add(UpdatePhysicalNetworkCmd.class); cmdList.add(UpdateStorageNetworkIpRangeCmd.class); + cmdList.add(DedicateGuestVlanRangeCmd.class); + cmdList.add(ListDedicatedGuestVlanRangesCmd.class); + cmdList.add(ReleaseDedicatedGuestVlanRangeCmd.class); cmdList.add(CreateDiskOfferingCmd.class); cmdList.add(CreateServiceOfferingCmd.class); cmdList.add(DeleteDiskOfferingCmd.class); diff --git a/server/src/com/cloud/user/AccountManagerImpl.java b/server/src/com/cloud/user/AccountManagerImpl.java index 8de73fbd582..4088f64f58b 100755 --- a/server/src/com/cloud/user/AccountManagerImpl.java +++ b/server/src/com/cloud/user/AccountManagerImpl.java @@ -59,6 +59,7 @@ import com.cloud.configuration.dao.ConfigurationDao; import com.cloud.configuration.dao.ResourceCountDao; import com.cloud.dc.DataCenterVO; import com.cloud.dc.dao.DataCenterDao; +import com.cloud.dc.dao.DataCenterVnetDao; import com.cloud.domain.Domain; import com.cloud.domain.DomainVO; import com.cloud.domain.dao.DomainDao; @@ -76,6 +77,8 @@ import com.cloud.network.IpAddress; import com.cloud.network.NetworkManager; import com.cloud.network.VpnUserVO; import com.cloud.network.as.AutoScaleManager; +import com.cloud.network.dao.AccountGuestVlanMapDao; +import com.cloud.network.dao.AccountGuestVlanMapVO; import com.cloud.network.dao.IPAddressDao; import com.cloud.network.dao.IPAddressVO; import com.cloud.network.dao.NetworkDao; @@ -222,6 +225,10 @@ public class AccountManagerImpl extends ManagerBase implements AccountManager, M @Inject VolumeManager volumeMgr; @Inject private AffinityGroupDao _affinityGroupDao; + @Inject + private AccountGuestVlanMapDao _accountGuestVlanMapDao; + @Inject + private DataCenterVnetDao _dataCenterVnetDao; private List _userAuthenticators; List _userPasswordEncoders; @@ -699,6 +706,14 @@ public class AccountManagerImpl extends ManagerBase implements AccountManager, M } } + // release account specific guest vlans + List maps = _accountGuestVlanMapDao.listAccountGuestVlanMapsByAccount(accountId); + for (AccountGuestVlanMapVO map : maps) { + _dataCenterVnetDao.releaseDedicatedGuestVlans(map.getId()); + } + int vlansReleased = _accountGuestVlanMapDao.removeByAccountId(accountId); + s_logger.info("deleteAccount: Released " + vlansReleased + " dedicated guest vlan ranges from account " + accountId); + return true; } catch (Exception ex) { s_logger.warn("Failed to cleanup account " + account + " due to ", ex); diff --git a/server/test/com/cloud/network/DedicateGuestVlanRangesTest.java b/server/test/com/cloud/network/DedicateGuestVlanRangesTest.java new file mode 100644 index 00000000000..e81d7222a60 --- /dev/null +++ b/server/test/com/cloud/network/DedicateGuestVlanRangesTest.java @@ -0,0 +1,378 @@ +// 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; + +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; +import java.lang.reflect.Field; + +import org.apache.cloudstack.api.command.admin.network.DedicateGuestVlanRangeCmd; +import org.apache.cloudstack.api.command.admin.network.ListDedicatedGuestVlanRangesCmd; +import org.apache.cloudstack.api.command.admin.network.ReleaseDedicatedGuestVlanRangeCmd; + +import org.apache.log4j.Logger; +import org.junit.Before; +import org.junit.Test; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; + +import com.cloud.dc.DataCenterVnetVO; +import com.cloud.dc.dao.DataCenterVnetDao; +import com.cloud.network.dao.AccountGuestVlanMapDao; +import com.cloud.network.dao.AccountGuestVlanMapVO; +import com.cloud.network.dao.PhysicalNetworkDao; +import com.cloud.network.dao.PhysicalNetworkVO; +import com.cloud.projects.ProjectManager; +import com.cloud.user.Account; +import com.cloud.user.dao.AccountDao; +import com.cloud.user.AccountManager; +import com.cloud.user.AccountVO; +import com.cloud.user.UserContext; +import com.cloud.utils.db.Transaction; + +import junit.framework.Assert; + +import static org.mockito.Matchers.*; +import static org.mockito.Mockito.when; +import static org.mockito.Mockito.doNothing; + +public class DedicateGuestVlanRangesTest { + + private static final Logger s_logger = Logger.getLogger(DedicateGuestVlanRangesTest.class); + + NetworkServiceImpl networkService = new NetworkServiceImpl(); + + DedicateGuestVlanRangeCmd dedicateGuestVlanRangesCmd = new DedicateGuestVlanRangeCmdExtn(); + Class _dedicateGuestVlanRangeClass = dedicateGuestVlanRangesCmd.getClass().getSuperclass(); + + ReleaseDedicatedGuestVlanRangeCmd releaseDedicatedGuestVlanRangesCmd = new ReleaseDedicatedGuestVlanRangeCmdExtn(); + Class _releaseGuestVlanRangeClass = releaseDedicatedGuestVlanRangesCmd.getClass().getSuperclass(); + + ListDedicatedGuestVlanRangesCmd listDedicatedGuestVlanRangesCmd = new ListDedicatedGuestVlanRangesCmdExtn(); + Class _listDedicatedGuestVlanRangeClass = listDedicatedGuestVlanRangesCmd.getClass().getSuperclass(); + + + @Mock AccountManager _accountMgr; + @Mock AccountDao _accountDao; + @Mock ProjectManager _projectMgr; + @Mock PhysicalNetworkDao _physicalNetworkDao; + @Mock DataCenterVnetDao _dataCenterVnetDao; + @Mock AccountGuestVlanMapDao _accountGuestVlanMapDao; + + @Before + public void setup() throws Exception { + MockitoAnnotations.initMocks(this); + + networkService._accountMgr = _accountMgr; + networkService._accountDao = _accountDao; + networkService._projectMgr = _projectMgr; + networkService._physicalNetworkDao = _physicalNetworkDao; + networkService._datacneter_vnet = _dataCenterVnetDao; + networkService._accountGuestVlanMapDao = _accountGuestVlanMapDao; + + Account account = (Account) new AccountVO("testaccount", 1, "networkdomain", (short) 0, UUID.randomUUID().toString()); + when(networkService._accountMgr.getAccount(anyLong())).thenReturn(account); + when(networkService._accountDao.findActiveAccount(anyString(), anyLong())).thenReturn(account); + + UserContext.registerContext(1, account, null, true); + + Field accountNameField = _dedicateGuestVlanRangeClass.getDeclaredField("accountName"); + accountNameField.setAccessible(true); + accountNameField.set(dedicateGuestVlanRangesCmd, "accountname"); + + Field projectIdField = _dedicateGuestVlanRangeClass.getDeclaredField("projectId"); + projectIdField.setAccessible(true); + projectIdField.set(dedicateGuestVlanRangesCmd, null); + + Field domainIdField = _dedicateGuestVlanRangeClass.getDeclaredField("domainId"); + domainIdField.setAccessible(true); + domainIdField.set(dedicateGuestVlanRangesCmd, 1L); + + Field physicalNetworkIdField = _dedicateGuestVlanRangeClass.getDeclaredField("physicalNetworkId"); + physicalNetworkIdField.setAccessible(true); + physicalNetworkIdField.set(dedicateGuestVlanRangesCmd, 1L); + + Field releaseIdField = _releaseGuestVlanRangeClass.getDeclaredField("id"); + releaseIdField.setAccessible(true); + releaseIdField.set(releaseDedicatedGuestVlanRangesCmd, 1L); + } + + @Test + public void testDedicateGuestVlanRange() throws Exception { + s_logger.info("Running tests for DedicateGuestVlanRange API"); + + /* + * TEST 1: given valid parameters DedicateGuestVlanRange should succeed + */ + runDedicateGuestVlanRangePostiveTest(); + + /* + * TEST 2: given invalid format for vlan range DedicateGuestVlanRange should fail + */ + runDedicateGuestVlanRangeInvalidFormat(); + + /* + * TEST 3: given vlan range that doesn't exist in the system request should fail + */ + runDedicateGuestVlanRangeInvalidRangeValue(); + + /* + * TEST 4: given vlan range has vlans that are allocated to a different account request should fail + */ + runDedicateGuestVlanRangeAllocatedVlans(); + + /* + * TEST 5: given vlan range is already dedicated to another account request should fail + */ + runDedicateGuestVlanRangeDedicatedRange(); + + /* + * TEST 6: given vlan range is partially dedicated to a different account request should fail + */ + runDedicateGuestVlanRangePartiallyDedicated(); + } + + @Test + public void testReleaseDedicatedGuestVlanRange() throws Exception { + + s_logger.info("Running tests for ReleaseDedicatedGuestVlanRange API"); + + /* + * TEST 1: given valid parameters ReleaseDedicatedGuestVlanRange should succeed + */ + runReleaseDedicatedGuestVlanRangePostiveTest(); + + /* + * TEST 2: given range doesn't exist request should fail + */ + runReleaseDedicatedGuestVlanRangeInvalidRange(); + } + + void runDedicateGuestVlanRangePostiveTest() throws Exception { + Transaction txn = Transaction.open("runDedicateGuestVlanRangePostiveTest"); + + Field dedicateVlanField = _dedicateGuestVlanRangeClass.getDeclaredField("vlan"); + dedicateVlanField.setAccessible(true); + dedicateVlanField.set(dedicateGuestVlanRangesCmd, "2-5"); + + PhysicalNetworkVO physicalNetwork = new PhysicalNetworkVO(1L, 1L, "2-5", "200", 1L, null, "testphysicalnetwork"); + physicalNetwork.addIsolationMethod("VLAN"); + AccountGuestVlanMapVO accountGuestVlanMapVO = new AccountGuestVlanMapVO(1L,1L); + + when(networkService._physicalNetworkDao.findById(anyLong())).thenReturn(physicalNetwork); + + when(networkService._datacneter_vnet.listAllocatedVnetsInRange(anyLong(), anyLong(), anyInt(), anyInt())).thenReturn(null); + + when(networkService._accountGuestVlanMapDao.listAccountGuestVlanMapsByPhysicalNetwork(anyLong())).thenReturn(null); + + when(networkService._accountGuestVlanMapDao.persist(any(AccountGuestVlanMapVO.class))).thenReturn(accountGuestVlanMapVO); + + when(networkService._datacneter_vnet.update(anyLong(), any(DataCenterVnetVO.class))).thenReturn(true); + + List dataCenterVnetList = new ArrayList(); + DataCenterVnetVO dataCenterVnetVO = new DataCenterVnetVO("2-5", 1L, 1L); + dataCenterVnetList.add(dataCenterVnetVO); + when(networkService._datacneter_vnet.findVnet(anyLong(), anyString())).thenReturn(dataCenterVnetList); + + try { + GuestVlan result = networkService.dedicateGuestVlanRange(dedicateGuestVlanRangesCmd); + Assert.assertNotNull(result); + } catch (Exception e) { + s_logger.info("exception in testing runDedicateGuestVlanRangePostiveTest message: " + e.toString()); + } finally { + txn.close("runDedicateGuestRangePostiveTest"); + } + } + + void runDedicateGuestVlanRangeInvalidFormat() throws Exception { + Transaction txn = Transaction.open("runDedicateGuestVlanRangeInvalidFormat"); + + Field dedicateVlanField = _dedicateGuestVlanRangeClass.getDeclaredField("vlan"); + dedicateVlanField.setAccessible(true); + dedicateVlanField.set(dedicateGuestVlanRangesCmd, "2"); + + PhysicalNetworkVO physicalNetwork = new PhysicalNetworkVO(1L, 1L, "2-5", "200", 1L, null, "testphysicalnetwork"); + physicalNetwork.addIsolationMethod("VLAN"); + + when(networkService._physicalNetworkDao.findById(anyLong())).thenReturn(physicalNetwork); + + try { + networkService.dedicateGuestVlanRange(dedicateGuestVlanRangesCmd); + } catch (Exception e) { + Assert.assertTrue(e.getMessage().contains("Invalid format for parameter value vlan")); + } finally { + txn.close("runDedicateGuestVlanRangeInvalidFormat"); + } + } + + void runDedicateGuestVlanRangeInvalidRangeValue() throws Exception { + Transaction txn = Transaction.open("runDedicateGuestVlanRangeInvalidRangeValue"); + + Field dedicateVlanField = _dedicateGuestVlanRangeClass.getDeclaredField("vlan"); + dedicateVlanField.setAccessible(true); + dedicateVlanField.set(dedicateGuestVlanRangesCmd, "2-5"); + + PhysicalNetworkVO physicalNetwork = new PhysicalNetworkVO(1L, 1L, "6-10", "200", 1L, null, "testphysicalnetwork"); + physicalNetwork.addIsolationMethod("VLAN"); + + when(networkService._physicalNetworkDao.findById(anyLong())).thenReturn(physicalNetwork); + + try { + networkService.dedicateGuestVlanRange(dedicateGuestVlanRangesCmd); + } catch (Exception e) { + Assert.assertTrue(e.getMessage().contains("Unable to find guest vlan by range")); + } finally { + txn.close("runDedicateGuestVlanRangeInvalidRangeValue"); + } + } + + void runDedicateGuestVlanRangeAllocatedVlans() throws Exception { + Transaction txn = Transaction.open("runDedicateGuestVlanRangeAllocatedVlans"); + + Field dedicateVlanField = _dedicateGuestVlanRangeClass.getDeclaredField("vlan"); + dedicateVlanField.setAccessible(true); + dedicateVlanField.set(dedicateGuestVlanRangesCmd, "2-5"); + + PhysicalNetworkVO physicalNetwork = new PhysicalNetworkVO(1L, 1L, "2-5", "200", 1L, null, "testphysicalnetwork"); + physicalNetwork.addIsolationMethod("VLAN"); + when(networkService._physicalNetworkDao.findById(anyLong())).thenReturn(physicalNetwork); + + List dataCenterList = new ArrayList(); + DataCenterVnetVO dataCenter = new DataCenterVnetVO("2-5", 1L, 1L); + dataCenter.setAccountId(1L); + dataCenterList.add(dataCenter); + when(networkService._datacneter_vnet.listAllocatedVnetsInRange(anyLong(), anyLong(), anyInt(), anyInt())).thenReturn(dataCenterList); + + try { + networkService.dedicateGuestVlanRange(dedicateGuestVlanRangesCmd); + } catch (Exception e) { + Assert.assertTrue(e.getMessage().contains("is allocated to a different account")); + } finally { + txn.close("runDedicateGuestVlanRangeAllocatedVlans"); + } + } + + void runDedicateGuestVlanRangeDedicatedRange() throws Exception { + Transaction txn = Transaction.open("runDedicateGuestVlanRangeDedicatedRange"); + + Field dedicateVlanField = _dedicateGuestVlanRangeClass.getDeclaredField("vlan"); + dedicateVlanField.setAccessible(true); + dedicateVlanField.set(dedicateGuestVlanRangesCmd, "2-5"); + + PhysicalNetworkVO physicalNetwork = new PhysicalNetworkVO(1L, 1L, "2-5", "200", 1L, null, "testphysicalnetwork"); + physicalNetwork.addIsolationMethod("VLAN"); + + when(networkService._physicalNetworkDao.findById(anyLong())).thenReturn(physicalNetwork); + + when(networkService._datacneter_vnet.listAllocatedVnetsInRange(anyLong(), anyLong(), anyInt(), anyInt())).thenReturn(null); + + List guestVlanMaps = new ArrayList(); + AccountGuestVlanMapVO accountGuestVlanMap = new AccountGuestVlanMapVO(1L, 1L); + accountGuestVlanMap.setGuestVlanRange("2-5"); + guestVlanMaps.add(accountGuestVlanMap); + when(networkService._accountGuestVlanMapDao.listAccountGuestVlanMapsByPhysicalNetwork(anyLong())).thenReturn(guestVlanMaps); + + try { + networkService.dedicateGuestVlanRange(dedicateGuestVlanRangesCmd); + } catch (Exception e) { + Assert.assertTrue(e.getMessage().contains("Vlan range is already dedicated to another account")); + } finally { + txn.close("runDedicateGuestVlanRangeDedicatedRange"); + } + } + + void runDedicateGuestVlanRangePartiallyDedicated() throws Exception { + Transaction txn = Transaction.open("runDedicateGuestVlanRangePartiallyDedicated"); + + Field dedicateVlanField = _dedicateGuestVlanRangeClass.getDeclaredField("vlan"); + dedicateVlanField.setAccessible(true); + dedicateVlanField.set(dedicateGuestVlanRangesCmd, "2-5"); + + PhysicalNetworkVO physicalNetwork = new PhysicalNetworkVO(1L, 1L, "2-5", "200", 1L, null, "testphysicalnetwork"); + physicalNetwork.addIsolationMethod("VLAN"); + + when(networkService._physicalNetworkDao.findById(anyLong())).thenReturn(physicalNetwork); + + when(networkService._datacneter_vnet.listAllocatedVnetsInRange(anyLong(), anyLong(), anyInt(), anyInt())).thenReturn(null); + + List guestVlanMaps = new ArrayList(); + AccountGuestVlanMapVO accountGuestVlanMap = new AccountGuestVlanMapVO(2L, 1L); + accountGuestVlanMap.setGuestVlanRange("4-8"); + guestVlanMaps.add(accountGuestVlanMap); + when(networkService._accountGuestVlanMapDao.listAccountGuestVlanMapsByPhysicalNetwork(anyLong())).thenReturn(guestVlanMaps); + + try { + networkService.dedicateGuestVlanRange(dedicateGuestVlanRangesCmd); + } catch (Exception e) { + Assert.assertTrue(e.getMessage().contains("Vlan range is partially dedicated to another account")); + } finally { + txn.close("runDedicateGuestVlanRangePartiallyDedicated"); + } + } + + void runReleaseDedicatedGuestVlanRangePostiveTest() throws Exception { + Transaction txn = Transaction.open("runReleaseDedicatedGuestVlanRangePostiveTest"); + + AccountGuestVlanMapVO accountGuestVlanMap = new AccountGuestVlanMapVO(1L, 1L); + when(networkService._accountGuestVlanMapDao.findById(anyLong())).thenReturn(accountGuestVlanMap); + doNothing().when(networkService._datacneter_vnet).releaseDedicatedGuestVlans(anyLong()); + when(networkService._accountGuestVlanMapDao.remove(anyLong())).thenReturn(true); + + try { + Boolean result = networkService.releaseDedicatedGuestVlanRange(releaseDedicatedGuestVlanRangesCmd.getId()); + Assert.assertTrue(result); + } catch (Exception e) { + s_logger.info("exception in testing runReleaseGuestVlanRangePostiveTest1 message: " + e.toString()); + } finally { + txn.close("runReleaseDedicatedGuestVlanRangePostiveTest"); + } + } + + void runReleaseDedicatedGuestVlanRangeInvalidRange() throws Exception { + Transaction txn = Transaction.open("runReleaseDedicatedGuestVlanRangeInvalidRange"); + + when(networkService._accountGuestVlanMapDao.findById(anyLong())).thenReturn(null); + + try { + networkService.releaseDedicatedGuestVlanRange(releaseDedicatedGuestVlanRangesCmd.getId()); + } catch (Exception e) { + Assert.assertTrue(e.getMessage().contains("Dedicated guest vlan with specified id doesn't exist in the system")); + } finally { + txn.close("runReleaseDedicatedGuestVlanRangeInvalidRange"); + } + } + + public class DedicateGuestVlanRangeCmdExtn extends DedicateGuestVlanRangeCmd { + public long getEntityOwnerId() { + return 1; + } + } + + public class ReleaseDedicatedGuestVlanRangeCmdExtn extends ReleaseDedicatedGuestVlanRangeCmd { + public long getEntityOwnerId() { + return 1; + } + } + + public class ListDedicatedGuestVlanRangesCmdExtn extends ListDedicatedGuestVlanRangesCmd { + public long getEntityOwnerId() { + return 1; + } + } +} diff --git a/server/test/com/cloud/network/MockNetworkManagerImpl.java b/server/test/com/cloud/network/MockNetworkManagerImpl.java index 45562c6ea31..2f717c8c156 100755 --- a/server/test/com/cloud/network/MockNetworkManagerImpl.java +++ b/server/test/com/cloud/network/MockNetworkManagerImpl.java @@ -29,6 +29,7 @@ import com.cloud.network.Networks.TrafficType; import com.cloud.network.addr.PublicIp; import com.cloud.network.dao.IPAddressVO; import com.cloud.network.dao.NetworkVO; +import com.cloud.network.GuestVlan; import com.cloud.network.element.LoadBalancingServiceProvider; import com.cloud.network.element.StaticNatServiceProvider; import com.cloud.network.element.UserDataServiceProvider; @@ -46,6 +47,8 @@ import com.cloud.utils.component.ManagerBase; import com.cloud.vm.*; import com.cloud.vm.VirtualMachine.Type; import org.apache.cloudstack.acl.ControlledEntity.ACLType; +import org.apache.cloudstack.api.command.admin.network.DedicateGuestVlanRangeCmd; +import org.apache.cloudstack.api.command.admin.network.ListDedicatedGuestVlanRangesCmd; import org.apache.cloudstack.api.command.admin.usage.ListTrafficTypeImplementorsCmd; import org.apache.cloudstack.api.command.user.network.CreateNetworkCmd; import org.apache.cloudstack.api.command.user.network.ListNetworksCmd; @@ -326,6 +329,24 @@ public class MockNetworkManagerImpl extends ManagerBase implements NetworkManage } @Override + public GuestVlan dedicateGuestVlanRange(DedicateGuestVlanRangeCmd cmd) { + // TODO Auto-generated method stub + return null; + } + + @Override + public Pair, Integer> listDedicatedGuestVlanRanges(ListDedicatedGuestVlanRangesCmd cmd) { + // TODO Auto-generated method stub + return null; + } + + @Override + public boolean releaseDedicatedGuestVlanRange(Long dedicatedGuestVlanRangeId) { + // TODO Auto-generated method stub + return true; + } + + @Override public List listNetworkServices(String providerName) { // TODO Auto-generated method stub return null; diff --git a/server/test/com/cloud/vpc/MockNetworkManagerImpl.java b/server/test/com/cloud/vpc/MockNetworkManagerImpl.java index 668935707ee..f884ba1d767 100644 --- a/server/test/com/cloud/vpc/MockNetworkManagerImpl.java +++ b/server/test/com/cloud/vpc/MockNetworkManagerImpl.java @@ -28,6 +28,7 @@ import com.cloud.network.Network.Provider; import com.cloud.network.Network.Service; import com.cloud.network.Networks.TrafficType; import com.cloud.network.addr.PublicIp; +import com.cloud.network.dao.AccountGuestVlanMapVO; import com.cloud.network.dao.IPAddressVO; import com.cloud.network.dao.NetworkServiceMapDao; import com.cloud.network.dao.NetworkVO; @@ -50,6 +51,8 @@ import com.cloud.utils.component.ManagerBase; import com.cloud.vm.*; import com.cloud.vm.VirtualMachine.Type; import org.apache.cloudstack.acl.ControlledEntity.ACLType; +import org.apache.cloudstack.api.command.admin.network.DedicateGuestVlanRangeCmd; +import org.apache.cloudstack.api.command.admin.network.ListDedicatedGuestVlanRangesCmd; import org.apache.cloudstack.api.command.admin.usage.ListTrafficTypeImplementorsCmd; import org.apache.cloudstack.api.command.user.network.CreateNetworkCmd; import org.apache.cloudstack.api.command.user.network.ListNetworksCmd; @@ -338,9 +341,24 @@ public class MockNetworkManagerImpl extends ManagerBase implements NetworkManage return false; } + @Override + public GuestVlan dedicateGuestVlanRange(DedicateGuestVlanRangeCmd cmd) { + // TODO Auto-generated method stub + return null; + } + @Override + public Pair, Integer> listDedicatedGuestVlanRanges(ListDedicatedGuestVlanRangesCmd cmd) { + // TODO Auto-generated method stub + return null; + } + @Override + public boolean releaseDedicatedGuestVlanRange(Long dedicatedGuestVlanRangeId) { + // TODO Auto-generated method stub + return true; + } /* (non-Javadoc) * @see com.cloud.network.NetworkService#listNetworkServices(java.lang.String) diff --git a/server/test/org/apache/cloudstack/affinity/AffinityApiTestConfiguration.java b/server/test/org/apache/cloudstack/affinity/AffinityApiTestConfiguration.java index 4dd6ad7e8d0..a1224db62c3 100644 --- a/server/test/org/apache/cloudstack/affinity/AffinityApiTestConfiguration.java +++ b/server/test/org/apache/cloudstack/affinity/AffinityApiTestConfiguration.java @@ -72,6 +72,7 @@ import com.cloud.network.NetworkManager; import com.cloud.network.NetworkModel; import com.cloud.network.NetworkService; import com.cloud.network.StorageNetworkManager; +import com.cloud.network.dao.AccountGuestVlanMapDaoImpl; import com.cloud.network.dao.FirewallRulesCidrsDaoImpl; import com.cloud.network.dao.FirewallRulesDaoImpl; import com.cloud.network.dao.IPAddressDaoImpl; @@ -136,7 +137,7 @@ import com.cloud.vm.dao.VMInstanceDaoImpl; FirewallRulesCidrsDaoImpl.class, PhysicalNetworkDaoImpl.class, PhysicalNetworkTrafficTypeDaoImpl.class, PhysicalNetworkServiceProviderDaoImpl.class, LoadBalancerDaoImpl.class, NetworkServiceMapDaoImpl.class, PrimaryDataStoreDaoImpl.class, StoragePoolDetailsDaoImpl.class, AffinityGroupServiceImpl.class, - ComponentContext.class, AffinityGroupProcessor.class, UserVmVO.class, EventUtils.class, UserVmVO.class + ComponentContext.class, AffinityGroupProcessor.class, UserVmVO.class, EventUtils.class, UserVmVO.class, AccountGuestVlanMapDaoImpl.class }, includeFilters = { @Filter(value = AffinityApiTestConfiguration.Library.class, type = FilterType.CUSTOM) }, useDefaultFilters = false) public class AffinityApiTestConfiguration { diff --git a/server/test/org/apache/cloudstack/networkoffering/ChildTestConfiguration.java b/server/test/org/apache/cloudstack/networkoffering/ChildTestConfiguration.java index 709dfe29ed1..d47deaa7018 100644 --- a/server/test/org/apache/cloudstack/networkoffering/ChildTestConfiguration.java +++ b/server/test/org/apache/cloudstack/networkoffering/ChildTestConfiguration.java @@ -53,6 +53,7 @@ import com.cloud.network.NetworkManager; import com.cloud.network.NetworkModel; import com.cloud.network.NetworkService; import com.cloud.network.StorageNetworkManager; +import com.cloud.network.dao.AccountGuestVlanMapDaoImpl; import com.cloud.network.dao.FirewallRulesCidrsDaoImpl; import com.cloud.network.dao.FirewallRulesDaoImpl; import com.cloud.network.dao.IPAddressDaoImpl; @@ -146,7 +147,8 @@ import com.cloud.vm.dao.VMInstanceDaoImpl; LoadBalancerDaoImpl.class, NetworkServiceMapDaoImpl.class, PrimaryDataStoreDaoImpl.class, - StoragePoolDetailsDaoImpl.class + StoragePoolDetailsDaoImpl.class, + AccountGuestVlanMapDaoImpl.class }, includeFilters={@Filter(value=ChildTestConfiguration.Library.class, type=FilterType.CUSTOM)}, useDefaultFilters=false diff --git a/setup/db/db/schema-410to420.sql b/setup/db/db/schema-410to420.sql index 99b476d4581..c8ac1ecfc2e 100644 --- a/setup/db/db/schema-410to420.sql +++ b/setup/db/db/schema-410to420.sql @@ -1115,6 +1115,7 @@ CREATE VIEW `cloud`.`account_view` AS and async_job.instance_type = 'Account' and async_job.job_status = 0; + alter table `cloud_usage`.`usage_network_offering` add column nic_id bigint(20) unsigned NOT NULL; ALTER TABLE `cloud`.`data_center_details` MODIFY value varchar(1024); ALTER TABLE `cloud`.`cluster_details` MODIFY value varchar(255); @@ -1126,3 +1127,19 @@ INSERT IGNORE INTO `cloud`.`configuration` VALUES ('Network', 'DEFAULT', 'manage alter table cloud.vpc_gateways add column source_nat boolean default false; alter table cloud.private_ip_address add column source_nat boolean default false; + +CREATE TABLE `cloud`.`account_vnet_map` ( + `id` bigint unsigned NOT NULL UNIQUE AUTO_INCREMENT, + `uuid` varchar(255) UNIQUE, + `vnet_range` varchar(255) NOT NULL COMMENT 'dedicated guest vlan range', + `account_id` bigint unsigned NOT NULL COMMENT 'account id. foreign key to account table', + `physical_network_id` bigint unsigned NOT NULL COMMENT 'physical network id. foreign key to the the physical network table', + PRIMARY KEY (`id`), + CONSTRAINT `fk_account_vnet_map__physical_network_id` FOREIGN KEY (`physical_network_id`) REFERENCES `physical_network` (`id`) ON DELETE CASCADE, + INDEX `i_account_vnet_map__physical_network_id`(`physical_network_id`), + CONSTRAINT `fk_account_vnet_map__account_id` FOREIGN KEY (`account_id`) REFERENCES `account` (`id`) ON DELETE CASCADE, + INDEX `i_account_vnet_map__account_id`(`account_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + +ALTER TABLE `cloud`.`op_dc_vnet_alloc` ADD COLUMN account_vnet_map_id bigint unsigned; +ALTER TABLE `cloud`.`op_dc_vnet_alloc` ADD CONSTRAINT `fk_op_dc_vnet_alloc__account_vnet_map_id` FOREIGN KEY `fk_op_dc_vnet_alloc__account_vnet_map_id` (`account_vnet_map_id`) REFERENCES `account_vnet_map` (`id`); diff --git a/test/integration/smoke/test_guest_vlan_range.py b/test/integration/smoke/test_guest_vlan_range.py new file mode 100644 index 00000000000..eca0e61f137 --- /dev/null +++ b/test/integration/smoke/test_guest_vlan_range.py @@ -0,0 +1,157 @@ +# 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. +""" P1 tests for Dedicating Guest Vlan Ranges +""" +#Import Local Modules +import marvin +from nose.plugins.attrib import attr +from marvin.cloudstackTestCase import * +from marvin.cloudstackAPI import * +from marvin.integration.lib.utils import * +from marvin.integration.lib.base import * +from marvin.integration.lib.common import * +import datetime + + +class Services: + """Test Dedicating Guest Vlan Ranges + """ + + def __init__(self): + self.services = { + "domain": { + "name": "Domain", + }, + "account": { + "email": "test@test.com", + "firstname": "Test", + "lastname": "User", + "username": "test", + "password": "password", + }, + "name": "testphysicalnetwork" + } + + +class TesDedicateGuestVlanRange(cloudstackTestCase): + + @classmethod + def setUpClass(cls): + cls.api_client = super(TesDedicateGuestVlanRange, cls).getClsTestClient().getApiClient() + cls.services = Services().services + # Get Zone, Domain + cls.domain = get_domain(cls.api_client, cls.services) + cls.zone = get_zone(cls.api_client, cls.services) + + # Create Account + cls.account = Account.create( + cls.api_client, + cls.services["account"], + domainid=cls.domain.id + ) + cls._cleanup = [ + #cls.account, + ] + return + + @classmethod + def tearDownClass(cls): + try: + # Cleanup resources used + cleanup_resources(cls.api_client, cls._cleanup) + except Exception as e: + raise Exception("Warning: Exception during cleanup : %s" % e) + return + + def setUp(self): + self.apiclient = self.testClient.getApiClient() + self.dbclient = self.testClient.getDbConnection() + self.cleanup = [] + return + + def tearDown(self): + try: + # Clean up + cleanup_resources(self.apiclient, self.cleanup) + except Exception as e: + raise Exception("Warning: Exception during cleanup : %s" % e) + return + + @attr(tags=["simulator", "advanced", "guestvlanrange", "dedicate", "release"]) + def test_dedicateGuestVlanRange(self): + """Test guest vlan range dedication + """ + + """Assume a physical network is available + """ + # Validate the following: + # 1. List the available physical network using ListPhysicalNetwork + # 2. Add a Guest Vlan range to the available physical network using UpdatePhysicalNetwork + # 3. Dedicate the created guest vlan range to user account using DedicateGuestVlanRange + # 4. Verify vlan range is dedicated with listDedicatedGuestVlanRanges + # 5. Release the dedicated guest vlan range back to the system + # 6. Verify guest vlan range has been released, verify with listDedicatedGuestVlanRanges + # 7. Remove the added guest vlan range using UpdatePhysicalNetwork + + self.debug("Listing available physical network") + list_physical_network_response = PhysicalNetwork.list( + self.apiclient + ) + self.assertEqual( + isinstance(list_physical_network_response, list), + True, + "Check for list guest vlan range response" + ) + physical_network_response = list_physical_network_response[0] + + self.debug("Adding guest vlan range") + addGuestVlanRangeResponse = physical_network_response.update(self.apiclient, id=physical_network_response.id, vlan="387-390") + + self.debug("Dedicating guest vlan range"); + dedicate_guest_vlan_range_response = PhysicalNetwork.dedicate( + self.apiclient, + "387-390", + physicalnetworkid=physical_network_response.id, + account=self.account.name, + domainid=self.account.domainid + ) + list_dedicated_guest_vlan_range_response = PhysicalNetwork.listDedicated( + self.apiclient, + id=dedicate_guest_vlan_range_response.id + ) + dedicated_guest_vlan_response = list_dedicated_guest_vlan_range_response[0] + self.assertEqual( + dedicated_guest_vlan_response.account, + self.account.name, + "Check account name is in listDedicatedGuestVlanRanges as the account the range is dedicated to" + ) + + self.debug("Releasing guest vlan range"); + dedicated_guest_vlan_response.release(self.apiclient) + list_dedicated_guest_vlan_range_response = PhysicalNetwork.listDedicated( + self.apiclient, + id=dedicate_guest_vlan_range_response.id + ) + dedicated_guest_vlan_response = list_dedicated_guest_vlan_range_response[0] + self.assertEqual( + dedicated_guest_vlan_response.account, + "system", + "Check account name is system account in listDedicatedGuestVlanRanges" + ) + + self.debug("Removing guest vlan range") + removeGuestVlanRangeResponse = physical_network_response.update(self.apiclient, id=physical_network_response.id, removevlan="387-390") diff --git a/tools/marvin/marvin/integration/lib/base.py b/tools/marvin/marvin/integration/lib/base.py index bebf2b50bcf..dc7fe60589c 100755 --- a/tools/marvin/marvin/integration/lib/base.py +++ b/tools/marvin/marvin/integration/lib/base.py @@ -2178,6 +2178,33 @@ class PhysicalNetwork: cmd.traffictype = type return apiclient.addTrafficType(cmd) + @classmethod + def dedicate(cls, apiclient, vlanrange, physicalnetworkid, account=None, domainid=None, projectid=None): + """Dedicate guest vlan range""" + + cmd = dedicateGuestVlanRange.dedicateGuestVlanRangeCmd() + cmd.vlanrange = vlanrange + cmd.physicalnetworkid = physicalnetworkid + cmd.account = account + cmd.domainid = domainid + cmd.projectid = projectid + return PhysicalNetwork(apiclient.dedicateGuestVlanRange(cmd).__dict__) + + def release(self, apiclient): + """Release guest vlan range""" + + cmd = releaseDedicatedGuestVlanRange.releaseDedicatedGuestVlanRangeCmd() + cmd.id = self.id + return apiclient.releaseDedicatedGuestVlanRange(cmd) + + @classmethod + def listDedicated(cls, apiclient, **kwargs): + """Lists all dedicated guest vlan ranges""" + + cmd = listDedicatedGuestVlanRanges.listDedicatedGuestVlanRangesCmd() + [setattr(cmd, k, v) for k, v in kwargs.items()] + return map(lambda pn : PhysicalNetwork(pn.__dict__), apiclient.listDedicatedGuestVlanRanges(cmd)) + @classmethod def list(cls, apiclient, **kwargs): """Lists all physical networks"""