From dd57e8bb38bd6eee8d498c911bcd0536dabe05d1 Mon Sep 17 00:00:00 2001 From: Brian Federle Date: Wed, 11 Jul 2012 14:04:27 -0700 Subject: [PATCH 1/8] VPC UI: CSS fixes -Fix hover state for virtual router block -- should not have a highlight effect -Add gray BG for multi-edit header area, for VPC PF/LB form -Remove border around static NAT tier select --- ui/css/cloudstack3.css | 37 ++++++++++++++++++++++++++++--------- 1 file changed, 28 insertions(+), 9 deletions(-) diff --git a/ui/css/cloudstack3.css b/ui/css/cloudstack3.css index 8188a01bf7e..3f08f0054e3 100644 --- a/ui/css/cloudstack3.css +++ b/ui/css/cloudstack3.css @@ -6934,17 +6934,36 @@ div.panel.ui-dialog div.list-view div.fixed-header { /** Header fields*/ .multi-edit .header-fields { position: relative; - /*+placement:shift 8px 11px;*/ + /*+placement:shift 14px 11px;*/ position: relative; - left: 8px; + left: 14px; top: 11px; } +.multi-edit .header-fields .form-container { + width: 96%; + height: 32px; + background: #E4E4E4; + /*+border-radius:4px;*/ + -moz-border-radius: 4px; + -webkit-border-radius: 4px; + -khtml-border-radius: 4px; + border-radius: 4px; + border: 1px solid #D4CFCF; +} + .multi-edit .header-fields .form-item { + padding: 4px 15px 3px 9px; margin-bottom: 32px; + margin-right: 0; float: left; } +.multi-edit .header-fields .form-item input, +.multi-edit .header-fields .form-item select { + margin-top: 4px; +} + .multi-edit .header-fields .form-item .name, .multi-edit .header-fields .form-item .value { float: left; @@ -8916,6 +8935,7 @@ div.panel.ui-dialog div.list-view div.fixed-header { padding: 35px 10px 10px; font-size: 14px; display: none; + z-index: 2000; position: absolute; } @@ -9245,6 +9265,7 @@ div.panel.ui-dialog div.list-view div.fixed-header { } .vpc-chart li.tier.virtual-router span { + cursor: default; color: #586E82; font-size: 18px; /*+text-shadow:0px 1px 3px #FFFFFF;*/ @@ -9258,6 +9279,11 @@ div.panel.ui-dialog div.list-view div.fixed-header { top: 22px; } +.vpc-chart li.tier.virtual-router span:hover { + background: none; + border: none; +} + .vpc-chart li.tier.virtual-router .connect-line { /*+placement:shift -47px 14px;*/ position: relative; @@ -9269,15 +9295,8 @@ div.panel.ui-dialog div.list-view div.fixed-header { /*VPC: Enable Static NAT fields*/ .list-view.instances .filters.tier-select { width: 246px; - /*+border-radius:4px;*/ - -moz-border-radius: 4px; - -webkit-border-radius: 4px; - -khtml-border-radius: 4px; - border-radius: 4px; - background: #8F98A1; padding: 2px 20px 2px 13px; margin: 1px 120px 0 19px; - border: 1px solid #000000; } .list-view.instances .filters.tier-select label { From ed4b6a517bb984c3e0a38b04a5096332bebc51c4 Mon Sep 17 00:00:00 2001 From: Edison Su Date: Wed, 11 Jul 2012 15:19:12 -0700 Subject: [PATCH 2/8] the default templates are put into download.cloud.com --- tools/devcloud/devcloudsetup.sh | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/tools/devcloud/devcloudsetup.sh b/tools/devcloud/devcloudsetup.sh index f8d78a6447d..b5a97cb091a 100644 --- a/tools/devcloud/devcloudsetup.sh +++ b/tools/devcloud/devcloudsetup.sh @@ -16,7 +16,7 @@ # specific language governing permissions and limitations # under the License. -fileSvr="http://nfs1.lab.vmops.com/templates/devcloud/" +fileSvr="http://download.cloud.com/templates/devcloud/" install_xen() { aptitude update echo "install xen" @@ -87,10 +87,10 @@ postsetup() { mkdir -p /opt/storage/secondary/template/tmpl/1/5 echo "/opt/storage/secondary *(rw,no_subtree_check,no_root_squash,fsid=0)" > /etc/exports - wget $fileSvr/vmtemplates/1/dc68eb4c-228c-4a78-84fa-b80ae178fbfd.vhd -P /opt/storage/secondary/template/tmpl/1/1/ - wget $fileSvr/vmtemplates/1/template.properties -P /opt/storage/secondary/template/tmpl/1/1/ - wget $fileSvr/vmtemplates/5/ce5b212e-215a-3461-94fb-814a635b2215.vhd -P /opt/storage/secondary/template/tmpl/1/5/ - wget $fileSvr/vmtemplates/5/template.properties -P /opt/storage/secondary/template/tmpl/1/5/ + wget $fileSvr/defaulttemplates/1/dc68eb4c-228c-4a78-84fa-b80ae178fbfd.vhd -P /opt/storage/secondary/template/tmpl/1/1/ + wget $fileSvr/defaulttemplates/1/template.properties -P /opt/storage/secondary/template/tmpl/1/1/ + wget $fileSvr/defaulttemplates/5/ce5b212e-215a-3461-94fb-814a635b2215.vhd -P /opt/storage/secondary/template/tmpl/1/5/ + wget $fileSvr/defaulttemplates/5/template.properties -P /opt/storage/secondary/template/tmpl/1/5/ /etc/init.d/nfs-kernel-server restart fi From 8b7b838c8a689e777a9c1ed321b225631762283e Mon Sep 17 00:00:00 2001 From: Edison Su Date: Wed, 11 Jul 2012 16:14:28 -0700 Subject: [PATCH 3/8] CS-15544: recreate router if router filesystem is crashed --- .../lb/ElasticLoadBalancerManagerImpl.java | 9 ++++++ .../AgentBasedConsoleProxyManager.java | 8 +++++ .../consoleproxy/ConsoleProxyManagerImpl.java | 8 +++++ .../VirtualNetworkApplianceManagerImpl.java | 13 ++++++++ .../src/com/cloud/storage/StorageManager.java | 2 +- .../com/cloud/storage/StorageManagerImpl.java | 30 +++++++++++++++---- .../SecondaryStorageManagerImpl.java | 8 +++++ .../src/com/cloud/vm/UserVmManagerImpl.java | 6 ++++ .../src/com/cloud/vm/VirtualMachineGuru.java | 2 ++ .../cloud/vm/VirtualMachineManagerImpl.java | 11 +++++-- .../com/cloud/vm/MockUserVmManagerImpl.java | 6 ++++ 11 files changed, 94 insertions(+), 9 deletions(-) diff --git a/plugins/network-elements/elastic-loadbalancer/src/com/cloud/network/lb/ElasticLoadBalancerManagerImpl.java b/plugins/network-elements/elastic-loadbalancer/src/com/cloud/network/lb/ElasticLoadBalancerManagerImpl.java index 3985c516d30..8d1963d303a 100644 --- a/plugins/network-elements/elastic-loadbalancer/src/com/cloud/network/lb/ElasticLoadBalancerManagerImpl.java +++ b/plugins/network-elements/elastic-loadbalancer/src/com/cloud/network/lb/ElasticLoadBalancerManagerImpl.java @@ -987,4 +987,13 @@ public class ElasticLoadBalancerManagerImpl implements return VirtualMachineName.getSystemVmId(vmName); } + + + @Override + public boolean recreateNeeded( + VirtualMachineProfile profile, long hostId, + Commands cmds, ReservationContext context) { + // TODO Auto-generated method stub + return false; + } } diff --git a/server/src/com/cloud/consoleproxy/AgentBasedConsoleProxyManager.java b/server/src/com/cloud/consoleproxy/AgentBasedConsoleProxyManager.java index d892957a50b..6d20fb2fc31 100755 --- a/server/src/com/cloud/consoleproxy/AgentBasedConsoleProxyManager.java +++ b/server/src/com/cloud/consoleproxy/AgentBasedConsoleProxyManager.java @@ -345,4 +345,12 @@ public class AgentBasedConsoleProxyManager implements ConsoleProxyManager, Virtu @Override public void finalizeExpunge(ConsoleProxyVO proxy) { } + + @Override + public boolean recreateNeeded( + VirtualMachineProfile profile, long hostId, + Commands cmds, ReservationContext context) { + // TODO Auto-generated method stub + return false; + } } diff --git a/server/src/com/cloud/consoleproxy/ConsoleProxyManagerImpl.java b/server/src/com/cloud/consoleproxy/ConsoleProxyManagerImpl.java index 6fef240d69d..ec4f685f3a7 100755 --- a/server/src/com/cloud/consoleproxy/ConsoleProxyManagerImpl.java +++ b/server/src/com/cloud/consoleproxy/ConsoleProxyManagerImpl.java @@ -2006,4 +2006,12 @@ public class ConsoleProxyManagerImpl implements ConsoleProxyManager, ConsoleProx } return _hashKey; } + + @Override + public boolean recreateNeeded( + VirtualMachineProfile profile, long hostId, + Commands cmds, ReservationContext context) { + // TODO Auto-generated method stub + return false; + } } diff --git a/server/src/com/cloud/network/router/VirtualNetworkApplianceManagerImpl.java b/server/src/com/cloud/network/router/VirtualNetworkApplianceManagerImpl.java index dea411484ff..766c7690ee8 100755 --- a/server/src/com/cloud/network/router/VirtualNetworkApplianceManagerImpl.java +++ b/server/src/com/cloud/network/router/VirtualNetworkApplianceManagerImpl.java @@ -2972,4 +2972,17 @@ public class VirtualNetworkApplianceManagerImpl implements VirtualNetworkApplian return routerControlIpAddress; } + + @Override + public boolean recreateNeeded( + VirtualMachineProfile profile, long hostId, + Commands cmds, ReservationContext context) { + //asssume that if failed to ssh into router, meaning router is crashed + CheckSshAnswer answer = (CheckSshAnswer) cmds.getAnswer("checkSsh"); + if (answer == null || !answer.getResult()) { + return true; + } + + return false; + } } diff --git a/server/src/com/cloud/storage/StorageManager.java b/server/src/com/cloud/storage/StorageManager.java index 9acc702e61b..67ad97c204b 100755 --- a/server/src/com/cloud/storage/StorageManager.java +++ b/server/src/com/cloud/storage/StorageManager.java @@ -180,7 +180,7 @@ public interface StorageManager extends StorageService, Manager { void createCapacityEntry(StoragePoolVO storagePool, short capacityType, long allocated); - void prepare(VirtualMachineProfile vm, DeployDestination dest) throws StorageUnavailableException, InsufficientStorageCapacityException, ConcurrentOperationException; + void prepare(VirtualMachineProfile vm, DeployDestination dest, boolean recreate) throws StorageUnavailableException, InsufficientStorageCapacityException, ConcurrentOperationException; void release(VirtualMachineProfile profile); diff --git a/server/src/com/cloud/storage/StorageManagerImpl.java b/server/src/com/cloud/storage/StorageManagerImpl.java index baea54c663c..27d8cb71e83 100755 --- a/server/src/com/cloud/storage/StorageManagerImpl.java +++ b/server/src/com/cloud/storage/StorageManagerImpl.java @@ -3173,7 +3173,7 @@ public class StorageManagerImpl implements StorageManager, Manager, ClusterManag } @Override - public void prepare(VirtualMachineProfile vm, DeployDestination dest) throws StorageUnavailableException, InsufficientStorageCapacityException { + public void prepare(VirtualMachineProfile vm, DeployDestination dest, boolean recreate) throws StorageUnavailableException, InsufficientStorageCapacityException { if (dest == null) { if (s_logger.isDebugEnabled()) { @@ -3193,7 +3193,11 @@ public class StorageManagerImpl implements StorageManager, Manager, ClusterManag if (dest.getStorageForDisks() != null) { assignedPool = dest.getStorageForDisks().get(vol); } - if (assignedPool != null) { + if (assignedPool == null && recreate) { + assignedPool = _storagePoolDao.findById(vol.getPoolId()); + + } + if (assignedPool != null || recreate) { Volume.State state = vol.getState(); if (state == Volume.State.Allocated || state == Volume.State.Creating) { recreateVols.add(vol); @@ -3231,6 +3235,12 @@ public class StorageManagerImpl implements StorageManager, Manager, ClusterManag for (VolumeVO vol : recreateVols) { VolumeVO newVol; + StoragePool existingPool = null; + if (recreate && (dest.getStorageForDisks() == null || dest.getStorageForDisks().get(vol) == null)) { + existingPool = _storagePoolDao.findById(vol.getPoolId()); + s_logger.debug("existing pool: " + existingPool.getId()); + } + if (vol.getState() == Volume.State.Allocated || vol.getState() == Volume.State.Creating) { newVol = vol; } else { @@ -3251,7 +3261,9 @@ public class StorageManagerImpl implements StorageManager, Manager, ClusterManag } catch (NoTransitionException e) { throw new CloudRuntimeException("Unable to create " + e.toString()); } - Pair created = createVolume(newVol, _diskOfferingDao.findById(newVol.getDiskOfferingId()), vm, vols, dest); + + Pair created = createVolume(newVol, _diskOfferingDao.findById(newVol.getDiskOfferingId()), vm, vols, dest, existingPool); + if (created == null) { Long poolId = newVol.getPoolId(); newVol.setPoolId(null); @@ -3307,7 +3319,7 @@ public class StorageManagerImpl implements StorageManager, Manager, ClusterManag } public Pair createVolume(VolumeVO toBeCreated, DiskOfferingVO offering, VirtualMachineProfile vm, List alreadyCreated, - DeployDestination dest) throws StorageUnavailableException { + DeployDestination dest, StoragePool sPool) throws StorageUnavailableException { if (s_logger.isDebugEnabled()) { s_logger.debug("Creating volume: " + toBeCreated); } @@ -3317,9 +3329,15 @@ public class StorageManagerImpl implements StorageManager, Manager, ClusterManag if (toBeCreated.getTemplateId() != null) { template = _templateDao.findById(toBeCreated.getTemplateId()); } + + StoragePool pool = null; + if (sPool != null) { + pool = sPool; + } else { + pool = dest.getStorageForDisks().get(toBeCreated); + } - if (dest.getStorageForDisks() != null) { - StoragePool pool = dest.getStorageForDisks().get(toBeCreated); + if (pool != null) { if (s_logger.isDebugEnabled()) { s_logger.debug("Trying to create in " + pool); } diff --git a/server/src/com/cloud/storage/secondary/SecondaryStorageManagerImpl.java b/server/src/com/cloud/storage/secondary/SecondaryStorageManagerImpl.java index bb7fa02ef22..1121bb19f61 100755 --- a/server/src/com/cloud/storage/secondary/SecondaryStorageManagerImpl.java +++ b/server/src/com/cloud/storage/secondary/SecondaryStorageManagerImpl.java @@ -1450,4 +1450,12 @@ public class SecondaryStorageManagerImpl implements SecondaryStorageVmManager, V } return null; } + + @Override + public boolean recreateNeeded( + VirtualMachineProfile profile, long hostId, + Commands cmds, ReservationContext context) { + // TODO Auto-generated method stub + return false; + } } diff --git a/server/src/com/cloud/vm/UserVmManagerImpl.java b/server/src/com/cloud/vm/UserVmManagerImpl.java index 635a943f676..649e215acf0 100755 --- a/server/src/com/cloud/vm/UserVmManagerImpl.java +++ b/server/src/com/cloud/vm/UserVmManagerImpl.java @@ -3534,6 +3534,12 @@ public class UserVmManagerImpl implements UserVmManager, UserVmService, Manager s_logger.info("AssignVM: vm " + vm.getInstanceName() + " now belongs to account " + cmd.getAccountName()); return vm; } + @Override + public boolean recreateNeeded(VirtualMachineProfile profile, + long hostId, Commands cmds, ReservationContext context) { + // TODO Auto-generated method stub + return false; + } @Override diff --git a/server/src/com/cloud/vm/VirtualMachineGuru.java b/server/src/com/cloud/vm/VirtualMachineGuru.java index d779485b3b6..b92982c7b31 100644 --- a/server/src/com/cloud/vm/VirtualMachineGuru.java +++ b/server/src/com/cloud/vm/VirtualMachineGuru.java @@ -63,6 +63,8 @@ public interface VirtualMachineGuru { void finalizeExpunge(T vm); + boolean recreateNeeded(VirtualMachineProfile profile, long hostId, Commands cmds, ReservationContext context); + /** * Returns the id parsed from the name. If it cannot parse the name, * then return null. This method is used to determine if this is diff --git a/server/src/com/cloud/vm/VirtualMachineManagerImpl.java b/server/src/com/cloud/vm/VirtualMachineManagerImpl.java index 561e5b290c8..ac8fd2ab46b 100755 --- a/server/src/com/cloud/vm/VirtualMachineManagerImpl.java +++ b/server/src/com/cloud/vm/VirtualMachineManagerImpl.java @@ -651,6 +651,7 @@ public class VirtualMachineManagerImpl implements VirtualMachineManager, Listene DataCenterDeployment originalPlan = plan; int retry = _retry; + boolean recreate = false; while (retry-- != 0) { // It's != so that it can match -1. if(reuseVolume){ @@ -745,7 +746,8 @@ public class VirtualMachineManagerImpl implements VirtualMachineManager, Listene } _networkMgr.prepare(vmProfile, dest, ctx); if (vm.getHypervisorType() != HypervisorType.BareMetal) { - _storageMgr.prepare(vmProfile, dest); + _storageMgr.prepare(vmProfile, dest, recreate); + recreate = false; } //since StorageMgr succeeded in volume creation, reuse Volume for further tries until current cluster has capacity if(!reuseVolume){ @@ -798,6 +800,7 @@ public class VirtualMachineManagerImpl implements VirtualMachineManager, Listene if (s_logger.isDebugEnabled()) { s_logger.info("The guru did not like the answers so stopping " + vm); } + StopCommand cmd = new StopCommand(vm.getInstanceName()); StopAnswer answer = (StopAnswer) _agentMgr.easySend(destHostId, cmd); if (answer == null || !answer.getResult()) { @@ -805,7 +808,11 @@ public class VirtualMachineManagerImpl implements VirtualMachineManager, Listene _haMgr.scheduleStop(vm, destHostId, WorkType.ForceStop); throw new ExecutionException("Unable to stop " + vm + " so we are unable to retry the start operation"); } - throw new ExecutionException("Unable to start " + vm + " due to error in finalizeStart, not retrying"); + if (vmGuru.recreateNeeded(vmProfile, destHostId, cmds, ctx)) { + recreate = true; + } else { + throw new ExecutionException("Unable to start " + vm + " due to error in finalizeStart, not retrying"); + } } } s_logger.info("Unable to start VM on " + dest.getHost() + " due to " + (startAnswer == null ? " no start answer" : startAnswer.getDetails())); diff --git a/server/test/com/cloud/vm/MockUserVmManagerImpl.java b/server/test/com/cloud/vm/MockUserVmManagerImpl.java index 5241eb216a6..31065fe48a6 100644 --- a/server/test/com/cloud/vm/MockUserVmManagerImpl.java +++ b/server/test/com/cloud/vm/MockUserVmManagerImpl.java @@ -290,6 +290,12 @@ public class MockUserVmManagerImpl implements UserVmManager, UserVmService, Mana } + @Override + public boolean recreateNeeded(VirtualMachineProfile profile, + long hostId, Commands cmds, ReservationContext context) { + // TODO Auto-generated method stub + return false; + } @Override public UserVm startVirtualMachine(DeployVMCmd cmd) throws InsufficientCapacityException, ConcurrentOperationException, ResourceUnavailableException { From 79c7da07abd4294f150851aa0c2d06a28564c5a9 Mon Sep 17 00:00:00 2001 From: Hugo Trippaers Date: Wed, 11 Jul 2012 16:14:28 -0700 Subject: [PATCH 4/8] Phase 1 of Nicira integration --- api/src/com/cloud/agent/api/to/NicTO.java | 11 + .../cloud/agent/api/to/VirtualMachineTO.java | 11 + api/src/com/cloud/api/ApiConstants.java | 4 + api/src/com/cloud/host/Host.java | 3 +- api/src/com/cloud/network/Network.java | 2 + api/src/com/cloud/network/Networks.java | 1 + .../com/cloud/network/PhysicalNetwork.java | 3 +- build/build-cloud-plugins.xml | 10 +- build/package.xml | 1 + client/tomcatconf/components.xml.in | 7 +- .../nicira-nvp_commands.properties.in | 12 + cloud.spec | 1 + .../xen/resource/CitrixResourceBase.java | 12 +- .../network-elements/nicira-nvp/.classpath | 12 + plugins/network-elements/nicira-nvp/.project | 17 + .../nicira-nvp/README.NiciraIntegration | 68 +++ plugins/network-elements/nicira-nvp/build.xml | 129 +++++ .../agent/api/CreateLogicalSwitchAnswer.java | 20 + .../agent/api/CreateLogicalSwitchCommand.java | 38 ++ .../api/CreateLogicalSwitchPortAnswer.java | 20 + .../api/CreateLogicalSwitchPortCommand.java | 42 ++ .../agent/api/DeleteLogicalSwitchAnswer.java | 14 + .../agent/api/DeleteLogicalSwitchCommand.java | 19 + .../api/DeleteLogicalSwitchPortAnswer.java | 14 + .../api/DeleteLogicalSwitchPortCommand.java | 25 + .../agent/api/StartupNiciraNvpCommand.java | 11 + .../api/commands/AddNiciraNvpDeviceCmd.java | 110 ++++ .../commands/DeleteNiciraNvpDeviceCmd.java | 76 +++ .../ListNiciraNvpDeviceNetworksCmd.java | 85 +++ .../api/commands/ListNiciraNvpDevicesCmd.java | 90 ++++ .../api/response/NiciraNvpDeviceResponse.java | 37 ++ .../com/cloud/network/NiciraNvpDeviceVO.java | 79 +++ .../cloud/network/NiciraNvpNicMappingVO.java | 65 +++ .../com/cloud/network/dao/NiciraNvpDao.java | 16 + .../cloud/network/dao/NiciraNvpDaoImpl.java | 32 ++ .../network/dao/NiciraNvpNicMappingDao.java | 13 + .../dao/NiciraNvpNicMappingDaoImpl.java | 30 ++ .../network/element/NiciraNvpElement.java | 502 ++++++++++++++++++ .../element/NiciraNvpElementService.java | 28 + .../guru/NiciraNvpGuestNetworkGuru.java | 257 +++++++++ .../com/cloud/network/nicira/Attachment.java | 22 + .../cloud/network/nicira/LogicalSwitch.java | 99 ++++ .../network/nicira/LogicalSwitchPort.java | 118 ++++ .../cloud/network/nicira/NiciraNvpApi.java | 413 ++++++++++++++ .../network/nicira/NiciraNvpApiException.java | 20 + .../cloud/network/nicira/NiciraNvpList.java | 25 + .../cloud/network/nicira/NiciraNvpTag.java | 47 ++ .../network/nicira/TransportZoneBinding.java | 47 ++ .../cloud/network/nicira/VifAttachment.java | 43 ++ .../network/resource/NiciraNvpResource.java | 240 +++++++++ .../network/guru/OvsGuestNetworkGuru.java | 28 + .../src/com/cloud/host/dao/HostDaoImpl.java | 4 +- .../cloud/hypervisor/HypervisorGuruBase.java | 15 + .../network/ExternalNetworkDeviceManager.java | 2 + .../com/cloud/network/NetworkManagerImpl.java | 5 +- .../guru/ExternalGuestNetworkGuru.java | 30 +- .../cloud/network/guru/GuestNetworkGuru.java | 53 +- .../src/com/cloud/server/StatsCollector.java | 1 + setup/db/create-schema.sql | 23 + ui/scripts/ui-custom/zoneWizard.js | 13 +- wscript_configure | 2 +- 61 files changed, 3155 insertions(+), 22 deletions(-) create mode 100644 client/tomcatconf/nicira-nvp_commands.properties.in create mode 100644 plugins/network-elements/nicira-nvp/.classpath create mode 100644 plugins/network-elements/nicira-nvp/.project create mode 100644 plugins/network-elements/nicira-nvp/README.NiciraIntegration create mode 100644 plugins/network-elements/nicira-nvp/build.xml create mode 100644 plugins/network-elements/nicira-nvp/src/com/cloud/agent/api/CreateLogicalSwitchAnswer.java create mode 100644 plugins/network-elements/nicira-nvp/src/com/cloud/agent/api/CreateLogicalSwitchCommand.java create mode 100644 plugins/network-elements/nicira-nvp/src/com/cloud/agent/api/CreateLogicalSwitchPortAnswer.java create mode 100644 plugins/network-elements/nicira-nvp/src/com/cloud/agent/api/CreateLogicalSwitchPortCommand.java create mode 100644 plugins/network-elements/nicira-nvp/src/com/cloud/agent/api/DeleteLogicalSwitchAnswer.java create mode 100644 plugins/network-elements/nicira-nvp/src/com/cloud/agent/api/DeleteLogicalSwitchCommand.java create mode 100644 plugins/network-elements/nicira-nvp/src/com/cloud/agent/api/DeleteLogicalSwitchPortAnswer.java create mode 100644 plugins/network-elements/nicira-nvp/src/com/cloud/agent/api/DeleteLogicalSwitchPortCommand.java create mode 100644 plugins/network-elements/nicira-nvp/src/com/cloud/agent/api/StartupNiciraNvpCommand.java create mode 100644 plugins/network-elements/nicira-nvp/src/com/cloud/api/commands/AddNiciraNvpDeviceCmd.java create mode 100644 plugins/network-elements/nicira-nvp/src/com/cloud/api/commands/DeleteNiciraNvpDeviceCmd.java create mode 100644 plugins/network-elements/nicira-nvp/src/com/cloud/api/commands/ListNiciraNvpDeviceNetworksCmd.java create mode 100644 plugins/network-elements/nicira-nvp/src/com/cloud/api/commands/ListNiciraNvpDevicesCmd.java create mode 100644 plugins/network-elements/nicira-nvp/src/com/cloud/api/response/NiciraNvpDeviceResponse.java create mode 100644 plugins/network-elements/nicira-nvp/src/com/cloud/network/NiciraNvpDeviceVO.java create mode 100644 plugins/network-elements/nicira-nvp/src/com/cloud/network/NiciraNvpNicMappingVO.java create mode 100644 plugins/network-elements/nicira-nvp/src/com/cloud/network/dao/NiciraNvpDao.java create mode 100644 plugins/network-elements/nicira-nvp/src/com/cloud/network/dao/NiciraNvpDaoImpl.java create mode 100644 plugins/network-elements/nicira-nvp/src/com/cloud/network/dao/NiciraNvpNicMappingDao.java create mode 100644 plugins/network-elements/nicira-nvp/src/com/cloud/network/dao/NiciraNvpNicMappingDaoImpl.java create mode 100644 plugins/network-elements/nicira-nvp/src/com/cloud/network/element/NiciraNvpElement.java create mode 100644 plugins/network-elements/nicira-nvp/src/com/cloud/network/element/NiciraNvpElementService.java create mode 100644 plugins/network-elements/nicira-nvp/src/com/cloud/network/guru/NiciraNvpGuestNetworkGuru.java create mode 100644 plugins/network-elements/nicira-nvp/src/com/cloud/network/nicira/Attachment.java create mode 100644 plugins/network-elements/nicira-nvp/src/com/cloud/network/nicira/LogicalSwitch.java create mode 100644 plugins/network-elements/nicira-nvp/src/com/cloud/network/nicira/LogicalSwitchPort.java create mode 100644 plugins/network-elements/nicira-nvp/src/com/cloud/network/nicira/NiciraNvpApi.java create mode 100644 plugins/network-elements/nicira-nvp/src/com/cloud/network/nicira/NiciraNvpApiException.java create mode 100644 plugins/network-elements/nicira-nvp/src/com/cloud/network/nicira/NiciraNvpList.java create mode 100644 plugins/network-elements/nicira-nvp/src/com/cloud/network/nicira/NiciraNvpTag.java create mode 100644 plugins/network-elements/nicira-nvp/src/com/cloud/network/nicira/TransportZoneBinding.java create mode 100644 plugins/network-elements/nicira-nvp/src/com/cloud/network/nicira/VifAttachment.java create mode 100644 plugins/network-elements/nicira-nvp/src/com/cloud/network/resource/NiciraNvpResource.java diff --git a/api/src/com/cloud/agent/api/to/NicTO.java b/api/src/com/cloud/agent/api/to/NicTO.java index b65c61ee47c..79a43d2e625 100644 --- a/api/src/com/cloud/agent/api/to/NicTO.java +++ b/api/src/com/cloud/agent/api/to/NicTO.java @@ -21,6 +21,7 @@ public class NicTO extends NetworkTO { Integer networkRateMbps; Integer networkRateMulticastMbps; boolean defaultNic; + String uuid; public NicTO() { super(); @@ -54,6 +55,16 @@ public class NicTO extends NetworkTO { this.defaultNic = defaultNic; } + @Override + public String getUuid() { + return uuid; + } + + @Override + public void setUuid(String uuid) { + this.uuid = uuid; + } + @Override public String toString() { return new StringBuilder("[Nic:").append(type).append("-").append(ip).append("-").append(broadcastUri).append("]").toString(); diff --git a/api/src/com/cloud/agent/api/to/VirtualMachineTO.java b/api/src/com/cloud/agent/api/to/VirtualMachineTO.java index 42d91626e35..a93c242b7c1 100644 --- a/api/src/com/cloud/agent/api/to/VirtualMachineTO.java +++ b/api/src/com/cloud/agent/api/to/VirtualMachineTO.java @@ -42,6 +42,7 @@ public class VirtualMachineTO { String vncPassword; String vncAddr; Map params; + String uuid; VolumeTO[] disks; NicTO[] nics; @@ -208,4 +209,14 @@ public class VirtualMachineTO { public void setDetails(Map params) { this.params = params; } + + public String getUuid() { + return uuid; + } + + public void setUuid(String uuid) { + this.uuid = uuid; + } + + } diff --git a/api/src/com/cloud/api/ApiConstants.java b/api/src/com/cloud/api/ApiConstants.java index 00ec392d7b9..e4105769084 100755 --- a/api/src/com/cloud/api/ApiConstants.java +++ b/api/src/com/cloud/api/ApiConstants.java @@ -361,6 +361,10 @@ public class ApiConstants { public static final String RESOURCE_IDS = "resourceids"; public static final String RESOURCE_ID = "resourceid"; public static final String CUSTOMER = "customer"; + public static final String NICIRA_NVP_DEVICE_ID = "nvpdeviceid"; + public static final String NICIRA_NVP_TRANSPORT_ZONE_UUID = "transportzoneuuid"; + public static final String NICIRA_NVP_DEVICE_NAME = "niciradevicename"; + public enum HostDetails { all, capacity, events, stats, min; diff --git a/api/src/com/cloud/host/Host.java b/api/src/com/cloud/host/Host.java index 0c9d06d48bf..1bac0d20a40 100755 --- a/api/src/com/cloud/host/Host.java +++ b/api/src/com/cloud/host/Host.java @@ -41,7 +41,8 @@ public interface Host extends StateObject { ExternalDhcp(false), SecondaryStorageVM(true), - LocalSecondaryStorage(false); + LocalSecondaryStorage(false), + L2Networking(false); boolean _virtual; private Type(boolean virtual) { _virtual = virtual; diff --git a/api/src/com/cloud/network/Network.java b/api/src/com/cloud/network/Network.java index 0443a0f41cc..459b05bc6ab 100644 --- a/api/src/com/cloud/network/Network.java +++ b/api/src/com/cloud/network/Network.java @@ -52,6 +52,7 @@ public interface Network extends ControlledEntity { public static final Service StaticNat = new Service("StaticNat", Capability.ElasticIp); public static final Service PortForwarding = new Service("PortForwarding"); public static final Service SecurityGroup = new Service("SecurityGroup"); + public static final Service Connectivity = new Service("Connectivity"); private String name; private Capability[] caps; @@ -114,6 +115,7 @@ public interface Network extends ControlledEntity { public static final Provider ElasticLoadBalancerVm = new Provider("ElasticLoadBalancerVm", false); public static final Provider SecurityGroupProvider = new Provider("SecurityGroupProvider", false); public static final Provider None = new Provider("None", false); + public static final Provider NiciraNvp = new Provider("NiciraNvp", true); private String name; private boolean isExternal; diff --git a/api/src/com/cloud/network/Networks.java b/api/src/com/cloud/network/Networks.java index 84135b8ee45..b96eaa2ff6c 100755 --- a/api/src/com/cloud/network/Networks.java +++ b/api/src/com/cloud/network/Networks.java @@ -61,6 +61,7 @@ public class Networks { LinkLocal(null, null), Vnet("vnet", Long.class), Storage("storage", Integer.class), + Lswitch("lswitch", String.class), UnDecided(null, null); private String scheme; diff --git a/api/src/com/cloud/network/PhysicalNetwork.java b/api/src/com/cloud/network/PhysicalNetwork.java index e54fe00bef0..be4b1d0d352 100644 --- a/api/src/com/cloud/network/PhysicalNetwork.java +++ b/api/src/com/cloud/network/PhysicalNetwork.java @@ -31,7 +31,8 @@ public interface PhysicalNetwork { public enum IsolationMethod { VLAN, L3, - GRE; + GRE, + STT; } public enum BroadcastDomainRange { diff --git a/build/build-cloud-plugins.xml b/build/build-cloud-plugins.xml index 61b0e624901..c16474d3fbf 100755 --- a/build/build-cloud-plugins.xml +++ b/build/build-cloud-plugins.xml @@ -279,8 +279,8 @@ - - + + @@ -301,6 +301,12 @@ + + + + + + diff --git a/build/package.xml b/build/package.xml index 2b5a74b123a..d61c6983609 100755 --- a/build/package.xml +++ b/build/package.xml @@ -225,6 +225,7 @@ + diff --git a/client/tomcatconf/components.xml.in b/client/tomcatconf/components.xml.in index f36355d4ff3..16d7b198367 100755 --- a/client/tomcatconf/components.xml.in +++ b/client/tomcatconf/components.xml.in @@ -70,7 +70,7 @@ However, above case barely happens. --> - + @@ -78,6 +78,7 @@ + @@ -142,6 +143,7 @@ + @@ -165,10 +167,13 @@ + + + diff --git a/client/tomcatconf/nicira-nvp_commands.properties.in b/client/tomcatconf/nicira-nvp_commands.properties.in new file mode 100644 index 00000000000..8e749d6bf29 --- /dev/null +++ b/client/tomcatconf/nicira-nvp_commands.properties.in @@ -0,0 +1,12 @@ +### bitmap of permissions at the end of each classname, 1 = ADMIN, 2 = RESOURCE_DOMAIN_ADMIN, 4 = DOMAIN_ADMIN, 8 = USER +### Please standardize naming conventions to camel-case (even for acronyms). + +#### nicira nvp commands + +addNiciraNvpDevice = com.cloud.api.commands.AddNiciraNvpDeviceCmd;1 +deleteNiciraNvpDevice = com.cloud.api.commands.DeleteNiciraNvpDeviceCmd;1 +listNiciraNvpDevices = com.cloud.api.commands.ListNiciraNvpDevicesCmd;1 +listNiciraNvpDeviceNetworks = com.cloud.api.commands.ListNiciraNvpDeviceNetworksCmd;1 + +# Not implemented (yet) +#configureNiciraNvpDevice = com.cloud.api.commands.ConfigureNiciraNvpDeviceCmd;1 \ No newline at end of file diff --git a/cloud.spec b/cloud.spec index 773a729ae06..7233f0150e2 100644 --- a/cloud.spec +++ b/cloud.spec @@ -427,6 +427,7 @@ fi %{_javadir}/%{name}-user-authenticator-plaintext.jar %{_javadir}/%{name}-vmware.jar %{_javadir}/%{name}-xen.jar +%{_javadir}/%{name}-plugin-nicira-nvp.jar %{_javadir}/%{name}-plugin-elb.jar %{_javadir}/%{name}-plugin-netapp.jar %config(noreplace) %{_sysconfdir}/%{name}/server/* 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 496aeb33020..c81d4613509 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 @@ -751,12 +751,17 @@ public abstract class CitrixResourceBase implements ServerResource, HypervisorRe long vlan = Long.parseLong(broadcastUri.getHost()); return enableVlanNetwork(conn, vlan, network); } + } else if (nic.getBroadcastType() == BroadcastDomainType.Lswitch) { + // Nicira Logical Switch + return network.getNetwork(); } throw new CloudRuntimeException("Unable to support this type of network broadcast domain: " + nic.getBroadcastUri()); } protected VIF createVif(Connection conn, String vmName, VM vm, NicTO nic) throws XmlRpcException, XenAPIException { + assert(nic.getUuid() != null) : "Nic should have a uuid value"; + if (s_logger.isDebugEnabled()) { s_logger.debug("Creating VIF for " + vmName + " on nic " + nic); } @@ -765,7 +770,12 @@ public abstract class CitrixResourceBase implements ServerResource, HypervisorRe vifr.VM = vm; vifr.device = Integer.toString(nic.getDeviceId()); vifr.MAC = nic.getMac(); - + + // Nicira needs these IDs to find the NIC + vifr.otherConfig = new HashMap(); + vifr.otherConfig.put("nicira-iface-id", nic.getUuid()); + vifr.otherConfig.put("nicira-vm-id", vm.getUuid(conn)); + vifr.network = getNetwork(conn, nic); if (nic.getNetworkRateMbps() != null && nic.getNetworkRateMbps().intValue() != -1) { diff --git a/plugins/network-elements/nicira-nvp/.classpath b/plugins/network-elements/nicira-nvp/.classpath new file mode 100644 index 00000000000..edbcfa2399f --- /dev/null +++ b/plugins/network-elements/nicira-nvp/.classpath @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/plugins/network-elements/nicira-nvp/.project b/plugins/network-elements/nicira-nvp/.project new file mode 100644 index 00000000000..15d5c676eb4 --- /dev/null +++ b/plugins/network-elements/nicira-nvp/.project @@ -0,0 +1,17 @@ + + + nicira-nvp + + + + + + org.eclipse.jdt.core.javabuilder + + + + + + org.eclipse.jdt.core.javanature + + diff --git a/plugins/network-elements/nicira-nvp/README.NiciraIntegration b/plugins/network-elements/nicira-nvp/README.NiciraIntegration new file mode 100644 index 00000000000..4ab74cdb532 --- /dev/null +++ b/plugins/network-elements/nicira-nvp/README.NiciraIntegration @@ -0,0 +1,68 @@ +Nicira Network Virtualization Platform (NVP) integration code is contributed +by Nicira and Schuberg Philis and copyright is donated to the Apache Software +Foundation. + +Authors + Somik Behera + Hugo Trippaers + +== New API Calls + +The following API calls are added to CloudStack to support the integrations with +the Nicira NVP platform. Please see the API documentation of CloudStack for +parameters and return values. + + * addNiciraNvpDevice + * deleteNiciraNvpDevice + * listNiciraNvpDevices + * listNiciraNvpDeviceNetworks + +== How to enable the Nicira NVP integration. + +When configuring a zone create a new physical network for "Guest" traffic and +select "STT" as the isolation type. Set the Xen traffic label for "Guest" +traffic to the label of the integration bridge (refer to the Nicira +Documentation for setting up the integration bridge). Note that this requires +all traffic types to have their traffic labels set. + +These steps are specified by the API calls as there is currently no GUI +available. + +1. addNetworkServiceProvider + name="NiciraNvp", physicalnetworkid=, + servicelist="Connectivity" +2. updateNetworkServiceProvider + id=, state="Enabled" +3. addNiciraNvpDevice + physicalnetworkid=, + hostname= + username= + password= + transportzoneuuid= + +== How to use the Nicira integration + +When creating a guest network make sure it is created in the physical network +with the isolation type set to "STT". When the first virtual machine is +launched in this network the NiciraNvpNetworkGuru will configure a logical +switch on the NVP Controller. During the startup of a virtual machine the +NiciraNvpElement will create a logical port for any NICs in the guest networks +and attach the port to the existing logical swith. + +== Debugging/Troubleshooting + +All elements created on the NVP controller have tags with the name of the +account, this can be used to search the items using the NVP manager. The NVP +uuid of the logical switch is also stored in the BroadcastUri of the +corresponding Guest network in an lswitch uri scheme. The CloudStack uuid of +the NIC is used to make the Vif attachement on the logical switchport. + +The following classes should be set to log level debug when troubleshooting. + com.cloud.network + (Most NiciraNvp related objects live in this package and subpackages) + org.apache.commons.httpclient + (used by NiciraNvpApi to make calls to the SDN Controller) + httpclient.wire + (wirelevel http tracing of httpclient) + +Please report any findings to the developer mailing list. diff --git a/plugins/network-elements/nicira-nvp/build.xml b/plugins/network-elements/nicira-nvp/build.xml new file mode 100644 index 00000000000..2d84c5c455f --- /dev/null +++ b/plugins/network-elements/nicira-nvp/build.xml @@ -0,0 +1,129 @@ + + + + + + + Cloud Stack ant build file + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plugins/network-elements/nicira-nvp/src/com/cloud/agent/api/CreateLogicalSwitchAnswer.java b/plugins/network-elements/nicira-nvp/src/com/cloud/agent/api/CreateLogicalSwitchAnswer.java new file mode 100644 index 00000000000..c9a2f8c62f3 --- /dev/null +++ b/plugins/network-elements/nicira-nvp/src/com/cloud/agent/api/CreateLogicalSwitchAnswer.java @@ -0,0 +1,20 @@ +package com.cloud.agent.api; + +public class CreateLogicalSwitchAnswer extends Answer { + private String _logicalSwitchUuid; + + public CreateLogicalSwitchAnswer(Command command, boolean success, + String details, String logicalSwitchUuid) { + super(command, success, details); + this._logicalSwitchUuid = logicalSwitchUuid; + } + + public CreateLogicalSwitchAnswer(Command command, Exception e) { + super(command, e); + } + + public String getLogicalSwitchUuid() { + return _logicalSwitchUuid; + } + +} diff --git a/plugins/network-elements/nicira-nvp/src/com/cloud/agent/api/CreateLogicalSwitchCommand.java b/plugins/network-elements/nicira-nvp/src/com/cloud/agent/api/CreateLogicalSwitchCommand.java new file mode 100644 index 00000000000..acc347d0818 --- /dev/null +++ b/plugins/network-elements/nicira-nvp/src/com/cloud/agent/api/CreateLogicalSwitchCommand.java @@ -0,0 +1,38 @@ +package com.cloud.agent.api; + +public class CreateLogicalSwitchCommand extends Command { + + private String _transportUuid; + private String _transportType; + private String _name; + private String _ownerName; + + public CreateLogicalSwitchCommand(String transportUuid, String transportType, String name, String ownerName) { + this._transportUuid = transportUuid; + this._transportType = transportType; + this._name = name; + this._ownerName = ownerName; + } + + @Override + public boolean executeInSequence() { + return false; + } + + public String getTransportUuid() { + return _transportUuid; + } + + public String getTransportType() { + return _transportType; + } + + public String getName() { + return _name; + } + + public String getOwnerName() { + return _ownerName; + } + +} diff --git a/plugins/network-elements/nicira-nvp/src/com/cloud/agent/api/CreateLogicalSwitchPortAnswer.java b/plugins/network-elements/nicira-nvp/src/com/cloud/agent/api/CreateLogicalSwitchPortAnswer.java new file mode 100644 index 00000000000..88522af4909 --- /dev/null +++ b/plugins/network-elements/nicira-nvp/src/com/cloud/agent/api/CreateLogicalSwitchPortAnswer.java @@ -0,0 +1,20 @@ +package com.cloud.agent.api; + +public class CreateLogicalSwitchPortAnswer extends Answer { + private String _logicalSwitchPortUuid; + + public CreateLogicalSwitchPortAnswer(Command command, boolean success, + String details, String localSwitchPortUuid) { + super(command, success, details); + this._logicalSwitchPortUuid = localSwitchPortUuid; + } + + public String getLogicalSwitchPortUuid() { + return _logicalSwitchPortUuid; + } + + public CreateLogicalSwitchPortAnswer(Command command, Exception e) { + super(command, e); + } + +} diff --git a/plugins/network-elements/nicira-nvp/src/com/cloud/agent/api/CreateLogicalSwitchPortCommand.java b/plugins/network-elements/nicira-nvp/src/com/cloud/agent/api/CreateLogicalSwitchPortCommand.java new file mode 100644 index 00000000000..af6f52921b7 --- /dev/null +++ b/plugins/network-elements/nicira-nvp/src/com/cloud/agent/api/CreateLogicalSwitchPortCommand.java @@ -0,0 +1,42 @@ +package com.cloud.agent.api; + +public class CreateLogicalSwitchPortCommand extends Command { + private String _logicalSwitchUuid; + private String _attachmentUuid; + private String _ownerName; + private String _nicName; + + public CreateLogicalSwitchPortCommand(String logicalSwitchUuid, String attachmentUuid, String ownerName, String nicName) { + this._logicalSwitchUuid = logicalSwitchUuid; + this._attachmentUuid = attachmentUuid; + this._ownerName = ownerName; + this._nicName = nicName; + } + + + public String getLogicalSwitchUuid() { + return _logicalSwitchUuid; + } + + + public String getAttachmentUuid() { + return _attachmentUuid; + } + + + public String getOwnerName() { + return _ownerName; + } + + + public String getNicName() { + return _nicName; + } + + + @Override + public boolean executeInSequence() { + return false; + } + +} diff --git a/plugins/network-elements/nicira-nvp/src/com/cloud/agent/api/DeleteLogicalSwitchAnswer.java b/plugins/network-elements/nicira-nvp/src/com/cloud/agent/api/DeleteLogicalSwitchAnswer.java new file mode 100644 index 00000000000..cec44bcf332 --- /dev/null +++ b/plugins/network-elements/nicira-nvp/src/com/cloud/agent/api/DeleteLogicalSwitchAnswer.java @@ -0,0 +1,14 @@ +package com.cloud.agent.api; + +public class DeleteLogicalSwitchAnswer extends Answer { + + public DeleteLogicalSwitchAnswer(Command command, boolean success, + String details) { + super(command, success, details); + } + + public DeleteLogicalSwitchAnswer(Command command, Exception e) { + super(command, e); + } + +} diff --git a/plugins/network-elements/nicira-nvp/src/com/cloud/agent/api/DeleteLogicalSwitchCommand.java b/plugins/network-elements/nicira-nvp/src/com/cloud/agent/api/DeleteLogicalSwitchCommand.java new file mode 100644 index 00000000000..04c7630b8f5 --- /dev/null +++ b/plugins/network-elements/nicira-nvp/src/com/cloud/agent/api/DeleteLogicalSwitchCommand.java @@ -0,0 +1,19 @@ +package com.cloud.agent.api; + +public class DeleteLogicalSwitchCommand extends Command { + + private String _logicalSwitchUuid; + + public DeleteLogicalSwitchCommand(String logicalSwitchUuid) { + this._logicalSwitchUuid = logicalSwitchUuid; + } + + @Override + public boolean executeInSequence() { + return false; + } + + public String getLogicalSwitchUuid() { + return _logicalSwitchUuid; + } +} diff --git a/plugins/network-elements/nicira-nvp/src/com/cloud/agent/api/DeleteLogicalSwitchPortAnswer.java b/plugins/network-elements/nicira-nvp/src/com/cloud/agent/api/DeleteLogicalSwitchPortAnswer.java new file mode 100644 index 00000000000..008d44c1ad8 --- /dev/null +++ b/plugins/network-elements/nicira-nvp/src/com/cloud/agent/api/DeleteLogicalSwitchPortAnswer.java @@ -0,0 +1,14 @@ +package com.cloud.agent.api; + +public class DeleteLogicalSwitchPortAnswer extends Answer { + + public DeleteLogicalSwitchPortAnswer(Command command, boolean success, + String details) { + super(command, success, details); + } + + public DeleteLogicalSwitchPortAnswer(Command command, Exception e) { + super(command, e); + } + +} diff --git a/plugins/network-elements/nicira-nvp/src/com/cloud/agent/api/DeleteLogicalSwitchPortCommand.java b/plugins/network-elements/nicira-nvp/src/com/cloud/agent/api/DeleteLogicalSwitchPortCommand.java new file mode 100644 index 00000000000..b3a7d6474fc --- /dev/null +++ b/plugins/network-elements/nicira-nvp/src/com/cloud/agent/api/DeleteLogicalSwitchPortCommand.java @@ -0,0 +1,25 @@ +package com.cloud.agent.api; + +public class DeleteLogicalSwitchPortCommand extends Command { + private String _logicalSwitchUuid; + private String _logicalSwithPortUuid; + + public DeleteLogicalSwitchPortCommand(String logicalSwitchUuid, String logicalSwitchPortUuid) { + this._logicalSwitchUuid = logicalSwitchUuid; + this._logicalSwithPortUuid = logicalSwitchPortUuid; + } + + public String getLogicalSwitchUuid() { + return _logicalSwitchUuid; + } + + public String getLogicalSwitchPortUuid() { + return _logicalSwithPortUuid; + } + + @Override + public boolean executeInSequence() { + return false; + } + +} diff --git a/plugins/network-elements/nicira-nvp/src/com/cloud/agent/api/StartupNiciraNvpCommand.java b/plugins/network-elements/nicira-nvp/src/com/cloud/agent/api/StartupNiciraNvpCommand.java new file mode 100644 index 00000000000..a57c2fd6d03 --- /dev/null +++ b/plugins/network-elements/nicira-nvp/src/com/cloud/agent/api/StartupNiciraNvpCommand.java @@ -0,0 +1,11 @@ +package com.cloud.agent.api; + +import com.cloud.host.Host; + +public class StartupNiciraNvpCommand extends StartupCommand { + + public StartupNiciraNvpCommand() { + super(Host.Type.L2Networking); + } + +} diff --git a/plugins/network-elements/nicira-nvp/src/com/cloud/api/commands/AddNiciraNvpDeviceCmd.java b/plugins/network-elements/nicira-nvp/src/com/cloud/api/commands/AddNiciraNvpDeviceCmd.java new file mode 100644 index 00000000000..e32d7d2b84e --- /dev/null +++ b/plugins/network-elements/nicira-nvp/src/com/cloud/api/commands/AddNiciraNvpDeviceCmd.java @@ -0,0 +1,110 @@ +package com.cloud.api.commands; + +import org.apache.log4j.Logger; + +import com.cloud.api.ApiConstants; +import com.cloud.api.BaseAsyncCmd; +import com.cloud.api.BaseCmd; +import com.cloud.api.IdentityMapper; +import com.cloud.api.Implementation; +import com.cloud.api.Parameter; +import com.cloud.api.PlugService; +import com.cloud.api.ServerApiException; +import com.cloud.api.BaseCmd.CommandType; +import com.cloud.api.response.NiciraNvpDeviceResponse; +import com.cloud.event.EventTypes; +import com.cloud.exception.ConcurrentOperationException; +import com.cloud.exception.InsufficientCapacityException; +import com.cloud.exception.InvalidParameterValueException; +import com.cloud.exception.NetworkRuleConflictException; +import com.cloud.exception.ResourceAllocationException; +import com.cloud.exception.ResourceUnavailableException; +import com.cloud.network.ExternalLoadBalancerDeviceVO; +import com.cloud.network.NiciraNvpDeviceVO; +import com.cloud.network.element.NiciraNvpElementService; +import com.cloud.user.UserContext; +import com.cloud.utils.exception.CloudRuntimeException; + +@Implementation(responseObject=NiciraNvpDeviceResponse.class, description="Adds a Nicira NVP device") +public class AddNiciraNvpDeviceCmd extends BaseCmd { + private static final Logger s_logger = Logger.getLogger(AddNiciraNvpDeviceCmd.class.getName()); + private static final String s_name = "addniciranvpdevice"; + @PlugService NiciraNvpElementService _niciraNvpElementService; + + ///////////////////////////////////////////////////// + //////////////// API parameters ///////////////////// + ///////////////////////////////////////////////////// + + @IdentityMapper(entityTableName="physical_network") + @Parameter(name=ApiConstants.PHYSICAL_NETWORK_ID, type=CommandType.LONG, required=true, description="the Physical Network ID") + private Long physicalNetworkId; + + @Parameter(name=ApiConstants.HOST_NAME, type=CommandType.STRING, required = true, description="Hostname of ip address of the Nicira NVP Controller.") + private String host; + + @Parameter(name=ApiConstants.USERNAME, type=CommandType.STRING, required = true, description="Credentials to access the Nicira Controller API") + private String username; + + @Parameter(name=ApiConstants.PASSWORD, type=CommandType.STRING, required = true, description="Credentials to access the Nicira Controller API") + private String password; + + @Parameter(name=ApiConstants.NICIRA_NVP_TRANSPORT_ZONE_UUID, type=CommandType.STRING, required = true, description="The Transportzone UUID configured on the Nicira Controller") + private String transportzoneuuid; + + ///////////////////////////////////////////////////// + /////////////////// Accessors /////////////////////// + ///////////////////////////////////////////////////// + + public Long getPhysicalNetworkId() { + return physicalNetworkId; + } + + public String getHost() { + return host; + } + + public String getUsername() { + return username; + } + + public String getPassword() { + return password; + } + + public String getTransportzoneUuid() { + return transportzoneuuid; + } + + ///////////////////////////////////////////////////// + /////////////// API Implementation/////////////////// + ///////////////////////////////////////////////////// + + @Override + public void execute() throws ResourceUnavailableException, InsufficientCapacityException, ServerApiException, ConcurrentOperationException, ResourceAllocationException { + try { + NiciraNvpDeviceVO niciraNvpDeviceVO = _niciraNvpElementService.addNiciraNvpDevice(this); + if (niciraNvpDeviceVO != null) { + NiciraNvpDeviceResponse response = _niciraNvpElementService.createNiciraNvpDeviceResponse(niciraNvpDeviceVO); + response.setObjectName("niciranvpdevice"); + response.setResponseName(getCommandName()); + this.setResponseObject(response); + } else { + throw new ServerApiException(BaseAsyncCmd.INTERNAL_ERROR, "Failed to add Nicira NVP device due to internal error."); + } + } catch (InvalidParameterValueException invalidParamExcp) { + throw new ServerApiException(BaseCmd.PARAM_ERROR, invalidParamExcp.getMessage()); + } catch (CloudRuntimeException runtimeExcp) { + throw new ServerApiException(BaseCmd.INTERNAL_ERROR, runtimeExcp.getMessage()); + } + } + + @Override + public String getCommandName() { + return s_name; + } + + @Override + public long getEntityOwnerId() { + return UserContext.current().getCaller().getId(); + } +} diff --git a/plugins/network-elements/nicira-nvp/src/com/cloud/api/commands/DeleteNiciraNvpDeviceCmd.java b/plugins/network-elements/nicira-nvp/src/com/cloud/api/commands/DeleteNiciraNvpDeviceCmd.java new file mode 100644 index 00000000000..181a74792b8 --- /dev/null +++ b/plugins/network-elements/nicira-nvp/src/com/cloud/api/commands/DeleteNiciraNvpDeviceCmd.java @@ -0,0 +1,76 @@ +package com.cloud.api.commands; + +import org.apache.log4j.Logger; + +import com.cloud.api.ApiConstants; +import com.cloud.api.BaseCmd; +import com.cloud.api.IdentityMapper; +import com.cloud.api.Implementation; +import com.cloud.api.Parameter; +import com.cloud.api.PlugService; +import com.cloud.api.ServerApiException; +import com.cloud.api.response.SuccessResponse; +import com.cloud.exception.ConcurrentOperationException; +import com.cloud.exception.InsufficientCapacityException; +import com.cloud.exception.InvalidParameterValueException; +import com.cloud.exception.ResourceAllocationException; +import com.cloud.exception.ResourceUnavailableException; +import com.cloud.network.element.NiciraNvpElementService; +import com.cloud.user.UserContext; +import com.cloud.utils.exception.CloudRuntimeException; + +@Implementation(responseObject=SuccessResponse.class, description=" delete a nicira nvp device") +public class DeleteNiciraNvpDeviceCmd extends BaseCmd { + private static final Logger s_logger = Logger.getLogger(DeleteNiciraNvpDeviceCmd.class.getName()); + private static final String s_name = "addniciranvpdevice"; + @PlugService NiciraNvpElementService _niciraNvpElementService; + + ///////////////////////////////////////////////////// + //////////////// API parameters ///////////////////// + ///////////////////////////////////////////////////// + + @IdentityMapper(entityTableName="external_nicira_nvp_devices") + @Parameter(name=ApiConstants.NICIRA_NVP_DEVICE_ID, type=CommandType.LONG, required=true, description="Nicira device ID") + private Long niciraNvpDeviceId; + + ///////////////////////////////////////////////////// + /////////////////// Accessors /////////////////////// + ///////////////////////////////////////////////////// + + public Long getNiciraNvpDeviceId() { + return niciraNvpDeviceId; + } + + ///////////////////////////////////////////////////// + /////////////// API Implementation/////////////////// + ///////////////////////////////////////////////////// + + @Override + public void execute() throws ResourceUnavailableException, InsufficientCapacityException, ServerApiException, ConcurrentOperationException, ResourceAllocationException { + try { + boolean result = _niciraNvpElementService.deleteNiciraNvpDevice(this); + if (result) { + SuccessResponse response = new SuccessResponse(getCommandName()); + response.setResponseName(getCommandName()); + this.setResponseObject(response); + } else { + throw new ServerApiException(BaseCmd.INTERNAL_ERROR, "Failed to delete Nicira device."); + } + } catch (InvalidParameterValueException invalidParamExcp) { + throw new ServerApiException(BaseCmd.PARAM_ERROR, invalidParamExcp.getMessage()); + } catch (CloudRuntimeException runtimeExcp) { + throw new ServerApiException(BaseCmd.INTERNAL_ERROR, runtimeExcp.getMessage()); + } + } + + @Override + public String getCommandName() { + return s_name; + } + + @Override + public long getEntityOwnerId() { + return UserContext.current().getCaller().getId(); + } + +} diff --git a/plugins/network-elements/nicira-nvp/src/com/cloud/api/commands/ListNiciraNvpDeviceNetworksCmd.java b/plugins/network-elements/nicira-nvp/src/com/cloud/api/commands/ListNiciraNvpDeviceNetworksCmd.java new file mode 100644 index 00000000000..b4c1f88d1f8 --- /dev/null +++ b/plugins/network-elements/nicira-nvp/src/com/cloud/api/commands/ListNiciraNvpDeviceNetworksCmd.java @@ -0,0 +1,85 @@ +package com.cloud.api.commands; + +import java.util.ArrayList; +import java.util.List; + +import org.apache.log4j.Logger; + +import com.cloud.api.ApiConstants; +import com.cloud.api.BaseCmd; +import com.cloud.api.BaseListCmd; +import com.cloud.api.IdentityMapper; +import com.cloud.api.Implementation; +import com.cloud.api.Parameter; +import com.cloud.api.PlugService; +import com.cloud.api.ServerApiException; +import com.cloud.api.BaseCmd.CommandType; +import com.cloud.api.response.ListResponse; +import com.cloud.api.response.NetworkResponse; +import com.cloud.exception.ConcurrentOperationException; +import com.cloud.exception.InsufficientCapacityException; +import com.cloud.exception.InvalidParameterValueException; +import com.cloud.exception.NetworkRuleConflictException; +import com.cloud.exception.ResourceAllocationException; +import com.cloud.exception.ResourceUnavailableException; +import com.cloud.network.Network; +import com.cloud.network.element.NiciraNvpElementService; +import com.cloud.utils.exception.CloudRuntimeException; + +@Implementation(responseObject=NetworkResponse.class, description="lists network that are using a nicira nvp device") +public class ListNiciraNvpDeviceNetworksCmd extends BaseListCmd { + + public static final Logger s_logger = Logger.getLogger(ListNiciraNvpDeviceNetworksCmd.class.getName()); + private static final String s_name = "listniciranvpdevicenetworks"; + @PlugService NiciraNvpElementService _niciraNvpElementService; + + ///////////////////////////////////////////////////// + //////////////// API parameters ///////////////////// + ///////////////////////////////////////////////////// + + @IdentityMapper(entityTableName="external_nicira_nvp_devices") + @Parameter(name=ApiConstants.NICIRA_NVP_DEVICE_ID, type=CommandType.LONG, required = true, description="nicira nvp device ID") + private Long niciraNvpDeviceId; + + ///////////////////////////////////////////////////// + /////////////////// Accessors /////////////////////// + ///////////////////////////////////////////////////// + + public Long getNiciraNvpDeviceId() { + return niciraNvpDeviceId; + } + + ///////////////////////////////////////////////////// + /////////////// API Implementation/////////////////// + ///////////////////////////////////////////////////// + + @Override + public void execute() throws ResourceUnavailableException, InsufficientCapacityException, ServerApiException, ConcurrentOperationException, ResourceAllocationException { + try { + List networks = _niciraNvpElementService.listNiciraNvpDeviceNetworks(this); + ListResponse response = new ListResponse(); + List networkResponses = new ArrayList(); + + if (networks != null && !networks.isEmpty()) { + for (Network network : networks) { + NetworkResponse networkResponse = _responseGenerator.createNetworkResponse(network); + networkResponses.add(networkResponse); + } + } + + response.setResponses(networkResponses); + response.setResponseName(getCommandName()); + this.setResponseObject(response); + } catch (InvalidParameterValueException invalidParamExcp) { + throw new ServerApiException(BaseCmd.PARAM_ERROR, invalidParamExcp.getMessage()); + } catch (CloudRuntimeException runtimeExcp) { + throw new ServerApiException(BaseCmd.INTERNAL_ERROR, runtimeExcp.getMessage()); + } + } + + @Override + public String getCommandName() { + return s_name; + } + +} diff --git a/plugins/network-elements/nicira-nvp/src/com/cloud/api/commands/ListNiciraNvpDevicesCmd.java b/plugins/network-elements/nicira-nvp/src/com/cloud/api/commands/ListNiciraNvpDevicesCmd.java new file mode 100644 index 00000000000..a521f0e7643 --- /dev/null +++ b/plugins/network-elements/nicira-nvp/src/com/cloud/api/commands/ListNiciraNvpDevicesCmd.java @@ -0,0 +1,90 @@ +package com.cloud.api.commands; + +import java.util.ArrayList; +import java.util.List; + +import org.apache.log4j.Logger; + +import com.cloud.api.ApiConstants; +import com.cloud.api.BaseCmd; +import com.cloud.api.BaseListCmd; +import com.cloud.api.IdentityMapper; +import com.cloud.api.Implementation; +import com.cloud.api.Parameter; +import com.cloud.api.PlugService; +import com.cloud.api.ServerApiException; +import com.cloud.api.response.ListResponse; +import com.cloud.api.response.NiciraNvpDeviceResponse; +import com.cloud.exception.ConcurrentOperationException; +import com.cloud.exception.InsufficientCapacityException; +import com.cloud.exception.InvalidParameterValueException; +import com.cloud.exception.ResourceAllocationException; +import com.cloud.exception.ResourceUnavailableException; +import com.cloud.network.NiciraNvpDeviceVO; +import com.cloud.network.element.NiciraNvpElementService; +import com.cloud.utils.exception.CloudRuntimeException; + +@Implementation(responseObject=NiciraNvpDeviceResponse.class, description="Lists Nicira NVP devices") +public class ListNiciraNvpDevicesCmd extends BaseListCmd { + private static final Logger s_logger = Logger.getLogger(ListNiciraNvpDevicesCmd.class.getName()); + private static final String s_name = "listniciranvpdevices"; + @PlugService NiciraNvpElementService _niciraNvpElementService; + + ///////////////////////////////////////////////////// + //////////////// API parameters ///////////////////// + ///////////////////////////////////////////////////// + + @IdentityMapper(entityTableName="physical_network") + @Parameter(name=ApiConstants.PHYSICAL_NETWORK_ID, type=CommandType.LONG, description="the Physical Network ID") + private Long physicalNetworkId; + + @IdentityMapper(entityTableName="external_nicira_nvp_devices") + @Parameter(name=ApiConstants.NICIRA_NVP_DEVICE_ID, type=CommandType.LONG, description="nicira nvp device ID") + private Long niciraNvpDeviceId; + + ///////////////////////////////////////////////////// + /////////////////// Accessors /////////////////////// + ///////////////////////////////////////////////////// + + public Long getNiciraNvpDeviceId() { + return niciraNvpDeviceId; + } + + public Long getPhysicalNetworkId() { + return physicalNetworkId; + } + + ///////////////////////////////////////////////////// + /////////////// API Implementation/////////////////// + ///////////////////////////////////////////////////// + + @Override + public void execute() throws ResourceUnavailableException, InsufficientCapacityException, ServerApiException, ConcurrentOperationException, ResourceAllocationException { + try { + List niciraDevices = _niciraNvpElementService.listNiciraNvpDevices(this); + ListResponse response = new ListResponse(); + List niciraDevicesResponse = new ArrayList(); + + if (niciraDevices != null && !niciraDevices.isEmpty()) { + for (NiciraNvpDeviceVO niciraDeviceVO : niciraDevices) { + NiciraNvpDeviceResponse niciraDeviceResponse = _niciraNvpElementService.createNiciraNvpDeviceResponse(niciraDeviceVO); + niciraDevicesResponse.add(niciraDeviceResponse); + } + } + + response.setResponses(niciraDevicesResponse); + response.setResponseName(getCommandName()); + this.setResponseObject(response); + } catch (InvalidParameterValueException invalidParamExcp) { + throw new ServerApiException(BaseCmd.PARAM_ERROR, invalidParamExcp.getMessage()); + } catch (CloudRuntimeException runtimeExcp) { + throw new ServerApiException(BaseCmd.INTERNAL_ERROR, runtimeExcp.getMessage()); + } + } + + @Override + public String getCommandName() { + return s_name; + } + +} diff --git a/plugins/network-elements/nicira-nvp/src/com/cloud/api/response/NiciraNvpDeviceResponse.java b/plugins/network-elements/nicira-nvp/src/com/cloud/api/response/NiciraNvpDeviceResponse.java new file mode 100644 index 00000000000..e134bed1c9d --- /dev/null +++ b/plugins/network-elements/nicira-nvp/src/com/cloud/api/response/NiciraNvpDeviceResponse.java @@ -0,0 +1,37 @@ +package com.cloud.api.response; + +import com.cloud.api.ApiConstants; +import com.cloud.serializer.Param; +import com.cloud.utils.IdentityProxy; +import com.google.gson.annotations.SerializedName; + +public class NiciraNvpDeviceResponse extends BaseResponse { + @SerializedName(ApiConstants.NICIRA_NVP_DEVICE_ID) @Param(description="device id of the Nicire Nvp") + private IdentityProxy id = new IdentityProxy("external_nicira_nvp_devices"); + + @SerializedName(ApiConstants.PHYSICAL_NETWORK_ID) @Param(description="the physical network to which this Nirica Nvp belongs to") + private IdentityProxy physicalNetworkId = new IdentityProxy("physical_network"); + + @SerializedName(ApiConstants.PROVIDER) @Param(description="name of the provider") + private String providerName; + + @SerializedName(ApiConstants.NICIRA_NVP_DEVICE_NAME) @Param(description="device name") + private String deviceName; + + public void setId(long nvpDeviceId) { + this.id.setValue(nvpDeviceId); + } + + public void setPhysicalNetworkId(long physicalNetworkId) { + this.physicalNetworkId.setValue(physicalNetworkId); + } + + public void setProviderName(String providerName) { + this.providerName = providerName; + } + + public void setDeviceName(String deviceName) { + this.deviceName = deviceName; + } + +} diff --git a/plugins/network-elements/nicira-nvp/src/com/cloud/network/NiciraNvpDeviceVO.java b/plugins/network-elements/nicira-nvp/src/com/cloud/network/NiciraNvpDeviceVO.java new file mode 100644 index 00000000000..550479bd3fe --- /dev/null +++ b/plugins/network-elements/nicira-nvp/src/com/cloud/network/NiciraNvpDeviceVO.java @@ -0,0 +1,79 @@ +package com.cloud.network; + +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; + +@Entity +@Table(name="external_nicira_nvp_devices") +public class NiciraNvpDeviceVO { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + @Column(name="id") + private long id; + + @Column(name="uuid") + private String uuid; + + @Column(name="host_id") + private long hostId; + + @Column(name="physical_network_id") + private long physicalNetworkId; + + @Column(name="provider_name") + private String providerName; + + @Column(name="device_name") + private String deviceName; + + + public NiciraNvpDeviceVO() { + this.uuid = UUID.randomUUID().toString(); + } + + public NiciraNvpDeviceVO(long hostId, long physicalNetworkId, + String providerName, String deviceName) { + super(); + this.hostId = hostId; + this.physicalNetworkId = physicalNetworkId; + this.providerName = providerName; + this.deviceName = deviceName; + this.uuid = UUID.randomUUID().toString(); + } + + public long getId() { + return id; + } + + public String getUuid() { + return uuid; + } + + public void setUuid(String uuid) { + this.uuid = uuid; + } + + public long getPhysicalNetworkId() { + return physicalNetworkId; + } + + public long getHostId() { + return hostId; + } + + public String getProviderName() { + return providerName; + } + + public String getDeviceName() { + return deviceName; + } + +} diff --git a/plugins/network-elements/nicira-nvp/src/com/cloud/network/NiciraNvpNicMappingVO.java b/plugins/network-elements/nicira-nvp/src/com/cloud/network/NiciraNvpNicMappingVO.java new file mode 100644 index 00000000000..2b5f8bad451 --- /dev/null +++ b/plugins/network-elements/nicira-nvp/src/com/cloud/network/NiciraNvpNicMappingVO.java @@ -0,0 +1,65 @@ +package com.cloud.network; + +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.GenerationType; +import javax.persistence.Id; +import javax.persistence.Table; + +@Entity +@Table(name="nicira_nvp_nic_map") +public class NiciraNvpNicMappingVO { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + @Column(name="id") + private long id; + + @Column(name="logicalswitch") + private String logicalSwitchUuid; + + @Column(name="logicalswitchport") + private String logicalSwitchPortUuid; + + @Column(name="nic") + private String nicUuid; + + public NiciraNvpNicMappingVO () { + } + + public NiciraNvpNicMappingVO (String logicalSwitchUuid, String logicalSwitchPortUuid, String nicUuid) { + this.logicalSwitchUuid = logicalSwitchUuid; + this.logicalSwitchPortUuid = logicalSwitchPortUuid; + this.nicUuid = nicUuid; + } + + public String getLogicalSwitchUuid() { + return logicalSwitchUuid; + } + + public void setLogicalSwitchUuid(String logicalSwitchUuid) { + this.logicalSwitchUuid = logicalSwitchUuid; + } + + public String getLogicalSwitchPortUuid() { + return logicalSwitchPortUuid; + } + + public void setLogicalSwitchPortUuid(String logicalSwitchPortUuid) { + this.logicalSwitchPortUuid = logicalSwitchPortUuid; + } + + public String getNicUuid() { + return nicUuid; + } + + public void setNicUuid(String nicUuid) { + this.nicUuid = nicUuid; + } + + public long getId() { + return id; + } + +} diff --git a/plugins/network-elements/nicira-nvp/src/com/cloud/network/dao/NiciraNvpDao.java b/plugins/network-elements/nicira-nvp/src/com/cloud/network/dao/NiciraNvpDao.java new file mode 100644 index 00000000000..fddb75ecc50 --- /dev/null +++ b/plugins/network-elements/nicira-nvp/src/com/cloud/network/dao/NiciraNvpDao.java @@ -0,0 +1,16 @@ +package com.cloud.network.dao; + +import java.util.List; + +import com.cloud.network.NiciraNvpDeviceVO; +import com.cloud.utils.db.GenericDao; + +public interface NiciraNvpDao extends GenericDao{ + /** + * list all the nicira nvp devices added in to this physical network + * @param physicalNetworkId physical Network Id + * @return list of NiciraNvpDeviceVO for this physical network. + */ + List listByPhysicalNetwork(long physicalNetworkId); + +} diff --git a/plugins/network-elements/nicira-nvp/src/com/cloud/network/dao/NiciraNvpDaoImpl.java b/plugins/network-elements/nicira-nvp/src/com/cloud/network/dao/NiciraNvpDaoImpl.java new file mode 100644 index 00000000000..916d1ffa1d1 --- /dev/null +++ b/plugins/network-elements/nicira-nvp/src/com/cloud/network/dao/NiciraNvpDaoImpl.java @@ -0,0 +1,32 @@ +package com.cloud.network.dao; + +import java.util.List; + +import javax.ejb.Local; + +import com.cloud.network.NiciraNvpDeviceVO; +import com.cloud.utils.db.GenericDaoBase; +import com.cloud.utils.db.SearchBuilder; +import com.cloud.utils.db.SearchCriteria; +import com.cloud.utils.db.SearchCriteria.Op; + +@Local(value=NiciraNvpDao.class) +public class NiciraNvpDaoImpl extends GenericDaoBase + implements NiciraNvpDao { + + protected final SearchBuilder physicalNetworkIdSearch; + + public NiciraNvpDaoImpl() { + physicalNetworkIdSearch = createSearchBuilder(); + physicalNetworkIdSearch.and("physicalNetworkId", physicalNetworkIdSearch.entity().getPhysicalNetworkId(), Op.EQ); + physicalNetworkIdSearch.done(); + } + + @Override + public List listByPhysicalNetwork(long physicalNetworkId) { + SearchCriteria sc = physicalNetworkIdSearch.create(); + sc.setParameters("physicalNetworkId", physicalNetworkId); + return search(sc, null); + } + +} diff --git a/plugins/network-elements/nicira-nvp/src/com/cloud/network/dao/NiciraNvpNicMappingDao.java b/plugins/network-elements/nicira-nvp/src/com/cloud/network/dao/NiciraNvpNicMappingDao.java new file mode 100644 index 00000000000..a51f5214f68 --- /dev/null +++ b/plugins/network-elements/nicira-nvp/src/com/cloud/network/dao/NiciraNvpNicMappingDao.java @@ -0,0 +1,13 @@ +package com.cloud.network.dao; + +import com.cloud.network.NiciraNvpNicMappingVO; +import com.cloud.utils.db.GenericDao; + +public interface NiciraNvpNicMappingDao extends GenericDao { + + /** find the mapping for a nic + * @param nicUuid the Uuid of a nic attached to a logical switch port + * @return NiciraNvpNicMapping for this nic uuid or null if it does not exist + */ + public NiciraNvpNicMappingVO findByNicUuid(String nicUuid); +} diff --git a/plugins/network-elements/nicira-nvp/src/com/cloud/network/dao/NiciraNvpNicMappingDaoImpl.java b/plugins/network-elements/nicira-nvp/src/com/cloud/network/dao/NiciraNvpNicMappingDaoImpl.java new file mode 100644 index 00000000000..b3223d3df1e --- /dev/null +++ b/plugins/network-elements/nicira-nvp/src/com/cloud/network/dao/NiciraNvpNicMappingDaoImpl.java @@ -0,0 +1,30 @@ +package com.cloud.network.dao; + +import javax.ejb.Local; + +import com.cloud.network.NiciraNvpNicMappingVO; +import com.cloud.utils.db.GenericDaoBase; +import com.cloud.utils.db.SearchBuilder; +import com.cloud.utils.db.SearchCriteria; +import com.cloud.utils.db.SearchCriteria.Op; + +@Local(value=NiciraNvpNicMappingDao.class) +public class NiciraNvpNicMappingDaoImpl extends + GenericDaoBase implements NiciraNvpNicMappingDao { + + protected final SearchBuilder nicSearch; + + public NiciraNvpNicMappingDaoImpl() { + nicSearch = createSearchBuilder(); + nicSearch.and("nicUuid", nicSearch.entity().getNicUuid(), Op.EQ); + nicSearch.done(); + } + + @Override + public NiciraNvpNicMappingVO findByNicUuid(String nicUuid) { + SearchCriteria sc = nicSearch.create(); + sc.setParameters("nicUuid", nicUuid); + return findOneBy(sc); + } + +} diff --git a/plugins/network-elements/nicira-nvp/src/com/cloud/network/element/NiciraNvpElement.java b/plugins/network-elements/nicira-nvp/src/com/cloud/network/element/NiciraNvpElement.java new file mode 100644 index 00000000000..ba4b9614520 --- /dev/null +++ b/plugins/network-elements/nicira-nvp/src/com/cloud/network/element/NiciraNvpElement.java @@ -0,0 +1,502 @@ +/** Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package com.cloud.network.element; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.UUID; + +import javax.ejb.Local; +import javax.naming.ConfigurationException; + +import org.apache.log4j.Logger; + +import com.cloud.agent.AgentManager; +import com.cloud.agent.api.CreateLogicalSwitchPortAnswer; +import com.cloud.agent.api.CreateLogicalSwitchPortCommand; +import com.cloud.agent.api.DeleteLogicalSwitchPortAnswer; +import com.cloud.agent.api.DeleteLogicalSwitchPortCommand; +import com.cloud.agent.api.StartupCommand; +import com.cloud.agent.api.StartupNiciraNvpCommand; +import com.cloud.api.commands.AddNiciraNvpDeviceCmd; +import com.cloud.api.commands.DeleteNiciraNvpDeviceCmd; +import com.cloud.api.commands.ListNiciraNvpDeviceNetworksCmd; +import com.cloud.api.commands.ListNiciraNvpDevicesCmd; +import com.cloud.api.response.NiciraNvpDeviceResponse; +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.DetailVO; +import com.cloud.host.Host; +import com.cloud.host.HostVO; +import com.cloud.host.dao.HostDao; +import com.cloud.host.dao.HostDetailsDao; +import com.cloud.network.Network; +import com.cloud.network.ExternalNetworkDeviceManager.NetworkDevice; +import com.cloud.network.Network.Capability; +import com.cloud.network.Network.Provider; +import com.cloud.network.Network.Service; +import com.cloud.network.NetworkVO; +import com.cloud.network.Networks; +import com.cloud.network.Networks.BroadcastDomainType; +import com.cloud.network.NiciraNvpDeviceVO; +import com.cloud.network.NiciraNvpNicMappingVO; +import com.cloud.network.PhysicalNetworkServiceProvider; +import com.cloud.network.PhysicalNetworkVO; +import com.cloud.network.dao.NetworkDao; +import com.cloud.network.dao.NiciraNvpDao; +import com.cloud.network.dao.NiciraNvpNicMappingDao; +import com.cloud.network.dao.PhysicalNetworkDao; +import com.cloud.network.dao.PhysicalNetworkServiceProviderDao; +import com.cloud.network.dao.PhysicalNetworkServiceProviderVO; +import com.cloud.network.guru.NiciraNvpGuestNetworkGuru; +import com.cloud.network.resource.NiciraNvpResource; +import com.cloud.offering.NetworkOffering; +import com.cloud.resource.ResourceManager; +import com.cloud.resource.ResourceState; +import com.cloud.resource.ResourceStateAdapter; +import com.cloud.resource.ServerResource; +import com.cloud.resource.UnableDeleteHostException; +import com.cloud.utils.component.AdapterBase; +import com.cloud.utils.component.Inject; +import com.cloud.utils.db.DB; +import com.cloud.utils.db.Transaction; +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.VirtualMachine; +import com.cloud.vm.VirtualMachineProfile; +import com.cloud.vm.dao.NicDao; + +@Local(value = NetworkElement.class) +public class NiciraNvpElement extends AdapterBase implements NetworkElement, NiciraNvpElementService, ResourceStateAdapter { + private static final Logger s_logger = Logger.getLogger(NiciraNvpElement.class); + + private static final Map> capabilities = setCapabilities(); + + + @Inject + NicDao _nicDao; + @Inject + ResourceManager _resourceMgr; + @Inject + PhysicalNetworkDao _physicalNetworkDao; + @Inject + PhysicalNetworkServiceProviderDao _physicalNetworkServiceProviderDao; + @Inject + NiciraNvpDao _niciraNvpDao; + @Inject + HostDetailsDao _hostDetailsDao; + @Inject + HostDao _hostDao; + @Inject + AgentManager _agentMgr; + @Inject + NiciraNvpNicMappingDao _niciraNvpNicMappingDao; + @Inject + NetworkDao _networkDao; + + @Override + public Map> getCapabilities() { + return capabilities; + } + + @Override + public Provider getProvider() { + return Provider.NiciraNvp; + } + + private boolean canHandle(Network network) { + if (network.getBroadcastDomainType() != BroadcastDomainType.Lswitch) { + return false; + } + + return true; + } + + @Override + public boolean configure(String name, Map params) + throws ConfigurationException { + super.configure(name, params); + _resourceMgr.registerResourceStateAdapter(this.getClass().getSimpleName(), this); + return true; + } + + @Override + public boolean implement(Network network, NetworkOffering offering, + DeployDestination dest, ReservationContext context) + throws ConcurrentOperationException, ResourceUnavailableException, + InsufficientCapacityException { + + if (!canHandle(network)) { + return false; + } + + return true; + } + + @Override + public boolean prepare(Network network, NicProfile nic, + VirtualMachineProfile vm, + DeployDestination dest, ReservationContext context) + throws ConcurrentOperationException, ResourceUnavailableException, + InsufficientCapacityException { + + if (!canHandle(network)) { + return false; + } + + if (network.getBroadcastUri() == null) { + s_logger.error("Nic has no broadcast Uri with the LSwitch Uuid"); + return false; + } + + NicVO nicVO = _nicDao.findById(nic.getId()); + + List devices = _niciraNvpDao.listByPhysicalNetwork(network.getPhysicalNetworkId()); + if (devices.isEmpty()) { + s_logger.error("No NiciraNvp Controller on physical network " + network.getPhysicalNetworkId()); + return false; + } + NiciraNvpDeviceVO niciraNvpDevice = devices.get(0); + HostVO niciraNvpHost = _hostDao.findById(niciraNvpDevice.getHostId()); + + CreateLogicalSwitchPortCommand cmd = new CreateLogicalSwitchPortCommand(network.getBroadcastUri().getSchemeSpecificPart(), nicVO.getUuid(), + context.getDomain().getName() + "-" + context.getAccount().getAccountName(), nic.getName()); + CreateLogicalSwitchPortAnswer answer = (CreateLogicalSwitchPortAnswer) _agentMgr.easySend(niciraNvpHost.getId(), cmd); + + if (answer == null || !answer.getResult()) { + s_logger.error ("CreateLogicalSwitchPortCommand failed"); + return false; + } + + NiciraNvpNicMappingVO nicMap = new NiciraNvpNicMappingVO(network.getBroadcastUri().getSchemeSpecificPart(), answer.getLogicalSwitchPortUuid(), nicVO.getUuid()); + _niciraNvpNicMappingDao.persist(nicMap); + + return true; + } + + @Override + public boolean release(Network network, NicProfile nic, + VirtualMachineProfile vm, + ReservationContext context) throws ConcurrentOperationException, + ResourceUnavailableException { + + if (!canHandle(network)) { + return false; + } + + if (network.getBroadcastUri() == null) { + s_logger.error("Nic has no broadcast Uri with the LSwitch Uuid"); + return false; + } + + NicVO nicVO = _nicDao.findById(nic.getId()); + + List devices = _niciraNvpDao.listByPhysicalNetwork(network.getPhysicalNetworkId()); + if (devices.isEmpty()) { + s_logger.error("No NiciraNvp Controller on physical network " + network.getPhysicalNetworkId()); + return false; + } + NiciraNvpDeviceVO niciraNvpDevice = devices.get(0); + HostVO niciraNvpHost = _hostDao.findById(niciraNvpDevice.getHostId()); + + NiciraNvpNicMappingVO nicMap = _niciraNvpNicMappingDao.findByNicUuid(nicVO.getUuid()); + if (nicMap == null) { + s_logger.error("No mapping for nic " + nic.getName()); + return false; + } + + DeleteLogicalSwitchPortCommand cmd = new DeleteLogicalSwitchPortCommand(nicMap.getLogicalSwitchUuid(), nicMap.getLogicalSwitchPortUuid()); + DeleteLogicalSwitchPortAnswer answer = (DeleteLogicalSwitchPortAnswer) _agentMgr.easySend(niciraNvpHost.getId(), cmd); + + if (answer == null || !answer.getResult()) { + s_logger.error ("DeleteLogicalSwitchPortCommand failed"); + return false; + } + + _niciraNvpNicMappingDao.remove(nicMap.getId()); + + return true; + } + + @Override + public boolean shutdown(Network network, ReservationContext context, + boolean cleanup) throws ConcurrentOperationException, + ResourceUnavailableException { + if (!canHandle(network)) { + return false; + } + + return true; + } + + @Override + public boolean destroy(Network network) + throws ConcurrentOperationException, ResourceUnavailableException { + if (!canHandle(network)) { + return false; + } + + return true; + } + + @Override + public boolean isReady(PhysicalNetworkServiceProvider provider) { + return true; + } + + @Override + public boolean shutdownProviderInstances( + PhysicalNetworkServiceProvider provider, ReservationContext context) + throws ConcurrentOperationException, ResourceUnavailableException { + // Nothing to do here. + return true; + } + + @Override + public boolean canEnableIndividualServices() { + return false; + } + + @Override + public boolean verifyServicesCombination(List services) { + return true; + } + + private static Map> setCapabilities() { + Map> capabilities = new HashMap>(); + + capabilities.put(Service.Connectivity, null); + return capabilities; + } + + @Override + public String getPropertiesFile() { + return "nicira-nvp_commands.properties"; + } + + @Override + @DB + public NiciraNvpDeviceVO addNiciraNvpDevice(AddNiciraNvpDeviceCmd cmd) { + ServerResource resource = new NiciraNvpResource(); + String deviceName = Network.Provider.NiciraNvp.getName(); + NetworkDevice networkDevice = NetworkDevice.getNetworkDevice(deviceName); + Long physicalNetworkId = cmd.getPhysicalNetworkId(); + NiciraNvpDeviceVO niciraNvpDevice = null; + + PhysicalNetworkVO physicalNetwork = _physicalNetworkDao.findById(physicalNetworkId); + if (physicalNetwork == null) { + throw new InvalidParameterValueException("Could not find phyical network with ID: " + physicalNetworkId); + } + long zoneId = physicalNetwork.getDataCenterId(); + + PhysicalNetworkServiceProviderVO ntwkSvcProvider = _physicalNetworkServiceProviderDao.findByServiceProvider(physicalNetwork.getId(), networkDevice.getNetworkServiceProvder()); + if (ntwkSvcProvider == null) { + throw new CloudRuntimeException("Network Service Provider: " + networkDevice.getNetworkServiceProvder() + + " is not enabled in the physical network: " + physicalNetworkId + "to add this device"); + } else if (ntwkSvcProvider.getState() == PhysicalNetworkServiceProvider.State.Shutdown) { + throw new CloudRuntimeException("Network Service Provider: " + ntwkSvcProvider.getProviderName() + + " is in shutdown state in the physical network: " + physicalNetworkId + "to add this device"); + } + + if (_niciraNvpDao.listByPhysicalNetwork(physicalNetworkId).size() != 0) { + throw new CloudRuntimeException("A NiciraNvp device is already configured on this physical network"); + } + + Map params = new HashMap(); + params.put("guid", UUID.randomUUID().toString()); + params.put("zoneId", String.valueOf(physicalNetwork.getDataCenterId())); + params.put("physicalNetworkId", String.valueOf(physicalNetwork.getId())); + params.put("name", "Nicira Controller - " + cmd.getHost()); + params.put("ip", cmd.getHost()); + params.put("adminuser", cmd.getUsername()); + params.put("adminpass", cmd.getPassword()); + params.put("transportzoneuuid", cmd.getTransportzoneUuid()); + params.put("transportzoneisotype", physicalNetwork.getIsolationMethods().get(0).toLowerCase()); // FIXME What to do with multiple isolation types + + Map hostdetails = new HashMap(); + hostdetails.putAll(params); + + + Transaction txn = Transaction.currentTxn(); + try { + resource.configure(cmd.getHost(), hostdetails); + + Host host = _resourceMgr.addHost(zoneId, resource, Host.Type.L2Networking, params); + if (host != null) { + txn.start(); + + niciraNvpDevice = new NiciraNvpDeviceVO(host.getId(), physicalNetworkId, ntwkSvcProvider.getProviderName(), deviceName); + _niciraNvpDao.persist(niciraNvpDevice); + + DetailVO detail = new DetailVO(host.getId(), "niciranvpdeviceid", String.valueOf(niciraNvpDevice.getId())); + _hostDetailsDao.persist(detail); + + txn.commit(); + return niciraNvpDevice; + } else { + throw new CloudRuntimeException("Failed to add Nicira Nvp Device due to internal error."); + } + } catch (ConfigurationException e) { + txn.rollback(); + throw new CloudRuntimeException(e.getMessage()); + } + } + + @Override + public NiciraNvpDeviceResponse createNiciraNvpDeviceResponse( + NiciraNvpDeviceVO niciraNvpDeviceVO) { + NiciraNvpDeviceResponse response = new NiciraNvpDeviceResponse(); + response.setDeviceName(niciraNvpDeviceVO.getDeviceName()); + response.setPhysicalNetworkId(niciraNvpDeviceVO.getPhysicalNetworkId()); + response.setId(niciraNvpDeviceVO.getId()); + response.setProviderName(niciraNvpDeviceVO.getProviderName()); + return response; + } + + @Override + public boolean deleteNiciraNvpDevice(DeleteNiciraNvpDeviceCmd cmd) { + Long niciraDeviceId = cmd.getNiciraNvpDeviceId(); + NiciraNvpDeviceVO niciraNvpDevice = _niciraNvpDao.findById(niciraDeviceId); + if (niciraNvpDevice == null) { + throw new InvalidParameterValueException("Could not find a nicira device with id " + niciraDeviceId); + } + + // Find the physical network we work for + Long physicalNetworkId = niciraNvpDevice.getPhysicalNetworkId(); + PhysicalNetworkVO physicalNetwork = _physicalNetworkDao.findById(physicalNetworkId); + if (physicalNetwork != null) { + // Lets see if there are networks that use us + // Find the nicira networks on this physical network + List networkList = _networkDao.listByPhysicalNetwork(physicalNetworkId); + + // Networks with broadcast type lswitch are ours + for (NetworkVO network : networkList) { + if (network.getBroadcastDomainType() == Networks.BroadcastDomainType.Lswitch) { + if ((network.getState() != Network.State.Shutdown) && (network.getState() != Network.State.Destroy)) { + throw new CloudRuntimeException("This Nicira Nvp device can not be deleted as there are one or more logical networks provisioned by cloudstack."); + } + } + } + } + + HostVO niciraHost = _hostDao.findById(niciraNvpDevice.getHostId()); + Long hostId = niciraHost.getId(); + + niciraHost.setResourceState(ResourceState.Maintenance); + _hostDao.update(hostId, niciraHost); + _resourceMgr.deleteHost(hostId, false, false); + + _niciraNvpDao.remove(niciraDeviceId); + + return true; + } + + @Override + public List listNiciraNvpDevices(ListNiciraNvpDevicesCmd cmd) { + Long physicalNetworkId = cmd.getPhysicalNetworkId(); + Long niciraNvpDeviceId = cmd.getNiciraNvpDeviceId(); + List responseList = new ArrayList(); + + if (physicalNetworkId == null && niciraNvpDeviceId == null) { + throw new InvalidParameterValueException("Either physical network Id or nicira device Id must be specified"); + } + + if (niciraNvpDeviceId != null) { + NiciraNvpDeviceVO niciraNvpDevice = _niciraNvpDao.findById(niciraNvpDeviceId); + if (niciraNvpDevice == null) { + throw new InvalidParameterValueException("Could not find Nicira Nvp device with id: " + niciraNvpDevice); + } + responseList.add(niciraNvpDevice); + } + else { + PhysicalNetworkVO physicalNetwork = _physicalNetworkDao.findById(physicalNetworkId); + if (physicalNetwork == null) { + throw new InvalidParameterValueException("Could not find a physical network with id: " + physicalNetworkId); + } + responseList = _niciraNvpDao.listByPhysicalNetwork(physicalNetworkId); + } + + return responseList; + } + + @Override + public List listNiciraNvpDeviceNetworks(ListNiciraNvpDeviceNetworksCmd cmd) { + Long niciraDeviceId = cmd.getNiciraNvpDeviceId(); + NiciraNvpDeviceVO niciraNvpDevice = _niciraNvpDao.findById(niciraDeviceId); + if (niciraNvpDevice == null) { + throw new InvalidParameterValueException("Could not find a nicira device with id " + niciraDeviceId); + } + + // Find the physical network we work for + Long physicalNetworkId = niciraNvpDevice.getPhysicalNetworkId(); + PhysicalNetworkVO physicalNetwork = _physicalNetworkDao.findById(physicalNetworkId); + if (physicalNetwork == null) { + // No such physical network, so no provisioned networks + return Collections.emptyList(); + } + + // Find the nicira networks on this physical network + List networkList = _networkDao.listByPhysicalNetwork(physicalNetworkId); + + // Networks with broadcast type lswitch are ours + List responseList = new ArrayList(); + for (NetworkVO network : networkList) { + if (network.getBroadcastDomainType() == Networks.BroadcastDomainType.Lswitch) { + responseList.add(network); + } + } + + return responseList; + } + + @Override + public HostVO createHostVOForConnectedAgent(HostVO host, + StartupCommand[] cmd) { + // TODO Auto-generated method stub + return null; + } + + @Override + public HostVO createHostVOForDirectConnectAgent(HostVO host, + StartupCommand[] startup, ServerResource resource, + Map details, List hostTags) { + if (!(startup[0] instanceof StartupNiciraNvpCommand)) { + return null; + } + host.setType(Host.Type.L2Networking); + return host; + } + + @Override + public DeleteHostAnswer deleteHost(HostVO host, boolean isForced, + boolean isForceDeleteStorage) throws UnableDeleteHostException { + if (!(host.getType() == Host.Type.L2Networking)) { + return null; + } + return new DeleteHostAnswer(true); + } + +} diff --git a/plugins/network-elements/nicira-nvp/src/com/cloud/network/element/NiciraNvpElementService.java b/plugins/network-elements/nicira-nvp/src/com/cloud/network/element/NiciraNvpElementService.java new file mode 100644 index 00000000000..0f503e7e8f9 --- /dev/null +++ b/plugins/network-elements/nicira-nvp/src/com/cloud/network/element/NiciraNvpElementService.java @@ -0,0 +1,28 @@ +package com.cloud.network.element; + +import java.util.List; + +import com.cloud.api.commands.AddNiciraNvpDeviceCmd; +import com.cloud.api.commands.DeleteNiciraNvpDeviceCmd; +import com.cloud.api.commands.ListNiciraNvpDeviceNetworksCmd; +import com.cloud.api.commands.ListNiciraNvpDevicesCmd; +import com.cloud.api.response.NiciraNvpDeviceResponse; +import com.cloud.network.Network; +import com.cloud.network.NiciraNvpDeviceVO; +import com.cloud.utils.component.PluggableService; + +public interface NiciraNvpElementService extends PluggableService { + + public NiciraNvpDeviceVO addNiciraNvpDevice(AddNiciraNvpDeviceCmd cmd); + + public NiciraNvpDeviceResponse createNiciraNvpDeviceResponse( + NiciraNvpDeviceVO niciraDeviceVO); + + boolean deleteNiciraNvpDevice(DeleteNiciraNvpDeviceCmd cmd); + + List listNiciraNvpDeviceNetworks( + ListNiciraNvpDeviceNetworksCmd cmd); + + List listNiciraNvpDevices(ListNiciraNvpDevicesCmd cmd); + +} diff --git a/plugins/network-elements/nicira-nvp/src/com/cloud/network/guru/NiciraNvpGuestNetworkGuru.java b/plugins/network-elements/nicira-nvp/src/com/cloud/network/guru/NiciraNvpGuestNetworkGuru.java new file mode 100644 index 00000000000..3bac88b6b97 --- /dev/null +++ b/plugins/network-elements/nicira-nvp/src/com/cloud/network/guru/NiciraNvpGuestNetworkGuru.java @@ -0,0 +1,257 @@ +/** Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package com.cloud.network.guru; + +import java.net.URI; +import java.net.URISyntaxException; +import java.util.List; + +import javax.ejb.Local; + +import org.apache.log4j.Logger; + +import com.cloud.agent.AgentManager; +import com.cloud.agent.api.CreateLogicalSwitchAnswer; +import com.cloud.agent.api.CreateLogicalSwitchCommand; +import com.cloud.agent.api.DeleteLogicalSwitchAnswer; +import com.cloud.agent.api.DeleteLogicalSwitchCommand; +import com.cloud.dc.DataCenter.NetworkType; +import com.cloud.dc.dao.DataCenterDao; +import com.cloud.deploy.DeployDestination; +import com.cloud.deploy.DeploymentPlan; +import com.cloud.exception.InsufficientAddressCapacityException; +import com.cloud.exception.InsufficientVirtualNetworkCapcityException; +import com.cloud.host.HostVO; +import com.cloud.host.dao.HostDao; +import com.cloud.host.dao.HostDetailsDao; +import com.cloud.network.Network; +import com.cloud.network.NetworkManager; +import com.cloud.network.NetworkProfile; +import com.cloud.network.NetworkVO; +import com.cloud.network.Network.GuestType; +import com.cloud.network.Network.State; +import com.cloud.network.Networks.BroadcastDomainType; +import com.cloud.network.NiciraNvpDeviceVO; +import com.cloud.network.PhysicalNetwork; +import com.cloud.network.PhysicalNetwork.IsolationMethod; +import com.cloud.network.PhysicalNetworkVO; +import com.cloud.network.dao.NetworkDao; +import com.cloud.network.dao.NiciraNvpDao; +import com.cloud.network.dao.PhysicalNetworkDao; +import com.cloud.offering.NetworkOffering; +import com.cloud.resource.ResourceManager; +import com.cloud.user.Account; +import com.cloud.user.dao.AccountDao; +import com.cloud.utils.component.Inject; +import com.cloud.vm.NicProfile; +import com.cloud.vm.ReservationContext; +import com.cloud.vm.VirtualMachine; +import com.cloud.vm.VirtualMachineProfile; + +@Local(value=NetworkGuru.class) +public class NiciraNvpGuestNetworkGuru extends GuestNetworkGuru { + private static final Logger s_logger = Logger.getLogger(NiciraNvpGuestNetworkGuru.class); + + @Inject + NetworkManager _externalNetworkManager; + @Inject + NetworkManager _networkMgr; + @Inject + NetworkDao _networkDao; + @Inject + DataCenterDao _zoneDao; + @Inject + PhysicalNetworkDao _physicalNetworkDao; + @Inject + AccountDao _accountDao; + @Inject + NiciraNvpDao _niciraNvpDao; + @Inject + HostDao _hostDao; + @Inject + ResourceManager _resourceMgr; + @Inject + AgentManager _agentMgr; + @Inject + HostDetailsDao _hostDetailsDao; + + public NiciraNvpGuestNetworkGuru() { + super(); + _isolationMethods = new IsolationMethod[] { IsolationMethod.STT }; + } + + @Override + protected boolean canHandle(NetworkOffering offering, final NetworkType networkType, final PhysicalNetwork physicalNetwork) { + // This guru handles only Guest Isolated network that supports Source nat service + if (networkType == NetworkType.Advanced + && isMyTrafficType(offering.getTrafficType()) + && offering.getGuestType() == Network.GuestType.Isolated + && isMyIsolationMethod(physicalNetwork)) { + return true; + } else { + s_logger.trace("We only take care of Guest networks of type " + GuestType.Isolated + " in zone of type " + NetworkType.Advanced); + return false; + } + } + + @Override + public Network design(NetworkOffering offering, DeploymentPlan plan, + Network userSpecified, Account owner) { + // Check of the isolation type of the related physical network is STT + PhysicalNetworkVO physnet = _physicalNetworkDao.findById(plan.getPhysicalNetworkId()); + if (physnet == null || physnet.getIsolationMethods() == null || !physnet.getIsolationMethods().contains("STT")) { + s_logger.debug("Refusing to design this network, the physical isolation type is not STT"); + return null; + } + + List devices = _niciraNvpDao.listByPhysicalNetwork(physnet.getId()); + if (devices.isEmpty()) { + s_logger.error("No NiciraNvp Controller on physical network " + physnet.getName()); + return null; + } + s_logger.debug("Nicira Nvp " + devices.get(0).getUuid() + " found on physical network " + physnet.getId()); + + s_logger.debug("Physical isolation type is STT, asking GuestNetworkGuru to design this network"); + NetworkVO networkObject = (NetworkVO) super.design(offering, plan, userSpecified, owner); + if (networkObject == null) { + return null; + } + // Override the broadcast domain type + networkObject.setBroadcastDomainType(BroadcastDomainType.Lswitch); + + return networkObject; + } + + @Override + public Network implement(Network network, NetworkOffering offering, + DeployDestination dest, ReservationContext context) + throws InsufficientVirtualNetworkCapcityException { + assert (network.getState() == State.Implementing) : "Why are we implementing " + network; + + long dcId = dest.getDataCenter().getId(); + + //get physical network id + long physicalNetworkId = _networkMgr.findPhysicalNetworkId(dcId, offering.getTags(), offering.getTrafficType()); + + NetworkVO implemented = new NetworkVO(network.getTrafficType(), network.getMode(), network.getBroadcastDomainType(), network.getNetworkOfferingId(), State.Allocated, + network.getDataCenterId(), physicalNetworkId); + + if (network.getGateway() != null) { + implemented.setGateway(network.getGateway()); + } + + if (network.getCidr() != null) { + implemented.setCidr(network.getCidr()); + } + + // Name is either the given name or the uuid + String name = implemented.getName(); + if (name == null || name.isEmpty()) { + name = implemented.getUuid(); + } + if (name.length() > 40 ) { + name = name.substring(0, 39); // max length 40 + } + + List devices = _niciraNvpDao.listByPhysicalNetwork(physicalNetworkId); + if (devices.isEmpty()) { + s_logger.error("No NiciraNvp Controller on physical network " + physicalNetworkId); + return null; + } + NiciraNvpDeviceVO niciraNvpDevice = devices.get(0); + HostVO niciraNvpHost = _hostDao.findById(niciraNvpDevice.getHostId()); + _hostDao.loadDetails(niciraNvpHost); + String transportzoneuuid = niciraNvpHost.getDetail("transportzoneuuid"); + String transportzoneisotype = niciraNvpHost.getDetail("transportzoneisotype"); + + CreateLogicalSwitchCommand cmd = new CreateLogicalSwitchCommand(transportzoneuuid, transportzoneisotype, network.getName(), + context.getDomain().getName() + "-" + context.getAccount().getAccountName()); + CreateLogicalSwitchAnswer answer = (CreateLogicalSwitchAnswer) _agentMgr.easySend(niciraNvpHost.getId(), cmd); + + if (answer == null || !answer.getResult()) { + s_logger.error ("CreateLogicalSwitchCommand failed"); + return null; + } + + try { + implemented.setBroadcastUri(new URI("lswitch", answer.getLogicalSwitchUuid(), null)); + implemented.setBroadcastDomainType(BroadcastDomainType.Lswitch); + s_logger.info("Implemented OK, network linked to = " + implemented.getBroadcastUri().toString()); + } catch (URISyntaxException e) { + s_logger.error("Unable to store logical switch id in broadcast uri, uuid = " + implemented.getUuid(), e); + } + + return implemented; + } + + @Override + public void reserve(NicProfile nic, Network network, + VirtualMachineProfile vm, + DeployDestination dest, ReservationContext context) + throws InsufficientVirtualNetworkCapcityException, + InsufficientAddressCapacityException { + // TODO Auto-generated method stub + super.reserve(nic, network, vm, dest, context); + } + + @Override + public boolean release(NicProfile nic, + VirtualMachineProfile vm, + String reservationId) { + // TODO Auto-generated method stub + return super.release(nic, vm, reservationId); + } + + @Override + public void shutdown(NetworkProfile profile, NetworkOffering offering) { + NetworkVO networkObject = _networkDao.findById(profile.getId()); + if (networkObject.getBroadcastDomainType() != BroadcastDomainType.Lswitch || + networkObject.getBroadcastUri() == null) { + s_logger.warn("BroadcastUri is empty or incorrect for guestnetwork " + networkObject.getDisplayText()); + return; + } + + List devices = _niciraNvpDao.listByPhysicalNetwork(networkObject.getPhysicalNetworkId()); + if (devices.isEmpty()) { + s_logger.error("No NiciraNvp Controller on physical network " + networkObject.getPhysicalNetworkId()); + return; + } + NiciraNvpDeviceVO niciraNvpDevice = devices.get(0); + HostVO niciraNvpHost = _hostDao.findById(niciraNvpDevice.getHostId()); + + DeleteLogicalSwitchCommand cmd = new DeleteLogicalSwitchCommand(networkObject.getBroadcastUri().getSchemeSpecificPart()); + DeleteLogicalSwitchAnswer answer = (DeleteLogicalSwitchAnswer) _agentMgr.easySend(niciraNvpHost.getId(), cmd); + + if (answer == null || !answer.getResult()) { + s_logger.error ("DeleteLogicalSwitchCommand failed"); + } + + super.shutdown(profile, offering); + } + + @Override + public boolean trash(Network network, NetworkOffering offering, + Account owner) { + return super.trash(network, offering, owner); + } + + + + + +} diff --git a/plugins/network-elements/nicira-nvp/src/com/cloud/network/nicira/Attachment.java b/plugins/network-elements/nicira-nvp/src/com/cloud/network/nicira/Attachment.java new file mode 100644 index 00000000000..f70d0a174da --- /dev/null +++ b/plugins/network-elements/nicira-nvp/src/com/cloud/network/nicira/Attachment.java @@ -0,0 +1,22 @@ +/** Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package com.cloud.network.nicira; + +public abstract class Attachment { + +} diff --git a/plugins/network-elements/nicira-nvp/src/com/cloud/network/nicira/LogicalSwitch.java b/plugins/network-elements/nicira-nvp/src/com/cloud/network/nicira/LogicalSwitch.java new file mode 100644 index 00000000000..55024421fbc --- /dev/null +++ b/plugins/network-elements/nicira-nvp/src/com/cloud/network/nicira/LogicalSwitch.java @@ -0,0 +1,99 @@ +/** Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package com.cloud.network.nicira; + +import java.util.List; + +public class LogicalSwitch { + private String display_name; + private boolean port_isolation_enabled; + private List tags; + private List transport_zones; + private String type; + private String uuid; + private String _href; + //private RequestQueryParameters _query; + //private LogicalSwitchRelations _relations; + private String _schema; + + public String getDisplay_name() { + return display_name; + } + + public void setDisplay_name(String display_name) { + this.display_name = display_name; + } + + public boolean isPort_isolation_enabled() { + return port_isolation_enabled; + } + + public void setPort_isolation_enabled(boolean port_isolation_enabled) { + this.port_isolation_enabled = port_isolation_enabled; + } + + public String getType() { + return type; + } + + public void setType(String type) { + this.type = type; + } + + public String getUuid() { + return uuid; + } + + public void setUuid(String uuid) { + this.uuid = uuid; + } + + public String get_href() { + return _href; + } + + public void set_href(String _href) { + this._href = _href; + } + + public String get_schema() { + return _schema; + } + + public void set_schema(String _schema) { + this._schema = _schema; + } + + public List getTags() { + return tags; + } + + public void setTags(List tags) { + this.tags = tags; + } + + public List getTransport_zones() { + return transport_zones; + } + + public void setTransport_zones(List transport_zones) { + this.transport_zones = transport_zones; + } + + +} diff --git a/plugins/network-elements/nicira-nvp/src/com/cloud/network/nicira/LogicalSwitchPort.java b/plugins/network-elements/nicira-nvp/src/com/cloud/network/nicira/LogicalSwitchPort.java new file mode 100644 index 00000000000..e74fda248b7 --- /dev/null +++ b/plugins/network-elements/nicira-nvp/src/com/cloud/network/nicira/LogicalSwitchPort.java @@ -0,0 +1,118 @@ +/** Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package com.cloud.network.nicira; + +import java.util.List; + +public class LogicalSwitchPort { + private String display_name; + private List tags; + private Integer portno; + private boolean admin_status_enabled; + //private List allowed_address_pairs; + private String queue_uuid; + private List security_profiles; + private List mirror_targets; + private String type; + private String uuid; + + public LogicalSwitchPort() { + super(); + } + + public LogicalSwitchPort(String display_name, List tags, + boolean admin_status_enabled) { + super(); + this.display_name = display_name; + this.tags = tags; + this.admin_status_enabled = admin_status_enabled; + } + + public String getDisplay_name() { + return display_name; + } + + public void setDisplay_name(String display_name) { + this.display_name = display_name; + } + + public List getTags() { + return tags; + } + + public void setTags(List tags) { + this.tags = tags; + } + + public Integer getPortno() { + return portno; + } + + public void setPortno(Integer portno) { + this.portno = portno; + } + + public boolean isAdmin_status_enabled() { + return admin_status_enabled; + } + + public void setAdmin_status_enabled(boolean admin_status_enabled) { + this.admin_status_enabled = admin_status_enabled; + } + + public String getQueue_uuid() { + return queue_uuid; + } + + public void setQueue_uuid(String queue_uuid) { + this.queue_uuid = queue_uuid; + } + + public List getSecurity_profiles() { + return security_profiles; + } + + public void setSecurity_profiles(List security_profiles) { + this.security_profiles = security_profiles; + } + + public List getMirror_targets() { + return mirror_targets; + } + + public void setMirror_targets(List mirror_targets) { + this.mirror_targets = mirror_targets; + } + + public String getType() { + return type; + } + + public void setType(String type) { + this.type = type; + } + + public String getUuid() { + return uuid; + } + + public void setUuid(String uuid) { + this.uuid = uuid; + } + +} diff --git a/plugins/network-elements/nicira-nvp/src/com/cloud/network/nicira/NiciraNvpApi.java b/plugins/network-elements/nicira-nvp/src/com/cloud/network/nicira/NiciraNvpApi.java new file mode 100644 index 00000000000..c2cf9c5b362 --- /dev/null +++ b/plugins/network-elements/nicira-nvp/src/com/cloud/network/nicira/NiciraNvpApi.java @@ -0,0 +1,413 @@ +/** Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package com.cloud.network.nicira; + +import java.io.IOException; +import java.io.UnsupportedEncodingException; +import java.lang.reflect.Type; +import java.net.InetAddress; +import java.net.InetSocketAddress; +import java.net.MalformedURLException; +import java.net.Socket; +import java.net.URL; +import java.net.UnknownHostException; +import java.security.KeyManagementException; +import java.security.NoSuchAlgorithmException; +import java.security.cert.X509Certificate; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import javax.net.ssl.SSLContext; +import javax.net.ssl.SSLSocketFactory; +import javax.net.ssl.TrustManager; +import javax.net.ssl.X509TrustManager; + +import org.apache.commons.httpclient.ConnectTimeoutException; +import org.apache.commons.httpclient.HttpClient; +import org.apache.commons.httpclient.HttpException; +import org.apache.commons.httpclient.HttpMethodBase; +import org.apache.commons.httpclient.HttpStatus; +import org.apache.commons.httpclient.NameValuePair; +import org.apache.commons.httpclient.cookie.CookiePolicy; +import org.apache.commons.httpclient.methods.DeleteMethod; +import org.apache.commons.httpclient.methods.GetMethod; +import org.apache.commons.httpclient.methods.PostMethod; +import org.apache.commons.httpclient.methods.PutMethod; +import org.apache.commons.httpclient.methods.StringRequestEntity; +import org.apache.commons.httpclient.params.HttpConnectionParams; +import org.apache.commons.httpclient.protocol.Protocol; +import org.apache.commons.httpclient.protocol.ProtocolSocketFactory; +import org.apache.commons.httpclient.protocol.SecureProtocolSocketFactory; +import org.apache.log4j.Logger; +import com.google.gson.Gson; +import com.google.gson.reflect.TypeToken; + +public class NiciraNvpApi { + private static final Logger s_logger = Logger.getLogger(NiciraNvpApi.class); + + private String _name; + private String _host; + private String _adminuser; + private String _adminpass; + + private HttpClient _client; + + public NiciraNvpApi(String host, String adminuser, String adminpass) throws NiciraNvpApiException { + this._host = host; + this._adminpass = adminpass; + this._adminuser = adminuser; + + if (_host == null || _adminpass == null || _adminuser == null) { + throw new NiciraNvpApiException("host, adminuser and adminpass may not be null"); + } + + _client = new HttpClient( ); + _client.getParams().setCookiePolicy(CookiePolicy.BROWSER_COMPATIBILITY); + + try { + // Cast to ProtocolSocketFactory to avoid the deprecated constructor with the SecureProtocolSocketFactory parameter + Protocol.registerProtocol("https", new Protocol("https", (ProtocolSocketFactory) new TrustingProtocolSocketFactory(), 443)); + } catch (IOException e) { + s_logger.warn("Failed to register the TrustingProtocolSocketFactory, falling back to default SSLSocketFactory", e); + } + + } + + /** + * Logs into the Nicira API. The cookie is stored in the _authcookie variable. + *

+ * The method returns false if the login failed or the connection could not be made. + * + */ + private void login() throws NiciraNvpApiException { + String url; + + try { + url = new URL("https", _host, "/ws.v1/login").toString(); + } catch (MalformedURLException e) { + s_logger.error("Unable to build Nicira API URL", e); + throw new NiciraNvpApiException("Unable to build Nicira API URL", e); + } + + PostMethod pm = new PostMethod(url); + pm.addParameter("username", _adminuser); + pm.addParameter("password", _adminpass); + + try { + _client.executeMethod(pm); + } catch (HttpException e) { + throw new NiciraNvpApiException("Nicira NVP API login failed ", e); + } catch (IOException e) { + throw new NiciraNvpApiException("Nicira NVP API login failed ", e); + } + + if (pm.getStatusCode() != HttpStatus.SC_OK) { + s_logger.error("Nicira NVP API login failed : " + pm.getStatusText()); + throw new NiciraNvpApiException("Nicira NVP API login failed " + pm.getStatusText()); + } + + // Success; the cookie required for login is kept in _client + } + + public LogicalSwitch createLogicalSwitch(LogicalSwitch logicalSwitch) throws NiciraNvpApiException { + String uri = "/ws.v1/lswitch"; + LogicalSwitch createdLogicalSwitch = executeCreateObject(logicalSwitch, new TypeToken(){}.getType(), uri, Collections.emptyMap()); + + return createdLogicalSwitch; + } + + public void deleteLogicalSwitch(String uuid) throws NiciraNvpApiException { + String uri = "/ws.v1/lswitch/" + uuid; + executeDeleteObject(uri); + } + + public LogicalSwitchPort createLogicalSwitchPort(String logicalSwitchUuid, LogicalSwitchPort logicalSwitchPort) throws NiciraNvpApiException { + String uri = "/ws.v1/lswitch/" + logicalSwitchUuid + "/lport"; + LogicalSwitchPort createdLogicalSwitchPort = executeCreateObject(logicalSwitchPort, new TypeToken(){}.getType(), uri, Collections.emptyMap());; + + return createdLogicalSwitchPort; + } + + public void modifyLogicalSwitchPortAttachment(String logicalSwitchUuid, String logicalSwitchPortUuid, Attachment attachment) throws NiciraNvpApiException { + String uri = "/ws.v1/lswitch/" + logicalSwitchUuid + "/lport/" + logicalSwitchPortUuid + "/attachment"; + executeUpdateObject(attachment, uri, Collections.emptyMap()); + } + + public void deleteLogicalSwitchPort(String logicalSwitchUuid, String logicalSwitchPortUuid) throws NiciraNvpApiException { + String uri = "/ws.v1/lswitch/" + logicalSwitchUuid + "/lport/" + logicalSwitchPortUuid; + executeDeleteObject(uri); + } + + public String findLogicalSwitchPortUuidByVifAttachmentUuid(String logicalSwitchUuid, String vifAttachmentUuid) throws NiciraNvpApiException { + String uri = "/ws.v1/lswitch/" + logicalSwitchUuid + "/lport"; + Map params = new HashMap(); + params.put("attachment_vif_uuid", vifAttachmentUuid); + params.put("fields", "uuid"); + + NiciraNvpList lspl = executeRetrieveObject(new TypeToken>(){}.getType(), uri, params); + + if (lspl == null || lspl.getResult_count() != 1) { + throw new NiciraNvpApiException("Unexpected response from API"); + } + + LogicalSwitchPort lsp = lspl.getResults().get(0); + return lsp.getUuid(); + } + + private void executeUpdateObject(T newObject, String uri, Map parameters) throws NiciraNvpApiException { + String url; + try { + url = new URL("https", _host, uri).toString(); + } catch (MalformedURLException e) { + s_logger.error("Unable to build Nicira API URL", e); + throw new NiciraNvpApiException("Connection to NVP Failed"); + } + + Gson gson = new Gson(); + + PutMethod pm = new PutMethod(url); + pm.setRequestHeader("Content-Type", "application/json"); + try { + pm.setRequestEntity(new StringRequestEntity( + gson.toJson(newObject),"application/json", null)); + } catch (UnsupportedEncodingException e) { + throw new NiciraNvpApiException("Failed to encode json request body", e); + } + + executeMethod(pm); + + if (pm.getStatusCode() != HttpStatus.SC_OK) { + String errorMessage = responseToErrorMessage(pm); + s_logger.error("Failed to update object : " + errorMessage); + throw new NiciraNvpApiException("Failed to update object : " + errorMessage); + } + + } + + private T executeCreateObject(T newObject, Type returnObjectType, String uri, Map parameters) throws NiciraNvpApiException { + String url; + try { + url = new URL("https", _host, uri).toString(); + } catch (MalformedURLException e) { + s_logger.error("Unable to build Nicira API URL", e); + throw new NiciraNvpApiException("Unable to build Nicira API URL", e); + } + + Gson gson = new Gson(); + + PostMethod pm = new PostMethod(url); + pm.setRequestHeader("Content-Type", "application/json"); + try { + pm.setRequestEntity(new StringRequestEntity( + gson.toJson(newObject),"application/json", null)); + } catch (UnsupportedEncodingException e) { + throw new NiciraNvpApiException("Failed to encode json request body", e); + } + + executeMethod(pm); + + if (pm.getStatusCode() != HttpStatus.SC_CREATED) { + String errorMessage = responseToErrorMessage(pm); + s_logger.error("Failed to create object : " + errorMessage); + throw new NiciraNvpApiException("Failed to create object : " + errorMessage); + } + + T result; + try { + result = gson.fromJson(pm.getResponseBodyAsString(), TypeToken.get(newObject.getClass()).getType()); + } catch (IOException e) { + throw new NiciraNvpApiException("Failed to decode json response body", e); + } + + return result; + } + + private void executeDeleteObject(String uri) throws NiciraNvpApiException { + String url; + try { + url = new URL("https", _host, uri).toString(); + } catch (MalformedURLException e) { + s_logger.error("Unable to build Nicira API URL", e); + throw new NiciraNvpApiException("Unable to build Nicira API URL", e); + } + + DeleteMethod dm = new DeleteMethod(url); + dm.setRequestHeader("Content-Type", "application/json"); + + executeMethod(dm); + + if (dm.getStatusCode() != HttpStatus.SC_NO_CONTENT) { + String errorMessage = responseToErrorMessage(dm); + s_logger.error("Failed to delete object : " + errorMessage); + throw new NiciraNvpApiException("Failed to delete object : " + errorMessage); + } + } + + private T executeRetrieveObject(Type returnObjectType, String uri, Map parameters) throws NiciraNvpApiException { + String url; + try { + url = new URL("https", _host, uri).toString(); + } catch (MalformedURLException e) { + s_logger.error("Unable to build Nicira API URL", e); + throw new NiciraNvpApiException("Unable to build Nicira API URL", e); + } + + GetMethod gm = new GetMethod(url); + gm.setRequestHeader("Content-Type", "application/json"); + List nameValuePairs = new ArrayList(parameters.size()); + for (Entry e : parameters.entrySet()) { + nameValuePairs.add(new NameValuePair(e.getKey(), e.getValue())); + } + gm.setQueryString(nameValuePairs.toArray(new NameValuePair[0])); + + executeMethod(gm); + + if (gm.getStatusCode() != HttpStatus.SC_OK) { + String errorMessage = responseToErrorMessage(gm); + s_logger.error("Failed to retrieve object : " + errorMessage); + throw new NiciraNvpApiException("Failed to retrieve object : " + errorMessage); + } + + Gson gson = new Gson(); + T returnValue; + try { + returnValue = gson.fromJson(gm.getResponseBodyAsString(), returnObjectType); + } catch (IOException e) { + s_logger.error("IOException while retrieving response body",e); + throw new NiciraNvpApiException(e); + } + + return returnValue; + } + + private void executeMethod(HttpMethodBase method) throws NiciraNvpApiException { + try { + _client.executeMethod(method); + if (method.getStatusCode() == HttpStatus.SC_UNAUTHORIZED) { + // login and try again + login(); + _client.executeMethod(method); + } + } catch (HttpException e) { + s_logger.error("HttpException caught while trying to connect to the Nicira NVP Controller", e); + throw new NiciraNvpApiException("API call to Nicira NVP Controller Failed", e); + } catch (IOException e) { + s_logger.error("IOException caught while trying to connect to the Nicira NVP Controller", e); + throw new NiciraNvpApiException("API call to Nicira NVP Controller Failed", e); + } + } + + private String responseToErrorMessage(HttpMethodBase method) { + assert method.isRequestSent() : "no use getting an error message unless the request is sent"; + + if ("text/html".equals(method.getResponseHeader("Content-Type").getValue())) { + // The error message is the response content + // Safety margin of 1024 characters, anything longer is probably useless + // and will clutter the logs + try { + return method.getResponseBodyAsString(1024); + } catch (IOException e) { + s_logger.debug("Error while loading response body", e); + } + } + + // The default + return method.getStatusText(); + } + + /* The Nicira controller uses a self-signed certificate. The + * TrustingProtocolSocketFactory will accept any provided + * certificate when making an SSL connection to the SDN + * Manager + */ + private class TrustingProtocolSocketFactory implements SecureProtocolSocketFactory { + + private SSLSocketFactory ssf; + + public TrustingProtocolSocketFactory() throws IOException { + // Create a trust manager that does not validate certificate chains + TrustManager[] trustAllCerts = new TrustManager[] { + new X509TrustManager() { + public X509Certificate[] getAcceptedIssuers() { + return null; + } + + public void checkClientTrusted(X509Certificate[] certs, String authType) { + // Trust always + } + + public void checkServerTrusted(X509Certificate[] certs, String authType) { + // Trust always + } + } + }; + + try { + // Install the all-trusting trust manager + SSLContext sc = SSLContext.getInstance("SSL"); + sc.init(null, trustAllCerts, new java.security.SecureRandom()); + ssf = sc.getSocketFactory(); + } catch (KeyManagementException e) { + throw new IOException(e); + } catch (NoSuchAlgorithmException e) { + throw new IOException(e); + } + } + + @Override + public Socket createSocket(String host, int port) throws IOException, + UnknownHostException { + return ssf.createSocket(host, port); + } + + @Override + public Socket createSocket(String address, int port, InetAddress localAddress, + int localPort) throws IOException, UnknownHostException { + return ssf.createSocket(address, port, localAddress, localPort); + } + + @Override + public Socket createSocket(Socket socket, String host, int port, + boolean autoClose) throws IOException, UnknownHostException { + return ssf.createSocket(socket, host, port, autoClose); + } + + @Override + public Socket createSocket(String host, int port, InetAddress localAddress, + int localPort, HttpConnectionParams params) throws IOException, + UnknownHostException, ConnectTimeoutException { + int timeout = params.getConnectionTimeout(); + if (timeout == 0) { + return createSocket(host, port, localAddress, localPort); + } + else { + Socket s = ssf.createSocket(); + s.bind(new InetSocketAddress(localAddress, localPort)); + s.connect(new InetSocketAddress(host, port), timeout); + return s; + } + } + + + } + + +} diff --git a/plugins/network-elements/nicira-nvp/src/com/cloud/network/nicira/NiciraNvpApiException.java b/plugins/network-elements/nicira-nvp/src/com/cloud/network/nicira/NiciraNvpApiException.java new file mode 100644 index 00000000000..2a09cc0b3e1 --- /dev/null +++ b/plugins/network-elements/nicira-nvp/src/com/cloud/network/nicira/NiciraNvpApiException.java @@ -0,0 +1,20 @@ +package com.cloud.network.nicira; + +public class NiciraNvpApiException extends Exception { + + public NiciraNvpApiException() { + } + + public NiciraNvpApiException(String message) { + super(message); + } + + public NiciraNvpApiException(Throwable cause) { + super(cause); + } + + public NiciraNvpApiException(String message, Throwable cause) { + super(message, cause); + } + +} diff --git a/plugins/network-elements/nicira-nvp/src/com/cloud/network/nicira/NiciraNvpList.java b/plugins/network-elements/nicira-nvp/src/com/cloud/network/nicira/NiciraNvpList.java new file mode 100644 index 00000000000..79f582af931 --- /dev/null +++ b/plugins/network-elements/nicira-nvp/src/com/cloud/network/nicira/NiciraNvpList.java @@ -0,0 +1,25 @@ +package com.cloud.network.nicira; + +import java.util.List; + +public class NiciraNvpList { + private List results; + private int result_count; + + public List getResults() { + return results; + } + + public void setResults(List results) { + this.results = results; + } + + public int getResult_count() { + return result_count; + } + + public void setResult_count(int result_count) { + this.result_count = result_count; + } + +} diff --git a/plugins/network-elements/nicira-nvp/src/com/cloud/network/nicira/NiciraNvpTag.java b/plugins/network-elements/nicira-nvp/src/com/cloud/network/nicira/NiciraNvpTag.java new file mode 100644 index 00000000000..de0b40f708d --- /dev/null +++ b/plugins/network-elements/nicira-nvp/src/com/cloud/network/nicira/NiciraNvpTag.java @@ -0,0 +1,47 @@ +/** Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package com.cloud.network.nicira; + +public class NiciraNvpTag { + private String scope; + private String tag; + + public NiciraNvpTag() {} + + public NiciraNvpTag(String scope, String tag) { + this.scope = scope; + this.tag = tag; + } + + public String getScope() { + return scope; + } + + public void setScope(String scope) { + this.scope = scope; + } + + public String getTag() { + return tag; + } + + public void setTag(String tag) { + this.tag = tag; + } + +} diff --git a/plugins/network-elements/nicira-nvp/src/com/cloud/network/nicira/TransportZoneBinding.java b/plugins/network-elements/nicira-nvp/src/com/cloud/network/nicira/TransportZoneBinding.java new file mode 100644 index 00000000000..530352eebcb --- /dev/null +++ b/plugins/network-elements/nicira-nvp/src/com/cloud/network/nicira/TransportZoneBinding.java @@ -0,0 +1,47 @@ +/** Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package com.cloud.network.nicira; + +public class TransportZoneBinding { + private String zone_uuid; + private String transport_type; + + public TransportZoneBinding() {} + + public TransportZoneBinding(String zone_uuid, String transport_type) { + this.zone_uuid = zone_uuid; + this.transport_type = transport_type; + } + + public String getZone_uuid() { + return zone_uuid; + } + + public void setZone_uuid(String zone_uuid) { + this.zone_uuid = zone_uuid; + } + + public String getTransport_type() { + return transport_type; + } + + public void setTransport_type(String transport_type) { + this.transport_type = transport_type; + } + +} diff --git a/plugins/network-elements/nicira-nvp/src/com/cloud/network/nicira/VifAttachment.java b/plugins/network-elements/nicira-nvp/src/com/cloud/network/nicira/VifAttachment.java new file mode 100644 index 00000000000..a5f0de77fb4 --- /dev/null +++ b/plugins/network-elements/nicira-nvp/src/com/cloud/network/nicira/VifAttachment.java @@ -0,0 +1,43 @@ +/** Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package com.cloud.network.nicira; + +public class VifAttachment extends Attachment { + private final String type = "VifAttachment"; + private String vif_uuid; + + public VifAttachment() { + } + + public VifAttachment(String vifUuid) { + this.vif_uuid = vifUuid; + } + + public String getVif_uuid() { + return vif_uuid; + } + + public void setVif_uuid(String vif_uuid) { + this.vif_uuid = vif_uuid; + } + + public String getType() { + return type; + } + +} diff --git a/plugins/network-elements/nicira-nvp/src/com/cloud/network/resource/NiciraNvpResource.java b/plugins/network-elements/nicira-nvp/src/com/cloud/network/resource/NiciraNvpResource.java new file mode 100644 index 00000000000..ae7b37e6edb --- /dev/null +++ b/plugins/network-elements/nicira-nvp/src/com/cloud/network/resource/NiciraNvpResource.java @@ -0,0 +1,240 @@ +package com.cloud.network.resource; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +import javax.naming.ConfigurationException; + +import org.apache.log4j.Logger; + +import com.cloud.agent.IAgentControl; +import com.cloud.agent.api.Answer; +import com.cloud.agent.api.Command; +import com.cloud.agent.api.CreateLogicalSwitchAnswer; +import com.cloud.agent.api.CreateLogicalSwitchCommand; +import com.cloud.agent.api.CreateLogicalSwitchPortAnswer; +import com.cloud.agent.api.CreateLogicalSwitchPortCommand; +import com.cloud.agent.api.DeleteLogicalSwitchAnswer; +import com.cloud.agent.api.DeleteLogicalSwitchCommand; +import com.cloud.agent.api.DeleteLogicalSwitchPortAnswer; +import com.cloud.agent.api.DeleteLogicalSwitchPortCommand; +import com.cloud.agent.api.MaintainAnswer; +import com.cloud.agent.api.MaintainCommand; +import com.cloud.agent.api.PingCommand; +import com.cloud.agent.api.ReadyAnswer; +import com.cloud.agent.api.ReadyCommand; +import com.cloud.agent.api.StartupCommand; +import com.cloud.agent.api.StartupNiciraNvpCommand; +import com.cloud.host.Host; +import com.cloud.host.Host.Type; +import com.cloud.network.nicira.LogicalSwitch; +import com.cloud.network.nicira.LogicalSwitchPort; +import com.cloud.network.nicira.NiciraNvpApi; +import com.cloud.network.nicira.NiciraNvpApiException; +import com.cloud.network.nicira.NiciraNvpTag; +import com.cloud.network.nicira.TransportZoneBinding; +import com.cloud.network.nicira.VifAttachment; +import com.cloud.resource.ServerResource; + +public class NiciraNvpResource implements ServerResource { + private static final Logger s_logger = Logger.getLogger(NiciraNvpResource.class); + + private String _name; + private String _ip; + private String _adminuser; + private String _adminpass; + private String _guid; + private String _zoneId; + + private NiciraNvpApi _niciraNvpApi; + + @Override + public boolean configure(String name, Map params) + throws ConfigurationException { + + _name = (String) params.get("name"); + if (_name == null) { + throw new ConfigurationException("Unable to find name"); + } + + _ip = (String) params.get("ip"); + if (_ip == null) { + throw new ConfigurationException("Unable to find IP"); + } + + _adminuser = (String) params.get("adminuser"); + if (_adminuser == null) { + throw new ConfigurationException("Unable to find admin username"); + } + + _adminpass = (String) params.get("adminpass"); + if (_adminpass == null) { + throw new ConfigurationException("Unable to find admin password"); + } + + _guid = (String)params.get("guid"); + if (_guid == null) { + throw new ConfigurationException("Unable to find the guid"); + } + + _zoneId = (String) params.get("zoneId"); + if (_zoneId == null) { + throw new ConfigurationException("Unable to find zone"); + } + + try { + _niciraNvpApi = new NiciraNvpApi(_ip, _adminuser, _adminpass); + } catch (NiciraNvpApiException e) { + throw new ConfigurationException(e.getMessage()); + } + + return true; + } + + @Override + public boolean start() { + return true; + } + + @Override + public boolean stop() { + return true; + } + + @Override + public String getName() { + return _name; + } + + @Override + public Type getType() { + // Think up a better name for this Type? + return Host.Type.L2Networking; + } + + @Override + public StartupCommand[] initialize() { + StartupNiciraNvpCommand sc = new StartupNiciraNvpCommand(); + sc.setGuid(_guid); + sc.setName(_name); + sc.setDataCenter(_zoneId); + sc.setPod(""); + sc.setPrivateIpAddress(""); + sc.setStorageIpAddress(""); + sc.setVersion(""); + return new StartupCommand[] { sc }; + } + + @Override + public PingCommand getCurrentStatus(long id) { + return new PingCommand(Host.Type.L2Networking, id); + } + + @Override + public Answer executeRequest(Command cmd) { + if (cmd instanceof ReadyCommand) { + return executeRequest((ReadyCommand) cmd); + } + else if (cmd instanceof MaintainCommand) { + return executeRequest((MaintainCommand)cmd); + } + else if (cmd instanceof CreateLogicalSwitchCommand) { + return executeRequest((CreateLogicalSwitchCommand)cmd); + } + else if (cmd instanceof DeleteLogicalSwitchCommand) { + return executeRequest((DeleteLogicalSwitchCommand) cmd); + } + else if (cmd instanceof CreateLogicalSwitchPortCommand) { + return executeRequest((CreateLogicalSwitchPortCommand) cmd); + } + else if (cmd instanceof DeleteLogicalSwitchPortCommand) { + return executeRequest((DeleteLogicalSwitchPortCommand) cmd); + } + s_logger.debug("Received unsupported command " + cmd.toString()); + return Answer.createUnsupportedCommandAnswer(cmd); + } + + @Override + public void disconnected() { + } + + @Override + public IAgentControl getAgentControl() { + return null; + } + + @Override + public void setAgentControl(IAgentControl agentControl) { + } + + private Answer executeRequest(CreateLogicalSwitchCommand cmd) { + LogicalSwitch logicalSwitch = new LogicalSwitch(); + logicalSwitch.setDisplay_name("lswitch-" + cmd.getOwnerName()); + logicalSwitch.setPort_isolation_enabled(false); + + // Set transport binding + List ltzb = new ArrayList(); + ltzb.add(new TransportZoneBinding(cmd.getTransportUuid(), cmd.getTransportType())); + logicalSwitch.setTransport_zones(ltzb); + + // Tags set to scope cs_account and account name + List tags = new ArrayList(); + tags.add(new NiciraNvpTag("cs_account",cmd.getOwnerName())); + logicalSwitch.setTags(tags); + + try { + logicalSwitch = _niciraNvpApi.createLogicalSwitch(logicalSwitch); + return new CreateLogicalSwitchAnswer(cmd, true, "Logicalswitch " + logicalSwitch.getUuid() + " created", logicalSwitch.getUuid()); + } catch (NiciraNvpApiException e) { + return new CreateLogicalSwitchAnswer(cmd, e); + } + + } + + private Answer executeRequest(DeleteLogicalSwitchCommand cmd) { + try { + _niciraNvpApi.deleteLogicalSwitch(cmd.getLogicalSwitchUuid()); + return new DeleteLogicalSwitchAnswer(cmd, true, "Logicalswitch " + cmd.getLogicalSwitchUuid() + " deleted"); + } catch (NiciraNvpApiException e) { + return new DeleteLogicalSwitchAnswer(cmd, e); + } + } + + private Answer executeRequest(CreateLogicalSwitchPortCommand cmd) { + String logicalSwitchUuid = cmd.getLogicalSwitchUuid(); + String attachmentUuid = cmd.getAttachmentUuid(); + + try { + // Tags set to scope cs_account and account name + List tags = new ArrayList(); + tags.add(new NiciraNvpTag("cs_account",cmd.getOwnerName())); + + LogicalSwitchPort logicalSwitchPort = new LogicalSwitchPort(attachmentUuid, tags, true); + LogicalSwitchPort newPort = _niciraNvpApi.createLogicalSwitchPort(logicalSwitchUuid, logicalSwitchPort); + _niciraNvpApi.modifyLogicalSwitchPortAttachment(cmd.getLogicalSwitchUuid(), newPort.getUuid(), new VifAttachment(attachmentUuid)); + return new CreateLogicalSwitchPortAnswer(cmd, true, "Logical switch port " + newPort.getUuid() + " created", newPort.getUuid()); + } catch (NiciraNvpApiException e) { + return new CreateLogicalSwitchPortAnswer(cmd, e); + } + + } + + private Answer executeRequest(DeleteLogicalSwitchPortCommand cmd) { + try { + _niciraNvpApi.deleteLogicalSwitchPort(cmd.getLogicalSwitchUuid(), cmd.getLogicalSwitchPortUuid()); + return new DeleteLogicalSwitchPortAnswer(cmd, true, "Logical switch port " + cmd.getLogicalSwitchPortUuid() + " deleted"); + } catch (NiciraNvpApiException e) { + return new DeleteLogicalSwitchPortAnswer(cmd, e); + } + } + + private Answer executeRequest(ReadyCommand cmd) { + return new ReadyAnswer(cmd); + } + + private Answer executeRequest(MaintainCommand cmd) { + return new MaintainAnswer(cmd); + } + +} 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 d031feeb6eb..7bfa7151fba 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 @@ -12,11 +12,14 @@ // Automatically generated by addcopyright.py at 04/03/2012 package com.cloud.network.guru; +import java.util.List; + import javax.ejb.Local; import org.apache.log4j.Logger; import com.cloud.dc.DataCenter; +import com.cloud.dc.DataCenter.NetworkType; import com.cloud.deploy.DeployDestination; import com.cloud.deploy.DeploymentPlan; import com.cloud.event.EventTypes; @@ -38,7 +41,10 @@ import com.cloud.vm.ReservationContext; import com.cloud.vm.VirtualMachine; import com.cloud.vm.VirtualMachineProfile; import com.cloud.network.Networks.BroadcastDomainType; +import com.cloud.network.Network.GuestType; import com.cloud.network.Network.State; +import com.cloud.network.PhysicalNetwork; +import com.cloud.network.PhysicalNetwork.IsolationMethod; @Local(value=NetworkGuru.class) public class OvsGuestNetworkGuru extends GuestNetworkGuru { @@ -46,6 +52,28 @@ public class OvsGuestNetworkGuru extends GuestNetworkGuru { @Inject NetworkManager _externalNetworkManager; @Inject OvsTunnelManager _ovsTunnelMgr; + + OvsGuestNetworkGuru() { + super(); + _isolationMethods = new IsolationMethod[] { IsolationMethod.GRE, IsolationMethod.L3, IsolationMethod.VLAN }; + } + + protected boolean canHandle(NetworkOffering offering, + final NetworkType networkType, final PhysicalNetwork physicalNetwork) { + // This guru handles only Guest Isolated network that supports Source + // nat service + if (networkType == NetworkType.Advanced + && isMyTrafficType(offering.getTrafficType()) + && offering.getGuestType() == Network.GuestType.Isolated + && isMyIsolationMethod(physicalNetwork)) { + return true; + } else { + s_logger.trace("We only take care of Guest networks of type " + + GuestType.Isolated + " in zone of type " + + NetworkType.Advanced); + return false; + } + } @Override public Network design(NetworkOffering offering, DeploymentPlan plan, Network userSpecified, Account owner) { diff --git a/server/src/com/cloud/host/dao/HostDaoImpl.java b/server/src/com/cloud/host/dao/HostDaoImpl.java index a6d794d4e38..ab1e77eb7f4 100755 --- a/server/src/com/cloud/host/dao/HostDaoImpl.java +++ b/server/src/com/cloud/host/dao/HostDaoImpl.java @@ -354,7 +354,7 @@ public class HostDaoImpl extends GenericDaoBase implements HostDao txn.start(); SearchCriteria sc = UnmanagedApplianceSearch.create(); sc.setParameters("lastPinged", lastPingSecondsAfter); - sc.setParameters("types", Type.ExternalDhcp, Type.ExternalFirewall, Type.ExternalLoadBalancer, Type.PxeServer, Type.TrafficMonitor); + sc.setParameters("types", Type.ExternalDhcp, Type.ExternalFirewall, Type.ExternalLoadBalancer, Type.PxeServer, Type.TrafficMonitor, Type.L2Networking); List hosts = lockRows(sc, null, true); for (HostVO host : hosts) { @@ -493,7 +493,7 @@ public class HostDaoImpl extends GenericDaoBase implements HostDao List result = new ArrayList(); ResultSet rs = null; try { - String sql = "select h.id from host h left join cluster c on h.cluster_id=c.id where h.mgmt_server_id is not null and h.last_ping < ? and h.status in ('Up', 'Updating', 'Disconnected', 'Connecting') and h.type not in ('ExternalFirewall', 'ExternalLoadBalancer', 'TrafficMonitor', 'SecondaryStorage', 'LocalSecondaryStorage') and (h.cluster_id is null or c.managed_state = 'Managed') ;" ; + String sql = "select h.id from host h left join cluster c on h.cluster_id=c.id where h.mgmt_server_id is not null and h.last_ping < ? and h.status in ('Up', 'Updating', 'Disconnected', 'Connecting') and h.type not in ('ExternalFirewall', 'ExternalLoadBalancer', 'TrafficMonitor', 'SecondaryStorage', 'LocalSecondaryStorage', 'L2Networking') and (h.cluster_id is null or c.managed_state = 'Managed') ;" ; pstmt = txn.prepareStatement(sql); pstmt.setLong(1, timeout); rs = pstmt.executeQuery(); diff --git a/server/src/com/cloud/hypervisor/HypervisorGuruBase.java b/server/src/com/cloud/hypervisor/HypervisorGuruBase.java index a5151948044..bd547abd239 100644 --- a/server/src/com/cloud/hypervisor/HypervisorGuruBase.java +++ b/server/src/com/cloud/hypervisor/HypervisorGuruBase.java @@ -28,12 +28,18 @@ import com.cloud.storage.dao.VMTemplateDetailsDao; import com.cloud.utils.component.AdapterBase; import com.cloud.utils.component.Inject; import com.cloud.vm.NicProfile; +import com.cloud.vm.NicVO; +import com.cloud.vm.VMInstanceVO; import com.cloud.vm.VirtualMachine; import com.cloud.vm.VirtualMachineProfile; +import com.cloud.vm.dao.NicDao; +import com.cloud.vm.dao.VMInstanceDao; public abstract class HypervisorGuruBase extends AdapterBase implements HypervisorGuru { @Inject VMTemplateDetailsDao _templateDetailsDao; + @Inject NicDao _nicDao; + @Inject VMInstanceDao _virtualMachineDao; protected HypervisorGuruBase() { super(); @@ -55,6 +61,10 @@ public abstract class HypervisorGuruBase extends AdapterBase implements Hypervis to.setIsolationuri(profile.getIsolationUri()); to.setNetworkRateMbps(profile.getNetworkRate()); to.setName(profile.getName()); + + // Workaround to make sure the TO has the UUID we need for Niciri integration + NicVO nicVO = _nicDao.findById(profile.getId()); + to.setUuid(nicVO.getUuid()); return to; } @@ -92,6 +102,11 @@ public abstract class HypervisorGuruBase extends AdapterBase implements Hypervis details.putAll(detailsInVm); } to.setDetails(details); + + // Workaround to make sure the TO has the UUID we need for Niciri integration + VMInstanceVO vmInstance = _virtualMachineDao.findById(to.getId()); + to.setUuid(vmInstance.getUuid()); + return to; } diff --git a/server/src/com/cloud/network/ExternalNetworkDeviceManager.java b/server/src/com/cloud/network/ExternalNetworkDeviceManager.java index 115de1baeb4..dec0608c8df 100644 --- a/server/src/com/cloud/network/ExternalNetworkDeviceManager.java +++ b/server/src/com/cloud/network/ExternalNetworkDeviceManager.java @@ -39,6 +39,8 @@ public interface ExternalNetworkDeviceManager extends Manager { public static final NetworkDevice NetscalerSDXLoadBalancer = new NetworkDevice("NetscalerSDXLoadBalancer", Network.Provider.Netscaler.getName()); public static final NetworkDevice F5BigIpLoadBalancer = new NetworkDevice("F5BigIpLoadBalancer", Network.Provider.F5BigIp.getName()); public static final NetworkDevice JuniperSRXFirewall = new NetworkDevice("JuniperSRXFirewall", Network.Provider.JuniperSRX.getName()); + public static final NetworkDevice NiciraNvp = new NetworkDevice("NiciraNvp", Network.Provider.NiciraNvp.getName()); + public NetworkDevice(String deviceName, String ntwkServiceprovider) { _name = deviceName; diff --git a/server/src/com/cloud/network/NetworkManagerImpl.java b/server/src/com/cloud/network/NetworkManagerImpl.java index f26d40d92f0..d04a14018e7 100755 --- a/server/src/com/cloud/network/NetworkManagerImpl.java +++ b/server/src/com/cloud/network/NetworkManagerImpl.java @@ -1455,7 +1455,8 @@ public class NetworkManagerImpl implements NetworkManager, NetworkService, Manag try { if (predefined == null - || (offering.getTrafficType() != TrafficType.Guest && predefined.getCidr() == null && predefined.getBroadcastUri() == null && predefined.getBroadcastDomainType() != BroadcastDomainType.Vlan)) { + || (offering.getTrafficType() != TrafficType.Guest && predefined.getCidr() == null && predefined.getBroadcastUri() == null && + !(predefined.getBroadcastDomainType() == BroadcastDomainType.Vlan || predefined.getBroadcastDomainType() == BroadcastDomainType.Lswitch))) { List configs = _networksDao.listBy(owner.getId(), offering.getId(), plan.getDataCenterId()); if (configs.size() > 0) { if (s_logger.isDebugEnabled()) { @@ -1721,6 +1722,8 @@ public class NetworkManagerImpl implements NetworkManager, NetworkService, Manag Integer networkRate = getNetworkRate(config.getId(), null); to.setNetworkRateMbps(networkRate); + + to.setUuid(config.getUuid()); return to; } diff --git a/server/src/com/cloud/network/guru/ExternalGuestNetworkGuru.java b/server/src/com/cloud/network/guru/ExternalGuestNetworkGuru.java index daa35e36795..24d24f85521 100644 --- a/server/src/com/cloud/network/guru/ExternalGuestNetworkGuru.java +++ b/server/src/com/cloud/network/guru/ExternalGuestNetworkGuru.java @@ -20,9 +20,12 @@ import java.util.List; import javax.ejb.Local; +import org.apache.log4j.Logger; + import com.cloud.configuration.Config; import com.cloud.configuration.dao.ConfigurationDao; import com.cloud.dc.DataCenter; +import com.cloud.dc.DataCenter.NetworkType; import com.cloud.dc.dao.DataCenterDao; import com.cloud.deploy.DeployDestination; import com.cloud.deploy.DeploymentPlan; @@ -32,10 +35,13 @@ import com.cloud.event.EventVO; import com.cloud.exception.InsufficientAddressCapacityException; import com.cloud.exception.InsufficientVirtualNetworkCapcityException; import com.cloud.network.Network; +import com.cloud.network.Network.GuestType; import com.cloud.network.Network.State; import com.cloud.network.NetworkManager; import com.cloud.network.NetworkVO; import com.cloud.network.Networks.BroadcastDomainType; +import com.cloud.network.PhysicalNetwork; +import com.cloud.network.PhysicalNetwork.IsolationMethod; import com.cloud.network.PhysicalNetworkVO; import com.cloud.network.dao.NetworkDao; import com.cloud.network.dao.PhysicalNetworkDao; @@ -58,7 +64,7 @@ import com.cloud.vm.VirtualMachineProfile; @Local(value = NetworkGuru.class) public class ExternalGuestNetworkGuru extends GuestNetworkGuru { - + private static final Logger s_logger = Logger.getLogger(ExternalGuestNetworkGuru.class); @Inject NetworkManager _networkMgr; @Inject @@ -68,7 +74,27 @@ public class ExternalGuestNetworkGuru extends GuestNetworkGuru { @Inject PortForwardingRulesDao _pfRulesDao; - //FIXME: why there is dependency on Ovs tunnel manager. + public ExternalGuestNetworkGuru() { + super(); + _isolationMethods = new IsolationMethod[] { IsolationMethod.GRE, IsolationMethod.L3, IsolationMethod.VLAN }; + } + + protected boolean canHandle(NetworkOffering offering, + final NetworkType networkType, final PhysicalNetwork physicalNetwork) { + // This guru handles only Guest Isolated network that supports Source + // nat service + if (networkType == NetworkType.Advanced + && isMyTrafficType(offering.getTrafficType()) + && offering.getGuestType() == Network.GuestType.Isolated + && isMyIsolationMethod(physicalNetwork)) { + return true; + } else { + s_logger.trace("We only take care of Guest networks of type " + + GuestType.Isolated + " in zone of type " + + NetworkType.Advanced); + return false; + } + } @Override public Network design(NetworkOffering offering, DeploymentPlan plan, Network userSpecified, Account owner) { diff --git a/server/src/com/cloud/network/guru/GuestNetworkGuru.java b/server/src/com/cloud/network/guru/GuestNetworkGuru.java index 33cfb2d1af5..cd5f551abce 100755 --- a/server/src/com/cloud/network/guru/GuestNetworkGuru.java +++ b/server/src/com/cloud/network/guru/GuestNetworkGuru.java @@ -16,6 +16,7 @@ // under the License. package com.cloud.network.guru; +import java.util.ArrayList; import java.util.List; import java.util.Random; import java.util.Set; @@ -46,9 +47,12 @@ import com.cloud.network.Network.State; import com.cloud.network.NetworkManager; import com.cloud.network.NetworkProfile; import com.cloud.network.NetworkVO; +import com.cloud.network.PhysicalNetwork; +import com.cloud.network.PhysicalNetwork.IsolationMethod; import com.cloud.network.PhysicalNetworkVO; import com.cloud.network.Networks.AddressFormat; import com.cloud.network.Networks.BroadcastDomainType; +import com.cloud.network.Networks.IsolationType; import com.cloud.network.Networks.Mode; import com.cloud.network.Networks.TrafficType; import com.cloud.network.dao.IPAddressDao; @@ -72,7 +76,7 @@ import com.cloud.vm.VirtualMachineProfile; import com.cloud.vm.dao.NicDao; @Local(value = NetworkGuru.class) -public class GuestNetworkGuru extends AdapterBase implements NetworkGuru { +public abstract class GuestNetworkGuru extends AdapterBase implements NetworkGuru { private static final Logger s_logger = Logger.getLogger(GuestNetworkGuru.class); @Inject protected NetworkManager _networkMgr; @@ -93,12 +97,16 @@ public class GuestNetworkGuru extends AdapterBase implements NetworkGuru { Random _rand = new Random(System.currentTimeMillis()); private static final TrafficType[] _trafficTypes = {TrafficType.Guest}; - + + // Currently set to anything except STT for the Nicira integration. + protected IsolationMethod[] _isolationMethods; + String _defaultGateway; String _defaultCidr; protected GuestNetworkGuru() { super(); + _isolationMethods = null; } @Override @@ -115,21 +123,54 @@ public class GuestNetworkGuru extends AdapterBase implements NetworkGuru { public TrafficType[] getSupportedTrafficType() { return _trafficTypes; } + + public boolean isMyIsolationMethod(PhysicalNetwork physicalNetwork) { + if (physicalNetwork == null) { + // Can't tell if there is no physical network + return false; + } + + List methods = physicalNetwork.getIsolationMethods(); + if (methods.isEmpty()) { + // The empty isolation method is assumed to be VLAN + s_logger.debug("Empty physical isolation type for physical network " + physicalNetwork.getUuid()); + methods = new ArrayList(1); + methods.add("VLAN"); + } + + for (IsolationMethod m : _isolationMethods) { + if (methods.contains(m.toString())) { + return true; + } + } + + return false; + } + + public IsolationMethod[] getIsolationMethods() { + return _isolationMethods; + } - protected boolean canHandle(NetworkOffering offering, DataCenter dc) { + protected abstract boolean canHandle(NetworkOffering offering, final NetworkType networkType, PhysicalNetwork physicalNetwork); +/* protected boolean canHandle(NetworkOffering offering, final NetworkType networkType, final List isolationMethods) { // This guru handles only Guest Isolated network that supports Source nat service - if (dc.getNetworkType() == NetworkType.Advanced && isMyTrafficType(offering.getTrafficType()) && offering.getGuestType() == Network.GuestType.Isolated) { + if (networkType == NetworkType.Advanced + && isMyTrafficType(offering.getTrafficType()) + && offering.getGuestType() == Network.GuestType.Isolated + && isMyIsolationMethod(isolationMethods)) { return true; } else { s_logger.trace("We only take care of Guest networks of type " + GuestType.Isolated + " in zone of type " + NetworkType.Advanced); return false; } } - +*/ @Override public Network design(NetworkOffering offering, DeploymentPlan plan, Network userSpecified, Account owner) { DataCenter dc = _dcDao.findById(plan.getDataCenterId()); - if (!canHandle(offering, dc)) { + PhysicalNetworkVO physnet = _physicalNetworkDao.findById(plan.getPhysicalNetworkId()); + + if (!canHandle(offering, dc.getNetworkType(), physnet)) { return null; } diff --git a/server/src/com/cloud/server/StatsCollector.java b/server/src/com/cloud/server/StatsCollector.java index 389b728bc75..29e423322e1 100755 --- a/server/src/com/cloud/server/StatsCollector.java +++ b/server/src/com/cloud/server/StatsCollector.java @@ -168,6 +168,7 @@ public class StatsCollector { sc.addAnd("type", SearchCriteria.Op.NEQ, Host.Type.SecondaryStorageVM.toString()); sc.addAnd("type", SearchCriteria.Op.NEQ, Host.Type.ExternalFirewall.toString()); sc.addAnd("type", SearchCriteria.Op.NEQ, Host.Type.ExternalLoadBalancer.toString()); + sc.addAnd("type", SearchCriteria.Op.NEQ, Host.Type.L2Networking.toString()); ConcurrentHashMap hostStats = new ConcurrentHashMap(); List hosts = _hostDao.search(sc, null); for (HostVO host : hosts) diff --git a/setup/db/create-schema.sql b/setup/db/create-schema.sql index c2efb2723e1..a15222aa203 100755 --- a/setup/db/create-schema.sql +++ b/setup/db/create-schema.sql @@ -137,6 +137,9 @@ DROP TABLE IF EXISTS `cloud`.`op_dc_storage_network_ip_address`; DROP TABLE IF EXISTS `cloud`.`cluster_vsm_map`; DROP TABLE IF EXISTS `cloud`.`virtual_supervisor_module`; DROP TABLE IF EXISTS `cloud`.`port_profile`; +DROP TABLE IF EXISTS `cloud`,`external_nicira_nvp_devices`; +DROP TABLE IF EXISTS `cloud`,`nicira_nvp_nic_map`; + CREATE TABLE `cloud`.`version` ( `id` bigint unsigned NOT NULL UNIQUE AUTO_INCREMENT COMMENT 'id', @@ -2152,4 +2155,24 @@ CREATE TABLE `cloud`.`resource_tags` ( ) ENGINE=InnoDB DEFAULT CHARSET=utf8; +CREATE TABLE `cloud`.`external_nicira_nvp_devices` ( + `id` bigint unsigned NOT NULL AUTO_INCREMENT COMMENT 'id', + `uuid` varchar(255) UNIQUE, + `physical_network_id` bigint unsigned NOT NULL COMMENT 'id of the physical network in to which nicira nvp device is added', + `provider_name` varchar(255) NOT NULL COMMENT 'Service Provider name corresponding to this nicira nvp device', + `device_name` varchar(255) NOT NULL COMMENT 'name of the nicira nvp device', + `host_id` bigint unsigned NOT NULL COMMENT 'host id coresponding to the external nicira nvp device', + PRIMARY KEY (`id`), + CONSTRAINT `fk_external_nicira_nvp_devices__host_id` FOREIGN KEY (`host_id`) REFERENCES `host`(`id`) ON DELETE CASCADE, + CONSTRAINT `fk_external_nicira_nvp_devices__physical_network_id` FOREIGN KEY (`physical_network_id`) REFERENCES `physical_network`(`id`) ON DELETE CASCADE +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + +CREATE TABLE `cloud`.`nicira_nvp_nic_map` ( + `id` bigint unsigned NOT NULL AUTO_INCREMENT COMMENT 'id', + `logicalswitch` varchar(255) NOT NULL COMMENT 'nicira uuid of logical switch this port is provisioned on', + `logicalswitchport` varchar(255) UNIQUE COMMENT 'nicira 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`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + SET foreign_key_checks = 1; diff --git a/ui/scripts/ui-custom/zoneWizard.js b/ui/scripts/ui-custom/zoneWizard.js index 3928619565c..a94bf5b8c9e 100644 --- a/ui/scripts/ui-custom/zoneWizard.js +++ b/ui/scripts/ui-custom/zoneWizard.js @@ -596,7 +596,7 @@ } }); //when OVS tunnel manager is used - if(ovsTunnelManager == true) { + //if(ovsTunnelManager == true) { //Advanced zone supports 2 isolation method(VLAN, GRE), so show dropdown including the 2 options if($wizard.find('.select-network-model input:radio[name=network-model]:checked').val() == 'Advanced') { $nameField.append( @@ -614,15 +614,20 @@ }).html('VLAN'), $('

').addClass('drop-container').append( diff --git a/wscript_configure b/wscript_configure index 0ccf40ac321..70fb163a61d 100644 --- a/wscript_configure +++ b/wscript_configure @@ -288,7 +288,7 @@ depsclasspath = [ in_javadir(_basename(x)) for x in _glob(_join(conf.srcdir,"dep conf.env.DEPSCLASSPATH = pathsep.join(depsclasspath) # the MS classpath points to JARs required to run the management server -msclasspath = [ in_javadir("%s-%s.jar"%(conf.env.PACKAGE,x)) for x in "utils api core server server-extras core-extras vmware-base ovm dp-user-concentrated-pod dp-user-dispersing host-allocator-random plugin-f5 plugin-netscaler plugin-ovs plugin-srx storage-allocator-random user-authenticator-ldap user-authenticator-md5 user-authenticator-plaintext vmware xen".split() ] +msclasspath = [ in_javadir("%s-%s.jar"%(conf.env.PACKAGE,x)) for x in "utils api core server server-extras core-extras vmware-base ovm dp-user-concentrated-pod dp-user-dispersing host-allocator-random plugin-f5 plugin-netscaler plugin-ovs plugin-srx storage-allocator-random user-authenticator-ldap user-authenticator-md5 user-authenticator-plaintext vmware xen plugin-nicira-nvp".split() ] conf.env.MSCLASSPATH = pathsep.join(msclasspath) # the agent and simulator classpaths point to JARs required to run these two applications From 9b039d9a8d0f46861e79901482b81e1dd441b115 Mon Sep 17 00:00:00 2001 From: Brian Federle Date: Thu, 12 Jul 2012 13:43:54 -0700 Subject: [PATCH 5/8] List view UI: Support for text action buttons Currently, only icons are rendered on list view actions. This change adds support for showing a text label next to specified actions, which has a button appearance. This is to allow certain actions to be more visible, in the case where an icon isn't clear enough. To make an action have a text label, add a 'textLabel' attribute to the action properties: editVpc: { label: 'Edit VPC', // textLabel property textLabel: 'label.configure', action: { ... } } --- ui/css/cloudstack3.css | 28 ++++++++++++++++++++++++++++ ui/scripts/ui/widgets/listView.js | 10 +++++++++- 2 files changed, 37 insertions(+), 1 deletion(-) diff --git a/ui/css/cloudstack3.css b/ui/css/cloudstack3.css index 3f08f0054e3..caf225f7d35 100644 --- a/ui/css/cloudstack3.css +++ b/ui/css/cloudstack3.css @@ -2817,6 +2817,34 @@ table tr.even td.actions .action.disabled .icon { background-color: #DFE1E3; } +table tr td.actions .action.text { + cursor: pointer; + display: inline-block; + border: 1px solid #C2C2C2; + /*+border-radius:4px;*/ + -moz-border-radius: 4px; + -webkit-border-radius: 4px; + -khtml-border-radius: 4px; + border-radius: 4px; + background: url(../images/bg-gradients.png) repeat-x 0px -83px; +} + +table tr td.actions .action.text:hover { + /*+box-shadow:inset 0px 1px 3px #171717;*/ + -moz-box-shadow: inset 0px 1px 3px #171717; + -webkit-box-shadow: inset 0px 1px 3px #171717; + -o-box-shadow: inset 0px 1px 3px #171717; + box-shadow: inset 0px 1px 3px #171717; +} + +table tr td.actions .action.text .label { + padding: 4px 0 0 4px; +} + +table tr td.actions .action.text .icon { + padding-bottom: 4px; +} + table tr.selected td.actions .action.disabled .icon { background-color: #CBDDF3; } diff --git a/ui/scripts/ui/widgets/listView.js b/ui/scripts/ui/widgets/listView.js index 9ba57301c34..b01d01e18b0 100644 --- a/ui/scripts/ui/widgets/listView.js +++ b/ui/scripts/ui/widgets/listView.js @@ -689,13 +689,21 @@ var $action = $('
') .addClass('action') .addClass(actionName) - .append($('').addClass('icon')) + .append($('').addClass('icon').html(' ')) .attr({ alt: _l(action.label), title: _l(action.label) }) .data('list-view-action-id', actionName); + if (action.textLabel) { + $action + .addClass('text') + .prepend( + $('').addClass('label').html(_l(action.textLabel)) + ); + } + // Disabled appearance/behavior for filtered actions if (allowedActions && $.inArray(actionName, allowedActions) == -1) { $action.addClass('disabled'); From 2a971d7c1bf5dc3c3dbdfaa104df1690d2ee703b Mon Sep 17 00:00:00 2001 From: Brian Federle Date: Thu, 12 Jul 2012 15:14:57 -0700 Subject: [PATCH 6/8] Detail view UI: Support for text action buttons Currently, only icons are rendered on detail view actions. This change adds support for showing a text label next to specified actions, which has a button appearance. This is to allow certain actions to be more visible, in the case where an icon isn't clear enough. To make an action have a text label, add a 'textLabel' attribute to the action properties: editVpc: { label: 'Edit VPC', // textLabel property textLabel: 'label.configure', action: { ... } } --- ui/css/cloudstack3.css | 29 +++++++++++++++++++++++++++++ ui/scripts/ui/widgets/detailView.js | 12 ++++++++++-- 2 files changed, 39 insertions(+), 2 deletions(-) diff --git a/ui/css/cloudstack3.css b/ui/css/cloudstack3.css index caf225f7d35..2af3c47311a 100644 --- a/ui/css/cloudstack3.css +++ b/ui/css/cloudstack3.css @@ -1671,6 +1671,35 @@ div.detail-group.actions td { height: 26px; } +.detail-group table td.detail-actions .action.text { + padding: 4px 6px 4px 7px; + cursor: pointer; + display: inline-block; + border: 1px solid #C2C2C2; + /*+border-radius:4px;*/ + -moz-border-radius: 4px; + -webkit-border-radius: 4px; + -khtml-border-radius: 4px; + border-radius: 4px; + background: url(../images/bg-gradients.png) repeat-x 0px -83px; +} + +.detail-group table td.detail-actions .action.text .label { + font-size: 12px; + /*+placement:shift -1px 8px;*/ + position: relative; + left: -1px; + top: 8px; +} + +.detail-group table td.detail-actions .action.text:hover { + /*+box-shadow:inset 0px 1px 3px #171717;*/ + -moz-box-shadow: inset 0px 1px 3px #171717; + -webkit-box-shadow: inset 0px 1px 3px #171717; + -o-box-shadow: inset 0px 1px 3px #171717; + box-shadow: inset 0px 1px 3px #171717; +} + .detail-group table td.detail-actions div.buttons { /*+placement:shift 6px 0px;*/ position: relative; diff --git a/ui/scripts/ui/widgets/detailView.js b/ui/scripts/ui/widgets/detailView.js index 1ac609f2745..f703395102e 100644 --- a/ui/scripts/ui/widgets/detailView.js +++ b/ui/scripts/ui/widgets/detailView.js @@ -641,6 +641,14 @@ ) .appendTo($action); + if (value.textLabel) { + $action + .addClass('text') + .prepend( + $('').addClass('label').html(_l(value.textLabel)) + ); + } + return true; }); @@ -1091,8 +1099,8 @@ } // Detail action - if ($target.closest('div.detail-view [detail-action]').size()) { - var $action = $target.closest('div.detail-view [detail-action]'); + if ($target.closest('div.detail-view [detail-action], div.detail-view .action.text').size()) { + var $action = $target.closest('.action').find('[detail-action]'); var actionName = $action.attr('detail-action'); var actionCallback = $action.data('detail-view-action-callback'); var detailViewArgs = $action.closest('div.detail-view').data('view-args'); From 50373b99d66775f421bc63a5343deb83e60576f8 Mon Sep 17 00:00:00 2001 From: Brian Federle Date: Thu, 12 Jul 2012 15:26:07 -0700 Subject: [PATCH 7/8] Detail view: Fix layout of text actions --- ui/css/cloudstack3.css | 8 +++++++- ui/scripts/ui/widgets/detailView.js | 4 ++-- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/ui/css/cloudstack3.css b/ui/css/cloudstack3.css index 2af3c47311a..ef81697e464 100644 --- a/ui/css/cloudstack3.css +++ b/ui/css/cloudstack3.css @@ -1672,9 +1672,11 @@ div.detail-group.actions td { } .detail-group table td.detail-actions .action.text { - padding: 4px 6px 4px 7px; + padding: 0px 6px 0px 0px; cursor: pointer; display: inline-block; + float: right; + margin-right: 8px; border: 1px solid #C2C2C2; /*+border-radius:4px;*/ -moz-border-radius: 4px; @@ -1746,6 +1748,10 @@ div.detail-group.actions td { background-position: -414px -625px; } +.detail-group table td.detail-actions div.action.text a { + background: none; +} + .detail-group table td.detail-actions div.action.single a:hover { background-position: -414px -587px; } diff --git a/ui/scripts/ui/widgets/detailView.js b/ui/scripts/ui/widgets/detailView.js index f703395102e..b1e9a68c8a9 100644 --- a/ui/scripts/ui/widgets/detailView.js +++ b/ui/scripts/ui/widgets/detailView.js @@ -643,7 +643,7 @@ if (value.textLabel) { $action - .addClass('text') + .addClass('single text') .prepend( $('').addClass('label').html(_l(value.textLabel)) ); @@ -652,7 +652,7 @@ return true; }); - var $actionButtons = $actions.find('div.action'); + var $actionButtons = $actions.find('div.action:not(.text)'); if ($actionButtons.size() == 1) $actionButtons.addClass('single'); else { From 3d7f6a35ad2ab1e335b3beeb52d278bfd355a791 Mon Sep 17 00:00:00 2001 From: Prasanna Santhanam Date: Fri, 13 Jul 2012 10:49:49 -0700 Subject: [PATCH 8/8] CS-15560 : Improve HVM logging of hosts When a host is not considered for deployment because it has disabled HVM, then call that out in the logs for debugging. Signed-off-by: Nitin Mehta --- .../agent/manager/allocator/impl/FirstFitAllocator.java | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/server/src/com/cloud/agent/manager/allocator/impl/FirstFitAllocator.java b/server/src/com/cloud/agent/manager/allocator/impl/FirstFitAllocator.java index 0f163cc6e7a..27892316469 100755 --- a/server/src/com/cloud/agent/manager/allocator/impl/FirstFitAllocator.java +++ b/server/src/com/cloud/agent/manager/allocator/impl/FirstFitAllocator.java @@ -285,6 +285,7 @@ public class FirstFitAllocator implements HostAllocator { String templateGuestOSCategory = getTemplateGuestOSCategory(template); List prioritizedHosts = new ArrayList(); + List noHvmHosts = new ArrayList(); // If a template requires HVM and a host doesn't support HVM, remove it from consideration List hostsToCheck = new ArrayList(); @@ -292,12 +293,19 @@ public class FirstFitAllocator implements HostAllocator { for (HostVO host : hosts) { if (hostSupportsHVM(host)) { hostsToCheck.add(host); + } else { + noHvmHosts.add(host); } } } else { hostsToCheck.addAll(hosts); } + if (s_logger.isDebugEnabled()) { + if (noHvmHosts.size() > 0) { + s_logger.debug("Not considering hosts: " + noHvmHosts + " to deploy template: " + template +" as they are not HVM enabled"); + } + } // If a host is tagged with the same guest OS category as the template, move it to a high priority list // If a host is tagged with a different guest OS category than the template, move it to a low priority list List highPriorityHosts = new ArrayList();