cloudstack/server/src/com/cloud/network/JuniperSrxManagerImpl.java

462 lines
21 KiB
Java

/**
* Copyright (C) 2011 Cloud.com, Inc. All rights reserved.
*/
package com.cloud.network;
import java.net.URI;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.ejb.Local;
import javax.naming.ConfigurationException;
import org.apache.log4j.Logger;
import com.cloud.agent.api.Answer;
import com.cloud.agent.api.routing.IpAssocCommand;
import com.cloud.agent.api.routing.NetworkElementCommand;
import com.cloud.agent.api.routing.SetPortForwardingRulesCommand;
import com.cloud.agent.api.routing.SetStaticNatRulesCommand;
import com.cloud.agent.api.to.IpAddressTO;
import com.cloud.agent.api.to.PortForwardingRuleTO;
import com.cloud.agent.api.to.StaticNatRuleTO;
import com.cloud.api.commands.AddExternalFirewallCmd;
import com.cloud.api.commands.DeleteExternalFirewallCmd;
import com.cloud.api.commands.ListExternalFirewallsCmd;
import com.cloud.configuration.ConfigurationManager;
import com.cloud.dc.DataCenter;
import com.cloud.dc.DataCenterVO;
import com.cloud.dc.Vlan;
import com.cloud.dc.VlanVO;
import com.cloud.dc.DataCenter.NetworkType;
import com.cloud.dc.dao.DataCenterDao;
import com.cloud.dc.dao.VlanDao;
import com.cloud.exception.AgentUnavailableException;
import com.cloud.exception.InvalidParameterValueException;
import com.cloud.exception.ResourceUnavailableException;
import com.cloud.host.DetailVO;
import com.cloud.host.Host;
import com.cloud.host.HostVO;
import com.cloud.network.Networks.TrafficType;
import com.cloud.network.dao.FirewallRulesDao;
import com.cloud.network.dao.InlineLoadBalancerNicMapDao;
import com.cloud.network.resource.JuniperSrxResource;
import com.cloud.network.rules.FirewallRule;
import com.cloud.network.rules.FirewallRule.Purpose;
import com.cloud.network.rules.FirewallRuleVO;
import com.cloud.network.rules.PortForwardingRule;
import com.cloud.network.rules.StaticNatRule;
import com.cloud.network.rules.StaticNatRuleImpl;
import com.cloud.offering.NetworkOffering;
import com.cloud.server.api.response.ExternalFirewallResponse;
import com.cloud.user.Account;
import com.cloud.user.AccountManager;
import com.cloud.user.User;
import com.cloud.user.UserContext;
import com.cloud.user.dao.AccountDao;
import com.cloud.user.dao.UserStatisticsDao;
import com.cloud.utils.component.Inject;
import com.cloud.utils.exception.CloudRuntimeException;
import com.cloud.utils.net.NetUtils;
import com.cloud.utils.net.UrlUtil;
import com.cloud.vm.Nic.ReservationStrategy;
import com.cloud.vm.Nic.State;
import com.cloud.vm.NicVO;
import com.cloud.vm.dao.NicDao;
@Local(value = { ExternalFirewallManager.class })
public class JuniperSrxManagerImpl extends ExternalNetworkManagerImpl implements ExternalFirewallManager {
@Inject
NetworkManager _networkMgr;
@Inject
NicDao _nicDao;
@Inject
AccountDao _accountDao;
@Inject
DataCenterDao _dcDao;
@Inject
FirewallRulesDao _firewallRulesDao;
@Inject
UserStatisticsDao _userStatsDao;
@Inject
VlanDao _vlanDao;
@Inject
ConfigurationManager _configMgr;
@Inject
AccountManager _accountMgr;
private static final org.apache.log4j.Logger s_logger = Logger.getLogger(JuniperSrxManagerImpl.class);
@Override
public Host addExternalFirewall(AddExternalFirewallCmd cmd) {
long zoneId = cmd.getZoneId();
DataCenterVO zone = _dcDao.findById(zoneId);
String zoneName;
if (zone == null) {
throw new InvalidParameterValueException("Could not find zone with ID: " + zoneId);
} else {
zoneName = zone.getName();
}
List<HostVO> externalFirewallsInZone = _hostDao.listByTypeDataCenter(Host.Type.ExternalFirewall, zoneId);
if (externalFirewallsInZone.size() != 0) {
throw new InvalidParameterValueException("Already added an external firewall in zone: " + zoneName);
}
URI uri;
try {
uri = new URI(cmd.getUrl());
} catch (Exception e) {
s_logger.debug(e);
throw new InvalidParameterValueException(e.getMessage());
}
String ipAddress = uri.getHost();
String username = cmd.getUsername();
String password = cmd.getPassword();
Map<String, String> params = new HashMap<String, String>();
UrlUtil.parseQueryParameters(uri.getQuery(), true, params);
String publicInterface = params.get("publicinterface");
String usageInterface = params.get("usageinterface");
String privateInterface = params.get("privateinterface");
String publicZone = params.get("publiczone");
String privateZone = params.get("privatezone");
String numRetries = params.get("numretries");
String timeout = params.get("timeout");
if (publicInterface == null) {
throw new InvalidParameterValueException("Please specify a public interface.");
}
if (usageInterface != null) {
if (!usageInterface.contains(".")) {
usageInterface += ".0";
}
}
if (privateInterface != null) {
if (privateInterface.contains(".")) {
throw new InvalidParameterValueException("The private interface name must not have a unit identifier.");
}
} else {
throw new InvalidParameterValueException("Please specify a private interface.");
}
if (publicZone == null) {
publicZone = "untrust";
}
if (privateZone == null) {
privateZone = "trust";
}
if (numRetries == null) {
numRetries = "1";
}
if (timeout == null) {
timeout = "300";
}
JuniperSrxResource resource = new JuniperSrxResource();
String guid = getExternalNetworkResourceGuid(zoneId, ExternalNetworkResourceName.JuniperSrx, ipAddress);
Map hostDetails = new HashMap<String, String>();
hostDetails.put("zoneId", String.valueOf(zoneId));
hostDetails.put("ip", ipAddress);
hostDetails.put("username", username);
hostDetails.put("password", password);
hostDetails.put("publicInterface", publicInterface);
hostDetails.put("privateInterface", privateInterface);
hostDetails.put("publicZone", publicZone);
hostDetails.put("privateZone", privateZone);
hostDetails.put("numRetries", numRetries);
hostDetails.put("timeout", timeout);
hostDetails.put("guid", guid);
hostDetails.put("name", guid);
if (usageInterface != null) {
hostDetails.put("usageInterface", usageInterface);
}
try {
resource.configure(guid, hostDetails);
} catch (ConfigurationException e) {
throw new CloudRuntimeException(e.getMessage());
}
Host externalFirewall = _agentMgr.addHost(zoneId, resource, Host.Type.ExternalFirewall, hostDetails);
if (externalFirewall != null) {
zone.setFirewallProvider(Network.Provider.JuniperSRX.getName());
zone.setUserDataProvider(Network.Provider.DhcpServer.getName());
zone.setVpnProvider(null);
if (zone.getGatewayProvider() == null || !zone.getGatewayProvider().equals(Network.Provider.ExternalGateWay)) {
zone.setGatewayProvider(Network.Provider.JuniperSRX.getName());
}
if (zone.getDnsProvider() == null || !zone.getDnsProvider().equals(Network.Provider.ExternalDhcpServer)) {
zone.setDnsProvider(Network.Provider.DhcpServer.getName());
}
if (zone.getDhcpProvider() == null || !zone.getDhcpProvider().equals(Network.Provider.ExternalDhcpServer)) {
zone.setDhcpProvider(Network.Provider.DhcpServer.getName());
}
if (zone.getLoadBalancerProvider() == null || !zone.getLoadBalancerProvider().equals(Network.Provider.F5BigIp.getName())) {
zone.setLoadBalancerProvider(Network.Provider.None.getName());
}
_dcDao.update(zone.getId(), zone);
return externalFirewall;
} else {
return null;
}
}
@Override
public boolean deleteExternalFirewall(DeleteExternalFirewallCmd cmd) {
long hostId = cmd.getId();
User caller = _accountMgr.getActiveUser(UserContext.current().getCallerUserId());
HostVO externalFirewall = _hostDao.findById(hostId);
if (externalFirewall == null) {
throw new InvalidParameterValueException("Could not find an external firewall with ID: " + hostId);
}
try {
if (_agentMgr.maintain(hostId) && _agentMgr.deleteHost(hostId, false, false, caller)) {
DataCenterVO zone = _dcDao.findById(externalFirewall.getDataCenterId());
zone.setFirewallProvider(Network.Provider.VirtualRouter.getName());
zone.setUserDataProvider(Network.Provider.VirtualRouter.getName());
zone.setVpnProvider(Network.Provider.VirtualRouter.getName());
if (zone.getGatewayProvider() != null && !zone.getGatewayProvider().equals(Network.Provider.ExternalGateWay)) {
zone.setGatewayProvider(Network.Provider.VirtualRouter.getName());
}
if (zone.getDnsProvider() != null && !zone.getDnsProvider().equals(Network.Provider.ExternalDhcpServer)) {
zone.setDnsProvider(Network.Provider.VirtualRouter.getName());
}
if (zone.getDhcpProvider() != null && !zone.getDhcpProvider().equals(Network.Provider.ExternalDhcpServer)) {
zone.setDhcpProvider(Network.Provider.VirtualRouter.getName());
}
if (zone.getLoadBalancerProvider() != null && zone.getLoadBalancerProvider().equals(Network.Provider.None)) {
if (zone.getNetworkType().equals(NetworkType.Advanced)) {
zone.setLoadBalancerProvider(Network.Provider.VirtualRouter.getName());
} else if (zone.getNetworkType().equals(NetworkType.Basic)) {
zone.setLoadBalancerProvider(null);
}
}
return _dcDao.update(zone.getId(), zone);
} else {
return false;
}
} catch (AgentUnavailableException e) {
s_logger.debug(e);
return false;
}
}
@Override
public List<HostVO> listExternalFirewalls(ListExternalFirewallsCmd cmd) {
long zoneId = cmd.getZoneId();
return _hostDao.listByTypeDataCenter(Host.Type.ExternalFirewall, zoneId);
}
@Override
public ExternalFirewallResponse getApiResponse(Host externalFirewall) {
Map<String, String> fwDetails = _detailsDao.findDetails(externalFirewall.getId());
ExternalFirewallResponse response = new ExternalFirewallResponse();
response.setId(externalFirewall.getId());
response.setIpAddress(externalFirewall.getPrivateIpAddress());
response.setUsername(fwDetails.get("username"));
response.setPublicInterface(fwDetails.get("publicInterface"));
response.setUsageInterface(fwDetails.get("usageInterface"));
response.setPrivateInterface(fwDetails.get("privateInterface"));
response.setPublicZone(fwDetails.get("publicZone"));
response.setPrivateZone(fwDetails.get("privateZone"));
response.setNumRetries(fwDetails.get("numRetries"));
response.setTimeout(fwDetails.get("timeout"));
return response;
}
@Override
public boolean manageGuestNetwork(boolean add, Network network, NetworkOffering offering) throws ResourceUnavailableException {
if (network.getTrafficType() != TrafficType.Guest) {
s_logger.trace("JuniperSrxManager can only add/remove guest networks.");
return false;
}
// Find the external firewall in this zone
long zoneId = network.getDataCenterId();
DataCenterVO zone = _dcDao.findById(zoneId);
HostVO externalFirewall = getExternalNetworkAppliance(zoneId, Host.Type.ExternalFirewall);
if (externalFirewall == null) {
return false;
}
Account account = _accountDao.findByIdIncludingRemoved(network.getAccountId());
boolean sharedSourceNat = offering.isSharedSourceNatService();
IPAddressVO sourceNatIp = null;
if (!sharedSourceNat) {
// Get the source NAT IP address for this network
List<IPAddressVO> sourceNatIps = _networkMgr.listPublicIpAddressesInVirtualNetwork(network.getAccountId(), zoneId, true, null);
if (sourceNatIps.size() != 1) {
String errorMsg = "JuniperSrxManager was unable to find the source NAT IP address for account " + account.getAccountName();
s_logger.error(errorMsg);
return true;
} else {
sourceNatIp = sourceNatIps.get(0);
}
}
// Send a command to the external firewall to implement or shutdown the guest network
long guestVlanTag = Long.parseLong(network.getBroadcastUri().getHost());
String guestVlanGateway = network.getGateway();
String guestVlanCidr = network.getCidr();
String sourceNatIpAddress = sourceNatIp.getAddress().addr();
VlanVO publicVlan = _vlanDao.findById(sourceNatIp.getVlanId());
String publicVlanTag = publicVlan.getVlanTag();
// Get network rate
Integer networkRate = _networkMgr.getNetworkRate(network.getId(), null);
IpAddressTO ip = new IpAddressTO(account.getId(), sourceNatIpAddress, add, false, !sharedSourceNat, publicVlanTag, null, null, null, null, networkRate, sourceNatIp.isOneToOneNat());
IpAddressTO[] ips = new IpAddressTO[1];
ips[0] = ip;
IpAssocCommand cmd = new IpAssocCommand(ips);
cmd.setAccessDetail(NetworkElementCommand.GUEST_NETWORK_GATEWAY, guestVlanGateway);
cmd.setAccessDetail(NetworkElementCommand.GUEST_NETWORK_CIDR, guestVlanCidr);
cmd.setAccessDetail(NetworkElementCommand.GUEST_VLAN_TAG, String.valueOf(guestVlanTag));
Answer answer = _agentMgr.easySend(externalFirewall.getId(), cmd);
if (answer == null || !answer.getResult()) {
String action = add ? "implement" : "shutdown";
String answerDetails = (answer != null) ? answer.getDetails() : "answer was null";
String msg = "JuniperSrxManager was unable to " + action + " the guest network on the external firewall in zone " + zone.getName() + " due to " + answerDetails;
s_logger.error(msg);
throw new ResourceUnavailableException(msg, DataCenter.class, zoneId);
}
List<String> reservedIpAddressesForGuestNetwork = _nicDao.listIpAddressInNetwork(network.getId());
if (add && (!reservedIpAddressesForGuestNetwork.contains(network.getGateway()))) {
// Insert a new NIC for this guest network to reserve the gateway address
savePlaceholderNic(network, network.getGateway());
}
// Delete any mappings used for inline external load balancers in this network
List<NicVO> nicsInNetwork = _nicDao.listByNetworkId(network.getId());
for (NicVO nic : nicsInNetwork) {
InlineLoadBalancerNicMapVO mapping = _inlineLoadBalancerNicMapDao.findByNicId(nic.getId());
if (mapping != null) {
_nicDao.expunge(mapping.getNicId());
_inlineLoadBalancerNicMapDao.expunge(mapping.getId());
}
}
String action = add ? "implemented" : "shut down";
s_logger.debug("JuniperSrxManager has " + action + " the guest network for account " + account.getAccountName() + "(id = " + account.getAccountId() + ") with VLAN tag " + guestVlanTag);
return true;
}
public void applyStaticNatRuleForInlineLBRule(DataCenterVO zone, Network network, HostVO externalFirewall, boolean revoked, String publicIp, String privateIp) throws ResourceUnavailableException {
List<StaticNatRuleTO> staticNatRules = new ArrayList<StaticNatRuleTO>();
IPAddressVO ipVO = _ipAddressDao.listByDcIdIpAddress(zone.getId(), publicIp).get(0);
VlanVO vlan = _vlanDao.findById(ipVO.getVlanId());
FirewallRuleVO fwRule = new FirewallRuleVO(null, ipVO.getId(), -1, -1, "any", network.getId(), network.getAccountId(), network.getDomainId(), Purpose.StaticNat, null, null, null, null);
FirewallRule.State state = !revoked ? FirewallRule.State.Add : FirewallRule.State.Revoke;
fwRule.setState(state);
StaticNatRule rule = new StaticNatRuleImpl(fwRule, privateIp);
StaticNatRuleTO ruleTO = new StaticNatRuleTO(rule, vlan.getVlanTag(), publicIp, privateIp);
staticNatRules.add(ruleTO);
applyStaticNatRules(staticNatRules, zone, externalFirewall.getId());
}
@Override
public boolean applyFirewallRules(Network network, List<? extends FirewallRule> rules) throws ResourceUnavailableException {
// Find the external firewall in this zone
long zoneId = network.getDataCenterId();
DataCenterVO zone = _dcDao.findById(zoneId);
HostVO externalFirewall = getExternalNetworkAppliance(zoneId, Host.Type.ExternalFirewall);
if (externalFirewall == null) {
return false;
}
if (network.getState() == Network.State.Allocated) {
s_logger.debug("JuniperSrxManager was asked to apply firewall rules for network with ID " + network.getId() + "; this network is not implemented. Skipping backend commands.");
return true;
}
List<StaticNatRuleTO> staticNatRules = new ArrayList<StaticNatRuleTO>();
List<PortForwardingRuleTO> portForwardingRules = new ArrayList<PortForwardingRuleTO>();
for (FirewallRule rule : rules) {
IpAddress sourceIp = _networkMgr.getIp(rule.getSourceIpAddressId());
Vlan vlan = _vlanDao.findById(sourceIp.getVlanId());
if (rule.getPurpose() == Purpose.StaticNat) {
StaticNatRule staticNatRule = (StaticNatRule) rule;
StaticNatRuleTO ruleTO = new StaticNatRuleTO(staticNatRule, vlan.getVlanTag(), sourceIp.getAddress().addr(), staticNatRule.getDestIpAddress());
staticNatRules.add(ruleTO);
} else if (rule.getPurpose() == Purpose.PortForwarding) {
PortForwardingRuleTO ruleTO = new PortForwardingRuleTO((PortForwardingRule) rule, vlan.getVlanTag(), sourceIp.getAddress().addr());
portForwardingRules.add(ruleTO);
}
}
// Apply static nat rules
applyStaticNatRules(staticNatRules, zone, externalFirewall.getId());
// apply port forwarding rules
applyPortForwardingRules(portForwardingRules, zone, externalFirewall.getId());
return true;
}
protected void applyStaticNatRules(List<StaticNatRuleTO> staticNatRules, DataCenter zone, long externalFirewallId) throws ResourceUnavailableException {
if (!staticNatRules.isEmpty()) {
SetStaticNatRulesCommand cmd = new SetStaticNatRulesCommand(staticNatRules);
Answer answer = _agentMgr.easySend(externalFirewallId, cmd);
if (answer == null || !answer.getResult()) {
String details = (answer != null) ? answer.getDetails() : "details unavailable";
String msg = "JuniperSrxManager was unable to apply static nat rules to the SRX appliance in zone " + zone.getName() + " due to: " + details + ".";
s_logger.error(msg);
throw new ResourceUnavailableException(msg, DataCenter.class, zone.getId());
}
}
}
protected void applyPortForwardingRules(List<PortForwardingRuleTO> portForwardingRules, DataCenter zone, long externalFirewallId) throws ResourceUnavailableException {
if (!portForwardingRules.isEmpty()) {
SetPortForwardingRulesCommand cmd = new SetPortForwardingRulesCommand(portForwardingRules);
Answer answer = _agentMgr.easySend(externalFirewallId, cmd);
if (answer == null || !answer.getResult()) {
String details = (answer != null) ? answer.getDetails() : "details unavailable";
String msg = "JuniperSrxManager was unable to apply port forwarding rules to the SRX appliance in zone " + zone.getName() + " due to: " + details + ".";
s_logger.error(msg);
throw new ResourceUnavailableException(msg, DataCenter.class, zone.getId());
}
}
}
@Override
public boolean applyIps(Network network, List<? extends PublicIpAddress> ipAddresses) throws ResourceUnavailableException {
return true;
}
}