From 1a232171eb662f619e60f1eb1967b6fa62ba174e Mon Sep 17 00:00:00 2001 From: Alena Prokharchyk Date: Tue, 26 Jun 2012 11:10:55 -0700 Subject: [PATCH] VPC: implementation for Add/delete/list StaticRoute. Agent implementation is yet to be done --- .../api/routing/SetStaticRouteAnswer.java | 35 ++++ .../api/routing/SetStaticRouteCommand.java | 35 ++++ .../api/commands/CreateStaticRouteCmd.java | 3 +- .../api/response/StaticRouteResponse.java | 45 +++- .../cloud/api/response/VolumeResponse.java | 2 +- .../cloud/network/element/VpcProvider.java | 5 +- .../cloud/network/vpc/StaticRouteProfile.java | 97 +++++++++ api/src/com/cloud/network/vpc/VpcService.java | 6 +- .../xen/resource/CitrixResourceBase.java | 11 +- .../src/com/cloud/api/ApiResponseHelper.java | 2 + .../element/VpcVirtualRouterElement.java | 32 +-- .../network/firewall/FirewallManagerImpl.java | 24 ++- .../VpcVirtualNetworkApplianceManager.java | 9 + ...VpcVirtualNetworkApplianceManagerImpl.java | 40 +++- .../cloud/network/vpc/Dao/StaticRouteDao.java | 8 + .../network/vpc/Dao/StaticRouteDaoImpl.java | 51 +++++ .../com/cloud/network/vpc/StaticRouteVO.java | 17 +- .../com/cloud/network/vpc/VpcManagerImpl.java | 193 ++++++++++++++++-- .../src/com/cloud/vm/dao/DomainRouterDao.java | 2 +- .../com/cloud/vm/dao/DomainRouterDaoImpl.java | 2 +- 20 files changed, 572 insertions(+), 47 deletions(-) create mode 100644 api/src/com/cloud/agent/api/routing/SetStaticRouteAnswer.java create mode 100644 api/src/com/cloud/agent/api/routing/SetStaticRouteCommand.java create mode 100644 api/src/com/cloud/network/vpc/StaticRouteProfile.java diff --git a/api/src/com/cloud/agent/api/routing/SetStaticRouteAnswer.java b/api/src/com/cloud/agent/api/routing/SetStaticRouteAnswer.java new file mode 100644 index 00000000000..93e79aad0cb --- /dev/null +++ b/api/src/com/cloud/agent/api/routing/SetStaticRouteAnswer.java @@ -0,0 +1,35 @@ +// Copyright 2012 Citrix Systems, Inc. Licensed under the +// Apache License, Version 2.0 (the "License"); you may not use this +// file except in compliance with the License. Citrix Systems, Inc. +// reserves all rights not expressly granted by 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. +// +// Automatically generated by addcopyright.py at 04/03/2012 +package com.cloud.agent.api.routing; + +import com.cloud.agent.api.Answer; + +/** + * @author Alena Prokharchyk + */ +public class SetStaticRouteAnswer extends Answer{ + String[] results; + + protected SetStaticRouteAnswer() { + } + + public SetStaticRouteAnswer(SetStaticRouteCommand cmd, boolean success, String[] results) { + super(cmd, success, null); + assert (cmd.getStaticRoutes().length == results.length) : "Static routes and their results should be the same length"; + this.results = results; + } + + public String[] getResults() { + return results; + } +} diff --git a/api/src/com/cloud/agent/api/routing/SetStaticRouteCommand.java b/api/src/com/cloud/agent/api/routing/SetStaticRouteCommand.java new file mode 100644 index 00000000000..1ab59d7174e --- /dev/null +++ b/api/src/com/cloud/agent/api/routing/SetStaticRouteCommand.java @@ -0,0 +1,35 @@ +// Copyright 2012 Citrix Systems, Inc. Licensed under the +// Apache License, Version 2.0 (the "License"); you may not use this +// file except in compliance with the License. Citrix Systems, Inc. +// reserves all rights not expressly granted by 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. +// +// Automatically generated by addcopyright.py at 04/03/2012 +package com.cloud.agent.api.routing; + +import java.util.List; + +import com.cloud.network.vpc.StaticRouteProfile; + +/** + * @author Alena Prokharchyk + */ +public class SetStaticRouteCommand extends NetworkElementCommand{ + StaticRouteProfile[] staticRoutes; + + protected SetStaticRouteCommand() { + } + + public SetStaticRouteCommand(List staticRoutes) { + this.staticRoutes = staticRoutes.toArray(new StaticRouteProfile[staticRoutes.size()]); + } + + public StaticRouteProfile[] getStaticRoutes() { + return staticRoutes; + } +} diff --git a/api/src/com/cloud/api/commands/CreateStaticRouteCmd.java b/api/src/com/cloud/api/commands/CreateStaticRouteCmd.java index 805013eaad9..af6fc000b20 100644 --- a/api/src/com/cloud/api/commands/CreateStaticRouteCmd.java +++ b/api/src/com/cloud/api/commands/CreateStaticRouteCmd.java @@ -28,6 +28,7 @@ import com.cloud.event.EventTypes; import com.cloud.exception.InvalidParameterValueException; import com.cloud.exception.NetworkRuleConflictException; import com.cloud.exception.ResourceAllocationException; +import com.cloud.exception.ResourceUnavailableException; import com.cloud.network.vpc.PrivateGateway; import com.cloud.network.vpc.StaticRoute; import com.cloud.user.UserContext; @@ -91,7 +92,7 @@ public class CreateStaticRouteCmd extends BaseAsyncCreateCmd{ } @Override - public void execute() { + public void execute() throws ResourceUnavailableException { boolean success = false; StaticRoute route = _entityMgr.findById(StaticRoute.class, getEntityId()); try { diff --git a/api/src/com/cloud/api/response/StaticRouteResponse.java b/api/src/com/cloud/api/response/StaticRouteResponse.java index a77c71b25fd..025be6e0b82 100644 --- a/api/src/com/cloud/api/response/StaticRouteResponse.java +++ b/api/src/com/cloud/api/response/StaticRouteResponse.java @@ -21,7 +21,7 @@ import com.google.gson.annotations.SerializedName; * @author Alena Prokharchyk */ @SuppressWarnings("unused") -public class StaticRouteResponse extends BaseResponse{ +public class StaticRouteResponse extends BaseResponse implements ControlledEntityResponse{ @SerializedName(ApiConstants.ID) @Param(description="the ID of static route") private IdentityProxy id = new IdentityProxy("static_routes"); @@ -36,6 +36,24 @@ public class StaticRouteResponse extends BaseResponse{ @SerializedName(ApiConstants.CIDR) @Param(description="static route CIDR") private String cidr; + + @SerializedName(ApiConstants.ACCOUNT) + @Param(description = "the account associated with the static route") + private String accountName; + + @SerializedName(ApiConstants.PROJECT_ID) @Param(description="the project id of the static route") + private IdentityProxy projectId = new IdentityProxy("projects"); + + @SerializedName(ApiConstants.PROJECT) @Param(description="the project name of the static route") + private String projectName; + + @SerializedName(ApiConstants.DOMAIN_ID) + @Param(description = "the ID of the domain associated with the static route") + private IdentityProxy domainId = new IdentityProxy("domain"); + + @SerializedName(ApiConstants.DOMAIN) + @Param(description = "the domain associated with the static route") + private String domainName; public void setId(Long id) { this.id.setValue(id); @@ -56,4 +74,29 @@ public class StaticRouteResponse extends BaseResponse{ public void setCidr(String cidr) { this.cidr = cidr; } + + @Override + public void setAccountName(String accountName) { + this.accountName = accountName; + } + + @Override + public void setDomainId(Long domainId) { + this.domainId.setValue(domainId); + } + + @Override + public void setDomainName(String domainName) { + this.domainName = domainName; + } + + @Override + public void setProjectId(Long projectId) { + this.projectId.setValue(projectId); + } + + @Override + public void setProjectName(String projectName) { + this.projectName = projectName; + } } diff --git a/api/src/com/cloud/api/response/VolumeResponse.java b/api/src/com/cloud/api/response/VolumeResponse.java index 86595252000..926e3688e54 100755 --- a/api/src/com/cloud/api/response/VolumeResponse.java +++ b/api/src/com/cloud/api/response/VolumeResponse.java @@ -292,5 +292,5 @@ public class VolumeResponse extends BaseResponse implements ControlledEntityResp @Override public void setProjectName(String projectName) { this.projectName = projectName; - } + } } diff --git a/api/src/com/cloud/network/element/VpcProvider.java b/api/src/com/cloud/network/element/VpcProvider.java index 34bdb511cb8..3e369b3e721 100644 --- a/api/src/com/cloud/network/element/VpcProvider.java +++ b/api/src/com/cloud/network/element/VpcProvider.java @@ -12,6 +12,7 @@ // Automatically generated by addcopyright.py at 04/03/2012 package com.cloud.network.element; + import java.util.List; import com.cloud.deploy.DeployDestination; @@ -20,7 +21,7 @@ import com.cloud.exception.InsufficientCapacityException; import com.cloud.exception.InsufficientNetworkCapacityException; import com.cloud.exception.ResourceUnavailableException; import com.cloud.network.vpc.PrivateGateway; -import com.cloud.network.vpc.StaticRoute; +import com.cloud.network.vpc.StaticRouteProfile; import com.cloud.network.vpc.Vpc; import com.cloud.vm.ReservationContext; @@ -48,5 +49,5 @@ public interface VpcProvider extends NetworkElement{ boolean deletePrivateGateway(PrivateGateway privateGateway) throws ConcurrentOperationException, ResourceUnavailableException; - boolean applyStaticRoutes(Vpc vpc, List routes) throws ResourceUnavailableException; + boolean applyStaticRoutes(Vpc vpc, List routes) throws ResourceUnavailableException; } diff --git a/api/src/com/cloud/network/vpc/StaticRouteProfile.java b/api/src/com/cloud/network/vpc/StaticRouteProfile.java new file mode 100644 index 00000000000..073621d7321 --- /dev/null +++ b/api/src/com/cloud/network/vpc/StaticRouteProfile.java @@ -0,0 +1,97 @@ +// Copyright 2012 Citrix Systems, Inc. Licensed under the +// Apache License, Version 2.0 (the "License"); you may not use this +// file except in compliance with the License. Citrix Systems, Inc. +// reserves all rights not expressly granted by 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. +// +// Automatically generated by addcopyright.py at 04/03/2012 +package com.cloud.network.vpc; + +/** + * @author Alena Prokharchyk + */ +public class StaticRouteProfile implements StaticRoute{ + private long id; + private String cidr; + private long accountId; + private long domainId; + private long gatewayId; + private StaticRoute.State state; + private long vpcId; + String vlanTag; + String gateway; + String netmask; + String ipAddress; + + + public StaticRouteProfile(StaticRoute staticRoute, PrivateGateway gateway) { + this.id = staticRoute.getId(); + this.cidr = staticRoute.getCidr(); + this.accountId = staticRoute.getAccountId(); + this.domainId = staticRoute.getDomainId(); + this.gatewayId = staticRoute.getVpcGatewayId(); + this.state = staticRoute.getState(); + this.vpcId = staticRoute.getVpcId(); + this.vlanTag = gateway.getVlanTag(); + this.gateway = gateway.getGateway(); + this.netmask = gateway.getNetmask(); + this.ipAddress = gateway.getIp4Address(); + } + + @Override + public long getAccountId() { + return accountId; + } + + @Override + public long getDomainId() { + return domainId; + } + + @Override + public long getVpcGatewayId() { + return gatewayId; + } + + @Override + public String getCidr() { + return cidr; + } + + @Override + public State getState() { + return state; + } + + @Override + public Long getVpcId() { + return vpcId; + } + + @Override + public long getId() { + return id; + } + + public String getVlanTag() { + return vlanTag; + } + + public String getIp4Address() { + return ipAddress; + } + + public String getGateway() { + return gateway; + } + + public String getNetmask() { + return netmask; + } + +} diff --git a/api/src/com/cloud/network/vpc/VpcService.java b/api/src/com/cloud/network/vpc/VpcService.java index d1faf237ddd..a4e1a1a3451 100644 --- a/api/src/com/cloud/network/vpc/VpcService.java +++ b/api/src/com/cloud/network/vpc/VpcService.java @@ -189,14 +189,16 @@ public interface VpcService { /** * @param vpcId * @return + * @throws ResourceUnavailableException */ - public boolean applyStaticRoutes(long vpcId); + public boolean applyStaticRoutes(long vpcId) throws ResourceUnavailableException; /** * @param routeId * @return TODO + * @throws ResourceUnavailableException */ - public boolean revokeStaticRoute(long routeId); + public boolean revokeStaticRoute(long routeId) throws ResourceUnavailableException; /** * @param gatewayId diff --git a/core/src/com/cloud/hypervisor/xen/resource/CitrixResourceBase.java b/core/src/com/cloud/hypervisor/xen/resource/CitrixResourceBase.java index 7153dc4607d..dac8f23c198 100644 --- a/core/src/com/cloud/hypervisor/xen/resource/CitrixResourceBase.java +++ b/core/src/com/cloud/hypervisor/xen/resource/CitrixResourceBase.java @@ -156,6 +156,8 @@ import com.cloud.agent.api.routing.SetPortForwardingRulesVpcCommand; import com.cloud.agent.api.routing.SetSourceNatCommand; import com.cloud.agent.api.routing.SetStaticNatRulesAnswer; import com.cloud.agent.api.routing.SetStaticNatRulesCommand; +import com.cloud.agent.api.routing.SetStaticRouteAnswer; +import com.cloud.agent.api.routing.SetStaticRouteCommand; import com.cloud.agent.api.routing.VmDataCommand; import com.cloud.agent.api.routing.VpnUsersCfgCommand; import com.cloud.agent.api.storage.CopyVolumeAnswer; @@ -542,12 +544,13 @@ public abstract class CitrixResourceBase implements ServerResource, HypervisorRe return execute((SetNetworkACLCommand) cmd); } else if (clazz == SetPortForwardingRulesVpcCommand.class) { return execute((SetPortForwardingRulesVpcCommand) cmd); + } else if (clazz == SetStaticRouteCommand.class) { + return execute((SetStaticRouteCommand) cmd); } else { return Answer.createUnsupportedCommandAnswer(cmd); } } - protected XsLocalNetwork getNativeNetworkForTraffic(Connection conn, TrafficType type, String name) throws XenAPIException, XmlRpcException { if (name != null) { if (s_logger.isDebugEnabled()) { @@ -7125,4 +7128,10 @@ public abstract class CitrixResourceBase implements ServerResource, HypervisorRe //TODO - add implementation return null; } + + + private SetStaticRouteAnswer execute(SetStaticRouteCommand cmd) { + // TODO Auto-generated method stub + return null; + } } diff --git a/server/src/com/cloud/api/ApiResponseHelper.java b/server/src/com/cloud/api/ApiResponseHelper.java index d01213e9099..094af0a07f9 100755 --- a/server/src/com/cloud/api/ApiResponseHelper.java +++ b/server/src/com/cloud/api/ApiResponseHelper.java @@ -3563,6 +3563,8 @@ public class ApiResponseHelper implements ResponseGenerator { stateToSet = "Deleting"; } response.setState(stateToSet); + populateAccount(response, result.getAccountId()); + populateDomain(response, result.getDomainId()); response.setObjectName("staticroute"); return response; diff --git a/server/src/com/cloud/network/element/VpcVirtualRouterElement.java b/server/src/com/cloud/network/element/VpcVirtualRouterElement.java index e9a2cf5ac10..c5e2efdee98 100644 --- a/server/src/com/cloud/network/element/VpcVirtualRouterElement.java +++ b/server/src/com/cloud/network/element/VpcVirtualRouterElement.java @@ -32,19 +32,19 @@ import com.cloud.network.Network; import com.cloud.network.Network.Capability; import com.cloud.network.Network.Provider; import com.cloud.network.Network.Service; -import com.cloud.network.VirtualRouterProvider.VirtualRouterProviderType; import com.cloud.network.NetworkService; import com.cloud.network.PublicIpAddress; +import com.cloud.network.VirtualRouterProvider.VirtualRouterProviderType; import com.cloud.network.router.VirtualRouter; import com.cloud.network.router.VirtualRouter.Role; import com.cloud.network.router.VpcVirtualNetworkApplianceManager; import com.cloud.network.rules.FirewallRule; import com.cloud.network.rules.NetworkACL; -import com.cloud.network.vpc.StaticRoute; +import com.cloud.network.vpc.PrivateGateway; +import com.cloud.network.vpc.StaticRouteProfile; import com.cloud.network.vpc.Vpc; import com.cloud.network.vpc.VpcGateway; import com.cloud.network.vpc.VpcManager; -import com.cloud.network.vpc.PrivateGateway; import com.cloud.offering.NetworkOffering; import com.cloud.utils.component.Inject; import com.cloud.utils.exception.CloudRuntimeException; @@ -119,7 +119,7 @@ public class VpcVirtualRouterElement extends VirtualRouterElement implements Vpc @Override public boolean shutdownVpc(Vpc vpc) throws ConcurrentOperationException, ResourceUnavailableException { - List routers = _routerDao.listRoutersByVpcId(vpc.getId()); + List routers = _routerDao.listByVpcId(vpc.getId()); if (routers == null || routers.isEmpty()) { return true; } @@ -228,7 +228,7 @@ public class VpcVirtualRouterElement extends VirtualRouterElement implements Vpc return success; } - List routers = _routerDao.listRoutersByVpcId(vpcId); + List routers = _routerDao.listByVpcId(vpcId); for (VirtualRouter router : routers) { //1) Check if router is already a part of the network if (!_ntwkService.isVmPartOfNetwork(router.getId(), network.getId())) { @@ -256,7 +256,7 @@ public class VpcVirtualRouterElement extends VirtualRouterElement implements Vpc return success; } - List routers = _routerDao.listRoutersByVpcId(vpcId); + List routers = _routerDao.listByVpcId(vpcId); for (VirtualRouter router : routers) { //1) Check if router is already a part of the network if (!_ntwkService.isVmPartOfNetwork(router.getId(), config.getId())) { @@ -403,12 +403,20 @@ public class VpcVirtualRouterElement extends VirtualRouterElement implements Vpc return VirtualRouterProviderType.VPCVirtualRouter; } - /* (non-Javadoc) - * @see com.cloud.network.element.VpcProvider#applyStaticRoutes(com.cloud.network.vpc.Vpc, java.util.List) - */ @Override - public boolean applyStaticRoutes(Vpc vpc, List routes) throws ResourceUnavailableException { - // TODO Auto-generated method stub - return false; + public boolean applyStaticRoutes(Vpc vpc, List routes) throws ResourceUnavailableException { + List routers = _routerDao.listByVpcId(vpc.getId()); + if (routers == null || routers.isEmpty()) { + s_logger.debug("Virtual router elemnt doesn't need to static routes on the backend; virtual " + + "router doesn't exist in the vpc " + vpc); + return true; + } + + if (!_vpcRouterMgr.applyStaticRoutes(routes, routers)) { + throw new CloudRuntimeException("Failed to apply static routes in vpc " + vpc); + } else { + s_logger.debug("Applied static routes on vpc " + vpc); + return true; + } } } diff --git a/server/src/com/cloud/network/firewall/FirewallManagerImpl.java b/server/src/com/cloud/network/firewall/FirewallManagerImpl.java index 7d0a78581d9..a364dbc48d0 100644 --- a/server/src/com/cloud/network/firewall/FirewallManagerImpl.java +++ b/server/src/com/cloud/network/firewall/FirewallManagerImpl.java @@ -277,16 +277,16 @@ public class FirewallManagerImpl implements FirewallService, FirewallManager, Ma if (!oneOfRulesIsFirewall) { if (rule.getPurpose() == Purpose.StaticNat && newRule.getPurpose() != Purpose.StaticNat) { throw new NetworkRuleConflictException("There is 1 to 1 Nat rule specified for the ip address id=" - + newRule.getSourceIpAddressId()); + + newRule.getSourceIpAddressId()); } else if (rule.getPurpose() != Purpose.StaticNat && newRule.getPurpose() == Purpose.StaticNat) { throw new NetworkRuleConflictException("There is already firewall rule specified for the ip address id=" - + newRule.getSourceIpAddressId()); + + newRule.getSourceIpAddressId()); } } if (rule.getNetworkId() != newRule.getNetworkId() && rule.getState() != State.Revoke) { throw new NetworkRuleConflictException("New rule is for a different network than what's specified in rule " - + rule.getXid()); + + rule.getXid()); } if (newRule.getProtocol().equalsIgnoreCase(NetUtils.ICMP_PROTO) && newRule.getProtocol().equalsIgnoreCase(rule.getProtocol())) { @@ -302,14 +302,20 @@ public class FirewallManagerImpl implements FirewallService, FirewallManager, Ma if (!notNullPorts) { continue; } else if (!oneOfRulesIsFirewall && !(bothRulesFirewall && !duplicatedCidrs) - && ((rule.getSourcePortStart().intValue() <= newRule.getSourcePortStart().intValue() && rule.getSourcePortEnd().intValue() >= newRule.getSourcePortStart().intValue()) - || (rule.getSourcePortStart().intValue() <= newRule.getSourcePortEnd().intValue() && rule.getSourcePortEnd().intValue() >= newRule.getSourcePortEnd().intValue()) - || (newRule.getSourcePortStart().intValue() <= rule.getSourcePortStart().intValue() && newRule.getSourcePortEnd().intValue() >= rule.getSourcePortStart().intValue()) - || (newRule.getSourcePortStart().intValue() <= rule.getSourcePortEnd().intValue() && newRule.getSourcePortEnd().intValue() >= rule.getSourcePortEnd().intValue()))) { + && ((rule.getSourcePortStart().intValue() <= newRule.getSourcePortStart().intValue() + && rule.getSourcePortEnd().intValue() >= newRule.getSourcePortStart().intValue()) + || (rule.getSourcePortStart().intValue() <= newRule.getSourcePortEnd().intValue() + && rule.getSourcePortEnd().intValue() >= newRule.getSourcePortEnd().intValue()) + || (newRule.getSourcePortStart().intValue() <= rule.getSourcePortStart().intValue() + && newRule.getSourcePortEnd().intValue() >= rule.getSourcePortStart().intValue()) + || (newRule.getSourcePortStart().intValue() <= rule.getSourcePortEnd().intValue() + && newRule.getSourcePortEnd().intValue() >= rule.getSourcePortEnd().intValue()))) { // we allow port forwarding rules with the same parameters but different protocols - boolean allowPf = (rule.getPurpose() == Purpose.PortForwarding && newRule.getPurpose() == Purpose.PortForwarding && !newRule.getProtocol().equalsIgnoreCase(rule.getProtocol())); - boolean allowStaticNat = (rule.getPurpose() == Purpose.StaticNat && newRule.getPurpose() == Purpose.StaticNat && !newRule.getProtocol().equalsIgnoreCase(rule.getProtocol())); + boolean allowPf = (rule.getPurpose() == Purpose.PortForwarding && newRule.getPurpose() == Purpose.PortForwarding + && !newRule.getProtocol().equalsIgnoreCase(rule.getProtocol())); + boolean allowStaticNat = (rule.getPurpose() == Purpose.StaticNat && newRule.getPurpose() == Purpose.StaticNat + && !newRule.getProtocol().equalsIgnoreCase(rule.getProtocol())); if (!(allowPf || allowStaticNat || oneOfRulesIsFirewall)) { throw new NetworkRuleConflictException("The range specified, " + newRule.getSourcePortStart() + "-" + newRule.getSourcePortEnd() + ", conflicts with rule " + rule.getId() diff --git a/server/src/com/cloud/network/router/VpcVirtualNetworkApplianceManager.java b/server/src/com/cloud/network/router/VpcVirtualNetworkApplianceManager.java index 0d738ee20b4..a17c7cfa0f3 100644 --- a/server/src/com/cloud/network/router/VpcVirtualNetworkApplianceManager.java +++ b/server/src/com/cloud/network/router/VpcVirtualNetworkApplianceManager.java @@ -22,6 +22,7 @@ import com.cloud.exception.ResourceUnavailableException; import com.cloud.network.Network; import com.cloud.network.VpcVirtualNetworkApplianceService; import com.cloud.network.rules.NetworkACL; +import com.cloud.network.vpc.StaticRouteProfile; import com.cloud.network.vpc.Vpc; import com.cloud.network.vpc.PrivateGateway; import com.cloud.user.Account; @@ -75,4 +76,12 @@ public interface VpcVirtualNetworkApplianceManager extends VirtualNetworkApplian */ boolean destroyPrivateGateway(PrivateGateway gateway, VirtualRouter router) throws ConcurrentOperationException, ResourceUnavailableException; + /** + * @param routes + * @param routers + * @return + * @throws ResourceUnavailableException + */ + boolean applyStaticRoutes(List routes, List routers) throws ResourceUnavailableException; + } diff --git a/server/src/com/cloud/network/router/VpcVirtualNetworkApplianceManagerImpl.java b/server/src/com/cloud/network/router/VpcVirtualNetworkApplianceManagerImpl.java index 405cf3cb3b3..f8388855e8f 100644 --- a/server/src/com/cloud/network/router/VpcVirtualNetworkApplianceManagerImpl.java +++ b/server/src/com/cloud/network/router/VpcVirtualNetworkApplianceManagerImpl.java @@ -35,6 +35,7 @@ import com.cloud.agent.api.routing.IpAssocVpcCommand; import com.cloud.agent.api.routing.NetworkElementCommand; import com.cloud.agent.api.routing.SetNetworkACLCommand; import com.cloud.agent.api.routing.SetSourceNatCommand; +import com.cloud.agent.api.routing.SetStaticRouteCommand; import com.cloud.agent.api.to.IpAddressTO; import com.cloud.agent.api.to.NetworkACLTO; import com.cloud.agent.api.to.NicTO; @@ -72,6 +73,7 @@ import com.cloud.network.dao.PhysicalNetworkDao; import com.cloud.network.firewall.NetworkACLService; import com.cloud.network.rules.NetworkACL; import com.cloud.network.vpc.PrivateGateway; +import com.cloud.network.vpc.StaticRouteProfile; import com.cloud.network.vpc.Vpc; import com.cloud.network.vpc.Dao.VpcDao; import com.cloud.network.vpc.Dao.VpcOfferingDao; @@ -183,7 +185,7 @@ public class VpcVirtualNetworkApplianceManagerImpl extends VirtualNetworkApplian long dcId = dest.getDataCenter().getId(); DeploymentPlan plan = new DataCenterDeployment(dcId); - List routers = _routerDao.listRoutersByVpcId(vpcId); + List routers = _routerDao.listByVpcId(vpcId); return new Pair>(plan, routers); } @@ -668,7 +670,8 @@ public class VpcVirtualNetworkApplianceManagerImpl extends VirtualNetworkApplian } - protected boolean sendNetworkACLs(VirtualRouter router, List rules, long guestNetworkId) throws ResourceUnavailableException { + protected boolean sendNetworkACLs(VirtualRouter router, List rules, long guestNetworkId) + throws ResourceUnavailableException { Commands cmds = new Commands(OnError.Continue); createNetworkACLsCommands(rules, router, cmds, guestNetworkId); return sendCommandsToRouter(router, cmds); @@ -936,4 +939,37 @@ public class VpcVirtualNetworkApplianceManagerImpl extends VirtualNetworkApplian } } } + + @Override + public boolean applyStaticRoutes(List staticRoutes, List routers) throws ResourceUnavailableException { + if (staticRoutes == null || staticRoutes.isEmpty()) { + s_logger.debug("No static routes to apply"); + return true; + } + + //send commands to only one router as there is only one in the VPC + return sendStaticRoutes(staticRoutes, routers.get(0)); + + } + + protected boolean sendStaticRoutes(List staticRoutes, DomainRouterVO router) + throws ResourceUnavailableException { + Commands cmds = new Commands(OnError.Continue); + createStaticRouteCommands(staticRoutes, router, cmds); + return sendCommandsToRouter(router, cmds); + } + + /** + * @param staticRoutes + * @param router + * @param cmds + */ + private void createStaticRouteCommands(List staticRoutes, DomainRouterVO router, Commands cmds) { + SetStaticRouteCommand cmd = new SetStaticRouteCommand(staticRoutes); + cmd.setAccessDetail(NetworkElementCommand.ROUTER_IP, getRouterControlIp(router.getId())); + cmd.setAccessDetail(NetworkElementCommand.ROUTER_NAME, router.getInstanceName()); + DataCenterVO dcVo = _dcDao.findById(router.getDataCenterIdToDeployIn()); + cmd.setAccessDetail(NetworkElementCommand.ZONE_NETWORK_TYPE, dcVo.getNetworkType().toString()); + cmds.addCommand(cmd); + } } diff --git a/server/src/com/cloud/network/vpc/Dao/StaticRouteDao.java b/server/src/com/cloud/network/vpc/Dao/StaticRouteDao.java index f4bc80ab39e..9f5a33964d8 100644 --- a/server/src/com/cloud/network/vpc/Dao/StaticRouteDao.java +++ b/server/src/com/cloud/network/vpc/Dao/StaticRouteDao.java @@ -12,6 +12,9 @@ // Automatically generated by addcopyright.py at 04/03/2012 package com.cloud.network.vpc.Dao; +import java.util.List; + +import com.cloud.network.vpc.StaticRoute; import com.cloud.network.vpc.StaticRouteVO; import com.cloud.utils.db.GenericDao; @@ -19,5 +22,10 @@ import com.cloud.utils.db.GenericDao; * @author Alena Prokharchyk */ public interface StaticRouteDao extends GenericDao{ + + boolean setStateToAdd(StaticRouteVO rule); + List listByGatewayIdAndNotRevoked(long gatewayId); + + List listByVpcId(long vpcId); } diff --git a/server/src/com/cloud/network/vpc/Dao/StaticRouteDaoImpl.java b/server/src/com/cloud/network/vpc/Dao/StaticRouteDaoImpl.java index b25b9316a12..0f03a85ea97 100644 --- a/server/src/com/cloud/network/vpc/Dao/StaticRouteDaoImpl.java +++ b/server/src/com/cloud/network/vpc/Dao/StaticRouteDaoImpl.java @@ -12,11 +12,17 @@ // Automatically generated by addcopyright.py at 04/03/2012 package com.cloud.network.vpc.Dao; +import java.util.List; + import javax.ejb.Local; +import com.cloud.network.vpc.StaticRoute; import com.cloud.network.vpc.StaticRouteVO; import com.cloud.utils.db.DB; import com.cloud.utils.db.GenericDaoBase; +import com.cloud.utils.db.SearchBuilder; +import com.cloud.utils.db.SearchCriteria; +import com.cloud.utils.db.SearchCriteria.Op; /** * @author Alena Prokharchyk @@ -25,5 +31,50 @@ import com.cloud.utils.db.GenericDaoBase; @Local(value = StaticRouteDao.class) @DB(txn = false) public class StaticRouteDaoImpl extends GenericDaoBase implements StaticRouteDao{ + protected final SearchBuilder AllFieldsSearch; + protected final SearchBuilder NotRevokedSearch; + + protected StaticRouteDaoImpl() { + super(); + AllFieldsSearch = createSearchBuilder(); + AllFieldsSearch.and("gatewayId", AllFieldsSearch.entity().getVpcGatewayId(), Op.EQ); + AllFieldsSearch.and("vpcId", AllFieldsSearch.entity().getVpcId(), Op.EQ); + AllFieldsSearch.and("state", AllFieldsSearch.entity().getState(), Op.EQ); + AllFieldsSearch.and("id", AllFieldsSearch.entity().getId(), Op.EQ); + AllFieldsSearch.done(); + + NotRevokedSearch = createSearchBuilder(); + NotRevokedSearch.and("gatewayId", NotRevokedSearch.entity().getVpcGatewayId(), Op.EQ); + NotRevokedSearch.and("state", NotRevokedSearch.entity().getState(), Op.NEQ); + NotRevokedSearch.done(); + } + + + @Override + public boolean setStateToAdd(StaticRouteVO rule) { + SearchCriteria sc = AllFieldsSearch.create(); + sc.setParameters("id", rule.getId()); + sc.setParameters("state", StaticRoute.State.Staged); + + rule.setState(StaticRoute.State.Add); + + return update(rule, sc) > 0; + } + + + @Override + public List listByGatewayIdAndNotRevoked(long gatewayId) { + SearchCriteria sc = NotRevokedSearch.create(); + sc.setParameters("gatewayId", gatewayId); + sc.setParameters("state", StaticRoute.State.Revoke); + return listBy(sc); + } + + @Override + public List listByVpcId(long vpcId) { + SearchCriteria sc = AllFieldsSearch.create(); + sc.setParameters("vpcId", vpcId); + return listBy(sc); + } } diff --git a/server/src/com/cloud/network/vpc/StaticRouteVO.java b/server/src/com/cloud/network/vpc/StaticRouteVO.java index f8b59a0beeb..8859aa8c8d6 100644 --- a/server/src/com/cloud/network/vpc/StaticRouteVO.java +++ b/server/src/com/cloud/network/vpc/StaticRouteVO.java @@ -72,13 +72,17 @@ public class StaticRouteVO implements Identity, StaticRoute{ * @param vpcGatewayId * @param cidr * @param vpcId + * @param accountId TODO + * @param domainId TODO */ - public StaticRouteVO(long vpcGatewayId, String cidr, Long vpcId) { + public StaticRouteVO(long vpcGatewayId, String cidr, Long vpcId, long accountId, long domainId) { super(); this.vpcGatewayId = vpcGatewayId; this.cidr = cidr; this.state = State.Staged; this.vpcId = vpcId; + this.accountId = accountId; + this.domainId = domainId; this.uuid = UUID.randomUUID().toString(); } @@ -121,4 +125,15 @@ public class StaticRouteVO implements Identity, StaticRoute{ public long getDomainId() { return domainId; } + + public void setState(State state) { + this.state = state; + } + + @Override + public String toString() { + StringBuilder buf = new StringBuilder("StaticRoute["); + buf.append(uuid).append("|").append(cidr).append("|").append(vpcGatewayId).append("]"); + return buf.toString(); + } } \ No newline at end of file diff --git a/server/src/com/cloud/network/vpc/VpcManagerImpl.java b/server/src/com/cloud/network/vpc/VpcManagerImpl.java index f21ca703a62..0eeb47afd61 100644 --- a/server/src/com/cloud/network/vpc/VpcManagerImpl.java +++ b/server/src/com/cloud/network/vpc/VpcManagerImpl.java @@ -77,6 +77,7 @@ import com.cloud.utils.db.SearchBuilder; import com.cloud.utils.db.SearchCriteria; import com.cloud.utils.db.SearchCriteria.Op; import com.cloud.utils.db.Transaction; +import com.cloud.utils.exception.CloudRuntimeException; import com.cloud.utils.net.NetUtils; import com.cloud.vm.DomainRouterVO; import com.cloud.vm.ReservationContext; @@ -611,7 +612,6 @@ public class VpcManagerImpl implements VpcManager, Manager{ sb.and("state", sb.entity().getState(), SearchCriteria.Op.EQ); sb.and("restartRequired", sb.entity().isRestartRequired(), SearchCriteria.Op.EQ); - // now set the SC criteria... SearchCriteria sc = sb.create(); _accountMgr.buildACLSearchCriteria(sc, domainId, isRecursive, permittedAccounts, listProjectResourcesCriteria); @@ -796,7 +796,7 @@ public class VpcManagerImpl implements VpcManager, Manager{ } try { - //1) CIDR is required + //1) CIDR is required if (cidr == null) { throw new InvalidParameterValueException("Gateway/netmask are required when create network for VPC"); } @@ -930,7 +930,7 @@ public class VpcManagerImpl implements VpcManager, Manager{ @Override public List getVpcRouters(long vpcId) { - return _routerDao.listRoutersByVpcId(vpcId); + return _routerDao.listByVpcId(vpcId); } @Override @@ -1110,26 +1110,193 @@ public class VpcManagerImpl implements VpcManager, Manager{ } @Override - public boolean applyStaticRoutes(long vpcId) { - // TODO Auto-generated method stub - return false; + public boolean applyStaticRoutes(long vpcId) throws ResourceUnavailableException { + Account caller = UserContext.current().getCaller(); + List routes = _staticRouteDao.listByVpcId(vpcId); + return applyStaticRoutes(routes, caller); + } + + protected boolean applyStaticRoutes(List routes, Account caller) throws ResourceUnavailableException { + boolean success = true; + List staticRouteProfiles = new ArrayList(routes.size()); + Map gatewayMap = new HashMap(); + for (StaticRoute route : routes) { + PrivateGateway gateway = gatewayMap.get(route.getVpcGatewayId()); + if (gateway == null) { + gateway = getVpcPrivateGateway(route.getVpcGatewayId()); + gatewayMap.put(gateway.getId(), gateway); + } + staticRouteProfiles.add(new StaticRouteProfile(route, gateway)); + } + if (!applyStaticRoutes(staticRouteProfiles)) { + s_logger.warn("Routes are not completely applied"); + return false; + } else { + for (StaticRoute route : routes) { + if (route.getState() == StaticRoute.State.Revoke) { + _staticRouteDao.remove(route.getId()); + } else if (route.getState() == StaticRoute.State.Add) { + StaticRouteVO ruleVO = _staticRouteDao.findById(route.getId()); + ruleVO.setState(StaticRoute.State.Active); + _staticRouteDao.update(ruleVO.getId(), ruleVO); + } + } + } + + return success; + } + + protected boolean applyStaticRoutes(List routes) throws ResourceUnavailableException{ + if (routes.isEmpty()) { + s_logger.debug("No static routes to apply"); + return true; + } + Vpc vpc = getVpc(routes.get(0).getVpcId()); + + s_logger.debug("Applying static routes for vpc " + vpc); + if (getVpcElement().applyStaticRoutes(vpc, routes)) { + s_logger.debug("Applied static routes for vpc " + vpc); + } else { + s_logger.warn("Failed to apply static routes for vpc " + vpc); + return false; + } + + return true; } @Override - public boolean revokeStaticRoute(long routeId) { - // TODO Auto-generated method stub - return false; + public boolean revokeStaticRoute(long routeId) throws ResourceUnavailableException { + Account caller = UserContext.current().getCaller(); + + StaticRouteVO route = _staticRouteDao.findById(routeId); + if (route == null) { + throw new InvalidParameterValueException("Unable to find static route by id"); + } + + _accountMgr.checkAccess(caller, null, false, route); + + revokeStaticRoute(route, caller); + + return applyStaticRoutes(route.getVpcId()); + } @Override + @DB public StaticRoute createStaticRoute(long gatewayId, String cidr) throws NetworkRuleConflictException { - // TODO Auto-generated method stub - return null; + Account caller = UserContext.current().getCaller(); + + //parameters validation + PrivateGateway gateway = getVpcPrivateGateway(gatewayId); + if (gateway == null) { + throw new InvalidParameterValueException("Invalid gateway id is given"); + } + + Vpc vpc = getVpc(gateway.getVpcId()); + _accountMgr.checkAccess(caller, null, false, vpc); + + if (!NetUtils.isValidCIDR(cidr)){ + throw new InvalidParameterValueException("Invalid format for cidr " + cidr); + } + + //TODO - check cidr for the conflicts + Transaction txn = Transaction.currentTxn(); + txn.start(); + + StaticRouteVO newRoute = new StaticRouteVO(gateway.getId(), cidr, vpc.getId(), vpc.getAccountId(), vpc.getDomainId()); + s_logger.debug("Adding static route " + newRoute); + newRoute = _staticRouteDao.persist(newRoute); + + detectRoutesConflict(newRoute); + + if (!_staticRouteDao.setStateToAdd(newRoute)) { + throw new CloudRuntimeException("Unable to update the state to add for " + newRoute); + } + UserContext.current().setEventDetails("Static route Id: " + newRoute.getId()); + + txn.commit(); + + return newRoute; } @Override public List listStaticRoutes(ListStaticRoutesCmd cmd) { - // TODO Auto-generated method stub - return null; + Long id = cmd.getId(); + Long gatewayId = cmd.getGatewayId(); + Long vpcId = cmd.getVpcId(); + Long domainId = cmd.getDomainId(); + Boolean isRecursive = cmd.isRecursive(); + Boolean listAll = cmd.listAll(); + String accountName = cmd.getAccountName(); + + Account caller = UserContext.current().getCaller(); + List permittedAccounts = new ArrayList(); + + Ternary domainIdRecursiveListProject = new Ternary(domainId, isRecursive, null); + _accountMgr.buildACLSearchParameters(caller, id, accountName, null, permittedAccounts, domainIdRecursiveListProject, + listAll, false); + domainId = domainIdRecursiveListProject.first(); + isRecursive = domainIdRecursiveListProject.second(); + ListProjectResourcesCriteria listProjectResourcesCriteria = domainIdRecursiveListProject.third(); + Filter searchFilter = new Filter(StaticRouteVO.class, "created", false, cmd.getStartIndex(), cmd.getPageSizeVal()); + + SearchBuilder sb = _staticRouteDao.createSearchBuilder(); + _accountMgr.buildACLSearchBuilder(sb, domainId, isRecursive, permittedAccounts, listProjectResourcesCriteria); + + sb.and("id", sb.entity().getId(), SearchCriteria.Op.EQ); + sb.and("vpcId", sb.entity().getVpcId(), SearchCriteria.Op.EQ); + sb.and("vpcGatewayId", sb.entity().getVpcGatewayId(), SearchCriteria.Op.EQ); + + SearchCriteria sc = sb.create(); + _accountMgr.buildACLSearchCriteria(sc, domainId, isRecursive, permittedAccounts, listProjectResourcesCriteria); + + if (id != null) { + sc.addAnd("id", Op.EQ, id); + } + + if (vpcId != null) { + sc.addAnd("vpcId", Op.EQ, vpcId); + } + + if (gatewayId != null) { + sc.addAnd("vpcGatewayId", Op.EQ, vpcId); + } + + return _staticRouteDao.search(sc, searchFilter); + } + + protected void detectRoutesConflict(StaticRoute newRoute) throws NetworkRuleConflictException { + List routes = _staticRouteDao.listByGatewayIdAndNotRevoked(newRoute.getVpcGatewayId()); + assert (routes.size() >= 1) : "For static routes, we now always first persist the route and then check for " + + "network conflicts so we should at least have one rule at this point."; + + for (StaticRoute route : routes) { + if (route.getId() == newRoute.getId()) { + continue; // Skips my own route. + } + + if (NetUtils.isNetworksOverlap(route.getCidr(), newRoute.getCidr())) { + throw new NetworkRuleConflictException("New static route cidr conflicts with existing route " + route); + } + } + } + + protected void revokeStaticRoute(StaticRouteVO route, Account caller) { + s_logger.debug("Revoking static route " + route); + if (caller != null) { + _accountMgr.checkAccess(caller, null, false, route); + } + + if (route.getState() == StaticRoute.State.Staged) { + if (s_logger.isDebugEnabled()) { + s_logger.debug("Found a static route that is still in stage state so just removing it: " + route); + } + _staticRouteDao.remove(route.getId()); + } else if (route.getState() == StaticRoute.State.Add || route.getState() == StaticRoute.State.Active) { + route.setState(StaticRoute.State.Revoke); + _staticRouteDao.update(route.getId(), route); + } + } } diff --git a/server/src/com/cloud/vm/dao/DomainRouterDao.java b/server/src/com/cloud/vm/dao/DomainRouterDao.java index 11f93bbb6ca..ed861841d59 100755 --- a/server/src/com/cloud/vm/dao/DomainRouterDao.java +++ b/server/src/com/cloud/vm/dao/DomainRouterDao.java @@ -110,7 +110,7 @@ public interface DomainRouterDao extends GenericDao { * @param vpcId * @return */ - List listRoutersByVpcId(long vpcId); + List listByVpcId(long vpcId); /** * @param routerId diff --git a/server/src/com/cloud/vm/dao/DomainRouterDaoImpl.java b/server/src/com/cloud/vm/dao/DomainRouterDaoImpl.java index f0257ac12d7..c58cc4a6a0f 100755 --- a/server/src/com/cloud/vm/dao/DomainRouterDaoImpl.java +++ b/server/src/com/cloud/vm/dao/DomainRouterDaoImpl.java @@ -303,7 +303,7 @@ public class DomainRouterDaoImpl extends GenericDaoBase im } @Override - public List listRoutersByVpcId(long vpcId) { + public List listByVpcId(long vpcId) { SearchCriteria sc = VpcSearch.create(); sc.setParameters("vpcId", vpcId); sc.setParameters("role", Role.VIRTUAL_ROUTER);