blob: c2841f18c1cb06a7cbe461f1ca4543c891dd322d [file] [log] [blame]
//
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
//
package com.cloud.network.resource;
import java.security.KeyManagementException;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.util.Map;
import javax.naming.ConfigurationException;
import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.LogManager;
import com.cloud.agent.IAgentControl;
import com.cloud.agent.api.Answer;
import com.cloud.agent.api.Command;
import com.cloud.agent.api.PingCommand;
import com.cloud.agent.api.StartupCommand;
import com.cloud.agent.api.StartupNiciraNvpCommand;
import com.cloud.host.Host;
import com.cloud.host.Host.Type;
import com.cloud.network.nicira.ControlClusterStatus;
import com.cloud.network.nicira.ControlClusterStatus.ClusterRoleConfig;
import com.cloud.network.nicira.DestinationNatRule;
import com.cloud.network.nicira.Match;
import com.cloud.network.nicira.NatRule;
import com.cloud.network.nicira.NiciraNvpApi;
import com.cloud.network.nicira.NiciraNvpApiException;
import com.cloud.network.nicira.SourceNatRule;
import com.cloud.network.utils.CommandRetryUtility;
import com.cloud.resource.ServerResource;
import com.cloud.utils.rest.CloudstackRESTException;
import com.cloud.utils.rest.HttpClientHelper;
import com.cloud.utils.nicira.nvp.plugin.NiciraNvpApiVersion;
public class NiciraNvpResource implements ServerResource {
protected Logger logger = LogManager.getLogger(getClass());
public static final int NAME_MAX_LEN = 40;
public static final int NUM_RETRIES = 2;
private static final int MAX_REDIRECTS = 5;
private String name;
private String guid;
private String zoneId;
private NiciraNvpApi niciraNvpApi;
private NiciraNvpUtilities niciraNvpUtilities;
private CommandRetryUtility retryUtility;
protected NiciraNvpApi createNiciraNvpApi(final String host, final String username, final String password) throws CloudstackRESTException {
try {
return NiciraNvpApi.create().host(host).username(username).password(password).httpClient(HttpClientHelper.createHttpClient(MAX_REDIRECTS)).build();
} catch (final KeyManagementException e) {
throw new CloudstackRESTException("Could not create HTTP client", e);
} catch (final NoSuchAlgorithmException e) {
throw new CloudstackRESTException("Could not create HTTP client", e);
} catch (final KeyStoreException e) {
throw new CloudstackRESTException("Could not create HTTP client", e);
}
}
@Override
public boolean configure(final String ignoredName, final Map<String, Object> params) throws ConfigurationException {
name = (String) params.get("name");
if (name == null) {
throw new ConfigurationException("Unable to find name");
}
guid = (String) params.get("guid");
if (guid == null) {
throw new ConfigurationException("Unable to find the guid");
}
zoneId = (String) params.get("zoneId");
if (zoneId == null) {
throw new ConfigurationException("Unable to find zone");
}
final String ip = (String) params.get("ip");
if (ip == null) {
throw new ConfigurationException("Unable to find IP");
}
final String adminuser = (String) params.get("adminuser");
if (adminuser == null) {
throw new ConfigurationException("Unable to find admin username");
}
final String adminpass = (String) params.get("adminpass");
if (adminpass == null) {
throw new ConfigurationException("Unable to find admin password");
}
niciraNvpUtilities = NiciraNvpUtilities.getInstance();
retryUtility = CommandRetryUtility.getInstance();
retryUtility.setServerResource(this);
try {
niciraNvpApi = createNiciraNvpApi(ip, adminuser, adminpass);
} catch (final CloudstackRESTException e) {
throw new ConfigurationException("Could not create a Nicira Nvp API client: " + e.getMessage());
}
return true;
}
public NiciraNvpApi getNiciraNvpApi() {
return niciraNvpApi;
}
public NiciraNvpUtilities getNiciraNvpUtilities() {
return niciraNvpUtilities;
}
public CommandRetryUtility getRetryUtility() {
return retryUtility;
}
@Override
public boolean start() {
return true;
}
@Override
public boolean stop() {
return true;
}
@Override
public String getName() {
return name;
}
@Override
public Type getType() {
// Think up a better name for this Type?
return Host.Type.L2Networking;
}
@Override
public StartupCommand[] initialize() {
final StartupNiciraNvpCommand sc = new StartupNiciraNvpCommand();
sc.setGuid(guid);
sc.setName(name);
sc.setDataCenter(zoneId);
sc.setPod("");
sc.setPrivateIpAddress("");
sc.setStorageIpAddress("");
sc.setVersion(NiciraNvpResource.class.getPackage().getImplementationVersion());
return new StartupCommand[] { sc };
}
@Override
public PingCommand getCurrentStatus(final long id) {
try {
final ControlClusterStatus ccs = niciraNvpApi.getControlClusterStatus();
getApiProviderMajorityVersion(ccs);
if (!"stable".equals(ccs.getClusterStatus())) {
logger.error("ControlCluster state is not stable: " + ccs.getClusterStatus());
return null;
}
} catch (final NiciraNvpApiException e) {
logger.error("getControlClusterStatus failed", e);
return null;
}
return new PingCommand(Host.Type.L2Networking, id);
}
private void getApiProviderMajorityVersion(ControlClusterStatus ccs) {
ClusterRoleConfig[] configuredRoles = ccs.getConfiguredRoles();
if (configuredRoles != null){
String apiProviderMajorityVersion = searchApiProvider(configuredRoles);
NiciraNvpApiVersion.setNiciraApiVersion(apiProviderMajorityVersion);
NiciraNvpApiVersion.logNiciraApiVersion();
}
}
private String searchApiProvider(ClusterRoleConfig[] configuredRoles) {
for (int i = 0; i < configuredRoles.length; i++) {
if (configuredRoles[i].getRole() != null && configuredRoles[i].getRole().equals("api_provider")){
return configuredRoles[i].getMajorityVersion();
}
}
return null;
}
@Override
public Answer executeRequest(final Command cmd) {
final NiciraNvpRequestWrapper wrapper = NiciraNvpRequestWrapper.getInstance();
try {
return wrapper.execute(cmd, this);
} catch (final Exception e) {
logger.debug("Received unsupported command " + cmd.toString());
return Answer.createUnsupportedCommandAnswer(cmd);
}
}
@Override
public void disconnected() {
}
@Override
public IAgentControl getAgentControl() {
return null;
}
@Override
public void setAgentControl(final IAgentControl agentControl) {
}
public String natRuleToString(final NatRule rule) {
final StringBuilder natRuleStr = new StringBuilder();
natRuleStr.append("Rule ");
natRuleStr.append(rule.getUuid());
natRuleStr.append(" (");
natRuleStr.append(rule.getType());
natRuleStr.append(") :");
final Match m = rule.getMatch();
natRuleStr.append("match (");
natRuleStr.append(m.getProtocol());
natRuleStr.append(" ");
natRuleStr.append(m.getSourceIpAddresses());
natRuleStr.append(" [");
natRuleStr.append(m.getSourcePort());
natRuleStr.append(" ] -> ");
natRuleStr.append(m.getDestinationIpAddresses());
natRuleStr.append(" [");
natRuleStr.append(m.getDestinationPort());
natRuleStr.append(" ]) -->");
if ("SourceNatRule".equals(rule.getType())) {
natRuleStr.append(((SourceNatRule) rule).getToSourceIpAddressMin());
natRuleStr.append("-");
natRuleStr.append(((SourceNatRule) rule).getToSourceIpAddressMax());
natRuleStr.append(" [");
natRuleStr.append(((SourceNatRule) rule).getToSourcePort());
natRuleStr.append(" ])");
} else {
natRuleStr.append(((DestinationNatRule) rule).getToDestinationIpAddress());
natRuleStr.append(" [");
natRuleStr.append(((DestinationNatRule) rule).getToDestinationPort());
natRuleStr.append(" ])");
}
return natRuleStr.toString();
}
public String truncate(final String string, final int length) {
if (string.length() <= length) {
return string;
} else {
return string.substring(0, length);
}
}
public NatRule[] generateStaticNatRulePair(final String insideIp, final String outsideIp) {
final NatRule[] rulepair = new NatRule[2];
rulepair[0] = new DestinationNatRule();
rulepair[0].setType("DestinationNatRule");
rulepair[0].setOrder(100);
rulepair[1] = new SourceNatRule();
rulepair[1].setType("SourceNatRule");
rulepair[1].setOrder(100);
Match m = new Match();
m.setDestinationIpAddresses(outsideIp);
rulepair[0].setMatch(m);
((DestinationNatRule) rulepair[0]).setToDestinationIpAddress(insideIp);
// create matching snat rule
m = new Match();
m.setSourceIpAddresses(insideIp);
rulepair[1].setMatch(m);
((SourceNatRule) rulepair[1]).setToSourceIpAddressMin(outsideIp);
((SourceNatRule) rulepair[1]).setToSourceIpAddressMax(outsideIp);
return rulepair;
}
public NatRule[] generatePortForwardingRulePair(final String insideIp, final int[] insidePorts, final String outsideIp, final int[] outsidePorts,
final String protocol) {
// Start with a basic static nat rule, then add port and protocol details
final NatRule[] rulepair = generateStaticNatRulePair(insideIp, outsideIp);
((DestinationNatRule) rulepair[0]).setToDestinationPort(insidePorts[0]);
rulepair[0].getMatch().setDestinationPort(outsidePorts[0]);
rulepair[0].setOrder(50);
rulepair[0].getMatch().setEthertype("IPv4");
if ("tcp".equals(protocol)) {
rulepair[0].getMatch().setProtocol(6);
} else if ("udp".equals(protocol)) {
rulepair[0].getMatch().setProtocol(17);
}
((SourceNatRule) rulepair[1]).setToSourcePort(outsidePorts[0]);
rulepair[1].getMatch().setSourcePort(insidePorts[0]);
rulepair[1].setOrder(50);
rulepair[1].getMatch().setEthertype("IPv4");
if ("tcp".equals(protocol)) {
rulepair[1].getMatch().setProtocol(6);
} else if ("udp".equals(protocol)) {
rulepair[1].getMatch().setProtocol(17);
}
return rulepair;
}
@Override
public void setName(final String name) {
// TODO Auto-generated method stub
}
@Override
public void setConfigParams(final Map<String, Object> params) {
// TODO Auto-generated method stub
}
@Override
public Map<String, Object> getConfigParams() {
// TODO Auto-generated method stub
return null;
}
@Override
public int getRunLevel() {
// TODO Auto-generated method stub
return 0;
}
@Override
public void setRunLevel(final int level) {
// TODO Auto-generated method stub
}
}