diff --git a/api/src/com/cloud/api/commands/AddSwiftCmd.java b/api/src/com/cloud/api/commands/AddSwiftCmd.java index 06886838f86..4625d71d1a0 100644 --- a/api/src/com/cloud/api/commands/AddSwiftCmd.java +++ b/api/src/com/cloud/api/commands/AddSwiftCmd.java @@ -34,7 +34,7 @@ import com.cloud.user.Account; @Implementation(description = "Adds Swift.", responseObject = HostResponse.class) public class AddSwiftCmd extends BaseCmd { public static final Logger s_logger = Logger.getLogger(AddSwiftCmd.class.getName()); - private static final String s_name = "addSwiftresponse"; + private static final String s_name = "addswiftresponse"; ///////////////////////////////////////////////////// //////////////// API parameters ///////////////////// diff --git a/api/src/com/cloud/api/commands/ListSwiftCmd.java b/api/src/com/cloud/api/commands/ListSwiftsCmd.java similarity index 95% rename from api/src/com/cloud/api/commands/ListSwiftCmd.java rename to api/src/com/cloud/api/commands/ListSwiftsCmd.java index 9e8e6b3e141..42cde414e17 100644 --- a/api/src/com/cloud/api/commands/ListSwiftCmd.java +++ b/api/src/com/cloud/api/commands/ListSwiftsCmd.java @@ -35,9 +35,9 @@ import com.cloud.storage.Swift; import com.cloud.user.Account; @Implementation(description = "List Swift.", responseObject = HostResponse.class) -public class ListSwiftCmd extends BaseCmd { - public static final Logger s_logger = Logger.getLogger(ListSwiftCmd.class.getName()); - private static final String s_name = "ListSwiftresponse"; +public class ListSwiftsCmd extends BaseCmd { + public static final Logger s_logger = Logger.getLogger(ListSwiftsCmd.class.getName()); + private static final String s_name = "listswiftresponse"; ///////////////////////////////////////////////////// //////////////// API parameters ///////////////////// @@ -67,7 +67,7 @@ public class ListSwiftCmd extends BaseCmd { @Override public void execute(){ - List result = _resourceService.listSwift(this); + List result = _resourceService.listSwifts(this); ListResponse response = new ListResponse(); List swiftResponses = new ArrayList(); diff --git a/api/src/com/cloud/resource/ResourceService.java b/api/src/com/cloud/resource/ResourceService.java index 2235ebe5e3c..d8917ed7033 100755 --- a/api/src/com/cloud/resource/ResourceService.java +++ b/api/src/com/cloud/resource/ResourceService.java @@ -25,7 +25,7 @@ import com.cloud.api.commands.AddSecondaryStorageCmd; import com.cloud.api.commands.AddSwiftCmd; import com.cloud.api.commands.CancelMaintenanceCmd; import com.cloud.api.commands.DeleteClusterCmd; -import com.cloud.api.commands.ListSwiftCmd; +import com.cloud.api.commands.ListSwiftsCmd; import com.cloud.api.commands.PrepareForMaintenanceCmd; import com.cloud.api.commands.ReconnectHostCmd; import com.cloud.api.commands.UpdateHostCmd; @@ -94,5 +94,5 @@ public interface ResourceService { List getSupportedHypervisorTypes(long zoneId); - List listSwift(ListSwiftCmd cmd); + List listSwifts(ListSwiftsCmd cmd); } diff --git a/client/tomcatconf/commands.properties.in b/client/tomcatconf/commands.properties.in index bdf24a65f8b..5801bf6f851 100755 --- a/client/tomcatconf/commands.properties.in +++ b/client/tomcatconf/commands.properties.in @@ -181,7 +181,7 @@ listCapacity=com.cloud.api.commands.ListCapacityCmd;3 #### swift commands^M addSwift=com.cloud.api.commands.AddSwiftCmd;1 -listSwift=com.cloud.api.commands.ListSwiftCmd;1 +listSwifts=com.cloud.api.commands.ListSwiftsCmd;1 #### host commands diff --git a/cloud.spec b/cloud.spec index 210673adb92..f65f50d6c2f 100644 --- a/cloud.spec +++ b/cloud.spec @@ -24,10 +24,6 @@ BuildRoot: %{_tmppath}/%{name}-%{_ver}-%{release}-build BuildRequires: java-1.6.0-openjdk-devel BuildRequires: tomcat6 BuildRequires: ws-commons-util -#BuildRequires: commons-codec -#BuildRequires: commons-dbcp -#BuildRequires: commons-collections -BuildRequires: commons-httpclient BuildRequires: jpackage-utils BuildRequires: gcc BuildRequires: glibc-devel @@ -148,7 +144,6 @@ Requires: %{name}-python = %{version} # Requires: %{name}-agent Requires: tomcat6 Requires: ws-commons-util -#Requires: commons-codec Requires: jpackage-utils Requires: sudo Requires: /sbin/service @@ -165,12 +160,6 @@ Requires: apache-commons-collections Requires: jakarta-commons-httpclient %endif -%if 0%{?rhel} >= 5 -Requires: commons-dbcp -Requires: commons-collection -Requires: commons-httpclient -%endif - Group: System Environment/Libraries %description client The Cloud.com management server is the central point of coordination, @@ -272,11 +261,7 @@ Requires: java >= 1.6.0 Requires: %{name}-utils = %{version}, %{name}-core = %{version}, %{name}-deps = %{version}, %{name}-agent-libs = %{version} Requires: python Requires: %{name}-python = %{version} -Requires: commons-httpclient #Requires: commons-codec -Requires: commons-collections -Requires: commons-pool -Requires: commons-dbcp Requires: jakarta-commons-logging Requires: jpackage-utils Requires: %{name}-daemonize diff --git a/patches/systemvm/debian/config/etc/init.d/cloud-early-config b/patches/systemvm/debian/config/etc/init.d/cloud-early-config index 32a43dfa76c..580ab149c5e 100755 --- a/patches/systemvm/debian/config/etc/init.d/cloud-early-config +++ b/patches/systemvm/debian/config/etc/init.d/cloud-early-config @@ -418,6 +418,7 @@ setup_redundant_router() { cp /root/redundant_router/primary-backup.sh.templ $rrouter_bin_path/primary-backup.sh cp /root/redundant_router/heartbeat.sh.templ $rrouter_bin_path/heartbeat.sh cp /root/redundant_router/check_heartbeat.sh.templ $rrouter_bin_path/check_heartbeat.sh + cp /root/redundant_router/arping_gateways.sh.templ $rrouter_bin_path/arping_gateways.sh cp /root/redundant_router/check_bumpup.sh $rrouter_bin_path/ cp /root/redundant_router/disable_pubip.sh $rrouter_bin_path/ cp /root/redundant_router/checkrouter.sh.templ /root/checkrouter.sh @@ -446,6 +447,7 @@ setup_redundant_router() { sed -i "s/\[RROUTER_LOG\]/$rrouter_log_str/g" $rrouter_bin_path/fault.sh sed -i "s/\[RROUTER_LOG\]/$rrouter_log_str/g" $rrouter_bin_path/primary-backup.sh sed -i "s/\[RROUTER_LOG\]/$rrouter_log_str/g" $rrouter_bin_path/check_heartbeat.sh + sed -i "s/\[RROUTER_LOG\]/$rrouter_log_str/g" $rrouter_bin_path/arping_gateways.sh sed -i "s/\[RROUTER_LOG\]/$rrouter_log_str/g" /root/checkrouter.sh chmod a+x $rrouter_bin_path/*.sh diff --git a/patches/systemvm/debian/config/root/redundant_router/arping_gateways.sh.templ b/patches/systemvm/debian/config/root/redundant_router/arping_gateways.sh.templ new file mode 100644 index 00000000000..80f7f030dcb --- /dev/null +++ b/patches/systemvm/debian/config/root/redundant_router/arping_gateways.sh.templ @@ -0,0 +1,10 @@ +ip link|grep BROADCAST|grep -v eth0|grep -v eth1|cut -d ":" -f 2 > /tmp/iflist +while read i +do + ip addr show $i|grep "inet " > /tmp/iplist_$i + while read line + do + ip=`echo $line|cut -d " " -f 2|cut -d "/" -f 1` + arping -I $i -A $ip -c 2 >> [RROUTER_LOG] 2>&1 + done < /tmp/iplist_$i +done < /tmp/iflist diff --git a/patches/systemvm/debian/config/root/redundant_router/master.sh.templ b/patches/systemvm/debian/config/root/redundant_router/master.sh.templ index d935ea85b90..3c07f3ef860 100644 --- a/patches/systemvm/debian/config/root/redundant_router/master.sh.templ +++ b/patches/systemvm/debian/config/root/redundant_router/master.sh.templ @@ -31,9 +31,7 @@ if [ $ret -ne 0 ] then echo Fail to switch conntrackd mode, but try to continue working >> [RROUTER_LOG] fi -ping -n -c 3 [GATEWAY] >> [RROUTER_LOG] 2>&1 & -sleep 3 -pkill ping +[RROUTER_BIN_PATH]/arping_gateways.sh echo Status: MASTER >> [RROUTER_LOG] releaseLockFile $lock $locked diff --git a/scripts/vm/hypervisor/xenserver/vmops b/scripts/vm/hypervisor/xenserver/vmops index c0d2b6f91d1..44838ad2cbf 100755 --- a/scripts/vm/hypervisor/xenserver/vmops +++ b/scripts/vm/hypervisor/xenserver/vmops @@ -430,8 +430,6 @@ def default_ebtables_rules(): util.pread2(['ebtables', '-A', 'DEFAULT_EBTABLES', '-p', 'IPv6', '-j', 'DROP']) # deny vlan util.pread2(['ebtables', '-A', 'DEFAULT_EBTABLES', '-p', '802_1Q', '-j', 'DROP']) - # deny all other 802. frames - util.pread2(['ebtables', '-A', 'FORWARD', '-j', 'DROP']) except: util.SMlog('Chain DEFAULT_EBTABLES already exists') diff --git a/server/src/com/cloud/resource/ResourceManagerImpl.java b/server/src/com/cloud/resource/ResourceManagerImpl.java index 4db664e4b58..add6d645add 100755 --- a/server/src/com/cloud/resource/ResourceManagerImpl.java +++ b/server/src/com/cloud/resource/ResourceManagerImpl.java @@ -54,7 +54,7 @@ import com.cloud.api.commands.AddSecondaryStorageCmd; import com.cloud.api.commands.AddSwiftCmd; import com.cloud.api.commands.CancelMaintenanceCmd; import com.cloud.api.commands.DeleteClusterCmd; -import com.cloud.api.commands.ListSwiftCmd; +import com.cloud.api.commands.ListSwiftsCmd; import com.cloud.api.commands.PrepareForMaintenanceCmd; import com.cloud.api.commands.ReconnectHostCmd; import com.cloud.api.commands.UpdateHostCmd; @@ -518,8 +518,8 @@ public class ResourceManagerImpl implements ResourceManager, ResourceService, Ma } @Override - public List listSwift(ListSwiftCmd cmd) { - return _swiftMgr.listSwift(cmd); + public List listSwifts(ListSwiftsCmd cmd) { + return _swiftMgr.listSwifts(cmd); } private List discoverHostsFull(Long dcId, Long podId, Long clusterId, String clusterName, String url, String username, String password, String hypervisorType, List hostTags, diff --git a/server/src/com/cloud/storage/StorageManagerImpl.java b/server/src/com/cloud/storage/StorageManagerImpl.java index f1f837190dc..ca39232cc22 100755 --- a/server/src/com/cloud/storage/StorageManagerImpl.java +++ b/server/src/com/cloud/storage/StorageManagerImpl.java @@ -112,7 +112,6 @@ import com.cloud.host.Host; import com.cloud.host.HostVO; import com.cloud.host.Status; import com.cloud.host.dao.HostDao; -import com.cloud.host.dao.HostDetailsDao; import com.cloud.hypervisor.Hypervisor.HypervisorType; import com.cloud.hypervisor.HypervisorGuruManager; import com.cloud.network.NetworkManager; @@ -135,6 +134,7 @@ import com.cloud.storage.dao.StoragePoolWorkDao; import com.cloud.storage.dao.VMTemplateDao; import com.cloud.storage.dao.VMTemplateHostDao; import com.cloud.storage.dao.VMTemplatePoolDao; +import com.cloud.storage.dao.VMTemplateSwiftDao; import com.cloud.storage.dao.VolumeDao; import com.cloud.storage.listener.StoragePoolMonitor; import com.cloud.storage.secondary.SecondaryStorageVmManager; @@ -236,6 +236,8 @@ public class StorageManagerImpl implements StorageManager, StorageService, Manag @Inject protected VMTemplatePoolDao _vmTemplatePoolDao = null; @Inject + protected VMTemplateSwiftDao _vmTemplateSwiftDao = null; + @Inject protected VMTemplateDao _vmTemplateDao = null; @Inject protected StoragePoolHostDao _poolHostDao = null; @@ -2515,14 +2517,20 @@ public class StorageManagerImpl implements StorageManager, StorageService, Manag sc.setParameters("id", template.getId()); sc.setParameters("state", com.cloud.storage.VMTemplateStorageResourceAssoc.Status.DOWNLOADED); sc.setJoinParameters("host", "dcId", vm.getDataCenterIdToDeployIn()); - - List sss = _vmTemplateHostDao.search(sc, null); - if (sss.size() == 0) { - throw new CloudRuntimeException("Template " + template.getName() + " has not been completely downloaded to zone " + vm.getDataCenterIdToDeployIn()); + List tsvs = _vmTemplateSwiftDao.listByTemplateId(template.getId()); + Long size = null; + if (tsvs != null && tsvs.size() > 0) { + size = tsvs.get(0).getSize(); + } + if (size == null) { + List sss = _vmTemplateHostDao.search(sc, null); + if (sss == null || sss.size() == 0) { + throw new CloudRuntimeException("Template " + template.getName() + " has not been completely downloaded to zone " + vm.getDataCenterIdToDeployIn()); + } + size = sss.get(0).getSize(); } - VMTemplateHostVO ss = sss.get(0); - VolumeVO vol = new VolumeVO(type, name, vm.getDataCenterIdToDeployIn(), owner.getDomainId(), owner.getId(), offering.getId(), ss.getSize()); + VolumeVO vol = new VolumeVO(type, name, vm.getDataCenterIdToDeployIn(), owner.getDomainId(), owner.getId(), offering.getId(), size); if (vm != null) { vol.setInstanceId(vm.getId()); } diff --git a/server/src/com/cloud/storage/dao/VMTemplateZoneDao.java b/server/src/com/cloud/storage/dao/VMTemplateZoneDao.java index a064cbbc421..3b6b7b9bfa6 100755 --- a/server/src/com/cloud/storage/dao/VMTemplateZoneDao.java +++ b/server/src/com/cloud/storage/dao/VMTemplateZoneDao.java @@ -30,6 +30,6 @@ public interface VMTemplateZoneDao extends GenericDao { public VMTemplateZoneVO findByZoneTemplate(long zoneId, long templateId); - public List listByZoneTemplate(long zoneId, long templateId); + public List listByZoneTemplate(Long zoneId, long templateId); } diff --git a/server/src/com/cloud/storage/dao/VMTemplateZoneDaoImpl.java b/server/src/com/cloud/storage/dao/VMTemplateZoneDaoImpl.java index 9e1d323f0ea..b72975ca6a8 100644 --- a/server/src/com/cloud/storage/dao/VMTemplateZoneDaoImpl.java +++ b/server/src/com/cloud/storage/dao/VMTemplateZoneDaoImpl.java @@ -77,9 +77,11 @@ public class VMTemplateZoneDaoImpl extends GenericDaoBase listByZoneTemplate(long zoneId, long templateId) { - SearchCriteria sc = ZoneTemplateSearch.create(); - sc.setParameters("zone_id", zoneId); + public List listByZoneTemplate(Long zoneId, long templateId) { + SearchCriteria sc = ZoneTemplateSearch.create(); + if (zoneId != null) { + sc.setParameters("zone_id", zoneId); + } sc.setParameters("template_id", templateId); return listBy(sc); } diff --git a/server/src/com/cloud/storage/swift/SwiftManager.java b/server/src/com/cloud/storage/swift/SwiftManager.java index 8875f7469e9..de7797c59f8 100644 --- a/server/src/com/cloud/storage/swift/SwiftManager.java +++ b/server/src/com/cloud/storage/swift/SwiftManager.java @@ -30,7 +30,7 @@ import com.cloud.agent.api.to.SwiftTO; import com.cloud.api.commands.AddSwiftCmd; import com.cloud.api.commands.DeleteIsoCmd; import com.cloud.api.commands.DeleteTemplateCmd; -import com.cloud.api.commands.ListSwiftCmd; +import com.cloud.api.commands.ListSwiftsCmd; import com.cloud.exception.DiscoveryException; import com.cloud.storage.Swift; import com.cloud.storage.SwiftVO; @@ -57,5 +57,5 @@ public interface SwiftManager extends Manager { Long chooseZoneForTmpltExtract(Long tmpltId); - List listSwift(ListSwiftCmd cmd); -} \ No newline at end of file + List listSwifts(ListSwiftsCmd cmd); +} diff --git a/server/src/com/cloud/storage/swift/SwiftManagerImpl.java b/server/src/com/cloud/storage/swift/SwiftManagerImpl.java index 125e262bf6d..5a4782fc42f 100644 --- a/server/src/com/cloud/storage/swift/SwiftManagerImpl.java +++ b/server/src/com/cloud/storage/swift/SwiftManagerImpl.java @@ -42,7 +42,7 @@ import com.cloud.agent.api.to.SwiftTO; import com.cloud.api.commands.AddSwiftCmd; import com.cloud.api.commands.DeleteIsoCmd; import com.cloud.api.commands.DeleteTemplateCmd; -import com.cloud.api.commands.ListSwiftCmd; +import com.cloud.api.commands.ListSwiftsCmd; import com.cloud.configuration.Config; import com.cloud.configuration.dao.ConfigurationDao; import com.cloud.dc.DataCenterVO; @@ -266,7 +266,7 @@ public class SwiftManagerImpl implements SwiftManager { } @Override - public List listSwift(ListSwiftCmd cmd) { + public List listSwifts(ListSwiftsCmd cmd) { if (cmd.getId() == null) { return _swiftDao.listAll(); } else { diff --git a/server/src/com/cloud/template/TemplateManagerImpl.java b/server/src/com/cloud/template/TemplateManagerImpl.java index bd9cb3cebc6..bea8cc0c321 100755 --- a/server/src/com/cloud/template/TemplateManagerImpl.java +++ b/server/src/com/cloud/template/TemplateManagerImpl.java @@ -95,6 +95,7 @@ import com.cloud.storage.VMTemplateStorageResourceAssoc; import com.cloud.storage.VMTemplateStorageResourceAssoc.Status; import com.cloud.storage.VMTemplateSwiftVO; import com.cloud.storage.VMTemplateVO; +import com.cloud.storage.VMTemplateZoneVO; import com.cloud.storage.VolumeVO; import com.cloud.storage.dao.SnapshotDao; import com.cloud.storage.dao.StoragePoolDao; @@ -1160,6 +1161,14 @@ public class TemplateManagerImpl implements TemplateManager, Manager, TemplateSe boolean result = adapter.delete(profile); if (result){ + if (cmd.getZoneId() == null && _swiftMgr.isSwiftEnabled()) { + List templateZones = _tmpltZoneDao.listByZoneTemplate(null, templateId); + if (templateZones != null) { + for (VMTemplateZoneVO templateZone : templateZones) { + _tmpltZoneDao.remove(templateZone.getId()); + } + } + } return true; }else{ throw new CloudRuntimeException("Failed to delete template"); @@ -1191,10 +1200,18 @@ public class TemplateManagerImpl implements TemplateManager, Manager, TemplateSe } TemplateAdapter adapter = getAdapter(template.getHypervisorType()); TemplateProfile profile = adapter.prepareDelete(cmd); - boolean result = adapter.delete(profile); - if (result){ - return true; - }else{ + boolean result = adapter.delete(profile); + if (result) { + if (cmd.getZoneId() == null && _swiftMgr.isSwiftEnabled()) { + List templateZones = _tmpltZoneDao.listByZoneTemplate(null, templateId); + if (templateZones != null) { + for (VMTemplateZoneVO templateZone : templateZones) { + _tmpltZoneDao.remove(templateZone.getId()); + } + } + } + return true; + } else { throw new CloudRuntimeException("Failed to delete ISO"); } } diff --git a/setup/db/db/schema-2212to2213.sql b/setup/db/db/schema-2212to2213.sql index d0a8b0beb2d..58c6ed9c1af 100644 --- a/setup/db/db/schema-2212to2213.sql +++ b/setup/db/db/schema-2212to2213.sql @@ -61,6 +61,6 @@ update host_details set name='privateip' where host_id in (select id from host w INSERT IGNORE INTO configuration VALUES ('Advanced', 'DEFAULT', 'management-server', 'vmware.root.disk.controller', 'ide', 'Specify the default disk controller for root volumes, valid values are scsi, ide'); INSERT IGNORE INTO configuration VALUES ('Advanced', 'DEFAULT', 'management-server', 'vm.destory.forcestop', 'false', 'On destory, force-stop takes this value'); - INSERT IGNORE INTO configuration VALUES ('Network', 'DEFAULT', 'management-server', 'network.lock.timeout', '600', 'Lock wait timeout (seconds) while implementing network'); +INSERT IGNORE INTO configuration VALUES ('Network', 'DEFAULT', 'management-server', 'network.disable.rpfilter','true','disable rp_filter on Domain Router VM public interfaces.'); diff --git a/setup/db/db/schema-228to229.sql b/setup/db/db/schema-228to229.sql index 6cddc62a185..2540e231e99 100644 --- a/setup/db/db/schema-228to229.sql +++ b/setup/db/db/schema-228to229.sql @@ -53,7 +53,6 @@ INSERT IGNORE INTO configuration VALUES ('Network', 'DEFAULT', 'management-serve 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.'); -INSERT IGNORE INTO configuration VALUES ('Network', 'DEFAULT', 'management-server', 'network.disable.rpfilter','true','disable rp_filter on Domain Router VM public interfaces.'); INSERT IGNORE INTO configuration VALUES ('Advanced', 'DEFAULT', 'NetworkManager', 'use.external.dns', 'false', 'Bypass the cloudstack DHCP/DNS server vm name service, use zone external dns1 and dns2'); INSERT IGNORE INTO configuration VALUES ('Advanced', 'DEFAULT', 'management-server', 'network.loadbalancer.basiczone.elb.enabled', 'false', 'Whether the load balancing service is enabled for basic zones'); INSERT IGNORE INTO configuration VALUES ('Advanced', 'DEFAULT', 'management-server', 'network.loadbalancer.basiczone.elb.gc.interval.minutes', '120', 'Garbage collection interval to destroy unused ELB vms in minutes. Minimum of 5'); diff --git a/setup/db/db/schema-229to2210.sql b/setup/db/db/schema-229to2210.sql index 8e7aaec5445..045ce9e980c 100644 --- a/setup/db/db/schema-229to2210.sql +++ b/setup/db/db/schema-229to2210.sql @@ -35,7 +35,6 @@ INSERT IGNORE INTO configuration VALUES ('Network', 'DEFAULT', 'management-serve 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.'); -INSERT IGNORE INTO configuration VALUES ('Network', 'DEFAULT', 'management-server', 'network.disable.rpfilter','true','disable rp_filter on Domain Router VM public interfaces.'); INSERT IGNORE INTO configuration VALUES ('Advanced', 'DEFAULT', 'NetworkManager', 'use.external.dns', 'false', 'Bypass the cloudstack DHCP/DNS server vm name service, use zone external dns1 and dns2'); INSERT IGNORE INTO configuration VALUES ('Advanced', 'DEFAULT', 'management-server', 'network.loadbalancer.basiczone.elb.enabled', 'false', 'Whether the load balancing service is enabled for basic zones'); INSERT IGNORE INTO configuration VALUES ('Advanced', 'DEFAULT', 'management-server', 'network.loadbalancer.basiczone.elb.gc.interval.minutes', '120', 'Garbage collection interval to destroy unused ELB vms in minutes. Minimum of 5'); diff --git a/ui/css/cloudstack3.css b/ui/css/cloudstack3.css index 3a7450a4b5e..932692cb6a8 100644 --- a/ui/css/cloudstack3.css +++ b/ui/css/cloudstack3.css @@ -29,6 +29,14 @@ body { font-family: sans-serif; height: 769px !important; overflow: auto; + background: #FFFFFF; +} + +body.install-wizard { + font-family: sans-serif; + height: 769px !important; + overflow: auto; + background: #FFFFFF url(../images/bg-login.png); } #container { @@ -354,7 +362,7 @@ body.login { color: #4A4A4A; font-size: 15px; line-height: 23px; - background: url(../images/bg-transparent-white.png); + background: url(../images/bg-gradient-white-transparent.png) repeat-x -114px -270px; } .install-wizard .step ul li { @@ -383,15 +391,15 @@ body.login { .install-wizard .body { width: 1012px; - height: 626px; + height: 762px; margin: -352px auto auto; z-index: 10; - background: #FFFFFF -114px -141px; - /*+box-shadow:0px -7px 10px #C6C6C6;*/ - -moz-box-shadow: 0px -7px 10px #C6C6C6; - -webkit-box-shadow: 0px -7px 10px #C6C6C6; - -o-box-shadow: 0px -7px 10px #C6C6C6; - box-shadow: 0px -7px 10px #C6C6C6; + background: url(../images/bg-gradient-white-transparent.png) repeat-x -114px -141px; + /*+box-shadow:0px -3px 4px #CFCFCF;*/ + -moz-box-shadow: 0px -3px 4px #CFCFCF; + -webkit-box-shadow: 0px -3px 4px #CFCFCF; + -o-box-shadow: 0px -3px 4px #CFCFCF; + box-shadow: 0px -3px 4px #CFCFCF; } .install-wizard h2 { @@ -602,11 +610,11 @@ body.login { -webkit-text-shadow: 0px 1px 0px #FFFFFF; -o-text-shadow: 0px 1px 0px #FFFFFF; text-shadow: 0px 1px 0px #FFFFFF; - /*+box-shadow:inset 0px 1px 5px #FFFFFF;*/ - -moz-box-shadow: inset 0px 1px 5px #FFFFFF; - -webkit-box-shadow: inset 0px 1px 5px #FFFFFF; - -o-box-shadow: inset 0px 1px 5px #FFFFFF; - box-shadow: inset 0px 1px 5px #FFFFFF; + /*+box-shadow:0px 5px 9px #9F9F9F;*/ + -moz-box-shadow: 0px 5px 9px #9F9F9F; + -webkit-box-shadow: 0px 5px 9px #9F9F9F; + -o-box-shadow: 0px 5px 9px #9F9F9F; + box-shadow: 0px 5px 9px #9F9F9F; } .install-wizard .step .setup-form .title { @@ -2006,11 +2014,11 @@ div.toolbar div.text-search div.search-bar { z-index: 4; position: relative; border-right: 1px solid #8B8989; - /*+border-radius:3px 0 0 3px;*/ - -moz-border-radius: 3px 0 0 3px; - -webkit-border-radius: 3px 0 0 3px; - -khtml-border-radius: 3px 0 0 3px; - border-radius: 3px 0 0 3px; + /*+border-radius:4px 0 0 4px;*/ + -moz-border-radius: 4px 0 0 4px; + -webkit-border-radius: 4px 0 0 4px; + -khtml-border-radius: 4px 0 0 4px; + border-radius: 4px 0 0 4px; } div.toolbar div.text-search div.search-bar input { @@ -2261,7 +2269,15 @@ div.list-view div.toolbar div.section-switcher div.section-select { div.list-view div.toolbar div.section-switcher div.section-select select { width: 142px; + height: 21px; margin-right: 13px; + font-size: 12px; + border: 1px solid #808080; + /*+border-radius:4px;*/ + -moz-border-radius: 4px; + -webkit-border-radius: 4px; + -khtml-border-radius: 4px; + border-radius: 4px 4px 4px 4px; } div.list-view div.toolbar div.section-switcher div.section-select label { @@ -2306,6 +2322,7 @@ div.toolbar div.filters select { -khtml-border-radius: 4px; border-radius: 4px 4px 4px 4px; padding: 0px 0 0; + margin: 1px 0 0; } #breadcrumbs { @@ -4430,7 +4447,7 @@ label.error { float: left; display: block; clear: both; - margin: 0 0 0 58px; + margin: 12px 0 0 58px; /*+placement:shift 0px -6px;*/ position: relative; left: 0px; @@ -4446,6 +4463,10 @@ label.error { font-size: 11px; margin-right: 9px; margin-left: 2px; + /*+placement:shift;*/ + position: relative; + left: 0; + top: 0; } .multi-wizard.instance-wizard .select-iso .wizard-step-conditional.select-iso .content .select.selected { @@ -4468,6 +4489,12 @@ label.error { z-index: 10; } +.multi-wizard .select-iso .ui-tabs ul { + float: left; + left: 0px; + top: 1px; +} + .multi-wizard .ui-tabs ul li.first a { border-left: 1px solid #E2DDDD; } @@ -4910,6 +4937,10 @@ label.error { margin: 0 0 0 11px; } +.multi-wizard.instance-wizard .select-network .select.new-network label.error { + display: none !important; +} + .multi-wizard.instance-wizard .select-network .select.new-network .secondary-input { width: 97px; padding: 13px 0 17px; diff --git a/ui/images/bg-gradient-white-transparent.png b/ui/images/bg-gradient-white-transparent.png new file mode 100644 index 00000000000..96660125761 Binary files /dev/null and b/ui/images/bg-gradient-white-transparent.png differ diff --git a/ui/index.jsp b/ui/index.jsp index a88eed611ea..f31407e60d9 100644 --- a/ui/index.jsp +++ b/ui/index.jsp @@ -236,7 +236,7 @@
Name
- +
diff --git a/ui/scripts/cloudStack.js b/ui/scripts/cloudStack.js index 100973cac4f..465485e2c3b 100644 --- a/ui/scripts/cloudStack.js +++ b/ui/scripts/cloudStack.js @@ -23,9 +23,9 @@ storage: {}, network: {}, templates: {}, + events: {}, accounts: {}, domains: {}, - events: {}, system: {}, projects: {}, 'global-settings': {}, @@ -92,9 +92,9 @@ dataType: "json", async: false, success: function(json) { - /* g_supportELB: "guest" เฅ†เค†ˆ€” ips are allocated on guest network (so use 'forvirtualnetwork' = false) + /* g_supportELB: "guest" เฅ†เค††เฅ†เค…†ˆ€” ips are allocated on guest network (so use 'forvirtualnetwork' = false) * g_supportELB: "public" - ips are allocated on public network (so use 'forvirtualnetwork' = true) - * g_supportELB: "false" เฅ†เค†ˆ€“ no ELB support + * g_supportELB: "false" เฅ†เค††เฅ†เค…†ˆ€“ no ELB support */ g_capabilities = json.listcapabilitiesresponse.capability; g_supportELB = json.listcapabilitiesresponse.capability.supportELB.toString(); //convert boolean to string if it's boolean diff --git a/ui/scripts/configuration.js b/ui/scripts/configuration.js index 354ccef682c..8d3f8776494 100644 --- a/ui/scripts/configuration.js +++ b/ui/scripts/configuration.js @@ -969,18 +969,24 @@ action: function(args) { var formData = args.data; var inputData = {}; - var services = {}; + var serviceProviderMap = {}; + var serviceCapabilityMap = {}; $.each(formData, function(key, value) { var serviceData = key.split('.'); - if (serviceData.length > 1) { + if (serviceData.length > 1) { if (serviceData[0] == 'service' && serviceData[2] == 'isEnabled' && value == 'on') { // Services field - services[serviceData[1]] = formData[ + serviceProviderMap[serviceData[1]] = formData[ 'service.' + serviceData[1] + '.provider' ]; + } + else if (serviceData[0] == 'service' && + serviceData[2].indexOf('Capability') != -1 && + value == 'on') { // Services field + serviceCapabilityMap[serviceData[1]] = serviceData[2]; } } else if (value != '') { // Normal data inputData[key] = value; @@ -988,7 +994,7 @@ }); // Make supported services list - inputData['supportedServices'] = $.map(services, function(value, key) { + inputData['supportedServices'] = $.map(serviceProviderMap, function(value, key) { return key; }).join(','); @@ -1000,12 +1006,25 @@ // Make service provider map var serviceProviderIndex = 0; - $.each(services, function(key, value) { + $.each(serviceProviderMap, function(key, value) { inputData['serviceProviderList[' + serviceProviderIndex + '].service'] = key; inputData['serviceProviderList[' + serviceProviderIndex + '].provider'] = value; serviceProviderIndex++; }); - + + var serviceCapabilityIndex = 0; + $.each(serviceCapabilityMap, function(key, value) { + var capabilityType = null; + if(value == "redundantRouterCapability") + capabilityType = "RedundantRouter"; + if(capabilityType != null) { + inputData['serviceCapabilityList[' + serviceCapabilityIndex + '].service'] = key; + inputData['serviceCapabilityList[' + serviceCapabilityIndex + '].capabilitytype'] = capabilityType; + inputData['serviceCapabilityList[' + serviceCapabilityIndex + '].capabilityvalue'] = true; + serviceCapabilityIndex++; + } + }); + $.ajax({ url: createURL('createNetworkOffering'), data: inputData, @@ -1153,6 +1172,11 @@ }); } }, + + "service.SourceNat.redundantRouterCapability" : { + label: "Redundant router capability", + isBoolean: true + }, tags: { label: 'Tags' } } diff --git a/ui/scripts/instances.js b/ui/scripts/instances.js index 776c77d6f4a..3bf0f01dc34 100644 --- a/ui/scripts/instances.js +++ b/ui/scripts/instances.js @@ -392,7 +392,7 @@ error: function(XMLHttpResponse) { isCreateNetworkSuccessful = false; var errorMsg = "Failed to create new network, unable to proceed to deploy VM. Error: " + parseXMLHttpResponse(XMLHttpResponse); - alert(errorMsg); + //alert(errorMsg); args.response.error(errorMsg); //args.response.error(errorMsg) here doesn't show errorMsg. Waiting for Brian to fix it. use alert(errorMsg) to show errorMsg for now. } }); @@ -460,8 +460,7 @@ ); }, error: function(XMLHttpResponse) { - //args.response.error(); //wait for Brian to implement - alert("Failed to deploy VM."); + args.response.error(parseXMLHttpResponse(XMLHttpResponse)); //wait for Brian to implement } }); } @@ -1648,7 +1647,6 @@ allowedActions.push("detachISO"); allowedActions.push("resetPassword"); - allowedActions.push("changeService"); if(jsonObj.hypervisor == "BareMetal") { allowedActions.push("createTemplate"); diff --git a/ui/scripts/network.js b/ui/scripts/network.js index 1b9d5cf78b3..bd7d476ac49 100644 --- a/ui/scripts/network.js +++ b/ui/scripts/network.js @@ -530,8 +530,8 @@ }); }, - error: function(data) { - args.response.error(parseXMLHttpResponse(data)); + error: function(json) { + args.response.error(parseXMLHttpResponse(json)); } }); }, diff --git a/ui/scripts/projects.js b/ui/scripts/projects.js index 2df71a753b4..8c5650d88f1 100644 --- a/ui/scripts/projects.js +++ b/ui/scripts/projects.js @@ -18,13 +18,13 @@ success: function(json) { updatedResources++; if (updatedResources == totalResources) { - args.response.success(); + args.response.success(); } } }); }); }, - + dataProvider: function(args) { $.ajax({ url: createURL('listResourceLimits'), @@ -70,7 +70,7 @@ }); } }); - + } }, @@ -80,9 +80,9 @@ $.ajax({ url: createURL('listVirtualMachines'), success: function(json) { - var instances = json.listvirtualmachinesresponse.virtualmachine ? + var instances = json.listvirtualmachinesresponse.virtualmachine ? json.listvirtualmachinesresponse.virtualmachine : []; - + dataFns.storage($.extend(data, { runningInstances: $.grep(instances, function(instance) { return instance.state == 'Running'; @@ -124,7 +124,7 @@ id: network.networkofferingid }, success: function(json) { - totalBandwidth += + totalBandwidth += json.listnetworkofferingsresponse.networkoffering[0].networkrate; } }); @@ -142,7 +142,7 @@ url: createURL('listPublicIpAddresses'), success: function(json) { dataFns.loadBalancingRules($.extend(data, { - totalIPAddresses: json.listpublicipaddressesresponse ? + totalIPAddresses: json.listpublicipaddressesresponse.count ? json.listpublicipaddressesresponse.count : 0 })); } @@ -154,7 +154,7 @@ url: createURL('listLoadBalancerRules'), success: function(json) { dataFns.portForwardingRules($.extend(data, { - totalLoadBalancers: json.listloadbalancerrulesresponse ? + totalLoadBalancers: json.listloadbalancerrulesresponse.count ? json.listloadbalancerrulesresponse.count : 0 })); } @@ -166,7 +166,7 @@ url: createURL('listPortForwardingRules'), success: function(json) { dataFns.users($.extend(data, { - totalPortForwards: json.listportforwardingrulesresponse ? + totalPortForwards: json.listportforwardingrulesresponse.count ? json.listportforwardingrulesresponse.count : 0 })); } @@ -193,13 +193,19 @@ events: function(data) { $.ajax({ url: createURL('listEvents', { ignoreProject: true }), + data: { + page: 1, + pageSize: 8 + }, success: function(json) { var events = json.listeventsresponse.event; complete($.extend(data, { events: $.map(events, function(event) { return { - date: event.created.substr(5, 2) + '/' + event.created.substr(8, 2) + '/' + event.created.substr(2, 2), + date: event.created.substr(5, 2) + + '/' + event.created.substr(8, 2) + + '/' + event.created.substr(2, 2), desc: event.description }; }) @@ -381,7 +387,7 @@ actionPreFilter: function(args) { if (!cloudStack.context.projects && args.context.multiRule[0].role != 'Admin') { // This is for the new project wizard - return ['destroy']; + return ['destroy']; } if (args.context.multiRule[0].role != 'Admin') { @@ -489,10 +495,10 @@ data.listprojectsresponse.project ? data.listprojectsresponse.project : [], function(elem) { - return $.extend(elem, { - displayText: elem.displaytext - }); - }) + return $.extend(elem, { + displayText: elem.displaytext + }); + }) }); } }); @@ -812,14 +818,14 @@ var projectsActionFilter = function(args) { var allowedActions = ['destroy']; - + if (args.context.item.account == cloudStack.context.users[0].account || args.context.users[0].role == '1') { if (args.context.item.state == 'Suspended') { allowedActions.push('enable'); } else if (args.context.item.state == 'Active') { allowedActions.push('disable'); } - + return allowedActions; } diff --git a/ui/scripts/storage.js b/ui/scripts/storage.js index 68cf55e0dcb..4d852c2866b 100644 --- a/ui/scripts/storage.js +++ b/ui/scripts/storage.js @@ -142,6 +142,9 @@ } } ); + }, + error: function(json) { + args.response.error(parseXMLHttpResponse(json)); } }); }, diff --git a/ui/scripts/system.js b/ui/scripts/system.js index 28270773421..716ed36fafa 100644 --- a/ui/scripts/system.js +++ b/ui/scripts/system.js @@ -4322,6 +4322,10 @@ {jobId: jid} } ); + }, + + error: function(json) { + args.response.error(parseXMLHttpResponse(json)); } }); }, diff --git a/ui/scripts/templates.js b/ui/scripts/templates.js index 3d2bfc091fc..a3e4ef23d29 100644 --- a/ui/scripts/templates.js +++ b/ui/scripts/templates.js @@ -1,4 +1,4 @@ -(function(cloudStack, testData) { +(function(cloudStack, $, testData) { cloudStack.sections.templates = { title: 'Templates', @@ -290,18 +290,13 @@ copyTemplate: { label: 'Copy template', + addRow: 'false', messages: { confirm: function(args) { return 'Are you sure you want to copy template?'; }, - success: function(args) { - return 'Template is being copied.'; - }, notification: function(args) { return 'Copying template'; - }, - complete: function(args) { - return 'Template has been copied.'; } }, createForm: { @@ -310,6 +305,7 @@ fields: { destinationZoneId: { label: 'Destination zone', + validation: { required: true }, select: function(args) { $.ajax({ url: createURL("listZones&available=true"), @@ -317,12 +313,21 @@ async: true, success: function(json) { args.response.success({ - data: $.map(json.listzonesresponse.zone, function(zone) { - return { - id: zone.id, - description: zone.name - }; - }) + data: $.map( + $.grep( + json.listzonesresponse.zone ? json.listzonesresponse.zone : [], + + function(zone) { + return zone.id != args.context.templates[0].zoneid; + } + ), + function(zone) { + return { + id: zone.id, + description: zone.name + }; + } + ) }); } }); @@ -562,6 +567,7 @@ fields: { destinationZoneId: { label: 'Destination zone', + validation: { required: true }, select: function(args) { $.ajax({ url: createURL("listZones&available=true"), @@ -804,13 +810,23 @@ } ], - dataProvider: function(args) { - args.response.success( - { - actionFilter: templateActionfilter, - data:args.context.templates[0] - } - ); + dataProvider: function(args) { + var jsonObj = args.context.templates[0]; + var apiCmd = "listTemplates&templatefilter=self&id=" + jsonObj.id; + if(jsonObj.zoneid != null) + apiCmd = apiCmd + "&zoneid=" + jsonObj.zoneid; + + $.ajax({ + url: createURL(apiCmd), + dataType: "json", + success: function(json) { + args.response.success({ + actionFilter: templateActionfilter, + data: json.listtemplatesresponse.template[0] + }); + } + }); + } } } @@ -995,19 +1011,14 @@ confirm: function(args) { return 'Are you sure you want to copy ISO?'; }, - success: function(args) { - return 'ISO is being copied.'; - }, notification: function(args) { return 'Copying ISO'; - }, - complete: function(args) { - return 'ISO has been copied.'; } }, createForm: { title: 'Copy ISO', desc: '', + addRow: 'false', fields: { destinationZoneId: { label: 'Destination zone', @@ -1493,12 +1504,22 @@ ], dataProvider: function(args) { - args.response.success( - { - actionFilter: isoActionfilter, - data:args.context.isos[0] - } - ); + var jsonObj = args.context.isos[0]; + var apiCmd = "listIsos&isofilter=self&id="+jsonObj.id; + if(jsonObj.zoneid != null) + apiCmd = apiCmd + "&zoneid="+jsonObj.zoneid; + + $.ajax({ + url: createURL(apiCmd), + dataType: "json", + success: function(json) { + args.response.success({ + actionFilter: isoActionfilter, + data: json.listisosresponse.iso[0] + }); + } + }); + } } } @@ -1609,4 +1630,4 @@ return allowedActions; } -})(cloudStack, testData); +})(cloudStack, jQuery, testData); diff --git a/ui/scripts/ui-custom/installWizard.js b/ui/scripts/ui-custom/installWizard.js index 3abe57fba71..db467ae50da 100644 --- a/ui/scripts/ui-custom/installWizard.js +++ b/ui/scripts/ui-custom/installWizard.js @@ -13,6 +13,7 @@ */ var complete = function() { $installWizard.remove(); + $('html body').removeClass('install-wizard'); args.complete(); }; @@ -379,7 +380,7 @@ tooltipID: 'addZone', diagram: '.part.zone', prevStepID: 'addZoneIntro', - nextStepID: 'addPod', + nextStepID: 'addPodIntro', form: { name: { label: 'Name', validation: { required: true } }, dns1: { label: 'DNS 1', validation: { required: true } }, @@ -430,7 +431,7 @@ id: 'add-guest-network', stateID: 'guestNetwork', tooltipID: 'addGuestNetwork', - diagram: '.part.zone', + diagram: '.part.zone, .part.pod', prevStepID: 'addPod', nextStepID: 'addClusterIntro', form: { @@ -734,6 +735,7 @@ var initialStep = steps.intro().addClass('step'); showDiagram(''); + $('html body').addClass('install-wizard'); $installWizard.append( elems.header(), diff --git a/ui/scripts/ui-custom/instanceWizard.js b/ui/scripts/ui-custom/instanceWizard.js index c5c6491a8be..461a074ffca 100644 --- a/ui/scripts/ui-custom/instanceWizard.js +++ b/ui/scripts/ui-custom/instanceWizard.js @@ -583,7 +583,11 @@ // Next button if ($target.closest('div.button.next').size()) { - if (!$form.valid()) return false; + if (!$form.valid()) { + if ($form.find('input.error:visible, select.error:visible').size()) { + return false; + } + } showStep($steps.filter(':visible').index() + 2); diff --git a/ui/scripts/ui-custom/projects.js b/ui/scripts/ui-custom/projects.js index 72afa1685f6..3905a547ce6 100644 --- a/ui/scripts/ui-custom/projects.js +++ b/ui/scripts/ui-custom/projects.js @@ -4,7 +4,7 @@ * User management multi-edit */ userManagement: function(args) { - var multiEdit = !args.useInvites ? + var multiEdit = !args.useInvites ? cloudStack.projects.addUserForm : cloudStack.projects.inviteForm; @@ -62,7 +62,7 @@ } else { $item.hide().html(value).fadeIn(); } - }); + }); } }); } @@ -85,8 +85,10 @@ }; // Only show management tabs to owner of project - if (cloudStack.context.projects && - (cloudStack.context.projects[0].account == cloudStack.context.users[0].account)) { + if (isAdmin() || ( + cloudStack.context.projects && + (cloudStack.context.projects[0].account == cloudStack.context.users[0].account) + )) { tabs.users = function() { return $('
').addClass('management').data('tab-title', 'Users'); }; @@ -94,14 +96,14 @@ if (g_capabilities.projectinviterequired) { tabs.invitations = function() { return $('
').addClass('management-invite').data('tab-title', 'Invitations'); - }; + }; } tabs.resources = function() { var $resources = $('
').addClass('resources').data('tab-title', 'Resources'); var $form = $('
'); var $submit = $('').attr({ - type: 'submit' + type: 'submit' }).val('Apply'); cloudStack.projects.resourceManagement.dataProvider({ @@ -118,7 +120,7 @@ name: resource.type, value: resource.value }).addClass('required'); - + $field.append($label, $input); $field.appendTo($form); }); @@ -147,7 +149,7 @@ } } }); - + return false; }); @@ -156,7 +158,7 @@ } } }); - + return $resources; }; } @@ -167,14 +169,15 @@ // Make UI tabs $.each(tabs, function(tabName, tab) { var $tab = $('
  • ').appendTo($tabs.find('ul:first')); + var $tabContent = tab(); var $tabLink = $('') .attr({ href: '#project-view-dashboard-' + tabName }) - .html(tab().data('tab-title')) + .html($tabContent.data('tab-title')) .appendTo($tab); var $content = $('
    ') .appendTo($tabs) .attr({ id: 'project-view-dashboard-' + tabName }) - .append(tab); + .append($tabContent); }); $tabs.find('ul li:first').addClass('first'); @@ -252,7 +255,7 @@ var project = args.data; $(window).trigger('cloudStack.fullRefresh'); - + $loading.remove(); // Confirmation @@ -346,7 +349,7 @@ var $instanceRow = args.$instanceRow; $instanceRow.animate({ opacity: 0.5 }); - + cloudStack.projects.addUserForm.actions.destroy.action({ context: $.extend(true, {}, cloudStack.context, { projects: [project], @@ -388,9 +391,16 @@ $('.ui-dialog, .overlay').remove(); }); + $laterButton.click(function() { + $(':ui-dialog, .overlay').remove(); + + return false; + }); + return $review; }); }); + $laterButton.html('Close').appendTo($userManagement); return $userManagement; }); diff --git a/ui/scripts/ui/core.js b/ui/scripts/ui/core.js index f9be4e10ca9..ba3efa2c7e5 100644 --- a/ui/scripts/ui/core.js +++ b/ui/scripts/ui/core.js @@ -123,6 +123,18 @@ var $target = $(event.target); var $projectSwitcher = $(this); var $container = $('html body'); + var $navDisabled = $( + $.map([ + 'projects', + 'accounts', + 'domains', + 'system', + 'global-settings', + 'configuration' + ], function(id) { + return '#navigation li.' + id; + }).join(',') + ); if ($target.closest('.select.project-view').size()) { $('#cloudStack3-container').addClass('project-view'); @@ -131,14 +143,12 @@ .siblings().removeClass('active'); // Activate project view - $('#navigation li.projects').addClass('disabled').attr({ - title: 'Projects can only be edited outside of project view.' - }); + $navDisabled.hide(); cloudStack.uiCustom.projects({ $projectSelect: $projectSelect.hide().find('select') }); } else { - $('#navigation li.projects').removeClass('disabled').attr('title', ''); + $navDisabled.show(); $('#cloudStack3-container').removeClass('project-view'); $projectSwitcher.removeClass('alt'); $projectSelect.hide(); diff --git a/ui/scripts/ui/dialog.js b/ui/scripts/ui/dialog.js index 0c1c1313037..9f32f732480 100644 --- a/ui/scripts/ui/dialog.js +++ b/ui/scripts/ui/dialog.js @@ -259,8 +259,7 @@ var getFormValues = function() { var formValues = {}; - $.each(args.form.fields, function(key) { - }); + $.each(args.form.fields, function(key) {}); }; // Setup form validation @@ -277,7 +276,7 @@ if (!$formContainer.find('form').valid()) { // Ignore hidden field validation - if ($formContainer.find('input.error:visible').size()) { + if ($formContainer.find('input.error:visible, select.error:visible').size()) { return false; } } diff --git a/ui/scripts/ui/events.js b/ui/scripts/ui/events.js index 69f85a13ddb..71e9578841f 100644 --- a/ui/scripts/ui/events.js +++ b/ui/scripts/ui/events.js @@ -1,39 +1,44 @@ (function($, cloudStack) { - var event = cloudStack.ui.event = {}; - - // Attach element to a specific event type - event.elem = function(widget, elem, $elem, extraData) { - // Setup DOM metadata - var data = { cloudStack: {} }; - data.cloudStack[widget] = { - elem: elem - }; - if (extraData) $.extend(data.cloudStack[widget], extraData); + cloudStack.ui.event = { + // Attach element to specific event type + elem: function(widget, elem, $elem, extraData) { + // Setup DOM metadata + var data = { cloudStack: {} }; + data.cloudStack[widget] = { + elem: elem + }; + if (extraData) $.extend(data.cloudStack[widget], extraData); - return $elem - .addClass('cloudStack-elem') - .addClass(widget) - .data(data); - }; + return $elem + .addClass('cloudStack-elem') + .addClass(widget) + .data(data); + }, - // Create widget-based event - event.bind = function(widget, events) { - return function(event) { - var $target = $(event.target); - var $widget, $elem; - var data, elem; + // Create widget-based event + bind: function(widget, events) { + return function(event) { + var $target = $(event.target); + var $widget, $elem; + var data, elem; - $elem = $target.closest('.cloudStack-elem.' + widget); - if (!$elem.size()) - return true; + $elem = $target.closest('.cloudStack-elem.' + widget); + if (!$elem.size()) + return true; - $widget = $('.cloudStack-widget.' + widget); - data = $elem.data('cloudStack')[widget]; - elem = data.elem; + $widget = $('.cloudStack-widget.' + widget); + data = $elem.data('cloudStack')[widget]; + elem = data.elem; - events[elem]($elem, $widget, data); + events[elem]($elem, $widget, data); - return false; - }; + return false; + }; + }, + + // Trigger CloudStack UI event (cloudStack.*) + call: function(eventName, data) { + $(window).trigger('cloudStack.' + eventName, data); + } }; })(jQuery, cloudStack); diff --git a/ui/scripts/ui/widgets/detailView.js b/ui/scripts/ui/widgets/detailView.js index 3aebd5b146c..312d6fecd17 100644 --- a/ui/scripts/ui/widgets/detailView.js +++ b/ui/scripts/ui/widgets/detailView.js @@ -1,53 +1,4 @@ (function($, cloudStack) { - /** - * Add 'pending' notification - */ - var addNotification = function(notification, success, successArgs, error, errorArgs) { - if (!notification) { - success(successArgs); - - return false; - }; - - var $notifications = $('div.notifications'); - - if (!notification.poll) { - $notifications.notifications('add', { - section: notification.section, - desc: notification.desc, - interval: 0, - poll: function(args) { success(successArgs); args.complete(); } - }); - } else { - $notifications.notifications('add', { - section: notification.section, - desc: notification.desc, - interval: 2000, - _custom: notification._custom, - poll: function(args) { - var complete = args.complete; - var notificationError = args.error; - - notification.poll({ - _custom: args._custom, - complete: function(args) { - success($.extend(successArgs, args)); - complete(args); - }, - error: function(args) { - error($.extend(errorArgs, args)); - notificationError(args); - - return cloudStack.dialog.error; - } - }); - } - }); - } - - return true; - }; - var replaceListViewItem = function($detailView, newData) { var $row = $detailView.data('list-view-row'); @@ -141,7 +92,7 @@ notification.desc = messages.notification(args.messageArgs); notification._custom = args._custom; - addNotification( + cloudStack.ui.notifications.add( notification, // Success @@ -158,7 +109,9 @@ {}, // Error - function(args) {} + function(args) { + $loading.remove(); + } ); } }); @@ -181,7 +134,7 @@ if (additional && additional.success) additional.success(args); // Setup notification - addNotification( + cloudStack.ui.notifications.add( notification, function(args) { if ($detailView.is(':visible')) { @@ -208,13 +161,12 @@ // Error function(args) { - + $loading.remove(); } ); }, error: function(args) { - // if (args.message) - // cloudStack.dialog.notice({ message: args.message }); + $loading.remove(); } } }); @@ -368,13 +320,13 @@ if (!action.notification) { convertInputs($inputs); - addNotification( + cloudStack.ui.notifications.add( notificationArgs, function() {}, [] ); replaceListViewItem($detailView, data); } else { $loading.appendTo($detailView); - addNotification( + cloudStack.ui.notifications.add( $.extend(true, {}, action.notification, notificationArgs), function(args) { replaceListViewItem($detailView, data); diff --git a/ui/scripts/ui/widgets/listView.js b/ui/scripts/ui/widgets/listView.js index c1f27ae2ed0..b5c029f3a3f 100644 --- a/ui/scripts/ui/widgets/listView.js +++ b/ui/scripts/ui/widgets/listView.js @@ -2,53 +2,6 @@ * Create dynamic list view based on data callbacks */ (function($, cloudStack) { - /** - * Add 'pending' notification - */ - var addNotification = function(notification, success, successArgs, error, errorArgs) { - if (!notification) { - success(successArgs); - - return false; - }; - - var $notifications = $('div.notifications'); - - if (!notification.poll) { - $notifications.notifications('add', { - section: notification.section, - desc: notification.desc, - interval: 0, - poll: function(args) { success(successArgs); args.complete(); } - }); - } else { - $notifications.notifications('add', { - section: notification.section, - desc: notification.desc, - interval: 5000, - _custom: notification._custom, - poll: function(args) { - var complete = args.complete; - var notificationError = args.error; - - notification.poll({ - _custom: args._custom, - complete: function(args) { - success($.extend(successArgs, args)); - complete(args); - }, - error: function(args) { - error($.extend(errorArgs, args)); - notificationError(args); - } - }); - } - }); - } - - return true; - }; - var uiActions = { standard: function($instanceRow, args, additional) { var listViewArgs = $instanceRow.closest('div.list-view').data('view-args'); @@ -110,7 +63,7 @@ notification.desc = messages.notification(args.messageArgs); notification._custom = args._custom; - addNotification( + cloudStack.ui.notifications.add( notification, function(args) { if ($item.is(':visible')) { @@ -174,7 +127,7 @@ if (additional && additional.success) additional.success(args); - addNotification( + cloudStack.ui.notifications.add( notification, // Success @@ -233,8 +186,8 @@ ); }, error: function(message) { - if ($.isPlainObject(args.action.createForm) - && args.action.addRow != 'false') { + if (($.isPlainObject(args.action.createForm) && args.action.addRow != 'false') || + (!args.action.createForm && args.action.addRow == 'true')) { $instanceRow.remove(); } @@ -428,15 +381,14 @@ var newName = $editInput.val(); showLabel(newName, { success: function() { - addNotification( + cloudStack.ui.notifications.add( { section: $instanceRow.closest('div.view').data('view-args').id, - desc: newName ? 'Set value of ' + $instanceRow.find('td.name span').html() + ' to ' + newName : + desc: newName ? + 'Set value of ' + $instanceRow.find('td.name span').html() + ' to ' + newName : 'Unset value for ' + $instanceRow.find('td.name span').html() }, - function(args) { - - }, + function(args) {}, [{ name: newName }] ); } diff --git a/ui/scripts/ui/widgets/notifications.js b/ui/scripts/ui/widgets/notifications.js index 08b5dc48aba..45761abf76f 100644 --- a/ui/scripts/ui/widgets/notifications.js +++ b/ui/scripts/ui/widgets/notifications.js @@ -213,6 +213,10 @@ } }; + /** + * Define notification widget -- this is basically represented in a + * notifications icon, that contains a pop-up list of notifications + */ $.fn.notifications = function(method, args) { var $attachTo = this; var $total = $attachTo.find('div.total span'); @@ -230,7 +234,60 @@ return this; }; - // Events + /** + * Notifications UI helpers + */ + cloudStack.ui.notifications = { + add: function(notification, success, successArgs, error, errorArgs) { + if (!notification) { + success(successArgs); + + return false; + }; + + var $notifications = $('div.notifications'); + + if (!notification.poll) { + cloudStack.ui.event.call('addNotification', { + section: notification.section, + desc: notification.desc, + interval: 0, + poll: function(args) { success(successArgs); args.complete(); } + }); + } else { + cloudStack.ui.event.call('addNotification', { + section: notification.section, + desc: notification.desc, + interval: 5000, + _custom: notification._custom, + poll: function(args) { + var complete = args.complete; + var notificationError = args.error; + + notification.poll({ + _custom: args._custom, + complete: function(args) { + success($.extend(successArgs, args)); + complete(args); + }, + error: function(args) { + error($.extend(errorArgs, args)); + notificationError(args); + } + }); + } + }); + } + + return true; + } + }; + + // Setup notification listener -- accepts same args as + $(window).bind('cloudStack.addNotification', function(event, data) { + $('.notifications').notifications('add', data); + }); + $(document).click(function(event) { var $target = $(event.target); var $attachTo, $popup;