| // 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.network.tungsten.service; |
| |
| import com.cloud.agent.AgentManager; |
| import com.cloud.agent.Listener; |
| import com.cloud.agent.api.AgentControlAnswer; |
| import com.cloud.agent.api.AgentControlCommand; |
| import com.cloud.agent.api.Answer; |
| import com.cloud.agent.api.Command; |
| import com.cloud.agent.api.StartupCommand; |
| import com.cloud.agent.api.to.LoadBalancerTO; |
| import com.cloud.api.ApiDBUtils; |
| import com.cloud.configuration.Config; |
| import com.cloud.dc.DataCenter; |
| import com.cloud.dc.DataCenterVO; |
| import com.cloud.dc.HostPodVO; |
| import com.cloud.dc.VlanVO; |
| import com.cloud.dc.dao.DataCenterDao; |
| import com.cloud.dc.dao.HostPodDao; |
| import com.cloud.dc.dao.VlanDao; |
| import com.cloud.deploy.DeployDestination; |
| import com.cloud.exception.ConcurrentOperationException; |
| import com.cloud.exception.ResourceUnavailableException; |
| import com.cloud.host.Host; |
| import com.cloud.host.HostVO; |
| import com.cloud.host.Status; |
| import com.cloud.host.dao.HostDao; |
| import com.cloud.hypervisor.Hypervisor; |
| import com.cloud.network.IpAddressManager; |
| import com.cloud.network.Network; |
| import com.cloud.network.NetworkMigrationResponder; |
| import com.cloud.network.NetworkModel; |
| import com.cloud.network.Networks; |
| import com.cloud.network.PhysicalNetworkServiceProvider; |
| import com.cloud.network.PublicIpAddress; |
| import com.cloud.network.TungstenGuestNetworkIpAddressVO; |
| import com.cloud.network.TungstenProvider; |
| import com.cloud.network.dao.IPAddressDao; |
| import com.cloud.network.dao.IPAddressVO; |
| import com.cloud.network.dao.LoadBalancerCertMapDao; |
| import com.cloud.network.dao.LoadBalancerCertMapVO; |
| import com.cloud.network.dao.LoadBalancerDao; |
| import com.cloud.network.dao.LoadBalancerVMMapDao; |
| import com.cloud.network.dao.LoadBalancerVMMapVO; |
| import com.cloud.network.dao.LoadBalancerVO; |
| import com.cloud.network.dao.NetworkDao; |
| import com.cloud.network.dao.NetworkDetailVO; |
| import com.cloud.network.dao.NetworkDetailsDao; |
| import com.cloud.network.dao.NetworkServiceMapDao; |
| import com.cloud.network.dao.NetworkVO; |
| import com.cloud.network.dao.PhysicalNetworkDao; |
| import com.cloud.network.dao.PhysicalNetworkTrafficTypeDao; |
| import com.cloud.network.dao.PhysicalNetworkTrafficTypeVO; |
| import com.cloud.network.dao.TungstenGuestNetworkIpAddressDao; |
| import com.cloud.network.dao.TungstenProviderDao; |
| import com.cloud.network.element.DnsServiceProvider; |
| import com.cloud.network.element.FirewallServiceProvider; |
| import com.cloud.network.element.IpDeployer; |
| import com.cloud.network.element.LoadBalancingServiceProvider; |
| import com.cloud.network.element.PortForwardingServiceProvider; |
| import com.cloud.network.element.StaticNatServiceProvider; |
| import com.cloud.network.element.TungstenProviderVO; |
| import com.cloud.network.lb.LoadBalancingRule; |
| import com.cloud.network.rules.FirewallRule; |
| import com.cloud.network.rules.LbStickinessMethod; |
| import com.cloud.network.rules.LoadBalancerContainer; |
| import com.cloud.network.rules.PortForwardingRule; |
| import com.cloud.network.rules.StaticNat; |
| import com.cloud.offering.NetworkOffering; |
| import com.cloud.resource.ResourceManager; |
| import com.cloud.resource.ResourceStateAdapter; |
| import com.cloud.resource.ServerResource; |
| import com.cloud.user.AccountManager; |
| import com.cloud.uservm.UserVm; |
| import com.cloud.utils.Pair; |
| import com.cloud.utils.TungstenUtils; |
| import com.cloud.utils.component.AdapterBase; |
| import com.cloud.utils.exception.CloudRuntimeException; |
| import com.cloud.utils.fsm.StateListener; |
| import com.cloud.utils.fsm.StateMachine2; |
| import com.cloud.utils.net.Ip; |
| import com.cloud.utils.net.NetUtils; |
| import com.cloud.vm.Nic; |
| import com.cloud.vm.NicProfile; |
| import com.cloud.vm.NicVO; |
| import com.cloud.vm.ReservationContext; |
| import com.cloud.vm.VMInstanceVO; |
| import com.cloud.vm.VirtualMachine; |
| import com.cloud.vm.VirtualMachineProfile; |
| import com.cloud.vm.dao.NicDao; |
| import com.cloud.vm.dao.VMInstanceDao; |
| import com.google.gson.Gson; |
| import org.apache.cloudstack.framework.config.dao.ConfigurationDao; |
| import org.apache.cloudstack.framework.messagebus.MessageBus; |
| import org.apache.cloudstack.framework.messagebus.PublishScope; |
| import org.apache.cloudstack.network.tungsten.agent.api.ApplyTungstenNetworkPolicyCommand; |
| import org.apache.cloudstack.network.tungsten.agent.api.ApplyTungstenPortForwardingCommand; |
| import org.apache.cloudstack.network.tungsten.agent.api.AssignTungstenFloatingIpCommand; |
| import org.apache.cloudstack.network.tungsten.agent.api.CreateTungstenNetworkLoadbalancerCommand; |
| import org.apache.cloudstack.network.tungsten.agent.api.CreateTungstenNetworkPolicyCommand; |
| import org.apache.cloudstack.network.tungsten.agent.api.CreateTungstenVirtualMachineCommand; |
| import org.apache.cloudstack.network.tungsten.agent.api.DeleteTungstenFloatingIpCommand; |
| import org.apache.cloudstack.network.tungsten.agent.api.DeleteTungstenLoadBalancerCommand; |
| import org.apache.cloudstack.network.tungsten.agent.api.DeleteTungstenLoadBalancerListenerCommand; |
| import org.apache.cloudstack.network.tungsten.agent.api.DeleteTungstenNetworkPolicyCommand; |
| import org.apache.cloudstack.network.tungsten.agent.api.DeleteTungstenVRouterPortCommand; |
| import org.apache.cloudstack.network.tungsten.agent.api.DeleteTungstenVmCommand; |
| import org.apache.cloudstack.network.tungsten.agent.api.DeleteTungstenVmInterfaceCommand; |
| import org.apache.cloudstack.network.tungsten.agent.api.ReleaseTungstenFloatingIpCommand; |
| import org.apache.cloudstack.network.tungsten.agent.api.SetupTfRouteCommand; |
| import org.apache.cloudstack.network.tungsten.agent.api.SetupTungstenVRouterCommand; |
| import org.apache.cloudstack.network.tungsten.agent.api.StartupTungstenCommand; |
| import org.apache.cloudstack.network.tungsten.agent.api.TungstenAnswer; |
| import org.apache.cloudstack.network.tungsten.agent.api.TungstenCommand; |
| import org.apache.cloudstack.network.tungsten.agent.api.UpdateTungstenLoadBalancerHealthMonitorCommand; |
| import org.apache.cloudstack.network.tungsten.agent.api.UpdateTungstenLoadBalancerMemberCommand; |
| import org.apache.cloudstack.network.tungsten.agent.api.UpdateTungstenLoadBalancerPoolCommand; |
| import org.apache.cloudstack.network.tungsten.dao.TungstenFabricLBHealthMonitorDao; |
| import org.apache.cloudstack.network.tungsten.dao.TungstenFabricLBHealthMonitorVO; |
| import org.apache.cloudstack.network.tungsten.model.TungstenLoadBalancerMember; |
| import org.apache.cloudstack.network.tungsten.model.TungstenRule; |
| import org.apache.commons.lang3.StringUtils; |
| import org.apache.log4j.Logger; |
| import org.springframework.stereotype.Component; |
| |
| import java.util.ArrayList; |
| import java.util.Arrays; |
| import java.util.HashMap; |
| import java.util.HashSet; |
| import java.util.List; |
| import java.util.Map; |
| import java.util.Set; |
| |
| import javax.inject.Inject; |
| import javax.naming.ConfigurationException; |
| |
| @Component |
| public class TungstenElement extends AdapterBase |
| implements StaticNatServiceProvider, IpDeployer, FirewallServiceProvider, |
| LoadBalancingServiceProvider, PortForwardingServiceProvider, ResourceStateAdapter, DnsServiceProvider, Listener, |
| StateListener<VirtualMachine.State, VirtualMachine.Event, VirtualMachine>, NetworkMigrationResponder { |
| private static final Logger s_logger = Logger.getLogger(TungstenElement.class); |
| |
| private static final String NETWORK = "network"; |
| |
| private final Map<Network.Service, Map<Network.Capability, String>> capabilities = initCapabilities(); |
| @Inject |
| HostPodDao podDao; |
| @Inject |
| DataCenterDao dataCenterDao; |
| @Inject |
| NetworkModel networkModel; |
| @Inject |
| NetworkDao networkDao; |
| @Inject |
| AccountManager accountMgr; |
| @Inject |
| ResourceManager resourceMgr; |
| @Inject |
| IPAddressDao ipAddressDao; |
| @Inject |
| IpAddressManager ipAddressMgr; |
| @Inject |
| PhysicalNetworkDao physicalNetworkDao; |
| @Inject |
| VMInstanceDao vmInstanceDao; |
| @Inject |
| AgentManager agentMgr; |
| @Inject |
| ConfigurationDao configDao; |
| @Inject |
| VlanDao vlanDao; |
| @Inject |
| HostDao hostDao; |
| @Inject |
| NicDao nicDao; |
| @Inject |
| NetworkServiceMapDao networkServiceMapDao; |
| @Inject |
| NetworkDetailsDao networkDetailsDao; |
| @Inject |
| LoadBalancerVMMapDao lbVmMapDao; |
| @Inject |
| LoadBalancerDao lbDao; |
| @Inject |
| TungstenService tungstenService; |
| @Inject |
| MessageBus messageBus; |
| @Inject |
| TungstenProviderDao tungstenProviderDao; |
| @Inject |
| TungstenGuestNetworkIpAddressDao tungstenGuestNetworkIpAddressDao; |
| @Inject |
| TungstenFabricUtils tungstenFabricUtils; |
| @Inject |
| PhysicalNetworkTrafficTypeDao physicalNetworkTrafficTypeDao; |
| @Inject |
| TungstenFabricLBHealthMonitorDao tungstenFabricLBHealthMonitorDao; |
| @Inject |
| LoadBalancerCertMapDao loadBalancerCertMapDao; |
| |
| private static Map<Network.Service, Map<Network.Capability, String>> initCapabilities() { |
| Map<Network.Service, Map<Network.Capability, String>> capabilities = new HashMap<>(); |
| Map<Network.Capability, String> dhcpCapabilities = new HashMap<>(); |
| dhcpCapabilities.put(Network.Capability.DhcpAccrossMultipleSubnets, "true"); |
| capabilities.put(Network.Service.Dhcp, dhcpCapabilities); |
| Map<Network.Capability, String> sourceNatCapabilities = new HashMap<>(); |
| sourceNatCapabilities.put(Network.Capability.RedundantRouter, "true"); |
| sourceNatCapabilities.put(Network.Capability.SupportedSourceNatTypes, "peraccount"); |
| capabilities.put(Network.Service.SourceNat, sourceNatCapabilities); |
| capabilities.put(Network.Service.Connectivity, null); |
| capabilities.put(Network.Service.SecurityGroup, null); |
| capabilities.put(Network.Service.StaticNat, null); |
| Map<Network.Capability, String> dnsCapabilities = new HashMap<>(); |
| dnsCapabilities.put(Network.Capability.AllowDnsSuffixModification, "true"); |
| capabilities.put(Network.Service.Dns, dnsCapabilities); |
| Map<Network.Capability, String> firewallCapabilities = new HashMap<>(); |
| firewallCapabilities.put(Network.Capability.SupportedProtocols, "tcp,udp,icmp"); |
| firewallCapabilities.put(Network.Capability.SupportedEgressProtocols, "tcp,udp,icmp,all"); |
| firewallCapabilities.put(Network.Capability.MultipleIps, "true"); |
| firewallCapabilities.put(Network.Capability.TrafficStatistics, "per public ip"); |
| firewallCapabilities.put(Network.Capability.SupportedTrafficDirection, "ingress, egress"); |
| capabilities.put(Network.Service.Firewall, firewallCapabilities); |
| |
| Map<Network.Capability, String> lbCapabilities = new HashMap<>(); |
| lbCapabilities.put(Network.Capability.SupportedLBAlgorithms, "roundrobin,leastconn,source"); |
| lbCapabilities.put(Network.Capability.SupportedLBIsolation, "dedicated"); |
| lbCapabilities.put(Network.Capability.SupportedProtocols, "tcp,udp,http,ssl"); |
| lbCapabilities.put(Network.Capability.TrafficStatistics, "per public ip"); |
| lbCapabilities.put(Network.Capability.LoadBalancingSupportedIps, "additional"); |
| lbCapabilities.put(Network.Capability.LbSchemes, LoadBalancerContainer.Scheme.Public.toString()); |
| lbCapabilities.put(Network.Capability.SslTermination, "true"); |
| |
| LbStickinessMethod method; |
| List<LbStickinessMethod> methodList = new ArrayList<>(); |
| method = new LbStickinessMethod(LbStickinessMethod.StickinessMethodType.LBCookieBased, |
| "This is cookie based sticky method, can be used only for http"); |
| methodList.add(method); |
| |
| method = new LbStickinessMethod(LbStickinessMethod.StickinessMethodType.AppCookieBased, |
| "This is app session based sticky method, can be used only for http"); |
| methodList.add(method); |
| method.addParam("name", true, "cookie name passed in http header by apllication to the client", false); |
| |
| method = new LbStickinessMethod(LbStickinessMethod.StickinessMethodType.SourceBased, |
| "This is source based sticky method, can be used for any type of protocol."); |
| methodList.add(method); |
| |
| Gson gson = new Gson(); |
| String stickyMethodList = gson.toJson(methodList); |
| lbCapabilities.put(Network.Capability.SupportedStickinessMethods, stickyMethodList); |
| |
| lbCapabilities.put(Network.Capability.HealthCheckPolicy, "true"); |
| capabilities.put(Network.Service.Lb, lbCapabilities); |
| capabilities.put(Network.Service.PortForwarding, null); |
| |
| return capabilities; |
| } |
| |
| protected boolean canHandle(Network network, Network.Service service) { |
| s_logger.debug("Checking if TungstenElement can handle service " + service.getName() + " on network " |
| + network.getDisplayText()); |
| |
| if (!networkModel.isProviderForNetwork(getProvider(), network.getId())) { |
| s_logger.debug("TungstenElement is not a provider for network " + network.getDisplayText()); |
| return false; |
| } |
| |
| return true; |
| } |
| |
| @Override |
| public boolean applyStaticNats(Network config, List<? extends StaticNat> rules) { |
| for(StaticNat staticNat : rules) { |
| long sourceIpAddressId = staticNat.getSourceIpAddressId(); |
| IPAddressVO ipAddressVO = ipAddressDao.findByIdIncludingRemoved(sourceIpAddressId); |
| VMInstanceVO vm = vmInstanceDao.findByIdIncludingRemoved(ipAddressVO.getAssociatedWithVmId()); |
| // floating ip is released when nic was deleted |
| if (vm == null || networkModel.getNicInNetworkIncludingRemoved(vm.getId(), config.getId()) == null) { |
| continue; |
| } |
| Nic nic = networkModel.getNicInNetworkIncludingRemoved(vm.getId(), config.getId()); |
| Network publicNetwork = networkModel.getSystemNetworkByZoneAndTrafficType(config.getDataCenterId(), Networks.TrafficType.Public); |
| if (!staticNat.isForRevoke()) { |
| TungstenCommand assignTungstenFloatingIpCommand = new AssignTungstenFloatingIpCommand(publicNetwork.getUuid(), nic.getUuid(), |
| TungstenUtils.getFloatingIpPoolName(config.getDataCenterId()), TungstenUtils.getFloatingIpName(ipAddressVO.getId()), nic.getIPv4Address()); |
| TungstenAnswer assignFloatingIpAnswer = tungstenFabricUtils.sendTungstenCommand( |
| assignTungstenFloatingIpCommand, config.getDataCenterId()); |
| return assignFloatingIpAnswer.getResult(); |
| } else { |
| TungstenCommand releaseTungstenFloatingIpCommand = new ReleaseTungstenFloatingIpCommand(publicNetwork.getUuid(), TungstenUtils.getFloatingIpPoolName(config.getDataCenterId()), |
| TungstenUtils.getFloatingIpName(ipAddressVO.getId())); |
| TungstenAnswer releaseFloatingIpAnswer = tungstenFabricUtils.sendTungstenCommand( |
| releaseTungstenFloatingIpCommand, config.getDataCenterId()); |
| return releaseFloatingIpAnswer.getResult(); |
| } |
| } |
| |
| return true; |
| } |
| |
| @Override |
| public boolean applyLBRules(Network network, List<LoadBalancingRule> rules) { |
| Network publicNetwork = networkModel.getSystemNetworkByZoneAndTrafficType(network.getDataCenterId(), |
| Networks.TrafficType.Public); |
| for (LoadBalancingRule loadBalancingRule : rules) { |
| String tungstenProjectFqn = tungstenService.getTungstenProjectFqn(network); |
| LoadBalancerCertMapVO loadBalancerCertMapVO = loadBalancerCertMapDao.findByLbRuleId(loadBalancingRule.getId()); |
| if ((loadBalancerCertMapVO == null || !loadBalancerCertMapVO.isRevoke()) && loadBalancingRule.getState() == FirewallRule.State.Add) { |
| String protocol = StringUtils.upperCase(loadBalancingRule.getLbProtocol()); |
| if (loadBalancingRule.getSourcePortStart() == NetUtils.HTTP_PORT |
| || loadBalancingRule.getSourcePortStart() == NetUtils.HTTPS_PORT) { |
| protocol = "HTTP"; |
| } |
| |
| IPAddressVO ipAddressVO = ipAddressDao.findByIpAndDcId(network.getDataCenterId(), |
| loadBalancingRule.getSourceIp().addr()); |
| |
| List<TungstenLoadBalancerMember> memberIp = createTungstenLoadBalancerMember(loadBalancingRule); |
| |
| createLoadBalancer(network, publicNetwork, loadBalancingRule, ipAddressVO, memberIp, tungstenProjectFqn, protocol); |
| |
| updateLBHealthMonitor(network, loadBalancingRule, ipAddressVO, tungstenProjectFqn); |
| |
| updateLBPool(network, loadBalancingRule, protocol, tungstenProjectFqn); |
| |
| updateLoadBalancerMember(network, loadBalancingRule, memberIp, tungstenProjectFqn); |
| |
| return tungstenService.updateLoadBalancer(network, loadBalancingRule); |
| } |
| |
| if (loadBalancingRule.getState() == FirewallRule.State.Revoke) { |
| return applyRevokeRule(network, loadBalancingRule, publicNetwork, tungstenProjectFqn); |
| } |
| } |
| |
| return true; |
| } |
| |
| private void updateLoadBalancerMember(Network network, LoadBalancingRule loadBalancingRule, List<TungstenLoadBalancerMember> memberIp, String tungstenProjectFqn) { |
| TungstenCommand updateTungstenLoadBalancerMemberCommand = new UpdateTungstenLoadBalancerMemberCommand( |
| tungstenProjectFqn, network.getUuid(), TungstenUtils.getLoadBalancerPoolName(loadBalancingRule.getId()), memberIp); |
| TungstenAnswer updateTungstenLoadBalancerMemberAnswer = tungstenFabricUtils.sendTungstenCommand( |
| updateTungstenLoadBalancerMemberCommand, network.getDataCenterId()); |
| if (!updateTungstenLoadBalancerMemberAnswer.getResult()) { |
| throw new CloudRuntimeException("Can not create Tungsten Fabric Load Balancer Member"); |
| } |
| } |
| |
| private void createLoadBalancer(Network network, Network publicNetwork, LoadBalancingRule loadBalancingRule, IPAddressVO ipAddressVO, List<TungstenLoadBalancerMember> memberIp, String tungstenProjectFqn, String protocol) { |
| String lbIp = getLoadBalancerIpAddress(network, ipAddressVO); |
| TungstenCommand createTungstenNetworkLoadbalancerCommand = new CreateTungstenNetworkLoadbalancerCommand( |
| tungstenProjectFqn, network.getUuid(), publicNetwork.getUuid(), TungstenUtils.getLoadBalancerAlgorithm(loadBalancingRule.getAlgorithm()), |
| TungstenUtils.getLoadBalancerName(ipAddressVO.getId()), TungstenUtils.getLoadBalancerListenerName(loadBalancingRule.getId()), |
| TungstenUtils.getLoadBalancerPoolName(loadBalancingRule.getId()), TungstenUtils.getLoadBalancerHealthMonitorName(ipAddressVO.getId()), |
| TungstenUtils.getLoadBalancerVmiName(ipAddressVO.getId()), TungstenUtils.getLoadBalancerIiName(ipAddressVO.getId()), loadBalancingRule.getId(), memberIp, |
| protocol, loadBalancingRule.getSourcePortStart(), loadBalancingRule.getDefaultPortStart(), lbIp, |
| TungstenUtils.getFloatingIpPoolName(network.getDataCenterId()), TungstenUtils.getFloatingIpName(ipAddressVO.getId()), |
| TungstenService.MonitorType.PING.toString(), 3, 5, 5, null, null, null); |
| TungstenAnswer createTungstenNetworkLoadbalancerAnswer = tungstenFabricUtils.sendTungstenCommand( |
| createTungstenNetworkLoadbalancerCommand, network.getDataCenterId()); |
| if (!createTungstenNetworkLoadbalancerAnswer.getResult()) { |
| throw new CloudRuntimeException("Can not create Tungsten Fabric Load Balancer"); |
| } |
| } |
| |
| private List<TungstenLoadBalancerMember> createTungstenLoadBalancerMember(LoadBalancingRule loadBalancingRule) { |
| List<TungstenLoadBalancerMember> memberIp = new ArrayList<>(); |
| |
| List<LoadBalancerVMMapVO> loadBalancerVMMapVOList = lbVmMapDao.listByLoadBalancerId( |
| loadBalancingRule.getId(), false); |
| |
| for (LoadBalancerVMMapVO lbVMMapVO : loadBalancerVMMapVOList) { |
| int port = loadBalancingRule.getDefaultPortStart(); |
| if (loadBalancingRule.getDefaultPortStart() == NetUtils.HTTPS_PORT) { |
| port = NetUtils.HTTP_PORT; |
| } |
| |
| TungstenLoadBalancerMember tungstenLoadBalancerMember = new TungstenLoadBalancerMember( |
| TungstenUtils.getLoadBalancerMemberName(loadBalancingRule.getId(), lbVMMapVO.getInstanceIp()), |
| lbVMMapVO.getInstanceIp(), port, 1); |
| memberIp.add(tungstenLoadBalancerMember); |
| } |
| |
| return memberIp; |
| } |
| |
| private String getLoadBalancerIpAddress(Network network, IPAddressVO ipAddressVO) { |
| String lbIp; |
| TungstenGuestNetworkIpAddressVO guestNetworkIpAddressVO = tungstenGuestNetworkIpAddressDao.findByNetworkIdAndPublicIp( |
| network.getId(), ipAddressVO.getAddress().addr()); |
| |
| if (guestNetworkIpAddressVO == null) { |
| lbIp = ipAddressMgr.acquireGuestIpAddress(network, null); |
| |
| if (lbIp == null) { |
| throw new CloudRuntimeException("Can not acquire ip address for loadbalancer"); |
| } |
| |
| // register tungsten guest network ip |
| TungstenGuestNetworkIpAddressVO tungstenGuestNetworkIpAddressVO = new TungstenGuestNetworkIpAddressVO(); |
| tungstenGuestNetworkIpAddressVO.setNetworkId(network.getId()); |
| tungstenGuestNetworkIpAddressVO.setPublicIpAddress(ipAddressVO.getAddress()); |
| tungstenGuestNetworkIpAddressVO.setGuestIpAddress(new Ip(lbIp)); |
| tungstenGuestNetworkIpAddressDao.persist(tungstenGuestNetworkIpAddressVO); |
| } else { |
| lbIp = guestNetworkIpAddressVO.getGuestIpAddress().addr(); |
| } |
| |
| return lbIp; |
| } |
| |
| private void updateLBPool(Network network, LoadBalancingRule loadBalancingRule, String protocol, String tungstenProjectFqn) { |
| // update stickiness, algorithm, protocol |
| List<LoadBalancingRule.LbStickinessPolicy> lbStickinessPolicyList = loadBalancingRule.getStickinessPolicies(); |
| String lbSessionPersistence = null; |
| String lbPersistenceCookieName = null; |
| if (!lbStickinessPolicyList.isEmpty()) { |
| lbSessionPersistence = TungstenUtils.getLoadBalancerSession(lbStickinessPolicyList.get(0).getMethodName()); |
| if (lbStickinessPolicyList.get(0).getMethodName().equals("AppCookie")) { |
| lbPersistenceCookieName = lbStickinessPolicyList.get(0).getParams().get(0).second(); |
| } |
| } |
| |
| // update haproxy |
| TungstenCommand updateTungstenLoadBalancerPoolCommand; |
| String lbStatsVisibility = configDao.getValue(Config.NetworkLBHaproxyStatsVisbility.key()); |
| if (!lbStatsVisibility.equals("disabled")) { |
| String lbStatsUri = configDao.getValue(Config.NetworkLBHaproxyStatsUri.key()); |
| String lbStatsAuth = configDao.getValue(Config.NetworkLBHaproxyStatsAuth.key()); |
| String lbStatsPort = configDao.getValue(Config.NetworkLBHaproxyStatsPort.key()); |
| updateTungstenLoadBalancerPoolCommand = new UpdateTungstenLoadBalancerPoolCommand( |
| tungstenProjectFqn, TungstenUtils.getLoadBalancerPoolName(loadBalancingRule.getId()), |
| TungstenUtils.getLoadBalancerAlgorithm(loadBalancingRule.getAlgorithm()), |
| lbSessionPersistence, lbPersistenceCookieName, protocol, true, lbStatsPort, lbStatsUri, |
| lbStatsAuth); |
| } else { |
| updateTungstenLoadBalancerPoolCommand = new UpdateTungstenLoadBalancerPoolCommand( |
| tungstenProjectFqn, TungstenUtils.getLoadBalancerPoolName(loadBalancingRule.getId()), |
| TungstenUtils.getLoadBalancerAlgorithm(loadBalancingRule.getAlgorithm()), |
| lbSessionPersistence, lbPersistenceCookieName, protocol, false, null, null, null); |
| } |
| TungstenAnswer updateTungstenLoadBalancerPoolAnswer = tungstenFabricUtils.sendTungstenCommand( |
| updateTungstenLoadBalancerPoolCommand, network.getDataCenterId()); |
| if (!updateTungstenLoadBalancerPoolAnswer.getResult()) { |
| throw new CloudRuntimeException("Can not update Tungsten Fabric Load Balancer Pool"); |
| } |
| } |
| |
| private void updateLBHealthMonitor(Network network, LoadBalancingRule loadBalancingRule, IPAddressVO ipAddressVO, String tungstenProjectFqn) { |
| // update load balancer health monitor |
| TungstenFabricLBHealthMonitorVO tungstenFabricLBHealthMonitorVO = tungstenFabricLBHealthMonitorDao.findByLbId( |
| loadBalancingRule.getId()); |
| if (tungstenFabricLBHealthMonitorVO != null) { |
| TungstenCommand updateTungstenHealthMonitorCommand = new UpdateTungstenLoadBalancerHealthMonitorCommand( |
| tungstenProjectFqn, TungstenUtils.getLoadBalancerHealthMonitorName(ipAddressVO.getId()), |
| tungstenFabricLBHealthMonitorVO.getType(), tungstenFabricLBHealthMonitorVO.getRetry(), |
| tungstenFabricLBHealthMonitorVO.getTimeout(), tungstenFabricLBHealthMonitorVO.getInterval(), |
| tungstenFabricLBHealthMonitorVO.getHttpMethod(), tungstenFabricLBHealthMonitorVO.getExpectedCode(), |
| tungstenFabricLBHealthMonitorVO.getUrlPath()); |
| TungstenAnswer updateTungstenHealthMonitorAnswer = tungstenFabricUtils.sendTungstenCommand( |
| updateTungstenHealthMonitorCommand, network.getDataCenterId()); |
| if (!updateTungstenHealthMonitorAnswer.getResult()) { |
| throw new CloudRuntimeException("Can not update Tungsten Fabric Health Monitor"); |
| } |
| } |
| } |
| |
| private boolean applyRevokeRule(Network network, LoadBalancingRule loadBalancingRule, Network publicNetwork, String tungstenProjectFqn) { |
| IPAddressVO ipAddressVO = ipAddressDao.findByIpAndDcId(network.getDataCenterId(), |
| loadBalancingRule.getSourceIp().addr()); |
| List<LoadBalancerVO> listLoadBalancerVO = lbDao.listByIpAddress(ipAddressVO.getId()); |
| if (listLoadBalancerVO.size() > 1) { |
| TungstenCommand deleteTungstenLoadBalancerListenerCommand = |
| new DeleteTungstenLoadBalancerListenerCommand( |
| tungstenProjectFqn, TungstenUtils.getLoadBalancerListenerName(loadBalancingRule.getId())); |
| TungstenAnswer deleteTungstenLoadBalancerListenerAnswer = tungstenFabricUtils.sendTungstenCommand( |
| deleteTungstenLoadBalancerListenerCommand, network.getDataCenterId()); |
| if (!deleteTungstenLoadBalancerListenerAnswer.getResult()) { |
| return false; |
| } |
| |
| return tungstenService.updateLoadBalancer(network, loadBalancingRule); |
| } else { |
| TungstenCommand deleteTungstenLoadBalancerCommand = new DeleteTungstenLoadBalancerCommand( |
| tungstenProjectFqn, publicNetwork.getUuid(), |
| TungstenUtils.getLoadBalancerName(ipAddressVO.getId()), |
| TungstenUtils.getLoadBalancerHealthMonitorName(ipAddressVO.getId()), |
| TungstenUtils.getLoadBalancerVmiName(ipAddressVO.getId()), |
| TungstenUtils.getFloatingIpPoolName(network.getDataCenterId()), |
| TungstenUtils.getFloatingIpName(ipAddressVO.getId())); |
| TungstenAnswer deleteTungstenLoadBalancerAnswer = tungstenFabricUtils.sendTungstenCommand( |
| deleteTungstenLoadBalancerCommand, network.getDataCenterId()); |
| if (!deleteTungstenLoadBalancerAnswer.getResult()) { |
| return false; |
| } |
| |
| TungstenGuestNetworkIpAddressVO guestNetworkIpAddressVO = |
| tungstenGuestNetworkIpAddressDao.findByNetworkIdAndPublicIp( |
| network.getId(), ipAddressVO.getAddress().addr()); |
| if (guestNetworkIpAddressVO != null) { |
| return tungstenGuestNetworkIpAddressDao.remove(guestNetworkIpAddressVO.getId()); |
| } |
| } |
| |
| return true; |
| } |
| |
| @Override |
| public boolean validateLBRule(Network network, LoadBalancingRule rule) { |
| return true; |
| } |
| |
| @Override |
| public List<LoadBalancerTO> updateHealthChecks(Network network, List<LoadBalancingRule> lbrules) { |
| return new ArrayList<>(); |
| } |
| |
| @Override |
| public boolean handlesOnlyRulesInTransitionState() { |
| return false; |
| } |
| |
| @Override |
| public boolean applyPFRules(final Network network, final List<PortForwardingRule> rules) { |
| Network publicNetwork = networkModel.getSystemNetworkByZoneAndTrafficType(network.getDataCenterId(), |
| Networks.TrafficType.Public); |
| // tungsten port forwarding don't support multiple vm per public ip address |
| // if multiple vm, only 1 vm get effect |
| // frontend : don't allow to add multiple vm per public ip address |
| for (PortForwardingRule rule : rules) { |
| IPAddressVO publicIp = ApiDBUtils.findIpAddressById(rule.getSourceIpAddressId()); |
| UserVm vm = ApiDBUtils.findUserVmById(rule.getVirtualMachineId()); |
| if (vm == null || networkModel.getNicInNetwork(vm.getId(), network.getId()) == null) { |
| continue; |
| } |
| Nic guestNic = networkModel.getNicInNetwork(vm.getId(), network.getId()); |
| if (rule.getState() == FirewallRule.State.Add || rule.getState() == FirewallRule.State.Revoke) { |
| TungstenCommand applyTungstenPortForwardingCommand = new ApplyTungstenPortForwardingCommand( |
| rule.getState() == FirewallRule.State.Add, publicNetwork.getUuid(), |
| TungstenUtils.getFloatingIpPoolName(network.getDataCenterId()), |
| TungstenUtils.getFloatingIpName(publicIp.getId()), guestNic.getUuid(), |
| StringUtils.upperCase(rule.getProtocol()), rule.getSourcePortStart(), |
| rule.getDestinationPortStart()); |
| TungstenAnswer applyTungstenPortForwardingAnswer = tungstenFabricUtils.sendTungstenCommand( |
| applyTungstenPortForwardingCommand, network.getDataCenterId()); |
| if (!applyTungstenPortForwardingAnswer.getResult()) { |
| return false; |
| } |
| } |
| } |
| |
| return true; |
| } |
| |
| @Override |
| public IpDeployer getIpDeployer(Network network) { |
| return this; |
| } |
| |
| @Override |
| public Map<Network.Service, Map<Network.Capability, String>> getCapabilities() { |
| return capabilities; |
| } |
| |
| @Override |
| public boolean applyIps(Network network, List<? extends PublicIpAddress> ipAddress, Set<Network.Service> services) { |
| return true; |
| } |
| |
| @Override |
| public Network.Provider getProvider() { |
| return Network.Provider.Tungsten; |
| } |
| |
| @Override |
| public boolean implement(Network network, NetworkOffering offering, DeployDestination dest, |
| ReservationContext context) |
| throws ConcurrentOperationException { |
| return true; |
| } |
| |
| @Override |
| public boolean prepare(Network network, NicProfile nic, VirtualMachineProfile vm, DeployDestination dest, |
| ReservationContext context) |
| throws ConcurrentOperationException { |
| if (network.getTrafficType() == Networks.TrafficType.Public) { |
| TungstenAnswer createVirtualMachineAnswer = createTungstenVM(network, nic, vm, dest); |
| if (!createVirtualMachineAnswer.getResult()) { |
| throw new CloudRuntimeException("can not create Tungsten-Fabric vm"); |
| } |
| |
| // get tungsten public firewall rule |
| IPAddressVO ipAddressVO = ipAddressDao.findByIpAndDcId(network.getDataCenterId(), nic.getIPv4Address()); |
| List<TungstenRule> tungstenRuleList = createDefaultTungstenFirewallRuleList(vm.getType(), |
| nic.getIPv4Address()); |
| |
| // create tungsten public network policy for system vm |
| TungstenCommand createTungstenNetworkPolicyCommand = new CreateTungstenNetworkPolicyCommand( |
| TungstenUtils.getPublicNetworkPolicyName(ipAddressVO.getId()), null, tungstenRuleList); |
| TungstenAnswer createTungstenNetworkPolicyAnswer = tungstenFabricUtils.sendTungstenCommand( |
| createTungstenNetworkPolicyCommand, network.getDataCenterId()); |
| if (!createTungstenNetworkPolicyAnswer.getResult()) { |
| throw new CloudRuntimeException("can not create Tungsten-Fabric public network policy"); |
| } |
| |
| messageBus.publish(_name, TungstenService.MESSAGE_APPLY_NETWORK_POLICY_EVENT, PublishScope.LOCAL, network); |
| |
| updateTungstenFabricService(nic); |
| } |
| |
| if (network.getTrafficType() == Networks.TrafficType.Management) { |
| TungstenAnswer createVirtualMachineAnswer = createTungstenVM(network, nic, vm, dest); |
| if (!createVirtualMachineAnswer.getResult()) { |
| throw new CloudRuntimeException("can not create Tungsten-Fabric vm"); |
| } |
| |
| updateTungstenFabricService(nic); |
| } |
| |
| return true; |
| } |
| |
| @Override |
| public boolean release(Network network, NicProfile nic, VirtualMachineProfile vm, ReservationContext context) |
| throws ConcurrentOperationException { |
| VMInstanceVO vmInstanceVO = vmInstanceDao.findById(vm.getId()); |
| HostVO host = hostDao.findById(vmInstanceVO.getLastHostId()); |
| |
| if (host != null) { |
| if (network.getTrafficType() == Networks.TrafficType.Public) { |
| try { |
| TungstenCommand deleteTungstenVRouterPortCommand = new DeleteTungstenVRouterPortCommand( |
| host.getPublicIpAddress(), nic.getUuid()); |
| tungstenFabricUtils.sendTungstenCommand(deleteTungstenVRouterPortCommand, network.getDataCenterId()); |
| String nicName = TungstenUtils.getVmiName(network.getTrafficType().toString(), vm.getType().toString(), |
| vm.getInstanceName(), nic.getId()); |
| String tungstenProjectFqn = tungstenService.getTungstenProjectFqn(network); |
| DeleteTungstenVmInterfaceCommand deleteVmiCmd = new DeleteTungstenVmInterfaceCommand(tungstenProjectFqn, |
| nicName); |
| tungstenFabricUtils.sendTungstenCommand(deleteVmiCmd, network.getDataCenterId()); |
| |
| TungstenCommand deleteVmCmd = new DeleteTungstenVmCommand(vm.getUuid()); |
| tungstenFabricUtils.sendTungstenCommand(deleteVmCmd, network.getDataCenterId()); |
| |
| IPAddressVO ipAddressVO = ipAddressDao.findByIpAndDcId(network.getDataCenterId(), nic.getIPv4Address()); |
| TungstenCommand deleteTungstenNetworkPolicyCommand = new DeleteTungstenNetworkPolicyCommand( |
| TungstenUtils.getPublicNetworkPolicyName(ipAddressVO.getId()), null, network.getUuid()); |
| tungstenFabricUtils.sendTungstenCommand(deleteTungstenNetworkPolicyCommand, network.getDataCenterId()); |
| } catch (IllegalArgumentException e) { |
| throw new CloudRuntimeException( |
| "Failing to expunge the vm from Tungsten-Fabric with the uuid " + vm.getUuid()); |
| } |
| } |
| |
| if (network.getTrafficType() == Networks.TrafficType.Management) { |
| try { |
| TungstenCommand deleteTungstenVRouterPortCommand = new DeleteTungstenVRouterPortCommand( |
| host.getPublicIpAddress(), nic.getUuid()); |
| tungstenFabricUtils.sendTungstenCommand(deleteTungstenVRouterPortCommand, network.getDataCenterId()); |
| String nicName = TungstenUtils.getVmiName(network.getTrafficType().toString(), vm.getType().toString(), |
| vm.getInstanceName(), nic.getId()); |
| String tungstenProjectFqn = tungstenService.getTungstenProjectFqn(network); |
| TungstenCommand deleteVmiCmd = new DeleteTungstenVmInterfaceCommand(tungstenProjectFqn, nicName); |
| tungstenFabricUtils.sendTungstenCommand(deleteVmiCmd, network.getDataCenterId()); |
| |
| TungstenCommand deleteVmCmd = new DeleteTungstenVmCommand(vm.getUuid()); |
| tungstenFabricUtils.sendTungstenCommand(deleteVmCmd, network.getDataCenterId()); |
| } catch (IllegalArgumentException e) { |
| throw new CloudRuntimeException( |
| "Failing to expunge the vm from Tungsten-Fabric with the uuid " + vm.getUuid()); |
| } |
| } |
| } |
| |
| return true; |
| } |
| |
| @Override |
| public boolean shutdown(Network network, ReservationContext context, boolean cleanup) |
| throws ConcurrentOperationException { |
| return canHandle(network, Network.Service.Connectivity); |
| } |
| |
| @Override |
| public boolean destroy(Network network, ReservationContext context) |
| throws ConcurrentOperationException, ResourceUnavailableException { |
| boolean result = true; |
| // delete floating ips |
| List<IPAddressVO> staticNatIpList = ipAddressDao.listByAssociatedNetwork(network.getId(), false); |
| for (IPAddressVO ipAddressVO : staticNatIpList) { |
| TungstenCommand deleteTungstenFloatingIpCommand = new DeleteTungstenFloatingIpCommand(network.getUuid(), |
| TungstenUtils.getFloatingIpPoolName(network.getDataCenterId()), |
| TungstenUtils.getFloatingIpName(ipAddressVO.getId())); |
| TungstenAnswer tungstenDeleteFIPAnswer = tungstenFabricUtils.sendTungstenCommand( |
| deleteTungstenFloatingIpCommand, network.getDataCenterId()); |
| result = result && tungstenDeleteFIPAnswer.getResult(); |
| |
| TungstenCommand deleteTungstenNetworkPolicyCommand = new DeleteTungstenNetworkPolicyCommand( |
| TungstenUtils.getPublicNetworkPolicyName(ipAddressVO.getId()), null, network.getUuid()); |
| TungstenAnswer tungstenDeleteNPAnswer = tungstenFabricUtils.sendTungstenCommand( |
| deleteTungstenNetworkPolicyCommand, network.getDataCenterId()); |
| result = result && tungstenDeleteNPAnswer.getResult(); |
| } |
| |
| return result; |
| } |
| |
| @Override |
| public boolean isReady(PhysicalNetworkServiceProvider provider) { |
| PhysicalNetworkTrafficTypeVO managementNetwork = physicalNetworkTrafficTypeDao.findBy( |
| provider.getPhysicalNetworkId(), Networks.TrafficType.Management); |
| return managementNetwork != null; |
| } |
| |
| @Override |
| public boolean shutdownProviderInstances(PhysicalNetworkServiceProvider provider, ReservationContext context) |
| throws ConcurrentOperationException { |
| long zoneId = physicalNetworkDao.findById(provider.getPhysicalNetworkId()).getDataCenterId(); |
| |
| TungstenProvider tungstenProvider = tungstenProviderDao.findByZoneId(zoneId); |
| if (tungstenProvider != null) { |
| DataCenter dataCenter = dataCenterDao.findById(zoneId); |
| |
| if (!dataCenter.isSecurityGroupEnabled()) { |
| // delete network service map |
| Network publicNetwork = networkModel.getSystemNetworkByZoneAndTrafficType(zoneId, |
| Networks.TrafficType.Public); |
| if (publicNetwork != null) { |
| networkServiceMapDao.deleteByNetworkId(publicNetwork.getId()); |
| List<VlanVO> listVlanVO = vlanDao.listVlansByNetworkIdIncludingRemoved(publicNetwork.getId()); |
| for (VlanVO vlanVO : listVlanVO) { |
| tungstenService.removePublicNetworkSubnet(vlanVO); |
| } |
| |
| tungstenService.deletePublicNetwork(zoneId); |
| } |
| } |
| |
| List<HostPodVO> listPod = podDao.listByDataCenterId(zoneId); |
| for (HostPodVO pod : listPod) { |
| tungstenService.removeManagementNetworkSubnet(pod); |
| } |
| |
| tungstenService.deleteManagementNetwork(zoneId); |
| tungstenProviderDao.expunge(tungstenProvider.getId()); |
| } |
| return true; |
| } |
| |
| @Override |
| public boolean canEnableIndividualServices() { |
| return true; |
| } |
| |
| @Override |
| public boolean verifyServicesCombination(final Set<Network.Service> services) { |
| // tf can use configdrive for userdata |
| services.remove(Network.Service.UserData); |
| final Set<Network.Service> sharedZoneServices = new HashSet<>( |
| Arrays.asList(Network.Service.Connectivity, |
| Network.Service.Dhcp, |
| Network.Service.Dns, Network.Service.SecurityGroup)); |
| final Set<Network.Service> isolatedZoneServices = new HashSet<>( |
| Arrays.asList(Network.Service.Connectivity, |
| Network.Service.Dhcp, |
| Network.Service.Dns, Network.Service.SourceNat, Network.Service.StaticNat, |
| Network.Service.Lb, Network.Service.PortForwarding, Network.Service.Firewall)); |
| return (services.containsAll(sharedZoneServices) && sharedZoneServices.containsAll(services)) || ( |
| services.containsAll(isolatedZoneServices) && isolatedZoneServices.containsAll(services)); |
| } |
| |
| @Override |
| public boolean configure(String name, Map<String, Object> params) throws ConfigurationException { |
| super.configure(name, params); |
| agentMgr.registerForHostEvents(this, true, true, true); |
| resourceMgr.registerResourceStateAdapter(this.getClass().getSimpleName(), this); |
| VirtualMachine.State.getStateMachine().registerListener(this); |
| |
| return true; |
| } |
| |
| @Override |
| public HostVO createHostVOForConnectedAgent(HostVO host, StartupCommand[] cmd) { |
| return null; |
| } |
| |
| @Override |
| public HostVO createHostVOForDirectConnectAgent(HostVO host, StartupCommand[] startup, ServerResource resource, |
| Map<String, String> details, List<String> hostTags) { |
| if (!(startup[0] instanceof StartupTungstenCommand)) { |
| return null; |
| } |
| host.setType(Host.Type.L2Networking); |
| return host; |
| } |
| |
| @Override |
| public DeleteHostAnswer deleteHost(HostVO host, boolean isForced, boolean isForceDeleteStorage) { |
| if (host.getType() != Host.Type.L2Networking) { |
| return null; |
| } |
| return new DeleteHostAnswer(true); |
| } |
| |
| @Override |
| public boolean processAnswers(final long agentId, final long seq, final Answer[] answers) { |
| return false; |
| } |
| |
| @Override |
| public boolean processCommands(final long agentId, final long seq, final Command[] commands) { |
| return false; |
| } |
| |
| @Override |
| public AgentControlAnswer processControlCommand(final long agentId, final AgentControlCommand cmd) { |
| return null; |
| } |
| |
| @Override |
| public void processHostAdded(final long hostId) { |
| // Do nothing |
| } |
| |
| @Override |
| public void processConnect(final Host host, final StartupCommand cmd, final boolean forRebalance) { |
| long zoneId = host.getDataCenterId(); |
| TungstenProviderVO tungstenProvider = tungstenProviderDao.findByZoneId(zoneId); |
| if (host.getHypervisorType() == Hypervisor.HypervisorType.KVM && tungstenProvider != null |
| && host.getPublicIpAddress().equals(tungstenProvider.getGateway())) { |
| setupVrouter(host); |
| } |
| |
| if ((host.getType() == Host.Type.ConsoleProxy || host.getType() == Host.Type.SecondaryStorageVM) && tungstenProvider != null) { |
| VirtualMachine.Type type = host.getType() == Host.Type.SecondaryStorageVM ? VirtualMachine.Type.SecondaryStorageVm : VirtualMachine.Type.ConsoleProxy; |
| List<VMInstanceVO> vmList = vmInstanceDao.listByZoneIdAndType(zoneId, type); |
| if (vmList.size() == 1 && vmList.get(0).getState() == VirtualMachine.State.Running) { |
| NicVO nicVO = nicDao.getControlNicForVM(vmList.get(0).getId()); |
| HostVO kvmHost = hostDao.findById(vmList.get(0).getHostId()); |
| String srcNetwork = NetUtils.getCidrFromGatewayAndNetmask(kvmHost.getPrivateIpAddress(), kvmHost.getPrivateNetmask()); |
| Command setupTfRoute = new SetupTfRouteCommand(nicVO.getIPv4Address(), host.getPublicIpAddress(), srcNetwork); |
| agentMgr.easySend(vmList.get(0).getHostId(), setupTfRoute); |
| } |
| } |
| } |
| |
| private void setupVrouter(Host host) { |
| long zoneId = host.getDataCenterId(); |
| DataCenterVO dataCenterVO = dataCenterDao.findById(zoneId); |
| if (dataCenterVO.isSecurityGroupEnabled()) { |
| List<NetworkVO> networks = networkDao.listByZoneSecurityGroup(zoneId); |
| for (NetworkVO network : networks) { |
| NetworkDetailVO networkDetail = networkDetailsDao.findDetail(network.getId(), "vrf"); |
| if (networkDetail != null) { |
| Command setupTungstenVRouterCommand = new SetupTungstenVRouterCommand( |
| "create", TungstenUtils.getSgVgwName(network.getId()), network.getCidr(), |
| NetUtils.ALL_IP4_CIDRS, networkDetail.getValue()); |
| agentMgr.easySend(host.getId(), setupTungstenVRouterCommand); |
| } |
| } |
| } else { |
| List<VlanVO> vlanList = vlanDao.listByZone(zoneId); |
| List<String> publicSubnetList = new ArrayList<>(); |
| |
| for (VlanVO vlanVO : vlanList) { |
| String subnet = NetUtils.getCidrFromGatewayAndNetmask(vlanVO.getVlanGateway(), |
| vlanVO.getVlanNetmask()); |
| publicSubnetList.add(subnet); |
| } |
| |
| String publicSubnet = StringUtils.join(publicSubnetList.toArray(), " "); |
| Network publicNetwork = networkModel.getSystemNetworkByZoneAndTrafficType(zoneId, |
| Networks.TrafficType.Public); |
| NetworkDetailVO networkDetail = networkDetailsDao.findDetail(publicNetwork.getId(), "vrf"); |
| if (networkDetail != null) { |
| Command setupTungstenVRouterCommand = new SetupTungstenVRouterCommand("create", |
| TungstenUtils.getVgwName(zoneId), publicSubnet, NetUtils.ALL_IP4_CIDRS, |
| networkDetail.getValue()); |
| agentMgr.easySend(host.getId(), setupTungstenVRouterCommand); |
| } |
| } |
| } |
| |
| @Override |
| public boolean processDisconnect(final long agentId, final Status state) { |
| return true; |
| } |
| |
| @Override |
| public void processHostAboutToBeRemoved(final long hostId) { |
| Host host = hostDao.findById(hostId); |
| long zoneId = host.getDataCenterId(); |
| |
| TungstenProviderVO tungstenProvider = tungstenProviderDao.findByZoneId(zoneId); |
| if (host.getHypervisorType() == Hypervisor.HypervisorType.KVM && tungstenProvider != null |
| && host.getPublicIpAddress().equals(tungstenProvider.getGateway())) { |
| DataCenterVO dataCenterVO = dataCenterDao.findById(zoneId); |
| if (dataCenterVO.isSecurityGroupEnabled()) { |
| List<NetworkVO> networks = networkDao.listByZoneSecurityGroup(zoneId); |
| for (NetworkVO network : networks) { |
| Command setupTungstenVRouterCommand = new SetupTungstenVRouterCommand("delete", |
| TungstenUtils.getSgVgwName(network.getId()), NetUtils.ALL_IP4_CIDRS, NetUtils.ALL_IP4_CIDRS, |
| NetUtils.ALL_IP4_CIDRS); |
| agentMgr.easySend(host.getId(), setupTungstenVRouterCommand); |
| } |
| } else { |
| Command setupTungstenVRouterCommand = new SetupTungstenVRouterCommand("delete", |
| TungstenUtils.getVgwName(zoneId), NetUtils.ALL_IP4_CIDRS, NetUtils.ALL_IP4_CIDRS, |
| NetUtils.ALL_IP4_CIDRS); |
| agentMgr.easySend(host.getId(), setupTungstenVRouterCommand); |
| } |
| } |
| } |
| |
| @Override |
| public void processHostRemoved(final long hostId, final long clusterId) { |
| // Do no thing |
| } |
| |
| @Override |
| public boolean isRecurring() { |
| return false; |
| } |
| |
| @Override |
| public int getTimeout() { |
| return 0; |
| } |
| |
| @Override |
| public boolean processTimeout(final long agentId, final long seq) { |
| return false; |
| } |
| |
| @Override |
| public boolean applyFWRules(final Network network, final List<? extends FirewallRule> rules) |
| throws ResourceUnavailableException { |
| String tungstenProjectFqn; |
| String networkUuid; |
| String policyName; |
| Network publicNetwork = networkModel.getSystemNetworkByZoneAndTrafficType(network.getDataCenterId(), |
| Networks.TrafficType.Public); |
| for (FirewallRule firewallRule : rules) { |
| if (firewallRule.getPurpose() == FirewallRule.Purpose.Firewall) { |
| if (firewallRule.getDestinationCidrList() == null) { |
| return false; |
| } |
| |
| if (firewallRule.getTrafficType() == FirewallRule.TrafficType.Egress) { |
| tungstenProjectFqn = tungstenService.getTungstenProjectFqn(network); |
| networkUuid = network.getUuid(); |
| policyName = TungstenUtils.getRuleNetworkPolicyName(firewallRule.getId()); |
| } else { |
| tungstenProjectFqn = null; |
| networkUuid = publicNetwork.getUuid(); |
| policyName = TungstenUtils.getPublicNetworkPolicyName(firewallRule.getSourceIpAddressId()); |
| } |
| |
| applyAddRule(network, firewallRule, tungstenProjectFqn, networkUuid,policyName); |
| |
| if (firewallRule.getState() == FirewallRule.State.Revoke) { |
| TungstenCommand deleteTungstenNetworkPolicyCommand = new DeleteTungstenNetworkPolicyCommand( |
| policyName, tungstenProjectFqn, networkUuid); |
| tungstenFabricUtils.sendTungstenCommand( |
| deleteTungstenNetworkPolicyCommand, network.getDataCenterId()); |
| } |
| } |
| } |
| |
| return true; |
| } |
| |
| private void applyAddRule(Network network, FirewallRule firewallRule, String tungstenProjectFqn, String networkUuid,String policyName) throws ResourceUnavailableException { |
| if (firewallRule.getState() == FirewallRule.State.Add) { |
| TungstenRule tungstenRule = convertFirewallRule(firewallRule); |
| List<TungstenRule> tungstenRuleList = new ArrayList<>(); |
| tungstenRuleList.add(tungstenRule); |
| |
| TungstenCommand createTungstenNetworkPolicyCommand = new CreateTungstenNetworkPolicyCommand( |
| policyName, tungstenProjectFqn, tungstenRuleList); |
| TungstenAnswer createNetworkPolicyAnswer = tungstenFabricUtils.sendTungstenCommand( |
| createTungstenNetworkPolicyCommand, network.getDataCenterId()); |
| if (!createNetworkPolicyAnswer.getResult()) { |
| throw new CloudRuntimeException("Can not create tungsten fabric network policy"); |
| } |
| |
| TungstenCommand applyTungstenNetworkPolicyCommand = new ApplyTungstenNetworkPolicyCommand( |
| tungstenProjectFqn, policyName, networkUuid, 0, 0); |
| TungstenAnswer applyNetworkPolicyAnswer = tungstenFabricUtils.sendTungstenCommand( |
| applyTungstenNetworkPolicyCommand, network.getDataCenterId()); |
| if (!applyNetworkPolicyAnswer.getResult()) { |
| throw new CloudRuntimeException("Can not apply tungsten fabric network policy"); |
| } |
| } |
| } |
| |
| private TungstenRule convertFirewallRule(FirewallRule firewallRule) throws ResourceUnavailableException { |
| List<String> srcCidrs = firewallRule.getSourceCidrList(); |
| List<String> dstCidrs = firewallRule.getDestinationCidrList(); |
| |
| if (firewallRule.getTrafficType() == FirewallRule.TrafficType.Egress && dstCidrs == null) { |
| throw new ResourceUnavailableException("invalid destination cidr", FirewallRule.class, |
| firewallRule.getId()); |
| } |
| |
| String dstPrefix = dstCidrs.size() == 1 ? NetUtils.getCidr(dstCidrs.get(0)).first() : "0.0.0.0"; |
| int dstPrefixLen = dstCidrs.size() == 1 ? NetUtils.getCidr(dstCidrs.get(0)).second() : 0; |
| int dstPortStart = firewallRule.getSourcePortStart() != null ? firewallRule.getSourcePortStart() : -1; |
| int dstPortEnd = firewallRule.getSourcePortEnd() != null ? firewallRule.getSourcePortEnd() : -1; |
| String tungstenProtocol = |
| firewallRule.getProtocol().equals(NetUtils.ALL_PROTO) ? TungstenUtils.ANY : firewallRule.getProtocol(); |
| |
| if (srcCidrs == null || srcCidrs.size() != 1) { |
| throw new ResourceUnavailableException("invalid source cidr", FirewallRule.class, firewallRule.getId()); |
| } |
| |
| Pair<String, Integer> srcSubnet = NetUtils.getCidr(srcCidrs.get(0)); |
| |
| if (firewallRule.getTrafficType() == FirewallRule.TrafficType.Ingress) { |
| long id = firewallRule.getSourceIpAddressId(); |
| IPAddressVO ipAddressVO = ipAddressDao.findById(id); |
| dstPrefix = ipAddressVO.getAddress().addr(); |
| dstPrefixLen = 32; |
| } |
| |
| return new TungstenRule(firewallRule.getUuid(), TungstenUtils.PASS_ACTION, TungstenUtils.ONE_WAY_DIRECTION, |
| tungstenProtocol, TungstenUtils.ANY, srcSubnet.first(), srcSubnet.second(), -1, -1, TungstenUtils.ANY, |
| dstPrefix, dstPrefixLen, dstPortStart, dstPortEnd); |
| } |
| |
| private TungstenRule getDefaultIngressRule(String ip, String protocol, int startPort, int endPort) { |
| return new TungstenRule(TungstenUtils.PASS_ACTION, TungstenUtils.TWO_WAY_DIRECTION, protocol, TungstenUtils.ANY, |
| TungstenUtils.ALL_IP4_PREFIX, 0, -1, -1, TungstenUtils.ANY, ip, TungstenUtils.MAX_CIDR, startPort, endPort); |
| } |
| |
| private TungstenRule getDefaultEgressRule(String ip, String protocol, int startPort, int endPort) { |
| return new TungstenRule(TungstenUtils.PASS_ACTION, TungstenUtils.ONE_WAY_DIRECTION, protocol, TungstenUtils.ANY, |
| TungstenUtils.ALL_IP4_PREFIX, 0, startPort, endPort, TungstenUtils.ANY, ip, TungstenUtils.MAX_CIDR, -1, -1); |
| } |
| |
| private List<TungstenRule> createDefaultTungstenFirewallRuleList(VirtualMachine.Type vmType, String ip) { |
| List<TungstenRule> tungstenRuleList = new ArrayList<>(); |
| tungstenRuleList.add(getDefaultIngressRule(ip, NetUtils.ICMP_PROTO, -1, -1)); |
| tungstenRuleList.add(getDefaultEgressRule(ip, NetUtils.UDP_PROTO, TungstenUtils.DNS_SERVICE_PORT, |
| TungstenUtils.DNS_SERVICE_PORT)); |
| tungstenRuleList.add(getDefaultEgressRule(ip, NetUtils.UDP_PROTO, TungstenUtils.NTP_SERVICE_PORT, |
| TungstenUtils.NTP_SERVICE_PORT)); |
| if (vmType == VirtualMachine.Type.ConsoleProxy) { |
| tungstenRuleList.add(getDefaultIngressRule(ip, NetUtils.TCP_PROTO, NetUtils.HTTP_PORT, NetUtils.HTTP_PORT)); |
| tungstenRuleList.add(getDefaultIngressRule(ip, NetUtils.TCP_PROTO, TungstenUtils.WEB_SERVICE_PORT, |
| TungstenUtils.WEB_SERVICE_PORT)); |
| tungstenRuleList.add( |
| getDefaultIngressRule(ip, NetUtils.TCP_PROTO, NetUtils.HTTPS_PORT, NetUtils.HTTPS_PORT)); |
| } else { |
| tungstenRuleList.add(getDefaultEgressRule(ip, NetUtils.TCP_PROTO, NetUtils.HTTP_PORT, NetUtils.HTTP_PORT)); |
| } |
| |
| return tungstenRuleList; |
| } |
| |
| @Override |
| public boolean addDnsEntry(Network network, NicProfile nic, VirtualMachineProfile vm, DeployDestination dest, |
| ReservationContext context) |
| throws ConcurrentOperationException { |
| return networkModel.isProviderSupportServiceInNetwork(network.getId(), Network.Service.Dhcp, getProvider()); |
| } |
| |
| @Override |
| public boolean configDnsSupportForSubnet(Network network, NicProfile nic, VirtualMachineProfile vm, |
| DeployDestination dest, ReservationContext context) |
| throws ConcurrentOperationException { |
| return networkModel.isProviderSupportServiceInNetwork(network.getId(), Network.Service.Dhcp, getProvider()); |
| } |
| |
| @Override |
| public boolean removeDnsSupportForSubnet(Network network) { |
| return networkModel.isProviderSupportServiceInNetwork(network.getId(), Network.Service.Dhcp, getProvider()); |
| } |
| |
| @Override |
| public boolean preStateTransitionEvent(final VirtualMachine.State oldState, final VirtualMachine.Event event, |
| final VirtualMachine.State newState, final VirtualMachine vo, final boolean status, final Object opaque) { |
| return true; |
| } |
| |
| @Override |
| public boolean postStateTransitionEvent( |
| final StateMachine2.Transition<VirtualMachine.State, VirtualMachine.Event> transition, final VirtualMachine vo, |
| final boolean status, final Object opaque) { |
| if (!status) { |
| return false; |
| } |
| |
| VirtualMachine.State oldState = transition.getCurrentState(); |
| VirtualMachine.State newState = transition.getToState(); |
| VirtualMachine.Event event = transition.getEvent(); |
| if (VirtualMachine.State.isVmStarted(oldState, event, newState)) { |
| return tungstenService.addTungstenVmSecurityGroup((VMInstanceVO) vo); |
| } else if (VirtualMachine.State.isVmStopped(oldState, event, newState)) { |
| return tungstenService.removeTungstenVmSecurityGroup((VMInstanceVO) vo); |
| } |
| |
| return true; |
| } |
| |
| @Override |
| public boolean prepareMigration(final NicProfile nic, final Network network, final VirtualMachineProfile vm, |
| final DeployDestination dest, final ReservationContext context) { |
| if (vm.getType().isUsedBySystem()) { |
| TungstenAnswer answer = createTungstenVM(network, nic, vm, dest); |
| return answer.getResult(); |
| } else { |
| return true; |
| } |
| } |
| |
| @Override |
| public void rollbackMigration(final NicProfile nic, final Network network, final VirtualMachineProfile vm, |
| final ReservationContext src, final ReservationContext dst) { |
| if (vm.getType().isUsedBySystem()) { |
| Long hostId = vm.getVirtualMachine().getHostId(); |
| HostVO host = hostDao.findById(hostId); |
| TungstenCommand deleteTungstenVRouterPortCommand = new DeleteTungstenVRouterPortCommand( |
| host.getPublicIpAddress(), nic.getUuid()); |
| tungstenFabricUtils.sendTungstenCommand(deleteTungstenVRouterPortCommand, network.getDataCenterId()); |
| } |
| } |
| |
| @Override |
| public void commitMigration(final NicProfile nic, final Network network, final VirtualMachineProfile vm, |
| final ReservationContext src, final ReservationContext dst) { |
| if (vm.getType().isUsedBySystem()) { |
| Long hostId = vm.getVirtualMachine().getLastHostId(); |
| HostVO host = hostDao.findById(hostId); |
| TungstenCommand deleteTungstenVRouterPortCommand = new DeleteTungstenVRouterPortCommand( |
| host.getPublicIpAddress(), nic.getUuid()); |
| tungstenFabricUtils.sendTungstenCommand(deleteTungstenVRouterPortCommand, network.getDataCenterId()); |
| } |
| } |
| |
| private TungstenAnswer createTungstenVM(Network network, NicProfile nic, VirtualMachineProfile vm, |
| DeployDestination dest) { |
| String tungstenProjectFqn = tungstenService.getTungstenProjectFqn(network); |
| VMInstanceVO vmInstanceVO = vmInstanceDao.findById(vm.getId()); |
| Host host = dest.getHost(); |
| if (host == null) { |
| host = hostDao.findById(vmInstanceVO.getHostId()); |
| } |
| |
| TungstenCommand createTungstenVirtualMachineCommand = new CreateTungstenVirtualMachineCommand( |
| tungstenProjectFqn, network.getUuid(), vm.getUuid(), vm.getInstanceName(), nic.getUuid(), nic.getId(), |
| nic.getIPv4Address(), null, nic.getMacAddress(), vm.getType().toString(), |
| network.getTrafficType().toString(), host.getPublicIpAddress(), network.getGateway(), nic.isDefaultNic()); |
| return tungstenFabricUtils.sendTungstenCommand(createTungstenVirtualMachineCommand, network.getDataCenterId()); |
| } |
| |
| private void updateTungstenFabricService(NicProfile nic) { |
| if (nic.getIPv4Address() != null) { |
| nic.setReservationStrategy(Nic.ReservationStrategy.Create); |
| } |
| |
| nic.setBroadcastType(Networks.BroadcastDomainType.TUNGSTEN); |
| nic.setBroadcastUri(Networks.BroadcastDomainType.TUNGSTEN.toUri("tf")); |
| |
| if (nic.getName() == null) { |
| nic.setName(TungstenUtils.DEFAULT_VHOST_INTERFACE); |
| } |
| } |
| } |