| // 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.element; |
| |
| import java.net.MalformedURLException; |
| import java.net.URL; |
| import java.util.ArrayList; |
| import java.util.Arrays; |
| import java.util.HashMap; |
| import java.util.List; |
| import java.util.Map; |
| import java.util.Set; |
| import java.util.UUID; |
| |
| import javax.inject.Inject; |
| import javax.naming.ConfigurationException; |
| |
| import org.apache.log4j.Logger; |
| |
| import org.apache.cloudstack.api.commands.AddSspCmd; |
| import org.apache.cloudstack.api.commands.DeleteSspCmd; |
| import org.apache.cloudstack.engine.orchestration.service.NetworkOrchestrationService; |
| import org.apache.cloudstack.framework.config.dao.ConfigurationDao; |
| import org.apache.cloudstack.network.dao.SspCredentialDao; |
| import org.apache.cloudstack.network.dao.SspCredentialVO; |
| import org.apache.cloudstack.network.dao.SspTenantDao; |
| import org.apache.cloudstack.network.dao.SspTenantVO; |
| import org.apache.cloudstack.network.dao.SspUuidDao; |
| import org.apache.cloudstack.network.dao.SspUuidVO; |
| |
| import com.cloud.dc.dao.DataCenterDao; |
| import com.cloud.deploy.DeployDestination; |
| import com.cloud.exception.ConcurrentOperationException; |
| import com.cloud.exception.InsufficientCapacityException; |
| import com.cloud.exception.InvalidParameterValueException; |
| import com.cloud.exception.ResourceUnavailableException; |
| import com.cloud.host.Host; |
| import com.cloud.host.HostVO; |
| import com.cloud.host.dao.HostDao; |
| import com.cloud.network.Network; |
| import com.cloud.network.Network.Capability; |
| import com.cloud.network.Network.Provider; |
| import com.cloud.network.Network.Service; |
| import com.cloud.network.NetworkMigrationResponder; |
| import com.cloud.network.NetworkModel; |
| import com.cloud.network.Networks.BroadcastDomainType; |
| import com.cloud.network.PhysicalNetwork; |
| import com.cloud.network.PhysicalNetworkServiceProvider; |
| import com.cloud.network.PhysicalNetworkServiceProvider.State; |
| import com.cloud.network.dao.NetworkServiceMapDao; |
| import com.cloud.network.dao.PhysicalNetworkDao; |
| import com.cloud.network.dao.PhysicalNetworkServiceProviderDao; |
| import com.cloud.network.dao.PhysicalNetworkServiceProviderVO; |
| import com.cloud.network.element.ConnectivityProvider; |
| import com.cloud.offering.NetworkOffering; |
| import com.cloud.resource.ResourceManager; |
| import com.cloud.utils.component.AdapterBase; |
| import com.cloud.utils.exception.CloudRuntimeException; |
| import com.cloud.vm.NicProfile; |
| import com.cloud.vm.NicVO; |
| import com.cloud.vm.ReservationContext; |
| import com.cloud.vm.VirtualMachineProfile; |
| import com.cloud.vm.dao.NicDao; |
| |
| /** |
| * Stratosphere sdn platform network element |
| * |
| * This class will be called per network setup operations. |
| * This class also have ssp specific methods. |
| * |
| * Current implementation use HostVO for storage of api endpoint information, |
| * but note this is not necessary. The other way is create our own database |
| * table for that information. |
| */ |
| public class SspElement extends AdapterBase implements ConnectivityProvider, SspManager, SspService, NetworkMigrationResponder { |
| private static final Logger s_logger = Logger.getLogger(SspElement.class); |
| public static final String s_SSP_NAME = "StratosphereSsp"; |
| private static final Provider s_ssp_provider = new Provider(s_SSP_NAME, false); |
| |
| @Inject |
| NetworkServiceMapDao _ntwkSrvcDao; |
| @Inject |
| NetworkModel _networkModel; |
| @Inject |
| NetworkOrchestrationService _networkMgr; |
| @Inject |
| ResourceManager _resourceMgr; |
| @Inject |
| PhysicalNetworkDao _physicalNetworkDao; |
| @Inject |
| PhysicalNetworkServiceProviderDao _physicalNetworkServiceProviderDao; |
| @Inject |
| SspCredentialDao _sspCredentialDao; |
| @Inject |
| SspTenantDao _sspTenantDao; |
| @Inject |
| SspUuidDao _sspUuidDao; |
| @Inject |
| DataCenterDao _dcDao; |
| @Inject |
| HostDao _hostDao; |
| @Inject |
| ConfigurationDao _configDao; |
| @Inject |
| NicDao _nicDao = null; |
| |
| @Override |
| public boolean configure(String name, Map<String, Object> params) throws ConfigurationException { |
| return super.configure(name, params); |
| } |
| |
| @Override |
| public Map<Service, Map<Capability, String>> getCapabilities() { |
| Map<Service, Map<Capability, String>> capabilities = new HashMap<Service, Map<Capability, String>>(); |
| capabilities.put(Service.Connectivity, new HashMap<Capability, String>()); // XXX: We might need some more category here. |
| return capabilities; |
| } |
| |
| @Override |
| public Provider getProvider() { |
| return s_ssp_provider; |
| } |
| |
| private List<SspClient> fetchSspClients(Long physicalNetworkId, Long dataCenterId, boolean enabledOnly) { |
| ArrayList<SspClient> clients = new ArrayList<SspClient>(); |
| |
| boolean provider_found = false; |
| PhysicalNetworkServiceProviderVO provider = _physicalNetworkServiceProviderDao.findByServiceProvider(physicalNetworkId, s_SSP_NAME); |
| if (enabledOnly) { |
| if (provider != null && provider.getState() == State.Enabled) { |
| provider_found = true; |
| } |
| } else { |
| provider_found = true; |
| } |
| |
| if (physicalNetworkId != null && provider_found) { |
| SspCredentialVO credential = _sspCredentialDao.findByZone(dataCenterId); |
| List<HostVO> hosts = _resourceMgr.listAllHostsInOneZoneByType(Host.Type.L2Networking, dataCenterId); |
| for (HostVO host : hosts) { |
| assert (credential != null); |
| _hostDao.loadDetails(host); |
| if ("v1Api".equals(host.getDetail("sspHost"))) { |
| clients.add(new SspClient(host.getDetail("url"), credential.getUsername(), credential.getPassword())); |
| } |
| } |
| } |
| if (clients.size() == 0) { |
| String global_apiUrl = _configDao.getValueAndInitIfNotExist("ssp.url", "Network", null); |
| String global_username = _configDao.getValueAndInitIfNotExist("ssp.username", "Network", null); |
| String global_password = _configDao.getValueAndInitIfNotExist("ssp.password", "Network", null); |
| if (global_apiUrl != null && global_username != null && global_password != null) { |
| clients.add(new SspClient(global_apiUrl, global_username, global_password)); |
| } |
| } |
| return clients; |
| } |
| |
| /* (non-Javadoc) |
| * @see org.apache.cloudstack.network.element.NetworkElement#isReady(com.cloud.network.PhysicalNetworkServiceProvider) |
| */ |
| @Override |
| public boolean isReady(PhysicalNetworkServiceProvider provider) { |
| PhysicalNetwork physicalNetwork = _physicalNetworkDao.findById(provider.getPhysicalNetworkId()); |
| assert (physicalNetwork != null); |
| if (fetchSspClients(physicalNetwork.getId(), physicalNetwork.getDataCenterId(), false).size() > 0) { |
| return true; |
| } |
| s_logger.warn("Ssp api endpoint not found. " + physicalNetwork.toString()); |
| return false; |
| } |
| |
| /* (non-Javadoc) |
| * If this element is ready, then it can be enabled. |
| * @see org.apache.cloudstack.network.element.SspManager#isEnabled(com.cloud.network.PhysicalNetwork) |
| */ |
| @Override |
| public boolean canHandle(PhysicalNetwork physicalNetwork) { |
| if (physicalNetwork != null) { |
| if (fetchSspClients(physicalNetwork.getId(), physicalNetwork.getDataCenterId(), true).size() > 0) { |
| return true; |
| } |
| s_logger.warn("enabled Ssp api endpoint not found. " + physicalNetwork.toString()); |
| } else { |
| s_logger.warn("PhysicalNetwork is NULL."); |
| } |
| return false; |
| } |
| |
| private boolean canHandle(Network network) { |
| if (canHandle(_physicalNetworkDao.findById(network.getPhysicalNetworkId()))) { |
| if (!_ntwkSrvcDao.canProviderSupportServiceInNetwork(network.getId(), Service.Connectivity, getProvider())) { |
| s_logger.info("SSP is implicitly active for " + network); |
| } |
| return true; |
| } |
| return false; |
| } |
| |
| @Override |
| public Host addSspHost(AddSspCmd cmd) { |
| SspClient client = new SspClient(cmd.getUrl(), cmd.getUsername(), cmd.getPassword()); |
| if (!client.login()) { |
| throw new CloudRuntimeException("Ssp login failed."); |
| } |
| |
| long zoneId = cmd.getZoneId(); |
| SspCredentialVO credential = _sspCredentialDao.findByZone(zoneId); |
| if (credential == null) { |
| if (cmd.getUsername() == null || cmd.getPassword() == null) { |
| throw new InvalidParameterValueException("Initial credential required for zone: " + zoneId); |
| } |
| credential = new SspCredentialVO(); |
| credential.setZoneId(zoneId); |
| credential.setUsername(cmd.getUsername()); |
| credential.setPassword(cmd.getPassword()); |
| _sspCredentialDao.persist(credential); |
| } else { |
| if (cmd.getUsername() != null || cmd.getPassword() != null) { |
| s_logger.warn("Tenant credential already configured for zone:" + zoneId); |
| } |
| } |
| |
| String tenantUuid = _sspTenantDao.findUuidByZone(zoneId); |
| if (tenantUuid == null) { |
| if (cmd.getTenantUuid() == null) { |
| throw new InvalidParameterValueException("Initial tenant uuid required for zone: " + zoneId); |
| } |
| SspTenantVO tenant = new SspTenantVO(); |
| tenant.setZoneId(zoneId); |
| tenant.setUuid(cmd.getTenantUuid()); |
| _sspTenantDao.persist(tenant); |
| } else { |
| if (cmd.getTenantUuid() != null) { |
| s_logger.warn("Tenant uuid already configured for zone:" + zoneId); |
| } |
| } |
| |
| String normalizedUrl = null; |
| String hostname = null; |
| try { |
| URL url = new URL(cmd.getUrl()); |
| normalizedUrl = url.toString(); |
| hostname = url.getHost(); |
| } catch (MalformedURLException e1) { |
| throw new CloudRuntimeException("Invalid url " + cmd.getUrl()); |
| } |
| |
| List<HostVO> hosts = _resourceMgr.listAllHostsInOneZoneByType(Host.Type.L2Networking, zoneId); |
| for (HostVO host : hosts) { |
| assert (credential != null); |
| _hostDao.loadDetails(host); |
| if ("v1Api".equals(host.getDetail("sspHost"))) { |
| if (normalizedUrl.equals(host.getDetail("url"))) { |
| s_logger.warn("Ssp host already registered " + normalizedUrl); |
| return host; |
| } |
| } |
| } |
| // SspHost HostVO will be created per zone and url. |
| HostVO host = new HostVO(UUID.randomUUID().toString()); |
| host.setDataCenterId(zoneId); |
| host.setType(Host.Type.L2Networking); |
| host.setPrivateIpAddress(hostname); // db schema not null. It may be a name, not IP address. |
| // host.setPrivateMacAddress(""); // db schema nullable |
| // host.setPrivateNetmask(""); // db schema nullable |
| host.setVersion("1"); // strange db schema not null |
| host.setName(cmd.getName()); |
| |
| host.setDetails(new HashMap<String, String>()); |
| host.setDetail("sspHost", "v1Api"); |
| host.setDetail("url", normalizedUrl); |
| return _hostDao.persist(host); |
| } |
| |
| @Override |
| public boolean deleteSspHost(DeleteSspCmd cmd) { |
| s_logger.info("deleteStratosphereSsp"); |
| return _hostDao.remove(cmd.getHostId()); |
| } |
| |
| @Override |
| public boolean createNetwork(Network network, NetworkOffering offering, DeployDestination dest, ReservationContext context) { |
| if (_sspUuidDao.findUuidByNetwork(network) != null) { |
| s_logger.info("Network already has ssp TenantNetwork uuid :" + network.toString()); |
| return true; |
| } |
| if (!canHandle(network)) { |
| return false; |
| } |
| |
| String tenantUuid = _sspTenantDao.findUuidByZone(network.getDataCenterId()); |
| if (tenantUuid == null) { |
| tenantUuid = _configDao.getValueAndInitIfNotExist("ssp.tenant", "Network", null); |
| } |
| |
| boolean processed = false; |
| for (SspClient client : fetchSspClients(network.getPhysicalNetworkId(), network.getDataCenterId(), true)) { |
| SspClient.TenantNetwork sspNet = client.createTenantNetwork(tenantUuid, network.getName()); |
| if (sspNet != null) { |
| SspUuidVO uuid = new SspUuidVO(); |
| uuid.setUuid(sspNet.uuid); |
| uuid.setObjClass(SspUuidVO.objClassNetwork); |
| uuid.setObjId(network.getId()); |
| _sspUuidDao.persist(uuid); |
| return true; |
| } |
| processed = true; |
| } |
| if (processed) { |
| s_logger.error("Could not allocate an uuid for network " + network.toString()); |
| return false; |
| } else { |
| s_logger.error("Skipping #createNetwork() for " + network.toString()); |
| return true; |
| } |
| } |
| |
| @Override |
| public boolean deleteNetwork(Network network) { |
| String tenantNetworkUuid = _sspUuidDao.findUuidByNetwork(network); |
| if (tenantNetworkUuid != null) { |
| boolean processed = false; |
| for (SspClient client : fetchSspClients(network.getPhysicalNetworkId(), network.getDataCenterId(), true)) { |
| if (client.deleteTenantNetwork(tenantNetworkUuid)) { |
| _sspUuidDao.removeUuid(tenantNetworkUuid); |
| processed = true; |
| break; |
| } |
| } |
| if (!processed) { |
| s_logger.error("Ssp api tenant network deletion failed " + network.toString()); |
| } |
| } else { |
| s_logger.debug("Silently skipping #deleteNetwork() for " + network.toString()); |
| } |
| return true; |
| } |
| |
| // we use context.reservationId for dedup of guru & element operations. |
| @Override |
| public boolean createNicEnv(Network network, NicProfile nic, DeployDestination dest, ReservationContext context) { |
| String tenantNetworkUuid = _sspUuidDao.findUuidByNetwork(network); |
| if (tenantNetworkUuid == null) { |
| s_logger.debug("Skipping #createNicEnv() for nic on " + network.toString()); |
| return true; |
| } |
| |
| String reservationId = context.getReservationId(); |
| List<SspUuidVO> tenantPortUuidVos = _sspUuidDao.listUUidVoByNicProfile(nic); |
| for (SspUuidVO tenantPortUuidVo : tenantPortUuidVos) { |
| if (reservationId.equals(tenantPortUuidVo.getReservationId())) { |
| s_logger.info("Skipping because reservation found " + reservationId); |
| return true; |
| } |
| } |
| |
| String tenantPortUuid = null; |
| for (SspClient client : fetchSspClients(network.getPhysicalNetworkId(), network.getDataCenterId(), true)) { |
| SspClient.TenantPort sspPort = client.createTenantPort(tenantNetworkUuid); |
| if (sspPort != null) { |
| tenantPortUuid = sspPort.uuid; |
| nic.setReservationId(reservationId); |
| |
| SspUuidVO uuid = new SspUuidVO(); |
| uuid.setUuid(tenantPortUuid); |
| uuid.setObjClass(SspUuidVO.objClassNicProfile); |
| uuid.setObjId(nic.getId()); |
| uuid.setReservationId(reservationId); |
| _sspUuidDao.persist(uuid); |
| break; |
| } |
| } |
| if (tenantPortUuid == null) { |
| s_logger.debug("#createNicEnv() failed for nic on " + network.toString()); |
| return false; |
| } |
| |
| for (SspClient client : fetchSspClients(network.getPhysicalNetworkId(), network.getDataCenterId(), true)) { |
| SspClient.TenantPort sspPort = client.updateTenantVifBinding(tenantPortUuid, dest.getHost().getPrivateIpAddress()); |
| if (sspPort != null) { |
| if (sspPort.vlanId != null) { |
| nic.setBroadcastType(BroadcastDomainType.Vlan); |
| nic.setBroadcastUri(BroadcastDomainType.Vlan.toUri(String.valueOf(sspPort.vlanId))); |
| } |
| return true; |
| } |
| } |
| s_logger.error("Updating vif failed " + nic.toString()); |
| return false; |
| } |
| |
| @Override |
| public boolean deleteNicEnv(Network network, NicProfile nic, ReservationContext context) { |
| if (context == null) { |
| s_logger.error("ReservationContext was null for " + nic + " " + network); |
| return false; |
| } |
| String reservationId = context.getReservationId(); |
| |
| SspUuidVO deleteTarget = null; |
| SspUuidVO remainingTarget = null; |
| List<SspUuidVO> tenantPortUuidVos = _sspUuidDao.listUUidVoByNicProfile(nic); |
| for (SspUuidVO tenantPortUuidVo : tenantPortUuidVos) { |
| if (reservationId.equals(tenantPortUuidVo.getReservationId())) { |
| deleteTarget = tenantPortUuidVo; |
| } else { |
| remainingTarget = tenantPortUuidVo; |
| } |
| } |
| |
| if (deleteTarget != null) { // delete the target ssp uuid (tenant-port) |
| String tenantPortUuid = deleteTarget.getUuid(); |
| boolean processed = false; |
| for (SspClient client : fetchSspClients(network.getPhysicalNetworkId(), network.getDataCenterId(), true)) { |
| SspClient.TenantPort sspPort = client.updateTenantVifBinding(tenantPortUuid, null); |
| if (sspPort != null) { |
| processed = true; |
| break; |
| } |
| } |
| if (!processed) { |
| s_logger.warn("Ssp api nic detach failed " + nic.toString()); |
| } |
| processed = false; |
| for (SspClient client : fetchSspClients(network.getPhysicalNetworkId(), network.getDataCenterId(), true)) { |
| if (client.deleteTenantPort(tenantPortUuid)) { |
| _sspUuidDao.removeUuid(tenantPortUuid); |
| processed = true; |
| break; |
| } |
| } |
| if (!processed) { |
| s_logger.warn("Ssp api tenant port deletion failed " + nic.toString()); |
| } |
| _sspUuidDao.removeUuid(tenantPortUuid); |
| } |
| if (remainingTarget != null) { |
| NicVO nicVo = _nicDao.findById(nic.getId()); |
| nicVo.setReservationId(remainingTarget.getReservationId()); |
| _nicDao.persist(nicVo); // persist the new reservationId |
| } |
| return true; |
| } |
| |
| /* (non-Javadoc) |
| * Implements a network using ssp element. |
| * |
| * This method will be called right after NetworkGuru#implement(). |
| * see also {@link #shutdown(Network, ReservationContext, boolean)} |
| * @see org.apache.cloudstack.network.element.NetworkElement#implement(com.cloud.network.Network, com.cloud.offering.NetworkOffering, com.cloud.deploy.DeployDestination, com.cloud.vm.ReservationContext) |
| */ |
| @Override |
| public boolean implement(Network network, NetworkOffering offering, DeployDestination dest, ReservationContext context) throws ConcurrentOperationException, |
| ResourceUnavailableException, InsufficientCapacityException { |
| s_logger.info("implement"); |
| return createNetwork(network, offering, dest, context); |
| } |
| |
| /* (non-Javadoc) |
| * Shutdown the network implementation |
| * |
| * This method will be called right BEFORE NetworkGuru#shutdown(). |
| * The entities was acquired by {@link #implement(Network, NetworkOffering, DeployDestination, ReservationContext)} |
| * @see org.apache.cloudstack.network.element.NetworkElement#shutdown(com.cloud.network.Network, com.cloud.vm.ReservationContext, boolean) |
| */ |
| @Override |
| public boolean shutdown(Network network, ReservationContext context, boolean cleanup) throws ConcurrentOperationException, ResourceUnavailableException { |
| s_logger.trace("shutdown"); |
| return deleteNetwork(network); |
| } |
| |
| /* (non-Javadoc) |
| * Prepares a network environment for a VM nic. |
| * |
| * This method will be called right after NetworkGuru#reserve(). |
| * The entities will be released by {@link #release(Network, NicProfile, VirtualMachineProfile, ReservationContext)} |
| * @see org.apache.cloudstack.network.element.NetworkElement#prepare(com.cloud.network.Network, com.cloud.vm.NicProfile, com.cloud.vm.VirtualMachineProfile, com.cloud.deploy.DeployDestination, com.cloud.vm.ReservationContext) |
| */ |
| @Override |
| public boolean prepare(Network network, NicProfile nic, VirtualMachineProfile vm, DeployDestination dest, ReservationContext context) |
| throws ConcurrentOperationException, ResourceUnavailableException, InsufficientCapacityException { |
| s_logger.trace("prepare"); |
| return createNicEnv(network, nic, dest, context); |
| } |
| |
| /* (non-Javadoc) |
| * Release the network environment that was prepared for a VM nic. |
| * |
| * This method will be called right AFTER NetworkGuru#release(). |
| * The entities was acquired in {@link #prepare(Network, NicProfile, VirtualMachineProfile, DeployDestination, ReservationContext)} |
| * @see org.apache.cloudstack.network.element.NetworkElement#release(com.cloud.network.Network, com.cloud.vm.NicProfile, com.cloud.vm.VirtualMachineProfile, com.cloud.vm.ReservationContext) |
| */ |
| @Override |
| public boolean release(Network network, NicProfile nic, VirtualMachineProfile vm, ReservationContext context) throws ConcurrentOperationException, |
| ResourceUnavailableException { |
| s_logger.trace("release"); |
| return deleteNicEnv(network, nic, context); |
| } |
| |
| /* (non-Javadoc) |
| * Destroy a network implementation. |
| * |
| * This method will be called right BEFORE NetworkGuru#trash() in "Expunge" phase. |
| * @see org.apache.cloudstack.network.element.NetworkElement#destroy(com.cloud.network.Network) |
| */ |
| @Override |
| public boolean destroy(Network network, ReservationContext context) throws ConcurrentOperationException, ResourceUnavailableException { |
| s_logger.trace("destroy"); |
| // nothing to do here. |
| return true; |
| } |
| |
| @Override |
| public boolean shutdownProviderInstances(PhysicalNetworkServiceProvider provider, ReservationContext context) throws ConcurrentOperationException, |
| ResourceUnavailableException { |
| s_logger.trace("shutdownProviderInstances"); |
| return true; |
| } |
| |
| @Override |
| public boolean canEnableIndividualServices() { |
| s_logger.trace("canEnableIndividualServices"); |
| return true; // because there is only Connectivity |
| } |
| |
| @Override |
| public boolean verifyServicesCombination(Set<Service> services) { |
| s_logger.trace("verifyServicesCombination " + services.toString()); |
| return true; |
| } |
| |
| @Override |
| public boolean prepareMigration(NicProfile nic, Network network, VirtualMachineProfile vm, DeployDestination dest, ReservationContext context) { |
| try { |
| prepare(network, nic, vm, dest, context); |
| } catch (ConcurrentOperationException e) { |
| s_logger.error("prepareForMigration failed.", e); |
| return false; |
| } catch (ResourceUnavailableException e) { |
| s_logger.error("prepareForMigration failed.", e); |
| return false; |
| } catch (InsufficientCapacityException e) { |
| s_logger.error("prepareForMigration failed.", e); |
| return false; |
| } |
| return true; |
| } |
| |
| @Override |
| public void rollbackMigration(NicProfile nic, Network network, VirtualMachineProfile vm, ReservationContext src, ReservationContext dst) { |
| try { |
| release(network, nic, vm, dst); |
| } catch (ConcurrentOperationException e) { |
| s_logger.error("rollbackMigration failed.", e); |
| } catch (ResourceUnavailableException e) { |
| s_logger.error("rollbackMigration failed.", e); |
| } |
| } |
| |
| @Override |
| public void commitMigration(NicProfile nic, Network network, VirtualMachineProfile vm, ReservationContext src, ReservationContext dst) { |
| try { |
| release(network, nic, vm, src); |
| } catch (ConcurrentOperationException e) { |
| s_logger.error("commitMigration failed.", e); |
| } catch (ResourceUnavailableException e) { |
| s_logger.error("commitMigration failed.", e); |
| } |
| } |
| |
| @Override |
| public List<Class<?>> getCommands() { |
| return Arrays.<Class<?>> asList(AddSspCmd.class, DeleteSspCmd.class); |
| } |
| } |