blob: 8ea65f4e729f2438a5b45b7b5107ed3f49ab4775 [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 org.apache.cloudstack.network.opendaylight.agent;
import java.net.MalformedURLException;
import java.net.URL;
import java.security.InvalidParameterException;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Random;
import java.util.UUID;
import javax.naming.ConfigurationException;
import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.LogManager;
import org.apache.cloudstack.network.opendaylight.agent.commands.AddHypervisorCommand;
import org.apache.cloudstack.network.opendaylight.agent.commands.ConfigureNetworkCommand;
import org.apache.cloudstack.network.opendaylight.agent.commands.ConfigurePortCommand;
import org.apache.cloudstack.network.opendaylight.agent.commands.DestroyNetworkCommand;
import org.apache.cloudstack.network.opendaylight.agent.commands.DestroyPortCommand;
import org.apache.cloudstack.network.opendaylight.agent.commands.StartupOpenDaylightControllerCommand;
import org.apache.cloudstack.network.opendaylight.agent.responses.AddHypervisorAnswer;
import org.apache.cloudstack.network.opendaylight.agent.responses.ConfigureNetworkAnswer;
import org.apache.cloudstack.network.opendaylight.agent.responses.ConfigurePortAnswer;
import org.apache.cloudstack.network.opendaylight.agent.responses.DestroyNetworkAnswer;
import org.apache.cloudstack.network.opendaylight.agent.responses.DestroyPortAnswer;
import org.apache.cloudstack.network.opendaylight.api.NeutronRestApiException;
import org.apache.cloudstack.network.opendaylight.api.model.NeutronNetwork;
import org.apache.cloudstack.network.opendaylight.api.model.NeutronNetworkWrapper;
import org.apache.cloudstack.network.opendaylight.api.model.NeutronNetworksList;
import org.apache.cloudstack.network.opendaylight.api.model.NeutronNode;
import org.apache.cloudstack.network.opendaylight.api.model.NeutronNodeWrapper;
import org.apache.cloudstack.network.opendaylight.api.model.NeutronNodesList;
import org.apache.cloudstack.network.opendaylight.api.model.NeutronPort;
import org.apache.cloudstack.network.opendaylight.api.model.NeutronPortWrapper;
import org.apache.cloudstack.network.opendaylight.api.resources.NeutronNetworksNorthboundAction;
import org.apache.cloudstack.network.opendaylight.api.resources.NeutronNodesNorthboundAction;
import org.apache.cloudstack.network.opendaylight.api.resources.NeutronPortsNorthboundAction;
import com.cloud.agent.IAgentControl;
import com.cloud.agent.api.Answer;
import com.cloud.agent.api.Command;
import com.cloud.agent.api.MaintainAnswer;
import com.cloud.agent.api.MaintainCommand;
import com.cloud.agent.api.PingCommand;
import com.cloud.agent.api.ReadyAnswer;
import com.cloud.agent.api.ReadyCommand;
import com.cloud.agent.api.StartupCommand;
import com.cloud.host.Host;
import com.cloud.host.Host.Type;
import com.cloud.resource.ServerResource;
public class OpenDaylightControllerResource implements ServerResource {
protected Logger logger = LogManager.getLogger(getClass());
private Map<String, Object> configuration = new HashMap<String, Object>();
private URL controllerUrl;
private String controllerUsername;
private String controllerPassword;
private int runLevel;
@Override
public String getName() {
if (configuration.containsKey("name"))
return (String)configuration.get("name");
else
return null;
}
@Override
public void setName(String name) {
configuration.put("name", name);
}
@Override
public void setConfigParams(Map<String, Object> params) {
for (Entry<String, Object> entry : params.entrySet()) {
configuration.put(entry.getKey(), entry.getValue());
}
updateConfiguration();
}
@Override
public Map<String, Object> getConfigParams() {
return Collections.unmodifiableMap(configuration);
}
@Override
public int getRunLevel() {
return runLevel;
}
@Override
public void setRunLevel(int level) {
runLevel = level;
}
@Override
public boolean configure(String name, Map<String, Object> params) throws ConfigurationException {
for (Entry<String, Object> entry : params.entrySet()) {
configuration.put(entry.getKey(), entry.getValue());
}
updateConfiguration();
return true;
}
@Override
public boolean start() {
return true;
}
@Override
public boolean stop() {
return true;
}
@Override
public Type getType() {
return Type.L2Networking;
}
@Override
public StartupCommand[] initialize() {
StartupOpenDaylightControllerCommand sc = new StartupOpenDaylightControllerCommand();
sc.setGuid((String)configuration.get("guid"));
sc.setName(getName());
sc.setDataCenter((String)configuration.get("zoneId"));
sc.setPod("");
sc.setPrivateIpAddress("");
sc.setStorageIpAddress("");
sc.setVersion(OpenDaylightControllerResource.class.getPackage().getImplementationVersion());
return new StartupCommand[] {sc};
}
@Override
public PingCommand getCurrentStatus(long id) {
return new PingCommand(Host.Type.L2Networking, id);
}
@Override
public Answer executeRequest(Command cmd) {
if (cmd instanceof ConfigureNetworkCommand) {
return executeRequest((ConfigureNetworkCommand)cmd);
} else if (cmd instanceof DestroyNetworkCommand) {
return executeRequest((DestroyNetworkCommand)cmd);
} else if (cmd instanceof ConfigurePortCommand) {
return executeRequest((ConfigurePortCommand)cmd);
} else if (cmd instanceof DestroyPortCommand) {
return executeRequest((DestroyPortCommand)cmd);
} else if (cmd instanceof AddHypervisorCommand) {
return executeRequest((AddHypervisorCommand)cmd);
} else if (cmd instanceof ReadyCommand) {
return executeRequest((ReadyCommand)cmd);
} else if (cmd instanceof MaintainCommand) {
return executeRequest((MaintainCommand)cmd);
} else {
return Answer.createUnsupportedCommandAnswer(cmd);
}
}
@Override
public void disconnected() {
logger.warn("OpenDaylightControllerResource is disconnected from the controller at " + controllerUrl);
}
@Override
public IAgentControl getAgentControl() {
// TODO Auto-generated method stub
return null;
}
@Override
public void setAgentControl(IAgentControl agentControl) {
// TODO Auto-generated method stub
}
private Answer executeRequest(final ReadyCommand cmd) {
return new ReadyAnswer(cmd);
}
private Answer executeRequest(final MaintainCommand cmd) {
return new MaintainAnswer(cmd);
}
private Answer executeRequest(ConfigureNetworkCommand cmd) {
NeutronNetworksNorthboundAction configureNetwork = new NeutronNetworksNorthboundAction(controllerUrl, controllerUsername, controllerPassword);
// Find free gre key
int gre_key = -1;
Random keyGenerator = new Random(System.currentTimeMillis());
try {
NeutronNetworksList<NeutronNetwork> networks = configureNetwork.listAllNetworks();
while (true) {
int i = keyGenerator.nextInt();
for (NeutronNetwork network : networks.getNetworks()) {
if (network.getSegmentationId() == i) {
continue;
}
}
gre_key = i;
break;
}
} catch (NeutronRestApiException e) {
logger.error("Failed to list existing networks on the ODL Controller", e);
return new ConfigureNetworkAnswer(cmd, e);
}
NeutronNetwork newNetwork = new NeutronNetwork();
// Configuration from the command
newNetwork.setName(cmd.getName());
newNetwork.setTenantId(cmd.getTenantId());
// Static configuration
newNetwork.setNetworkType("gre");
newNetwork.setShared(false);
newNetwork.setSegmentationId(gre_key);
newNetwork.setId(UUID.randomUUID());
NeutronNetworkWrapper wrapper = new NeutronNetworkWrapper();
wrapper.setNetwork(newNetwork);
try {
wrapper = configureNetwork.createNeutronNetwork(wrapper);
} catch (NeutronRestApiException e) {
logger.error("createNeutronNetwork failed", e);
return new ConfigureNetworkAnswer(cmd, e);
}
return new ConfigureNetworkAnswer(cmd, true, null, wrapper.getNetwork().getId().toString());
}
private Answer executeRequest(DestroyNetworkCommand cmd) {
NeutronNetworksNorthboundAction configureNetwork = new NeutronNetworksNorthboundAction(controllerUrl, controllerUsername, controllerPassword);
try {
configureNetwork.deleteNeutronNetwork(cmd.getNetworkUuid());
} catch (NeutronRestApiException e) {
logger.error("deleteNeutronNetwork failed", e);
return new DestroyNetworkAnswer(cmd, e);
}
return new DestroyNetworkAnswer(cmd, true, "Network " + cmd.getNetworkUuid() + " deleted");
}
private Answer executeRequest(ConfigurePortCommand cmd) {
NeutronPortsNorthboundAction configurePort = new NeutronPortsNorthboundAction(controllerUrl, controllerUsername, controllerPassword);
NeutronPort newPort = new NeutronPort();
// Configuration from the command
newPort.setId(cmd.getPortId());
newPort.setTenantId(cmd.getTennantId());
newPort.setAdminStateUp(true);
newPort.setName(cmd.getPortId().toString());
newPort.setNetworkId(cmd.getNetworkId());
newPort.setMacAddress(cmd.getMacAddress());
newPort.setDeviceId(UUID.randomUUID());
// Static valus
newPort.setStatus("ACTIVE");
newPort.setFixedIps(Collections.<String> emptyList());
NeutronPortWrapper portWrapper = new NeutronPortWrapper();
portWrapper.setPort(newPort);
try {
portWrapper = configurePort.createNeutronPort(portWrapper);
} catch (NeutronRestApiException e) {
logger.error("createPortCommand failed", e);
return new ConfigurePortAnswer(cmd, e);
}
return new ConfigurePortAnswer(cmd, true, "Port " + portWrapper.getPort().getId().toString() + " created");
}
private Answer executeRequest(DestroyPortCommand cmd) {
NeutronPortsNorthboundAction configurePort = new NeutronPortsNorthboundAction(controllerUrl, controllerUsername, controllerPassword);
try {
configurePort.deleteNeutronPort(cmd.getPortId().toString());
} catch (NeutronRestApiException e) {
logger.error("deleteNeutronPort failed", e);
return new DestroyPortAnswer(cmd, e);
}
return new DestroyPortAnswer(cmd, true, "Port " + cmd.getPortId().toString() + " deleted");
}
private Answer executeRequest(AddHypervisorCommand cmd) {
NeutronNodesNorthboundAction nodeActions = new NeutronNodesNorthboundAction(controllerUrl, controllerUsername, controllerPassword);
try {
NeutronNodesList<NeutronNodeWrapper> nodes = nodeActions.listAllNodes();
if (nodes.getNodes() != null) {
for (NeutronNodeWrapper nodeWrapper : nodes.getNodes()) {
NeutronNode node = nodeWrapper.getNode();
if (node.getId().equals(cmd.getHostId())) {
return new AddHypervisorAnswer(cmd, true, "Hypervisor already connected");
}
}
}
// Not found in the existing node list, add it
nodeActions.updateNeutronNodeV2("OVS", cmd.getHostId(), cmd.getIpAddress(), 6640);
} catch (NeutronRestApiException e) {
logger.error("Call to OpenDaylight failed", e);
return new AddHypervisorAnswer(cmd, e);
}
return new AddHypervisorAnswer(cmd, true, "Hypervisor " + cmd.getHostId() + " added");
}
private void updateConfiguration() {
if (!configuration.containsKey("url") || !configuration.containsKey("username") || !configuration.containsKey("password"))
throw new InvalidParameterException("OpenDaylightControllerResource needs a url, username and password.");
try {
controllerUrl = new URL((String)configuration.get("url"));
} catch (MalformedURLException e) {
throw new InvalidParameterException("OpenDaylightControllerResource found an invalid controller url");
}
controllerUsername = (String)configuration.get("username");
controllerPassword = (String)configuration.get("password");
}
}