diff --git a/client/WEB-INF/classes/resources/messages.properties b/client/WEB-INF/classes/resources/messages.properties index 948038c2e9b..21cd03bbb06 100644 --- a/client/WEB-INF/classes/resources/messages.properties +++ b/client/WEB-INF/classes/resources/messages.properties @@ -4,6 +4,8 @@ #Labels +label.action.edit.host=Edit Host + network.rate=Network Rate ICMP.type=ICMP Type diff --git a/client/WEB-INF/classes/resources/messages_es.properties b/client/WEB-INF/classes/resources/messages_es.properties index 21259a7d7f7..30f0c3a88c8 100644 --- a/client/WEB-INF/classes/resources/messages_es.properties +++ b/client/WEB-INF/classes/resources/messages_es.properties @@ -4,6 +4,8 @@ #Labels +label.action.edit.host=edición Anfitrión + network.rate=Tasa de red ICMP.type=Tipo ICMP diff --git a/client/WEB-INF/classes/resources/messages_ja.properties b/client/WEB-INF/classes/resources/messages_ja.properties index 77555ee743b..defd567977c 100644 --- a/client/WEB-INF/classes/resources/messages_ja.properties +++ b/client/WEB-INF/classes/resources/messages_ja.properties @@ -4,6 +4,8 @@ #Labels +label.action.edit.host=ホストを編集する + network.rate=ネットワーク速度 ICMP.type=ICMPタイプ diff --git a/client/WEB-INF/classes/resources/messages_zh_CN.properties b/client/WEB-INF/classes/resources/messages_zh_CN.properties index 3e05d429ad8..8de433f026f 100644 --- a/client/WEB-INF/classes/resources/messages_zh_CN.properties +++ b/client/WEB-INF/classes/resources/messages_zh_CN.properties @@ -4,6 +4,8 @@ #Labels +label.action.edit.host=编辑主机 + network.rate=网络速率 ICMP.type=ICMP类型 diff --git a/core/src/com/cloud/hypervisor/vmware/resource/VmwareResource.java b/core/src/com/cloud/hypervisor/vmware/resource/VmwareResource.java index 653438586b1..cd1b30ca9e9 100755 --- a/core/src/com/cloud/hypervisor/vmware/resource/VmwareResource.java +++ b/core/src/com/cloud/hypervisor/vmware/resource/VmwareResource.java @@ -601,7 +601,8 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa try { String[] addRules = rules[LoadBalancerConfigurator.ADD]; - String[] removeRules = rules[LoadBalancerConfigurator.REMOVE]; + String[] removeRules = rules[LoadBalancerConfigurator.REMOVE]; + String[] statRules = rules[LoadBalancerConfigurator.STATS]; String args = ""; args += "-i " + routerIp; @@ -624,7 +625,16 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa args += " -d " + sb.toString(); } - + + sb = new StringBuilder(); + if (statRules.length > 0) { + for (int i = 0; i < statRules.length; i++) { + sb.append(statRules[i]).append(','); + } + + args += " -s " + sb.toString(); + } + Pair result = SshHelper.sshExecute(controlIp, DEFAULT_DOMR_SSHPORT, "root", mgr.getSystemVMKeyFile(), null, "scp " + tmpCfgFilePath + " /etc/haproxy/haproxy.cfg.new"); if (!result.first()) { @@ -1077,6 +1087,7 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa if (getVmState(vmMo) != State.Stopped) vmMo.safePowerOff(_shutdown_waitMs); vmMo.tearDownDevices(new Class[] { VirtualDisk.class, VirtualEthernetCard.class }); + vmMo.ensureScsiDeviceController(); } else { ManagedObjectReference morDc = hyperHost.getHyperHostDatacenter(); assert (morDc != null); @@ -1091,7 +1102,8 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa if (getVmState(vmMo) != State.Stopped) vmMo.safePowerOff(_shutdown_waitMs); - vmMo.tearDownDevices(new Class[] { VirtualDisk.class, VirtualEthernetCard.class }); + vmMo.tearDownDevices(new Class[] { VirtualDisk.class, VirtualEthernetCard.class }); + vmMo.ensureScsiDeviceController(); } else { int ramMb = (int) (vmSpec.getMinRam() / (1024 * 1024)); Pair rootDiskDataStoreDetails = null; diff --git a/core/src/com/cloud/network/HAProxyConfigurator.java b/core/src/com/cloud/network/HAProxyConfigurator.java index 1f482f4b0df..b02ecc0da63 100644 --- a/core/src/com/cloud/network/HAProxyConfigurator.java +++ b/core/src/com/cloud/network/HAProxyConfigurator.java @@ -206,7 +206,7 @@ public class HAProxyConfigurator implements LoadBalancerConfigurator { result.addAll(Arrays.asList(defaultsSection)); if (!lbCmd.lbStatsVisibility.equals("disabled")) { - if (lbCmd.lbStatsVisibility.equals("guest-network")) + if (lbCmd.lbStatsVisibility.equals("guest-network") || lbCmd.lbStatsVisibility.equals("link-local")) { result.add(getBlankLine()); diff --git a/deps/.classpath b/deps/.classpath index 45c54d0cfea..3d085366b8d 100755 --- a/deps/.classpath +++ b/deps/.classpath @@ -6,16 +6,11 @@ - - - - - @@ -55,5 +50,10 @@ + + + + + diff --git a/deps/cloud-commons-codec-1.4.jar b/deps/cloud-commons-codec-1.4.jar deleted file mode 100644 index 458d432da88..00000000000 Binary files a/deps/cloud-commons-codec-1.4.jar and /dev/null differ diff --git a/deps/cloud-commons-codec-1.5.jar b/deps/cloud-commons-codec-1.5.jar new file mode 100644 index 00000000000..e9013fed78f Binary files /dev/null and b/deps/cloud-commons-codec-1.5.jar differ diff --git a/deps/cloud-commons-dbcp-1.2.2.jar b/deps/cloud-commons-dbcp-1.2.2.jar deleted file mode 100644 index faea05626bc..00000000000 Binary files a/deps/cloud-commons-dbcp-1.2.2.jar and /dev/null differ diff --git a/deps/cloud-commons-dbcp-1.4.jar b/deps/cloud-commons-dbcp-1.4.jar new file mode 100644 index 00000000000..c4c1c4f286a Binary files /dev/null and b/deps/cloud-commons-dbcp-1.4.jar differ diff --git a/deps/cloud-commons-httpclient-3.1.jar b/deps/cloud-commons-httpclient-3.1.jar deleted file mode 100644 index 7c59774aed4..00000000000 Binary files a/deps/cloud-commons-httpclient-3.1.jar and /dev/null differ diff --git a/deps/cloud-commons-pool-1.4.jar b/deps/cloud-commons-pool-1.4.jar deleted file mode 100644 index d6bc185450a..00000000000 Binary files a/deps/cloud-commons-pool-1.4.jar and /dev/null differ diff --git a/deps/cloud-commons-pool-1.5.6.jar b/deps/cloud-commons-pool-1.5.6.jar new file mode 100644 index 00000000000..ce5ff607bfb Binary files /dev/null and b/deps/cloud-commons-pool-1.5.6.jar differ diff --git a/deps/cloud-google-gson-1.7.1.jar b/deps/cloud-google-gson-1.7.1.jar new file mode 100644 index 00000000000..acd16c0646b Binary files /dev/null and b/deps/cloud-google-gson-1.7.1.jar differ diff --git a/deps/cloud-gson.jar b/deps/cloud-gson.jar deleted file mode 100644 index e59483bbba6..00000000000 Binary files a/deps/cloud-gson.jar and /dev/null differ diff --git a/deps/cloud-httpclient-4.1.2.jar b/deps/cloud-httpclient-4.1.2.jar new file mode 100644 index 00000000000..b3cdb4cdc8c Binary files /dev/null and b/deps/cloud-httpclient-4.1.2.jar differ diff --git a/patches/systemvm/debian/config/root/func.sh b/patches/systemvm/debian/config/root/func.sh new file mode 100644 index 00000000000..c1a921a86c9 --- /dev/null +++ b/patches/systemvm/debian/config/root/func.sh @@ -0,0 +1,44 @@ +#!/bin/bash + +# getLockFile() parameters +# $1 lock filename +# $2 timeout seconds +getLockFile() { + __locked=0 + __LOCKFILE="/tmp/$1.lock" + if [ $2 ] + then + __TIMEOUT=$2 + else + __TIMEOUT=10 + fi + + for i in `seq 1 $__TIMEOUT` + do + if [ ! -e $__LOCKFILE ] + then + touch $__LOCKFILE + __locked=1 + break + fi + sleep 1 + logger -t cloud "sleep 1 second wait for the lock file " $__LOCKFILE + done + if [ $__locked -ne 1 ] + then + logger -t cloud "fail to acquire the lock file $__LOCKFILE after $__TIMEOUT seconds time out!" + fi + echo $__locked +} + +# releaseLockFile() parameters +# $1 lock filename +# $2 locked(1) or not(0) +releaseLockFile() { + __LOCKFILE="/tmp/$1.lock" + __locked=$2 + if [ "$__locked" == "1" ] + then + rm $__LOCKFILE + fi +} diff --git a/patches/systemvm/debian/config/root/loadbalancer.sh b/patches/systemvm/debian/config/root/loadbalancer.sh index 9ea4f784e16..bdd480b4d48 100755 --- a/patches/systemvm/debian/config/root/loadbalancer.sh +++ b/patches/systemvm/debian/config/root/loadbalancer.sh @@ -79,7 +79,7 @@ fw_remove_backup() { sudo iptables -X back_load_balancer_$vif 2> /dev/null done sudo iptables -F back_lb_stats 2> /dev/null - sudo iptables -D INPUT -i $STAT_IF -p tcp -j back_lb_stats 2> /dev/null + sudo iptables -D INPUT -p tcp -j back_lb_stats 2> /dev/null sudo iptables -X back_lb_stats 2> /dev/null } fw_restore() { @@ -90,7 +90,7 @@ fw_restore() { sudo iptables -E back_load_balancer_$vif load_balancer_$vif 2> /dev/null done sudo iptables -F lb_stats 2> /dev/null - sudo iptables -D INPUT -i $STAT_IF -p tcp -j lb_stats 2> /dev/null + sudo iptables -D INPUT -p tcp -j lb_stats 2> /dev/null sudo iptables -X lb_stats 2> /dev/null sudo iptables -E back_lb_stats lb_stats 2> /dev/null } @@ -121,7 +121,7 @@ fw_entry() { done sudo iptables -E lb_stats back_lb_stats 2> /dev/null sudo iptables -N lb_stats 2> /dev/null - sudo iptables -A INPUT -i $STAT_IF -p tcp -j lb_stats + sudo iptables -A INPUT -p tcp -j lb_stats for i in $a do @@ -259,8 +259,6 @@ if [ "$VIF_LIST" == "eth0" ] then ip_entry $addedIps $removedIps fi -# FIXME make the load balancer stat interface generic -STAT_IF="eth0" # hot reconfigure haproxy reconfig_lb $cfgfile diff --git a/patches/systemvm/debian/config/root/reconfigLB.sh b/patches/systemvm/debian/config/root/reconfigLB.sh index 38b07142f99..ef4ac7be011 100755 --- a/patches/systemvm/debian/config/root/reconfigLB.sh +++ b/patches/systemvm/debian/config/root/reconfigLB.sh @@ -18,9 +18,18 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see . # - +name="reconfigLB" +source func.sh +locked=$(getLockFile $name) +if [ "$locked" != "1" ] +then + logger -t cloud "Fail to get the lock for " $name + exit 1 +fi + +ret=0 # save previous state mv /etc/haproxy/haproxy.cfg /etc/haproxy/haproxy.cfg.old mv /var/run/haproxy.pid /var/run/haproxy.pid.old @@ -32,7 +41,7 @@ echo "New haproxy instance successfully loaded, stopping previous one." kill -KILL $(cat /var/run/haproxy.pid.old) rm -f /var/run/haproxy.pid.old - exit 0 + ret=0 else echo "New instance failed to start, resuming previous one." kill -TTIN $(cat /var/run/haproxy.pid.old) @@ -40,5 +49,9 @@ mv /var/run/haproxy.pid.old /var/run/haproxy.pid mv /etc/haproxy/haproxy.cfg /etc/haproxy/haproxy.cfg.new mv /etc/haproxy/haproxy.cfg.old /etc/haproxy/haproxy.cfg - exit 1 + ret=1 fi + +releaseLockFile $name $locked + +exit $ret diff --git a/server/src/com/cloud/alert/AlertManagerImpl.java b/server/src/com/cloud/alert/AlertManagerImpl.java index 95e64ef9dee..d2ad750c247 100755 --- a/server/src/com/cloud/alert/AlertManagerImpl.java +++ b/server/src/com/cloud/alert/AlertManagerImpl.java @@ -264,7 +264,7 @@ public class AlertManagerImpl implements AlertManager { try { txn.start(); // Calculate new Public IP capacity - List datacenters = _dcDao.listAllIncludingRemoved(); + List datacenters = _dcDao.listAll(); for (DataCenterVO datacenter : datacenters) { long dcId = datacenter.getId(); @@ -283,7 +283,7 @@ public class AlertManagerImpl implements AlertManager { txn.start(); // Calculate new Private IP capacity - List pods = _podDao.listAllIncludingRemoved(); + List pods = _podDao.listAll(); for (HostPodVO pod : pods) { long podId = pod.getId(); long dcId = pod.getDataCenterId(); diff --git a/server/src/com/cloud/configuration/Config.java b/server/src/com/cloud/configuration/Config.java index 656883df16d..6a20c3e17aa 100755 --- a/server/src/com/cloud/configuration/Config.java +++ b/server/src/com/cloud/configuration/Config.java @@ -58,7 +58,7 @@ public enum Config { StorageTemplateCleanupEnabled("Storage", ManagementServer.class, Boolean.class, "storage.template.cleanup.enabled", "true", "Enable/disable template cleanup activity, only take effect when overall storage cleanup is enabled", null), // Network - NetworkLBHaproxyStatsVisbility("Network", ManagementServer.class, String.class, "network.loadbalancer.haproxy.stats.visibility", "global", "Load Balancer(haproxy) stats visibilty, it can be global,guest-network,disabled", null), + NetworkLBHaproxyStatsVisbility("Network", ManagementServer.class, String.class, "network.loadbalancer.haproxy.stats.visibility", "global", "Load Balancer(haproxy) stats visibilty, it can take the following four parameters : global,guest-network,link-local,disabled", null), NetworkLBHaproxyStatsUri("Network", ManagementServer.class, String.class, "network.loadbalancer.haproxy.stats.uri","/admin?stats","Load Balancer(haproxy) uri.",null), NetworkLBHaproxyStatsAuth("Network", ManagementServer.class, String.class, "network.loadbalancer.haproxy.stats.auth","admin1:AdMiN123","Load Balancer(haproxy) authetication string in the format username:password",null), NetworkLBHaproxyStatsPort("Network", ManagementServer.class, String.class, "network.loadbalancer.haproxy.stats.port","8081","Load Balancer(haproxy) stats port number.",null), @@ -79,7 +79,7 @@ public enum Config { SecurityGroupWorkerThreads("Network", ManagementServer.class, Integer.class, "network.securitygroups.workers.pool.size", "50", "Number of worker threads processing the security group update work queue", null), SecurityGroupWorkGlobalLockTimeout("Network", ManagementServer.class, Integer.class, "network.securitygroups.work.lock.timeout", "300", "Lock wait timeout (seconds) while updating the security group work queue", null), - FirewallRuleUiEnabled("Network", ManagementServer.class, Boolean.class, "firewall.rule.ui.enabled", "true", "enable/disable UI that separates firewall rules from NAT/LB rules", null), + FirewallRuleUiEnabled("Network", ManagementServer.class, Boolean.class, "firewall.rule.ui.enabled", "false", "enable/disable UI that separates firewall rules from NAT/LB rules", null), //VPN RemoteAccessVpnPskLength("Network", AgentManager.class, Integer.class, "remote.access.vpn.psk.length", "24", "The length of the ipsec preshared key (minimum 8, maximum 256)", null), diff --git a/server/src/com/cloud/host/dao/HostDaoImpl.java b/server/src/com/cloud/host/dao/HostDaoImpl.java index 988dfc4c231..f3d74885fcd 100755 --- a/server/src/com/cloud/host/dao/HostDaoImpl.java +++ b/server/src/com/cloud/host/dao/HostDaoImpl.java @@ -640,7 +640,7 @@ public class HostDaoImpl extends GenericDaoBase implements HostDao s_logger.warn("Unable to update db record for host id=" + host.getId() + "; it's possible that the host is removed"); } - if (s_logger.isDebugEnabled() && result == 1) { + if (s_logger.isDebugEnabled() && result == 0) { HostVO vo = findById(host.getId()); if (vo != null) { diff --git a/server/src/com/cloud/network/lb/ElasticLoadBalancerManagerImpl.java b/server/src/com/cloud/network/lb/ElasticLoadBalancerManagerImpl.java index 1631ac42caa..ee19eaed45c 100644 --- a/server/src/com/cloud/network/lb/ElasticLoadBalancerManagerImpl.java +++ b/server/src/com/cloud/network/lb/ElasticLoadBalancerManagerImpl.java @@ -299,7 +299,13 @@ public class ElasticLoadBalancerManagerImpl implements cmd.lbStatsUri = _configDao.getValue(Config.NetworkLBHaproxyStatsUri.key()); cmd.lbStatsAuth = _configDao.getValue(Config.NetworkLBHaproxyStatsAuth.key()); cmd.lbStatsPort = _configDao.getValue(Config.NetworkLBHaproxyStatsPort.key()); - cmd.lbStatsIp = elbVm.getGuestIpAddress(); + if (cmd.lbStatsVisibility.equals("guest-network")) + { + cmd.lbStatsIp = elbVm.getGuestIpAddress();; + }else + { + cmd.lbStatsIp = elbVm.getPrivateIpAddress(); + } cmds.addCommand(cmd); } diff --git a/server/src/com/cloud/network/router/VirtualNetworkApplianceManagerImpl.java b/server/src/com/cloud/network/router/VirtualNetworkApplianceManagerImpl.java index d2d8608b197..0e8fee0dd55 100755 --- a/server/src/com/cloud/network/router/VirtualNetworkApplianceManagerImpl.java +++ b/server/src/com/cloud/network/router/VirtualNetworkApplianceManagerImpl.java @@ -2017,11 +2017,19 @@ public class VirtualNetworkApplianceManagerImpl implements VirtualNetworkApplian } LoadBalancerConfigCommand cmd = new LoadBalancerConfigCommand(lbs); - cmd.lbStatsIp = router.getGuestIpAddress(); + cmd.lbStatsVisibility = _configDao.getValue(Config.NetworkLBHaproxyStatsVisbility.key()); cmd.lbStatsUri = _configDao.getValue(Config.NetworkLBHaproxyStatsUri.key()); cmd.lbStatsAuth = _configDao.getValue(Config.NetworkLBHaproxyStatsAuth.key()); cmd.lbStatsPort = _configDao.getValue(Config.NetworkLBHaproxyStatsPort.key()); + if (cmd.lbStatsVisibility.equals("guest-network")) + { + cmd.lbStatsIp = router.getGuestIpAddress(); + }else + { + cmd.lbStatsIp = router.getPrivateIpAddress(); + } + cmd.setAccessDetail(NetworkElementCommand.ROUTER_IP, router.getPrivateIpAddress()); cmd.setAccessDetail(NetworkElementCommand.ROUTER_GUEST_IP, router.getGuestIpAddress()); diff --git a/server/src/com/cloud/storage/dao/VMTemplateDao.java b/server/src/com/cloud/storage/dao/VMTemplateDao.java index 0a622d163ac..4b21a0a8833 100644 --- a/server/src/com/cloud/storage/dao/VMTemplateDao.java +++ b/server/src/com/cloud/storage/dao/VMTemplateDao.java @@ -22,7 +22,6 @@ import java.util.List; import java.util.Set; import com.cloud.domain.DomainVO; -import com.cloud.hypervisor.Hypervisor; import com.cloud.hypervisor.Hypervisor.HypervisorType; import com.cloud.storage.VMTemplateVO; import com.cloud.template.VirtualMachineTemplate.TemplateFilter; diff --git a/server/src/com/cloud/template/TemplateManagerImpl.java b/server/src/com/cloud/template/TemplateManagerImpl.java index 86320a5246b..ff7952d24c3 100755 --- a/server/src/com/cloud/template/TemplateManagerImpl.java +++ b/server/src/com/cloud/template/TemplateManagerImpl.java @@ -249,21 +249,23 @@ public class TemplateManagerImpl implements TemplateManager, Manager, TemplateSe } private Long extract(Account caller, Long templateId, String url, Long zoneId, String mode, Long eventId, boolean isISO, AsyncJobVO job, AsyncJobManager mgr) { - String desc = "template"; + String desc = Upload.Type.TEMPLATE.toString(); if (isISO) { - desc = "ISO"; + desc = Upload.Type.ISO.toString(); } eventId = eventId == null ? 0:eventId; + VMTemplateVO template = _tmpltDao.findById(templateId); if (template == null || template.getRemoved() != null) { throw new InvalidParameterValueException("Unable to find " +desc+ " with id " + templateId); } + if (template.getTemplateType() == Storage.TemplateType.SYSTEM){ throw new InvalidParameterValueException("Unable to extract the " + desc + " " + template.getName() + " as it is a default System template"); - } - if (template.getTemplateType() == Storage.TemplateType.PERHOST){ + } else if (template.getTemplateType() == Storage.TemplateType.PERHOST){ throw new InvalidParameterValueException("Unable to extract the " + desc + " " + template.getName() + " as it resides on host and not on SSVM"); } + if (isISO) { if (template.getFormat() != ImageFormat.ISO ){ throw new InvalidParameterValueException("Unsupported format, could not extract the ISO"); @@ -273,6 +275,7 @@ public class TemplateManagerImpl implements TemplateManager, Manager, TemplateSe throw new InvalidParameterValueException("Unsupported format, could not extract the template"); } } + if (_dcDao.findById(zoneId) == null) { throw new IllegalArgumentException("Please specify a valid zone."); } @@ -300,14 +303,15 @@ public class TemplateManagerImpl implements TemplateManager, Manager, TemplateSe } } - if ( tmpltHostRef == null ) { + if (tmpltHostRef == null ) { throw new InvalidParameterValueException("The " + desc + " has not been downloaded "); } + Upload.Mode extractMode; - if( mode == null || (!mode.equals(Upload.Mode.FTP_UPLOAD.toString()) && !mode.equals(Upload.Mode.HTTP_DOWNLOAD.toString())) ){ - throw new InvalidParameterValueException("Please specify a valid extract Mode "+Upload.Mode.values()); - }else{ - extractMode = mode.equals(Upload.Mode.FTP_UPLOAD.toString()) ? Upload.Mode.FTP_UPLOAD : Upload.Mode.HTTP_DOWNLOAD; + if (mode == null || (!mode.equalsIgnoreCase(Upload.Mode.FTP_UPLOAD.toString()) && !mode.equalsIgnoreCase(Upload.Mode.HTTP_DOWNLOAD.toString())) ){ + throw new InvalidParameterValueException("Please specify a valid extract Mode. Supported modes: "+ Upload.Mode.FTP_UPLOAD + ", " + Upload.Mode.HTTP_DOWNLOAD); + } else { + extractMode = mode.equalsIgnoreCase(Upload.Mode.FTP_UPLOAD.toString()) ? Upload.Mode.FTP_UPLOAD : Upload.Mode.HTTP_DOWNLOAD; } if (extractMode == Upload.Mode.FTP_UPLOAD){ @@ -334,7 +338,7 @@ public class TemplateManagerImpl implements TemplateManager, Manager, TemplateSe throw new InvalidParameterValueException("Unable to resolve " + host); } - if ( _uploadMonitor.isTypeUploadInProgress(templateId, isISO ? Type.ISO : Type.TEMPLATE) ){ + if (_uploadMonitor.isTypeUploadInProgress(templateId, isISO ? Type.ISO : Type.TEMPLATE) ){ throw new IllegalArgumentException(template.getName() + " upload is in progress. Please wait for some time to schedule another upload for the same"); } @@ -342,7 +346,7 @@ public class TemplateManagerImpl implements TemplateManager, Manager, TemplateSe } UploadVO vo = _uploadMonitor.createEntityDownloadURL(template, tmpltHostRef, zoneId, eventId); - if (vo!=null){ + if (vo != null){ return vo.getId(); }else{ return null; diff --git a/server/src/com/cloud/vm/VirtualMachineManagerImpl.java b/server/src/com/cloud/vm/VirtualMachineManagerImpl.java index d60af6f9d35..552fc246b4c 100755 --- a/server/src/com/cloud/vm/VirtualMachineManagerImpl.java +++ b/server/src/com/cloud/vm/VirtualMachineManagerImpl.java @@ -1594,13 +1594,20 @@ public class VirtualMachineManagerImpl implements VirtualMachineManager, Listene } } - if(vm.getHostId() == null || hostId != vm.getHostId()) { + if(serverState == State.Running) { try { - stateTransitTo(vm, VirtualMachine.Event.AgentReportMigrated, hostId); + if(hostId != vm.getHostId()) { + if (s_logger.isDebugEnabled()) { + s_logger.debug("detected host change when VM " + vm + " is at running state, VM could be live-migrated externally from host " + + vm.getHostId() + " to host " + hostId); + } + + stateTransitTo(vm, VirtualMachine.Event.AgentReportMigrated, hostId); + } } catch (NoTransitionException e) { s_logger.warn(e.getMessage()); } - } + } } if (agentState == serverState) { diff --git a/setup/db/db/schema-228to229.sql b/setup/db/db/schema-228to229.sql index 27bbad44b3e..6cddc62a185 100644 --- a/setup/db/db/schema-228to229.sql +++ b/setup/db/db/schema-228to229.sql @@ -49,7 +49,7 @@ ALTER TABLE `cloud`.`configuration` ADD INDEX `i_configuration__component` (`com ALTER TABLE `cloud`.`port_forwarding_rules` ADD CONSTRAINT `fk_port_forwarding_rules__instance_id` FOREIGN KEY `fk_port_forwarding_rules__instance_id` (`instance_id`) REFERENCES `vm_instance` (`id`) ON DELETE CASCADE; INSERT IGNORE INTO configuration VALUES ('Advanced', 'DEFAULT', 'management-server', 'agent.load.threshold', '0.70', 'Percentage (as a value between 0 and 1) of connected agents after which agent load balancing will start happening'); -INSERT IGNORE INTO configuration VALUES ('Network', 'DEFAULT', 'management-server', 'network.loadbalancer.haproxy.stats.visibility', 'global', 'Load Balancer(haproxy) stats visibilty, it can be global,guest-network,disabled'); +INSERT IGNORE INTO configuration VALUES ('Network', 'DEFAULT', 'management-server', 'network.loadbalancer.haproxy.stats.visibility', 'global', 'Load Balancer(haproxy) stats visibilty, it can take the following four parameters : global,guest-network,link-local,disabled'); INSERT IGNORE INTO configuration VALUES ('Network', 'DEFAULT', 'management-server', 'network.loadbalancer.haproxy.stats.uri','/admin?stats','Load Balancer(haproxy) uri.'); INSERT IGNORE INTO configuration VALUES ('Network', 'DEFAULT', 'management-server', 'network.loadbalancer.haproxy.stats.auth','admin1:AdMiN123','Load Balancer(haproxy) authetication string in the format username:password'); INSERT IGNORE INTO configuration VALUES ('Network', 'DEFAULT', 'management-server', 'network.loadbalancer.haproxy.stats.port','8081','Load Balancer(haproxy) stats port number.'); diff --git a/setup/db/db/schema-229to2210.sql b/setup/db/db/schema-229to2210.sql index c0fe2086f48..eb6d6f3671d 100644 --- a/setup/db/db/schema-229to2210.sql +++ b/setup/db/db/schema-229to2210.sql @@ -27,11 +27,11 @@ ALTER TABLE `cloud`.`firewall_rules` ADD CONSTRAINT `fk_firewall_rules__related` ALTER TABLE `cloud`.`firewall_rules` MODIFY `start_port` int(10) COMMENT 'starting port of a port range'; ALTER TABLE `cloud`.`firewall_rules` MODIFY `end_port` int(10) COMMENT 'end port of a port range'; -INSERT IGNORE INTO `cloud`.`configuration` (category, instance, name, value, description) VALUES ('Network', 'DEFAULT', 'firewall.rule.ui.enabled', 'true', 'enable/disable UI that separates firewall rules from NAT/LB rules'); +INSERT IGNORE INTO `cloud`.`configuration` (category, instance, name, value, description) VALUES ('Network', 'DEFAULT', 'firewall.rule.ui.enabled', 'false', 'enable/disable UI that separates firewall rules from NAT/LB rules'); INSERT IGNORE INTO configuration VALUES ('Advanced', 'DEFAULT', 'management-server', 'agent.load.threshold', '0.70', 'Percentage (as a value between 0 and 1) of connected agents after which agent load balancing will start happening'); -INSERT IGNORE INTO configuration VALUES ('Network', 'DEFAULT', 'management-server', 'network.loadbalancer.haproxy.stats.visibility', 'global', 'Load Balancer(haproxy) stats visibilty, it can be global,guest-network,disabled'); +INSERT IGNORE INTO configuration VALUES ('Network', 'DEFAULT', 'management-server', 'network.loadbalancer.haproxy.stats.visibility', 'global', 'Load Balancer(haproxy) stats visibilty, it can take the following four parameters : global,guest-network,link-local,disabled'); INSERT IGNORE INTO configuration VALUES ('Network', 'DEFAULT', 'management-server', 'network.loadbalancer.haproxy.stats.uri','/admin?stats','Load Balancer(haproxy) uri.'); INSERT IGNORE INTO configuration VALUES ('Network', 'DEFAULT', 'management-server', 'network.loadbalancer.haproxy.stats.auth','admin1:AdMiN123','Load Balancer(haproxy) authetication string in the format username:password'); INSERT IGNORE INTO configuration VALUES ('Network', 'DEFAULT', 'management-server', 'network.loadbalancer.haproxy.stats.port','8081','Load Balancer(haproxy) stats port number.'); diff --git a/tools/testClient/asyncJobMgr.py b/tools/testClient/asyncJobMgr.py index 3afc2c1e76e..39ee80b4643 100644 --- a/tools/testClient/asyncJobMgr.py +++ b/tools/testClient/asyncJobMgr.py @@ -4,6 +4,8 @@ import time import Queue import copy import sys +import jsonHelper +import datetime class job(object): def __init__(self): @@ -17,51 +19,81 @@ class jobStatus(object): self.endTime = None self.duration = None self.jobId = None + self.responsecls = None class workThread(threading.Thread): - def __init__(self, in_queue, out_dict, apiClient, db=None): + def __init__(self, in_queue, outqueue, apiClient, db=None, lock=None): threading.Thread.__init__(self) self.inqueue = in_queue - self.output = out_dict - self.connection = copy.copy(apiClient.connection) + self.output = outqueue + self.connection = apiClient.connection self.db = None + self.lock = lock + def queryAsynJob(self, job): + if job.jobId is None: + return job + + try: + self.lock.acquire() + result = self.connection.pollAsyncJob(job.jobId, job.responsecls).jobresult + except cloudstackException.cloudstackAPIException, e: + result = str(e) + finally: + self.lock.release() + + job.result = result + return job + + def executeCmd(self, job): + cmd = job.cmd + + jobstatus = jobStatus() + jobId = None + try: + self.lock.acquire() + + if cmd.isAsync == "false": + jobstatus.startTime = datetime.datetime.now() + + result = self.connection.make_request(cmd) + jobstatus.result = result + jobstatus.endTime = datetime.datetime.now() + jobstatus.duration = time.mktime(jobstatus.endTime.timetuple()) - time.mktime(jobstatus.startTime.timetuple()) + else: + result = self.connection.make_request(cmd, None, True) + if result is None: + jobstatus.status = False + else: + jobId = result.jobid + jobstatus.jobId = jobId + try: + responseName = cmd.__class__.__name__.replace("Cmd", "Response") + jobstatus.responsecls = jsonHelper.getclassFromName(cmd, responseName) + except: + pass + jobstatus.status = True + except cloudstackException.cloudstackAPIException, e: + jobstatus.result = str(e) + jobstatus.status = False + except: + jobstatus.status = False + jobstatus.result = sys.exc_info() + finally: + self.lock.release() + + return jobstatus + def run(self): while self.inqueue.qsize() > 0: job = self.inqueue.get() - cmd = job.cmd - cmdName = cmd.__class__.__name__ - responseName = cmdName.replace("Cmd", "Response") - responseInstance = self.connection.getclassFromName(cmd, responseName) - jobstatus = jobStatus() - jobId = None - try: - if not cmd.isAsync: - jobstatus.startTime = time.time() - result = self.connection.make_request(cmd, responseInstance) - jobstatus.result = result - jobstatus.endTime = time.time() - else: - result = self.connection.make_request(cmd, responseInstance, True) - jobId = self.connection.getAsyncJobId(responseInstance, result) - result = self.connection.pollAsyncJob(cmd, responseInstance, jobId) - jobstatus.result = result - jobstatus.jobId = jobId + if isinstance(job, jobStatus): + jobstatus = self.queryAsynJob(job) + else: + jobstatus = self.executeCmd(job) - jobstatus.status = True - except cloudstackException.cloudstackAPIException, e: - jobstatus.result = str(e) - jobstatus.status = False - except: - jobstatus.status = False - jobstatus.result = sys.exc_info() - - #print job.id - self.output.lock.acquire() - self.output.dict[job.id] = jobstatus - self.output.lock.release() + self.output.put(jobstatus) self.inqueue.task_done() - '''release the resource''' self.connection.close() @@ -92,6 +124,7 @@ class asyncJobMgr(object): def __init__(self, apiClient, db): self.inqueue = Queue.Queue() self.output = outputDict() + self.outqueue = Queue.Queue() self.apiClient = apiClient self.db = db @@ -109,34 +142,48 @@ class asyncJobMgr(object): ids.append(id) return ids - def waitForComplete(self): - self.inqueue.join() - - for k,jobstatus in self.output.dict.iteritems(): - jobId = jobstatus.jobId - if jobId is not None and self.db is not None: - result = self.db.execute("select job_status, created, last_updated from async_job where id=%s"%jobId) - if result is not None and len(result) > 0: - if result[0][0] == 1: - jobstatus.status = True - else: - jobstatus.status = False + def updateTimeStamp(self, jobstatus): + jobId = jobstatus.jobId + if jobId is not None and self.db is not None: + result = self.db.execute("select job_status, created, last_updated from async_job where id=%s"%jobId) + if result is not None and len(result) > 0: + if result[0][0] == 1: + jobstatus.status = True + else: + jobstatus.status = False jobstatus.startTime = result[0][1] jobstatus.endTime = result[0][2] delta = jobstatus.endTime - jobstatus.startTime jobstatus.duration = delta.total_seconds() + + def waitForComplete(self, workers=10): + self.inqueue.join() + lock = threading.Lock() + resultQueue = Queue.Queue() + '''intermediate result is stored in self.outqueue''' + for i in range(workers): + worker = workThread(self.outqueue, resultQueue, self.apiClient, self.db, lock) + worker.start() - return self.output.dict + self.outqueue.join() + + asyncJobResult = [] + while resultQueue.qsize() > 0: + jobstatus = resultQueue.get() + self.updateTimeStamp(jobstatus) + asyncJobResult.append(jobstatus) + + return asyncJobResult '''put commands into a queue at first, then start workers numbers threads to execute this commands''' def submitCmdsAndWait(self, cmds, workers=10): self.submitCmds(cmds) - + lock = threading.Lock() for i in range(workers): - worker = workThread(self.inqueue, self.output, self.apiClient, self.db) + worker = workThread(self.inqueue, self.outqueue, self.apiClient, self.db, lock) worker.start() - return self.waitForComplete() + return self.waitForComplete(workers) '''submit one job and execute the same job ntimes, with nums_threads of threads''' def submitJobExecuteNtimes(self, job, ntimes=1, nums_threads=1, interval=1): diff --git a/tools/testClient/cloudstackConnection.py b/tools/testClient/cloudstackConnection.py index e0a6a22519d..3d341418665 100644 --- a/tools/testClient/cloudstackConnection.py +++ b/tools/testClient/cloudstackConnection.py @@ -10,6 +10,7 @@ import time import inspect import cloudstackException from cloudstackAPI import * +import jsonHelper class cloudConnection(object): def __init__(self, mgtSvr, port=8096, apiKey = None, securityKey = None, asyncTimeout=3600, logging=None): @@ -38,7 +39,7 @@ class cloudConnection(object): def make_request_with_auth(self, command, requests={}): requests["command"] = command requests["apiKey"] = self.apiKey - requests["response"] = "xml" + requests["response"] = "json" requests = zip(requests.keys(), requests.values()) requests.sort(key=lambda x: str.lower(x[0])) @@ -54,148 +55,30 @@ class cloudConnection(object): def make_request_without_auth(self, command, requests={}): requests["command"] = command - requests["response"] = "xml" + requests["response"] = "json" requests = zip(requests.keys(), requests.values()) requestUrl = "&".join(["=".join([request[0], urllib.quote_plus(str(request[1]))]) for request in requests]) self.connection.request("GET", "/&%s"%requestUrl) return self.connection.getresponse().read() - def getText(self, elements): - if len(elements) < 1: - return None - if not elements[0].hasChildNodes(): - return None - if elements[0].childNodes[0].nodeValue is None: - return None - return elements[0].childNodes[0].nodeValue.strip() - - def getclassFromName(self, cmd, name): - module = inspect.getmodule(cmd) - return getattr(module, name)() - def parseOneInstance(self, element, instance): - ItemsNeedToCheck = {} - for attribute in dir(instance): - if attribute != "__doc__" and attribute != "__init__" and attribute != "__module__": - ItemsNeedToCheck[attribute] = getattr(instance, attribute) - for attribute, value in ItemsNeedToCheck.items(): - if type(value) == types.ListType: - subItem = [] - for subElement in element.getElementsByTagName(attribute): - newInstance = self.getclassFromName(instance, attribute) - self.parseOneInstance(subElement, newInstance) - subItem.append(newInstance) - setattr(instance, attribute, subItem) - continue - else: - item = element.getElementsByTagName(attribute) - if len(item) == 0: - continue - - returnValue = self.getText(item) - setattr(instance, attribute, returnValue) - - def hasErrorCode(self, elements, responseName): - errorCode = elements[0].getElementsByTagName("errorcode") - if len(errorCode) > 0: - erroCodeText = self.getText(errorCode) - errorText = elements[0].getElementsByTagName("errortext") - if len(errorText) > 0: - errorText = self.getText(errorText) - errMsg = "errorCode: %s, errorText:%s"%(erroCodeText, errorText) - raise cloudstackException.cloudstackAPIException(responseName, errMsg) - - def paraseReturnXML(self, result, response): - responseName = response.__class__.__name__.lower() - cls = response.__class__ - - responseLists = [] - morethanOne = False - - dom = xml.dom.minidom.parseString(result) - elements = dom.getElementsByTagName(responseName) - if len(elements) == 0: - return responseLists - - self.hasErrorCode(elements, responseName) - - count = elements[0].getElementsByTagName("count") - if len(count) > 0: - morethanOne = True - for node in elements[0].childNodes: - if node.nodeName == "count": - continue - newInstance = cls() - self.parseOneInstance(node, newInstance) - responseLists.append(newInstance) - - else: - if elements[0].hasChildNodes(): - newInstance = cls() - self.parseOneInstance(elements[0], newInstance) - responseLists.append(newInstance) - - return responseLists, morethanOne - - def paraseResultFromElement(self, elements, response): - responseName = response.__class__.__name__.lower() - cls = response.__class__ - - responseLists = [] - morethanOne = False - - newInstance = cls() - self.parseOneInstance(elements[0], newInstance) - responseLists.append(newInstance) - - return responseLists, morethanOne - def getAsyncJobId(self, response, resultXml): - responseName = response.__class__.__name__.lower() - dom = xml.dom.minidom.parseString(resultXml) - elements = dom.getElementsByTagName(responseName) - if len(elements) == 0: - raise cloudstackException.cloudstackAPIException("can't find %s"%responseName) - - self.hasErrorCode(elements, responseName) - - jobIdEle = elements[0].getElementsByTagName("jobid") - if len(jobIdEle) == 0: - errMsg = 'can not find jobId in the result:%s'%resultXml - - raise cloudstackException.cloudstackAPIException(errMsg) - - jobId = self.getText(jobIdEle) - return jobId - - def pollAsyncJob(self, cmd, response, jobId): - commandName = cmd.__class__.__name__.replace("Cmd", "") + def pollAsyncJob(self, jobId, response): cmd = queryAsyncJobResult.queryAsyncJobResultCmd() cmd.jobid = jobId while self.asyncTimeout > 0: - asyncResponse = queryAsyncJobResult.queryAsyncJobResultResponse() - responseName = asyncResponse.__class__.__name__.lower() - asyncResponseXml = self.make_request(cmd, asyncResponse, True) - dom = xml.dom.minidom.parseString(asyncResponseXml) - elements = dom.getElementsByTagName(responseName) - if len(elements) == 0: - raise cloudstackException.cloudstackAPIException("can't find %s"%responseName) - - self.hasErrorCode(elements, responseName) + asyncResonse = self.make_request(cmd, response, True) - jobstatus = self.getText(elements[0].getElementsByTagName("jobstatus")) + if asyncResonse.jobstatus == 2: + raise cloudstackException.cloudstackAPIException("asyncquery", asyncResonse.jobresult) + elif asyncResonse.jobstatus == 1: + return asyncResonse - if jobstatus == "2": - jobResult = self.getText(elements[0].getElementsByTagName("jobresult")) - raise cloudstackException.cloudstackAPIException(commandName, jobResult) - elif jobstatus == "1": - jobResultEle = elements[0].getElementsByTagName("jobresult") - - return self.paraseResultFromElement(jobResultEle, response) - time.sleep(5) + self.asyncTimeout = self.asyncTimeout - 5 - raise cloudstackException.cloudstackAPIException(commandName, "Async job timeout") - def make_request(self, cmd, response, raw=False): + raise cloudstackException.cloudstackAPIException("asyncquery", "Async job timeout") + + def make_request(self, cmd, response = None, raw=False): commandName = cmd.__class__.__name__.replace("Cmd", "") isAsync = "false" requests = {} @@ -231,7 +114,7 @@ class cloudConnection(object): i = i + 1 if self.logging is not None: - self.logging.debug("sending command: " + str(requests)) + self.logging.debug("sending command: %s %s"%(commandName, str(requests))) result = None if self.auth: result = self.make_request_with_auth(commandName, requests) @@ -243,19 +126,13 @@ class cloudConnection(object): if result is None: return None - if raw: - return result - if isAsync == "false": - result,num = self.paraseReturnXML(result, response) - else: - jobId = self.getAsyncJobId(response, result) - result,num = self.pollAsyncJob(cmd, response, jobId) - if num: + result = jsonHelper.getResultObj(result, response) + if raw or isAsync == "false": return result else: - if len(result) != 0: - return result[0] - return None + asynJobId = result.jobid + result = self.pollAsyncJob(asynJobId, response) + return result.jobresult if __name__ == '__main__': xml = '407i-1-407-RS3i-1-407-RS3system1ROOT2011-07-30T14:45:19-0700Runningfalse1CA13kvm-50-2054CentOS 5.5(64-bit) no GUI (KVM)CentOS 5.5(64-bit) no GUI (KVM)false1Small Instance15005121120NetworkFilesystem380203255.255.255.065.19.181.165.19.181.110vlan://65vlan://65GuestDirecttrue06:52:da:00:00:08KVM' diff --git a/tools/testClient/cloudstackTestClient.py b/tools/testClient/cloudstackTestClient.py index 150e02b9046..0d8f8108ea9 100644 --- a/tools/testClient/cloudstackTestClient.py +++ b/tools/testClient/cloudstackTestClient.py @@ -39,7 +39,8 @@ class cloudstackTestClient(object): def getApiClient(self): return self.apiClient - def submitCmdsAndWait(self, cmds, workers=10): + '''FixME, httplib has issue if more than one thread submitted''' + def submitCmdsAndWait(self, cmds, workers=1): if self.asyncJobMgr is None: self.asyncJobMgr = asyncJobMgr.asyncJobMgr(self.apiClient, self.dbConnection) return self.asyncJobMgr.submitCmdsAndWait(cmds, workers) diff --git a/tools/testClient/configGenerator.py b/tools/testClient/configGenerator.py index 51b58861ab7..10d82aa5671 100644 --- a/tools/testClient/configGenerator.py +++ b/tools/testClient/configGenerator.py @@ -1,57 +1,7 @@ import json import os from optparse import OptionParser -class Struct: - '''The recursive class for building and representing objects with.''' - def __init__(self, obj): - for k in obj: - v = obj[k] - if isinstance(v, dict): - setattr(self, k, Struct(v)) - elif isinstance(v, (list, tuple)): - setattr(self, k, [Struct(elem) for elem in v]) - else: - setattr(self,k,v) - def __getattr__(self, val): - if val in self.__dict__: - return self.__dict__[val] - else: - return None - def __repr__(self): - return '{%s}' % str(', '.join('%s : %s' % (k, repr(v)) for (k, v) in self.__dict__.iteritems())) - - -def json_repr(obj): - """Represent instance of a class as JSON. - Arguments: - obj -- any object - Return: - String that reprent JSON-encoded object. - """ - def serialize(obj): - """Recursively walk object's hierarchy.""" - if isinstance(obj, (bool, int, long, float, basestring)): - return obj - elif isinstance(obj, dict): - obj = obj.copy() - newobj = {} - for key in obj: - if obj[key] is not None: - if (isinstance(obj[key], list) and len(obj[key]) == 0): - continue - newobj[key] = serialize(obj[key]) - - return newobj - elif isinstance(obj, list): - return [serialize(item) for item in obj] - elif isinstance(obj, tuple): - return tuple(serialize([item for item in obj])) - elif hasattr(obj, '__dict__'): - return serialize(obj.__dict__) - else: - return repr(obj) # Don't know how to handle, convert to string - return serialize(obj) - +import jsonHelper class managementServer(): def __init__(self): self.mgtSvrIp = None @@ -199,7 +149,7 @@ def describe_setup_in_basic_mode(): p.name = "test" +str(l) + str(i) p.gateway = "192.168.%d.1"%i p.netmask = "255.255.255.0" - p.startip = "192.168.%d.200"%i + p.startip = "192.168.%d.150"%i p.endip = "192.168.%d.220"%i '''add two pod guest ip ranges''' @@ -399,10 +349,10 @@ def describe_setup_in_advanced_mode(): def generate_setup_config(config, file=None): describe = config if file is None: - return json.dumps(json_repr(describe)) + return json.dumps(jsonHelper.jsonDump.dump(describe)) else: fp = open(file, 'w') - json.dump(json_repr(describe), fp, indent=4) + json.dump(jsonHelper.jsonDump.dump(describe), fp, indent=4) fp.close() @@ -412,7 +362,7 @@ def get_setup_config(file): config = cloudstackConfiguration() fp = open(file, 'r') config = json.load(fp) - return Struct(config) + return jsonHelper.jsonLoader(config) if __name__ == "__main__": parser = OptionParser() diff --git a/tools/testClient/jsonHelper.py b/tools/testClient/jsonHelper.py new file mode 100644 index 00000000000..9c692159df9 --- /dev/null +++ b/tools/testClient/jsonHelper.py @@ -0,0 +1,169 @@ +import cloudstackException +import json +import inspect +from cloudstackAPI import * +class jsonLoader: + '''The recursive class for building and representing objects with.''' + def __init__(self, obj): + for k in obj: + v = obj[k] + if isinstance(v, dict): + setattr(self, k, jsonLoader(v)) + elif isinstance(v, (list, tuple)): + setattr(self, k, [jsonLoader(elem) for elem in v]) + else: + setattr(self,k,v) + def __getattr__(self, val): + if val in self.__dict__: + return self.__dict__[val] + else: + return None + def __repr__(self): + return '{%s}' % str(', '.join('%s : %s' % (k, repr(v)) for (k, v) in self.__dict__.iteritems())) + def __str__(self): + return '{%s}' % str(', '.join('%s : %s' % (k, repr(v)) for (k, v) in self.__dict__.iteritems())) + + +class jsonDump: + @staticmethod + def __serialize(obj): + """Recursively walk object's hierarchy.""" + if isinstance(obj, (bool, int, long, float, basestring)): + return obj + elif isinstance(obj, dict): + obj = obj.copy() + newobj = {} + for key in obj: + if obj[key] is not None: + if (isinstance(obj[key], list) and len(obj[key]) == 0): + continue + newobj[key] = jsonDump.__serialize(obj[key]) + + return newobj + elif isinstance(obj, list): + return [jsonDump.__serialize(item) for item in obj] + elif isinstance(obj, tuple): + return tuple(jsonDump.__serialize([item for item in obj])) + elif hasattr(obj, '__dict__'): + return jsonDump.__serialize(obj.__dict__) + else: + return repr(obj) # Don't know how to handle, convert to string + + @staticmethod + def dump(obj): + return jsonDump.__serialize(obj) + +def getclassFromName(cmd, name): + module = inspect.getmodule(cmd) + return getattr(module, name)() + +def finalizeResultObj(result, responseName, responsecls): + if responsecls is None and responseName.endswith("response") and responseName != "queryasyncjobresultresponse": + '''infer the response class from the name''' + moduleName = responseName.replace("response", "") + try: + responsecls = getclassFromName(moduleName, responseName) + except: + pass + + if responseName is not None and responseName == "queryasyncjobresultresponse" and responsecls is not None and result.jobresult is not None: + result.jobresult = finalizeResultObj(result.jobresult, None, responsecls) + return result + elif responsecls is not None: + for k,v in result.__dict__.iteritems(): + if k in responsecls.__dict__: + return result + + attr = result.__dict__.keys()[0] + + value = getattr(result, attr) + if not isinstance(value, jsonLoader): + return result + + findObj = False + for k,v in value.__dict__.iteritems(): + if k in responsecls.__dict__: + findObj = True + break + if findObj: + return value + else: + return result + else: + return result + + + +def getResultObj(returnObj, responsecls=None): + returnObj = json.loads(returnObj) + + if len(returnObj) == 0: + return None + responseName = returnObj.keys()[0] + + response = returnObj[responseName] + if len(response) == 0: + return None + + result = jsonLoader(response) + if result.errorcode is not None: + errMsg = "errorCode: %s, errorText:%s"%(result.errorcode, result.errortext) + raise cloudstackException.cloudstackAPIException(responseName.replace("response", ""), errMsg) + + if result.count is not None: + for key in result.__dict__.iterkeys(): + if key == "count": + continue + else: + return getattr(result, key) + else: + return finalizeResultObj(result, responseName, responsecls) + +if __name__ == "__main__": + + result = '{ "listzonesresponse" : { "count":1 ,"zone" : [ {"id":1,"name":"test0","dns1":"8.8.8.8","dns2":"4.4.4.4","internaldns1":"192.168.110.254","internaldns2":"192.168.110.253","networktype":"Basic","securitygroupsenabled":true,"allocationstate":"Enabled","zonetoken":"5e818a11-6b00-3429-9a07-e27511d3169a","dhcpprovider":"DhcpServer"} ] } }' + zones = getResultObj(result) + print zones[0].id + res = authorizeSecurityGroupIngress.authorizeSecurityGroupIngressResponse() + result = '{ "queryasyncjobresultresponse" : {"jobid":10,"jobstatus":1,"jobprocstatus":0,"jobresultcode":0,"jobresulttype":"object","jobresult":{"securitygroup":{"id":1,"name":"default","description":"Default Security Group","account":"admin","domainid":1,"domain":"ROOT","ingressrule":[{"ruleid":1,"protocol":"tcp","startport":22,"endport":22,"securitygroupname":"default","account":"a"},{"ruleid":2,"protocol":"tcp","startport":22,"endport":22,"securitygroupname":"default","account":"b"}]}}} }' + asynJob = getResultObj(result, res) + print asynJob.jobid, repr(asynJob.jobresult) + print asynJob.jobresult.ingressrule[0].account + + result = '{ "queryasyncjobresultresponse" : {"errorcode" : 431, "errortext" : "Unable to execute API command queryasyncjobresultresponse due to missing parameter jobid"} }' + try: + asynJob = getResultObj(result) + except cloudstackException.cloudstackAPIException, e: + print e + + result = '{ "queryasyncjobresultresponse" : {} }' + asynJob = getResultObj(result) + print asynJob + + result = '{}' + asynJob = getResultObj(result) + print asynJob + + result = '{ "createzoneresponse" : { "zone" : {"id":1,"name":"test0","dns1":"8.8.8.8","dns2":"4.4.4.4","internaldns1":"192.168.110.254","internaldns2":"192.168.110.253","networktype":"Basic","securitygroupsenabled":true,"allocationstate":"Enabled","zonetoken":"3442f287-e932-3111-960b-514d1f9c4610","dhcpprovider":"DhcpServer"} } }' + res = createZone.createZoneResponse() + zone = getResultObj(result, res) + print zone.id + + result = '{ "attachvolumeresponse" : {"jobid":24} }' + res = attachVolume.attachVolumeResponse() + res = getResultObj(result, res) + print res + + result = '{ "listtemplatesresponse" : { } }' + print getResultObj(result, listTemplates.listTemplatesResponse()) + + result = '{ "queryasyncjobresultresponse" : {"jobid":34,"jobstatus":2,"jobprocstatus":0,"jobresultcode":530,"jobresulttype":"object","jobresult":{"errorcode":431,"errortext":"Please provide either a volume id, or a tuple(device id, instance id)"}} }' + print getResultObj(result, listTemplates.listTemplatesResponse()) + result = '{ "queryasyncjobresultresponse" : {"jobid":41,"jobstatus":1,"jobprocstatus":0,"jobresultcode":0,"jobresulttype":"object","jobresult":{"virtualmachine":{"id":37,"name":"i-2-37-TEST","displayname":"i-2-37-TEST","account":"admin","domainid":1,"domain":"ROOT","created":"2011-08-25T11:13:42-0700","state":"Running","haenable":false,"zoneid":1,"zonename":"test0","hostid":5,"hostname":"SimulatedAgent.1e629060-f547-40dd-b792-57cdc4b7d611","templateid":10,"templatename":"CentOS 5.3(64-bit) no GUI (Simulator)","templatedisplaytext":"CentOS 5.3(64-bit) no GUI (Simulator)","passwordenabled":false,"serviceofferingid":7,"serviceofferingname":"Small Instance","cpunumber":1,"cpuspeed":500,"memory":512,"guestosid":11,"rootdeviceid":0,"rootdevicetype":"NetworkFilesystem","securitygroup":[{"id":1,"name":"default","description":"Default Security Group"}],"nic":[{"id":43,"networkid":204,"netmask":"255.255.255.0","gateway":"192.168.1.1","ipaddress":"192.168.1.27","isolationuri":"ec2://untagged","broadcasturi":"vlan://untagged","traffictype":"Guest","type":"Direct","isdefault":true,"macaddress":"06:56:b8:00:00:53"}],"hypervisor":"Simulator"}}} }' + vm = getResultObj(result, deployVirtualMachine.deployVirtualMachineResponse()) + print vm.jobresult.id + + cmd = deployVirtualMachine.deployVirtualMachineCmd() + responsename = cmd.__class__.__name__.replace("Cmd", "Response") + response = getclassFromName(cmd, responsename) + print response.id \ No newline at end of file diff --git a/tools/testClient/testcase/test_1.py b/tools/testClient/testcase/test_1.py index c1593c1c97b..bba55febc2e 100644 --- a/tools/testClient/testcase/test_1.py +++ b/tools/testClient/testcase/test_1.py @@ -10,7 +10,7 @@ class TestCase1(cloudstackTestCase): listtmcmd.templatefilter = "featured" listtmresponse = apiClient.listTemplates(listtmcmd) if listtmresponse is not None and len(listtmresponse) > 0: - self.debug(listtmresponse[0].isready) + self.debug(listtmresponse) self.debug("we are here") else: self.debug("we are there") diff --git a/tools/testClient/testcase/test_2.py b/tools/testClient/testcase/test_2.py index f9937b83e72..5a78dc3e2d7 100644 --- a/tools/testClient/testcase/test_2.py +++ b/tools/testClient/testcase/test_2.py @@ -7,5 +7,17 @@ class TestCase2(cloudstackTestCase): listtmcmd.id = 10 listtmcmd.zoneid = 1 listtmcmd.templatefilter = "featured" - listtmresponse = apiClient.listTemplates(listtmcmd) - self.debug(listtmresponse[0].isready) + #listtmresponse = apiClient.listTemplates(listtmcmd) + #self.debug(listtmresponse[0].isready) + + listhostcmd=listHosts.listHostsCmd() + listhostcmd.zoneid=1 + listhostcmd.type="Routing" + + asyncJobResult=self.testClient.submitCmdsAndWait([listhostcmd],1) + listVMresponse = asyncJobResult[0].result + self.debug("Total Number of Hosts: " + str(len(listVMresponse))) + + for i in listVMresponse: + self.debug("id: " + str(i.id) +" pod id: " + str(i.podid) +" host tag: " + str(i.hosttags)) + \ No newline at end of file diff --git a/tools/testClient/testcase/test_3.py b/tools/testClient/testcase/test_3.py index a41d9ecfad3..3f31e416ac3 100644 --- a/tools/testClient/testcase/test_3.py +++ b/tools/testClient/testcase/test_3.py @@ -21,11 +21,11 @@ class TestCase1(cloudstackTestCase): tmpls = self.testClient.getApiClient().listTemplates(listtmplcmd) if tmpls is not None: for tmpl in tmpls: - if tmpl.isready == "true": + if tmpl.isready: self.templateId = tmpl.id self.zoneId = tmpl.zoneid break - + def test_cloudstackapi(self): apiClient = self.testClient.getApiClient() @@ -52,14 +52,34 @@ class TestCase1(cloudstackTestCase): ''' cidrlist = ["192.168.1.1/24", "10.1.1.1/24"] securitygroup.cidrlist = cidrlist - apiClient.authorizeSecurityGroupIngress(securitygroup) - + try: + apiClient.authorizeSecurityGroupIngress(securitygroup) + except: + pass + ''' createvm = deployVirtualMachine.deployVirtualMachineCmd() createvm.serviceofferingid = self.svid createvm.templateid = self.templateId createvm.zoneid = self.zoneId vm = apiClient.deployVirtualMachine(createvm) vmId = vm.id + ''' + vmId = 1 + vmcmds = [] + for i in range(10): + createvm = deployVirtualMachine.deployVirtualMachineCmd() + createvm.serviceofferingid = self.svid + createvm.templateid = self.templateId + createvm.zoneid = self.zoneId + vmcmds.append(createvm) + + result = self.testClient.submitCmdsAndWait(vmcmds, 5) + for jobstatus in result: + if jobstatus.status == 1: + self.debug(jobstatus.result.id) + self.debug(jobstatus.result.displayname) + else: + self.debug(jobstatus.result) creatvolume = createVolume.createVolumeCmd() creatvolume.name = "tetst" + str(uuid.uuid4()) diff --git a/tools/testClient/unitTest/test_async.py b/tools/testClient/unitTest/test_async.py index acd5b6d75d7..19473ba74e9 100644 --- a/tools/testClient/unitTest/test_async.py +++ b/tools/testClient/unitTest/test_async.py @@ -49,7 +49,7 @@ if __name__ == "__main__": asyncJobResult = testclient.submitCmdsAndWait(cmds, 6) - for handle, jobStatus in asyncJobResult.iteritems(): + for jobStatus in asyncJobResult: if jobStatus.status: print jobStatus.result[0].id, jobStatus.result[0].templatename, jobStatus.startTime, jobStatus.endTime else: diff --git a/ui/css/main.css b/ui/css/main.css index fcec31c9150..52a18d45d27 100644 --- a/ui/css/main.css +++ b/ui/css/main.css @@ -74,7 +74,7 @@ a:hover { width:181px; height:66px; float:left; - background:url(../images/login_logo.gif) no-repeat top left; + background:url(../images/login_logo.png) no-repeat top left; margin:0 0 0 75px; display:inline; padding:0; @@ -1391,7 +1391,7 @@ a:hover { width:106px; height:37px; float:left; - background:url(../images/logo.gif) no-repeat top left; + background:url(../images/logo.png) no-repeat top left; margin:0 0 0 8px; display:inline; padding:0; @@ -3261,7 +3261,7 @@ a:hover.search_button { width:132px; height:22px; float:right; - background:url(../images/poweredby.gif) no-repeat top left; + /*background:url(../images/poweredby.gif) no-repeat top left;*/ margin:2px 10px 0 0; padding:0; display:inline; diff --git a/ui/images/login_logo.gif b/ui/images/login_logo.gif deleted file mode 100644 index 64d55a7c538..00000000000 Binary files a/ui/images/login_logo.gif and /dev/null differ diff --git a/ui/images/login_logo.png b/ui/images/login_logo.png new file mode 100644 index 00000000000..1189d1eb55c Binary files /dev/null and b/ui/images/login_logo.png differ diff --git a/ui/images/logo.gif b/ui/images/logo.gif deleted file mode 100644 index b399c7fa31a..00000000000 Binary files a/ui/images/logo.gif and /dev/null differ diff --git a/ui/images/logo.png b/ui/images/logo.png new file mode 100644 index 00000000000..5e8513fef72 Binary files /dev/null and b/ui/images/logo.png differ diff --git a/ui/jsp/host.jsp b/ui/jsp/host.jsp index 92183facb53..ce4dd10c886 100644 --- a/ui/jsp/host.jsp +++ b/ui/jsp/host.jsp @@ -7,6 +7,7 @@