diff --git a/api/src/com/cloud/network/Network.java b/api/src/com/cloud/network/Network.java index 74398e84b02..d19c999f16e 100644 --- a/api/src/com/cloud/network/Network.java +++ b/api/src/com/cloud/network/Network.java @@ -126,8 +126,8 @@ public interface Network extends ControlledEntity, StateObject, I public static final Provider NiciraNvp = new Provider("NiciraNvp", false); public static final Provider InternalLbVm = new Provider("InternalLbVm", false); public static final Provider CiscoVnmc = new Provider("CiscoVnmc", true); - // Ovs - public static final Provider Ovs = new Provider("Ovs", false); + // add new Ovs provider + public static final Provider Ovs = new Provider("Ovs", false); private final String name; private final boolean isExternal; diff --git a/api/src/com/cloud/network/OvsProvider.java b/api/src/com/cloud/network/OvsProvider.java new file mode 100644 index 00000000000..c9937282bef --- /dev/null +++ b/api/src/com/cloud/network/OvsProvider.java @@ -0,0 +1,10 @@ +package com.cloud.network; + +import org.apache.cloudstack.api.Identity; +import org.apache.cloudstack.api.InternalIdentity; + +public interface OvsProvider extends InternalIdentity, Identity { + public boolean isEnabled(); + + public long getNspId(); +} diff --git a/api/src/com/cloud/network/element/VirtualRouterElementService.java b/api/src/com/cloud/network/element/VirtualRouterElementService.java index e929d14ae50..c8d45cafe53 100644 --- a/api/src/com/cloud/network/element/VirtualRouterElementService.java +++ b/api/src/com/cloud/network/element/VirtualRouterElementService.java @@ -18,9 +18,12 @@ package com.cloud.network.element; import java.util.List; +import org.apache.cloudstack.api.command.admin.router.ConfigureOvsElementCmd; import org.apache.cloudstack.api.command.admin.router.ConfigureVirtualRouterElementCmd; +import org.apache.cloudstack.api.command.admin.router.ListOvsElementsCmd; import org.apache.cloudstack.api.command.admin.router.ListVirtualRouterElementsCmd; +import com.cloud.network.OvsProvider; import com.cloud.network.VirtualRouterProvider; import com.cloud.network.VirtualRouterProvider.Type; import com.cloud.utils.component.PluggableService; @@ -28,9 +31,12 @@ import com.cloud.utils.component.PluggableService; public interface VirtualRouterElementService extends PluggableService { VirtualRouterProvider configure(ConfigureVirtualRouterElementCmd cmd); + OvsProvider configure(ConfigureOvsElementCmd cmd); VirtualRouterProvider addElement(Long nspId, Type providerType); VirtualRouterProvider getCreatedElement(long id); List searchForVirtualRouterElement(ListVirtualRouterElementsCmd cmd); + + List searchForOvsElement(ListOvsElementsCmd cmd); } diff --git a/api/src/org/apache/cloudstack/api/ResponseGenerator.java b/api/src/org/apache/cloudstack/api/ResponseGenerator.java index 2d37b6a188b..64b703e6857 100644 --- a/api/src/org/apache/cloudstack/api/ResponseGenerator.java +++ b/api/src/org/apache/cloudstack/api/ResponseGenerator.java @@ -67,6 +67,7 @@ import org.apache.cloudstack.api.response.NetworkOfferingResponse; import org.apache.cloudstack.api.response.NetworkResponse; import org.apache.cloudstack.api.response.NicResponse; import org.apache.cloudstack.api.response.NicSecondaryIpResponse; +import org.apache.cloudstack.api.response.OvsProviderResponse; import org.apache.cloudstack.api.response.PhysicalNetworkResponse; import org.apache.cloudstack.api.response.PodResponse; import org.apache.cloudstack.api.response.PortableIpRangeResponse; @@ -118,7 +119,9 @@ import org.apache.cloudstack.region.PortableIpRange; import org.apache.cloudstack.region.Region; import org.apache.cloudstack.usage.Usage; +import com.cloud.async.AsyncJob; import com.cloud.capacity.Capacity; +import com.cloud.configuration.Configuration; import com.cloud.configuration.ResourceCount; import com.cloud.configuration.ResourceLimit; import com.cloud.dc.DataCenter; @@ -134,6 +137,7 @@ import com.cloud.network.IpAddress; import com.cloud.network.Network; import com.cloud.network.Network.Service; import com.cloud.network.Networks.IsolationType; +import com.cloud.network.OvsProvider; import com.cloud.network.PhysicalNetwork; import com.cloud.network.PhysicalNetworkServiceProvider; import com.cloud.network.PhysicalNetworkTrafficType; @@ -353,6 +357,10 @@ public interface ResponseGenerator { VirtualRouterProviderResponse createVirtualRouterProviderResponse(VirtualRouterProvider result); + OvsProviderResponse createOvsProviderResponse(OvsProvider result); + + LDAPConfigResponse createLDAPConfigResponse(String hostname, Integer port, Boolean useSSL, String queryFilter, String baseSearch, String dn); + StorageNetworkIpRangeResponse createStorageNetworkIpRangeResponse(StorageNetworkIpRange result); RegionResponse createRegionResponse(Region region); diff --git a/api/src/org/apache/cloudstack/api/command/admin/router/ConfigureOvsElementCmd.java b/api/src/org/apache/cloudstack/api/command/admin/router/ConfigureOvsElementCmd.java new file mode 100644 index 00000000000..0419154a424 --- /dev/null +++ b/api/src/org/apache/cloudstack/api/command/admin/router/ConfigureOvsElementCmd.java @@ -0,0 +1,116 @@ +package org.apache.cloudstack.api.command.admin.router; + +import java.util.List; + +import javax.inject.Inject; + +import org.apache.cloudstack.api.APICommand; +import org.apache.cloudstack.api.ApiCommandJobType; +import org.apache.cloudstack.api.ApiConstants; +import org.apache.cloudstack.api.ApiErrorCode; +import org.apache.cloudstack.api.BaseAsyncCmd; +import org.apache.cloudstack.api.Parameter; +import org.apache.cloudstack.api.ServerApiException; +import org.apache.cloudstack.api.response.OvsProviderResponse; +import org.apache.log4j.Logger; + +import com.cloud.event.EventTypes; +import com.cloud.exception.ConcurrentOperationException; +import com.cloud.exception.InsufficientCapacityException; +import com.cloud.exception.ResourceUnavailableException; +import com.cloud.network.OvsProvider; +import com.cloud.network.element.VirtualRouterElementService; +import com.cloud.user.Account; +import com.cloud.user.UserContext; + +@APICommand(name = "configureOvsElement", responseObject = OvsProviderResponse.class, description = "Configures an ovs element.") +public class ConfigureOvsElementCmd extends BaseAsyncCmd { + public static final Logger s_logger = Logger + .getLogger(ConfigureOvsElementCmd.class.getName()); + private static final String s_name = "configureovselementresponse"; + @Inject + private List _service; + + // /////////////////////////////////////////////////// + // ////////////// API parameters ///////////////////// + // /////////////////////////////////////////////////// + + @Parameter(name = ApiConstants.ID, type = CommandType.UUID, entityType = OvsProviderResponse.class, required = true, description = "the ID of the ovs provider") + private Long id; + + @Parameter(name = ApiConstants.ENABLED, type = CommandType.BOOLEAN, required = true, description = "Enabled/Disabled the service provider") + private Boolean enabled; + + // /////////////////////////////////////////////////// + // ///////////////// Accessors /////////////////////// + // /////////////////////////////////////////////////// + public void setId(Long id) { + this.id = id; + } + + public Long getId() { + return id; + } + + public void setEnabled(Boolean enabled) { + this.enabled = enabled; + } + + public Boolean getEnabled() { + return enabled; + } + + // /////////////////////////////////////////////////// + // ///////////// API Implementation/////////////////// + // /////////////////////////////////////////////////// + + @Override + public String getCommandName() { + return s_name; + } + + public static String getResultObjectName() { + return "boolean"; + } + + @Override + public long getEntityOwnerId() { + return Account.ACCOUNT_ID_SYSTEM; + } + + @Override + public String getEventType() { + return EventTypes.EVENT_NETWORK_ELEMENT_CONFIGURE; + } + + @Override + public String getEventDescription() { + return "configuring ovs provider: " + id; + } + + @Override + public ApiCommandJobType getInstanceType() { + return ApiCommandJobType.None; + } + + @Override + public Long getInstanceId() { + return id; + } + + @Override + public void execute() throws ConcurrentOperationException, + ResourceUnavailableException, InsufficientCapacityException { + UserContext.current().setEventDetails("Ovs element: " + id); + OvsProvider result = _service.get(0).configure(this); + if (result != null) { + OvsProviderResponse ovsResponse = _responseGenerator + .createOvsProviderResponse(result); + ovsResponse.setResponseName(getCommandName()); + this.setResponseObject(ovsResponse); + } else { + throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, + "Failed to configure the ovs provider"); + } + } +} diff --git a/api/src/org/apache/cloudstack/api/command/admin/router/ListOvsElementsCmd.java b/api/src/org/apache/cloudstack/api/command/admin/router/ListOvsElementsCmd.java new file mode 100644 index 00000000000..3e3ee635f48 --- /dev/null +++ b/api/src/org/apache/cloudstack/api/command/admin/router/ListOvsElementsCmd.java @@ -0,0 +1,91 @@ +package org.apache.cloudstack.api.command.admin.router; + +import java.util.ArrayList; +import java.util.List; + +import javax.inject.Inject; + +import org.apache.cloudstack.api.APICommand; +import org.apache.cloudstack.api.ApiConstants; +import org.apache.cloudstack.api.BaseListCmd; +import org.apache.cloudstack.api.Parameter; +import org.apache.cloudstack.api.ServerApiException; +import org.apache.cloudstack.api.command.user.network.ListNetworkOfferingsCmd; +import org.apache.cloudstack.api.response.ListResponse; +import org.apache.cloudstack.api.response.OvsProviderResponse; +import org.apache.cloudstack.api.response.ProviderResponse; +import org.apache.log4j.Logger; + +import com.cloud.exception.ConcurrentOperationException; +import com.cloud.exception.InsufficientCapacityException; +import com.cloud.exception.ResourceAllocationException; +import com.cloud.exception.ResourceUnavailableException; +import com.cloud.network.OvsProvider; +import com.cloud.network.element.VirtualRouterElementService; + +@APICommand(name = "listOvsElements", description = "Lists all available ovs elements.", responseObject = OvsProviderResponse.class) +public class ListOvsElementsCmd extends BaseListCmd { + public static final Logger s_logger = Logger + .getLogger(ListNetworkOfferingsCmd.class.getName()); + private static final String _name = "listovselementsresponse"; + @Inject + private List _service; + // /////////////////////////////////////////////////// + // ////////////// API parameters ///////////////////// + // /////////////////////////////////////////////////// + @Parameter(name = ApiConstants.ID, type = CommandType.UUID, entityType = OvsProviderResponse.class, description = "list ovs elements by id") + private Long id; + + @Parameter(name = ApiConstants.NSP_ID, type = CommandType.UUID, entityType = ProviderResponse.class, description = "list ovs elements by network service provider id") + private Long nspId; + + @Parameter(name = ApiConstants.ENABLED, type = CommandType.BOOLEAN, description = "list network offerings by enabled state") + private Boolean enabled; + + // /////////////////////////////////////////////////// + // ///////////////// Accessors /////////////////////// + // /////////////////////////////////////////////////// + + public void setId(Long id) { + this.id = id; + } + + public Long getId() { + return id; + } + + public void setNspId(Long nspId) { + this.nspId = nspId; + } + + public Long getNspId() { + return nspId; + } + + public void setEnabled(Boolean enabled) { + this.enabled = enabled; + } + + public Boolean getEnabled() { + return enabled; + } + + @Override + public String getCommandName() { + return _name; + } + @Override + public void execute() throws ResourceUnavailableException, InsufficientCapacityException, ServerApiException, ConcurrentOperationException, ResourceAllocationException { + List providers = _service.get(0).searchForOvsElement(this); + ListResponse response = new ListResponse(); + List providerResponses = new ArrayList(); + for (OvsProvider provider : providers) { + OvsProviderResponse providerResponse = _responseGenerator.createOvsProviderResponse(provider); + providerResponses.add(providerResponse); + } + response.setResponses(providerResponses); + response.setResponseName(getCommandName()); + this.setResponseObject(response); + + } +} diff --git a/api/src/org/apache/cloudstack/api/response/OvsProviderResponse.java b/api/src/org/apache/cloudstack/api/response/OvsProviderResponse.java new file mode 100644 index 00000000000..23e61341072 --- /dev/null +++ b/api/src/org/apache/cloudstack/api/response/OvsProviderResponse.java @@ -0,0 +1,77 @@ +package org.apache.cloudstack.api.response; + +import org.apache.cloudstack.api.ApiConstants; +import org.apache.cloudstack.api.BaseResponse; +import org.apache.cloudstack.api.EntityReference; + +import com.cloud.network.OvsProvider; +import com.cloud.serializer.Param; +import com.google.gson.annotations.SerializedName; + +@EntityReference(value = OvsProvider.class) +@SuppressWarnings("unused") +public class OvsProviderResponse extends BaseResponse implements + ControlledEntityResponse { + @SerializedName(ApiConstants.ID) + @Param(description = "the id of the ovs") + private String id; + @SerializedName(ApiConstants.NSP_ID) + @Param(description = "the physical network service provider id of the provider") + private String nspId; + @SerializedName(ApiConstants.ENABLED) + @Param(description = "Enabled/Disabled the service provider") + private Boolean enabled; + @SerializedName(ApiConstants.ACCOUNT) + @Param(description = "the account associated with the provider") + private String accountName; + @SerializedName(ApiConstants.PROJECT_ID) + @Param(description = "the project id of the ipaddress") + private String projectId; + @SerializedName(ApiConstants.PROJECT) + @Param(description = "the project name of the address") + private String projectName; + @SerializedName(ApiConstants.DOMAIN_ID) + @Param(description = "the domain ID associated with the provider") + private String domainId; + + @SerializedName(ApiConstants.DOMAIN) + @Param(description = "the domain associated with the provider") + private String domainName; + + @Override + public void setAccountName(String accountName) { + this.accountName = accountName; + } + + public void setId(String id) { + this.id = id; + } + + @Override + public void setDomainId(String domainId) { + this.domainId = domainId; + } + + @Override + public void setDomainName(String domainName) { + this.domainName = domainName; + } + + @Override + public void setProjectId(String projectId) { + this.projectId = projectId; + } + + @Override + public void setProjectName(String projectName) { + this.projectName = projectName; + } + + public void setNspId(String nspId) { + this.nspId = nspId; + } + + public void setEnabled(Boolean enabled) { + this.enabled = enabled; + } +} diff --git a/client/tomcatconf/applicationContext.xml.in b/client/tomcatconf/applicationContext.xml.in index 52606810f8a..b3778d48b8d 100644 --- a/client/tomcatconf/applicationContext.xml.in +++ b/client/tomcatconf/applicationContext.xml.in @@ -355,6 +355,7 @@ + diff --git a/client/tomcatconf/commands.properties.in b/client/tomcatconf/commands.properties.in index da4c03fc71c..bd46fa27607 100644 --- a/client/tomcatconf/commands.properties.in +++ b/client/tomcatconf/commands.properties.in @@ -503,6 +503,11 @@ createVirtualRouterElement=7 configureVirtualRouterElement=7 listVirtualRouterElements=7 +#### ovs commands +createOvsElement=7 +configureOvsElement=7 +listOvsElements=7 + #### usage commands generateUsageRecords=1 listUsageRecords=7 diff --git a/engine/schema/src/com/cloud/network/dao/OvsProviderDao.java b/engine/schema/src/com/cloud/network/dao/OvsProviderDao.java new file mode 100644 index 00000000000..b23e3d31f30 --- /dev/null +++ b/engine/schema/src/com/cloud/network/dao/OvsProviderDao.java @@ -0,0 +1,14 @@ +package com.cloud.network.dao; + +import java.util.List; + +import com.cloud.network.element.OvsProviderVO; +import com.cloud.utils.db.GenericDao; + +public interface OvsProviderDao extends GenericDao { + public OvsProviderVO findByNspId(long nspId); + + public List listByEnabled(boolean enabled); + + public OvsProviderVO findByIdAndEnabled(long id, boolean enabled); +} diff --git a/engine/schema/src/com/cloud/network/dao/OvsProviderDaoImpl.java b/engine/schema/src/com/cloud/network/dao/OvsProviderDaoImpl.java new file mode 100644 index 00000000000..b00d5c1e895 --- /dev/null +++ b/engine/schema/src/com/cloud/network/dao/OvsProviderDaoImpl.java @@ -0,0 +1,57 @@ +package com.cloud.network.dao; + +import java.util.List; + +import javax.ejb.Local; + +import org.springframework.stereotype.Component; + +import com.cloud.network.element.OvsProviderVO; +import com.cloud.utils.db.DB; +import com.cloud.utils.db.GenericDaoBase; +import com.cloud.utils.db.SearchBuilder; +import com.cloud.utils.db.SearchCriteria; + +@Component +@Local(value = OvsProviderDao.class) +@DB(txn = false) +public class OvsProviderDaoImpl extends GenericDaoBase + implements OvsProviderDao { + final SearchBuilder AllFieldsSearch; + + public OvsProviderDaoImpl() { + super(); + AllFieldsSearch = createSearchBuilder(); + AllFieldsSearch.and("id", AllFieldsSearch.entity().getId(), + SearchCriteria.Op.EQ); + AllFieldsSearch.and("nsp_id", AllFieldsSearch.entity().getNspId(), + SearchCriteria.Op.EQ); + AllFieldsSearch.and("uuid", AllFieldsSearch.entity().getUuid(), + SearchCriteria.Op.EQ); + AllFieldsSearch.and("enabled", AllFieldsSearch.entity().isEnabled(), + SearchCriteria.Op.EQ); + AllFieldsSearch.done(); + } + + @Override + public OvsProviderVO findByNspId(long nspId) { + SearchCriteria sc = AllFieldsSearch.create(); + sc.setParameters("nsp_id", nspId); + return findOneBy(sc); + } + + @Override + public List listByEnabled(boolean enabled) { + SearchCriteria sc = AllFieldsSearch.create(); + sc.setParameters("enabled", enabled); + return listBy(sc); + } + + @Override + public OvsProviderVO findByIdAndEnabled(long id, boolean enabled) { + SearchCriteria sc = AllFieldsSearch.create(); + sc.setParameters("id", id); + sc.setParameters("enabled", enabled); + return findOneBy(sc); + } +} diff --git a/engine/schema/src/com/cloud/network/element/OvsProviderVO.java b/engine/schema/src/com/cloud/network/element/OvsProviderVO.java new file mode 100644 index 00000000000..bc3455a2bb7 --- /dev/null +++ b/engine/schema/src/com/cloud/network/element/OvsProviderVO.java @@ -0,0 +1,83 @@ +package com.cloud.network.element; + +import java.util.Date; +import java.util.UUID; + +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.GenerationType; +import javax.persistence.Id; +import javax.persistence.Table; + +import com.cloud.network.OvsProvider; +import com.cloud.utils.db.GenericDao; + +@Entity +@Table(name = ("ovs_providers")) +public class OvsProviderVO implements OvsProvider { + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + @Column(name = "id") + long id; + + @Column(name = "nsp_id") + private long nspId; + + @Column(name = "uuid") + private String uuid; + + @Column(name = "enabled") + private boolean enabled; + + @Column(name = GenericDao.REMOVED_COLUMN) + Date removed; + + public OvsProviderVO() { + this.uuid = UUID.randomUUID().toString(); + } + + public OvsProviderVO(long nspId) { + this.nspId = nspId; + this.uuid = UUID.randomUUID().toString(); + } + + @Override + public long getNspId() { + return nspId; + } + + public String getUuid() { + return uuid; + } + + @Override + public long getId() { + return id; + } + + public Date getRemoved() { + return removed; + } + + public void setEnabled(boolean enabled) { + this.enabled = enabled; + } + + @Override + public boolean isEnabled() { + return this.enabled; + } + + public void setId(long id) { + this.id = id; + } + + public void setNspId(long nspId) { + this.nspId = nspId; + } + + public void setUuid(String uuid) { + this.uuid = uuid; + } +} diff --git a/plugins/hypervisors/xen/src/com/cloud/hypervisor/xen/resource/CitrixResourceBase.java b/plugins/hypervisors/xen/src/com/cloud/hypervisor/xen/resource/CitrixResourceBase.java index 25f30f416c7..e0932534a9c 100644 --- a/plugins/hypervisors/xen/src/com/cloud/hypervisor/xen/resource/CitrixResourceBase.java +++ b/plugins/hypervisors/xen/src/com/cloud/hypervisor/xen/resource/CitrixResourceBase.java @@ -156,6 +156,18 @@ import com.cloud.agent.api.ModifyStoragePoolAnswer; import com.cloud.agent.api.ModifyStoragePoolCommand; import com.cloud.agent.api.NetworkRulesSystemVmCommand; import com.cloud.agent.api.NetworkRulesVmSecondaryIpCommand; +import com.cloud.agent.api.OvsCreateGreTunnelCommand; +import com.cloud.agent.api.OvsCreateGreTunnelAnswer; +import com.cloud.agent.api.OvsCreateTunnelCommand; +import com.cloud.agent.api.OvsDestroyTunnelCommand; +import com.cloud.agent.api.OvsSetupBridgeCommand; +import com.cloud.agent.api.OvsDestroyBridgeCommand; +import com.cloud.agent.api.OvsCreateTunnelAnswer; +import com.cloud.agent.api.OvsDeleteFlowCommand; +import com.cloud.agent.api.OvsSetTagAndFlowAnswer; +import com.cloud.agent.api.OvsFetchInterfaceAnswer; +import com.cloud.agent.api.OvsSetTagAndFlowCommand; +import com.cloud.agent.api.OvsFetchInterfaceCommand; import com.cloud.agent.api.PingCommand; import com.cloud.agent.api.PingRoutingCommand; import com.cloud.agent.api.PingRoutingWithNwGroupsCommand; diff --git a/plugins/network-elements/ovs/resources/META-INF/cloudstack/ovs/spring-ovs-context.xml b/plugins/network-elements/ovs/resources/META-INF/cloudstack/ovs/spring-ovs-context.xml index e60d93e08a1..c6012d9d622 100644 --- a/plugins/network-elements/ovs/resources/META-INF/cloudstack/ovs/spring-ovs-context.xml +++ b/plugins/network-elements/ovs/resources/META-INF/cloudstack/ovs/spring-ovs-context.xml @@ -38,5 +38,6 @@ + diff --git a/plugins/network-elements/ovs/src/com/cloud/network/element/OvsElement.java b/plugins/network-elements/ovs/src/com/cloud/network/element/OvsElement.java index 263a214dcef..06965e8f396 100644 --- a/plugins/network-elements/ovs/src/com/cloud/network/element/OvsElement.java +++ b/plugins/network-elements/ovs/src/com/cloud/network/element/OvsElement.java @@ -16,6 +16,7 @@ // under the License. package com.cloud.network.element; +import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -46,6 +47,8 @@ import com.cloud.network.PhysicalNetworkServiceProvider; import com.cloud.network.PublicIpAddress; import com.cloud.network.dao.NetworkServiceMapDao; import com.cloud.network.ovs.OvsTunnelManager; +import com.cloud.network.router.VirtualRouter.Role; +import com.cloud.network.router.VpcVirtualNetworkApplianceManager; import com.cloud.network.rules.PortForwardingRule; import com.cloud.network.rules.StaticNat; import com.cloud.offering.NetworkOffering; @@ -54,9 +57,11 @@ import com.cloud.resource.ResourceStateAdapter; import com.cloud.resource.ServerResource; import com.cloud.resource.UnableDeleteHostException; import com.cloud.utils.component.AdapterBase; +import com.cloud.vm.DomainRouterVO; import com.cloud.vm.NicProfile; import com.cloud.vm.ReservationContext; import com.cloud.vm.VirtualMachineProfile; +import com.cloud.vm.dao.DomainRouterDao; @Local(value = { NetworkElement.class, ConnectivityProvider.class, SourceNatServiceProvider.class, StaticNatServiceProvider.class, @@ -73,6 +78,10 @@ public class OvsElement extends AdapterBase implements NetworkElement, NetworkServiceMapDao _ntwkSrvcDao; @Inject ResourceManager _resourceMgr; + @Inject + DomainRouterDao _routerDao; + @Inject + VpcVirtualNetworkApplianceManager _routerMgr; private static final Logger s_logger = Logger.getLogger(OvsElement.class); private static final Map> capabilities = setCapabilities(); @@ -130,8 +139,6 @@ public class OvsElement extends AdapterBase implements NetworkElement, if (!canHandle(network, Service.Connectivity)) { return false; } - // TODO: implement SourceNat immediately when we code L3 services - return true; } @@ -221,35 +228,35 @@ public class OvsElement extends AdapterBase implements NetworkElement, return false; } - if ((services.contains(Service.PortForwarding) || services - .contains(Service.StaticNat)) - && !services.contains(Service.SourceNat)) { - s_logger.warn("Unable to provide StaticNat and/or PortForwarding without the SourceNat service"); - return false; - } + // if ((services.contains(Service.PortForwarding) || services + // .contains(Service.StaticNat)) + // && !services.contains(Service.SourceNat)) { + // s_logger.warn("Unable to provide StaticNat and/or PortForwarding without the SourceNat service"); + // return false; + // } return true; } private static Map> setCapabilities() { Map> capabilities = new HashMap>(); - // we need L3 support for coding L3 services in next period - // L2 Support : SDN provisioning capabilities.put(Service.Connectivity, null); + // TODO: we need L3 support for coding L3 services in next period // L3 Support : Generic? - capabilities.put(Service.Gateway, null); + // capabilities.put(Service.Gateway, null); // L3 Support : SourceNat - Map sourceNatCapabilities = new HashMap(); - sourceNatCapabilities.put(Capability.SupportedSourceNatTypes, - "peraccount"); - sourceNatCapabilities.put(Capability.RedundantRouter, "false"); - capabilities.put(Service.SourceNat, sourceNatCapabilities); + // Map sourceNatCapabilities = new + // HashMap(); + // sourceNatCapabilities.put(Capability.SupportedSourceNatTypes, + // "peraccount"); + // sourceNatCapabilities.put(Capability.RedundantRouter, "false"); + // capabilities.put(Service.SourceNat, sourceNatCapabilities); // L3 Support : Port Forwarding - capabilities.put(Service.PortForwarding, null); + // capabilities.put(Service.PortForwarding, null); // L3 support : StaticNat capabilities.put(Service.StaticNat, null); @@ -259,7 +266,8 @@ public class OvsElement extends AdapterBase implements NetworkElement, @Override public List> getCommands() { - return null; + List> cmdList = new ArrayList>(); + return cmdList; } @Override @@ -291,24 +299,53 @@ public class OvsElement extends AdapterBase implements NetworkElement, // TODO: Adding L3 services below @Override public IpDeployer getIpDeployer(Network network) { - // TODO Auto-generated method stub - return null; + return this; } @Override public boolean applyIps(Network network, List ipAddress, Set services) throws ResourceUnavailableException { - // TODO Auto-generated method stub - return false; + boolean canHandle = true; + for (Service service : services) { + // check if Ovs can handle services except SourceNat + if (!canHandle(network, service) && service != Service.SourceNat) { + canHandle = false; + break; + } + } + if (canHandle) { + List routers = _routerDao.listByNetworkAndRole( + network.getId(), Role.VIRTUAL_ROUTER); + if (routers == null || routers.isEmpty()) { + s_logger.debug("Virtual router element doesn't need to associate ip addresses on the backend; virtual " + + "router doesn't exist in the network " + + network.getId()); + return true; + } + + return _routerMgr.associatePublicIP(network, ipAddress, routers); + } else { + return false; + } } @Override - public boolean applyStaticNats(Network config, + public boolean applyStaticNats(Network network, List rules) throws ResourceUnavailableException { - // TODO Auto-generated method stub - return false; + if (!canHandle(network, Service.StaticNat)) { + return false; + } + List routers = _routerDao.listByNetworkAndRole( + network.getId(), Role.VIRTUAL_ROUTER); + if (routers == null || routers.isEmpty()) { + s_logger.debug("Ovs element doesn't need to apply static nat on the backend; virtual " + + "router doesn't exist in the network " + network.getId()); + return true; + } + + return _routerMgr.applyStaticNats(network, rules, routers); } @Override diff --git a/plugins/network-elements/ovs/src/com/cloud/network/guru/OvsGuestNetworkGuru.java b/plugins/network-elements/ovs/src/com/cloud/network/guru/OvsGuestNetworkGuru.java index 635aff1b768..939f98a7981 100644 --- a/plugins/network-elements/ovs/src/com/cloud/network/guru/OvsGuestNetworkGuru.java +++ b/plugins/network-elements/ovs/src/com/cloud/network/guru/OvsGuestNetworkGuru.java @@ -91,9 +91,9 @@ public class OvsGuestNetworkGuru extends GuestNetworkGuru { public Network design(NetworkOffering offering, DeploymentPlan plan, Network userSpecified, Account owner) { - if (!_ovsTunnelMgr.isOvsTunnelEnabled()) { - return null; - } + // if (!_ovsTunnelMgr.isOvsTunnelEnabled()) { + // return null; + // } PhysicalNetworkVO physnet = _physicalNetworkDao.findById(plan .getPhysicalNetworkId()); DataCenter dc = _dcDao.findById(plan.getDataCenterId()); @@ -118,10 +118,11 @@ public class OvsGuestNetworkGuru extends GuestNetworkGuru { throws InsufficientVirtualNetworkCapcityException { assert (network.getState() == State.Implementing) : "Why are we implementing " + network; - if (!_ovsTunnelMgr.isOvsTunnelEnabled()) { - return null; - } + // if (!_ovsTunnelMgr.isOvsTunnelEnabled()) { + // return null; + // } long dcId = dest.getDataCenter().getId(); + NetworkType nwType = dest.getDataCenter().getNetworkType(); // get physical network id Long physicalNetworkId = network.getPhysicalNetworkId(); // physical network id can be null in Guest Network in Basic zone, so @@ -130,6 +131,13 @@ public class OvsGuestNetworkGuru extends GuestNetworkGuru { physicalNetworkId = _networkModel.findPhysicalNetworkId(dcId, offering.getTags(), offering.getTrafficType()); } + PhysicalNetworkVO physnet = _physicalNetworkDao + .findById(physicalNetworkId); + + if (!canHandle(offering, nwType, physnet)) { + s_logger.debug("Refusing to design this network"); + return null; + } NetworkVO implemented = (NetworkVO) super.implement(network, offering, dest, context); diff --git a/plugins/network-elements/ovs/src/com/cloud/network/ovs/OvsTunnelManagerImpl.java b/plugins/network-elements/ovs/src/com/cloud/network/ovs/OvsTunnelManagerImpl.java index 81518fbeef5..a03055f6340 100644 --- a/plugins/network-elements/ovs/src/com/cloud/network/ovs/OvsTunnelManagerImpl.java +++ b/plugins/network-elements/ovs/src/com/cloud/network/ovs/OvsTunnelManagerImpl.java @@ -19,7 +19,6 @@ package com.cloud.network.ovs; import java.util.ArrayList; import java.util.List; import java.util.Map; -import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; import javax.ejb.Local; @@ -61,7 +60,6 @@ import com.cloud.network.ovs.dao.OvsTunnelInterfaceVO; import com.cloud.network.ovs.dao.OvsTunnelNetworkDao; import com.cloud.network.ovs.dao.OvsTunnelNetworkVO; import com.cloud.utils.component.ManagerBase; -import com.cloud.utils.concurrency.NamedThreadFactory; import com.cloud.utils.db.DB; import com.cloud.utils.exception.CloudRuntimeException; import com.cloud.vm.DomainRouterVO; @@ -79,32 +77,94 @@ import com.cloud.vm.dao.UserVmDao; public class OvsTunnelManagerImpl extends ManagerBase implements OvsTunnelManager { public static final Logger s_logger = Logger.getLogger(OvsTunnelManagerImpl.class.getName()); - boolean _isEnabled; - ScheduledExecutorService _executorPool; + // boolean _isEnabled; + ScheduledExecutorService _executorPool; ScheduledExecutorService _cleanupExecutor; - @Inject - ConfigurationDao _configDao; - @Inject - NicDao _nicDao; - @Inject - HostDao _hostDao; - @Inject - PhysicalNetworkTrafficTypeDao _physNetTTDao; - @Inject - UserVmDao _userVmDao; - @Inject - DomainRouterDao _routerDao; - @Inject - OvsTunnelNetworkDao _tunnelNetworkDao; - @Inject - OvsTunnelInterfaceDao _tunnelInterfaceDao; - @Inject - AgentManager _agentMgr; + @Inject ConfigurationDao _configDao; + @Inject NicDao _nicDao; + @Inject HostDao _hostDao; + @Inject PhysicalNetworkTrafficTypeDao _physNetTTDao; + @Inject UserVmDao _userVmDao; + @Inject DomainRouterDao _routerDao; + @Inject OvsTunnelNetworkDao _tunnelNetworkDao; + @Inject OvsTunnelInterfaceDao _tunnelInterfaceDao; + @Inject AgentManager _agentMgr; - @Override - public boolean configure(String name, Map params) throws ConfigurationException { - _isEnabled = Boolean.parseBoolean(_configDao.getValue(Config.OvsTunnelNetwork.key())); + @Override + public boolean configure(String name, Map params) + throws ConfigurationException { + // _isEnabled = + // Boolean.parseBoolean(_configDao.getValue(Config.OvsTunnelNetwork.key())); + // + // if (_isEnabled) { + // _executorPool = Executors.newScheduledThreadPool(10, new + // NamedThreadFactory("OVS")); + // _cleanupExecutor = Executors.newScheduledThreadPool(1, new + // NamedThreadFactory("OVS-Cleanup")); + // } + + return true; + } + + @DB + protected OvsTunnelNetworkVO createTunnelRecord(long from, long to, long networkId, int key) { + OvsTunnelNetworkVO ta = null; + try { + ta = new OvsTunnelNetworkVO(from, to, key, networkId); + OvsTunnelNetworkVO lock = + _tunnelNetworkDao.acquireInLockTable(Long.valueOf(1)); + if (lock == null) { + s_logger.warn("Cannot lock table ovs_tunnel_account"); + return null; + } + _tunnelNetworkDao.persist(ta); + _tunnelNetworkDao.releaseFromLockTable(lock.getId()); + } catch (EntityExistsException e) { + s_logger.debug("A record for the tunnel from " + from + + " to " + to + " already exists"); + } + return ta; + } + + @DB + protected OvsTunnelInterfaceVO createInterfaceRecord(String ip, + String netmask,String mac,long hostId, String label) { + OvsTunnelInterfaceVO ti = null; + try { + ti = new OvsTunnelInterfaceVO(ip, netmask, mac, hostId, label); + //TODO: Is locking really necessary here? + OvsTunnelInterfaceVO lock = + _tunnelInterfaceDao.acquireInLockTable(Long.valueOf(1)); + if (lock == null) { + s_logger.warn("Cannot lock table ovs_tunnel_account"); + return null; + } + _tunnelInterfaceDao.persist(ti); + _tunnelInterfaceDao.releaseFromLockTable(lock.getId()); + } catch (EntityExistsException e) { + s_logger.debug("A record for the interface for network " + label + + " on host id " + hostId + " already exists"); + } + return ti; + } + + private String handleFetchInterfaceAnswer(Answer[] answers, Long hostId){ + OvsFetchInterfaceAnswer ans = (OvsFetchInterfaceAnswer) answers[0]; + if (ans.getResult()) { + if (ans.getIp() != null && + !("".equals(ans.getIp()))) { + OvsTunnelInterfaceVO ti = + createInterfaceRecord(ans.getIp(), ans.getNetmask(), + ans.getMac(), hostId, ans.getLabel()); + return ti.getIp(); + } + } + // Fetch interface failed! + s_logger.warn("Unable to fetch the IP address for the GRE tunnel endpoint" + + ans.getDetails()); + return null; + } if (_isEnabled) { _executorPool = Executors.newScheduledThreadPool(10, new NamedThreadFactory("OVS")); @@ -174,47 +234,61 @@ public class OvsTunnelManagerImpl extends ManagerBase implements OvsTunnelManage long networkId = r.getNetworkId(); OvsTunnelNetworkVO tunnel = _tunnelNetworkDao.getByFromToNetwork(from, to, networkId); if (tunnel == null) { - throw new CloudRuntimeException(String.format("Unable find tunnelNetwork record" + "(from=%1$s,to=%2$s, account=%3$s", from, to, networkId)); - } - if (!r.getResult()) { - tunnel.setState("FAILED"); - s_logger.warn("Create GRE tunnel failed due to " + r.getDetails() + s); - } else { - tunnel.setState("SUCCESS"); - tunnel.setPortName(r.getInPortName()); - s_logger.warn("Create GRE tunnel " + r.getDetails() + s); - } - _tunnelNetworkDao.update(tunnel.getId(), tunnel); - } + throw new CloudRuntimeException( + String.format("Unable find tunnelNetwork record" + + "(from=%1$s,to=%2$s, account=%3$s", + from, to, networkId)); + } + if (!r.getResult()) { + tunnel.setState("FAILED"); + s_logger.warn("Create GRE tunnel failed due to " + + r.getDetails() + s); + } else { + tunnel.setState("SUCCESS"); + tunnel.setPortName(r.getInPortName()); + s_logger.warn("Create GRE tunnel " + + r.getDetails() + s); + } + _tunnelNetworkDao.update(tunnel.getId(), tunnel); + } - private String getGreEndpointIP(Host host, Network nw) throws AgentUnavailableException, OperationTimedoutException { - String endpointIp = null; - // Fetch fefault name for network label from configuration - String physNetLabel = _configDao.getValue(Config.OvsTunnelNetworkDefaultLabel.key()); + private String getGreEndpointIP(Host host, Network nw) throws + AgentUnavailableException, OperationTimedoutException { + String endpointIp = null; + // Fetch fefault name for network label from configuration + String physNetLabel = _configDao.getValue(Config.OvsTunnelNetworkDefaultLabel.key()); Long physNetId = nw.getPhysicalNetworkId(); - PhysicalNetworkTrafficType physNetTT = _physNetTTDao.findBy(physNetId, TrafficType.Guest); + PhysicalNetworkTrafficType physNetTT = + _physNetTTDao.findBy(physNetId, TrafficType.Guest); HypervisorType hvType = host.getHypervisorType(); switch (hvType) { - case XenServer: - String label = physNetTT.getXenNetworkLabel(); - if ((label != null) && (!label.equals(""))) { - physNetLabel = label; - } - break; - default: - throw new CloudRuntimeException("Hypervisor " + hvType.toString() + " unsupported by OVS Tunnel Manager"); + case XenServer: + String label = physNetTT.getXenNetworkLabel(); + if ((label!=null) && (!label.equals(""))) { + physNetLabel = label; + } + break; + default: + throw new CloudRuntimeException("Hypervisor " + + hvType.toString() + + " unsupported by OVS Tunnel Manager"); } // Try to fetch GRE endpoint IP address for cloud db // If not found, then find it on the hypervisor - OvsTunnelInterfaceVO tunnelIface = _tunnelInterfaceDao.getByHostAndLabel(host.getId(), physNetLabel); + OvsTunnelInterfaceVO tunnelIface = + _tunnelInterfaceDao.getByHostAndLabel(host.getId(), + physNetLabel); if (tunnelIface == null) { //Now find and fetch configuration for physical interface - //for network with label on target host - Commands fetchIfaceCmds = new Commands(new OvsFetchInterfaceCommand(physNetLabel)); - s_logger.debug("Ask host " + host.getId() + " to retrieve interface for phy net with label:" + physNetLabel); - Answer[] fetchIfaceAnswers = _agentMgr.send(host.getId(), fetchIfaceCmds); + //for network with label on target host + Commands fetchIfaceCmds = + new Commands(new OvsFetchInterfaceCommand(physNetLabel)); + s_logger.debug("Ask host " + host.getId() + + " to retrieve interface for phy net with label:" + + physNetLabel); + Answer[] fetchIfaceAnswers = _agentMgr.send(host.getId(), fetchIfaceCmds); //And finally save it for future use endpointIp = handleFetchInterfaceAnswer(fetchIfaceAnswers, host.getId()); } else { @@ -223,51 +297,59 @@ public class OvsTunnelManagerImpl extends ManagerBase implements OvsTunnelManage return endpointIp; } - private int getGreKey(Network network) { - int key = 0; - try { - //The GRE key is actually in the host part of the URI + private int getGreKey(Network network) { + int key = 0; + try { + //The GRE key is actually in the host part of the URI // this is not true for lswitch/NiciraNvp! String keyStr = BroadcastDomainType.getValue(network.getBroadcastUri()); // The key is most certainly and int if network is a vlan. // !! not in the case of lswitch/pvlan/(possibly)vswitch // So we now feel quite safe in converting it into a string // by calling the appropriate BroadcastDomainType method - key = Integer.valueOf(keyStr); - return key; - } catch (NumberFormatException e) { - s_logger.debug("Well well, how did '" + key + "' end up in the broadcast URI for the network?"); - throw new CloudRuntimeException(String.format("Invalid GRE key parsed from" + "network broadcast URI (%s)", network.getBroadcastUri().toString())); - } - } + key = Integer.valueOf(keyStr); + return key; + } catch (NumberFormatException e) { + s_logger.debug("Well well, how did '" + key + + "' end up in the broadcast URI for the network?"); + throw new CloudRuntimeException( + String.format("Invalid GRE key parsed from" + + "network broadcast URI (%s)", + network.getBroadcastUri().toString())); + } + } - @DB + @DB protected void CheckAndCreateTunnel(VirtualMachine instance, Network nw, DeployDestination dest) { - if (!_isEnabled) { - return; - } + // if (!_isEnabled) { + // return; + // } - s_logger.debug("Creating tunnels with OVS tunnel manager"); - if (instance.getType() != VirtualMachine.Type.User && instance.getType() != VirtualMachine.Type.DomainRouter) { - s_logger.debug("Will not work if you're not" + "an instance or a virtual router"); - return; - } + s_logger.debug("Creating tunnels with OVS tunnel manager"); + if (instance.getType() != VirtualMachine.Type.User + && instance.getType() != VirtualMachine.Type.DomainRouter) { + s_logger.debug("Will not work if you're not" + + "an instance or a virtual router"); + return; + } - long hostId = dest.getHost().getId(); - int key = getGreKey(nw); - // Find active VMs with a NIC on the target network - List vms = _userVmDao.listByNetworkIdAndStates(nw.getId(), State.Running, State.Starting, State.Stopping, State.Unknown, State.Migrating); - // Find routers for the network - List routers = _routerDao.findByNetwork(nw.getId()); - List ins = new ArrayList(); - if (vms != null) { - ins.addAll(vms); - } - if (routers.size() != 0) { - ins.addAll(routers); - } - List toHostIds = new ArrayList(); - List fromHostIds = new ArrayList(); + long hostId = dest.getHost().getId(); + int key = getGreKey(nw); + // Find active VMs with a NIC on the target network + List vms = _userVmDao.listByNetworkIdAndStates(nw.getId(), + State.Running, State.Starting, + State.Stopping, State.Unknown, State.Migrating); + // Find routers for the network + List routers = _routerDao.findByNetwork(nw.getId()); + Listins = new ArrayList(); + if (vms != null) { + ins.addAll(vms); + } + if (routers.size() != 0) { + ins.addAll(routers); + } + List toHostIds = new ArrayList(); + List fromHostIds = new ArrayList(); for (VMInstanceVO v : ins) { Long rh = v.getHostId(); if (rh == null || rh.longValue() == hostId) { @@ -285,13 +367,16 @@ public class OvsTunnelManagerImpl extends ManagerBase implements OvsTunnelManage } } - ta = _tunnelNetworkDao.getByFromToNetwork(rh.longValue(), hostId, nw.getId()); + ta = _tunnelNetworkDao.getByFromToNetwork(rh.longValue(), + hostId, nw.getId()); // Try and create the tunnel even if a previous attempt failed if (ta == null || ta.getState().equals("FAILED")) { - s_logger.debug("Attempting to create tunnel from:" + rh.longValue() + " to:" + hostId); - if (ta == null) { - this.createTunnelRecord(rh.longValue(), hostId, nw.getId(), key); - } + s_logger.debug("Attempting to create tunnel from:" + + rh.longValue() + " to:" + hostId); + if (ta == null) { + this.createTunnelRecord(rh.longValue(), hostId, + nw.getId(), key); + } if (!fromHostIds.contains(rh)) { fromHostIds.add(rh); } @@ -303,48 +388,62 @@ public class OvsTunnelManagerImpl extends ManagerBase implements OvsTunnelManage if (myIp == null) throw new GreTunnelException("Unable to retrieve the source " + "endpoint for the GRE tunnel." + "Failure is on host:" + dest.getHost().getId()); boolean noHost = true; - for (Long i : toHostIds) { - HostVO rHost = _hostDao.findById(i); - String otherIp = getGreEndpointIP(rHost, nw); - if (otherIp == null) - throw new GreTunnelException("Unable to retrieve the remote " + "endpoint for the GRE tunnel." + "Failure is on host:" + rHost.getId()); - Commands cmds = new Commands(new OvsCreateTunnelCommand(otherIp, key, Long.valueOf(hostId), i, nw.getId(), myIp)); - s_logger.debug("Ask host " + hostId + " to create gre tunnel to " + i); - Answer[] answers = _agentMgr.send(hostId, cmds); - handleCreateTunnelAnswer(answers); - noHost = false; - } + for (Long i : toHostIds) { + HostVO rHost = _hostDao.findById(i); + String otherIp = getGreEndpointIP(rHost, nw); + if (otherIp == null) + throw new GreTunnelException("Unable to retrieve the remote " + + "endpoint for the GRE tunnel." + + "Failure is on host:" + rHost.getId()); + Commands cmds = new Commands( + new OvsCreateTunnelCommand(otherIp, key, + Long.valueOf(hostId), i, nw.getId(), myIp)); + s_logger.debug("Ask host " + hostId + + " to create gre tunnel to " + i); + Answer[] answers = _agentMgr.send(hostId, cmds); + handleCreateTunnelAnswer(answers); + noHost = false; + } - for (Long i : fromHostIds) { - HostVO rHost = _hostDao.findById(i); - String otherIp = getGreEndpointIP(rHost, nw); - Commands cmds = new Commands(new OvsCreateTunnelCommand(myIp, key, i, Long.valueOf(hostId), nw.getId(), otherIp)); - s_logger.debug("Ask host " + i + " to create gre tunnel to " + hostId); - Answer[] answers = _agentMgr.send(i, cmds); - handleCreateTunnelAnswer(answers); - noHost = false; - } - // If no tunnels have been configured, perform the bridge setup anyway - // This will ensure VIF rules will be triggered - if (noHost) { - Commands cmds = new Commands(new OvsSetupBridgeCommand(key, hostId, nw.getId())); - s_logger.debug("Ask host " + hostId + " to configure bridge for network:" + nw.getId()); - Answer[] answers = _agentMgr.send(hostId, cmds); - handleSetupBridgeAnswer(answers); - } - } catch (Exception e) { - // I really thing we should do a better handling of these exceptions - s_logger.warn("Ovs Tunnel network created tunnel failed", e); - } - } + for (Long i : fromHostIds) { + HostVO rHost = _hostDao.findById(i); + String otherIp = getGreEndpointIP(rHost, nw); + Commands cmds = new Commands( + new OvsCreateTunnelCommand(myIp, key, i, + Long.valueOf(hostId), + nw.getId(), otherIp)); + s_logger.debug("Ask host " + i + + " to create gre tunnel to " + hostId); + Answer[] answers = _agentMgr.send(i, cmds); + handleCreateTunnelAnswer(answers); + noHost = false; + } + // If no tunnels have been configured, perform the bridge setup anyway + // This will ensure VIF rules will be triggered + if (noHost) { + Commands cmds = new Commands( + new OvsSetupBridgeCommand(key, hostId, nw.getId())); + s_logger.debug("Ask host " + hostId + + " to configure bridge for network:" + nw.getId()); + Answer[] answers = _agentMgr.send(hostId, cmds); + handleSetupBridgeAnswer(answers); + } + } catch (Exception e) { + // I really thing we should do a better handling of these exceptions + s_logger.warn("Ovs Tunnel network created tunnel failed", e); + } + } + + @Override + public boolean isOvsTunnelEnabled() { + // return _isEnabled; + return true; + } @Override - public boolean isOvsTunnelEnabled() { - return _isEnabled; - } - - @Override - public void VmCheckAndCreateTunnel(VirtualMachineProfile vm, Network nw, DeployDestination dest) { + public void VmCheckAndCreateTunnel( + VirtualMachineProfile vm, + Network nw, DeployDestination dest) { CheckAndCreateTunnel(vm.getVirtualMachine(), nw, dest); } @@ -353,22 +452,27 @@ public class OvsTunnelManagerImpl extends ManagerBase implements OvsTunnelManage if (ans.getResult()) { OvsTunnelNetworkVO lock = _tunnelNetworkDao.acquireInLockTable(Long.valueOf(1)); if (lock == null) { - s_logger.warn(String.format("failed to lock" + "ovs_tunnel_account, remove record of " + "tunnel(from=%1$s, to=%2$s account=%3$s) failed", from, to, - network_id)); + s_logger.warn(String.format("failed to lock" + + "ovs_tunnel_account, remove record of " + + "tunnel(from=%1$s, to=%2$s account=%3$s) failed", + from, to, network_id)); return; } _tunnelNetworkDao.removeByFromToNetwork(from, to, network_id); _tunnelNetworkDao.releaseFromLockTable(lock.getId()); - s_logger.debug(String.format("Destroy tunnel(account:%1$s," + "from:%2$s, to:%3$s) successful", network_id, from, to)); + s_logger.debug(String.format("Destroy tunnel(account:%1$s," + + "from:%2$s, to:%3$s) successful", + network_id, from, to)); } else { s_logger.debug(String.format("Destroy tunnel(account:%1$s," + "from:%2$s, to:%3$s) failed", network_id, from, to)); } } @DB - private void handleDestroyBridgeAnswer(Answer ans, long host_id, long network_id) { + private void handleDestroyBridgeAnswer(Answer ans, + long host_id, long network_id) { if (ans.getResult()) { OvsTunnelNetworkVO lock = _tunnelNetworkDao.acquireInLockTable(Long.valueOf(1)); @@ -380,9 +484,11 @@ public class OvsTunnelManagerImpl extends ManagerBase implements OvsTunnelManage _tunnelNetworkDao.removeByFromNetwork(host_id, network_id); _tunnelNetworkDao.releaseFromLockTable(lock.getId()); - s_logger.debug(String.format("Destroy bridge for" + "network %1$s successful", network_id)); + s_logger.debug(String.format("Destroy bridge for" + + "network %1$s successful", network_id)); } else { - s_logger.debug(String.format("Destroy bridge for" + "network %1$s failed", network_id)); + s_logger.debug(String.format("Destroy bridge for" + + "network %1$s failed", network_id)); } } @@ -393,9 +499,9 @@ public class OvsTunnelManagerImpl extends ManagerBase implements OvsTunnelManage @Override public void CheckAndDestroyTunnel(VirtualMachine vm, Network nw) { - if (!_isEnabled) { - return; - } + // if (!_isEnabled) { + // return; + // } List userVms = _userVmDao.listByAccountIdAndHostId(vm.getAccountId(), vm.getHostId()); if (vm.getType() == VirtualMachine.Type.User) { @@ -422,15 +528,20 @@ public class OvsTunnelManagerImpl extends ManagerBase implements OvsTunnelManage handleDestroyBridgeAnswer(ans, vm.getHostId(), nw.getId()); /* Then ask hosts have peer tunnel with me to destroy them */ - List peers = _tunnelNetworkDao.listByToNetwork(vm.getHostId(), nw.getId()); + List peers = + _tunnelNetworkDao.listByToNetwork(vm.getHostId(), + nw.getId()); for (OvsTunnelNetworkVO p : peers) { - // If the tunnel was not successfully created don't bother to remove it - if (p.getState().equals("SUCCESS")) { - cmd = new OvsDestroyTunnelCommand(p.getNetworkId(), key, p.getPortName()); - s_logger.debug("Destroying tunnel to " + vm.getHostId() + " from " + p.getFrom()); - ans = _agentMgr.send(p.getFrom(), cmd); - handleDestroyTunnelAnswer(ans, p.getFrom(), p.getTo(), p.getNetworkId()); - } + // If the tunnel was not successfully created don't bother to remove it + if (p.getState().equals("SUCCESS")) { + cmd = new OvsDestroyTunnelCommand(p.getNetworkId(), key, + p.getPortName()); + s_logger.debug("Destroying tunnel to " + vm.getHostId() + + " from " + p.getFrom()); + ans = _agentMgr.send(p.getFrom(), cmd); + handleDestroyTunnelAnswer(ans, p.getFrom(), + p.getTo(), p.getNetworkId()); + } } } catch (Exception e) { s_logger.warn(String.format("Destroy tunnel(account:%1$s," + "hostId:%2$s) failed", vm.getAccountId(), vm.getHostId()), e); diff --git a/scripts/vm/hypervisor/xenserver/ovstunnel b/scripts/vm/hypervisor/xenserver/ovstunnel index a4760b2f89e..2b26ed6c0bf 100755 --- a/scripts/vm/hypervisor/xenserver/ovstunnel +++ b/scripts/vm/hypervisor/xenserver/ovstunnel @@ -271,17 +271,23 @@ def is_xcp(session, args): return platform def getLabel(session, args): + i = 0 pif_list_cmd = [lib.XE_PATH, 'pif-list', '--minimal'] pif_list_str = lib.do_cmd(pif_list_cmd) - pif_uuid = pif_list_str.split(',')[0].strip() - network_cmd = [lib.XE_PATH, 'pif-param-get', 'uuid=%s' % pif_uuid, - 'param-name=network-uuid'] - network_uuid = lib.do_cmd(network_cmd).split('.')[0] - - label_cmd = [lib.XE_PATH, 'network-param-get', 'uuid=%s' % network_uuid, - 'param-name=name-label'] - label = lib.do_cmd(label_cmd).split('.')[0] - return label + while True: + pif_uuid = pif_list_str.split(',')[i].strip() + network_cmd = [lib.XE_PATH, 'pif-param-get', 'uuid=%s' % pif_uuid, 'param-name=network-uuid'] + network_uuid = lib.do_cmd(network_cmd).split('.')[0] + iface_cmd = [lib.XE_PATH, 'network-param-get', 'uuid=%s' % network_uuid, 'param-name=bridge'] + iface = lib.do_cmd(iface_cmd) + status,output = commands.getstatusoutput("ifconfig "+iface+" | grep inet") + if (status != 0): + i += 1 + continue + label_cmd = [lib.XE_PATH, 'network-param-get', 'uuid=%s' % network_uuid, 'param-name=name-label'] + label = lib.do_cmd(label_cmd).split('.')[0] + return label + return False if __name__ == "__main__": XenAPIPlugin.dispatch({"create_tunnel": create_tunnel, diff --git a/scripts/vm/hypervisor/xenserver/vhd-util b/scripts/vm/hypervisor/xenserver/vhd-util new file mode 100755 index 00000000000..46d62dd44d9 Binary files /dev/null and b/scripts/vm/hypervisor/xenserver/vhd-util differ diff --git a/server/src/com/cloud/api/ApiResponseHelper.java b/server/src/com/cloud/api/ApiResponseHelper.java index 9700b26ef3c..c2a049145af 100755 --- a/server/src/com/cloud/api/ApiResponseHelper.java +++ b/server/src/com/cloud/api/ApiResponseHelper.java @@ -89,6 +89,7 @@ import org.apache.cloudstack.api.response.NetworkOfferingResponse; import org.apache.cloudstack.api.response.NetworkResponse; import org.apache.cloudstack.api.response.NicResponse; import org.apache.cloudstack.api.response.NicSecondaryIpResponse; +import org.apache.cloudstack.api.response.OvsProviderResponse; import org.apache.cloudstack.api.response.PhysicalNetworkResponse; import org.apache.cloudstack.api.response.PodResponse; import org.apache.cloudstack.api.response.PortableIpRangeResponse; @@ -206,6 +207,7 @@ import com.cloud.network.NetworkProfile; import com.cloud.network.Networks.BroadcastDomainType; import com.cloud.network.Networks.IsolationType; import com.cloud.network.Networks.TrafficType; +import com.cloud.network.OvsProvider; import com.cloud.network.PhysicalNetwork; import com.cloud.network.PhysicalNetworkServiceProvider; import com.cloud.network.PhysicalNetworkTrafficType; @@ -270,6 +272,7 @@ import com.cloud.storage.Snapshot; import com.cloud.storage.SnapshotVO; import com.cloud.storage.Storage.StoragePoolType; import com.cloud.storage.StoragePool; +import com.cloud.storage.Swift; import com.cloud.storage.Upload; import com.cloud.storage.UploadVO; import com.cloud.storage.VMTemplateVO; @@ -2726,6 +2729,22 @@ public class ApiResponseHelper implements ResponseGenerator { return response; } + @Override + public OvsProviderResponse createOvsProviderResponse(OvsProvider result) { + + OvsProviderResponse response = new OvsProviderResponse(); + response.setId(result.getUuid()); + PhysicalNetworkServiceProvider nsp = ApiDBUtils + .findPhysicalNetworkServiceProviderById(result.getNspId()); + if (nsp != null) { + response.setNspId(nsp.getUuid()); + } + response.setEnabled(result.isEnabled()); + + response.setObjectName("ovselement"); + return response; + } + @Override public LBStickinessResponse createLBStickinessPolicyResponse(StickinessPolicy stickinessPolicy, LoadBalancer lb) { LBStickinessResponse spResponse = new LBStickinessResponse(); diff --git a/server/src/com/cloud/network/NetworkServiceImpl.java b/server/src/com/cloud/network/NetworkServiceImpl.java index 6855587c36b..c24b650108c 100755 --- a/server/src/com/cloud/network/NetworkServiceImpl.java +++ b/server/src/com/cloud/network/NetworkServiceImpl.java @@ -19,6 +19,7 @@ package com.cloud.network; import java.net.Inet6Address; import java.net.InetAddress; import java.net.URI; + import java.net.UnknownHostException; import java.security.InvalidParameterException; import java.sql.PreparedStatement; @@ -109,6 +110,7 @@ import com.cloud.network.dao.NetworkDomainDao; import com.cloud.network.dao.NetworkDomainVO; import com.cloud.network.dao.NetworkServiceMapDao; import com.cloud.network.dao.NetworkVO; +import com.cloud.network.dao.OvsProviderDao; import com.cloud.network.dao.PhysicalNetworkDao; import com.cloud.network.dao.PhysicalNetworkServiceProviderDao; import com.cloud.network.dao.PhysicalNetworkServiceProviderVO; @@ -116,6 +118,7 @@ import com.cloud.network.dao.PhysicalNetworkTrafficTypeDao; import com.cloud.network.dao.PhysicalNetworkTrafficTypeVO; import com.cloud.network.dao.PhysicalNetworkVO; import com.cloud.network.element.NetworkElement; +import com.cloud.network.element.OvsProviderVO; import com.cloud.network.element.VirtualRouterElement; import com.cloud.network.element.VpcVirtualRouterElement; import com.cloud.network.guru.NetworkGuru; @@ -298,10 +301,8 @@ public class NetworkServiceImpl extends ManagerBase implements NetworkService { VpcDao _vpcDao; @Inject NetworkACLDao _networkACLDao; - @Inject - IpAddressManager _ipAddrMgr; - @Inject - EntityManager _entityMgr; + @Inject + OvsProviderDao _ovsProviderDao; int _cidrLimit; boolean _allowSubdomainNetworkAccess; @@ -2511,6 +2512,9 @@ public class NetworkServiceImpl extends ManagerBase implements NetworkService { // add VirtualRouter as the default network service provider addDefaultVirtualRouterToPhysicalNetwork(pNetwork.getId()); + if (pNetwork.getIsolationMethods().contains("GRE")) + addDefaultOvsToPhysicalNetwork(pNetwork.getId()); + // add security group provider to the physical network addDefaultSecurityGroupProviderToPhysicalNetwork(pNetwork.getId()); @@ -2532,7 +2536,7 @@ public class NetworkServiceImpl extends ManagerBase implements NetworkService { } } - @Override + @Override public Pair, Integer> searchPhysicalNetworks(Long id, Long zoneId, String keyword, Long startIndex, Long pageSize, String name) { Filter searchFilter = new Filter(PhysicalNetworkVO.class, "id", Boolean.TRUE, startIndex, pageSize); SearchCriteria sc = _physicalNetworkDao.createSearchCriteria(); @@ -3756,6 +3760,23 @@ public class NetworkServiceImpl extends ManagerBase implements NetworkService { return nsp; } + private PhysicalNetworkServiceProvider addDefaultOvsToPhysicalNetwork(long physicalNetworkId) { + PhysicalNetworkServiceProvider nsp = addProviderToPhysicalNetwork(physicalNetworkId, Network.Provider.Ovs.getName(), null, null); + NetworkElement networkElement = _networkModel.getElementImplementingProvider(Network.Provider.Ovs.getName()); + if (networkElement == null) { + throw new CloudRuntimeException("Unable to find the Network Element implementing the Ovs Provider"); + } + OvsProviderVO element = _ovsProviderDao.findByNspId(nsp.getId()); + if (element != null) { + s_logger.debug("There is already a Ovs element with service provider id " + + nsp.getId()); + return nsp; + } + element = new OvsProviderVO(nsp.getId()); + _ovsProviderDao.persist(element); + return nsp; + } + protected PhysicalNetworkServiceProvider addDefaultVpcVirtualRouterToPhysicalNetwork(long physicalNetworkId) { PhysicalNetworkServiceProvider nsp = addProviderToPhysicalNetwork(physicalNetworkId, Network.Provider.VPCVirtualRouter.getName(), null, null); diff --git a/server/src/com/cloud/network/element/VirtualRouterElement.java b/server/src/com/cloud/network/element/VirtualRouterElement.java index bcd4ce2082a..923094ba301 100755 --- a/server/src/com/cloud/network/element/VirtualRouterElement.java +++ b/server/src/com/cloud/network/element/VirtualRouterElement.java @@ -29,8 +29,10 @@ import org.apache.log4j.Logger; import com.google.gson.Gson; +import org.apache.cloudstack.api.command.admin.router.ConfigureOvsElementCmd; import org.apache.cloudstack.api.command.admin.router.ConfigureVirtualRouterElementCmd; import org.apache.cloudstack.api.command.admin.router.CreateVirtualRouterElementCmd; +import org.apache.cloudstack.api.command.admin.router.ListOvsElementsCmd; import org.apache.cloudstack.api.command.admin.router.ListVirtualRouterElementsCmd; import org.apache.cloudstack.framework.config.dao.ConfigurationDao; @@ -53,6 +55,7 @@ import com.cloud.network.NetworkMigrationResponder; import com.cloud.network.NetworkModel; import com.cloud.network.Networks; import com.cloud.network.Networks.TrafficType; +import com.cloud.network.OvsProvider; import com.cloud.network.PhysicalNetworkServiceProvider; import com.cloud.network.PublicIpAddress; import com.cloud.network.RemoteAccessVpn; @@ -62,6 +65,7 @@ import com.cloud.network.VpnUser; import com.cloud.network.dao.IPAddressDao; import com.cloud.network.dao.LoadBalancerDao; import com.cloud.network.dao.NetworkDao; +import com.cloud.network.dao.OvsProviderDao; import com.cloud.network.dao.VirtualRouterProviderDao; import com.cloud.network.lb.LoadBalancingRule; import com.cloud.network.lb.LoadBalancingRule.LbStickinessPolicy; @@ -96,10 +100,16 @@ import com.cloud.vm.VirtualMachineProfile; import com.cloud.vm.dao.DomainRouterDao; import com.cloud.vm.dao.UserVmDao; -@Local(value = {NetworkElement.class, FirewallServiceProvider.class, DhcpServiceProvider.class, UserDataServiceProvider.class, StaticNatServiceProvider.class, - LoadBalancingServiceProvider.class, PortForwardingServiceProvider.class, IpDeployer.class, RemoteAccessVPNServiceProvider.class, NetworkMigrationResponder.class}) -public class VirtualRouterElement extends AdapterBase implements VirtualRouterElementService, DhcpServiceProvider, UserDataServiceProvider, SourceNatServiceProvider, - StaticNatServiceProvider, FirewallServiceProvider, LoadBalancingServiceProvider, PortForwardingServiceProvider, RemoteAccessVPNServiceProvider, IpDeployer, +import com.google.gson.Gson; + +@Local(value = {NetworkElement.class, FirewallServiceProvider.class, + DhcpServiceProvider.class, UserDataServiceProvider.class, + StaticNatServiceProvider.class, LoadBalancingServiceProvider.class, + PortForwardingServiceProvider.class, IpDeployer.class, + RemoteAccessVPNServiceProvider.class, NetworkMigrationResponder.class} ) +public class VirtualRouterElement extends AdapterBase implements VirtualRouterElementService, DhcpServiceProvider, + UserDataServiceProvider, SourceNatServiceProvider, StaticNatServiceProvider, FirewallServiceProvider, + LoadBalancingServiceProvider, PortForwardingServiceProvider, RemoteAccessVPNServiceProvider, IpDeployer, NetworkMigrationResponder { private static final Logger s_logger = Logger.getLogger(VirtualRouterElement.class); @@ -137,6 +147,8 @@ public class VirtualRouterElement extends AdapterBase implements VirtualRouterEl @Inject VirtualRouterProviderDao _vrProviderDao; @Inject + OvsProviderDao _ovsProviderDao; + @Inject IPAddressDao _ipAddressDao; protected boolean canHandle(Network network, Service service) { @@ -712,6 +724,21 @@ public class VirtualRouterElement extends AdapterBase implements VirtualRouterEl return element; } + @Override + public OvsProvider configure(ConfigureOvsElementCmd cmd) { + OvsProviderVO element = _ovsProviderDao.findById(cmd.getId()); + if (element == null) { + s_logger.debug("Can't find Ovs element with network service provider id " + + cmd.getId()); + return null; + } + + element.setEnabled(cmd.getEnabled()); + _ovsProviderDao.persist(element); + + return element; + } + @Override public VirtualRouterProvider addElement(Long nspId, Type providerType) { if (!(providerType == Type.VirtualRouter || providerType == Type.VPCVirtualRouter)) { @@ -942,20 +969,42 @@ public class VirtualRouterElement extends AdapterBase implements VirtualRouterEl return sc.list(); } + @Override + public List searchForOvsElement( + ListOvsElementsCmd cmd) { + Long id = cmd.getId(); + Long nspId = cmd.getNspId(); + Boolean enabled = cmd.getEnabled(); + + SearchCriteriaService sc = SearchCriteria2 + .create(OvsProviderVO.class); + if (id != null) { + sc.addAnd(sc.getEntity().getId(), Op.EQ, id); + } + if (nspId != null) { + sc.addAnd(sc.getEntity().getNspId(), Op.EQ, nspId); + } + if (enabled != null) { + sc.addAnd(sc.getEntity().isEnabled(), Op.EQ, enabled); + } + + return sc.list(); + } + @Override public boolean verifyServicesCombination(Set services) { - if (!services.contains(Service.SourceNat)) { - if (services.contains(Service.StaticNat) || services.contains(Service.Firewall) || services.contains(Service.Lb) || - services.contains(Service.PortForwarding) || services.contains(Service.Vpn)) { - String servicesList = "["; - for (Service service : services) { - servicesList += service.getName() + " "; - } - servicesList += "]"; - s_logger.warn("Virtual router can't enable services " + servicesList + " without source NAT service"); - return false; - } - } +// if (!services.contains(Service.SourceNat)) { +// if (services.contains(Service.StaticNat) || services.contains(Service.Firewall) || services.contains(Service.Lb) || +// services.contains(Service.PortForwarding) || services.contains(Service.Vpn)) { +// String servicesList = "["; +// for (Service service : services) { +// servicesList += service.getName() + " "; +// } +// servicesList += "]"; +// s_logger.warn("Virtual router can't enable services " + servicesList + " without source NAT service"); +// return false; +// } +// } return true; } diff --git a/server/src/com/cloud/server/ManagementServerImpl.java b/server/src/com/cloud/server/ManagementServerImpl.java index c0f10aaab40..2b0f0b8dc94 100755 --- a/server/src/com/cloud/server/ManagementServerImpl.java +++ b/server/src/com/cloud/server/ManagementServerImpl.java @@ -138,9 +138,11 @@ import org.apache.cloudstack.api.command.admin.resource.DeleteAlertsCmd; import org.apache.cloudstack.api.command.admin.resource.ListAlertsCmd; import org.apache.cloudstack.api.command.admin.resource.ListCapacityCmd; import org.apache.cloudstack.api.command.admin.resource.UploadCustomCertificateCmd; +import org.apache.cloudstack.api.command.admin.router.ConfigureOvsElementCmd; import org.apache.cloudstack.api.command.admin.router.ConfigureVirtualRouterElementCmd; import org.apache.cloudstack.api.command.admin.router.CreateVirtualRouterElementCmd; import org.apache.cloudstack.api.command.admin.router.DestroyRouterCmd; +import org.apache.cloudstack.api.command.admin.router.ListOvsElementsCmd; import org.apache.cloudstack.api.command.admin.router.ListRoutersCmd; import org.apache.cloudstack.api.command.admin.router.ListVirtualRouterElementsCmd; import org.apache.cloudstack.api.command.admin.router.RebootRouterCmd; @@ -2864,6 +2866,8 @@ public class ManagementServerImpl extends ManagerBase implements ManagementServe cmdList.add(AssignCertToLoadBalancerCmd.class); cmdList.add(RemoveCertFromLoadBalancerCmd.class); cmdList.add(GenerateAlertCmd.class); + cmdList.add(ListOvsElementsCmd.class); + cmdList.add(ConfigureOvsElementCmd.class); return cmdList; } diff --git a/setup/db/create-schema.sql b/setup/db/create-schema.sql index 8d3aa201294..55cb4cce7b9 100755 --- a/setup/db/create-schema.sql +++ b/setup/db/create-schema.sql @@ -196,7 +196,6 @@ DROP TABLE IF EXISTS `cloud`.`vm_network_map`; DROP TABLE IF EXISTS `cloud`.`netapp_volume`; DROP TABLE IF EXISTS `cloud`.`netapp_pool`; DROP TABLE IF EXISTS `cloud`.`netapp_lun`; -DROP TABLE IF EXISTS `cloud`.`ovs_nic_map`; CREATE TABLE `cloud`.`version` ( `id` bigint unsigned NOT NULL UNIQUE AUTO_INCREMENT COMMENT 'id', @@ -2476,14 +2475,5 @@ CREATE TABLE `cloud`.`nicira_nvp_nic_map` ( CONSTRAINT `fk_nicira_nvp_nic_map__nic` FOREIGN KEY(`nic`) REFERENCES `nics`(`uuid`) ON DELETE CASCADE ) ENGINE=InnoDB DEFAULT CHARSET=utf8; -CREATE TABLE `cloud`.`ovs_nic_map` ( - `id` bigint unsigned NOT NULL AUTO_INCREMENT COMMENT 'id', - `logicalswitch` varchar(255) NOT NULL COMMENT 'uuid of logical switch this port is provisioned on', - `logicalswitchport` varchar(255) UNIQUE COMMENT 'uuid of this logical switch port', - `nic` varchar(255) UNIQUE COMMENT 'cloudstack uuid of the nic connected to this logical switch port', - PRIMARY KEY (`id`), - CONSTRAINT `fk_ovs_nic_map__nic` FOREIGN KEY(`nic`) REFERENCES `nics`(`uuid`) ON DELETE CASCADE -) ENGINE=InnoDB DEFAULT CHARSET=utf8; - SET foreign_key_checks = 1; diff --git a/setup/db/db/schema-410to420.sql b/setup/db/db/schema-410to420.sql index 522ccc4a272..6ec5723e825 100644 --- a/setup/db/db/schema-410to420.sql +++ b/setup/db/db/schema-410to420.sql @@ -2103,6 +2103,28 @@ CREATE TABLE `cloud`.`vm_disk_statistics` ( insert into `cloud`.`vm_disk_statistics`(data_center_id,account_id,vm_id,volume_id) select volumes.data_center_id, volumes.account_id, vm_instance.id, volumes.id from volumes,vm_instance where vm_instance.vm_type="User" and vm_instance.state<>"Expunging" and volumes.instance_id=vm_instance.id order by vm_instance.id; +DROP TABLE IF EXISTS `cloud`.`ovs_nic_map`; +CREATE TABLE `cloud`.`ovs_nic_map` ( + `id` bigint unsigned NOT NULL AUTO_INCREMENT COMMENT 'id', + `logicalswitch` varchar(255) NOT NULL COMMENT 'uuid of logical switch this port is provisioned on', + `logicalswitchport` varchar(255) UNIQUE COMMENT 'uuid of this logical switch port', + `nic` varchar(255) UNIQUE COMMENT 'cloudstack uuid of the nic connected to this logical switch port', + PRIMARY KEY (`id`), + CONSTRAINT `fk_ovs_nic_map__nic` FOREIGN KEY(`nic`) REFERENCES `nics`(`uuid`) ON DELETE CASCADE +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + +DROP TABLE IF EXISTS `cloud`.`ovs_providers`; +CREATE TABLE `cloud`.`ovs_providers` ( + `id` bigint unsigned NOT NULL auto_increment COMMENT 'id', + `nsp_id` bigint unsigned NOT NULL COMMENT 'Network Service Provider ID', + `uuid` varchar(40), + `enabled` int(1) NOT NULL COMMENT 'Enabled or disabled', + `removed` datetime COMMENT 'date removed if not null', + PRIMARY KEY (`id`), + CONSTRAINT `fk_ovs_providers__nsp_id` FOREIGN KEY (`nsp_id`) REFERENCES `physical_network_service_providers` (`id`) ON DELETE CASCADE, + CONSTRAINT `uc_ovs_providers__uuid` UNIQUE (`uuid`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + DROP TABLE IF EXISTS `cloud_usage`.`vm_disk_statistics`; CREATE TABLE `cloud_usage`.`vm_disk_statistics` ( `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT, diff --git a/tools/apidoc/gen_toc.py b/tools/apidoc/gen_toc.py index d58252ca61b..dcf132d702f 100644 --- a/tools/apidoc/gen_toc.py +++ b/tools/apidoc/gen_toc.py @@ -160,6 +160,7 @@ known_categories = { 'Ucs' : 'UCS', 'CacheStores' : 'Cache Stores', 'CacheStore' : 'Cache Store' + 'OvsElement' : 'Ovs Element' } diff --git a/ui/scripts/system.js b/ui/scripts/system.js index 315df5e6fcc..aa569fd0925 100644 --- a/ui/scripts/system.js +++ b/ui/scripts/system.js @@ -17916,35 +17916,55 @@ jsonObj["redundantRouterState"] = ""; } } + }; - var refreshNspData = function(nspName) { - var array1 = []; - if (nspName != null) - array1.push("&name=" + nspName); - - $.ajax({ - url: createURL("listNetworkServiceProviders&physicalnetworkid=" + selectedPhysicalNetworkObj.id + array1.join("")), - dataType: "json", - async: false, - success: function(json) { - nspMap = {}; //reset - - var items = json.listnetworkserviceprovidersresponse.networkserviceprovider; - if (items != null) { - for (var i = 0; i < items.length; i++) { - switch (items[i].name) { - case "VirtualRouter": - nspMap["virtualRouter"] = items[i]; - break; - case "InternalLbVm": - nspMap["InternalLbVm"] = items[i]; - break; - case "VpcVirtualRouter": - nspMap["vpcVirtualRouter"] = items[i]; - break; - case "Netscaler": - nspMap["netscaler"] = items[i]; - break; + var addExtraPropertiesToClusterObject = function(jsonObj) { + if(jsonObj.managedstate == "Managed") { + jsonObj.state = jsonObj.allocationstate; //jsonObj.state == Enabled, Disabled + } + else { + jsonObj.state = jsonObj.managedstate; //jsonObj.state == Unmanaged, PrepareUnmanaged, PrepareUnmanagedError + } + } + + var addExtraPropertiesToRouterInstanceObject = function(jsonObj) { + if(jsonObj.isredundantrouter == true) + jsonObj["redundantRouterState"] = jsonObj.redundantstate; + else + jsonObj["redundantRouterState"] = ""; + } + + var refreshNspData = function(nspName) { + var array1 = []; + if(nspName != null) + array1.push("&name=" + nspName); + + $.ajax({ + url: createURL("listNetworkServiceProviders&physicalnetworkid=" + selectedPhysicalNetworkObj.id + array1.join("")), + dataType: "json", + async: false, + success: function(json) { + nspMap = {}; //reset + + var items = json.listnetworkserviceprovidersresponse.networkserviceprovider; + if(items != null) { + for(var i = 0; i < items.length; i++) { + switch(items[i].name) { + case "VirtualRouter": + nspMap["virtualRouter"] = items[i]; + break; + case "Ovs": + nspMap["Ovs"] = items[i]; + break; + case "InternalLbVm": + nspMap["InternalLbVm"] = items[i]; + break; + case "VpcVirtualRouter": + nspMap["vpcVirtualRouter"] = items[i]; + break; + case "Netscaler": + nspMap["netscaler"] = items[i]; + break; case "MidoNet": nspMap["midoNet"] = items[i]; break; @@ -17969,59 +17989,52 @@ case "NiciraNvp": nspMap["niciraNvp"] = items[i]; break; - case "BigSwitchVns": - nspMap["bigswitchVns"] = items[i]; - break; - } - } - } - } - }); - - nspHardcodingArray = [{ - id: 'netscaler', - name: 'NetScaler', - state: nspMap.netscaler ? nspMap.netscaler.state : 'Disabled' - }, { - id: 'virtualRouter', - name: 'Virtual Router', - state: nspMap.virtualRouter ? nspMap.virtualRouter.state : 'Disabled' - }, { - id: 'niciraNvp', - name: 'Nicira Nvp', - state: nspMap.niciraNvp ? nspMap.niciraNvp.state : 'Disabled' - }, { - id: 'bigswitchVns', - name: 'BigSwitch Vns', - state: nspMap.bigswitchVns ? nspMap.bigswitchVns.state : 'Disabled' - }, { - id: 'BaremetalDhcpProvider', - name: 'Baremetal DHCP', - state: nspMap.BaremetalDhcpProvider ? nspMap.BaremetalDhcpProvider.state : 'Disabled' - }, { - id: 'BaremetalPxeProvider', - name: 'Baremetal PXE', - state: nspMap.BaremetalPxeProvider ? nspMap.BaremetalPxeProvider.state : 'Disabled' - }]; - - $(window).trigger('cloudStack.system.serviceProviders.makeHarcodedArray', { - nspHardcodingArray: nspHardcodingArray, - selectedZoneObj: selectedZoneObj, - selectedPhysicalNetworkObj: selectedPhysicalNetworkObj - }); - - if (selectedZoneObj.networktype == "Basic") { - nspHardcodingArray.push({ - id: 'securityGroups', - name: 'Security Groups', - state: nspMap.securityGroups ? nspMap.securityGroups.state : 'Disabled' - }); - } else if (selectedZoneObj.networktype == "Advanced") { - nspHardcodingArray.push({ - id: 'midoNet', - name: 'MidoNet', - state: nspMap.midoNet ? nspMap.midoNet.state : 'Disabled' - }); + case "BigSwitchVns": + nspMap["bigswitchVns"] = items[i]; + break; + } + } + } + } + }); + + nspHardcodingArray = [ + { + id: 'netscaler', + name: 'NetScaler', + state: nspMap.netscaler? nspMap.netscaler.state : 'Disabled' + }, + { + id: 'virtualRouter', + name: 'Virtual Router', + state: nspMap.virtualRouter ? nspMap.virtualRouter.state : 'Disabled' + }, + { + id: 'Ovs', + name: 'Ovs', + state: nspMap.Ovs ? nspMap.Ovs.state : 'Disabled' + }, + { + id: 'niciraNvp', + name: 'Nicira Nvp', + state: nspMap.niciraNvp ? nspMap.niciraNvp.state : 'Disabled' + }, + { + id: 'bigswitchVns', + name: 'BigSwitch Vns', + state: nspMap.bigswitchVns ? nspMap.bigswitchVns.state : 'Disabled' + }, + { + id: 'BaremetalDhcpProvider', + name: 'Baremetal DHCP', + state: nspMap.BaremetalDhcpProvider ? nspMap.BaremetalDhcpProvider.state : 'Disabled' + }, + { + id: 'BaremetalPxeProvider', + name: 'Baremetal PXE', + state: nspMap.BaremetalPxeProvider ? nspMap.BaremetalPxeProvider.state : 'Disabled' + } + ]; nspHardcodingArray.push({ id: 'InternalLbVm', diff --git a/ui/scripts/zoneWizard.js b/ui/scripts/zoneWizard.js index 5437fe42d04..000bed3a60d 100755 --- a/ui/scripts/zoneWizard.js +++ b/ui/scripts/zoneWizard.js @@ -219,6 +219,7 @@ }, storageTrafficIPRange: function(args) { + var multiEditData = []; var totalIndex = 0; @@ -3056,6 +3057,7 @@ return; } + var virtualRouterElementId; $.ajax({ url: createURL("configureInternalLoadBalancerElement&enabled=true&id=" + internalLbElementId), dataType: "json", @@ -3119,6 +3121,202 @@ }, g_queryAsyncJobResultInterval); } }); + // ***** Virtual Router ***** (end) ***** + + // ***** Ovs ***** (begin) ***** + var ovsProviderId = null; + $.ajax({ + url: createURL("listNetworkServiceProviders&name=Ovs&physicalNetworkId=" + thisPhysicalNetwork.id), + dataType: "json", + async: false, + success: function (json) { + var items = json.listnetworkserviceprovidersresponse.networkserviceprovider; + if (items != null && items.length > 0) { + ovsProviderId = items[0].id; + } + } + }); + if (ovsProviderId != null) { + var ovsElementId = null; + $.ajax({ + url: createURL("listOvsElements&nspid=" + ovsProviderId), + dataType: "json", + async: false, + success: function (json) { + var items = json.listovselementsresponse.ovselement; + if (items != null && items.length > 0) { + ovsElementId = items[0].id; + } + } + }); + if (ovsElementId != null) { + $.ajax({ + url: createURL("configureOvsElement&enabled=true&id=" + ovsElementId), + dataType: "json", + async: false, + success: function (json) { + var jobId = json.configureovselementresponse.jobid; + var enableOvsElementIntervalID = setInterval(function () { + $.ajax({ + url: createURL("queryAsyncJobResult&jobId=" + jobId), + dataType: "json", + success: function (json) { + var result = json.queryasyncjobresultresponse; + if (result.jobstatus == 0) { + return; //Job has not completed + } else { + clearInterval(enableOvsElementIntervalID); + + if (result.jobstatus == 1) { //configureOvsElement succeeded + $.ajax({ + url: createURL("updateNetworkServiceProvider&state=Enabled&id=" + ovsProviderId), + dataType: "json", + async: false, + success: function (json) { + var jobId = json.updatenetworkserviceproviderresponse.jobid; + var enableOvsProviderIntervalID = setInterval(function () { + $.ajax({ + url: createURL("queryAsyncJobResult&jobId=" + jobId), + dataType: "json", + success: function (json) { + var result = json.queryasyncjobresultresponse; + if (result.jobstatus == 0) { + return; //Job has not completed + } else { + clearInterval(enableOvsProviderIntervalID); + + if (result.jobstatus == 2) { + alert("failed to enable Ovs Provider. Error: " + _s(result.jobresult.errortext)); + } + } + }, + error: function (XMLHttpResponse) { + var errorMsg = parseXMLHttpResponse(XMLHttpResponse); + alert("updateNetworkServiceProvider failed. Error: " + errorMsg); + } + }); + }, g_queryAsyncJobResultInterval); + } + }); + } else if (result.jobstatus == 2) { + alert("configureOvsElement failed. Error: " + _s(result.jobresult.errortext)); + } + } + }, + error: function (XMLHttpResponse) { + var errorMsg = parseXMLHttpResponse(XMLHttpResponse); + alert("configureOvsElement failed. Error: " + errorMsg); + } + }); + }, g_queryAsyncJobResultInterval); + } + }); + } + + + } + + + // ***** Ovs ***** (end) ***** + + // ***** Internal LB ***** (begin) ***** + var internalLbProviderId; + $.ajax({ + url: createURL("listNetworkServiceProviders&name=Internallbvm&physicalNetworkId=" + thisPhysicalNetwork.id), + dataType: "json", + async: false, + success: function (json) { + var items = json.listnetworkserviceprovidersresponse.networkserviceprovider; + if (items != null && items.length > 0) { + internalLbProviderId = items[0].id; + } + } + }); + if (internalLbProviderId == null) { + alert("error: listNetworkServiceProviders API doesn't return internalLb provider ID"); + return; + } + + var internalLbElementId; + $.ajax({ + url: createURL("listInternalLoadBalancerElements&nspid=" + internalLbProviderId), + dataType: "json", + async: false, + success: function (json) { + var items = json.listinternalloadbalancerelementsresponse.internalloadbalancerelement; + if (items != null && items.length > 0) { + internalLbElementId = items[0].id; + } + } + }); + if (internalLbElementId == null) { + alert("error: listInternalLoadBalancerElements API doesn't return Internal LB Element Id"); + return; + } + + $.ajax({ + url: createURL("configureInternalLoadBalancerElement&enabled=true&id=" + internalLbElementId), + dataType: "json", + async: false, + success: function (json) { + var jobId = json.configureinternalloadbalancerelementresponse.jobid; + var enableInternalLbElementIntervalID = setInterval(function () { + $.ajax({ + url: createURL("queryAsyncJobResult&jobId=" + jobId), + dataType: "json", + success: function (json) { + var result = json.queryasyncjobresultresponse; + if (result.jobstatus == 0) { + return; //Job has not completed + } else { + clearInterval(enableInternalLbElementIntervalID); + + if (result.jobstatus == 1) { //configureVirtualRouterElement succeeded + $.ajax({ + url: createURL("updateNetworkServiceProvider&state=Enabled&id=" + internalLbProviderId), + dataType: "json", + async: false, + success: function (json) { + var jobId = json.updatenetworkserviceproviderresponse.jobid; + var enableInternalLbProviderIntervalID = setInterval(function () { + $.ajax({ + url: createURL("queryAsyncJobResult&jobId=" + jobId), + dataType: "json", + success: function (json) { + var result = json.queryasyncjobresultresponse; + if (result.jobstatus == 0) { + return; //Job has not completed + } else { + clearInterval(enableInternalLbProviderIntervalID); + + if (result.jobstatus == 1) { //Internal LB has been enabled successfully + //don't need to do anything here + } else if (result.jobstatus == 2) { + alert("failed to enable Internal LB Provider. Error: " + _s(result.jobresult.errortext)); + } + } + }, + error: function (XMLHttpResponse) { + var errorMsg = parseXMLHttpResponse(XMLHttpResponse); + alert("failed to enable Internal LB Provider. Error: " + errorMsg); + } + }); + }, g_queryAsyncJobResultInterval); + } + }); + } else if (result.jobstatus == 2) { + alert("configureVirtualRouterElement failed. Error: " + _s(result.jobresult.errortext)); + } + } + }, + error: function (XMLHttpResponse) { + var errorMsg = parseXMLHttpResponse(XMLHttpResponse); + alert("configureVirtualRouterElement failed. Error: " + errorMsg); + } + }); + }, g_queryAsyncJobResultInterval); + } + }); // ***** Internal LB ***** (end) ***** if (args.data.zone.sgEnabled != true) { //Advanced SG-disabled zone @@ -3128,7 +3326,7 @@ url: createURL("listNetworkServiceProviders&name=VpcVirtualRouter&physicalNetworkId=" + thisPhysicalNetwork.id), dataType: "json", async: false, - success: function(json) { + success: function (json) { var items = json.listnetworkserviceprovidersresponse.networkserviceprovider; if (items != null && items.length > 0) { vpcVirtualRouterProviderId = items[0].id; @@ -3145,7 +3343,7 @@ url: createURL("listVirtualRouterElements&nspid=" + vpcVirtualRouterProviderId), dataType: "json", async: false, - success: function(json) { + success: function (json) { var items = json.listvirtualrouterelementsresponse.virtualrouterelement; if (items != null && items.length > 0) { vpcVirtualRouterElementId = items[0].id; @@ -3161,13 +3359,13 @@ url: createURL("configureVirtualRouterElement&enabled=true&id=" + vpcVirtualRouterElementId), dataType: "json", async: false, - success: function(json) { + success: function (json) { var jobId = json.configurevirtualrouterelementresponse.jobid; - var enableVpcVirtualRouterElementIntervalID = setInterval(function() { + var enableVpcVirtualRouterElementIntervalID = setInterval(function () { $.ajax({ url: createURL("queryAsyncJobResult&jobId=" + jobId), dataType: "json", - success: function(json) { + success: function (json) { var result = json.queryasyncjobresultresponse; if (result.jobstatus == 0) { return; //Job has not completed @@ -3179,13 +3377,13 @@ url: createURL("updateNetworkServiceProvider&state=Enabled&id=" + vpcVirtualRouterProviderId), dataType: "json", async: false, - success: function(json) { + success: function (json) { var jobId = json.updatenetworkserviceproviderresponse.jobid; - var enableVpcVirtualRouterProviderIntervalID = setInterval(function() { + var enableVpcVirtualRouterProviderIntervalID = setInterval(function () { $.ajax({ url: createURL("queryAsyncJobResult&jobId=" + jobId), dataType: "json", - success: function(json) { + success: function (json) { var result = json.queryasyncjobresultresponse; if (result.jobstatus == 0) { return; //Job has not completed @@ -3199,7 +3397,7 @@ } } }, - error: function(XMLHttpResponse) { + error: function (XMLHttpResponse) { var errorMsg = parseXMLHttpResponse(XMLHttpResponse); alert("failed to enable VPC Virtual Router Provider. Error: " + errorMsg); } @@ -3212,7 +3410,7 @@ } } }, - error: function(XMLHttpResponse) { + error: function (XMLHttpResponse) { var errorMsg = parseXMLHttpResponse(XMLHttpResponse); alert("configureVirtualRouterElement failed. Error: " + errorMsg); } @@ -3221,7 +3419,7 @@ } }); // ***** VPC Virtual Router ***** (end) ***** - } else { //args.data.zone.sgEnabled == true //Advanced SG-enabled zone + } else { //args.data.zone.sgEnabled == true //Advanced SG-enabled zone message(dictionary['message.enabling.security.group.provider']); // get network service provider ID of Security Group @@ -3230,7 +3428,7 @@ url: createURL("listNetworkServiceProviders&name=SecurityGroupProvider&physicalNetworkId=" + thisPhysicalNetwork.id), dataType: "json", async: false, - success: function(json) { + success: function (json) { var items = json.listnetworkserviceprovidersresponse.networkserviceprovider; if (items != null && items.length > 0) { securityGroupProviderId = items[0].id; @@ -3291,6 +3489,7 @@ }, addNetscalerProvider: function(args) { + if (selectedNetworkOfferingHavingNetscaler == true) { message(dictionary['message.adding.Netscaler.provider']); @@ -3961,7 +4160,6 @@ url = hostname; url += "/" + dcName + "/" + clusterName; array1.push("&url=" + todb(url)); - clusterName = hostname + "/" + dcName + "/" + clusterName; //override clusterName } array1.push("&clustername=" + todb(clusterName)); diff --git a/utils/conf/db.properties b/utils/conf/db.properties index e1b5fe9a2c1..709d79e3330 100644 --- a/utils/conf/db.properties +++ b/utils/conf/db.properties @@ -25,7 +25,7 @@ region.id=1 # CloudStack database settings db.cloud.username=cloud db.cloud.password=cloud -db.root.password= +db.root.password=123 db.cloud.host=localhost db.cloud.port=3306 db.cloud.name=cloud