blob: de33b8ae7b4453bdefdd145203a590c136f753f7 [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.util.ArrayList;
import java.util.List;
import java.util.Map;
import javax.naming.ConfigurationException;
import org.apache.log4j.Logger;
import com.cloud.agent.IAgentControl;
import com.cloud.agent.api.Answer;
import com.cloud.agent.api.UpdateBcfRouterCommand;
import com.cloud.agent.api.BcfAnswer;
import com.cloud.agent.api.CacheBcfTopologyCommand;
import com.cloud.agent.api.Command;
import com.cloud.agent.api.CreateBcfRouterCommand;
import com.cloud.agent.api.CreateBcfRouterInterfaceCommand;
import com.cloud.agent.api.CreateBcfSegmentCommand;
import com.cloud.agent.api.CreateBcfAttachmentCommand;
import com.cloud.agent.api.CreateBcfStaticNatCommand;
import com.cloud.agent.api.DeleteBcfSegmentCommand;
import com.cloud.agent.api.DeleteBcfAttachmentCommand;
import com.cloud.agent.api.DeleteBcfStaticNatCommand;
import com.cloud.agent.api.GetControllerDataAnswer;
import com.cloud.agent.api.GetControllerDataCommand;
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.StartupBigSwitchBcfCommand;
import com.cloud.agent.api.StartupCommand;
import com.cloud.agent.api.SyncBcfTopologyCommand;
import com.cloud.agent.api.UpdateBcfAttachmentCommand;
import com.cloud.host.Host;
import com.cloud.host.Host.Type;
import com.cloud.network.bigswitch.AclData;
import com.cloud.network.bigswitch.BigSwitchBcfApi;
import com.cloud.network.bigswitch.BigSwitchBcfApiException;
import com.cloud.network.bigswitch.Capabilities;
import com.cloud.network.bigswitch.ControlClusterStatus;
import com.cloud.network.bigswitch.ControllerData;
import com.cloud.network.bigswitch.FloatingIpData;
import com.cloud.network.bigswitch.NetworkData;
import com.cloud.network.bigswitch.AttachmentData;
import com.cloud.network.bigswitch.RouterData;
import com.cloud.network.bigswitch.RouterInterfaceData;
import com.cloud.network.bigswitch.TopologyData;
import com.cloud.resource.ServerResource;
import com.cloud.utils.component.ManagerBase;
public class BigSwitchBcfResource extends ManagerBase implements ServerResource {
private static final Logger s_logger = Logger.getLogger(BigSwitchBcfResource.class);
private String _name;
private String _guid;
private String _zoneId;
private int _numRetries;
private BigSwitchBcfApi _bigswitchBcfApi;
private TopologyData _latestTopology = null;
private boolean initTopologySyncDone = false;
protected BigSwitchBcfApi createBigSwitchBcfApi() {
return new BigSwitchBcfApi();
}
@Override
public boolean configure(String name, 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");
}
_numRetries = 2;
String hostname = (String)params.get("hostname");
if (hostname == null) {
throw new ConfigurationException("Missing host name from params: " + params);
}
String username = (String) params.get("username");
if (username == null) {
throw new ConfigurationException("Missing user name from params: " + params);
}
String password = (String) params.get("password");
if (password == null) {
throw new ConfigurationException("Missing password from params: " + params);
}
Boolean nat = Boolean.parseBoolean((String) params.get("nat"));
if (nat == null) {
throw new ConfigurationException("Missing password from params: " + params);
}
_bigswitchBcfApi = createBigSwitchBcfApi();
_bigswitchBcfApi.setControllerAddress(hostname);
_bigswitchBcfApi.setControllerUsername(username);
_bigswitchBcfApi.setControllerPassword(password);
_bigswitchBcfApi.setControllerNat(nat);
_bigswitchBcfApi.setZoneId(_zoneId);
return true;
}
@Override
public boolean start() {
return true;
}
@Override
public boolean stop() {
return true;
}
@Override
public String getName() {
return _name;
}
@Override
public Type getType() {
return Host.Type.L2Networking;
}
@Override
public StartupCommand[] initialize() {
StartupBigSwitchBcfCommand sc = new StartupBigSwitchBcfCommand();
sc.setGuid(_guid);
sc.setName(_name);
sc.setDataCenter(_zoneId);
sc.setPod("");
sc.setPrivateIpAddress("");
sc.setStorageIpAddress("");
sc.setVersion("");
return new StartupCommand[] {sc};
}
@Override
public PingCommand getCurrentStatus(long id) {
if(!initTopologySyncDone && _latestTopology != null){
initTopologySyncDone = true;
if(_bigswitchBcfApi.isNatEnabled()){
try{
executeRequest(new SyncBcfTopologyCommand(true, true), _numRetries);
} catch(Exception e){
s_logger.error("BigSwitch BCF sync error", e);
}
} else {
try{
executeRequest(new SyncBcfTopologyCommand(true, false), _numRetries);
} catch (Exception e){
s_logger.error("BigSwitch BCF sync error", e);
}
}
}
try {
ControlClusterStatus ccs = _bigswitchBcfApi.getControlClusterStatus();
if (!ccs.getStatus()) {
s_logger.error("ControlCluster state is not ready: " + ccs.getStatus());
return null;
}
if (ccs.isTopologySyncRequested()) {
if(_latestTopology != null) {
if(_bigswitchBcfApi.isNatEnabled()){
executeRequest(new SyncBcfTopologyCommand(true, true), _numRetries);
} else {
executeRequest(new SyncBcfTopologyCommand(true, false), _numRetries);
}
} else {
s_logger.debug("topology sync needed but no topology history");
}
}
} catch (BigSwitchBcfApiException e) {
s_logger.error("getControlClusterStatus failed", e);
return null;
}
try {
Capabilities cap = _bigswitchBcfApi.getCapabilities();
// TODO: update controller status display, enable/disable service accordingly
if (cap.isTopologySyncRequested()) {
if(_latestTopology != null) {
if(_bigswitchBcfApi.isNatEnabled()){
executeRequest(new SyncBcfTopologyCommand(true, true), _numRetries);
} else {
executeRequest(new SyncBcfTopologyCommand(true, false), _numRetries);
}
}
}
} catch (BigSwitchBcfApiException e) {
s_logger.error("getCapabilities failed", e);
}
return new PingCommand(Host.Type.L2Networking, id);
}
@Override
public Answer executeRequest(Command cmd) {
return executeRequest(cmd, _numRetries);
}
public Answer executeRequest(Command cmd, int numRetries) {
if (cmd instanceof ReadyCommand) {
return executeRequest((ReadyCommand)cmd);
} else if (cmd instanceof MaintainCommand) {
return executeRequest((MaintainCommand)cmd);
} else if (cmd instanceof CreateBcfSegmentCommand) {
_latestTopology = ((CreateBcfSegmentCommand) cmd).getTopology();
return executeRequest((CreateBcfSegmentCommand)cmd, numRetries);
} else if (cmd instanceof DeleteBcfSegmentCommand) {
_latestTopology = ((DeleteBcfSegmentCommand) cmd).getTopology();
return executeRequest((DeleteBcfSegmentCommand)cmd, numRetries);
} else if (cmd instanceof CreateBcfAttachmentCommand) {
_latestTopology = ((CreateBcfAttachmentCommand) cmd).getTopology();
return executeRequest((CreateBcfAttachmentCommand)cmd, numRetries);
} else if (cmd instanceof DeleteBcfAttachmentCommand) {
_latestTopology = ((DeleteBcfAttachmentCommand) cmd).getTopology();
return executeRequest((DeleteBcfAttachmentCommand)cmd, numRetries);
} else if (cmd instanceof UpdateBcfAttachmentCommand) {
_latestTopology = ((UpdateBcfAttachmentCommand) cmd).getTopology();
return executeRequest((UpdateBcfAttachmentCommand)cmd, numRetries);
} else if (cmd instanceof CreateBcfRouterCommand) {
_latestTopology = ((CreateBcfRouterCommand) cmd).getTopology();
return executeRequest((CreateBcfRouterCommand)cmd, numRetries);
} else if (cmd instanceof CreateBcfRouterInterfaceCommand) {
_latestTopology = ((CreateBcfRouterInterfaceCommand) cmd).getTopology();
return executeRequest((CreateBcfRouterInterfaceCommand)cmd, numRetries);
} else if (cmd instanceof CreateBcfStaticNatCommand) {
_latestTopology = ((CreateBcfStaticNatCommand) cmd).getTopology();
return executeRequest((CreateBcfStaticNatCommand)cmd, numRetries);
} else if (cmd instanceof DeleteBcfStaticNatCommand) {
_latestTopology = ((DeleteBcfStaticNatCommand) cmd).getTopology();
return executeRequest((DeleteBcfStaticNatCommand)cmd, numRetries);
} else if (cmd instanceof UpdateBcfRouterCommand) {
_latestTopology = ((UpdateBcfRouterCommand) cmd).getTopology();
return executeRequest((UpdateBcfRouterCommand)cmd, numRetries);
} else if (cmd instanceof SyncBcfTopologyCommand) {
return executeRequest((SyncBcfTopologyCommand)cmd, numRetries);
} else if (cmd instanceof CacheBcfTopologyCommand) {
return executeRequest((CacheBcfTopologyCommand)cmd, numRetries);
} else if (cmd instanceof GetControllerDataCommand) {
return executeRequest((GetControllerDataCommand)cmd, numRetries);
}
s_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(IAgentControl agentControl) {
}
public void setTopology(TopologyData topology){
_latestTopology = topology;
}
public TopologyData getTopology(){
return _latestTopology;
}
private Answer executeRequest(CreateBcfSegmentCommand cmd, int numRetries) {
NetworkData network = new NetworkData();
network.getNetwork().setTenantId(cmd.getTenantId());
network.getNetwork().setTenantName(cmd.getTenantName());
network.getNetwork().setId(cmd.getNetworkId());
network.getNetwork().setName(truncate("segment-cloudstack-" + cmd.getNetworkName(), 64));
network.getNetwork().setVlan(cmd.getVlan());
try {
String hash =_bigswitchBcfApi.createNetwork(network);
return new BcfAnswer(cmd, true, "Segment " + network.getNetwork().getId() + " created", hash);
} catch (BigSwitchBcfApiException e) {
if (e.is_topologySyncRequested()) {
cmd.setTopologySyncRequested(true);
return new BcfAnswer(cmd, true, "Segment " + network.getNetwork().getId() + " created; topology sync required.");
} else {
if (numRetries > 0) {
return retry(cmd, --numRetries);
} else {
return new BcfAnswer(cmd, e);
}
}
}
}
private Answer executeRequest(DeleteBcfSegmentCommand cmd, int numRetries) {
try {
String hash = _bigswitchBcfApi.deleteNetwork(cmd.getTenantUuid(), cmd.getNetworkUuid());
return new BcfAnswer(cmd, true, "Segment " + cmd.getNetworkUuid() + " deleted", hash);
} catch (BigSwitchBcfApiException e) {
if (e.is_topologySyncRequested()) {
cmd.setTopologySyncRequested(true);
return new BcfAnswer(cmd, true, "Segment " + cmd.getNetworkUuid() + " deleted; topology sync required.");
} else {
if (numRetries > 0) {
return retry(cmd, --numRetries);
} else {
return new BcfAnswer(cmd, e);
}
}
}
}
private Answer executeRequest(CreateBcfAttachmentCommand cmd, int numRetries) {
AttachmentData attachment = new AttachmentData();
attachment.getAttachment().setId(cmd.getNicId());
attachment.getAttachment().setHostId(cmd.getPortId());
attachment.getAttachment().setTenantName(cmd.getTenantName());
attachment.getAttachment().setVlan(cmd.getVlan());
attachment.getAttachment().addIpv4(cmd.getIpv4());
attachment.getAttachment().setMac(cmd.getMac());
try {
String hash = _bigswitchBcfApi.createAttachment(cmd.getTenantId(), cmd.getNetworkId(), attachment);
return new BcfAnswer(cmd, true, "network attachment " + cmd.getPortId() + " created", hash);
} catch (BigSwitchBcfApiException e) {
if (e.is_topologySyncRequested()) {
cmd.setTopologySyncRequested(true);
return new BcfAnswer(cmd, true, "network attachment " + cmd.getPortId() + " created; topology sync required.");
} else {
if (numRetries > 0) {
return retry(cmd, --numRetries);
} else {
return new BcfAnswer(cmd, e);
}
}
}
}
private Answer executeRequest(DeleteBcfAttachmentCommand cmd, int numRetries) {
String nicName = cmd.getAttachmentId();
try {
String hash = _bigswitchBcfApi.deleteAttachment(cmd.getTenantId(), cmd.getNetworkId(), nicName);
return new BcfAnswer(cmd, true, "network attachment " + nicName + " deleted", hash);
} catch (BigSwitchBcfApiException e) {
if (e.is_topologySyncRequested()) {
cmd.setTopologySyncRequested(true);
return new BcfAnswer(cmd, true, "network attachment " + nicName + " deleted; topology sync required.");
} else {
if (numRetries > 0) {
return retry(cmd, --numRetries);
} else {
return new BcfAnswer(cmd, e);
}
}
}
}
private Answer executeRequest(UpdateBcfAttachmentCommand cmd, int numRetries) {
AttachmentData attachment = new AttachmentData();
attachment.getAttachment().setId(cmd.getAttachmentId());
attachment.getAttachment().setTenantName(cmd.getTenantId());
try {
String hash = _bigswitchBcfApi.modifyAttachment(cmd.getTenantId(), cmd.getNetworkId(), attachment);
return new BcfAnswer(cmd, true, "Network attachment " + cmd.getAttachmentId() + " updated", hash);
} catch (BigSwitchBcfApiException e) {
if (e.is_topologySyncRequested()) {
cmd.setTopologySyncRequested(true);
return new BcfAnswer(cmd, true, "Network attachment " + cmd.getAttachmentId() + " updated; topology sync required.");
} else {
if (numRetries > 0) {
return retry(cmd, --numRetries);
} else {
return new BcfAnswer(cmd, e);
}
}
}
}
private Answer executeRequest(CreateBcfStaticNatCommand cmd, int numRetries) {
FloatingIpData fip = new FloatingIpData();
fip.setTenantId(cmd.getTenantId());
fip.setNetworkId(cmd.getNetworkId());
fip.setFixedIp(cmd.getPrivateIp());
fip.setFloatingIpAndId(cmd.getPublicIp());
fip.setMac(cmd.getMac());
try {
String hash = _bigswitchBcfApi.createFloatingIp(cmd.getTenantId(), fip);
return new BcfAnswer(cmd, true, "floating ip " + cmd.getPublicIp() + ":" +
cmd.getPrivateIp() + " created", hash);
} catch (BigSwitchBcfApiException e) {
if (e.is_topologySyncRequested()) {
cmd.setTopologySyncRequested(true);
return new BcfAnswer(cmd, true, "floating ip " + cmd.getPublicIp() + ":" +
cmd.getPrivateIp() + " created; topology sync required.");
} else {
if (numRetries > 0) {
return retry(cmd, --numRetries);
} else {
return new BcfAnswer(cmd, e);
}
}
}
}
private Answer executeRequest(DeleteBcfStaticNatCommand cmd, int numRetries) {
try {
String hash = _bigswitchBcfApi.deleteFloatingIp(cmd.getTenantId(), cmd.getFloatingIpId());
return new BcfAnswer(cmd, true, "floating ip " + cmd.getPublicIp() + " deleted", hash);
} catch (BigSwitchBcfApiException e) {
if (e.is_topologySyncRequested()) {
cmd.setTopologySyncRequested(true);
return new BcfAnswer(cmd, true, "floating ip " + cmd.getPublicIp() + " deleted; topology sync required.");
} else {
if (numRetries > 0) {
return retry(cmd, --numRetries);
} else {
return new BcfAnswer(cmd, e);
}
}
}
}
private Answer executeRequest(CreateBcfRouterCommand cmd, int numRetries) {
RouterData router = new RouterData(cmd.getTenantId());
try {
String hash;
hash = _bigswitchBcfApi.createRouter(cmd.getTenantId(), router);
return new BcfAnswer(cmd, true, "router " + cmd.getTenantId() +
" created.", hash);
} catch (BigSwitchBcfApiException e) {
if (e.is_topologySyncRequested()) {
cmd.setTopologySyncRequested(true);
return new BcfAnswer(cmd, true, " created; topology sync required.");
} else {
if (numRetries > 0) {
return retry(cmd, --numRetries);
} else {
return new BcfAnswer(cmd, e);
}
}
}
}
private Answer executeRequest(CreateBcfRouterInterfaceCommand cmd, int numRetries) {
RouterInterfaceData routerInterface = new RouterInterfaceData(cmd.getTenantId(),
cmd.getGateway(), cmd.getCidr(), cmd.getNetworkId(), cmd.getNetworkName());
try {
String hash;
hash = _bigswitchBcfApi.createRouterInterface(cmd.getTenantId(),
cmd.getTenantId(), routerInterface);
return new BcfAnswer(cmd, true, "router " + cmd.getTenantId() +
" created.", hash);
} catch (BigSwitchBcfApiException e) {
if (e.is_topologySyncRequested()) {
cmd.setTopologySyncRequested(true);
return new BcfAnswer(cmd, true, " created; topology sync required.");
} else {
if (numRetries > 0) {
return retry(cmd, --numRetries);
} else {
return new BcfAnswer(cmd, e);
}
}
}
}
private Answer executeRequest(UpdateBcfRouterCommand cmd, int numRetries){
RouterData routerData = new RouterData(cmd.getTenantId());
List<AclData> acls = new ArrayList<AclData>();
acls.addAll(cmd.getAcls());
routerData.getRouter().getAcls().addAll(acls);
routerData.getRouter().addExternalGateway(cmd.getPublicIp());
try {
String hash = _bigswitchBcfApi.modifyRouter(cmd.getTenantId(), routerData);
return new BcfAnswer(cmd, true, "tenant " + cmd.getTenantId() + " router updated", hash);
} catch (BigSwitchBcfApiException e) {
if (e.is_topologySyncRequested()) {
cmd.setTopologySyncRequested(true);
return new BcfAnswer(cmd, true, "tenant " + cmd.getTenantId() + " router updated but topology sync required.");
} else {
if (numRetries > 0) {
return retry(cmd, --numRetries);
} else {
return new BcfAnswer(cmd, e);
}
}
} catch (IllegalArgumentException e1){
return new BcfAnswer(cmd, false, "Illegal argument in BCF router update");
}
}
private Answer executeRequest(SyncBcfTopologyCommand cmd, int numRetries) {
try {
TopologyData topo = _latestTopology;
if (!cmd.isNetworkIncluded()) {
topo.clearNetworks();
}
if(!cmd.isRouterIncluded()) {
topo.clearRouters();
}
String hash = _bigswitchBcfApi.syncTopology(topo);
if(!initTopologySyncDone){
initTopologySyncDone=true;
}
return new BcfAnswer(cmd, true, "BCF topology synced", hash);
} catch (BigSwitchBcfApiException e) {
if (numRetries > 0) {
return retry(cmd, --numRetries);
} else {
return new BcfAnswer(cmd, e);
}
} catch (IllegalArgumentException e1){
return new BcfAnswer(cmd, false, "Illegal argument in BCF topology sync");
}
}
private Answer executeRequest(CacheBcfTopologyCommand cmd, int numRetries) {
_latestTopology = cmd.getTopology();
return new Answer(cmd, true, "BCF topology cached");
}
private Answer executeRequest(GetControllerDataCommand cmd, int numRetries) {
ControllerData controller = _bigswitchBcfApi.getControllerData();
return new GetControllerDataAnswer(cmd,
controller.getIpAddress(),
controller.isPrimary());
}
private Answer executeRequest(ReadyCommand cmd) {
return new ReadyAnswer(cmd);
}
private Answer executeRequest(MaintainCommand cmd) {
return new MaintainAnswer(cmd);
}
private Answer retry(Command cmd, int numRetries) {
s_logger.warn("Retrying " + cmd.getClass().getSimpleName() + ". Number of retries remaining: " + numRetries);
return executeRequest(cmd, numRetries);
}
private String truncate(String string, int length) {
if (string.length() <= length) {
return string;
} else {
return string.substring(0, length);
}
}
}