From e5449e29c9bdc03c93fe8eb361f32878c9a1b980 Mon Sep 17 00:00:00 2001 From: Marcus Sorensen Date: Wed, 5 Mar 2014 12:24:04 -0700 Subject: [PATCH 01/70] CLOUDSTACK-6203: KVM Migration fixes. Moved migration to a thread so we can monitor it and potentially take action to make migration complete if admin has defined such. --- agent/conf/agent.properties | 11 +++ .../resource/LibvirtComputingResource.java | 97 +++++++++++++++++-- 2 files changed, 101 insertions(+), 7 deletions(-) diff --git a/agent/conf/agent.properties b/agent/conf/agent.properties index a7376b68947..e7e3b9cfdcb 100644 --- a/agent/conf/agent.properties +++ b/agent/conf/agent.properties @@ -70,6 +70,17 @@ domr.scripts.dir=scripts/network/domr/kvm # In MegaBytes per second #vm.migrate.speed=0 +# set target downtime at end of livemigration, the 'hiccup' for final copy. Higher numbers +# make livemigration easier, lower numbers may cause migration to never complete. Less than 1 +# means hypervisor default (20ms). +#vm.migrate.downtime=0 + +# Busy VMs may never finish migrating, depending on environment. When its available, we will +# want to add support for autoconvergence migration flag which should fix this. Set an upper +# limit in seconds for how long live migration should wait, at which point VM is paused and +# migration will finish quickly. Less than 1 means disabled. +#vm.migrate.pauseafter=0 + # set the type of bridge used on the hypervisor, this defines what commands the resource # will use to setup networking. Currently supported NATIVE, OPENVSWITCH #network.bridge.type=native diff --git a/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/LibvirtComputingResource.java b/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/LibvirtComputingResource.java index 1056bcf21f2..3f6abfced1f 100755 --- a/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/LibvirtComputingResource.java +++ b/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/LibvirtComputingResource.java @@ -254,11 +254,14 @@ import java.util.Map; import java.util.Properties; import java.util.Set; import java.util.UUID; +import java.util.concurrent.Callable; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.Future; +import java.util.concurrent.TimeoutException; +import java.util.concurrent.TimeUnit; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -306,6 +309,8 @@ public class LibvirtComputingResource extends ServerResourceBase implements Serv private String _pod; private String _clusterId; private int _migrateSpeed; + private int _migrateDowntime; + private int _migratePauseAfter; private long _hvVersion; private long _kernelVersion; @@ -889,6 +894,12 @@ public class LibvirtComputingResource extends ServerResourceBase implements Serv _mountPoint = "/mnt"; } + value = (String) params.get("vm.migrate.downtime"); + _migrateDowntime = NumbersUtil.parseInt(value, -1); + + value = (String) params.get("vm.migrate.pauseafter"); + _migratePauseAfter = NumbersUtil.parseInt(value, -1); + value = (String)params.get("vm.migrate.speed"); _migrateSpeed = NumbersUtil.parseInt(value, -1); if (_migrateSpeed == -1) { @@ -2986,7 +2997,7 @@ public class LibvirtComputingResource extends ServerResourceBase implements Serv Connect conn = null; String xmlDesc = null; try { - conn = LibvirtConnection.getConnectionByVmName(cmd.getVmName()); + conn = LibvirtConnection.getConnectionByVmName(vmName); ifaces = getInterfaces(conn, vmName); disks = getDisks(conn, vmName); dm = conn.domainLookupByName(vmName); @@ -3006,17 +3017,65 @@ public class LibvirtComputingResource extends ServerResourceBase implements Serv xmlDesc = dm.getXMLDesc(0).replace(_privateIp, cmd.getDestinationIp()); dconn = new Connect("qemu+tcp://" + cmd.getDestinationIp() + "/system"); - /* - * Hard code lm flag: VIR_MIGRATE_LIVE(1<<0) - */ - destDomain = dm.migrate(dconn, (1 << 0), xmlDesc, vmName, "tcp:" + cmd.getDestinationIp(), _migrateSpeed); - for (DiskDef disk : disks) { - cleanupDisk(disk); + //run migration in thread so we can monitor it + s_logger.info("Live migration of instance " + vmName + " initiated"); + ExecutorService executor = Executors.newFixedThreadPool(1); + Callable worker = new MigrateKVMAsync(dm, dconn, vmName, cmd.getDestinationIp()); + Future migrateThread = executor.submit(worker); + executor.shutdown(); + long sleeptime = 0; + while (!executor.isTerminated()) { + Thread.sleep(100); + sleeptime += 100; + if (sleeptime == 1000) { // wait 1s before attempting to set downtime on migration, since I don't know of a VIR_DOMAIN_MIGRATING state + if (_migrateDowntime > 0 ) { + try { + int setDowntime = dm.migrateSetMaxDowntime(_migrateDowntime); + if (setDowntime == 0 ) { + s_logger.debug("Set max downtime for migration of " + vmName + " to " + String.valueOf(_migrateDowntime) + "ms"); + } + } catch (LibvirtException e) { + s_logger.debug("Failed to set max downtime for migration, perhaps migration completed? Error: " + e.getMessage()); + } + } + } + if ((sleeptime % 1000) == 0) { + s_logger.info("Waiting for migration of " + vmName + " to complete, waited " + sleeptime + "ms"); + } + + // pause vm if we meet the vm.migrate.pauseafter threshold and not already paused + if (_migratePauseAfter > 0 && sleeptime > _migratePauseAfter && dm.getInfo().state == DomainInfo.DomainState.VIR_DOMAIN_RUNNING ) { + s_logger.info("Pausing VM " + vmName + " due to property vm.migrate.pauseafter setting to " + _migratePauseAfter+ "ms to complete migration"); + try { + dm.suspend(); + } catch (LibvirtException e) { + // pause could be racy if it attempts to pause right when vm is finished, simply warn + s_logger.info("Failed to pause vm " + vmName + " : " + e.getMessage()); + } + } + } + s_logger.info("Migration thread for " + vmName + " is done"); + + destDomain = migrateThread.get(10, TimeUnit.SECONDS); + + if (destDomain != null) { + for (DiskDef disk : disks) { + cleanupDisk(disk); + } } } catch (LibvirtException e) { s_logger.debug("Can't migrate domain: " + e.getMessage()); result = e.getMessage(); + } catch (InterruptedException e) { + s_logger.debug("Interrupted while migrating domain: " + e.getMessage()); + result = e.getMessage(); + } catch (ExecutionException e) { + s_logger.debug("Failed to execute while migrating domain: " + e.getMessage()); + result = e.getMessage(); + } catch (TimeoutException e) { + s_logger.debug("Timed out while migrating domain: " + e.getMessage()); + result = e.getMessage(); } finally { try { if (dm != null) { @@ -3054,6 +3113,30 @@ public class LibvirtComputingResource extends ServerResourceBase implements Serv return new MigrateAnswer(cmd, result == null, result, null); } + private class MigrateKVMAsync implements Callable { + Domain dm = null; + Connect dconn = null; + String vmName = ""; + String destIp = ""; + + MigrateKVMAsync(Domain dm, Connect dconn, String vmName, String destIp) { + this.dm = dm; + this.dconn = dconn; + this.vmName = vmName; + this.destIp = destIp; + } + + @Override + public Domain call() throws LibvirtException { + // set compression flag for migration if libvirt version supports it + if (dconn.getLibVirVersion() < 1003000) { + return dm.migrate(dconn, (1 << 0), vmName, "tcp:" + destIp, _migrateSpeed); + } else { + return dm.migrate(dconn, (1 << 0)|(1 << 11), vmName, "tcp:" + destIp, _migrateSpeed); + } + } + } + private synchronized Answer execute(PrepareForMigrationCommand cmd) { VirtualMachineTO vm = cmd.getVirtualMachine(); From bbaec7bae87fde2c93568a042b8cd085b57bf0d1 Mon Sep 17 00:00:00 2001 From: Marcus Sorensen Date: Wed, 5 Mar 2014 12:41:09 -0700 Subject: [PATCH 02/70] CLOUDSTACK-6203: Correct documentation for KVM migration tuneables --- agent/conf/agent.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/agent/conf/agent.properties b/agent/conf/agent.properties index e7e3b9cfdcb..b8b7a7cdad0 100644 --- a/agent/conf/agent.properties +++ b/agent/conf/agent.properties @@ -77,7 +77,7 @@ domr.scripts.dir=scripts/network/domr/kvm # Busy VMs may never finish migrating, depending on environment. When its available, we will # want to add support for autoconvergence migration flag which should fix this. Set an upper -# limit in seconds for how long live migration should wait, at which point VM is paused and +# limit in milliseconds for how long live migration should wait, at which point VM is paused and # migration will finish quickly. Less than 1 means disabled. #vm.migrate.pauseafter=0 From b06e66c50a43337d28c4157c396e39adb488902f Mon Sep 17 00:00:00 2001 From: Mike Tutkowski Date: Thu, 27 Feb 2014 13:20:56 -0700 Subject: [PATCH 03/70] CLOUDSTACK-6170 --- .../offering/CreateServiceOfferingCmd.java | 32 ++++ .../storage/to/PrimaryDataStoreTO.java | 18 ++ .../api/storage/DataMotionService.java | 2 + .../api/storage/DataMotionStrategy.java | 2 + .../api/storage/PrimaryDataStoreInfo.java | 18 ++ .../subsystem/api/storage/VolumeService.java | 6 +- .../orchestration/VolumeOrchestrator.java | 19 +- .../motion/AncientDataMotionStrategy.java | 25 ++- .../storage/motion/DataMotionServiceImpl.java | 9 +- .../storage/image/store/TemplateObject.java | 15 ++ .../test/MockStorageMotionStrategy.java | 5 + .../datastore/PrimaryDataStoreImpl.java | 20 +- .../provider/DefaultHostListener.java | 2 +- .../storage/volume/VolumeServiceImpl.java | 156 +++++++++++++++- .../motion/SimulatorDataMotionStrategy.java | 5 + .../motion/VmwareStorageMotionStrategy.java | 5 + .../xen/resource/CitrixResourceBase.java | 11 +- .../resource/XenServerStorageProcessor.java | 128 +++++++++---- .../XenServerStorageMotionStrategy.java | 5 + .../ConfigurationManagerImpl.java | 49 ++++- ui/scripts/configuration.js | 174 ++++++++++++++++-- 21 files changed, 639 insertions(+), 67 deletions(-) diff --git a/api/src/org/apache/cloudstack/api/command/admin/offering/CreateServiceOfferingCmd.java b/api/src/org/apache/cloudstack/api/command/admin/offering/CreateServiceOfferingCmd.java index 1d8cbff9307..4143c2e44c7 100644 --- a/api/src/org/apache/cloudstack/api/command/admin/offering/CreateServiceOfferingCmd.java +++ b/api/src/org/apache/cloudstack/api/command/admin/offering/CreateServiceOfferingCmd.java @@ -27,6 +27,7 @@ import org.apache.cloudstack.api.ApiErrorCode; import org.apache.cloudstack.api.BaseCmd; import org.apache.cloudstack.api.Parameter; import org.apache.cloudstack.api.ServerApiException; +import org.apache.cloudstack.api.BaseCmd.CommandType; import org.apache.cloudstack.api.response.DomainResponse; import org.apache.cloudstack.api.response.ServiceOfferingResponse; @@ -117,6 +118,21 @@ public class CreateServiceOfferingCmd extends BaseCmd { @Parameter(name = ApiConstants.IOPS_WRITE_RATE, type = CommandType.LONG, required = false, description = "io requests write rate of the disk offering") private Long iopsWriteRate; + @Parameter(name = ApiConstants.CUSTOMIZED_IOPS, type = CommandType.BOOLEAN, required = false, description = "whether compute offering iops is custom or not") + private Boolean customizedIops; + + @Parameter(name = ApiConstants.MIN_IOPS, type = CommandType.LONG, required = false, description = "min iops of the compute offering") + private Long minIops; + + @Parameter(name = ApiConstants.MAX_IOPS, type = CommandType.LONG, required = false, description = "max iops of the compute offering") + private Long maxIops; + + @Parameter(name = ApiConstants.HYPERVISOR_SNAPSHOT_RESERVE, + type = CommandType.INTEGER, + required = false, + description = "Hypervisor snapshot reserve space as a percent of a volume (for managed storage using Xen or VMware)") + private Integer hypervisorSnapshotReserve; + ///////////////////////////////////////////////////// /////////////////// Accessors /////////////////////// ///////////////////////////////////////////////////// @@ -215,6 +231,22 @@ public class CreateServiceOfferingCmd extends BaseCmd { return iopsWriteRate; } + public Boolean isCustomizedIops() { + return customizedIops; + } + + public Long getMinIops() { + return minIops; + } + + public Long getMaxIops() { + return maxIops; + } + + public Integer getHypervisorSnapshotReserve() { + return hypervisorSnapshotReserve; + } + ///////////////////////////////////////////////////// /////////////// API Implementation/////////////////// ///////////////////////////////////////////////////// diff --git a/core/src/org/apache/cloudstack/storage/to/PrimaryDataStoreTO.java b/core/src/org/apache/cloudstack/storage/to/PrimaryDataStoreTO.java index 01c05f004f9..6a5d6793312 100644 --- a/core/src/org/apache/cloudstack/storage/to/PrimaryDataStoreTO.java +++ b/core/src/org/apache/cloudstack/storage/to/PrimaryDataStoreTO.java @@ -16,6 +16,8 @@ // under the License. package org.apache.cloudstack.storage.to; +import java.util.Map; + import org.apache.cloudstack.engine.subsystem.api.storage.PrimaryDataStore; import com.cloud.agent.api.to.DataStoreTO; @@ -23,6 +25,16 @@ import com.cloud.storage.DataStoreRole; import com.cloud.storage.Storage.StoragePoolType; public class PrimaryDataStoreTO implements DataStoreTO { + public static final String MANAGED = PrimaryDataStore.MANAGED; + public static final String STORAGE_HOST = PrimaryDataStore.STORAGE_HOST; + public static final String MANAGED_STORE_TARGET = PrimaryDataStore.MANAGED_STORE_TARGET; + public static final String MANAGED_STORE_TARGET_ROOT_VOLUME = PrimaryDataStore.MANAGED_STORE_TARGET_ROOT_VOLUME; + public static final String CHAP_INITIATOR_USERNAME = PrimaryDataStore.CHAP_INITIATOR_USERNAME; + public static final String CHAP_INITIATOR_SECRET = PrimaryDataStore.CHAP_INITIATOR_SECRET; + public static final String CHAP_TARGET_USERNAME = PrimaryDataStore.CHAP_TARGET_USERNAME; + public static final String CHAP_TARGET_SECRET = PrimaryDataStore.CHAP_TARGET_SECRET; + public static final String VOLUME_SIZE = PrimaryDataStore.VOLUME_SIZE; + private final String uuid; private final String name; private String type; @@ -32,6 +44,7 @@ public class PrimaryDataStoreTO implements DataStoreTO { private String path; private int port; private final String url; + private Map details; public PrimaryDataStoreTO(PrimaryDataStore dataStore) { this.uuid = dataStore.getUuid(); @@ -42,6 +55,7 @@ public class PrimaryDataStoreTO implements DataStoreTO { this.setPath(dataStore.getPath()); this.setPort(dataStore.getPort()); this.url = dataStore.getUri(); + this.details = dataStore.getDetails(); } public long getId() { @@ -58,6 +72,10 @@ public class PrimaryDataStoreTO implements DataStoreTO { return this.url; } + public Map getDetails() { + return this.details; + } + public String getName() { return this.name; } diff --git a/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/DataMotionService.java b/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/DataMotionService.java index f20e18847fe..a8f8b308539 100644 --- a/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/DataMotionService.java +++ b/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/DataMotionService.java @@ -26,6 +26,8 @@ import com.cloud.agent.api.to.VirtualMachineTO; import com.cloud.host.Host; public interface DataMotionService { + void copyAsync(DataObject srcData, DataObject destData, Host destHost, AsyncCompletionCallback callback); + void copyAsync(DataObject srcData, DataObject destData, AsyncCompletionCallback callback); void copyAsync(Map volumeMap, VirtualMachineTO vmTo, Host srcHost, Host destHost, AsyncCompletionCallback callback); diff --git a/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/DataMotionStrategy.java b/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/DataMotionStrategy.java index 39a257d7262..b5601e9693c 100644 --- a/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/DataMotionStrategy.java +++ b/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/DataMotionStrategy.java @@ -30,6 +30,8 @@ public interface DataMotionStrategy { StrategyPriority canHandle(Map volumeMap, Host srcHost, Host destHost); + Void copyAsync(DataObject srcData, DataObject destData, Host destHost, AsyncCompletionCallback callback); + Void copyAsync(DataObject srcData, DataObject destData, AsyncCompletionCallback callback); Void copyAsync(Map volumeMap, VirtualMachineTO vmTo, Host srcHost, Host destHost, AsyncCompletionCallback callback); diff --git a/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/PrimaryDataStoreInfo.java b/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/PrimaryDataStoreInfo.java index 19893d07d1f..bb9f2dad1ff 100644 --- a/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/PrimaryDataStoreInfo.java +++ b/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/PrimaryDataStoreInfo.java @@ -18,6 +18,8 @@ */ package org.apache.cloudstack.engine.subsystem.api.storage; +import java.util.Map; + import org.apache.cloudstack.engine.subsystem.api.storage.disktype.DiskFormat; import com.cloud.hypervisor.Hypervisor.HypervisorType; @@ -25,6 +27,16 @@ import com.cloud.storage.Storage.StoragePoolType; import com.cloud.storage.StoragePool; public interface PrimaryDataStoreInfo extends StoragePool { + static final String MANAGED = "managed"; + static final String STORAGE_HOST= "storageHost"; + static final String MANAGED_STORE_TARGET = "managedStoreTarget"; + static final String MANAGED_STORE_TARGET_ROOT_VOLUME = "managedStoreTargetRootVolume"; + static final String CHAP_INITIATOR_USERNAME = "chapInitiatorUsername"; + static final String CHAP_INITIATOR_SECRET = "chapInitiatorSecret"; + static final String CHAP_TARGET_USERNAME = "chapTargetUsername"; + static final String CHAP_TARGET_SECRET = "chapTargetSecret"; + static final String VOLUME_SIZE = "volumeSize"; + boolean isHypervisorSupported(HypervisorType hypervisor); boolean isLocalStorageSupported(); @@ -37,5 +49,11 @@ public interface PrimaryDataStoreInfo extends StoragePool { @Override StoragePoolType getPoolType(); + boolean isManaged(); + + void setDetails(Map details); + + Map getDetails(); + PrimaryDataStoreLifeCycle getLifeCycle(); } diff --git a/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/VolumeService.java b/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/VolumeService.java index 3f676ae73dc..b6e61069e77 100644 --- a/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/VolumeService.java +++ b/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/VolumeService.java @@ -78,7 +78,11 @@ public interface VolumeService { VolumeEntity getVolumeEntity(long volumeId); - AsyncCallFuture createVolumeFromTemplateAsync(VolumeInfo volume, long dataStoreId, TemplateInfo template); + AsyncCallFuture createManagedStorageAndVolumeFromTemplateAsync(VolumeInfo volumeInfo, long destDataStoreId, + TemplateInfo srcTemplateInfo, long destHostId); + + AsyncCallFuture createVolumeFromTemplateAsync(VolumeInfo volume, long dataStoreId, + TemplateInfo template); AsyncCallFuture copyVolume(VolumeInfo srcVolume, DataStore destStore); diff --git a/engine/orchestration/src/org/apache/cloudstack/engine/orchestration/VolumeOrchestrator.java b/engine/orchestration/src/org/apache/cloudstack/engine/orchestration/VolumeOrchestrator.java index d3eda8a3721..4d0c7872c03 100644 --- a/engine/orchestration/src/org/apache/cloudstack/engine/orchestration/VolumeOrchestrator.java +++ b/engine/orchestration/src/org/apache/cloudstack/engine/orchestration/VolumeOrchestrator.java @@ -36,6 +36,7 @@ import org.apache.cloudstack.engine.orchestration.service.VolumeOrchestrationSer import org.apache.cloudstack.engine.subsystem.api.storage.ChapInfo; import org.apache.cloudstack.engine.subsystem.api.storage.DataStore; import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreManager; +import org.apache.cloudstack.engine.subsystem.api.storage.PrimaryDataStore; import org.apache.cloudstack.engine.subsystem.api.storage.SnapshotDataFactory; import org.apache.cloudstack.engine.subsystem.api.storage.SnapshotInfo; import org.apache.cloudstack.engine.subsystem.api.storage.SnapshotService; @@ -1113,7 +1114,23 @@ public class VolumeOrchestrator extends ManagerBase implements VolumeOrchestrati future = volService.createVolumeAsync(volume, destPool); } else { TemplateInfo templ = tmplFactory.getTemplate(templateId, DataStoreRole.Image); - future = volService.createVolumeFromTemplateAsync(volume, destPool.getId(), templ); + + PrimaryDataStore primaryDataStore = (PrimaryDataStore)destPool; + + if (primaryDataStore.isManaged()) { + DiskOffering diskOffering = _entityMgr.findById(DiskOffering.class, volume.getDiskOfferingId()); + HypervisorType hyperType = vm.getVirtualMachine().getHypervisorType(); + + // update the volume's hypervisor_ss_reserve from its disk offering (used for managed storage) + updateHypervisorSnapshotReserveForVolume(diskOffering, volume, hyperType); + + long hostId = vm.getVirtualMachine().getHostId(); + + future = volService.createManagedStorageAndVolumeFromTemplateAsync(volume, destPool.getId(), templ, hostId); + } + else { + future = volService.createVolumeFromTemplateAsync(volume, destPool.getId(), templ); + } } VolumeApiResult result = null; try { diff --git a/engine/storage/datamotion/src/org/apache/cloudstack/storage/motion/AncientDataMotionStrategy.java b/engine/storage/datamotion/src/org/apache/cloudstack/storage/motion/AncientDataMotionStrategy.java index 0556479e072..df81199461e 100644 --- a/engine/storage/datamotion/src/org/apache/cloudstack/storage/motion/AncientDataMotionStrategy.java +++ b/engine/storage/datamotion/src/org/apache/cloudstack/storage/motion/AncientDataMotionStrategy.java @@ -46,6 +46,7 @@ import org.apache.cloudstack.engine.subsystem.api.storage.VolumeInfo; import org.apache.cloudstack.engine.subsystem.api.storage.ZoneScope; import org.apache.cloudstack.framework.async.AsyncCompletionCallback; import org.apache.cloudstack.framework.config.dao.ConfigurationDao; +import org.apache.cloudstack.storage.RemoteHostEndPoint; import org.apache.cloudstack.storage.command.CopyCommand; import org.apache.cloudstack.storage.image.datastore.ImageStoreEntity; @@ -94,15 +95,17 @@ public class AncientDataMotionStrategy implements DataMotionStrategy { protected boolean needCacheStorage(DataObject srcData, DataObject destData) { DataTO srcTO = srcData.getTO(); - DataTO destTO = destData.getTO(); DataStoreTO srcStoreTO = srcTO.getDataStore(); - DataStoreTO destStoreTO = destTO.getDataStore(); + if (srcStoreTO instanceof NfsTO || srcStoreTO.getRole() == DataStoreRole.ImageCache) { //|| // (srcStoreTO instanceof PrimaryDataStoreTO && ((PrimaryDataStoreTO)srcStoreTO).getPoolType() == StoragePoolType.NetworkFilesystem)) { return false; } + DataTO destTO = destData.getTO(); + DataStoreTO destStoreTO = destTO.getDataStore(); + if (destStoreTO instanceof NfsTO || destStoreTO.getRole() == DataStoreRole.ImageCache) { return false; } @@ -147,7 +150,7 @@ public class AncientDataMotionStrategy implements DataMotionStrategy { return selectedScope; } - protected Answer copyObject(DataObject srcData, DataObject destData) { + protected Answer copyObject(DataObject srcData, DataObject destData, Host destHost) { String value = configDao.getValue(Config.PrimaryStorageDownloadWait.toString()); int _primaryStorageDownloadWait = NumbersUtil.parseInt(value, Integer.parseInt(Config.PrimaryStorageDownloadWait.getDefaultValue())); Answer answer = null; @@ -160,7 +163,7 @@ public class AncientDataMotionStrategy implements DataMotionStrategy { } CopyCommand cmd = new CopyCommand(srcForCopy.getTO(), destData.getTO(), _primaryStorageDownloadWait, VirtualMachineManager.ExecuteInSequence.value()); - EndPoint ep = selector.select(srcForCopy, destData); + EndPoint ep = destHost != null ? RemoteHostEndPoint.getHypervisorHostEndPoint(destHost) : selector.select(srcForCopy, destData); if (ep == null) { String errMsg = "No remote endpoint to send command, check if host or ssvm is down?"; s_logger.error(errMsg); @@ -193,6 +196,10 @@ public class AncientDataMotionStrategy implements DataMotionStrategy { } } + protected Answer copyObject(DataObject srcData, DataObject destData) { + return copyObject(srcData, destData, null); + } + protected DataObject cacheSnapshotChain(SnapshotInfo snapshot, Scope scope) { DataObject leafData = null; DataStore store = cacheMgr.getCacheStorage(snapshot, scope); @@ -392,8 +399,9 @@ public class AncientDataMotionStrategy implements DataMotionStrategy { return answer; } + // Note: destHost is currently only used if the copyObject method is invoked @Override - public Void copyAsync(DataObject srcData, DataObject destData, AsyncCompletionCallback callback) { + public Void copyAsync(DataObject srcData, DataObject destData, Host destHost, AsyncCompletionCallback callback) { Answer answer = null; String errMsg = null; try { @@ -416,7 +424,7 @@ public class AncientDataMotionStrategy implements DataMotionStrategy { } else if (srcData.getType() == DataObjectType.SNAPSHOT && destData.getType() == DataObjectType.SNAPSHOT) { answer = copySnapshot(srcData, destData); } else { - answer = copyObject(srcData, destData); + answer = copyObject(srcData, destData, destHost); } if (answer != null && !answer.getResult()) { @@ -432,6 +440,11 @@ public class AncientDataMotionStrategy implements DataMotionStrategy { return null; } + @Override + public Void copyAsync(DataObject srcData, DataObject destData, AsyncCompletionCallback callback) { + return copyAsync(srcData, destData, null, callback); + } + @DB protected Answer createTemplateFromSnapshot(DataObject srcData, DataObject destData) { diff --git a/engine/storage/datamotion/src/org/apache/cloudstack/storage/motion/DataMotionServiceImpl.java b/engine/storage/datamotion/src/org/apache/cloudstack/storage/motion/DataMotionServiceImpl.java index 37e8baabbe9..eed1e08005f 100644 --- a/engine/storage/datamotion/src/org/apache/cloudstack/storage/motion/DataMotionServiceImpl.java +++ b/engine/storage/datamotion/src/org/apache/cloudstack/storage/motion/DataMotionServiceImpl.java @@ -46,7 +46,7 @@ public class DataMotionServiceImpl implements DataMotionService { StorageStrategyFactory storageStrategyFactory; @Override - public void copyAsync(DataObject srcData, DataObject destData, AsyncCompletionCallback callback) { + public void copyAsync(DataObject srcData, DataObject destData, Host destHost, AsyncCompletionCallback callback) { if (srcData.getDataStore() == null || destData.getDataStore() == null) { throw new CloudRuntimeException("can't find data store"); } @@ -65,7 +65,12 @@ public class DataMotionServiceImpl implements DataMotionService { destData.getType().name() + " '" + destData.getUuid() + "'"); } - strategy.copyAsync(srcData, destData, callback); + strategy.copyAsync(srcData, destData, destHost, callback); + } + + @Override + public void copyAsync(DataObject srcData, DataObject destData, AsyncCompletionCallback callback) { + copyAsync(srcData, destData, null, callback); } @Override diff --git a/engine/storage/image/src/org/apache/cloudstack/storage/image/store/TemplateObject.java b/engine/storage/image/src/org/apache/cloudstack/storage/image/store/TemplateObject.java index 8db21ccbf7a..34db48146be 100644 --- a/engine/storage/image/src/org/apache/cloudstack/storage/image/store/TemplateObject.java +++ b/engine/storage/image/src/org/apache/cloudstack/storage/image/store/TemplateObject.java @@ -30,6 +30,7 @@ import org.apache.cloudstack.engine.subsystem.api.storage.DataObjectInStore; import org.apache.cloudstack.engine.subsystem.api.storage.DataStore; import org.apache.cloudstack.engine.subsystem.api.storage.ObjectInDataStoreStateMachine; import org.apache.cloudstack.engine.subsystem.api.storage.ObjectInDataStoreStateMachine.Event; +import org.apache.cloudstack.engine.subsystem.api.storage.PrimaryDataStore; import org.apache.cloudstack.engine.subsystem.api.storage.TemplateInfo; import org.apache.cloudstack.storage.command.CopyCmdAnswer; import org.apache.cloudstack.storage.datastore.ObjectInDataStoreManager; @@ -299,6 +300,20 @@ public class TemplateObject implements TemplateInfo { if (dataStore == null) { return null; } + + // managed primary data stores should not have an install path + if (dataStore instanceof PrimaryDataStore) { + PrimaryDataStore primaryDataStore = (PrimaryDataStore)dataStore; + + Map details = primaryDataStore.getDetails(); + + boolean managed = details != null && Boolean.parseBoolean(details.get(PrimaryDataStore.MANAGED)); + + if (managed) { + return null; + } + } + DataObjectInStore obj = objectInStoreMgr.findObject(this, dataStore); return obj.getInstallPath(); } diff --git a/engine/storage/integration-test/test/org/apache/cloudstack/storage/test/MockStorageMotionStrategy.java b/engine/storage/integration-test/test/org/apache/cloudstack/storage/test/MockStorageMotionStrategy.java index 2a11e1337e6..accfeb5318e 100644 --- a/engine/storage/integration-test/test/org/apache/cloudstack/storage/test/MockStorageMotionStrategy.java +++ b/engine/storage/integration-test/test/org/apache/cloudstack/storage/test/MockStorageMotionStrategy.java @@ -57,6 +57,11 @@ public class MockStorageMotionStrategy implements DataMotionStrategy { return StrategyPriority.HIGHEST; } + @Override + public Void copyAsync(DataObject srcData, DataObject destData, Host destHost, AsyncCompletionCallback callback) { + throw new UnsupportedOperationException(); + } + @Override public Void copyAsync(DataObject srcData, DataObject destData, AsyncCompletionCallback callback) { CopyCmdAnswer answer = null; diff --git a/engine/storage/volume/src/org/apache/cloudstack/storage/datastore/PrimaryDataStoreImpl.java b/engine/storage/volume/src/org/apache/cloudstack/storage/datastore/PrimaryDataStoreImpl.java index 649e6896c8e..4fb37e2a181 100644 --- a/engine/storage/volume/src/org/apache/cloudstack/storage/datastore/PrimaryDataStoreImpl.java +++ b/engine/storage/volume/src/org/apache/cloudstack/storage/datastore/PrimaryDataStoreImpl.java @@ -20,6 +20,7 @@ import java.io.File; import java.util.ArrayList; import java.util.Date; import java.util.List; +import java.util.Map; import javax.inject.Inject; @@ -67,6 +68,7 @@ import com.cloud.utils.storage.encoding.EncodingType; public class PrimaryDataStoreImpl implements PrimaryDataStore { private static final Logger s_logger = Logger.getLogger(PrimaryDataStoreImpl.class); + protected PrimaryDataStoreDriver driver; protected StoragePoolVO pdsv; @Inject @@ -86,6 +88,7 @@ public class PrimaryDataStoreImpl implements PrimaryDataStore { @Inject private VolumeDao volumeDao; + private Map _details; public PrimaryDataStoreImpl() { @@ -135,6 +138,16 @@ public class PrimaryDataStoreImpl implements PrimaryDataStore { return pdsv.getId(); } + @Override + public void setDetails(Map details) { + _details = details; + } + + @Override + public Map getDetails() { + return _details; + } + @Override public String getUri() { String path = pdsv.getPath().replaceFirst("/*", ""); @@ -222,10 +235,15 @@ public class PrimaryDataStoreImpl implements PrimaryDataStore { return null; } + @Override + public boolean isManaged() { + return pdsv.isManaged(); + } + @Override public DataObject create(DataObject obj) { // create template on primary storage - if (obj.getType() == DataObjectType.TEMPLATE) { + if (obj.getType() == DataObjectType.TEMPLATE && !isManaged()) { try { String templateIdPoolIdString = "templateId:" + obj.getId() + "poolId:" + getId(); VMTemplateStoragePoolVO templateStoragePoolRef; diff --git a/engine/storage/volume/src/org/apache/cloudstack/storage/datastore/provider/DefaultHostListener.java b/engine/storage/volume/src/org/apache/cloudstack/storage/datastore/provider/DefaultHostListener.java index 4838bf678e0..fffd1e815c4 100644 --- a/engine/storage/volume/src/org/apache/cloudstack/storage/datastore/provider/DefaultHostListener.java +++ b/engine/storage/volume/src/org/apache/cloudstack/storage/datastore/provider/DefaultHostListener.java @@ -85,7 +85,7 @@ public class DefaultHostListener implements HypervisorHostListener { poolVO.setCapacityBytes(mspAnswer.getPoolInfo().getCapacityBytes()); primaryStoreDao.update(pool.getId(), poolVO); - s_logger.info("Connection established between " + pool + " host + " + hostId); + s_logger.info("Connection established between storage pool " + pool + " and host " + hostId); return true; } diff --git a/engine/storage/volume/src/org/apache/cloudstack/storage/volume/VolumeServiceImpl.java b/engine/storage/volume/src/org/apache/cloudstack/storage/volume/VolumeServiceImpl.java index fa0fd956a7a..d47ee27d4a5 100644 --- a/engine/storage/volume/src/org/apache/cloudstack/storage/volume/VolumeServiceImpl.java +++ b/engine/storage/volume/src/org/apache/cloudstack/storage/volume/VolumeServiceImpl.java @@ -20,6 +20,7 @@ package org.apache.cloudstack.storage.volume; import java.util.ArrayList; import java.util.Date; +import java.util.HashMap; import java.util.List; import java.util.Map; @@ -40,6 +41,7 @@ import org.apache.cloudstack.engine.subsystem.api.storage.EndPoint; import org.apache.cloudstack.engine.subsystem.api.storage.EndPointSelector; import org.apache.cloudstack.engine.subsystem.api.storage.ObjectInDataStoreStateMachine; import org.apache.cloudstack.engine.subsystem.api.storage.ObjectInDataStoreStateMachine.Event; +import org.apache.cloudstack.engine.subsystem.api.storage.VolumeService.VolumeApiResult; import org.apache.cloudstack.engine.subsystem.api.storage.PrimaryDataStore; import org.apache.cloudstack.engine.subsystem.api.storage.PrimaryDataStoreDriver; import org.apache.cloudstack.engine.subsystem.api.storage.Scope; @@ -60,6 +62,7 @@ import org.apache.cloudstack.storage.datastore.PrimaryDataStoreProviderManager; import org.apache.cloudstack.storage.datastore.db.VolumeDataStoreDao; import org.apache.cloudstack.storage.datastore.db.VolumeDataStoreVO; import org.apache.cloudstack.storage.to.VolumeObjectTO; +import org.apache.cloudstack.storage.to.TemplateObjectTO; import com.cloud.agent.api.Answer; import com.cloud.agent.api.storage.ListVolumeAnswer; @@ -72,6 +75,7 @@ import com.cloud.event.EventTypes; import com.cloud.event.UsageEventUtils; import com.cloud.exception.ConcurrentOperationException; import com.cloud.exception.ResourceAllocationException; +import com.cloud.host.dao.HostDao; import com.cloud.host.Host; import com.cloud.storage.DataStoreRole; import com.cloud.storage.ScopeType; @@ -122,6 +126,8 @@ public class VolumeServiceImpl implements VolumeService { VolumeDao _volumeDao; @Inject EndPointSelector _epSelector; + @Inject + HostDao _hostDao; public VolumeServiceImpl() { } @@ -349,6 +355,39 @@ public class VolumeServiceImpl implements VolumeService { return null; } + private class ManagedCreateBaseImageContext extends AsyncRpcContext { + private final VolumeInfo _volumeInfo; + private final PrimaryDataStore _primaryDataStore; + private final TemplateInfo _templateInfo; + private final AsyncCallFuture _future; + + public ManagedCreateBaseImageContext(AsyncCompletionCallback callback, VolumeInfo volumeInfo, + PrimaryDataStore primaryDatastore, TemplateInfo templateInfo, AsyncCallFuture future) { + super(callback); + + _volumeInfo = volumeInfo; + _primaryDataStore = primaryDatastore; + _templateInfo = templateInfo; + _future = future; + } + + public VolumeInfo getVolumeInfo() { + return _volumeInfo; + } + + public PrimaryDataStore getPrimaryDataStore() { + return _primaryDataStore; + } + + public TemplateInfo getTemplateInfo() { + return _templateInfo; + } + + public AsyncCallFuture getFuture() { + return _future; + } + } + class CreateBaseImageContext extends AsyncRpcContext { private final VolumeInfo volume; private final PrimaryDataStore dataStore; @@ -411,7 +450,6 @@ public class VolumeServiceImpl implements VolumeService { @DB protected void createBaseImageAsync(VolumeInfo volume, PrimaryDataStore dataStore, TemplateInfo template, AsyncCallFuture future) { - DataObject templateOnPrimaryStoreObj = dataStore.create(template); VMTemplateStoragePoolVO templatePoolRef = _tmpltPoolDao.findByPoolTemplate(dataStore.getId(), template.getId()); @@ -476,6 +514,37 @@ public class VolumeServiceImpl implements VolumeService { return; } + protected Void managedCopyBaseImageCallback(AsyncCallbackDispatcher callback, + ManagedCreateBaseImageContext context) { + CopyCommandResult result = callback.getResult(); + VolumeInfo volumeInfo = context.getVolumeInfo(); + VolumeApiResult res = new VolumeApiResult(volumeInfo); + + if (result.isSuccess()) { + // volumeInfo.processEvent(Event.OperationSuccessed, result.getAnswer()); + + VolumeVO volume = volDao.findById(volumeInfo.getId()); + CopyCmdAnswer answer = (CopyCmdAnswer)result.getAnswer(); + TemplateObjectTO templateObjectTo = (TemplateObjectTO)answer.getNewData(); + + volume.setPath(templateObjectTo.getPath()); + volume.setFormat(templateObjectTo.getFormat()); + + volDao.update(volume.getId(), volume); + } + else { + volumeInfo.processEvent(Event.DestroyRequested); + + res.setResult(result.getResult()); + } + + AsyncCallFuture future = context.getFuture(); + + future.complete(res); + + return null; + } + @DB protected Void copyBaseImageCallback(AsyncCallbackDispatcher callback, CreateBaseImageContext context) { CopyCommandResult result = callback.getResult(); @@ -577,6 +646,91 @@ public class VolumeServiceImpl implements VolumeService { return null; } + @Override + public AsyncCallFuture createManagedStorageAndVolumeFromTemplateAsync(VolumeInfo volumeInfo, long destDataStoreId, + TemplateInfo srcTemplateInfo, long destHostId) { + PrimaryDataStore destPrimaryDataStore = dataStoreMgr.getPrimaryDataStore(destDataStoreId); + TemplateInfo destTemplateInfo = (TemplateInfo)destPrimaryDataStore.create(srcTemplateInfo); + Host destHost = _hostDao.findById(destHostId); + + if (destHost == null) { + throw new CloudRuntimeException("Destinatin host should not be null."); + } + + AsyncCallFuture future = new AsyncCallFuture(); + + try { + // must call driver to have a volume created + AsyncCallFuture createVolumeFuture = createVolumeAsync(volumeInfo, destPrimaryDataStore); + + VolumeApiResult createVolumeResult = createVolumeFuture.get(); + + if (createVolumeResult.isFailed()) { + throw new CloudRuntimeException("Creation of a volume failed: " + createVolumeResult.getResult()); + } + + // refresh the volume from the DB + volumeInfo = volFactory.getVolume(volumeInfo.getId(), destPrimaryDataStore); + + connectVolumeToHost(volumeInfo, destHost, destPrimaryDataStore); + + ManagedCreateBaseImageContext context = new ManagedCreateBaseImageContext(null, volumeInfo, + destPrimaryDataStore, srcTemplateInfo, future); + AsyncCallbackDispatcher caller = AsyncCallbackDispatcher.create(this); + caller.setCallback(caller.getTarget().managedCopyBaseImageCallback(null, null)).setContext(context); + + Map details = new HashMap(); + + details.put(PrimaryDataStore.MANAGED, Boolean.TRUE.toString()); + details.put(PrimaryDataStore.STORAGE_HOST, destPrimaryDataStore.getHostAddress()); + // for managed storage, the storage repository (XenServer) or datastore (ESX) name is based off of the iScsiName property of a volume + details.put(PrimaryDataStore.MANAGED_STORE_TARGET, volumeInfo.get_iScsiName()); + details.put(PrimaryDataStore.MANAGED_STORE_TARGET_ROOT_VOLUME, volumeInfo.getName()); + details.put(PrimaryDataStore.VOLUME_SIZE, String.valueOf(volumeInfo.getSize())); + + ChapInfo chapInfo = getChapInfo(volumeInfo, destPrimaryDataStore); + + if (chapInfo != null) { + details.put(PrimaryDataStore.CHAP_INITIATOR_USERNAME, chapInfo.getInitiatorUsername()); + details.put(PrimaryDataStore.CHAP_INITIATOR_SECRET, chapInfo.getInitiatorSecret()); + details.put(PrimaryDataStore.CHAP_TARGET_USERNAME, chapInfo.getTargetUsername()); + details.put(PrimaryDataStore.CHAP_TARGET_SECRET, chapInfo.getTargetSecret()); + } + + destPrimaryDataStore.setDetails(details); + + motionSrv.copyAsync(srcTemplateInfo, destTemplateInfo, destHost, caller); + } + catch (Throwable t) { + String errMsg = t.toString(); + + volumeInfo.processEvent(Event.DestroyRequested); + + disconnectVolumeFromHost(volumeInfo, destHost, destPrimaryDataStore); + + try { + AsyncCallFuture expungeVolumeFuture = expungeVolumeAsync(volumeInfo); + + VolumeApiResult expungeVolumeResult = expungeVolumeFuture.get(); + + if (expungeVolumeResult.isFailed()) { + errMsg += " : Failed to expunge a volume that was created"; + } + } + catch (Exception ex) { + errMsg += " : " + ex.getMessage(); + } + + VolumeApiResult result = new VolumeApiResult(volumeInfo); + + result.setResult(errMsg); + + future.complete(result); + } + + return future; + } + @DB @Override public AsyncCallFuture createVolumeFromTemplateAsync(VolumeInfo volume, long dataStoreId, TemplateInfo template) { diff --git a/plugins/hypervisors/simulator/src/org/apache/cloudstack/storage/motion/SimulatorDataMotionStrategy.java b/plugins/hypervisors/simulator/src/org/apache/cloudstack/storage/motion/SimulatorDataMotionStrategy.java index 3eb2cf60b7d..40909629c70 100644 --- a/plugins/hypervisors/simulator/src/org/apache/cloudstack/storage/motion/SimulatorDataMotionStrategy.java +++ b/plugins/hypervisors/simulator/src/org/apache/cloudstack/storage/motion/SimulatorDataMotionStrategy.java @@ -42,6 +42,11 @@ public class SimulatorDataMotionStrategy implements DataMotionStrategy { return StrategyPriority.HYPERVISOR; } + @Override + public Void copyAsync(DataObject srcData, DataObject destData, Host destHost, AsyncCompletionCallback callback) { + throw new UnsupportedOperationException(); + } + @Override public Void copyAsync(DataObject srcData, DataObject destData, AsyncCompletionCallback callback) { CopyCommandResult result = new CopyCommandResult("something", null); diff --git a/plugins/hypervisors/vmware/src/org/apache/cloudstack/storage/motion/VmwareStorageMotionStrategy.java b/plugins/hypervisors/vmware/src/org/apache/cloudstack/storage/motion/VmwareStorageMotionStrategy.java index 09f10688a68..24efde79a99 100644 --- a/plugins/hypervisors/vmware/src/org/apache/cloudstack/storage/motion/VmwareStorageMotionStrategy.java +++ b/plugins/hypervisors/vmware/src/org/apache/cloudstack/storage/motion/VmwareStorageMotionStrategy.java @@ -85,6 +85,11 @@ public class VmwareStorageMotionStrategy implements DataMotionStrategy { return StrategyPriority.CANT_HANDLE; } + @Override + public Void copyAsync(DataObject srcData, DataObject destData, Host destHost, AsyncCompletionCallback callback) { + throw new UnsupportedOperationException(); + } + @Override public Void copyAsync(DataObject srcData, DataObject destData, AsyncCompletionCallback callback) { CopyCommandResult result = new CopyCommandResult(null, null); diff --git a/plugins/hypervisors/xen/src/com/cloud/hypervisor/xen/resource/CitrixResourceBase.java b/plugins/hypervisors/xen/src/com/cloud/hypervisor/xen/resource/CitrixResourceBase.java index c0d691ad5ba..2b441e559ba 100644 --- a/plugins/hypervisors/xen/src/com/cloud/hypervisor/xen/resource/CitrixResourceBase.java +++ b/plugins/hypervisors/xen/src/com/cloud/hypervisor/xen/resource/CitrixResourceBase.java @@ -1869,18 +1869,23 @@ public abstract class CitrixResourceBase implements ServerResource, HypervisorRe return prepareManagedStorage(conn, details, null, vdiNameLabel); } - protected VDI prepareManagedStorage(Connection conn, Map details, String path, String vdiNameLabel) throws Exception { + protected SR prepareManagedSr(Connection conn, Map details) { String iScsiName = details.get(DiskTO.IQN); String storageHost = details.get(DiskTO.STORAGE_HOST); String chapInitiatorUsername = details.get(DiskTO.CHAP_INITIATOR_USERNAME); String chapInitiatorSecret = details.get(DiskTO.CHAP_INITIATOR_SECRET); - Long volumeSize = Long.parseLong(details.get(DiskTO.VOLUME_SIZE)); - SR sr = getIscsiSR(conn, iScsiName, storageHost, iScsiName, chapInitiatorUsername, chapInitiatorSecret, true); + return getIscsiSR(conn, iScsiName, storageHost, iScsiName, chapInitiatorUsername, chapInitiatorSecret, true); + } + + protected VDI prepareManagedStorage(Connection conn, Map details, String path, String vdiNameLabel) throws Exception { + SR sr = prepareManagedSr(conn, details); VDI vdi = getVDIbyUuid(conn, path, false); if (vdi == null) { + Long volumeSize = Long.parseLong(details.get(DiskTO.VOLUME_SIZE)); + vdi = createVdi(sr, vdiNameLabel, volumeSize); } diff --git a/plugins/hypervisors/xen/src/com/cloud/hypervisor/xen/resource/XenServerStorageProcessor.java b/plugins/hypervisors/xen/src/com/cloud/hypervisor/xen/resource/XenServerStorageProcessor.java index f2abff74f80..e512046b35b 100644 --- a/plugins/hypervisors/xen/src/com/cloud/hypervisor/xen/resource/XenServerStorageProcessor.java +++ b/plugins/hypervisors/xen/src/com/cloud/hypervisor/xen/resource/XenServerStorageProcessor.java @@ -59,6 +59,7 @@ import org.apache.cloudstack.storage.command.ForgetObjectCmd; import org.apache.cloudstack.storage.command.IntroduceObjectAnswer; import org.apache.cloudstack.storage.command.IntroduceObjectCmd; import org.apache.cloudstack.storage.datastore.protocol.DataStoreProtocol; +import org.apache.cloudstack.storage.to.PrimaryDataStoreTO; import org.apache.cloudstack.storage.to.SnapshotObjectTO; import org.apache.cloudstack.storage.to.TemplateObjectTO; import org.apache.cloudstack.storage.to.VolumeObjectTO; @@ -887,58 +888,121 @@ public class XenServerStorageProcessor implements StorageProcessor { @Override public Answer copyTemplateToPrimaryStorage(CopyCommand cmd) { - DataTO srcData = cmd.getSrcTO(); - DataTO destData = cmd.getDestTO(); + DataTO srcDataTo = cmd.getSrcTO(); + DataTO destDataTo = cmd.getDestTO(); int wait = cmd.getWait(); - DataStoreTO srcStore = srcData.getDataStore(); - try { - if ((srcStore instanceof NfsTO) && (srcData.getObjectType() == DataObjectType.TEMPLATE)) { - NfsTO srcImageStore = (NfsTO)srcStore; - TemplateObjectTO srcTemplate = (TemplateObjectTO)srcData; - String storeUrl = srcImageStore.getUrl(); + DataStoreTO srcDataStoreTo = srcDataTo.getDataStore(); + try { + if ((srcDataStoreTo instanceof NfsTO) && (srcDataTo.getObjectType() == DataObjectType.TEMPLATE)) { + NfsTO srcImageStore = (NfsTO)srcDataStoreTo; + TemplateObjectTO srcTemplateObjectTo = (TemplateObjectTO)srcDataTo; + String storeUrl = srcImageStore.getUrl(); URI uri = new URI(storeUrl); - String tmplpath = uri.getHost() + ":" + uri.getPath() + "/" + srcData.getPath(); - String poolName = destData.getDataStore().getUuid(); + String tmplPath = uri.getHost() + ":" + uri.getPath() + "/" + srcDataTo.getPath(); + DataStoreTO destDataStoreTo = destDataTo.getDataStore(); + + boolean managed = false; + String storageHost = null; + String managedStoragePoolName = null; + String managedStoragePoolRootVolumeName = null; + String managedStoragePoolRootVolumeSize = null; + String chapInitiatorUsername = null; + String chapInitiatorSecret = null; + + if (destDataStoreTo instanceof PrimaryDataStoreTO) { + PrimaryDataStoreTO destPrimaryDataStoreTo = (PrimaryDataStoreTO)destDataStoreTo; + + Map details = destPrimaryDataStoreTo.getDetails(); + + if (details != null) { + managed = Boolean.parseBoolean(details.get(PrimaryDataStoreTO.MANAGED)); + + if (managed) { + storageHost = details.get(PrimaryDataStoreTO.STORAGE_HOST); + managedStoragePoolName = details.get(PrimaryDataStoreTO.MANAGED_STORE_TARGET); + managedStoragePoolRootVolumeName = details.get(PrimaryDataStoreTO.MANAGED_STORE_TARGET_ROOT_VOLUME); + managedStoragePoolRootVolumeSize = details.get(PrimaryDataStoreTO.VOLUME_SIZE); + chapInitiatorUsername = details.get(PrimaryDataStoreTO.CHAP_INITIATOR_USERNAME); + chapInitiatorSecret = details.get(PrimaryDataStoreTO.CHAP_INITIATOR_SECRET); + } + } + } + Connection conn = hypervisorResource.getConnection(); - SR poolsr = null; - Set srs = SR.getByNameLabel(conn, poolName); - if (srs.size() != 1) { - String msg = "There are " + srs.size() + " SRs with same name: " + poolName; - s_logger.warn(msg); - return new CopyCmdAnswer(msg); - } else { - poolsr = srs.iterator().next(); + final SR sr; + + if (managed) { + Map details = new HashMap(); + + details.put(DiskTO.STORAGE_HOST, storageHost); + details.put(DiskTO.IQN, managedStoragePoolName); + details.put(DiskTO.VOLUME_SIZE, managedStoragePoolRootVolumeSize); + details.put(DiskTO.CHAP_INITIATOR_USERNAME, chapInitiatorUsername); + details.put(DiskTO.CHAP_INITIATOR_SECRET, chapInitiatorSecret); + + sr = hypervisorResource.prepareManagedSr(conn, details); } - String pUuid = poolsr.getUuid(conn); - boolean isISCSI = IsISCSI(poolsr.getType(conn)); - String uuid = copy_vhd_from_secondarystorage(conn, tmplpath, pUuid, wait); - VDI tmpl = getVDIbyUuid(conn, uuid); - VDI snapshotvdi = tmpl.snapshot(conn, new HashMap()); - String snapshotUuid = snapshotvdi.getUuid(conn); - snapshotvdi.setNameLabel(conn, "Template " + srcTemplate.getName()); - String parentuuid = getVhdParent(conn, pUuid, snapshotUuid, isISCSI); - VDI parent = getVDIbyUuid(conn, parentuuid); - Long phySize = parent.getPhysicalUtilisation(conn); - tmpl.destroy(conn); - poolsr.scan(conn); + else { + String srName = destDataStoreTo.getUuid(); + Set srs = SR.getByNameLabel(conn, srName); + + if (srs.size() != 1) { + String msg = "There are " + srs.size() + " SRs with same name: " + srName; + + s_logger.warn(msg); + + return new CopyCmdAnswer(msg); + } else { + sr = srs.iterator().next(); + } + } + + String srUuid = sr.getUuid(conn); + String tmplUuid = copy_vhd_from_secondarystorage(conn, tmplPath, srUuid, wait); + VDI tmplVdi = getVDIbyUuid(conn, tmplUuid); + + final String uuidToReturn; + + if (managed) { + uuidToReturn = tmplUuid; + + tmplVdi.setNameLabel(conn, managedStoragePoolRootVolumeName); + } + else { + VDI snapshotVdi = tmplVdi.snapshot(conn, new HashMap()); + + uuidToReturn = snapshotVdi.getUuid(conn); + + snapshotVdi.setNameLabel(conn, "Template " + srcTemplateObjectTo.getName()); + + tmplVdi.destroy(conn); + } + + sr.scan(conn); + try { Thread.sleep(5000); } catch (Exception e) { } TemplateObjectTO newVol = new TemplateObjectTO(); - newVol.setUuid(snapshotvdi.getUuid(conn)); - newVol.setPath(newVol.getUuid()); + + newVol.setUuid(uuidToReturn); + newVol.setPath(uuidToReturn); newVol.setFormat(ImageFormat.VHD); + return new CopyCmdAnswer(newVol); } } catch (Exception e) { String msg = "Catch Exception " + e.getClass().getName() + " for template + " + " due to " + e.toString(); + s_logger.warn(msg, e); + return new CopyCmdAnswer(msg); } + return new CopyCmdAnswer("not implemented yet"); } diff --git a/plugins/hypervisors/xen/src/org/apache/cloudstack/storage/motion/XenServerStorageMotionStrategy.java b/plugins/hypervisors/xen/src/org/apache/cloudstack/storage/motion/XenServerStorageMotionStrategy.java index e8217f7216f..975deec531f 100644 --- a/plugins/hypervisors/xen/src/org/apache/cloudstack/storage/motion/XenServerStorageMotionStrategy.java +++ b/plugins/hypervisors/xen/src/org/apache/cloudstack/storage/motion/XenServerStorageMotionStrategy.java @@ -90,6 +90,11 @@ public class XenServerStorageMotionStrategy implements DataMotionStrategy { return StrategyPriority.CANT_HANDLE; } + @Override + public Void copyAsync(DataObject srcData, DataObject destData, Host destHost, AsyncCompletionCallback callback) { + throw new UnsupportedOperationException(); + } + @Override public Void copyAsync(DataObject srcData, DataObject destData, AsyncCompletionCallback callback) { CopyCommandResult result = new CopyCommandResult(null, null); diff --git a/server/src/com/cloud/configuration/ConfigurationManagerImpl.java b/server/src/com/cloud/configuration/ConfigurationManagerImpl.java index 283aeeaf5a5..08cc5a63f50 100755 --- a/server/src/com/cloud/configuration/ConfigurationManagerImpl.java +++ b/server/src/com/cloud/configuration/ConfigurationManagerImpl.java @@ -2016,15 +2016,54 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati return createServiceOffering(userId, cmd.getIsSystem(), vmType, cmd.getServiceOfferingName(), cpuNumber, memory, cpuSpeed, cmd.getDisplayText(), localStorageRequired, offerHA, limitCpuUse, volatileVm, cmd.getTags(), cmd.getDomainId(), cmd.getHostTag(), cmd.getNetworkRate(), cmd.getDeploymentPlanner(), cmd.getDetails(), - cmd.getBytesReadRate(), cmd.getBytesWriteRate(), cmd.getIopsReadRate(), cmd.getIopsWriteRate()); + cmd.isCustomizedIops(), cmd.getMinIops(), cmd.getMaxIops(), cmd.getBytesReadRate(), cmd.getBytesWriteRate(), cmd.getIopsReadRate(), cmd.getIopsWriteRate(), + cmd.getHypervisorSnapshotReserve()); } protected ServiceOfferingVO createServiceOffering(long userId, boolean isSystem, VirtualMachine.Type vmType, String name, Integer cpu, Integer ramSize, Integer speed, String displayText, boolean localStorageRequired, boolean offerHA, boolean limitResourceUse, boolean volatileVm, String tags, Long domainId, String hostTag, - Integer networkRate, String deploymentPlanner, Map details, Long bytesReadRate, Long bytesWriteRate, Long iopsReadRate, Long iopsWriteRate) { + Integer networkRate, String deploymentPlanner, Map details, Boolean isCustomizedIops, Long minIops, Long maxIops, + Long bytesReadRate, Long bytesWriteRate, Long iopsReadRate, Long iopsWriteRate, Integer hypervisorSnapshotReserve) { tags = StringUtils.cleanupTags(tags); ServiceOfferingVO offering = new ServiceOfferingVO(name, cpu, ramSize, speed, networkRate, null, offerHA, limitResourceUse, volatileVm, displayText, localStorageRequired, false, tags, isSystem, vmType, domainId, hostTag, deploymentPlanner); + + if (isCustomizedIops != null) { + bytesReadRate = null; + bytesWriteRate = null; + iopsReadRate = null; + iopsWriteRate = null; + + if (isCustomizedIops) { + minIops = null; + maxIops = null; + } else { + if (minIops == null && maxIops == null) { + minIops = 0L; + maxIops = 0L; + } else { + if (minIops == null || minIops <= 0) { + throw new InvalidParameterValueException("The min IOPS must be greater than 0."); + } + + if (maxIops == null) { + maxIops = 0L; + } + + if (minIops > maxIops) { + throw new InvalidParameterValueException("The min IOPS must be less than or equal to the max IOPS."); + } + } + } + } else { + minIops = null; + maxIops = null; + } + + offering.setCustomizedIops(isCustomizedIops); + offering.setMinIops(minIops); + offering.setMaxIops(maxIops); + if ((bytesReadRate != null) && (bytesReadRate > 0)) offering.setBytesReadRate(bytesReadRate); if ((bytesWriteRate != null) && (bytesWriteRate > 0)) @@ -2034,6 +2073,12 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati if ((iopsWriteRate != null) && (iopsWriteRate > 0)) offering.setIopsWriteRate(iopsWriteRate); + if (hypervisorSnapshotReserve != null && hypervisorSnapshotReserve < 0) { + throw new InvalidParameterValueException("If provided, Hypervisor Snapshot Reserve must be greater than or equal to 0."); + } + + offering.setHypervisorSnapshotReserve(hypervisorSnapshotReserve); + if ((offering = _serviceOfferingDao.persist(offering)) != null) { if (details != null) { List detailsVO = new ArrayList(); diff --git a/ui/scripts/configuration.js b/ui/scripts/configuration.js index 869b876865c..cb54c318135 100644 --- a/ui/scripts/configuration.js +++ b/ui/scripts/configuration.js @@ -136,6 +136,113 @@ number: true } }, + qosType: { + label: 'label.qos.type', + docID: 'helpDiskOfferingQoSType', + select: function(args) { + var items = []; + items.push({ + id: '', + description: '' + }); + items.push({ + id: 'hypervisor', + description: 'hypervisor' + }); + items.push({ + id: 'storage', + description: 'storage' + }); + args.response.success({ + data: items + }); + + args.$select.change(function() { + var $form = $(this).closest('form'); + var $isCustomizedIops = $form.find('.form-item[rel=isCustomizedIops]'); + var $minIops = $form.find('.form-item[rel=minIops]'); + var $maxIops = $form.find('.form-item[rel=maxIops]'); + var $hypervisorSnapshotReserve = $form.find('.form-item[rel=hypervisorSnapshotReserve]'); + var $diskBytesReadRate = $form.find('.form-item[rel=diskBytesReadRate]'); + var $diskBytesWriteRate = $form.find('.form-item[rel=diskBytesWriteRate]'); + var $diskIopsReadRate = $form.find('.form-item[rel=diskIopsReadRate]'); + var $diskIopsWriteRate = $form.find('.form-item[rel=diskIopsWriteRate]'); + + var qosId = $(this).val(); + + if (qosId == 'storage') { // Storage QoS + $diskBytesReadRate.hide(); + $diskBytesWriteRate.hide(); + $diskIopsReadRate.hide(); + $diskIopsWriteRate.hide(); + + $isCustomizedIops.css('display', 'inline-block'); + + if ($isCustomizedIops.find('input[type=checkbox]').is(':checked')) { + $minIops.hide(); + $maxIops.hide(); + } else { + $minIops.css('display', 'inline-block'); + $maxIops.css('display', 'inline-block'); + } + + $hypervisorSnapshotReserve.css('display', 'inline-block'); + } else if (qosId == 'hypervisor') { // Hypervisor Qos + $isCustomizedIops.hide(); + $minIops.hide(); + $maxIops.hide(); + $hypervisorSnapshotReserve.hide(); + + $diskBytesReadRate.css('display', 'inline-block'); + $diskBytesWriteRate.css('display', 'inline-block'); + $diskIopsReadRate.css('display', 'inline-block'); + $diskIopsWriteRate.css('display', 'inline-block'); + } else { // No Qos + $diskBytesReadRate.hide(); + $diskBytesWriteRate.hide(); + $diskIopsReadRate.hide(); + $diskIopsWriteRate.hide(); + $isCustomizedIops.hide(); + $minIops.hide(); + $maxIops.hide(); + $hypervisorSnapshotReserve.hide(); + } + }); + } + }, + isCustomizedIops: { + label: 'label.custom.disk.iops', + docID: 'helpDiskOfferingCustomDiskIops', + isBoolean: true, + isReverse: true, + isChecked: false + }, + minIops: { + label: 'label.disk.iops.min', + docID: 'helpDiskOfferingDiskIopsMin', + dependsOn: 'isCustomizedIops', + validation: { + required: false, + number: true + } + }, + maxIops: { + label: 'label.disk.iops.max', + docID: 'helpDiskOfferingDiskIopsMax', + dependsOn: 'isCustomizedIops', + validation: { + required: false, + number: true + } + }, + hypervisorSnapshotReserve: { + label: 'label.hypervisor.snapshot.reserve', + docID: 'helpDiskOfferingHypervisorSnapshotReserve', + validation: { + required: false, + number: true + } + }, diskBytesReadRate: { label: 'label.disk.bytes.read.rate', docID: 'helpComputeOfferingDiskBytesReadRate', @@ -326,26 +433,59 @@ networkrate: args.data.networkRate }); } - if (args.data.diskBytesReadRate != null && args.data.diskBytesReadRate.length > 0) { + + if (args.data.qosType == 'storage') { + var customIops = args.data.isCustomizedIops == "on"; + $.extend(data, { - bytesreadrate: args.data.diskBytesReadRate - }); - } - if (args.data.diskBytesWriteRate != null && args.data.diskBytesWriteRate.length > 0) { - $.extend(data, { - byteswriterate: args.data.diskBytesWriteRate - }); - } - if (args.data.diskIopsReadRate != null && args.data.diskIopsReadRate.length > 0) { - $.extend(data, { - iopsreadrate: args.data.diskIopsReadRate - }); - } - if (args.data.diskIopsWriteRate != null && args.data.diskIopsWriteRate.length > 0) { - $.extend(data, { - iopswriterate: args.data.diskIopsWriteRate + customizediops: customIops }); + + if (!customIops) { + if (args.data.minIops != null && args.data.minIops.length > 0) { + $.extend(data, { + miniops: args.data.minIops + }); + } + + if (args.data.maxIops != null && args.data.maxIops.length > 0) { + $.extend(data, { + maxiops: args.data.maxIops + }); + } + } + + if (args.data.hypervisorSnapshotReserve != null && args.data.hypervisorSnapshotReserve.length > 0) { + $.extend(data, { + hypervisorsnapshotreserve: args.data.hypervisorSnapshotReserve + }); + } + } else if (args.data.qosType == 'hypervisor') { + if (args.data.diskBytesReadRate != null && args.data.diskBytesReadRate.length > 0) { + $.extend(data, { + bytesreadrate: args.data.diskBytesReadRate + }); + } + + if (args.data.diskBytesWriteRate != null && args.data.diskBytesWriteRate.length > 0) { + $.extend(data, { + byteswriterate: args.data.diskBytesWriteRate + }); + } + + if (args.data.diskIopsReadRate != null && args.data.diskIopsReadRate.length > 0) { + $.extend(data, { + iopsreadrate: args.data.diskIopsReadRate + }); + } + + if (args.data.diskIopsWriteRate != null && args.data.diskIopsWriteRate.length > 0) { + $.extend(data, { + iopswriterate: args.data.diskIopsWriteRate + }); + } } + $.extend(data, { offerha: (args.data.offerHA == "on") }); From e1e554277a10a4e881aaf032d906cadcd4bd3afc Mon Sep 17 00:00:00 2001 From: Brian Federle Date: Wed, 5 Mar 2014 13:34:48 -0800 Subject: [PATCH 04/70] UI Dialog: Was passing wrong field data for makeFields event --- ui/scripts/ui/dialog.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ui/scripts/ui/dialog.js b/ui/scripts/ui/dialog.js index 5f0697ac032..82e7fd428c2 100644 --- a/ui/scripts/ui/dialog.js +++ b/ui/scripts/ui/dialog.js @@ -72,7 +72,7 @@ $(window).trigger('cloudStack.createForm.makeFields', { $form: $form, - fields: fields + fields: args.form.fields }); var ret = function() { From 182c31899bb353eac66a43ca4e81117c4fd06332 Mon Sep 17 00:00:00 2001 From: vetrivelc Date: Wed, 5 Mar 2014 14:21:23 +0530 Subject: [PATCH 05/70] Externalized the hardcodedstrings from UI JAVASCRIPT files. --- .../classes/resources/messages.properties | 209 ++++++ .../resources/messages_ja_JP.properties | 272 +++++++- .../resources/messages_zh_CN.properties | 572 +++++++++++----- tools/ngui/static/js/app/accounts/accounts.js | 16 +- tools/ngui/static/js/app/storage/storage.js | 2 +- ui/dictionary.jsp | 220 +++++- .../vnmcNetworkProvider.js | 50 +- ui/scripts/configuration.js | 58 +- ui/scripts/installWizard.js | 6 +- ui/scripts/instances.js | 20 +- ui/scripts/network.js | 62 +- ui/scripts/sharedFunctions.js | 28 +- ui/scripts/storage.js | 6 +- ui/scripts/system.js | 634 +++++++++--------- ui/scripts/templates.js | 6 +- ui/scripts/ui-custom/zoneChart.js | 16 +- ui/scripts/ui/core.js | 2 +- ui/scripts/ui/widgets/tagger.js | 4 +- ui/scripts/vpc.js | 16 +- ui/scripts/zoneWizard.js | 12 +- 20 files changed, 1519 insertions(+), 692 deletions(-) diff --git a/client/WEB-INF/classes/resources/messages.properties b/client/WEB-INF/classes/resources/messages.properties index 82ac499a85e..cb4d29297d2 100644 --- a/client/WEB-INF/classes/resources/messages.properties +++ b/client/WEB-INF/classes/resources/messages.properties @@ -1291,6 +1291,7 @@ label.add.gslb=Add GSLB label.gslb.servicetype=Service Type label.gslb.details=GSLB details label.gslb.delete=delete GSLB +label.opendaylight.controller=OpenDaylight Controller label.opendaylight.controllers=OpenDaylight Controllers label.portable.ip.ranges=Portable IP Ranges label.add.portable.ip.range=Add Portable IP Range @@ -1319,6 +1320,167 @@ label.add.ucs.manager=Add UCS Manager label.ovm.traffic.label=OVM traffic label label.lxc.traffic.label=LXC Traffic Label label.hyperv.traffic.label=HyperV Traffic Label +label.resource.name=Resource Name +label.reource.id=Resource ID +label.vnmc.devices=VNMC Devices +label.add.vnmc.provider=Add VNMC provider +label.enable.vnmc.provider=Enable VNMC provider +label.add.vnmc.device=Add VNMC device +label.ciscovnmc.resource.details=CiscoVNMC resource details +label.delete.ciscovnmc.resource=delete CiscoVNMC resource +label.enable.vnmc.device=Enable VNMC device +label.disbale.vnmc.device=Disable VNMC device +label.disable.vnmc.provider=Disable VNMC provider +label.services=Services +label.secondary.staging.store=Secondary Staging Store +label.release.account=Release from Account +label.release.account.lowercase=release from account +label.vlan.vni.ranges=VLAN/VNI Range(s) +label.dedicated.vlan.vni.ranges=Dedicated VLAN/VNI Ranges +label.dedicate.vlan.vni.range=Dedicate VLAN/VNI Range +label.vlan.vni.range=VLAN/VNI Range +label.vlan.range.details=VLAN Range details +label.release.dedicated.vlan.range=Release dedicated VLAN range +label.broadcat.uri=broadcast URI +label.ipv4.cidr=IPv4 CIDR +label.guest.network.details=Guest network details +label.ipv4.gateway=IPv4 Gateway +label.release.dedicated.vlan.range=Release dedicated VLAN range +label.vlan.ranges=VLAN Range(s) +label.virtual.appliance.details=Virtual applicance details +label.start.lb.vm=Start LB VM +label.stop.lb.vm=Stop LB VM +label.migrate.lb.vm=Migrate LB VM +label.vpc.virtual.router=VPC Virtual Router +label.ovs=OVS +label.gslb.service=GSLB service +label.gslb.service.public.ip=GSLB service Public IP +label.gslb.service.private.ip=GSLB service Private IP +label.baremetal.dhcp.provider=Baremetal DHCP Provider +label.add.baremetal.dhcp.device=Add Baremetal DHCP Device +label.baremetal.pxe.provider=Baremetal PXE Provider +label.baremetal.pxe.device=Add Baremetal PXE Device +label.tftp.root.directory=Tftp root directory +label.add.vmware.datacenter=Add VMware datacenter +label.remove.vmware.datacenter=Remove VMware datacenter +label.dc.name=DC Name +label.vcenter=vcenter +label.dedicate.zone=Dedicate Zone +label.zone.dedicated=Zone Dedicated +label.release.dedicated.zone=Release Dedicated Zone +label.ipv6.dns1=IPv6 DNS1 +label.ipv6.dns2=IPv6 DNS2 +label.vmware.datacenter.name=VMware datacenter Name +label.vmware.datacenter.vcenter=VMware datacenter vcenter +label.vmware.datacenter.id=VMware datacenter ID +label.system.vm.details=System VM details +label.system.vm.scaled.up=System VM Scaled Up +label.console.proxy.vm=Console Proxy VM +label.settings=Settings +label.requires.upgrade=Requires Upgrade +label.upgrade.router.newer.template=Upgrade Router to Use Newer Template +label.router.vm.scaled.up=Router VM Scaled Up +label.total.virtual.routers=Total of Virtual Routers +label.upgrade.required=Upgrade is required +label.virtual.routers.group.zone=Virtual Routers group by zone +label.total.virtual.routers.upgrade=Total of Virtual Routers that require upgrade +label.virtual.routers.group.pod=Virtual Routers group by pod +label.virtual.routers.group.cluster=Virtual Routers group by cluster +label.zone.lower=zone +label.virtual.routers.group.account=Virtual Routers group by account +label.netscaler.details=NetScaler details +label.baremetal.dhcp.devices=Baremetal DHCP Devices +label.baremetal.pxe.devices=Baremetal PXE Devices +label.addes.new.f5=Added new F5 +label.f5.details=F5 details +label.srx.details=SRX details +label.palo.alto.details=Palo Alto details +label.added.nicira.nvp.controller=Added new Nicira NVP Controller\ +label.nicira.nvp.details=Nicira NVP details +label.added.new.bigswitch.vns.controller=Added new BigSwitch VNS Controller +label.bigswitch.vns.details=BigSwitch VNS details +label.dedicate=Dedicate +label.dedicate.pod=Dedicate Pod +label.pod.dedicated=Pod Dedicated +label.release.dedicated.pod=Release Dedicated Pod +label.override.public.traffic=Override Public-Traffic +label.public.traffic.vswitch.type=Public Traffic vSwitch Type +label.public.traffic.vswitch.name=Public Traffic vSwitch Name +label.override.guest.traffic=Override Guest-Traffic +label.guest.traffic.vswitch.type=Guest Traffic vSwitch Type +label.guest.traffic.vswitch.name=Guest Traffic vSwitch Name +label.cisco.nexus1000v.ip.address=Nexus 1000v IP Address +label.cisco.nexus1000v.username=Nexus 1000v Username +label.cisco.nexus1000v.password=Nexus 1000v Password +label.dedicate.cluster=Dedicate Cluster +label.release.dedicated.cluster=Release Dedicated Cluster +label.dedicate.host=Dedicate Host +label.release.dedicated.host=Release Dedicated Host +label.number.of.cpu.sockets=The Number of CPU Sockets +label.delete.ucs.manager=Delete UCS Manager +label.blades=Blades +label.chassis=Chassis +label.blade.id=Blade ID +label.associated.profile=Associated Profile +label.refresh.blades=Refresh Blades +label.instanciate.template.associate.profile.blade=Instanciate Template and Associate Profile to Blade +label.select.template=Select Template +label.profile=Profile +label.delete.profile=Delete Profile +label.disassociate.profile.blade=Disassociate Profile from Blade +label.secondary.storage.details=Secondary storage details +label.secondary.staging.store.details=Secondary Staging Store details +label.add.nfs.secondary.staging.store=Add NFS Secondary Staging Store +label.delete.secondary.staging.store=Delete Secondary Staging Store +label.ipv4.start.ip=IPv4 Start IP +label.ipv4.end.ip=IPv4 End IP +label.ipv6.start.ip=IPv6 Start IP +label.ipv6.end.ip=IPv6 End IP +label.vm.password=Password of the VM is +label.group.by.zone=group by zone +label.group.by.pod=group by pod +label.group.by.cluster=group by cluster +label.group.by.account=group by account +label.no.grouping=(no grouping)\ +label.create.nfs.secondary.staging.storage=Create NFS Secondary Staging Store +label.username.lower=username +label.password.lower=password +label.email.lower=email +label.firstname.lower=firstname +label.lastname.lower=lastname +label.domain.lower=domain +label.account.lower=account +label.type.lower=type +label.rule.number=Rule Number +label.action=Action +label.name.lower=name +label.ucs=UCS +label.change.affinity=Change Affinity +label.persistent=Persistent +label.broadcasturi=broadcasturi +label.network.cidr=Network CIDR +label.reserved.ip.range=Reserved IP Range +label.autoscale=AutoScale +label.health.check=Health Check +label.public.load.balancer.provider=Public Load Balancer Provider +label.add.isolated.network=Add Isolated Network +label.vlan=VLAN +label.secondary.isolated.vlan.id=Secondary Isolated VLAN ID +label.ipv4.netmask=IPv4 Netmask +label.custom=Custom +label.disable.network.offering=Disable network offering +label.enable.network.offering=Enable network offering +label.remove.network.offering=Remove network offering +label.system.offering.for.router=System Offering for Router +label.mode=Mode +label.associate.public.ip=Associate Public IP +label.acl=ACL +label.user.data=User Data +label.virtual.networking=Virtual Networking +label.allow=Allow +label.deny=Deny +label.default.egress.policy=Default egress policy +label.xenserver.tools.version.61.plus=XenServer Tools Version 6.1\+ managed.state=Managed State message.acquire.new.ip.vpc=Please confirm that you would like to acquire a new IP for this VPC. message.acquire.new.ip=Please confirm that you would like to acquire a new IP for this network. @@ -1669,6 +1831,53 @@ message.tier.required=Tier is required message.remove.ldap=Are you sure you want to delete the LDAP configuration? message.action.downloading.template=Downloading template. message.configure.ldap=Please confirm you would like to configure LDAP. +message.confirm.delete.ciscovnmc.resource=Please confirm you want to delete CiscoVNMC resource +message.confirm.add.vnmc.provider=Please confirm you would like to add the VNMC provider. +message.confirm.enable.vnmc.provider=Please confirm you would like to enable the VNMC provider. +message.confirm.disable.vnmc.provider=Please confirm you would like to disable the VNMC provider. +message.vnmc.available.list=VNMC is not available from provider list. +message.vnmc.not.available.list=VNMC is not available from provider list. +message.confirm.release.dedicate.vlan.range=Please confirm you want to release dedicated VLAN range +message.confirm.start.lb.vm=Please confirm you want to start LB VM +message.confirm.stop.lb.vm=Please confirm you want to stop LB VM +message.confirm.remove.vmware.datacenter=Please confirm you want to remove VMware datacenter +message.confirm.dedicate.zone=Do you really want to dedicate this zone to a domain/account? +message.confirm.release.dedicated.zone=Do you want to release this dedicated zone ? +message.dedicated.zone.released=Zone dedication released +message.read.admin.guide.scaling.up=Please read the dynamic scaling section in the admin guide before scaling up. +message.confirm.scale.up.system.vm=Do you really want to scale up the system VM ? +message.confirm.upgrade.router.newer.template=Please confirm that you want to upgrade router to use newer template +message.confirm.scale.up.router.vm=Do you really want to scale up the Router VM ? +message.confirm.upgrade.routers.newtemplate=Please confirm that you want to upgrade all routers in this zone to use newer template +message.confirm.upgrade.routers.pod.newtemplate=Please confirm that you want to upgrade all routers in this pod to use newer template +message.confirm.upgrade.routers.cluster.newtemplate=Please confirm that you want to upgrade all routers in this cluster to use newer template +message.confirm.upgrade.routers.account.newtemplate=Please confirm that you want to upgrade all routers in this account to use newer template +message.confirm.dedicate.pod.domain.account=Do you really want to dedicate this pod to a domain/account? +message.confirm.release.dedicated.pod=Do you want to release this dedicated pod ? +message.pod.dedication.released=Pod dedication released +message.confirm.dedicate.cluster.domain.account=Do you really want to dedicate this cluster to a domain/account? +message.cluster.dedicated=Cluster Dedicated +message.confirm.release.dedicated.cluster=Do you want to release this dedicated cluster ? +message.cluster.dedication.released=Cluster dedication released +message.confirm.dedicate.host.domain.account=Do you really want to dedicate this host to a domain/account? +message.host.dedicated=Host Dedicated +message.confirm.release.dedicated.host=Do you want to release this dedicated host ? +message.host.dedication.released=Host dedication released +message.confirm.delete.ucs.manager=Please confirm that you want to delete UCS Manager +message.confirm.refresh.blades=Please confirm that you want to refresh blades. +message.confirm.delete.secondary.staging.store=Please confirm you want to delete Secondary Staging Store. +message.select.tier=Please select a tier +message.disallowed.characters=Disallowed characters: \<\,\> +message.waiting.for.builtin.templates.to.load=Waiting for builtin templates to load... +message.systems.vms.ready=System VMs ready. +message.your.cloudstack.is.ready=Your CloudStack is ready\! +message.specifiy.tag.key.value=Please specify a tag key and value +message.enter.seperated.list.multiple.cidrs=Please enter a comma separated list of CIDRs if more than one +message.disabling.network.offering=Disabling network offering +message.confirm.enable.network.offering=Are you sure you want to enable this network offering? +message.enabling.network.offering=Enabling network offering +message.confirm.remove.network.offering=Are you sure you want to remove this network offering? +message.confirm.disable.network.offering=Are you sure you want to disable this network offering? mode=Mode network.rate=Network Rate notification.reboot.instance=Reboot instance diff --git a/client/WEB-INF/classes/resources/messages_ja_JP.properties b/client/WEB-INF/classes/resources/messages_ja_JP.properties index 828cf545c20..da4851a163b 100644 --- a/client/WEB-INF/classes/resources/messages_ja_JP.properties +++ b/client/WEB-INF/classes/resources/messages_ja_JP.properties @@ -29,7 +29,7 @@ label.smb.password=SMB \u30d1\u30b9\u30ef\u30fc\u30c9 label.smb.domain=SMB \u30c9\u30e1\u30a4\u30f3 label.hypervisors=\u30cf\u30a4\u30d1\u30fc\u30d0\u30a4\u30b6\u30fc label.home=\u30db\u30fc\u30e0 -label.sockets=CPU Sockets +label.sockets=CPU \u30bd\u30b1\u30c3\u30c8 label.root.disk.size=\u30eb\u30fc\u30c8 \u30c7\u30a3\u30b9\u30af \u30b5\u30a4\u30ba label.s3.nfs.server=S3 NFS \u30b5\u30fc\u30d0\u30fc label.s3.nfs.path=S3 NFS \u30d1\u30b9 @@ -63,7 +63,7 @@ message.action.delete.nic=\u3053\u306e NIC \u3092\u524a\u9664\u3057\u3066\u3082\ changed.item.properties=\u9805\u76ee\u306e\u30d7\u30ed\u30d1\u30c6\u30a3\u306e\u5909\u66f4 confirm.enable.s3=S3 \u30d9\u30fc\u30b9\u306e\u30bb\u30ab\u30f3\u30c0\u30ea \u30b9\u30c8\u30ec\u30fc\u30b8\u306e\u30b5\u30dd\u30fc\u30c8\u3092\u6709\u52b9\u306b\u3059\u308b\u306b\u306f\u3001\u6b21\u306e\u60c5\u5831\u3092\u5165\u529b\u3057\u3066\u304f\u3060\u3055\u3044\u3002 confirm.enable.swift=Swift \u306e\u30b5\u30dd\u30fc\u30c8\u3092\u6709\u52b9\u306b\u3059\u308b\u306b\u306f\u3001\u6b21\u306e\u60c5\u5831\u3092\u5165\u529b\u3057\u3066\u304f\u3060\u3055\u3044\u3002 -error.could.not.change.your.password.because.ldap.is.enabled=Error could not change your password because LDAP is enabled. +error.could.not.change.your.password.because.ldap.is.enabled=\u30a8\u30e9\u30fc\u3002LDAP \u304c\u6709\u52b9\u306a\u305f\u3081\u30d1\u30b9\u30ef\u30fc\u30c9\u3092\u5909\u66f4\u3067\u304d\u307e\u305b\u3093\u3002 error.could.not.enable.zone=\u30be\u30fc\u30f3\u3092\u6709\u52b9\u306b\u3067\u304d\u307e\u305b\u3093\u3067\u3057\u305f error.installWizard.message=\u554f\u984c\u304c\u767a\u751f\u3057\u307e\u3057\u305f\u3002\u623b\u3063\u3066\u30a8\u30e9\u30fc\u3092\u4fee\u6b63\u3067\u304d\u307e\u3059\u3002 error.invalid.username.password=\u7121\u52b9\u306a\u30e6\u30fc\u30b6\u30fc\u540d\u307e\u305f\u306f\u30d1\u30b9\u30ef\u30fc\u30c9\u3067\u3059\u3002 @@ -384,8 +384,8 @@ label.api.key=API \u30ad\u30fc label.apply=\u9069\u7528 label.assign.to.load.balancer=\u8ca0\u8377\u5206\u6563\u88c5\u7f6e\u306b\u30a4\u30f3\u30b9\u30bf\u30f3\u30b9\u3092\u5272\u308a\u5f53\u3066\u3066\u3044\u307e\u3059 label.assign=\u5272\u308a\u5f53\u3066 -label.associated.network.id=\u95a2\u9023\u3065\u3051\u3089\u308c\u305f\u30cd\u30c3\u30c8\u30ef\u30fc\u30af ID -label.associated.network=\u95a2\u9023\u3065\u3051\u3089\u308c\u305f\u30cd\u30c3\u30c8\u30ef\u30fc\u30af +label.associated.network.id=\u95a2\u9023\u4ed8\u3051\u3089\u308c\u305f\u30cd\u30c3\u30c8\u30ef\u30fc\u30af ID +label.associated.network=\u95a2\u9023\u4ed8\u3051\u3089\u308c\u305f\u30cd\u30c3\u30c8\u30ef\u30fc\u30af label.attached.iso=\u30a2\u30bf\u30c3\u30c1\u3055\u308c\u305f ISO label.author.email=\u4f5c\u6210\u8005\u306e\u96fb\u5b50\u30e1\u30fc\u30eb label.author.name=\u4f5c\u6210\u8005\u306e\u540d\u524d @@ -601,6 +601,7 @@ label.full=\u5b8c\u5168 label.gateway=\u30b2\u30fc\u30c8\u30a6\u30a7\u30a4 label.general.alerts=\u4e00\u822c\u30a2\u30e9\u30fc\u30c8 label.generating.url=URL \u3092\u751f\u6210\u3057\u3066\u3044\u307e\u3059 +label.gluster.volume=\u30dc\u30ea\u30e5\u30fc\u30e0 label.go.step.2=\u624b\u9806 2 \u306b\u9032\u3080 label.go.step.3=\u624b\u9806 3 \u306b\u9032\u3080 label.go.step.4=\u624b\u9806 4 \u306b\u9032\u3080 @@ -704,7 +705,7 @@ label.lang.arabic=\u30a2\u30e9\u30d3\u30a2\u8a9e label.lang.brportugese=\u30dd\u30eb\u30c8\u30ac\u30eb\u8a9e (\u30d6\u30e9\u30b8\u30eb) label.lang.catalan=\u30ab\u30bf\u30eb\u30cb\u30a2\u8a9e label.lang.chinese=\u7c21\u4f53\u5b57\u4e2d\u56fd\u8a9e -label.lang.dutch=Dutch (Netherlands) +label.lang.dutch=\u30aa\u30e9\u30f3\u30c0\u8a9e (\u30aa\u30e9\u30f3\u30c0) label.lang.english=\u82f1\u8a9e label.lang.french=\u30d5\u30e9\u30f3\u30b9\u8a9e label.lang.german=\u30c9\u30a4\u30c4\u8a9e @@ -712,7 +713,7 @@ label.lang.italian=\u30a4\u30bf\u30ea\u30a2\u8a9e label.lang.japanese=\u65e5\u672c\u8a9e label.lang.korean=\u97d3\u56fd\u8a9e label.lang.norwegian=\u30ce\u30eb\u30a6\u30a7\u30fc\u8a9e -label.lang.polish=Polish +label.lang.polish=\u30dd\u30fc\u30e9\u30f3\u30c9\u8a9e label.lang.russian=\u30ed\u30b7\u30a2\u8a9e label.lang.spanish=\u30b9\u30da\u30a4\u30f3\u8a9e label.last.disconnected=\u6700\u7d42\u5207\u65ad\u65e5\u6642 @@ -1067,7 +1068,7 @@ label.source=\u9001\u4fe1\u5143 label.specify.IP.ranges=IP \u30a2\u30c9\u30ec\u30b9\u306e\u7bc4\u56f2\u306e\u6307\u5b9a label.specify.vlan=VLAN \u3092\u6307\u5b9a\u3059\u308b label.specify.vxlan=VXLAN \u3092\u6307\u5b9a\u3059\u308b -label.SR.name = SR Name-Label +label.SR.name=SR \u540d\u30e9\u30d9\u30eb label.srx=SRX label.PA=Palo Alto label.start.IP=\u958b\u59cb IP \u30a2\u30c9\u30ec\u30b9 @@ -1111,7 +1112,7 @@ label.storage.tags=\u30b9\u30c8\u30ec\u30fc\u30b8 \u30bf\u30b0 label.storage.traffic=\u30b9\u30c8\u30ec\u30fc\u30b8 \u30c8\u30e9\u30d5\u30a3\u30c3\u30af label.storage.type=\u30b9\u30c8\u30ec\u30fc\u30b8\u306e\u7a2e\u985e label.qos.type=QoS \u306e\u7a2e\u985e -label.cache.mode=Write-cache Type +label.cache.mode=\u66f8\u304d\u8fbc\u307f\u30ad\u30e3\u30c3\u30b7\u30e5\u306e\u7a2e\u985e label.storage=\u30b9\u30c8\u30ec\u30fc\u30b8 label.subdomain.access=\u30b5\u30d6\u30c9\u30e1\u30a4\u30f3 \u30a2\u30af\u30bb\u30b9 label.submit=\u9001\u4fe1 @@ -1144,7 +1145,7 @@ label.tier.details=\u968e\u5c64\u306e\u8a73\u7d30 label.tier=\u968e\u5c64 label.time.zone=\u30bf\u30a4\u30e0\u30be\u30fc\u30f3 label.time=\u6642\u523b -label.timeout.in.second = Timeout(seconds) +label.timeout.in.second=\u30bf\u30a4\u30e0\u30a2\u30a6\u30c8 (\u79d2) label.timeout=\u30bf\u30a4\u30e0\u30a2\u30a6\u30c8 label.timezone=\u30bf\u30a4\u30e0\u30be\u30fc\u30f3 label.token=\u30c8\u30fc\u30af\u30f3 @@ -1166,8 +1167,8 @@ label.unavailable=\u4f7f\u7528\u4e0d\u80fd label.unlimited=\u7121\u5236\u9650 label.untagged=\u30bf\u30b0\u306a\u3057 label.update.project.resources=\u30d7\u30ed\u30b8\u30a7\u30af\u30c8 \u30ea\u30bd\u30fc\u30b9\u306e\u66f4\u65b0 -label.update.ssl.cert= SSL Certificate -label.update.ssl= SSL Certificate +label.update.ssl.cert=SSL \u8a3c\u660e\u66f8 +label.update.ssl=SSL \u8a3c\u660e\u66f8 label.updating=\u66f4\u65b0\u3057\u3066\u3044\u307e\u3059 label.upload.volume=\u30dc\u30ea\u30e5\u30fc\u30e0\u306e\u30a2\u30c3\u30d7\u30ed\u30fc\u30c9 label.upload=\u30a2\u30c3\u30d7\u30ed\u30fc\u30c9 @@ -1289,11 +1290,12 @@ label.add.gslb=GSLB \u306e\u8ffd\u52a0 label.gslb.servicetype=\u30b5\u30fc\u30d3\u30b9\u306e\u7a2e\u985e label.gslb.details=GSLB \u306e\u8a73\u7d30 label.gslb.delete=GSLB \u306e\u524a\u9664 -label.opendaylight.controllers=OpenDaylight Controllers +label.opendaylight.controller=OpenDaylight \u30b3\u30f3\u30c8\u30ed\u30fc\u30e9\u30fc +label.opendaylight.controllers=OpenDaylight \u30b3\u30f3\u30c8\u30ed\u30fc\u30e9\u30fc label.portable.ip.ranges=\u30dd\u30fc\u30bf\u30d6\u30eb IP \u30a2\u30c9\u30ec\u30b9\u306e\u7bc4\u56f2 label.add.portable.ip.range=\u30dd\u30fc\u30bf\u30d6\u30eb IP \u30a2\u30c9\u30ec\u30b9\u306e\u7bc4\u56f2\u306e\u8ffd\u52a0 label.delete.portable.ip.range=\u30dd\u30fc\u30bf\u30d6\u30eb IP \u30a2\u30c9\u30ec\u30b9\u306e\u7bc4\u56f2\u306e\u524a\u9664 -label.opendaylight.controllerdetail=OpenDaylight Controller Details +label.opendaylight.controllerdetail=OpenDaylight \u30b3\u30f3\u30c8\u30ed\u30fc\u30e9\u30fc\u306e\u8a73\u7d30 label.portable.ip.range.details=\u30dd\u30fc\u30bf\u30d6\u30eb IP \u30a2\u30c9\u30ec\u30b9\u306e\u7bc4\u56f2\u306e\u8a73\u7d30 label.portable.ips=\u30dd\u30fc\u30bf\u30d6\u30eb IP \u30a2\u30c9\u30ec\u30b9 label.gslb.assigned.lb=\u5272\u308a\u5f53\u3066\u6e08\u307f\u8ca0\u8377\u5206\u6563 @@ -1305,9 +1307,9 @@ label.enable.autoscale=\u81ea\u52d5\u30b5\u30a4\u30ba\u8a2d\u5b9a\u306e\u6709\u5 label.disable.autoscale=\u81ea\u52d5\u30b5\u30a4\u30ba\u8a2d\u5b9a\u306e\u7121\u52b9\u5316 label.min.instances=\u6700\u5c0f\u30a4\u30f3\u30b9\u30bf\u30f3\u30b9\u6570 label.max.instances=\u6700\u5927\u30a4\u30f3\u30b9\u30bf\u30f3\u30b9\u6570 -label.add.OpenDaylight.device=Add OpenDaylight Controller +label.add.OpenDaylight.device=OpenDaylight \u30b3\u30f3\u30c8\u30ed\u30fc\u30e9\u30fc\u306e\u8ffd\u52a0 label.show.advanced.settings=\u8a73\u7d30\u8a2d\u5b9a\u306e\u8868\u793a -label.delete.OpenDaylight.device=Delete OpenDaylight Controller +label.delete.OpenDaylight.device=OpenDaylight \u30b3\u30f3\u30c8\u30ed\u30fc\u30e9\u30fc\u306e\u524a\u9664 label.polling.interval.sec=\u30dd\u30fc\u30ea\u30f3\u30b0\u9593\u9694 (\u79d2) label.quiet.time.sec=\u5f85\u3061\u6642\u9593 (\u79d2) label.destroy.vm.graceperiod=VM \u7834\u68c4\u306e\u7336\u4e88\u671f\u9593 @@ -1317,6 +1319,167 @@ label.add.ucs.manager=UCS Manager \u306e\u8ffd\u52a0 label.ovm.traffic.label=OVM \u306e\u30c8\u30e9\u30d5\u30a3\u30c3\u30af \u30e9\u30d9\u30eb label.lxc.traffic.label=LXC \u306e\u30c8\u30e9\u30d5\u30a3\u30c3\u30af \u30e9\u30d9\u30eb label.hyperv.traffic.label=Hyper-V \u306e\u30c8\u30e9\u30d5\u30a3\u30c3\u30af \u30e9\u30d9\u30eb +label.resource.name=\u30ea\u30bd\u30fc\u30b9\u540d +label.reource.id=\u30ea\u30bd\u30fc\u30b9 ID +label.vnmc.devices=VNMC \u30c7\u30d0\u30a4\u30b9 +label.add.vnmc.provider=VNMC \u30d7\u30ed\u30d0\u30a4\u30c0\u30fc\u306e\u8ffd\u52a0 +label.enable.vnmc.provider=VNMC \u30d7\u30ed\u30d0\u30a4\u30c0\u30fc\u306e\u6709\u52b9\u5316 +label.add.vnmc.device=VNMC \u30c7\u30d0\u30a4\u30b9\u306e\u8ffd\u52a0 +label.ciscovnmc.resource.details=Cisco VNMC \u30ea\u30bd\u30fc\u30b9\u306e\u8a73\u7d30 +label.delete.ciscovnmc.resource=Cisco VNMC \u30ea\u30bd\u30fc\u30b9\u306e\u524a\u9664 +label.enable.vnmc.device=VNMC \u30c7\u30d0\u30a4\u30b9\u306e\u6709\u52b9\u5316 +label.disbale.vnmc.device=VNMC \u30c7\u30d0\u30a4\u30b9\u306e\u7121\u52b9\u5316 +label.disable.vnmc.provider=VNMC \u30d7\u30ed\u30d0\u30a4\u30c0\u30fc\u306e\u7121\u52b9\u5316 +label.services=\u30b5\u30fc\u30d3\u30b9 +label.secondary.staging.store=\u30bb\u30ab\u30f3\u30c0\u30ea \u30b9\u30c6\u30fc\u30b8\u30f3\u30b0 \u30b9\u30c8\u30a2 +label.release.account=\u30a2\u30ab\u30a6\u30f3\u30c8\u304b\u3089\u89e3\u653e +label.release.account.lowercase=\u30a2\u30ab\u30a6\u30f3\u30c8\u304b\u3089\u89e3\u653e +label.vlan.vni.ranges=VLAN/VNI \u306e\u7bc4\u56f2 +label.dedicated.vlan.vni.ranges=\u5c02\u7528 VLAN/VNI \u306e\u7bc4\u56f2 +label.dedicate.vlan.vni.range=VLAN/VNI \u306e\u7bc4\u56f2\u3092\u5c02\u7528\u306b\u8a2d\u5b9a +label.vlan.vni.range=VLAN/VNI \u306e\u7bc4\u56f2 +label.vlan.range.details=VLAN \u306e\u7bc4\u56f2\u306e\u8a73\u7d30 +label.release.dedicated.vlan.range=\u5c02\u7528 VLAN \u306e\u7bc4\u56f2\u306e\u89e3\u653e +label.broadcat.uri=\u30d6\u30ed\u30fc\u30c9\u30ad\u30e3\u30b9\u30c8 URI +label.ipv4.cidr=IPv4 CIDR +label.guest.network.details=\u30b2\u30b9\u30c8 \u30cd\u30c3\u30c8\u30ef\u30fc\u30af\u306e\u8a73\u7d30 +label.ipv4.gateway=IPv4 \u30b2\u30fc\u30c8\u30a6\u30a7\u30a4 +label.release.dedicated.vlan.range=\u5c02\u7528 VLAN \u306e\u7bc4\u56f2\u3092\u89e3\u653e +label.vlan.ranges=VLAN \u306e\u7bc4\u56f2 +label.virtual.appliance.details=\u4eee\u60f3\u30a2\u30d7\u30e9\u30a4\u30a2\u30f3\u30b9\u306e\u8a73\u7d30 +label.start.lb.vm=LB VM \u306e\u8d77\u52d5 +label.stop.lb.vm=LB VM \u306e\u505c\u6b62 +label.migrate.lb.vm=LB VM \u306e\u79fb\u884c +label.vpc.virtual.router=VPC \u4eee\u60f3\u30eb\u30fc\u30bf\u30fc +label.ovs=OVS +label.gslb.service=GSLB \u30b5\u30fc\u30d3\u30b9 +label.gslb.service.public.ip=GSLB \u30b5\u30fc\u30d3\u30b9\u306e\u30d1\u30d6\u30ea\u30c3\u30af IP \u30a2\u30c9\u30ec\u30b9 +label.gslb.service.private.ip=GSLB \u30b5\u30fc\u30d3\u30b9\u306e\u30d7\u30e9\u30a4\u30d9\u30fc\u30c8 IP \u30a2\u30c9\u30ec\u30b9 +label.baremetal.dhcp.provider=\u30d9\u30a2\u30e1\u30bf\u30eb DHCP \u30d7\u30ed\u30d0\u30a4\u30c0\u30fc +label.add.baremetal.dhcp.device=\u30d9\u30a2\u30e1\u30bf\u30eb DHCP \u30c7\u30d0\u30a4\u30b9\u306e\u8ffd\u52a0 +label.baremetal.pxe.provider=\u30d9\u30a2\u30e1\u30bf\u30eb PXE \u30d7\u30ed\u30d0\u30a4\u30c0\u30fc +label.baremetal.pxe.device=\u30d9\u30a2\u30e1\u30bf\u30eb PXE \u30c7\u30d0\u30a4\u30b9\u306e\u8ffd\u52a0 +label.tftp.root.directory=TFTP \u30eb\u30fc\u30c8 \u30c7\u30a3\u30ec\u30af\u30c8\u30ea +label.add.vmware.datacenter=VMware \u30c7\u30fc\u30bf\u30bb\u30f3\u30bf\u30fc\u306e\u8ffd\u52a0 +label.remove.vmware.datacenter=VMware \u30c7\u30fc\u30bf\u30bb\u30f3\u30bf\u30fc\u306e\u524a\u9664 +label.dc.name=DC \u540d +label.vcenter=vCenter +label.dedicate.zone=\u30be\u30fc\u30f3\u3092\u5c02\u7528\u306b\u8a2d\u5b9a +label.zone.dedicated=\u5c02\u7528\u30be\u30fc\u30f3 +label.release.dedicated.zone=\u5c02\u7528\u30be\u30fc\u30f3\u306e\u89e3\u653e +label.ipv6.dns1=IPv6 DNS 1 +label.ipv6.dns2=IPv6 DNS 2 +label.vmware.datacenter.name=VMware \u30c7\u30fc\u30bf\u30bb\u30f3\u30bf\u30fc\u540d +label.vmware.datacenter.vcenter=VMware \u30c7\u30fc\u30bf\u30bb\u30f3\u30bf\u30fc\u306e vCenter +label.vmware.datacenter.id=VMware \u30c7\u30fc\u30bf\u30bb\u30f3\u30bf\u30fc ID +label.system.vm.details=\u30b7\u30b9\u30c6\u30e0 VM \u306e\u8a73\u7d30 +label.system.vm.scaled.up=\u30b7\u30b9\u30c6\u30e0 VM \u306e\u30b5\u30a4\u30ba\u304c\u62e1\u5927\u3055\u308c\u307e\u3057\u305f +label.console.proxy.vm=\u30b3\u30f3\u30bd\u30fc\u30eb \u30d7\u30ed\u30ad\u30b7 VM +label.settings=\u8a2d\u5b9a +label.requires.upgrade=\u30a2\u30c3\u30d7\u30b0\u30ec\u30fc\u30c9\u304c\u5fc5\u8981 +label.upgrade.router.newer.template=\u30eb\u30fc\u30bf\u30fc\u3092\u30a2\u30c3\u30d7\u30b0\u30ec\u30fc\u30c9\u3057\u3066\u65b0\u3057\u3044\u30c6\u30f3\u30d7\u30ec\u30fc\u30c8\u3092\u4f7f\u7528\u3059\u308b +label.router.vm.scaled.up=\u30eb\u30fc\u30bf\u30fc VM \u306e\u30b5\u30a4\u30ba\u304c\u62e1\u5927\u3055\u308c\u307e\u3057\u305f +label.total.virtual.routers=\u4eee\u60f3\u30eb\u30fc\u30bf\u30fc\u5408\u8a08 +label.upgrade.required=\u30a2\u30c3\u30d7\u30b0\u30ec\u30fc\u30c9\u304c\u5fc5\u8981\u3067\u3059 +label.virtual.routers.group.zone=\u30be\u30fc\u30f3\u5225\u306e\u4eee\u60f3\u30eb\u30fc\u30bf\u30fc \u30b0\u30eb\u30fc\u30d7 +label.total.virtual.routers.upgrade=\u30a2\u30c3\u30d7\u30b0\u30ec\u30fc\u30c9\u304c\u5fc5\u8981\u306a\u4eee\u60f3\u30eb\u30fc\u30bf\u30fc\u5408\u8a08 +label.virtual.routers.group.pod=\u30dd\u30c3\u30c9\u5225\u306e\u4eee\u60f3\u30eb\u30fc\u30bf\u30fc \u30b0\u30eb\u30fc\u30d7 +label.virtual.routers.group.cluster=\u30af\u30e9\u30b9\u30bf\u30fc\u5225\u306e\u4eee\u60f3\u30eb\u30fc\u30bf\u30fc \u30b0\u30eb\u30fc\u30d7 +label.zone.lower=\u30be\u30fc\u30f3 +label.virtual.routers.group.account=\u30a2\u30ab\u30a6\u30f3\u30c8\u5225\u306e\u4eee\u60f3\u30eb\u30fc\u30bf\u30fc \u30b0\u30eb\u30fc\u30d7 +label.netscaler.details=NetScaler \u306e\u8a73\u7d30 +label.baremetal.dhcp.devices=\u30d9\u30a2\u30e1\u30bf\u30eb DHCP \u30c7\u30d0\u30a4\u30b9 +label.baremetal.pxe.devices=\u30d9\u30a2\u30e1\u30bf\u30eb PXE \u30c7\u30d0\u30a4\u30b9 +label.addes.new.f5=\u65b0\u3057\u3044 F5 \u3092\u8ffd\u52a0\u3057\u307e\u3057\u305f +label.f5.details=F5 \u306e\u8a73\u7d30 +label.srx.details=SRX \u306e\u8a73\u7d30 +label.palo.alto.details=Palo Alto \u306e\u8a73\u7d30 +label.added.nicira.nvp.controller=\u65b0\u3057\u3044 Nicira NVP Controller \u3092\u8ffd\u52a0\u3057\u307e\u3057\u305f\ +label.nicira.nvp.details=Nicira NVP \u306e\u8a73\u7d30 +label.added.new.bigswitch.vns.controller=\u65b0\u3057\u3044 Big Switch VNS \u30b3\u30f3\u30c8\u30ed\u30fc\u30e9\u30fc\u3092\u8ffd\u52a0\u3057\u307e\u3057\u305f +label.bigswitch.vns.details=Big Switch VNS \u306e\u8a73\u7d30 +label.dedicate=\u5c02\u7528\u306b\u8a2d\u5b9a +label.dedicate.pod=\u30dd\u30c3\u30c9\u3092\u5c02\u7528\u306b\u8a2d\u5b9a +label.pod.dedicated=\u30dd\u30c3\u30c9\u3092\u5c02\u7528\u306b\u8a2d\u5b9a\u3057\u307e\u3057\u305f +label.release.dedicated.pod=\u5c02\u7528\u30dd\u30c3\u30c9\u306e\u89e3\u653e +label.override.public.traffic=\u30d1\u30d6\u30ea\u30c3\u30af \u30c8\u30e9\u30d5\u30a3\u30c3\u30af\u3092\u30aa\u30fc\u30d0\u30fc\u30e9\u30a4\u30c9\u3059\u308b +label.public.traffic.vswitch.type=\u30d1\u30d6\u30ea\u30c3\u30af \u30c8\u30e9\u30d5\u30a3\u30c3\u30af\u306e vSwitch \u306e\u7a2e\u985e +label.public.traffic.vswitch.name=\u30d1\u30d6\u30ea\u30c3\u30af \u30c8\u30e9\u30d5\u30a3\u30c3\u30af\u306e vSwitch \u540d +label.override.guest.traffic=\u30b2\u30b9\u30c8 \u30c8\u30e9\u30d5\u30a3\u30c3\u30af\u3092\u30aa\u30fc\u30d0\u30fc\u30e9\u30a4\u30c9\u3059\u308b +label.guest.traffic.vswitch.type=\u30b2\u30b9\u30c8 \u30c8\u30e9\u30d5\u30a3\u30c3\u30af\u306e vSwitch \u306e\u7a2e\u985e +label.guest.traffic.vswitch.name=\u30b2\u30b9\u30c8 \u30c8\u30e9\u30d5\u30a3\u30c3\u30af\u306e vSwitch \u540d +label.cisco.nexus1000v.ip.address=Nexus 1000V \u306e IP \u30a2\u30c9\u30ec\u30b9 +label.cisco.nexus1000v.username=Nexus 1000V \u306e\u30e6\u30fc\u30b6\u30fc\u540d +label.cisco.nexus1000v.password=Nexus 1000V \u306e\u30d1\u30b9\u30ef\u30fc\u30c9 +label.dedicate.cluster=\u30af\u30e9\u30b9\u30bf\u30fc\u3092\u5c02\u7528\u306b\u8a2d\u5b9a +label.release.dedicated.cluster=\u5c02\u7528\u30af\u30e9\u30b9\u30bf\u30fc\u306e\u89e3\u653e +label.dedicate.host=\u30db\u30b9\u30c8\u3092\u5c02\u7528\u306b\u8a2d\u5b9a +label.release.dedicated.host=\u5c02\u7528\u30db\u30b9\u30c8\u306e\u89e3\u653e +label.number.of.cpu.sockets=CPU \u30bd\u30b1\u30c3\u30c8\u6570 +label.delete.ucs.manager=UCS Manager \u306e\u524a\u9664 +label.blades=\u30d6\u30ec\u30fc\u30c9 +label.chassis=\u30b7\u30e3\u30fc\u30b7 +label.blade.id=\u30d6\u30ec\u30fc\u30c9 ID +label.associated.profile=\u95a2\u9023\u4ed8\u3051\u3089\u308c\u305f\u30d7\u30ed\u30d5\u30a1\u30a4\u30eb +label.refresh.blades=\u30d6\u30ec\u30fc\u30c9\u306e\u66f4\u65b0 +label.instanciate.template.associate.profile.blade=\u30c6\u30f3\u30d7\u30ec\u30fc\u30c8\u306e\u30a4\u30f3\u30b9\u30bf\u30f3\u30b9\u4f5c\u6210\u304a\u3088\u3073\u30d7\u30ed\u30d5\u30a1\u30a4\u30eb\u3068\u30d6\u30ec\u30fc\u30c9\u306e\u95a2\u9023\u4ed8\u3051 +label.select.template=\u30c6\u30f3\u30d7\u30ec\u30fc\u30c8\u306e\u9078\u629e +label.profile=\u30d7\u30ed\u30d5\u30a1\u30a4\u30eb +label.delete.profile=\u30d7\u30ed\u30d5\u30a1\u30a4\u30eb\u306e\u524a\u9664 +label.disassociate.profile.blade=\u30d7\u30ed\u30d5\u30a1\u30a4\u30eb\u3068\u30d6\u30ec\u30fc\u30c9\u306e\u95a2\u9023\u4ed8\u3051\u306e\u89e3\u9664 +label.secondary.storage.details=\u30bb\u30ab\u30f3\u30c0\u30ea \u30b9\u30c8\u30ec\u30fc\u30b8\u306e\u8a73\u7d30 +label.secondary.staging.store.details=\u30bb\u30ab\u30f3\u30c0\u30ea \u30b9\u30c6\u30fc\u30b8\u30f3\u30b0 \u30b9\u30c8\u30a2\u306e\u8a73\u7d30 +label.add.nfs.secondary.staging.store=NFS \u30bb\u30ab\u30f3\u30c0\u30ea \u30b9\u30c6\u30fc\u30b8\u30f3\u30b0 \u30b9\u30c8\u30a2\u306e\u8ffd\u52a0 +label.delete.secondary.staging.store=\u30bb\u30ab\u30f3\u30c0\u30ea \u30b9\u30c6\u30fc\u30b8\u30f3\u30b0 \u30b9\u30c8\u30a2\u306e\u524a\u9664 +label.ipv4.start.ip=IPv4 \u958b\u59cb IP \u30a2\u30c9\u30ec\u30b9 +label.ipv4.end.ip=IPv4 \u7d42\u4e86 IP \u30a2\u30c9\u30ec\u30b9 +label.ipv6.start.ip=IPv6 \u958b\u59cb IP \u30a2\u30c9\u30ec\u30b9 +label.ipv6.end.ip=IPv6 \u7d42\u4e86 IP \u30a2\u30c9\u30ec\u30b9 +label.vm.password=VM \u306e\u30d1\u30b9\u30ef\u30fc\u30c9: +label.group.by.zone=\u30be\u30fc\u30f3\u5225\u30b0\u30eb\u30fc\u30d7 +label.group.by.pod=\u30dd\u30c3\u30c9\u5225\u30b0\u30eb\u30fc\u30d7 +label.group.by.cluster=\u30af\u30e9\u30b9\u30bf\u30fc\u5225\u30b0\u30eb\u30fc\u30d7 +label.group.by.account=\u30a2\u30ab\u30a6\u30f3\u30c8\u5225\u30b0\u30eb\u30fc\u30d7 +label.no.grouping=(\u30b0\u30eb\u30fc\u30d7\u306a\u3057)\ +label.create.nfs.secondary.staging.storage=NFS \u30bb\u30ab\u30f3\u30c0\u30ea \u30b9\u30c6\u30fc\u30b8\u30f3\u30b0 \u30b9\u30c8\u30a2\u3092\u4f5c\u6210\u3059\u308b +label.username.lower=\u30e6\u30fc\u30b6\u30fc\u540d +label.password.lower=\u30d1\u30b9\u30ef\u30fc\u30c9 +label.email.lower=\u96fb\u5b50\u30e1\u30fc\u30eb +label.firstname.lower=\u540d +label.lastname.lower=\u59d3 +label.domain.lower=\u30c9\u30e1\u30a4\u30f3 +label.account.lower=\u30a2\u30ab\u30a6\u30f3\u30c8 +label.type.lower=\u7a2e\u985e +label.rule.number=\u898f\u5247\u756a\u53f7 +label.action=\u64cd\u4f5c +label.name.lower=\u540d\u524d +label.ucs=UCS +label.change.affinity=\u30a2\u30d5\u30a3\u30cb\u30c6\u30a3\u306e\u5909\u66f4 +label.persistent=\u6c38\u7d9a +label.broadcasturi=\u30d6\u30ed\u30fc\u30c9\u30ad\u30e3\u30b9\u30c8 URI +label.network.cidr=\u30cd\u30c3\u30c8\u30ef\u30fc\u30af CIDR +label.reserved.ip.range=\u4e88\u7d04\u6e08\u307f IP \u30a2\u30c9\u30ec\u30b9\u306e\u7bc4\u56f2 +label.autoscale=\u81ea\u52d5\u30b5\u30a4\u30ba\u8a2d\u5b9a +label.health.check=\u30d8\u30eb\u30b9 \u30c1\u30a7\u30c3\u30af +label.public.load.balancer.provider=\u30d1\u30d6\u30ea\u30c3\u30af\u8ca0\u8377\u5206\u6563\u88c5\u7f6e\u30d7\u30ed\u30d0\u30a4\u30c0\u30fc +label.add.isolated.network=\u5206\u96e2\u3055\u308c\u305f\u30cd\u30c3\u30c8\u30ef\u30fc\u30af\u306e\u8ffd\u52a0 +label.vlan=VLAN +label.secondary.isolated.vlan.id=\u5206\u96e2\u3055\u308c\u305f\u30bb\u30ab\u30f3\u30c0\u30ea VLAN ID +label.ipv4.netmask=IPv4 \u30cd\u30c3\u30c8\u30de\u30b9\u30af +label.custom=\u30ab\u30b9\u30bf\u30e0 +label.disable.network.offering=\u30cd\u30c3\u30c8\u30ef\u30fc\u30af \u30aa\u30d5\u30a1\u30ea\u30f3\u30b0\u306e\u7121\u52b9\u5316 +label.enable.network.offering=\u30cd\u30c3\u30c8\u30ef\u30fc\u30af \u30aa\u30d5\u30a1\u30ea\u30f3\u30b0\u306e\u6709\u52b9\u5316 +label.remove.network.offering=\u30cd\u30c3\u30c8\u30ef\u30fc\u30af \u30aa\u30d5\u30a1\u30ea\u30f3\u30b0\u306e\u524a\u9664 +label.system.offering.for.router=\u30eb\u30fc\u30bf\u30fc\u7528\u30b7\u30b9\u30c6\u30e0 \u30aa\u30d5\u30a1\u30ea\u30f3\u30b0 +label.mode=\u30e2\u30fc\u30c9 +label.associate.public.ip=\u30d1\u30d6\u30ea\u30c3\u30af IP \u30a2\u30c9\u30ec\u30b9\u306e\u95a2\u9023\u4ed8\u3051 +label.acl=ACL +label.user.data=\u30e6\u30fc\u30b6\u30fc \u30c7\u30fc\u30bf +label.virtual.networking=\u4eee\u60f3\u30cd\u30c3\u30c8\u30ef\u30fc\u30af +label.allow=\u8a31\u53ef +label.deny=\u62d2\u5426 +label.default.egress.policy=\u30c7\u30d5\u30a9\u30eb\u30c8\u306e\u9001\u4fe1\u30dd\u30ea\u30b7\u30fc +label.xenserver.tools.version.61.plus=XenServer Tools Version 6.1 \u4ee5\u964d managed.state=\u7ba1\u7406\u5bfe\u8c61\u72b6\u614b message.acquire.new.ip.vpc=\u3053\u306e VPC \u306e\u65b0\u3057\u3044 IP \u30a2\u30c9\u30ec\u30b9\u3092\u53d6\u5f97\u3057\u3066\u3082\u3088\u308d\u3057\u3044\u3067\u3059\u304b? message.acquire.new.ip=\u3053\u306e\u30cd\u30c3\u30c8\u30ef\u30fc\u30af\u306e\u65b0\u3057\u3044 IP \u30a2\u30c9\u30ec\u30b9\u3092\u53d6\u5f97\u3057\u3066\u3082\u3088\u308d\u3057\u3044\u3067\u3059\u304b? @@ -1460,7 +1623,7 @@ message.creating.primary.storage=\u30d7\u30e9\u30a4\u30de\u30ea \u30b9\u30c8\u30 message.creating.secondary.storage=\u30bb\u30ab\u30f3\u30c0\u30ea \u30b9\u30c8\u30ec\u30fc\u30b8\u3092\u4f5c\u6210\u3057\u3066\u3044\u307e\u3059 message.creating.zone=\u30be\u30fc\u30f3\u3092\u4f5c\u6210\u3057\u3066\u3044\u307e\u3059 message.decline.invitation=\u3053\u306e\u30d7\u30ed\u30b8\u30a7\u30af\u30c8\u3078\u306e\u62db\u5f85\u3092\u8f9e\u9000\u3057\u3066\u3082\u3088\u308d\u3057\u3044\u3067\u3059\u304b? -message.dedicate.zone=\u30be\u30fc\u30f3\u3092\u5c02\u7528\u5316\u3057\u3066\u3044\u307e\u3059 +message.dedicate.zone=\u30be\u30fc\u30f3\u3092\u5c02\u7528\u306b\u8a2d\u5b9a\u3057\u3066\u3044\u307e\u3059 message.delete.account=\u3053\u306e\u30a2\u30ab\u30a6\u30f3\u30c8\u3092\u524a\u9664\u3057\u3066\u3082\u3088\u308d\u3057\u3044\u3067\u3059\u304b? message.delete.affinity.group=\u3053\u306e\u30a2\u30d5\u30a3\u30cb\u30c6\u30a3 \u30b0\u30eb\u30fc\u30d7\u3092\u524a\u9664\u3057\u3066\u3082\u3088\u308d\u3057\u3044\u3067\u3059\u304b? message.delete.gateway=\u3053\u306e\u30b2\u30fc\u30c8\u30a6\u30a7\u30a4\u3092\u524a\u9664\u3057\u3066\u3082\u3088\u308d\u3057\u3044\u3067\u3059\u304b? @@ -1632,21 +1795,21 @@ message.zone.step.3.desc=\u65b0\u3057\u3044\u30dd\u30c3\u30c9\u3092\u8ffd\u52a0\ message.zoneWizard.enable.local.storage=\u8b66\u544a\: \u3053\u306e\u30be\u30fc\u30f3\u306e\u30ed\u30fc\u30ab\u30eb \u30b9\u30c8\u30ec\u30fc\u30b8\u3092\u6709\u52b9\u306b\u3059\u308b\u5834\u5408\u306f\u3001\u30b7\u30b9\u30c6\u30e0 VM \u306e\u8d77\u52d5\u5834\u6240\u306b\u5fdc\u3058\u3066\u6b21\u306e\u64cd\u4f5c\u304c\u5fc5\u8981\u3067\u3059\u3002

1. \u30b7\u30b9\u30c6\u30e0 VM \u3092\u30d7\u30e9\u30a4\u30de\u30ea \u30b9\u30c8\u30ec\u30fc\u30b8\u3067\u8d77\u52d5\u3059\u308b\u5fc5\u8981\u304c\u3042\u308b\u5834\u5408\u306f\u3001\u30d7\u30e9\u30a4\u30de\u30ea \u30b9\u30c8\u30ec\u30fc\u30b8\u3092\u4f5c\u6210\u3057\u305f\u5f8c\u3067\u30be\u30fc\u30f3\u306b\u8ffd\u52a0\u3059\u308b\u5fc5\u8981\u304c\u3042\u308a\u307e\u3059\u3002\u30be\u30fc\u30f3\u3092\u7121\u52b9\u72b6\u614b\u304b\u3089\u958b\u59cb\u3059\u308b\u5fc5\u8981\u3082\u3042\u308a\u307e\u3059\u3002

2. \u30b7\u30b9\u30c6\u30e0 VM \u3092\u30ed\u30fc\u30ab\u30eb \u30b9\u30c8\u30ec\u30fc\u30b8\u3067\u8d77\u52d5\u3059\u308b\u5fc5\u8981\u304c\u3042\u308b\u5834\u5408\u306f\u3001\u30be\u30fc\u30f3\u3092\u6709\u52b9\u306b\u3059\u308b\u524d\u306b system.vm.use.local.storage \u3092 true \u306b\u8a2d\u5b9a\u3059\u308b\u5fc5\u8981\u304c\u3042\u308a\u307e\u3059\u3002


\u7d9a\u884c\u3057\u3066\u3082\u3088\u308d\u3057\u3044\u3067\u3059\u304b? message.validate.fieldrequired=\u3053\u308c\u306f\u5fc5\u9808\u306e\u30d5\u30a3\u30fc\u30eb\u30c9\u3067\u3059\u3002 message.validate.fixfield=\u3053\u306e\u30d5\u30a3\u30fc\u30eb\u30c9\u3092\u4fee\u6b63\u3057\u3066\u304f\u3060\u3055\u3044\u3002 -message.validate.email.address=Please enter a valid email address. -message.validate.URL=Please enter a valid URL. -message.validate.date=Please enter a valid date. -message.validate.date.ISO=Please enter a valid date (ISO). -message.validate.number=Please enter a valid number. -message.validate.digits=Please enter only digits. -message.validate.creditcard=Please enter a valid credit card number. -message.validate.equalto=Please enter the same value again. -message.validate.accept=Please enter a value with a valid extension. -message.validate.maxlength=Please enter no more than {0} characters. -message.validate.minlength=Please enter at least {0} characters. -message.validate.range.length=Please enter a value between {0} and {1} characters long. -message.validate.range=Please enter a value between {0} and {1}. -message.validate.max=Please enter a value less than or equal to {0}. -messgae.validate.min=Please enter a value greater than or equal to {0}. +message.validate.email.address=\u30e1\u30fc\u30eb \u30a2\u30c9\u30ec\u30b9\u3092\u6b63\u3057\u304f\u5165\u529b\u3057\u3066\u304f\u3060\u3055\u3044\u3002 +message.validate.URL=URL \u3092\u6b63\u3057\u304f\u5165\u529b\u3057\u3066\u304f\u3060\u3055\u3044\u3002 +message.validate.date=\u65e5\u4ed8\u3092\u6b63\u3057\u304f\u5165\u529b\u3057\u3066\u304f\u3060\u3055\u3044\u3002 +message.validate.date.ISO=\u65e5\u4ed8\u3092\u6b63\u3057\u304f\u5165\u529b\u3057\u3066\u304f\u3060\u3055\u3044 (ISO)\u3002 +message.validate.number=\u6570\u5024\u3092\u6b63\u3057\u304f\u5165\u529b\u3057\u3066\u304f\u3060\u3055\u3044\u3002 +message.validate.digits=\u6570\u5b57\u306e\u307f\u3092\u5165\u529b\u3057\u3066\u304f\u3060\u3055\u3044\u3002 +message.validate.creditcard=\u30af\u30ec\u30b8\u30c3\u30c8 \u30ab\u30fc\u30c9\u756a\u53f7\u3092\u6b63\u3057\u304f\u5165\u529b\u3057\u3066\u304f\u3060\u3055\u3044\u3002 +message.validate.equalto=\u540c\u3058\u5024\u3092\u518d\u5165\u529b\u3057\u3066\u304f\u3060\u3055\u3044\u3002 +message.validate.accept=\u6709\u52b9\u306a\u62e1\u5f35\u5b50\u3092\u6301\u3064\u5024\u3092\u5165\u529b\u3057\u3066\u304f\u3060\u3055\u3044\u3002 +message.validate.maxlength={0} \u6587\u5b57\u4ee5\u4e0b\u3067\u5165\u529b\u3057\u3066\u304f\u3060\u3055\u3044\u3002 +message.validate.minlength={0} \u6587\u5b57\u4ee5\u4e0a\u3067\u5165\u529b\u3057\u3066\u304f\u3060\u3055\u3044\u3002 +message.validate.range.length={0} \uff5e {1} \u6587\u5b57\u3067\u5165\u529b\u3057\u3066\u304f\u3060\u3055\u3044\u3002 +message.validate.range={0} \uff5e {1} \u306e\u5024\u3092\u5165\u529b\u3057\u3066\u304f\u3060\u3055\u3044\u3002 +message.validate.max={0} \u4ee5\u4e0b\u306e\u5024\u3092\u5165\u529b\u3057\u3066\u304f\u3060\u3055\u3044\u3002 +messgae.validate.min={0} \u4ee5\u4e0a\u306e\u5024\u3092\u5165\u529b\u3057\u3066\u304f\u3060\u3055\u3044\u3002 message.creating.systemVM=\u30b7\u30b9\u30c6\u30e0 VM \u3092\u4f5c\u6210\u3057\u3066\u3044\u307e\u3059 (\u3057\u3070\u3089\u304f\u304a\u5f85\u3061\u304f\u3060\u3055\u3044) message.enabling.zone.dots=\u30be\u30fc\u30f3\u3092\u6709\u52b9\u306b\u3057\u3066\u3044\u307e\u3059... message.restoreVM=VM \u3092\u5fa9\u5143\u3057\u3066\u3082\u3088\u308d\u3057\u3044\u3067\u3059\u304b? @@ -1667,6 +1830,53 @@ message.tier.required=\u968e\u5c64\u306f\u5fc5\u9808\u3067\u3059 message.remove.ldap=LDAP \u69cb\u6210\u3092\u524a\u9664\u3057\u3066\u3082\u3088\u308d\u3057\u3044\u3067\u3059\u304b? message.action.downloading.template=\u30c6\u30f3\u30d7\u30ec\u30fc\u30c8\u3092\u30c0\u30a6\u30f3\u30ed\u30fc\u30c9\u3057\u3066\u3044\u307e\u3059\u3002 message.configure.ldap=LDAP \u3092\u69cb\u6210\u3057\u3066\u3082\u3088\u308d\u3057\u3044\u3067\u3059\u304b? +message.confirm.delete.ciscovnmc.resource=Cisco VNMC \u30ea\u30bd\u30fc\u30b9\u3092\u524a\u9664\u3057\u3066\u3082\u3088\u308d\u3057\u3044\u3067\u3059\u304b? +message.confirm.add.vnmc.provider=VNMC \u30d7\u30ed\u30d0\u30a4\u30c0\u30fc\u3092\u8ffd\u52a0\u3057\u3066\u3082\u3088\u308d\u3057\u3044\u3067\u3059\u304b? +message.confirm.enable.vnmc.provider=VNMC \u30d7\u30ed\u30d0\u30a4\u30c0\u30fc\u3092\u6709\u52b9\u306b\u3057\u3066\u3082\u3088\u308d\u3057\u3044\u3067\u3059\u304b? +message.confirm.disable.vnmc.provider=VNMC \u30d7\u30ed\u30d0\u30a4\u30c0\u30fc\u3092\u7121\u52b9\u306b\u3057\u3066\u3082\u3088\u308d\u3057\u3044\u3067\u3059\u304b? +message.vnmc.available.list=\u30d7\u30ed\u30d0\u30a4\u30c0\u30fc\u4e00\u89a7\u3067 VNMC \u3092\u5229\u7528\u3067\u304d\u307e\u305b\u3093\u3002 +message.vnmc.not.available.list=\u30d7\u30ed\u30d0\u30a4\u30c0\u30fc\u4e00\u89a7\u3067 VNMC \u3092\u5229\u7528\u3067\u304d\u307e\u305b\u3093\u3002 +message.confirm.release.dedicate.vlan.range=\u5c02\u7528 VLAN \u306e\u7bc4\u56f2\u3092\u89e3\u653e\u3057\u3066\u3082\u3088\u308d\u3057\u3044\u3067\u3059\u304b? +message.confirm.start.lb.vm=LB VM \u3092\u8d77\u52d5\u3057\u3066\u3082\u3088\u308d\u3057\u3044\u3067\u3059\u304b? +message.confirm.stop.lb.vm=LB VM \u3092\u505c\u6b62\u3057\u3066\u3082\u3088\u308d\u3057\u3044\u3067\u3059\u304b? +message.confirm.remove.vmware.datacenter=VMware \u30c7\u30fc\u30bf\u30bb\u30f3\u30bf\u30fc\u3092\u524a\u9664\u3057\u3066\u3082\u3088\u308d\u3057\u3044\u3067\u3059\u304b? +message.confirm.dedicate.zone=\u3053\u306e\u30be\u30fc\u30f3\u3092\u30c9\u30e1\u30a4\u30f3/\u30a2\u30ab\u30a6\u30f3\u30c8\u5c02\u7528\u306b\u8a2d\u5b9a\u3057\u3066\u3082\u3088\u308d\u3057\u3044\u3067\u3059\u304b? +message.confirm.release.dedicated.zone=\u3053\u306e\u5c02\u7528\u30be\u30fc\u30f3\u3092\u89e3\u653e\u3057\u3066\u3082\u3088\u308d\u3057\u3044\u3067\u3059\u304b? +message.dedicated.zone.released=\u5c02\u7528\u30be\u30fc\u30f3\u304c\u89e3\u653e\u3055\u308c\u307e\u3057\u305f +message.read.admin.guide.scaling.up=\u30b5\u30a4\u30ba\u3092\u62e1\u5927\u3059\u308b\u524d\u306b\u7ba1\u7406\u8005\u30ac\u30a4\u30c9\u306e\u52d5\u7684\u306a\u30b5\u30a4\u30ba\u5909\u66f4\u306e\u30bb\u30af\u30b7\u30e7\u30f3\u3092\u304a\u8aad\u307f\u304f\u3060\u3055\u3044\u3002 +message.confirm.scale.up.system.vm=\u30b7\u30b9\u30c6\u30e0 VM \u306e\u30b5\u30a4\u30ba\u3092\u62e1\u5927\u3057\u3066\u3082\u3088\u308d\u3057\u3044\u3067\u3059\u304b? +message.confirm.upgrade.router.newer.template=\u30eb\u30fc\u30bf\u30fc\u3092\u30a2\u30c3\u30d7\u30b0\u30ec\u30fc\u30c9\u3057\u3066\u65b0\u3057\u3044\u30c6\u30f3\u30d7\u30ec\u30fc\u30c8\u3092\u4f7f\u7528\u3057\u3066\u3082\u3088\u308d\u3057\u3044\u3067\u3059\u304b? +message.confirm.scale.up.router.vm=\u30eb\u30fc\u30bf\u30fc VM \u306e\u30b5\u30a4\u30ba\u3092\u62e1\u5927\u3057\u3066\u3082\u3088\u308d\u3057\u3044\u3067\u3059\u304b? +message.confirm.upgrade.routers.newtemplate=\u3053\u306e\u30be\u30fc\u30f3\u306e\u3059\u3079\u3066\u306e\u30eb\u30fc\u30bf\u30fc\u3092\u30a2\u30c3\u30d7\u30b0\u30ec\u30fc\u30c9\u3057\u3066\u65b0\u3057\u3044\u30c6\u30f3\u30d7\u30ec\u30fc\u30c8\u3092\u4f7f\u7528\u3057\u3066\u3082\u3088\u308d\u3057\u3044\u3067\u3059\u304b? +message.confirm.upgrade.routers.pod.newtemplate=\u3053\u306e\u30dd\u30c3\u30c9\u306e\u3059\u3079\u3066\u306e\u30eb\u30fc\u30bf\u30fc\u3092\u30a2\u30c3\u30d7\u30b0\u30ec\u30fc\u30c9\u3057\u3066\u65b0\u3057\u3044\u30c6\u30f3\u30d7\u30ec\u30fc\u30c8\u3092\u4f7f\u7528\u3057\u3066\u3082\u3088\u308d\u3057\u3044\u3067\u3059\u304b? +message.confirm.upgrade.routers.cluster.newtemplate=\u3053\u306e\u30af\u30e9\u30b9\u30bf\u30fc\u306e\u3059\u3079\u3066\u306e\u30eb\u30fc\u30bf\u30fc\u3092\u30a2\u30c3\u30d7\u30b0\u30ec\u30fc\u30c9\u3057\u3066\u65b0\u3057\u3044\u30c6\u30f3\u30d7\u30ec\u30fc\u30c8\u3092\u4f7f\u7528\u3057\u3066\u3082\u3088\u308d\u3057\u3044\u3067\u3059\u304b? +message.confirm.upgrade.routers.account.newtemplate=\u3053\u306e\u30a2\u30ab\u30a6\u30f3\u30c8\u306e\u3059\u3079\u3066\u306e\u30eb\u30fc\u30bf\u30fc\u3092\u30a2\u30c3\u30d7\u30b0\u30ec\u30fc\u30c9\u3057\u3066\u65b0\u3057\u3044\u30c6\u30f3\u30d7\u30ec\u30fc\u30c8\u3092\u4f7f\u7528\u3057\u3066\u3082\u3088\u308d\u3057\u3044\u3067\u3059\u304b? +message.confirm.dedicate.pod.domain.account=\u3053\u306e\u30dd\u30c3\u30c9\u3092\u30c9\u30e1\u30a4\u30f3/\u30a2\u30ab\u30a6\u30f3\u30c8\u5c02\u7528\u306b\u8a2d\u5b9a\u3057\u3066\u3082\u3088\u308d\u3057\u3044\u3067\u3059\u304b? +message.confirm.release.dedicated.pod=\u3053\u306e\u5c02\u7528\u30dd\u30c3\u30c9\u3092\u89e3\u653e\u3057\u3066\u3082\u3088\u308d\u3057\u3044\u3067\u3059\u304b? +message.pod.dedication.released=\u5c02\u7528\u30dd\u30c3\u30c9\u304c\u89e3\u653e\u3055\u308c\u307e\u3057\u305f +message.confirm.dedicate.cluster.domain.account=\u3053\u306e\u30af\u30e9\u30b9\u30bf\u30fc\u3092\u30c9\u30e1\u30a4\u30f3/\u30a2\u30ab\u30a6\u30f3\u30c8\u5c02\u7528\u306b\u8a2d\u5b9a\u3057\u3066\u3082\u3088\u308d\u3057\u3044\u3067\u3059\u304b? +message.cluster.dedicated=\u30af\u30e9\u30b9\u30bf\u30fc\u3092\u5c02\u7528\u306b\u8a2d\u5b9a\u3057\u307e\u3057\u305f +message.confirm.release.dedicated.cluster=\u3053\u306e\u5c02\u7528\u30af\u30e9\u30b9\u30bf\u30fc\u3092\u89e3\u653e\u3057\u3066\u3082\u3088\u308d\u3057\u3044\u3067\u3059\u304b? +message.cluster.dedication.released=\u5c02\u7528\u30af\u30e9\u30b9\u30bf\u30fc\u304c\u89e3\u653e\u3055\u308c\u307e\u3057\u305f +message.confirm.dedicate.host.domain.account=\u3053\u306e\u30db\u30b9\u30c8\u3092\u30c9\u30e1\u30a4\u30f3/\u30a2\u30ab\u30a6\u30f3\u30c8\u5c02\u7528\u306b\u8a2d\u5b9a\u3057\u3066\u3082\u3088\u308d\u3057\u3044\u3067\u3059\u304b? +message.host.dedicated=\u30db\u30b9\u30c8\u3092\u5c02\u7528\u306b\u8a2d\u5b9a\u3057\u307e\u3057\u305f +message.confirm.release.dedicated.host=\u3053\u306e\u5c02\u7528\u30db\u30b9\u30c8\u3092\u89e3\u653e\u3057\u3066\u3082\u3088\u308d\u3057\u3044\u3067\u3059\u304b? +message.host.dedication.released=\u5c02\u7528\u30db\u30b9\u30c8\u304c\u89e3\u653e\u3055\u308c\u307e\u3057\u305f +message.confirm.delete.ucs.manager=UCS Manager \u3092\u524a\u9664\u3057\u3066\u3082\u3088\u308d\u3057\u3044\u3067\u3059\u304b? +message.confirm.refresh.blades=\u30d6\u30ec\u30fc\u30c9\u3092\u66f4\u65b0\u3057\u3066\u3082\u3088\u308d\u3057\u3044\u3067\u3059\u304b? +message.confirm.delete.secondary.staging.store=\u30bb\u30ab\u30f3\u30c0\u30ea \u30b9\u30c6\u30fc\u30b8\u30f3\u30b0 \u30b9\u30c8\u30a2\u3092\u524a\u9664\u3057\u3066\u3082\u3088\u308d\u3057\u3044\u3067\u3059\u304b? +message.select.tier=\u968e\u5c64\u3092\u9078\u629e\u3057\u3066\u304f\u3060\u3055\u3044\u3002 +message.disallowed.characters=\u8a31\u53ef\u3055\u308c\u306a\u3044\u6587\u5b57: \<\,\> +message.waiting.for.builtin.templates.to.load=\u7d44\u307f\u8fbc\u307f\u30c6\u30f3\u30d7\u30ec\u30fc\u30c8\u306e\u30ed\u30fc\u30c9\u3092\u5f85\u6a5f\u3057\u3066\u3044\u307e\u3059... +message.systems.vms.ready=\u30b7\u30b9\u30c6\u30e0 VM \u306e\u6e96\u5099\u304c\u3067\u304d\u307e\u3057\u305f\u3002 +message.your.cloudstack.is.ready=CloudStack \u306e\u6e96\u5099\u304c\u3067\u304d\u307e\u3057\u305f\! +message.specifiy.tag.key.value=\u30bf\u30b0 \u30ad\u30fc\u304a\u3088\u3073\u5024\u3092\u6307\u5b9a\u3057\u3066\u304f\u3060\u3055\u3044 +message.enter.seperated.list.multiple.cidrs=CIDR \u304c\u8907\u6570\u3042\u308b\u5834\u5408\u306f\u3001\u30b3\u30f3\u30de\u533a\u5207\u308a\u306e\u4e00\u89a7\u3092\u5165\u529b\u3057\u3066\u304f\u3060\u3055\u3044 +message.disabling.network.offering=\u30cd\u30c3\u30c8\u30ef\u30fc\u30af \u30aa\u30d5\u30a1\u30ea\u30f3\u30b0\u3092\u7121\u52b9\u306b\u3057\u3066\u3044\u307e\u3059 +message.confirm.enable.network.offering=\u3053\u306e\u30cd\u30c3\u30c8\u30ef\u30fc\u30af \u30aa\u30d5\u30a1\u30ea\u30f3\u30b0\u3092\u6709\u52b9\u306b\u3057\u3066\u3082\u3088\u308d\u3057\u3044\u3067\u3059\u304b? +message.enabling.network.offering=\u30cd\u30c3\u30c8\u30ef\u30fc\u30af \u30aa\u30d5\u30a1\u30ea\u30f3\u30b0\u3092\u6709\u52b9\u306b\u3057\u3066\u3044\u307e\u3059 +message.confirm.remove.network.offering=\u3053\u306e\u30cd\u30c3\u30c8\u30ef\u30fc\u30af \u30aa\u30d5\u30a1\u30ea\u30f3\u30b0\u3092\u524a\u9664\u3057\u3066\u3082\u3088\u308d\u3057\u3044\u3067\u3059\u304b? +message.confirm.disable.network.offering=\u3053\u306e\u30cd\u30c3\u30c8\u30ef\u30fc\u30af \u30aa\u30d5\u30a1\u30ea\u30f3\u30b0\u3092\u7121\u52b9\u306b\u3057\u3066\u3082\u3088\u308d\u3057\u3044\u3067\u3059\u304b? mode=\u30e2\u30fc\u30c9 network.rate=\u30cd\u30c3\u30c8\u30ef\u30fc\u30af\u901f\u5ea6 notification.reboot.instance=\u30a4\u30f3\u30b9\u30bf\u30f3\u30b9\u306e\u518d\u8d77\u52d5 diff --git a/client/WEB-INF/classes/resources/messages_zh_CN.properties b/client/WEB-INF/classes/resources/messages_zh_CN.properties index f4c206b04f6..bb3e50c8d8e 100644 --- a/client/WEB-INF/classes/resources/messages_zh_CN.properties +++ b/client/WEB-INF/classes/resources/messages_zh_CN.properties @@ -19,7 +19,7 @@ label.remove.ldap=\u5220\u9664 LDAP label.configure.ldap=\u914d\u7f6e LDAP label.ldap.configuration=LDAP \u914d\u7f6e label.ldap.port=LDAP \u7aef\u53e3 -label.create.nfs.secondary.staging.store=\u521b\u5efa NFS \u8f85\u52a9\u6682\u5b58\u5b58\u50a8 +label.create.nfs.secondary.staging.store=\u521b\u5efa NFS \u4e8c\u7ea7\u6682\u5b58\u5b58\u50a8 label.volatile=\u53ef\u53d8 label.planner.mode=\u89c4\u5212\u5668\u6a21\u5f0f label.deployment.planner=\u90e8\u7f72\u89c4\u5212\u5668 @@ -29,7 +29,7 @@ label.smb.password=SMB \u5bc6\u7801 label.smb.domain=SMB \u57df label.hypervisors=\u865a\u62df\u673a\u7ba1\u7406\u7a0b\u5e8f label.home=\u9996\u9875 -label.sockets=CPU Sockets +label.sockets=CPU \u63d2\u69fd label.root.disk.size=\u6839\u78c1\u76d8\u5927\u5c0f label.s3.nfs.server=S3 NFS \u670d\u52a1\u5668 label.s3.nfs.path=S3 NFS \u8def\u5f84 @@ -53,18 +53,18 @@ label.disk.iops.min=\u6700\u5c0f IOPS label.disk.iops.max=\u6700\u5927 IOPS label.disk.iops.total=\u603b IOPS label.hypervisor.snapshot.reserve=\u865a\u62df\u673a\u7ba1\u7406\u7a0b\u5e8f\u5feb\u7167\u9884\u7559 -label.view.secondary.ips=\u67e5\u770b\u8f85\u52a9 IP +label.view.secondary.ips=\u67e5\u770b\u4e8c\u7ea7 IP message.validate.invalid.characters=\u67e5\u627e\u5230\u65e0\u6548\u5b57\u7b26\uff0c\u8bf7\u66f4\u6b63\u3002 -message.acquire.ip.nic=\u8bf7\u786e\u8ba4\u60a8\u786e\u5b9e\u8981\u83b7\u53d6\u6b64 NIC \u7684\u65b0\u8f85\u52a9 IP\u3002
\u6ce8\u610f: \u60a8\u9700\u8981\u5728\u865a\u62df\u673a\u5185\u90e8\u624b\u52a8\u914d\u7f6e\u65b0\u83b7\u53d6\u7684\u8f85\u52a9 IP\u3002 +message.acquire.ip.nic=\u8bf7\u786e\u8ba4\u60a8\u786e\u5b9e\u8981\u83b7\u53d6\u6b64 NIC \u7684\u65b0\u4e8c\u7ea7 IP\u3002
\u6ce8\u610f: \u60a8\u9700\u8981\u5728\u865a\u62df\u673a\u5185\u90e8\u624b\u52a8\u914d\u7f6e\u65b0\u83b7\u53d6\u7684\u4e8c\u7ea7 IP\u3002 message.select.affinity.groups=\u8bf7\u9009\u62e9\u60a8\u5e0c\u671b\u6b64 VM \u6240\u5c5e\u7684\u4efb\u4f55\u5173\u8054\u6027\u7ec4: message.no.affinity.groups=\u60a8\u6ca1\u6709\u4efb\u4f55\u5173\u8054\u6027\u7ec4\u3002\u8bf7\u7ee7\u7eed\u6267\u884c\u4e0b\u4e00\u6b65\u64cd\u4f5c\u3002 label.action.delete.nic=\u79fb\u9664 NIC message.action.delete.nic=\u8bf7\u786e\u8ba4\u60a8\u786e\u5b9e\u8981\u79fb\u9664\u6b64 NIC\uff0c\u6b64\u64cd\u4f5c\u8fd8\u5c06\u4ece VM \u4e2d\u79fb\u9664\u5173\u8054\u7684\u7f51\u7edc\u3002 changed.item.properties=\u66f4\u6539\u9879\u76ee\u5c5e\u6027 -confirm.enable.s3=\u8bf7\u586b\u5199\u4ee5\u4e0b\u4fe1\u606f\u4ee5\u542f\u7528\u5bf9 S3 \u652f\u6301\u7684\u8f85\u52a9\u5b58\u50a8\u7684\u652f\u6301 +confirm.enable.s3=\u8bf7\u586b\u5199\u4ee5\u4e0b\u4fe1\u606f\u4ee5\u542f\u7528\u5bf9 S3 \u652f\u6301\u7684\u4e8c\u7ea7\u5b58\u50a8\u7684\u652f\u6301 confirm.enable.swift=\u8bf7\u586b\u5199\u4ee5\u4e0b\u4fe1\u606f\u4ee5\u542f\u7528\u5bf9 SWIFT \u7684\u652f\u6301 -error.could.not.change.your.password.because.ldap.is.enabled=Error could not change your password because LDAP is enabled. -error.could.not.enable.zone=\u65e0\u6cd5\u542f\u7528\u533a\u57df +error.could.not.change.your.password.because.ldap.is.enabled=\u9519\u8bef\u3002LDAP \u5904\u4e8e\u542f\u7528\u72b6\u6001\uff0c\u65e0\u6cd5\u66f4\u6539\u60a8\u7684\u5bc6\u7801\u3002 +error.could.not.enable.zone=\u65e0\u6cd5\u542f\u7528\u8d44\u6e90\u57df error.installWizard.message=\u51fa\u73b0\u95ee\u9898\uff1b\u8bf7\u8fd4\u56de\u5e76\u66f4\u6b63\u4efb\u4f55\u9519\u8bef error.invalid.username.password=\u7528\u6237\u540d\u6216\u5bc6\u7801\u65e0\u6548 error.login=\u60a8\u7684\u7528\u6237\u540d/\u5bc6\u7801\u4e0e\u6211\u4eec\u7684\u8bb0\u5f55\u4e0d\u4e00\u81f4\u3002 @@ -96,7 +96,7 @@ label.account.specific=\u5e10\u6237\u4e13\u7528 label.account=\u5e10\u6237 label.accounts=\u5e10\u6237 label.acquire.new.ip=\u83b7\u53d6\u65b0 IP -label.acquire.new.secondary.ip=\u83b7\u53d6\u65b0\u8f85\u52a9 IP +label.acquire.new.secondary.ip=\u83b7\u53d6\u65b0\u4e8c\u7ea7 IP label.action.attach.disk.processing=\u6b63\u5728\u9644\u52a0\u78c1\u76d8... label.action.attach.disk=\u9644\u52a0\u78c1\u76d8 label.action.attach.iso.processing=\u6b63\u5728\u9644\u52a0 ISO... @@ -144,8 +144,8 @@ label.action.delete.pod.processing=\u6b63\u5728\u5220\u9664\u63d0\u4f9b\u70b9... label.action.delete.pod=\u5220\u9664\u63d0\u4f9b\u70b9 label.action.delete.primary.storage.processing=\u6b63\u5728\u5220\u9664\u4e3b\u5b58\u50a8... label.action.delete.primary.storage=\u5220\u9664\u4e3b\u5b58\u50a8 -label.action.delete.secondary.storage.processing=\u6b63\u5728\u5220\u9664\u8f85\u52a9\u5b58\u50a8... -label.action.delete.secondary.storage=\u5220\u9664\u8f85\u52a9\u5b58\u50a8 +label.action.delete.secondary.storage.processing=\u6b63\u5728\u5220\u9664\u4e8c\u7ea7\u5b58\u50a8... +label.action.delete.secondary.storage=\u5220\u9664\u4e8c\u7ea7\u5b58\u50a8 label.action.delete.security.group.processing=\u6b63\u5728\u5220\u9664\u5b89\u5168\u7ec4... label.action.delete.security.group=\u5220\u9664\u5b89\u5168\u7ec4 label.action.delete.service.offering.processing=\u6b63\u5728\u5220\u9664\u670d\u52a1\u65b9\u6848... @@ -159,8 +159,8 @@ label.action.delete.user.processing=\u6b63\u5728\u5220\u9664\u7528\u6237... label.action.delete.user=\u5220\u9664\u7528\u6237 label.action.delete.volume.processing=\u6b63\u5728\u5220\u9664\u5377... label.action.delete.volume=\u5220\u9664\u5377 -label.action.delete.zone.processing=\u6b63\u5728\u5220\u9664\u533a\u57df... -label.action.delete.zone=\u5220\u9664\u533a\u57df +label.action.delete.zone.processing=\u6b63\u5728\u5220\u9664\u8d44\u6e90\u57df... +label.action.delete.zone=\u5220\u9664\u8d44\u6e90\u57df label.action.destroy.instance.processing=\u6b63\u5728\u9500\u6bc1\u5b9e\u4f8b... label.action.destroy.instance=\u9500\u6bc1\u5b9e\u4f8b label.action.destroy.systemvm.processing=\u6b63\u5728\u9500\u6bc1\u7cfb\u7edf VM... @@ -181,8 +181,8 @@ label.action.disable.static.NAT.processing=\u6b63\u5728\u7981\u7528\u9759\u6001 label.action.disable.static.NAT=\u7981\u7528\u9759\u6001 NAT label.action.disable.user.processing=\u6b63\u5728\u7981\u7528\u7528\u6237... label.action.disable.user=\u7981\u7528\u7528\u6237 -label.action.disable.zone.processing=\u6b63\u5728\u7981\u7528\u533a\u57df... -label.action.disable.zone=\u7981\u7528\u533a\u57df +label.action.disable.zone.processing=\u6b63\u5728\u7981\u7528\u8d44\u6e90\u57df... +label.action.disable.zone=\u7981\u7528\u8d44\u6e90\u57df label.action.download.ISO=\u4e0b\u8f7d ISO label.action.download.template=\u4e0b\u8f7d\u6a21\u677f label.action.download.volume.processing=\u6b63\u5728\u4e0b\u8f7d\u5377... @@ -203,7 +203,7 @@ label.action.edit.resource.limits=\u7f16\u8f91\u8d44\u6e90\u9650\u5236 label.action.edit.service.offering=\u7f16\u8f91\u670d\u52a1\u65b9\u6848 label.action.edit.template=\u7f16\u8f91\u6a21\u677f label.action.edit.user=\u7f16\u8f91\u7528\u6237 -label.action.edit.zone=\u7f16\u8f91\u533a\u57df +label.action.edit.zone=\u7f16\u8f91\u8d44\u6e90\u57df label.action.enable.account.processing=\u6b63\u5728\u542f\u7528\u5e10\u6237... label.action.enable.account=\u542f\u7528\u5e10\u6237 label.action.enable.cluster.processing=\u6b63\u5728\u542f\u7528\u7fa4\u96c6... @@ -218,8 +218,8 @@ label.action.enable.static.NAT.processing=\u6b63\u5728\u542f\u7528\u9759\u6001 N label.action.enable.static.NAT=\u542f\u7528\u9759\u6001 NAT label.action.enable.user.processing=\u6b63\u5728\u542f\u7528\u7528\u6237... label.action.enable.user=\u542f\u7528\u7528\u6237 -label.action.enable.zone.processing=\u6b63\u5728\u542f\u7528\u533a\u57df... -label.action.enable.zone=\u542f\u7528\u533a\u57df +label.action.enable.zone.processing=\u6b63\u5728\u542f\u7528\u8d44\u6e90\u57df... +label.action.enable.zone=\u542f\u7528\u8d44\u6e90\u57df label.action.expunge.instance=\u5220\u9664\u5b9e\u4f8b label.action.expunge.instance.processing=\u6b63\u5728\u5220\u9664\u5b9e\u4f8b... label.action.force.reconnect.processing=\u6b63\u5728\u91cd\u65b0\u8fde\u63a5... @@ -325,11 +325,11 @@ label.add.physical.network=\u6dfb\u52a0\u7269\u7406\u7f51\u7edc label.add.pod=\u6dfb\u52a0\u63d0\u4f9b\u70b9 label.add.port.forwarding.rule=\u6dfb\u52a0\u7aef\u53e3\u8f6c\u53d1\u89c4\u5219 label.add.primary.storage=\u6dfb\u52a0\u4e3b\u5b58\u50a8 -label.add.region=\u6dfb\u52a0\u533a\u57df +label.add.region=\u6dfb\u52a0\u5730\u7406\u533a\u57df label.add.resources=\u6dfb\u52a0\u8d44\u6e90 label.add.route=\u6dfb\u52a0\u8def\u7531 label.add.rule=\u6dfb\u52a0\u89c4\u5219 -label.add.secondary.storage=\u6dfb\u52a0\u8f85\u52a9\u5b58\u50a8 +label.add.secondary.storage=\u6dfb\u52a0\u4e8c\u7ea7\u5b58\u50a8 label.add.security.group=\u6dfb\u52a0\u5b89\u5168\u7ec4 label.add.service.offering=\u6dfb\u52a0\u670d\u52a1\u65b9\u6848 label.add.SRX.device=\u6dfb\u52a0 SRX \u8bbe\u5907 @@ -351,7 +351,7 @@ label.add.vpc=\u6dfb\u52a0 VPC label.add.vpn.customer.gateway=\u6dfb\u52a0 VPN \u5ba2\u6237\u7f51\u5173 label.add.VPN.gateway=\u6dfb\u52a0 VPN \u7f51\u5173 label.add.vpn.user=\u6dfb\u52a0 VPN \u7528\u6237 -label.add.zone=\u6dfb\u52a0\u533a\u57df +label.add.zone=\u6dfb\u52a0\u8d44\u6e90\u57df label.add=\u6dfb\u52a0 label.adding.cluster=\u6b63\u5728\u6dfb\u52a0\u7fa4\u96c6 label.adding.failed=\u6dfb\u52a0\u5931\u8d25 @@ -359,7 +359,7 @@ label.adding.pod=\u6b63\u5728\u6dfb\u52a0\u63d0\u4f9b\u70b9 label.adding.processing=\u6b63\u5728\u6dfb\u52a0... label.adding.succeeded=\u5df2\u6210\u529f\u6dfb\u52a0 label.adding.user=\u6b63\u5728\u6dfb\u52a0\u7528\u6237 -label.adding.zone=\u6b63\u5728\u6dfb\u52a0\u533a\u57df +label.adding.zone=\u6b63\u5728\u6dfb\u52a0\u8d44\u6e90\u57df label.adding=\u6b63\u5728\u6dfb\u52a0 label.additional.networks=\u5176\u4ed6\u7f51\u7edc label.admin.accounts=\u7ba1\u7406\u5458\u5e10\u6237 @@ -389,7 +389,7 @@ label.associated.network=\u5173\u8054\u7f51\u7edc label.attached.iso=\u5df2\u9644\u52a0 ISO label.author.email=\u4f5c\u8005\u7535\u5b50\u90ae\u4ef6 label.author.name=\u4f5c\u8005\u59d3\u540d -label.availability.zone=\u53ef\u7528\u533a\u57df +label.availability.zone=\u53ef\u7528\u8d44\u6e90\u57df label.availability=\u53ef\u7528\u6027 label.available.public.ips=\u53ef\u7528\u516c\u7528 IP \u5730\u5740 label.available=\u53ef\u7528 @@ -411,10 +411,10 @@ label.by.pod=\u6309\u63d0\u4f9b\u70b9 label.by.role=\u6309\u89d2\u8272 label.by.start.date=\u6309\u5f00\u59cb\u65e5\u671f label.by.state=\u6309\u72b6\u6001 -label.by.traffic.type=\u6309\u901a\u4fe1\u7c7b\u578b +label.by.traffic.type=\u6309\u6d41\u91cf\u7c7b\u578b label.by.type.id=\u6309\u7c7b\u578b ID label.by.type=\u6309\u7c7b\u578b -label.by.zone=\u6309\u533a\u57df +label.by.zone=\u6309\u8d44\u6e90\u57df label.bytes.received=\u63a5\u6536\u7684\u5b57\u8282\u6570 label.bytes.sent=\u53d1\u9001\u7684\u5b57\u8282\u6570 label.cancel=\u53d6\u6d88 @@ -474,7 +474,7 @@ label.create.template=\u521b\u5efa\u6a21\u677f label.create.VPN.connection=\u521b\u5efa VPN \u8fde\u63a5 label.created.by.system=\u7531\u7cfb\u7edf\u521b\u5efa label.created=\u521b\u5efa\u65e5\u671f -label.cross.zones=\u8de8\u533a\u57df +label.cross.zones=\u8de8\u8d44\u6e90\u57df label.custom.disk.size=\u81ea\u5b9a\u4e49\u78c1\u76d8\u5927\u5c0f label.daily=\u6bcf\u5929 label.data.disk.offering=\u6570\u636e\u78c1\u76d8\u65b9\u6848 @@ -505,7 +505,7 @@ label.deleting.failed=\u5220\u9664\u5931\u8d25 label.deleting.processing=\u6b63\u5728\u5220\u9664... label.description=\u8bf4\u660e label.destination.physical.network.id=\u76ee\u6807\u7269\u7406\u7f51\u7edc ID -label.destination.zone=\u76ee\u6807\u533a\u57df +label.destination.zone=\u76ee\u6807\u8d44\u6e90\u57df label.destroy.router=\u9500\u6bc1\u8def\u7531\u5668 label.destroy=\u9500\u6bc1 label.detaching.disk=\u6b63\u5728\u53d6\u6d88\u9644\u52a0\u78c1\u76d8 @@ -554,7 +554,7 @@ label.edit.lb.rule=\u7f16\u8f91\u8d1f\u8f7d\u5e73\u8861\u5668\u89c4\u5219 label.edit.network.details=\u7f16\u8f91\u7f51\u7edc\u8be6\u60c5 label.edit.project.details=\u7f16\u8f91\u9879\u76ee\u8be6\u60c5 label.edit.tags=\u7f16\u8f91\u6807\u7b7e -label.edit.traffic.type=\u7f16\u8f91\u901a\u4fe1\u7c7b\u578b +label.edit.traffic.type=\u7f16\u8f91\u6d41\u91cf\u7c7b\u578b label.edit.vpc=\u7f16\u8f91 VPC label.edit=\u7f16\u8f91 label.egress.rule=\u51fa\u53e3\u89c4\u5219 @@ -564,7 +564,7 @@ label.elastic.LB=\u5f39\u6027\u8d1f\u8f7d\u5e73\u8861\u5668 label.elastic=\u5f39\u6027 label.email=\u7535\u5b50\u90ae\u4ef6 label.enable.provider=\u542f\u7528\u63d0\u4f9b\u7a0b\u5e8f -label.enable.s3=\u542f\u7528 S3 \u652f\u6301\u7684\u8f85\u52a9\u5b58\u50a8 +label.enable.s3=\u542f\u7528 S3 \u652f\u6301\u7684\u4e8c\u7ea7\u5b58\u50a8 label.enable.swift=\u542f\u7528 SWIFT label.enable.vpn=\u542f\u7528 VPN label.enabling.vpn.access=\u6b63\u5728\u542f\u7528 VPN \u8bbf\u95ee @@ -601,6 +601,7 @@ label.full=\u6ee1\u8f7d label.gateway=\u7f51\u5173 label.general.alerts=\u5e38\u89c4\u8b66\u62a5 label.generating.url=\u6b63\u5728\u751f\u6210 URL +label.gluster.volume=\u5377 label.go.step.2=\u8f6c\u81f3\u6b65\u9aa4 2 label.go.step.3=\u8f6c\u81f3\u6b65\u9aa4 3 label.go.step.4=\u8f6c\u81f3\u6b65\u9aa4 4 @@ -615,7 +616,7 @@ label.guest.ip=\u6765\u5bbe IP \u5730\u5740 label.guest.netmask=\u6765\u5bbe\u7f51\u7edc\u63a9\u7801 label.guest.networks=\u6765\u5bbe\u7f51\u7edc label.guest.start.ip=\u6765\u5bbe\u8d77\u59cb IP -label.guest.traffic=\u6765\u5bbe\u901a\u4fe1 +label.guest.traffic=\u6765\u5bbe\u6d41\u91cf label.guest.type=\u6765\u5bbe\u7c7b\u578b label.guest=\u6765\u5bbe label.ha.enabled=\u5df2\u542f\u7528\u9ad8\u53ef\u7528\u6027 @@ -650,11 +651,11 @@ label.installWizard.addPodIntro.subtitle=\u4ec0\u4e48\u662f\u63d0\u4f9b\u70b9? label.installWizard.addPodIntro.title=\u6dfb\u52a0\u4e00\u4e2a\u63d0\u4f9b\u70b9 label.installWizard.addPrimaryStorageIntro.subtitle=\u4ec0\u4e48\u662f\u4e3b\u5b58\u50a8? label.installWizard.addPrimaryStorageIntro.title=\u6dfb\u52a0\u4e00\u4e2a\u4e3b\u5b58\u50a8 -label.installWizard.addSecondaryStorageIntro.subtitle=\u4ec0\u4e48\u662f\u8f85\u52a9\u5b58\u50a8? -label.installWizard.addSecondaryStorageIntro.title=\u6dfb\u52a0\u4e00\u4e2a\u8f85\u52a9\u5b58\u50a8 -label.installWizard.addZone.title=\u6dfb\u52a0\u533a\u57df -label.installWizard.addZoneIntro.subtitle=\u4ec0\u4e48\u662f\u533a\u57df? -label.installWizard.addZoneIntro.title=\u6dfb\u52a0\u4e00\u4e2a\u533a\u57df +label.installWizard.addSecondaryStorageIntro.subtitle=\u4ec0\u4e48\u662f\u4e8c\u7ea7\u5b58\u50a8? +label.installWizard.addSecondaryStorageIntro.title=\u6dfb\u52a0\u4e00\u4e2a\u4e8c\u7ea7\u5b58\u50a8 +label.installWizard.addZone.title=\u6dfb\u52a0\u8d44\u6e90\u57df +label.installWizard.addZoneIntro.subtitle=\u4ec0\u4e48\u662f\u8d44\u6e90\u57df? +label.installWizard.addZoneIntro.title=\u6dfb\u52a0\u4e00\u4e2a\u8d44\u6e90\u57df label.installWizard.click.launch=\u8bf7\u5355\u51fb\u201c\u542f\u52a8\u201d\u6309\u94ae\u3002 label.installWizard.subtitle=\u6b64\u6559\u7a0b\u5c06\u5e2e\u52a9\u60a8\u8bbe\u7f6e CloudStack&\#8482 \u5b89\u88c5 label.installWizard.title=\u60a8\u597d\uff0c\u6b22\u8fce\u4f7f\u7528 CloudStack&\#8482 @@ -698,13 +699,13 @@ label.item.listing=\u9879\u76ee\u5217\u8868 label.keep=\u4fdd\u7559 label.key=\u5bc6\u94a5 label.keyboard.type=\u952e\u76d8\u7c7b\u578b -label.kvm.traffic.label=KVM \u901a\u4fe1\u6807\u7b7e +label.kvm.traffic.label=KVM \u6d41\u91cf\u6807\u7b7e label.label=\u6807\u7b7e label.lang.arabic=\u963f\u62c9\u4f2f\u8bed label.lang.brportugese=\u8461\u8404\u7259\u8bed(\u5df4\u897f) label.lang.catalan=\u52a0\u6cf0\u7f57\u5c3c\u4e9a\u8bed label.lang.chinese=\u7b80\u4f53\u4e2d\u6587 -label.lang.dutch=Dutch (Netherlands) +label.lang.dutch=\u8377\u5170\u8bed(\u8377\u5170) label.lang.english=\u82f1\u8bed label.lang.french=\u6cd5\u8bed label.lang.german=\u5fb7\u8bed @@ -712,14 +713,14 @@ label.lang.italian=\u610f\u5927\u5229\u8bed label.lang.japanese=\u65e5\u8bed label.lang.korean=\u97e9\u8bed label.lang.norwegian=\u632a\u5a01\u8bed -label.lang.polish=Polish +label.lang.polish=\u6ce2\u5170\u8bed label.lang.russian=\u4fc4\u8bed label.lang.spanish=\u897f\u73ed\u7259\u8bed label.last.disconnected=\u4e0a\u6b21\u65ad\u5f00\u8fde\u63a5\u65f6\u95f4 label.last.name=\u59d3\u6c0f label.latest.events=\u6700\u65b0\u4e8b\u4ef6 label.launch.vm=\u542f\u52a8 VM -label.launch.zone=\u542f\u52a8\u533a\u57df +label.launch.zone=\u542f\u52a8\u8d44\u6e90\u57df label.launch=\u542f\u52a8 label.LB.isolation=\u8d1f\u8f7d\u5e73\u8861\u5668\u9694\u79bb label.least.connections=\u6700\u5c11\u8fde\u63a5\u7b97\u6cd5 @@ -747,7 +748,7 @@ label.max.memory=\u6700\u5927\u5185\u5b58(MiB) label.max.networks=\u6700\u5927\u7f51\u7edc\u6570 label.max.primary.storage=\u6700\u5927\u4e3b\u5b58\u50a8(GiB) label.max.public.ips=\u6700\u5927\u516c\u7528 IP \u6570 -label.max.secondary.storage=\u6700\u5927\u8f85\u52a9\u5b58\u50a8(GiB) +label.max.secondary.storage=\u6700\u5927\u4e8c\u7ea7\u5b58\u50a8(GiB) label.max.snapshots=\u6700\u5927\u5feb\u7167\u6570 label.max.templates=\u6700\u5927\u6a21\u677f\u6570 label.max.vms=\u6700\u5927\u7528\u6237 VM \u6570 @@ -787,7 +788,7 @@ label.menu.my.templates=\u6211\u7684\u6a21\u677f label.menu.network.offerings=\u7f51\u7edc\u65b9\u6848 label.menu.network=\u7f51\u7edc label.menu.physical.resources=\u7269\u7406\u8d44\u6e90 -label.menu.regions=\u533a\u57df +label.menu.regions=\u5730\u7406\u533a\u57df label.menu.running.instances=\u6b63\u5728\u8fd0\u884c\u7684\u5b9e\u4f8b label.menu.security.groups=\u5b89\u5168\u7ec4 label.menu.service.offerings=\u670d\u52a1\u65b9\u6848 @@ -863,7 +864,7 @@ label.nfs=NFS label.nic.adapter.type=NIC \u9002\u914d\u5668\u7c7b\u578b label.nicira.controller.address=\u63a7\u5236\u5668\u5730\u5740 label.nicira.l3gatewayserviceuuid=L3 Gateway Service UUID -label.nicira.transportzoneuuid=\u4f20\u8f93\u533a\u57df UUID +label.nicira.transportzoneuuid=\u4f20\u8f93\u8d44\u6e90\u57df UUID label.nics=NIC label.no.actions=\u65e0\u53ef\u7528\u64cd\u4f5c label.no.alerts=\u65e0\u6700\u8fd1\u53d1\u51fa\u7684\u8b66\u62a5 @@ -883,7 +884,7 @@ label.number.of.hosts=\u4e3b\u673a\u6570\u91cf label.number.of.pods=\u63d0\u4f9b\u70b9\u6570\u91cf label.number.of.system.vms=\u7cfb\u7edf VM \u6570 label.number.of.virtual.routers=\u865a\u62df\u8def\u7531\u5668\u6570 -label.number.of.zones=\u533a\u57df\u6570\u91cf +label.number.of.zones=\u8d44\u6e90\u57df\u6570\u91cf label.numretries=\u91cd\u8bd5\u6b21\u6570 label.ocfs2=OCFS2 label.offer.ha=\u63d0\u4f9b\u9ad8\u53ef\u7528\u6027 @@ -934,7 +935,7 @@ label.private.ip=\u4e13\u7528 IP \u5730\u5740 label.private.ips=\u4e13\u7528 IP \u5730\u5740 label.private.network=\u4e13\u7528\u7f51\u7edc label.private.port=\u4e13\u7528\u7aef\u53e3 -label.private.zone=\u4e13\u7528\u533a\u57df +label.private.zone=\u4e13\u7528\u8d44\u6e90\u57df label.privatekey=PKCS\#8 \u79c1\u94a5 label.project.dashboard=\u9879\u76ee\u63a7\u5236\u677f label.project.id=\u9879\u76ee ID @@ -950,8 +951,8 @@ label.public.ip=\u516c\u7528 IP \u5730\u5740 label.public.ips=\u516c\u7528 IP \u5730\u5740 label.public.network=\u516c\u7528\u7f51\u7edc label.public.port=\u516c\u7528\u7aef\u53e3 -label.public.traffic=\u516c\u5171\u901a\u4fe1 -label.public.zone=\u516c\u7528\u533a\u57df +label.public.traffic=\u516c\u5171\u6d41\u91cf +label.public.zone=\u516c\u7528\u8d44\u6e90\u57df label.public=\u516c\u7528 label.purpose=\u76ee\u7684 label.Pxe.server.type=Pxe \u670d\u52a1\u5668\u7c7b\u578b @@ -962,7 +963,7 @@ label.redundant.router.capability=\u5197\u4f59\u8def\u7531\u5668\u529f\u80fd label.redundant.router=\u5197\u4f59\u8def\u7531\u5668 label.redundant.state=\u5197\u4f59\u72b6\u6001 label.refresh=\u5237\u65b0 -label.region=\u533a\u57df +label.region=\u5730\u7406\u533a\u57df label.related=\u76f8\u5173\u8054 label.remind.later=\u4ee5\u540e\u63d0\u9192\u6211 label.remove.ACL=\u5220\u9664 ACL @@ -972,7 +973,7 @@ label.remove.ingress.rule=\u5220\u9664\u5165\u53e3\u89c4\u5219 label.remove.ip.range=\u5220\u9664 IP \u8303\u56f4 label.remove.pf=\u5220\u9664\u7aef\u53e3\u8f6c\u53d1\u89c4\u5219 label.remove.project.account=\u4ece\u9879\u76ee\u4e2d\u5220\u9664\u5e10\u6237 -label.remove.region=\u79fb\u9664\u533a\u57df +label.remove.region=\u5220\u9664\u5730\u7406\u533a\u57df label.remove.rule=\u5220\u9664\u89c4\u5219 label.remove.static.nat.rule=\u5220\u9664\u9759\u6001 NAT \u89c4\u5219 label.remove.static.route=\u5220\u9664\u9759\u6001\u8def\u7531 @@ -1019,11 +1020,11 @@ label.save=\u4fdd\u5b58 label.saving.processing=\u6b63\u5728\u4fdd\u5b58... label.scope=\u8303\u56f4 label.search=\u641c\u7d22 -label.secondary.storage.count=\u8f85\u52a9\u5b58\u50a8\u6c60 -label.secondary.storage.limits=\u8f85\u52a9\u5b58\u50a8\u9650\u5236(GiB) -label.secondary.storage.vm=\u8f85\u52a9\u5b58\u50a8 VM -label.secondary.storage=\u8f85\u52a9\u5b58\u50a8 -label.secondary.used=\u5df2\u4f7f\u7528\u7684\u8f85\u52a9\u5b58\u50a8 +label.secondary.storage.count=\u4e8c\u7ea7\u5b58\u50a8\u6c60 +label.secondary.storage.limits=\u4e8c\u7ea7\u5b58\u50a8\u9650\u5236(GiB) +label.secondary.storage.vm=\u4e8c\u7ea7\u5b58\u50a8 VM +label.secondary.storage=\u4e8c\u7ea7\u5b58\u50a8 +label.secondary.used=\u5df2\u4f7f\u7528\u7684\u4e8c\u7ea7\u5b58\u50a8 label.secret.key=\u5bc6\u94a5 label.security.group.name=\u5b89\u5168\u7ec4\u540d\u79f0 label.security.group=\u5b89\u5168\u7ec4 @@ -1031,7 +1032,7 @@ label.security.groups.enabled=\u5df2\u542f\u7528\u5b89\u5168\u7ec4 label.security.groups=\u5b89\u5168\u7ec4 label.select-view=\u9009\u62e9\u89c6\u56fe label.select.a.template=\u9009\u62e9\u4e00\u4e2a\u6a21\u677f -label.select.a.zone=\u9009\u62e9\u4e00\u4e2a\u533a\u57df +label.select.a.zone=\u9009\u62e9\u4e00\u4e2a\u8d44\u6e90\u57df label.select.instance.to.attach.volume.to=\u9009\u62e9\u8981\u5c06\u5377\u9644\u52a0\u5230\u7684\u5b9e\u4f8b label.select.instance=\u9009\u62e9\u5b9e\u4f8b label.select.iso.or.template=\u9009\u62e9 ISO \u6216\u6a21\u677f @@ -1045,9 +1046,9 @@ label.server=\u670d\u52a1\u5668 label.service.capabilities=\u670d\u52a1\u529f\u80fd label.service.offering=\u670d\u52a1\u65b9\u6848 label.session.expired=\u4f1a\u8bdd\u5df2\u8fc7\u671f -label.set.up.zone.type=\u8bbe\u7f6e\u533a\u57df\u7c7b\u578b +label.set.up.zone.type=\u8bbe\u7f6e\u8d44\u6e90\u57df\u7c7b\u578b label.setup.network=\u8bbe\u7f6e\u7f51\u7edc -label.setup.zone=\u8bbe\u7f6e\u533a\u57df +label.setup.zone=\u8bbe\u7f6e\u8d44\u6e90\u57df label.setup=\u8bbe\u7f6e label.shared=\u5df2\u5171\u4eab label.SharedMountPoint=SharedMountPoint @@ -1067,7 +1068,7 @@ label.source=\u6e90\u7b97\u6cd5 label.specify.IP.ranges=\u6307\u5b9a IP \u8303\u56f4 label.specify.vlan=\u6307\u5b9a VLAN label.specify.vxlan=\u6307\u5b9a VXLAN -label.SR.name = SR Name-Label +label.SR.name=SR \u540d\u79f0\u6807\u7b7e label.srx=SRX label.PA=Palo Alto label.start.IP=\u8d77\u59cb IP @@ -1108,10 +1109,10 @@ label.sticky.tablesize=\u8868\u5927\u5c0f label.stop=\u505c\u6b62 label.stopped.vms=\u5df2\u505c\u6b62\u7684 VM label.storage.tags=\u5b58\u50a8\u6807\u7b7e -label.storage.traffic=\u5b58\u50a8\u901a\u4fe1 +label.storage.traffic=\u5b58\u50a8\u6d41\u91cf label.storage.type=\u5b58\u50a8\u7c7b\u578b label.qos.type=QoS \u7c7b\u578b -label.cache.mode=Write-cache Type +label.cache.mode=\u5199\u5165\u7f13\u5b58\u7c7b\u578b label.storage=\u5b58\u50a8 label.subdomain.access=\u5b50\u57df\u8bbf\u95ee label.submit=\u63d0\u4ea4 @@ -1144,7 +1145,7 @@ label.tier.details=\u5c42\u8be6\u7ec6\u4fe1\u606f label.tier=\u5c42 label.time.zone=\u65f6\u533a label.time=\u65f6\u95f4 -label.timeout.in.second = Timeout(seconds) +label.timeout.in.second=\u8d85\u65f6(\u79d2) label.timeout=\u8d85\u65f6 label.timezone=\u65f6\u533a label.token=\u4ee4\u724c @@ -1156,9 +1157,9 @@ label.total.of.ip=\u603b IP \u5730\u5740\u6570 label.total.of.vm=\u603b VM \u6570 label.total.storage=\u5b58\u50a8\u603b\u91cf label.total.vms=\u603b VM \u6570 -label.traffic.label=\u901a\u4fe1\u6807\u7b7e -label.traffic.type=\u901a\u4fe1\u7c7b\u578b -label.traffic.types=\u901a\u4fe1\u7c7b\u578b +label.traffic.label=\u6d41\u91cf\u6807\u7b7e +label.traffic.type=\u6d41\u91cf\u7c7b\u578b +label.traffic.types=\u6d41\u91cf\u7c7b\u578b label.tuesday=\u661f\u671f\u4e8c label.type.id=\u7c7b\u578b ID label.type=\u7c7b\u578b @@ -1166,8 +1167,8 @@ label.unavailable=\u4e0d\u53ef\u7528 label.unlimited=\u65e0\u9650\u5236 label.untagged=\u5df2\u53d6\u6d88\u6807\u8bb0 label.update.project.resources=\u66f4\u65b0\u9879\u76ee\u8d44\u6e90 -label.update.ssl.cert= SSL Certificate -label.update.ssl= SSL Certificate +label.update.ssl.cert=SSL \u8bc1\u4e66 +label.update.ssl=SSL \u8bc1\u4e66 label.updating=\u6b63\u5728\u66f4\u65b0 label.upload.volume=\u4e0a\u8f7d\u5377 label.upload=\u4e0a\u8f7d @@ -1224,7 +1225,7 @@ label.vmsnapshot.memory=\u5feb\u7167\u5185\u5b58 label.vmsnapshot.parentname=\u7236\u540d\u79f0 label.vmsnapshot.type=\u7c7b\u578b label.vmsnapshot=VM \u5feb\u7167 -label.vmware.traffic.label=VMware \u901a\u4fe1\u6807\u7b7e +label.vmware.traffic.label=VMware \u6d41\u91cf\u6807\u7b7e label.volgroup=\u5377\u7ec4 label.volume.limits=\u5377\u9650\u5236 label.volume.name=\u5377\u540d\u79f0 @@ -1249,23 +1250,23 @@ label.weekly=\u6bcf\u5468 label.welcome.cloud.console=\u6b22\u8fce\u4f7f\u7528\u7ba1\u7406\u63a7\u5236\u53f0 label.welcome=\u6b22\u8fce label.what.is.cloudstack=\u4ec0\u4e48\u662f CloudStack&\#8482? -label.xen.traffic.label=XenServer \u901a\u4fe1\u6807\u7b7e +label.xen.traffic.label=XenServer \u6d41\u91cf\u6807\u7b7e label.yes=\u662f -label.zone.details=\u533a\u57df\u8be6\u60c5 -label.zone.id=\u533a\u57df ID -label.zone.name=\u533a\u57df\u540d\u79f0 +label.zone.details=\u8d44\u6e90\u57df\u8be6\u7ec6\u4fe1\u606f +label.zone.id=\u8d44\u6e90\u57df ID +label.zone.name=\u8d44\u6e90\u57df\u540d\u79f0 label.zone.step.1.title=\u6b65\u9aa4 1\: \u9009\u62e9\u4e00\u4e2a\u7f51\u7edc -label.zone.step.2.title=\u6b65\u9aa4 2\: \u6dfb\u52a0\u4e00\u4e2a\u533a\u57df +label.zone.step.2.title=\u6b65\u9aa4 2\: \u6dfb\u52a0\u4e00\u4e2a\u8d44\u6e90\u57df label.zone.step.3.title=\u6b65\u9aa4 3\: \u6dfb\u52a0\u4e00\u4e2a\u63d0\u4f9b\u70b9 label.zone.step.4.title=\u6b65\u9aa4 4\: \u6dfb\u52a0\u4e00\u4e2a IP \u8303\u56f4 -label.zone.type=\u533a\u57df\u7c7b\u578b -label.zone.wide=\u6574\u4e2a\u533a\u57df -label.zone=\u533a\u57df -label.zones=\u533a\u57df -label.zoneWizard.trafficType.guest=\u6765\u5bbe\: \u6700\u7ec8\u7528\u6237\u865a\u62df\u673a\u4e4b\u95f4\u7684\u901a\u4fe1 -label.zoneWizard.trafficType.management=\u7ba1\u7406\: CloudStack \u7684\u5185\u90e8\u8d44\u6e90(\u5305\u62ec\u4e0e\u7ba1\u7406\u670d\u52a1\u5668\u901a\u4fe1\u7684\u4efb\u4f55\u7ec4\u4ef6\uff0c\u4f8b\u5982\u4e3b\u673a\u548c CloudStack \u7cfb\u7edf VM)\u4e4b\u95f4\u7684\u901a\u4fe1 -label.zoneWizard.trafficType.public=\u516c\u7528\: \u4e91\u4e2d Internet \u4e0e\u865a\u62df\u673a\u4e4b\u95f4\u7684\u901a\u4fe1\u3002 -label.zoneWizard.trafficType.storage=\u5b58\u50a8\: \u4e3b\u5b58\u50a8\u670d\u52a1\u5668\u4e0e\u8f85\u52a9\u5b58\u50a8\u670d\u52a1\u5668(\u4f8b\u5982 VM \u6a21\u677f\u4e0e\u5feb\u7167)\u4e4b\u95f4\u7684\u901a\u4fe1 +label.zone.type=\u8d44\u6e90\u57df\u7c7b\u578b +label.zone.wide=\u6574\u4e2a\u8d44\u6e90\u57df +label.zone=\u8d44\u6e90\u57df +label.zones=\u8d44\u6e90\u57df +label.zoneWizard.trafficType.guest=\u6765\u5bbe\: \u6700\u7ec8\u7528\u6237\u865a\u62df\u673a\u4e4b\u95f4\u7684\u6d41\u91cf +label.zoneWizard.trafficType.management=\u7ba1\u7406\: CloudStack \u7684\u5185\u90e8\u8d44\u6e90(\u5305\u62ec\u4e0e\u7ba1\u7406\u670d\u52a1\u5668\u901a\u4fe1\u7684\u4efb\u4f55\u7ec4\u4ef6\uff0c\u4f8b\u5982\u4e3b\u673a\u548c CloudStack \u7cfb\u7edf VM)\u4e4b\u95f4\u7684\u6d41\u91cf +label.zoneWizard.trafficType.public=\u516c\u5171\: \u4e91\u4e2d Internet \u4e0e\u865a\u62df\u673a\u4e4b\u95f4\u7684\u6d41\u91cf\u3002 +label.zoneWizard.trafficType.storage=\u5b58\u50a8\: \u4e3b\u5b58\u50a8\u670d\u52a1\u5668\u4e0e\u4e8c\u7ea7\u5b58\u50a8\u670d\u52a1\u5668(\u4f8b\u5982 VM \u6a21\u677f\u4e0e\u5feb\u7167)\u4e4b\u95f4\u7684\u6d41\u91cf label.ldap.group.name=LDAP \u7ec4 label.password.reset.confirm=\u5bc6\u7801\u5df2\u91cd\u7f6e\u4e3a label.provider=\u63d0\u4f9b\u7a0b\u5e8f @@ -1283,17 +1284,18 @@ label.ipv6.address=IPv6 IP \u5730\u5740 label.ipv6.gateway=IPv6 \u7f51\u5173 label.ipv6.CIDR=IPv6 CIDR label.VPC.limits=VPC \u9650\u5236 -label.edit.region=\u7f16\u8f91\u533a\u57df +label.edit.region=\u7f16\u8f91\u5730\u7406\u533a\u57df label.gslb.domain.name=GSLB \u57df\u540d label.add.gslb=\u6dfb\u52a0 GSLB label.gslb.servicetype=\u670d\u52a1\u7c7b\u578b label.gslb.details=GSLB \u8be6\u7ec6\u4fe1\u606f label.gslb.delete=\u5220\u9664 GSLB -label.opendaylight.controllers=OpenDaylight Controllers +label.opendaylight.controller=OpenDaylight \u63a7\u5236\u5668 +label.opendaylight.controllers=OpenDaylight \u63a7\u5236\u5668 label.portable.ip.ranges=\u53ef\u79fb\u690d IP \u8303\u56f4 label.add.portable.ip.range=\u6dfb\u52a0\u53ef\u79fb\u690d IP \u8303\u56f4 label.delete.portable.ip.range=\u5220\u9664\u53ef\u79fb\u690d IP \u8303\u56f4 -label.opendaylight.controllerdetail=OpenDaylight Controller Details +label.opendaylight.controllerdetail=OpenDaylight \u63a7\u5236\u5668\u8be6\u7ec6\u4fe1\u606f label.portable.ip.range.details=\u53ef\u79fb\u690d IP \u8303\u56f4\u8be6\u7ec6\u4fe1\u606f label.portable.ips=\u53ef\u79fb\u690d IP label.gslb.assigned.lb=\u5df2\u5206\u914d\u8d1f\u8f7d\u5e73\u8861 @@ -1305,22 +1307,183 @@ label.enable.autoscale=\u542f\u7528\u81ea\u52a8\u6269\u5c55 label.disable.autoscale=\u7981\u7528\u81ea\u52a8\u6269\u5c55 label.min.instances=\u6700\u5c0f\u5b9e\u4f8b\u6570 label.max.instances=\u6700\u5927\u5b9e\u4f8b\u6570 -label.add.OpenDaylight.device=Add OpenDaylight Controller +label.add.OpenDaylight.device=\u6dfb\u52a0 OpenDaylight \u63a7\u5236\u5668 label.show.advanced.settings=\u663e\u793a\u9ad8\u7ea7\u8bbe\u7f6e -label.delete.OpenDaylight.device=Delete OpenDaylight Controller +label.delete.OpenDaylight.device=\u5220\u9664 OpenDaylight \u63a7\u5236\u5668 label.polling.interval.sec=\u8f6e\u8be2\u65f6\u95f4\u95f4\u9694(\u79d2) label.quiet.time.sec=\u5b89\u9759\u65f6\u95f4(\u79d2) label.destroy.vm.graceperiod=\u9500\u6bc1 VM \u5bbd\u9650\u671f label.SNMP.community=SNMP \u793e\u533a label.SNMP.port=SNMP \u7aef\u53e3 label.add.ucs.manager=\u6dfb\u52a0 UCS \u7ba1\u7406\u5668 -label.ovm.traffic.label=OVM \u901a\u4fe1\u6807\u7b7e -label.lxc.traffic.label=LXC \u901a\u4fe1\u6807\u7b7e -label.hyperv.traffic.label=HyperV \u901a\u4fe1\u6807\u7b7e +label.ovm.traffic.label=OVM \u6d41\u91cf\u6807\u7b7e +label.lxc.traffic.label=LXC \u6d41\u91cf\u6807\u7b7e +label.hyperv.traffic.label=HyperV \u6d41\u91cf\u6807\u7b7e +label.resource.name=\u8d44\u6e90\u540d\u79f0 +label.reource.id=\u8d44\u6e90 ID +label.vnmc.devices=VNMC \u8bbe\u5907 +label.add.vnmc.provider=\u6dfb\u52a0 VNMC \u63d0\u4f9b\u7a0b\u5e8f +label.enable.vnmc.provider=\u542f\u7528 VNMC \u63d0\u4f9b\u7a0b\u5e8f +label.add.vnmc.device=\u6dfb\u52a0 VNMC \u8bbe\u5907 +label.ciscovnmc.resource.details=CiscoVNMC \u8d44\u6e90\u8be6\u7ec6\u4fe1\u606f +label.delete.ciscovnmc.resource=\u5220\u9664 CiscoVNMC \u8d44\u6e90 +label.enable.vnmc.device=\u542f\u7528 VNMC \u8bbe\u5907 +label.disbale.vnmc.device=\u7981\u7528 VNMC \u8bbe\u5907 +label.disable.vnmc.provider=\u7981\u7528 VNMC \u63d0\u4f9b\u7a0b\u5e8f +label.services=\u670d\u52a1 +label.secondary.staging.store=\u4e8c\u7ea7\u6682\u5b58\u5b58\u50a8 +label.release.account=\u4ece\u5e10\u6237\u4e2d\u91ca\u653e +label.release.account.lowercase=\u4ece\u5e10\u6237\u4e2d\u91ca\u653e +label.vlan.vni.ranges=VLAN/VNI \u8303\u56f4 +label.dedicated.vlan.vni.ranges=VLAN/VNI \u8303\u56f4\u5df2\u4e13\u7528 +label.dedicate.vlan.vni.range=\u5c06 VLAN/VNI \u8303\u56f4\u4e13\u7528 +label.vlan.vni.range=VLAN/VNI \u8303\u56f4 +label.vlan.range.details=VLAN \u8303\u56f4\u8be6\u7ec6\u4fe1\u606f +label.release.dedicated.vlan.range=\u91ca\u653e\u4e13\u7528 VLAN \u8303\u56f4 +label.broadcat.uri=\u5e7f\u64ad URI +label.ipv4.cidr=IPv4 CIDR +label.guest.network.details=\u6765\u5bbe\u7f51\u7edc\u8be6\u7ec6\u4fe1\u606f +label.ipv4.gateway=IPv4 \u7f51\u5173 +label.release.dedicated.vlan.range=\u91ca\u653e\u4e13\u7528 VLAN \u8303\u56f4 +label.vlan.ranges=VLAN \u8303\u56f4 +label.virtual.appliance.details=\u865a\u62df\u8bbe\u5907\u8be6\u7ec6\u4fe1\u606f +label.start.lb.vm=\u542f\u52a8 LB VM +label.stop.lb.vm=\u505c\u6b62 LB VM +label.migrate.lb.vm=\u8fc1\u79fb LB VM +label.vpc.virtual.router=VPC \u865a\u62df\u8def\u7531\u5668 +label.ovs=OVS +label.gslb.service=GSLB \u670d\u52a1 +label.gslb.service.public.ip=GSLB \u670d\u52a1\u516c\u7528 IP +label.gslb.service.private.ip=GSLB \u670d\u52a1\u4e13\u7528 IP +label.baremetal.dhcp.provider=\u88f8\u673a DHCP \u63d0\u4f9b\u7a0b\u5e8f +label.add.baremetal.dhcp.device=\u6dfb\u52a0\u88f8\u673a DHCP \u8bbe\u5907 +label.baremetal.pxe.provider=\u88f8\u673a PXE \u63d0\u4f9b\u7a0b\u5e8f +label.baremetal.pxe.device=\u6dfb\u52a0\u88f8\u673a PXE \u8bbe\u5907 +label.tftp.root.directory=Tftp \u6839\u76ee\u5f55 +label.add.vmware.datacenter=\u6dfb\u52a0 VMware \u6570\u636e\u4e2d\u5fc3 +label.remove.vmware.datacenter=\u5220\u9664 VMware \u6570\u636e\u4e2d\u5fc3 +label.dc.name=\u6570\u636e\u4e2d\u5fc3\u540d\u79f0 +label.vcenter=vCenter +label.dedicate.zone=\u5c06\u8d44\u6e90\u57df\u4e13\u7528 +label.zone.dedicated=\u8d44\u6e90\u57df\u5df2\u4e13\u7528 +label.release.dedicated.zone=\u91ca\u653e\u4e13\u7528\u8d44\u6e90\u57df +label.ipv6.dns1=IPv6 DNS1 +label.ipv6.dns2=IPv6 DNS2 +label.vmware.datacenter.name=VMware \u6570\u636e\u4e2d\u5fc3\u540d\u79f0 +label.vmware.datacenter.vcenter=VMware \u6570\u636e\u4e2d\u5fc3 vCenter +label.vmware.datacenter.id=VMware \u6570\u636e\u4e2d\u5fc3 ID +label.system.vm.details=\u7cfb\u7edf VM \u8be6\u7ec6\u4fe1\u606f +label.system.vm.scaled.up=\u5df2\u6269\u5c55\u7cfb\u7edf VM +label.console.proxy.vm=\u63a7\u5236\u5668\u4ee3\u7406 VM +label.settings=\u8bbe\u7f6e +label.requires.upgrade=\u9700\u8981\u5347\u7ea7 +label.upgrade.router.newer.template=\u5347\u7ea7\u8def\u7531\u5668\u4ee5\u4f7f\u7528\u66f4\u65b0\u7684\u6a21\u677f +label.router.vm.scaled.up=\u5df2\u6269\u5c55\u8def\u7531\u5668 VM +label.total.virtual.routers=\u865a\u62df\u8def\u7531\u5668\u603b\u6570 +label.upgrade.required=\u9700\u8981\u5347\u7ea7 +label.virtual.routers.group.zone=\u865a\u62df\u8def\u7531\u5668(\u6309\u8d44\u6e90\u57df\u5206\u7ec4) +label.total.virtual.routers.upgrade=\u9700\u8981\u5347\u7ea7\u7684\u865a\u62df\u8def\u7531\u5668\u603b\u6570 +label.virtual.routers.group.pod=\u865a\u62df\u8def\u7531\u5668(\u6309\u63d0\u4f9b\u70b9\u5206\u7ec4) +label.virtual.routers.group.cluster=\u865a\u62df\u8def\u7531\u5668(\u6309\u7fa4\u96c6\u5206\u7ec4) +label.zone.lower=\u8d44\u6e90\u57df +label.virtual.routers.group.account=\u865a\u62df\u8def\u7531\u5668(\u6309\u5e10\u6237\u5206\u7ec4) +label.netscaler.details=NetScaler \u8be6\u7ec6\u4fe1\u606f +label.baremetal.dhcp.devices=\u88f8\u673a DHCP \u8bbe\u5907 +label.baremetal.pxe.devices=\u88f8\u673a PXE \u8bbe\u5907 +label.addes.new.f5=\u5df2\u6dfb\u52a0\u65b0 F5 +label.f5.details=F5 \u8be6\u7ec6\u4fe1\u606f +label.srx.details=SRX \u8be6\u7ec6\u4fe1\u606f +label.palo.alto.details=Palo Alto \u8be6\u7ec6\u4fe1\u606f +label.added.nicira.nvp.controller=\u5df2\u6dfb\u52a0\u65b0 Nicira NVP \u63a7\u5236\u5668\ +label.nicira.nvp.details=Nicira NVP \u8be6\u7ec6\u4fe1\u606f +label.added.new.bigswitch.vns.controller=\u5df2\u6dfb\u52a0\u65b0 BigSwitch VNS \u63a7\u5236\u5668 +label.bigswitch.vns.details=BigSwitch VNS \u8be6\u7ec6\u4fe1\u606f +label.dedicate=\u4e13\u7528 +label.dedicate.pod=\u5c06\u63d0\u4f9b\u70b9\u4e13\u7528 +label.pod.dedicated=\u63d0\u4f9b\u70b9\u5df2\u4e13\u7528 +label.release.dedicated.pod=\u91ca\u653e\u4e13\u7528\u63d0\u4f9b\u70b9 +label.override.public.traffic=\u66ff\u4ee3\u516c\u5171\u6d41\u91cf +label.public.traffic.vswitch.type=\u516c\u5171\u6d41\u91cf\u865a\u62df\u4ea4\u6362\u673a\u7c7b\u578b +label.public.traffic.vswitch.name=\u516c\u5171\u6d41\u91cf\u865a\u62df\u4ea4\u6362\u673a\u540d\u79f0 +label.override.guest.traffic=\u66ff\u4ee3\u6765\u5bbe\u6d41\u91cf +label.guest.traffic.vswitch.type=\u6765\u5bbe\u6d41\u91cf\u865a\u62df\u4ea4\u6362\u673a\u7c7b\u578b +label.guest.traffic.vswitch.name=\u6765\u5bbe\u6d41\u91cf\u865a\u62df\u4ea4\u6362\u673a\u540d\u79f0 +label.cisco.nexus1000v.ip.address=Nexus 1000v IP \u5730\u5740 +label.cisco.nexus1000v.username=Nexus 1000v \u7528\u6237\u540d +label.cisco.nexus1000v.password=Nexus 1000v \u5bc6\u7801 +label.dedicate.cluster=\u5c06\u7fa4\u96c6\u4e13\u7528 +label.release.dedicated.cluster=\u91ca\u653e\u4e13\u7528\u7fa4\u96c6 +label.dedicate.host=\u5c06\u4e3b\u673a\u4e13\u7528 +label.release.dedicated.host=\u91ca\u653e\u4e13\u7528\u4e3b\u673a +label.number.of.cpu.sockets=CPU \u63d2\u69fd\u6570 +label.delete.ucs.manager=\u5220\u9664 UCS Manager +label.blades=\u5200\u7247\u5f0f\u670d\u52a1\u5668 +label.chassis=\u673a\u7bb1 +label.blade.id=\u5200\u7247\u5f0f\u670d\u52a1\u5668 ID +label.associated.profile=\u5df2\u5173\u8054\u914d\u7f6e\u6587\u4ef6 +label.refresh.blades=\u5237\u65b0\u5200\u7247\u5f0f\u670d\u52a1\u5668 +label.instanciate.template.associate.profile.blade=\u5c06\u6a21\u677f\u5b9e\u4f8b\u5316\u5e76\u5c06\u914d\u7f6e\u6587\u4ef6\u4e0e\u5200\u7247\u5f0f\u670d\u52a1\u5668\u5173\u8054 +label.select.template=\u9009\u62e9\u6a21\u677f +label.profile=\u914d\u7f6e\u6587\u4ef6 +label.delete.profile=\u5220\u9664\u914d\u7f6e\u6587\u4ef6 +label.disassociate.profile.blade=\u53d6\u6d88\u5c06\u914d\u7f6e\u6587\u4ef6\u4e0e\u5200\u7247\u5f0f\u670d\u52a1\u5668\u5173\u8054 +label.secondary.storage.details=\u4e8c\u7ea7\u5b58\u50a8\u8be6\u7ec6\u4fe1\u606f +label.secondary.staging.store.details=\u4e8c\u7ea7\u6682\u5b58\u5b58\u50a8\u8be6\u7ec6\u4fe1\u606f +label.add.nfs.secondary.staging.store=\u6dfb\u52a0 NFS \u4e8c\u7ea7\u6682\u5b58\u5b58\u50a8 +label.delete.secondary.staging.store=\u5220\u9664\u4e8c\u7ea7\u6682\u5b58\u5b58\u50a8 +label.ipv4.start.ip=IPv4 \u8d77\u59cb IP +label.ipv4.end.ip=IPv4 \u7ed3\u675f IP +label.ipv6.start.ip=IPv6 \u8d77\u59cb IP +label.ipv6.end.ip=IPv6 \u7ed3\u675f IP +label.vm.password=VM \u7684\u5bc6\u7801 +label.group.by.zone=\u6309\u8d44\u6e90\u57df\u5206\u7ec4 +label.group.by.pod=\u6309\u63d0\u4f9b\u70b9\u5206\u7ec4 +label.group.by.cluster=\u6309\u7fa4\u96c6\u5206\u7ec4 +label.group.by.account=\u6309\u5e10\u6237\u5206\u7ec4 +label.no.grouping=(\u4e0d\u5206\u7ec4)\ +label.create.nfs.secondary.staging.storage=\u521b\u5efa NFS \u4e8c\u7ea7\u6682\u5b58\u5b58\u50a8 +label.username.lower=\u7528\u6237\u540d +label.password.lower=\u5bc6\u7801 +label.email.lower=\u7535\u5b50\u90ae\u4ef6 +label.firstname.lower=\u540d\u5b57 +label.lastname.lower=\u59d3\u6c0f +label.domain.lower=\u57df +label.account.lower=\u5e10\u6237 +label.type.lower=\u7c7b\u578b +label.rule.number=\u89c4\u5219\u7f16\u53f7 +label.action=\u64cd\u4f5c +label.name.lower=\u540d\u79f0 +label.ucs=UCS +label.change.affinity=\u66f4\u6539\u5173\u8054\u6027 +label.persistent=\u6c38\u4e45 +label.broadcasturi=\u5e7f\u64ad URI +label.network.cidr=\u7f51\u7edc CIDR +label.reserved.ip.range=\u9884\u7559 IP \u8303\u56f4 +label.autoscale=\u81ea\u52a8\u6269\u5c55 +label.health.check=\u8fd0\u884c\u72b6\u51b5\u68c0\u67e5 +label.public.load.balancer.provider=\u516c\u7528\u8d1f\u8f7d\u5e73\u8861\u5668\u63d0\u4f9b\u7a0b\u5e8f +label.add.isolated.network=\u6dfb\u52a0\u9694\u79bb\u7f51\u7edc +label.vlan=VLAN +label.secondary.isolated.vlan.id=\u4e8c\u7ea7\u9694\u79bb VLAN ID +label.ipv4.netmask=IPv4 \u7f51\u7edc\u63a9\u7801 +label.custom=\u81ea\u5b9a\u4e49 +label.disable.network.offering=\u7981\u7528\u7f51\u7edc\u65b9\u6848 +label.enable.network.offering=\u542f\u7528\u7f51\u7edc\u65b9\u6848 +label.remove.network.offering=\u5220\u9664\u7f51\u7edc\u65b9\u6848 +label.system.offering.for.router=\u8def\u7531\u5668\u7684\u7cfb\u7edf\u65b9\u6848 +label.mode=\u6a21\u5f0f +label.associate.public.ip=\u5173\u8054\u516c\u7528 IP +label.acl=ACL +label.user.data=\u7528\u6237\u6570\u636e +label.virtual.networking=\u865a\u62df\u7f51\u7edc\u8fde\u63a5 +label.allow=\u5141\u8bb8 +label.deny=\u62d2\u7edd +label.default.egress.policy=\u9ed8\u8ba4\u51fa\u53e3\u89c4\u5219 +label.xenserver.tools.version.61.plus=XenServer Tools \u7248\u672c 6.1\+ managed.state=\u6258\u7ba1\u72b6\u6001 message.acquire.new.ip.vpc=\u8bf7\u786e\u8ba4\u60a8\u786e\u5b9e\u8981\u4e3a\u6b64 VPC \u83b7\u53d6\u4e00\u4e2a\u65b0 IP\u3002 message.acquire.new.ip=\u8bf7\u786e\u8ba4\u60a8\u786e\u5b9e\u8981\u4e3a\u6b64\u7f51\u7edc\u83b7\u53d6\u4e00\u4e2a\u65b0 IP\u3002 -message.acquire.public.ip=\u8bf7\u9009\u62e9\u4e00\u4e2a\u8981\u4ece\u4e2d\u83b7\u53d6\u65b0 IP \u7684\u533a\u57df\u3002 +message.acquire.public.ip=\u8bf7\u9009\u62e9\u4e00\u4e2a\u8981\u4ece\u4e2d\u83b7\u53d6\u65b0 IP \u7684\u8d44\u6e90\u57df\u3002 message.action.cancel.maintenance.mode=\u8bf7\u786e\u8ba4\u60a8\u786e\u5b9e\u8981\u53d6\u6d88\u6b64\u7ef4\u62a4\u6a21\u5f0f\u3002 message.action.cancel.maintenance=\u5df2\u6210\u529f\u53d6\u6d88\u7ef4\u62a4\u60a8\u7684\u4e3b\u673a\u3002\u6b64\u8fc7\u7a0b\u53ef\u80fd\u9700\u8981\u957f\u8fbe\u51e0\u5206\u949f\u65f6\u95f4\u3002 message.action.change.service.warning.for.instance=\u5fc5\u987b\u5148\u7981\u7528\u60a8\u7684\u5b9e\u4f8b\uff0c\u7136\u540e\u518d\u5c1d\u8bd5\u66f4\u6539\u5176\u5f53\u524d\u7684\u670d\u52a1\u65b9\u6848\u3002 @@ -1331,22 +1494,22 @@ message.action.delete.domain=\u8bf7\u786e\u8ba4\u60a8\u786e\u5b9e\u8981\u5220\u9 message.action.delete.external.firewall=\u8bf7\u786e\u8ba4\u60a8\u786e\u5b9e\u8981\u5220\u9664\u6b64\u5916\u90e8\u9632\u706b\u5899\u3002\u8b66\u544a\: \u5982\u679c\u60a8\u8ba1\u5212\u91cd\u65b0\u6dfb\u52a0\u540c\u4e00\u4e2a\u5916\u90e8\u9632\u706b\u5899\uff0c\u5219\u5fc5\u987b\u5728\u8bbe\u5907\u4e0a\u91cd\u7f6e\u4f7f\u7528\u6570\u636e\u3002 message.action.delete.external.load.balancer=\u8bf7\u786e\u8ba4\u60a8\u786e\u5b9e\u8981\u5220\u9664\u6b64\u5916\u90e8\u8d1f\u8f7d\u5e73\u8861\u5668\u3002\u8b66\u544a\: \u5982\u679c\u60a8\u8ba1\u5212\u91cd\u65b0\u6dfb\u52a0\u540c\u4e00\u4e2a\u5916\u90e8\u8d1f\u8f7d\u5e73\u8861\u5668\uff0c\u5219\u5fc5\u987b\u5728\u8bbe\u5907\u4e0a\u91cd\u7f6e\u4f7f\u7528\u6570\u636e\u3002 message.action.delete.ingress.rule=\u8bf7\u786e\u8ba4\u60a8\u786e\u5b9e\u8981\u5220\u9664\u6b64\u5165\u53e3\u89c4\u5219\u3002 -message.action.delete.ISO.for.all.zones=\u6b64 ISO \u7531\u6240\u6709\u533a\u57df\u4f7f\u7528\u3002\u8bf7\u786e\u8ba4\u60a8\u786e\u5b9e\u8981\u5c06\u5176\u4ece\u6240\u6709\u533a\u57df\u4e2d\u5220\u9664\u3002 +message.action.delete.ISO.for.all.zones=\u6b64 ISO \u7531\u6240\u6709\u8d44\u6e90\u57df\u4f7f\u7528\u3002\u8bf7\u786e\u8ba4\u60a8\u786e\u5b9e\u8981\u5c06\u5176\u4ece\u6240\u6709\u8d44\u6e90\u57df\u4e2d\u5220\u9664\u3002 message.action.delete.ISO=\u8bf7\u786e\u8ba4\u60a8\u786e\u5b9e\u8981\u5220\u9664\u6b64 ISO\u3002 message.action.delete.network=\u8bf7\u786e\u8ba4\u60a8\u786e\u5b9e\u8981\u5220\u9664\u6b64\u7f51\u7edc\u3002 message.action.delete.nexusVswitch=\u8bf7\u786e\u8ba4\u60a8\u786e\u5b9e\u8981\u5220\u9664\u6b64 Nexus 1000v message.action.delete.physical.network=\u8bf7\u786e\u8ba4\u60a8\u786e\u5b9e\u8981\u5220\u9664\u6b64\u7269\u7406\u7f51\u7edc message.action.delete.pod=\u8bf7\u786e\u8ba4\u60a8\u786e\u5b9e\u8981\u5220\u9664\u6b64\u63d0\u4f9b\u70b9\u3002 message.action.delete.primary.storage=\u8bf7\u786e\u8ba4\u60a8\u786e\u5b9e\u8981\u5220\u9664\u6b64\u4e3b\u5b58\u50a8\u3002 -message.action.delete.secondary.storage=\u8bf7\u786e\u8ba4\u60a8\u786e\u5b9e\u8981\u5220\u9664\u6b64\u8f85\u52a9\u5b58\u50a8\u3002 +message.action.delete.secondary.storage=\u8bf7\u786e\u8ba4\u60a8\u786e\u5b9e\u8981\u5220\u9664\u6b64\u4e8c\u7ea7\u5b58\u50a8\u3002 message.action.delete.security.group=\u8bf7\u786e\u8ba4\u60a8\u786e\u5b9e\u8981\u5220\u9664\u6b64\u5b89\u5168\u7ec4\u3002 message.action.delete.service.offering=\u8bf7\u786e\u8ba4\u60a8\u786e\u5b9e\u8981\u5220\u9664\u6b64\u670d\u52a1\u65b9\u6848\u3002 message.action.delete.snapshot=\u8bf7\u786e\u8ba4\u60a8\u786e\u5b9e\u8981\u5220\u9664\u6b64\u5feb\u7167\u3002 message.action.delete.system.service.offering=\u8bf7\u786e\u8ba4\u60a8\u786e\u5b9e\u8981\u5220\u9664\u6b64\u7cfb\u7edf\u670d\u52a1\u65b9\u6848\u3002 -message.action.delete.template.for.all.zones=\u6b64\u6a21\u677f\u7531\u6240\u6709\u533a\u57df\u4f7f\u7528\u3002\u8bf7\u786e\u8ba4\u60a8\u786e\u5b9e\u8981\u5c06\u5176\u4ece\u6240\u6709\u533a\u57df\u4e2d\u5220\u9664\u3002 +message.action.delete.template.for.all.zones=\u6b64\u6a21\u677f\u7531\u6240\u6709\u8d44\u6e90\u57df\u4f7f\u7528\u3002\u8bf7\u786e\u8ba4\u60a8\u786e\u5b9e\u8981\u5c06\u5176\u4ece\u6240\u6709\u8d44\u6e90\u57df\u4e2d\u5220\u9664\u3002 message.action.delete.template=\u8bf7\u786e\u8ba4\u60a8\u786e\u5b9e\u8981\u5220\u9664\u6b64\u6a21\u677f\u3002 message.action.delete.volume=\u8bf7\u786e\u8ba4\u60a8\u786e\u5b9e\u8981\u5220\u9664\u6b64\u5377\u3002 -message.action.delete.zone=\u8bf7\u786e\u8ba4\u60a8\u786e\u5b9e\u8981\u5220\u9664\u6b64\u533a\u57df\u3002 +message.action.delete.zone=\u8bf7\u786e\u8ba4\u60a8\u786e\u5b9e\u8981\u5220\u9664\u6b64\u8d44\u6e90\u57df\u3002 message.action.destroy.instance=\u8bf7\u786e\u8ba4\u60a8\u786e\u5b9e\u8981\u9500\u6bc1\u6b64\u5b9e\u4f8b\u3002 message.action.destroy.systemvm=\u8bf7\u786e\u8ba4\u60a8\u786e\u5b9e\u8981\u9500\u6bc1\u6b64\u7cfb\u7edf VM\u3002 message.action.disable.cluster=\u8bf7\u786e\u8ba4\u60a8\u786e\u5b9e\u8981\u7981\u7528\u6b64\u7fa4\u96c6\u3002 @@ -1354,7 +1517,7 @@ message.action.disable.nexusVswitch=\u8bf7\u786e\u8ba4\u60a8\u786e\u5b9e\u8981\u message.action.disable.physical.network=\u8bf7\u786e\u8ba4\u60a8\u786e\u5b9e\u8981\u7981\u7528\u6b64\u7269\u7406\u7f51\u7edc\u3002 message.action.disable.pod=\u8bf7\u786e\u8ba4\u60a8\u786e\u5b9e\u8981\u7981\u7528\u6b64\u63d0\u4f9b\u70b9\u3002 message.action.disable.static.NAT=\u8bf7\u786e\u8ba4\u60a8\u786e\u5b9e\u8981\u7981\u7528\u9759\u6001 NAT\u3002 -message.action.disable.zone=\u8bf7\u786e\u8ba4\u60a8\u786e\u5b9e\u8981\u7981\u7528\u6b64\u533a\u57df\u3002 +message.action.disable.zone=\u8bf7\u786e\u8ba4\u60a8\u786e\u5b9e\u8981\u7981\u7528\u6b64\u8d44\u6e90\u57df\u3002 message.action.download.iso=\u8bf7\u786e\u8ba4\u60a8\u786e\u5b9e\u8981\u4e0b\u8f7d\u6b64 ISO\u3002 message.action.download.template=\u8bf7\u786e\u8ba4\u60a8\u786e\u5b9e\u8981\u4e0b\u8f7d\u6b64\u6a21\u677f\u3002 message.action.enable.cluster=\u8bf7\u786e\u8ba4\u60a8\u786e\u5b9e\u8981\u542f\u7528\u6b64\u7fa4\u96c6\u3002 @@ -1362,7 +1525,7 @@ message.action.enable.maintenance=\u5df2\u6210\u529f\u51c6\u5907\u597d\u7ef4\u62 message.action.enable.nexusVswitch=\u8bf7\u786e\u8ba4\u60a8\u786e\u5b9e\u8981\u542f\u7528\u6b64 Nexus 1000v message.action.enable.physical.network=\u8bf7\u786e\u8ba4\u60a8\u786e\u5b9e\u8981\u542f\u7528\u6b64\u7269\u7406\u7f51\u7edc\u3002 message.action.enable.pod=\u8bf7\u786e\u8ba4\u60a8\u786e\u5b9e\u8981\u542f\u7528\u6b64\u63d0\u4f9b\u70b9\u3002 -message.action.enable.zone=\u8bf7\u786e\u8ba4\u60a8\u786e\u5b9e\u8981\u542f\u7528\u6b64\u533a\u57df\u3002 +message.action.enable.zone=\u8bf7\u786e\u8ba4\u60a8\u786e\u5b9e\u8981\u542f\u7528\u6b64\u8d44\u6e90\u57df\u3002 message.action.expunge.instance=\u8bf7\u786e\u8ba4\u60a8\u786e\u5b9e\u8981\u5220\u9664\u6b64\u5b9e\u4f8b\u3002 message.action.force.reconnect=\u5df2\u6210\u529f\u5f3a\u5236\u91cd\u65b0\u8fde\u63a5\u60a8\u7684\u4e3b\u673a\u3002\u6b64\u8fc7\u7a0b\u53ef\u80fd\u9700\u8981\u957f\u8fbe\u51e0\u5206\u949f\u65f6\u95f4\u3002 message.action.host.enable.maintenance.mode=\u542f\u7528\u7ef4\u62a4\u6a21\u5f0f\u4f1a\u5bfc\u81f4\u5c06\u6b64\u4e3b\u673a\u4e0a\u6b63\u5728\u8fd0\u884c\u7684\u6240\u6709\u5b9e\u4f8b\u5b9e\u65f6\u8fc1\u79fb\u5230\u4efb\u4f55\u53ef\u7528\u7684\u4e3b\u673a\u3002 @@ -1389,26 +1552,26 @@ message.action.unmanage.cluster=\u8bf7\u786e\u8ba4\u60a8\u786e\u5b9e\u8981\u53d6 message.action.vmsnapshot.delete=\u8bf7\u786e\u8ba4\u60a8\u786e\u5b9e\u8981\u5220\u9664\u6b64 VM \u5feb\u7167\u3002 message.action.vmsnapshot.revert=\u8fd8\u539f VM \u5feb\u7167 message.activate.project=\u662f\u5426\u786e\u5b9e\u8981\u6fc0\u6d3b\u6b64\u9879\u76ee? -message.add.cluster.zone=\u5411\u533a\u57df \u4e2d\u6dfb\u52a0\u4e00\u4e2a\u865a\u62df\u673a\u7ba1\u7406\u7a0b\u5e8f\u6258\u7ba1\u7684\u7fa4\u96c6 -message.add.cluster=\u5411\u533a\u57df \u3001\u63d0\u4f9b\u70b9 \u4e2d\u6dfb\u52a0\u4e00\u4e2a\u865a\u62df\u673a\u7ba1\u7406\u7a0b\u5e8f\u6258\u7ba1\u7684\u7fa4\u96c6 +message.add.cluster.zone=\u5411\u8d44\u6e90\u57df \u4e2d\u6dfb\u52a0\u4e00\u4e2a\u865a\u62df\u673a\u7ba1\u7406\u7a0b\u5e8f\u6258\u7ba1\u7684\u7fa4\u96c6 +message.add.cluster=\u5411\u8d44\u6e90\u57df \u3001\u63d0\u4f9b\u70b9 \u4e2d\u6dfb\u52a0\u4e00\u4e2a\u865a\u62df\u673a\u7ba1\u7406\u7a0b\u5e8f\u6258\u7ba1\u7684\u7fa4\u96c6 message.add.disk.offering=\u8bf7\u6307\u5b9a\u4ee5\u4e0b\u53c2\u6570\u4ee5\u6dfb\u52a0\u4e00\u4e2a\u65b0\u7684\u78c1\u76d8\u65b9\u6848 message.add.domain=\u8bf7\u6307\u5b9a\u8981\u5728\u6b64\u57df\u4e0b\u521b\u5efa\u7684\u5b50\u57df -message.add.firewall=\u5411\u533a\u57df\u4e2d\u6dfb\u52a0\u4e00\u4e2a\u9632\u706b\u5899 +message.add.firewall=\u5411\u8d44\u6e90\u57df\u4e2d\u6dfb\u52a0\u4e00\u4e2a\u9632\u706b\u5899 message.add.guest.network=\u8bf7\u786e\u8ba4\u60a8\u786e\u5b9e\u8981\u6dfb\u52a0\u4e00\u4e2a\u6765\u5bbe\u7f51\u7edc message.add.host=\u8bf7\u6307\u5b9a\u4ee5\u4e0b\u53c2\u6570\u4ee5\u6dfb\u52a0\u4e00\u53f0\u65b0\u4e3b\u673a -message.add.ip.range.direct.network=\u5411\u533a\u57df \u4e2d\u7684\u76f4\u63a5\u7f51\u7edc \u6dfb\u52a0\u4e00\u4e2a IP \u8303\u56f4 +message.add.ip.range.direct.network=\u5411\u8d44\u6e90\u57df \u4e2d\u7684\u76f4\u63a5\u7f51\u7edc \u6dfb\u52a0\u4e00\u4e2a IP \u8303\u56f4 message.add.ip.range.to.pod=

\u5411\u63d0\u4f9b\u70b9\u6dfb\u52a0\u4e00\u4e2a IP \u8303\u56f4\:

-message.add.ip.range=\u5411\u533a\u57df\u4e2d\u7684\u516c\u7528\u7f51\u7edc\u6dfb\u52a0\u4e00\u4e2a IP \u8303\u56f4 +message.add.ip.range=\u5411\u8d44\u6e90\u57df\u4e2d\u7684\u516c\u7528\u7f51\u7edc\u6dfb\u52a0\u4e00\u4e2a IP \u8303\u56f4 message.add.load.balancer.under.ip=\u5df2\u5728\u4ee5\u4e0b IP \u4e0b\u6dfb\u52a0\u8d1f\u8f7d\u5e73\u8861\u5668\u89c4\u5219\: -message.add.load.balancer=\u5411\u533a\u57df\u4e2d\u6dfb\u52a0\u4e00\u4e2a\u8d1f\u8f7d\u5e73\u8861\u5668 -message.add.network=\u4e3a\u533a\u57df \u6dfb\u52a0\u4e00\u4e2a\u65b0\u7f51\u7edc +message.add.load.balancer=\u5411\u8d44\u6e90\u57df\u4e2d\u6dfb\u52a0\u4e00\u4e2a\u8d1f\u8f7d\u5e73\u8861\u5668 +message.add.network=\u4e3a\u8d44\u6e90\u57df \u6dfb\u52a0\u4e00\u4e2a\u65b0\u7f51\u7edc message.add.new.gateway.to.vpc=\u8bf7\u6307\u5b9a\u5c06\u65b0\u7f51\u5173\u6dfb\u52a0\u5230\u6b64 VPC \u6240\u9700\u7684\u4fe1\u606f\u3002 -message.add.pod.during.zone.creation=\u6bcf\u4e2a\u533a\u57df\u4e2d\u5fc5\u987b\u5305\u542b\u4e00\u4e2a\u6216\u591a\u4e2a\u63d0\u4f9b\u70b9\uff0c\u73b0\u5728\u6211\u4eec\u5c06\u6dfb\u52a0\u7b2c\u4e00\u4e2a\u63d0\u4f9b\u70b9\u3002\u63d0\u4f9b\u70b9\u4e2d\u5305\u542b\u4e3b\u673a\u548c\u4e3b\u5b58\u50a8\u670d\u52a1\u5668\uff0c\u60a8\u5c06\u5728\u968f\u540e\u7684\u67d0\u4e2a\u6b65\u9aa4\u4e2d\u6dfb\u52a0\u8fd9\u4e9b\u4e3b\u673a\u548c\u670d\u52a1\u5668\u3002\u9996\u5148\uff0c\u8bf7\u4e3a CloudStack \u7684\u5185\u90e8\u7ba1\u7406\u901a\u4fe1\u914d\u7f6e\u4e00\u4e2a\u9884\u7559 IP \u5730\u5740\u8303\u56f4\u3002\u9884\u7559\u7684 IP \u8303\u56f4\u5bf9\u4e91\u4e2d\u7684\u6bcf\u4e2a\u533a\u57df\u6765\u8bf4\u5fc5\u987b\u552f\u4e00\u3002 -message.add.pod=\u4e3a\u533a\u57df \u6dfb\u52a0\u4e00\u4e2a\u65b0\u63d0\u4f9b\u70b9 -message.add.primary.storage=\u4e3a\u533a\u57df \u3001\u63d0\u4f9b\u70b9 \u6dfb\u52a0\u4e00\u4e2a\u65b0\u4e3b\u5b58\u50a8 +message.add.pod.during.zone.creation=\u6bcf\u4e2a\u8d44\u6e90\u57df\u4e2d\u5fc5\u987b\u5305\u542b\u4e00\u4e2a\u6216\u591a\u4e2a\u63d0\u4f9b\u70b9\uff0c\u73b0\u5728\u6211\u4eec\u5c06\u6dfb\u52a0\u7b2c\u4e00\u4e2a\u63d0\u4f9b\u70b9\u3002\u63d0\u4f9b\u70b9\u4e2d\u5305\u542b\u4e3b\u673a\u548c\u4e3b\u5b58\u50a8\u670d\u52a1\u5668\uff0c\u60a8\u5c06\u5728\u968f\u540e\u7684\u67d0\u4e2a\u6b65\u9aa4\u4e2d\u6dfb\u52a0\u8fd9\u4e9b\u4e3b\u673a\u548c\u670d\u52a1\u5668\u3002\u9996\u5148\uff0c\u8bf7\u4e3a CloudStack \u7684\u5185\u90e8\u7ba1\u7406\u6d41\u91cf\u914d\u7f6e\u4e00\u4e2a\u9884\u7559 IP \u5730\u5740\u8303\u56f4\u3002\u9884\u7559\u7684 IP \u8303\u56f4\u5bf9\u4e91\u4e2d\u7684\u6bcf\u4e2a\u8d44\u6e90\u57df\u6765\u8bf4\u5fc5\u987b\u552f\u4e00\u3002 +message.add.pod=\u4e3a\u8d44\u6e90\u57df \u6dfb\u52a0\u4e00\u4e2a\u65b0\u63d0\u4f9b\u70b9 +message.add.primary.storage=\u4e3a\u8d44\u6e90\u57df \u3001\u63d0\u4f9b\u70b9 \u6dfb\u52a0\u4e00\u4e2a\u65b0\u4e3b\u5b58\u50a8 message.add.primary=\u8bf7\u6307\u5b9a\u4ee5\u4e0b\u53c2\u6570\u4ee5\u6dfb\u52a0\u4e00\u4e2a\u65b0\u4e3b\u5b58\u50a8 -message.add.region=\u8bf7\u6307\u5b9a\u6dfb\u52a0\u65b0\u533a\u57df\u6240\u9700\u7684\u4fe1\u606f\u3002 -message.add.secondary.storage=\u4e3a\u533a\u57df \u6dfb\u52a0\u4e00\u4e2a\u65b0\u5b58\u50a8 +message.add.region=\u8bf7\u6307\u5b9a\u6dfb\u52a0\u65b0\u5730\u7406\u533a\u57df\u6240\u9700\u7684\u4fe1\u606f\u3002 +message.add.secondary.storage=\u4e3a\u8d44\u6e90\u57df \u6dfb\u52a0\u4e00\u4e2a\u65b0\u5b58\u50a8 message.add.service.offering=\u8bf7\u586b\u5199\u4ee5\u4e0b\u6570\u636e\u4ee5\u6dfb\u52a0\u4e00\u4e2a\u65b0\u8ba1\u7b97\u65b9\u6848\u3002 message.add.system.service.offering=\u8bf7\u586b\u5199\u4ee5\u4e0b\u6570\u636e\u4ee5\u6dfb\u52a0\u4e00\u4e2a\u65b0\u7684\u7cfb\u7edf\u670d\u52a1\u65b9\u6848\u3002 message.add.template=\u8bf7\u8f93\u5165\u4ee5\u4e0b\u6570\u636e\u4ee5\u521b\u5efa\u65b0\u6a21\u677f @@ -1420,8 +1583,8 @@ message.adding.Netscaler.provider=\u6b63\u5728\u6dfb\u52a0 Netscaler \u63d0\u4f9 message.additional.networks.desc=\u8bf7\u9009\u62e9\u865a\u62df\u673a\u8981\u8fde\u63a5\u5230\u7684\u5176\u4ed6\u7f51\u7edc\u3002 message.advanced.mode.desc=\u5982\u679c\u60a8\u5e0c\u671b\u542f\u7528 VLAN \u652f\u6301\uff0c\u8bf7\u9009\u62e9\u6b64\u7f51\u7edc\u6a21\u5f0f\u3002\u6b64\u7f51\u7edc\u6a21\u5f0f\u5728\u5141\u8bb8\u7ba1\u7406\u5458\u63d0\u4f9b\u9632\u706b\u5899\u3001VPN \u6216\u8d1f\u8f7d\u5e73\u8861\u5668\u652f\u6301\u7b49\u81ea\u5b9a\u4e49\u7f51\u7edc\u65b9\u6848\u4ee5\u53ca\u542f\u7528\u76f4\u63a5\u7f51\u7edc\u8fde\u63a5\u4e0e\u865a\u62df\u7f51\u7edc\u8fde\u63a5\u7b49\u65b9\u9762\u63d0\u4f9b\u4e86\u6700\u5927\u7684\u7075\u6d3b\u6027\u3002 message.advanced.security.group=\u5982\u679c\u8981\u4f7f\u7528\u5b89\u5168\u7ec4\u63d0\u4f9b\u6765\u5bbe VM \u9694\u79bb\uff0c\u8bf7\u9009\u62e9\u6b64\u6a21\u5f0f\u3002 -message.advanced.virtual=\u5982\u679c\u8981\u4f7f\u7528\u6574\u4e2a\u533a\u57df\u7684 VLAN \u63d0\u4f9b\u6765\u5bbe VM \u9694\u79bb\uff0c\u8bf7\u9009\u62e9\u6b64\u6a21\u5f0f\u3002 -message.after.enable.s3=\u5df2\u914d\u7f6e S3 \u652f\u6301\u7684\u8f85\u52a9\u5b58\u50a8\u3002\u6ce8\u610f\: \u9000\u51fa\u6b64\u9875\u9762\u540e\uff0c\u60a8\u5c06\u65e0\u6cd5\u518d\u6b21\u91cd\u65b0\u914d\u7f6e S3\u3002 +message.advanced.virtual=\u5982\u679c\u8981\u4f7f\u7528\u6574\u4e2a\u8d44\u6e90\u57df\u7684 VLAN \u63d0\u4f9b\u6765\u5bbe VM \u9694\u79bb\uff0c\u8bf7\u9009\u62e9\u6b64\u6a21\u5f0f\u3002 +message.after.enable.s3=\u5df2\u914d\u7f6e S3 \u652f\u6301\u7684\u4e8c\u7ea7\u5b58\u50a8\u3002\u6ce8\u610f\: \u9000\u51fa\u6b64\u9875\u9762\u540e\uff0c\u60a8\u5c06\u65e0\u6cd5\u518d\u6b21\u91cd\u65b0\u914d\u7f6e S3\u3002 message.after.enable.swift=\u5df2\u914d\u7f6e SWIFT\u3002\u6ce8\u610f\: \u9000\u51fa\u6b64\u9875\u9762\u540e\uff0c\u60a8\u5c06\u65e0\u6cd5\u518d\u6b21\u91cd\u65b0\u914d\u7f6e SWIFT\u3002 message.alert.state.detected=\u68c0\u6d4b\u5230\u8b66\u62a5\u72b6\u6001 message.allow.vpn.access=\u8bf7\u8f93\u5165\u8981\u5141\u8bb8\u8fdb\u884c VPN \u8bbf\u95ee\u7684\u7528\u6237\u7684\u7528\u6237\u540d\u548c\u5bc6\u7801\u3002 @@ -1431,11 +1594,11 @@ message.attach.volume=\u8bf7\u586b\u5199\u4ee5\u4e0b\u6570\u636e\u4ee5\u9644\u52 message.basic.mode.desc=\u5982\u679c\u60a8*\u4e0d*\u5e0c\u671b\u542f\u7528\u4efb\u4f55 VLAN \u652f\u6301\uff0c\u8bf7\u9009\u62e9\u6b64\u7f51\u7edc\u6a21\u5f0f\u3002\u5c06\u76f4\u63a5\u4ece\u6b64\u7f51\u7edc\u4e2d\u4e3a\u5728\u6b64\u7f51\u7edc\u6a21\u5f0f\u4e0b\u521b\u5efa\u7684\u6240\u6709\u865a\u62df\u673a\u5b9e\u4f8b\u5206\u914d\u4e00\u4e2a IP\uff0c\u5e76\u4f7f\u7528\u5b89\u5168\u7ec4\u63d0\u4f9b\u5b89\u5168\u6027\u548c\u9694\u79bb\u3002 message.change.offering.confirm=\u8bf7\u786e\u8ba4\u60a8\u786e\u5b9e\u8981\u66f4\u6539\u6b64\u865a\u62df\u5b9e\u4f8b\u7684\u670d\u52a1\u65b9\u6848\u3002 message.change.password=\u8bf7\u66f4\u6539\u60a8\u7684\u5bc6\u7801\u3002 -message.configure.all.traffic.types=\u60a8\u6709\u591a\u4e2a\u7269\u7406\u7f51\u7edc\uff0c\u8bf7\u5355\u51fb\u201c\u7f16\u8f91\u201d\u6309\u94ae\u4e3a\u6bcf\u79cd\u901a\u4fe1\u7c7b\u578b\u914d\u7f6e\u6807\u7b7e\u3002 -message.configuring.guest.traffic=\u6b63\u5728\u914d\u7f6e\u6765\u5bbe\u901a\u4fe1 +message.configure.all.traffic.types=\u60a8\u6709\u591a\u4e2a\u7269\u7406\u7f51\u7edc\uff0c\u8bf7\u5355\u51fb\u201c\u7f16\u8f91\u201d\u6309\u94ae\u4e3a\u6bcf\u79cd\u6d41\u91cf\u7c7b\u578b\u914d\u7f6e\u6807\u7b7e\u3002 +message.configuring.guest.traffic=\u6b63\u5728\u914d\u7f6e\u6765\u5bbe\u6d41\u91cf message.configuring.physical.networks=\u6b63\u5728\u914d\u7f6e\u7269\u7406\u7f51\u7edc -message.configuring.public.traffic=\u6b63\u5728\u914d\u7f6e\u516c\u5171\u901a\u4fe1 -message.configuring.storage.traffic=\u6b63\u5728\u914d\u7f6e\u5b58\u50a8\u901a\u4fe1 +message.configuring.public.traffic=\u6b63\u5728\u914d\u7f6e\u516c\u5171\u6d41\u91cf +message.configuring.storage.traffic=\u6b63\u5728\u914d\u7f6e\u5b58\u50a8\u6d41\u91cf message.confirm.action.force.reconnect=\u8bf7\u786e\u8ba4\u60a8\u786e\u5b9e\u8981\u5f3a\u5236\u91cd\u65b0\u8fde\u63a5\u6b64\u4e3b\u673a\u3002 message.confirm.delete.F5=\u8bf7\u786e\u8ba4\u60a8\u786e\u5b9e\u8981\u5220\u9664 F5 message.confirm.delete.NetScaler=\u8bf7\u786e\u8ba4\u60a8\u786e\u5b9e\u8981\u5220\u9664 NetScaler @@ -1448,7 +1611,7 @@ message.confirm.join.project=\u8bf7\u786e\u8ba4\u60a8\u786e\u5b9e\u8981\u52a0\u5 message.confirm.remove.IP.range=\u8bf7\u786e\u8ba4\u60a8\u786e\u5b9e\u8981\u5220\u9664\u6b64 IP \u8303\u56f4\u3002 message.confirm.shutdown.provider=\u8bf7\u786e\u8ba4\u60a8\u786e\u5b9e\u8981\u5173\u95ed\u6b64\u63d0\u4f9b\u7a0b\u5e8f message.copy.iso.confirm=\u8bf7\u786e\u8ba4\u60a8\u786e\u5b9e\u8981\u5c06 ISO \u590d\u5236\u5230 -message.copy.template=\u5c06\u6a21\u677f XXX \u4ece\u533a\u57df \u590d\u5236\u5230 +message.copy.template=\u5c06\u6a21\u677f XXX \u4ece\u8d44\u6e90\u57df \u590d\u5236\u5230 message.create.template.vm=\u57fa\u4e8e\u6a21\u677f \u521b\u5efa VM message.create.template.volume=\u8bf7\u5148\u6307\u5b9a\u4ee5\u4e0b\u4fe1\u606f\uff0c\u7136\u540e\u518d\u521b\u5efa\u78c1\u76d8\u5377 \u7684\u6a21\u677f\u3002\u521b\u5efa\u6a21\u677f\u53ef\u80fd\u9700\u8981\u51e0\u5206\u949f\u5230\u66f4\u957f\u7684\u65f6\u95f4\uff0c\u5177\u4f53\u53d6\u51b3\u4e8e\u78c1\u76d8\u5377\u7684\u5927\u5c0f\u3002 message.create.template=\u662f\u5426\u786e\u5b9e\u8981\u521b\u5efa\u6a21\u677f? @@ -1457,10 +1620,10 @@ message.creating.guest.network=\u6b63\u5728\u521b\u5efa\u6765\u5bbe\u7f51\u7edc message.creating.physical.networks=\u6b63\u5728\u521b\u5efa\u7269\u7406\u7f51\u7edc message.creating.pod=\u6b63\u5728\u521b\u5efa\u63d0\u4f9b\u70b9 message.creating.primary.storage=\u6b63\u5728\u521b\u5efa\u4e3b\u5b58\u50a8 -message.creating.secondary.storage=\u6b63\u5728\u521b\u5efa\u8f85\u52a9\u5b58\u50a8 -message.creating.zone=\u6b63\u5728\u521b\u5efa\u533a\u57df +message.creating.secondary.storage=\u6b63\u5728\u521b\u5efa\u4e8c\u7ea7\u5b58\u50a8 +message.creating.zone=\u6b63\u5728\u521b\u5efa\u8d44\u6e90\u57df message.decline.invitation=\u662f\u5426\u786e\u5b9e\u8981\u62d2\u7edd\u6b64\u9879\u76ee\u9080\u8bf7? -message.dedicate.zone=\u6b63\u5728\u5c06\u533a\u57df\u4e13\u6709\u5316 +message.dedicate.zone=\u6b63\u5728\u5c06\u8d44\u6e90\u57df\u4e13\u7528 message.delete.account=\u8bf7\u786e\u8ba4\u60a8\u786e\u5b9e\u8981\u5220\u9664\u6b64\u5e10\u6237\u3002 message.delete.affinity.group=\u8bf7\u786e\u8ba4\u60a8\u786e\u5b9e\u8981\u5220\u9664\u6b64\u5173\u8054\u6027\u7ec4\u3002 message.delete.gateway=\u8bf7\u786e\u8ba4\u60a8\u786e\u5b9e\u8981\u5220\u9664\u6b64\u7f51\u5173 @@ -1474,8 +1637,8 @@ message.desc.basic.zone=\u63d0\u4f9b\u4e00\u4e2a\u7f51\u7edc\uff0c\u5c06\u76f4\u message.desc.cluster=\u6bcf\u4e2a\u63d0\u4f9b\u70b9\u4e2d\u5fc5\u987b\u5305\u542b\u4e00\u4e2a\u6216\u591a\u4e2a\u7fa4\u96c6\uff0c\u73b0\u5728\u6211\u4eec\u5c06\u6dfb\u52a0\u7b2c\u4e00\u4e2a\u7fa4\u96c6\u3002\u7fa4\u96c6\u63d0\u4f9b\u4e86\u4e00\u79cd\u7f16\u7ec4\u4e3b\u673a\u7684\u65b9\u6cd5\u3002\u7fa4\u96c6\u4e2d\u7684\u6240\u6709\u4e3b\u673a\u90fd\u5177\u6709\u76f8\u540c\u7684\u786c\u4ef6\uff0c\u8fd0\u884c\u76f8\u540c\u7684\u865a\u62df\u673a\u7ba1\u7406\u7a0b\u5e8f\uff0c\u4f4d\u4e8e\u76f8\u540c\u7684\u5b50\u7f51\u4e2d\uff0c\u5e76\u8bbf\u95ee\u76f8\u540c\u7684\u5171\u4eab\u5b58\u50a8\u3002\u6bcf\u4e2a\u7fa4\u96c6\u7531\u4e00\u4e2a\u6216\u591a\u4e2a\u4e3b\u673a\u4ee5\u53ca\u4e00\u4e2a\u6216\u591a\u4e2a\u4e3b\u5b58\u50a8\u670d\u52a1\u5668\u7ec4\u6210\u3002 message.desc.host=\u6bcf\u4e2a\u7fa4\u96c6\u4e2d\u5fc5\u987b\u81f3\u5c11\u5305\u542b\u4e00\u4e2a\u4e3b\u673a\u4ee5\u4f9b\u6765\u5bbe VM \u5728\u4e0a\u9762\u8fd0\u884c\uff0c\u73b0\u5728\u6211\u4eec\u5c06\u6dfb\u52a0\u7b2c\u4e00\u4e2a\u4e3b\u673a\u3002\u8981\u4f7f\u4e3b\u673a\u5728 CloudStack \u4e2d\u8fd0\u884c\uff0c\u5fc5\u987b\u5728\u6b64\u4e3b\u673a\u4e0a\u5b89\u88c5\u865a\u62df\u673a\u7ba1\u7406\u7a0b\u5e8f\u8f6f\u4ef6\uff0c\u4e3a\u5176\u5206\u914d\u4e00\u4e2a IP \u5730\u5740\uff0c\u5e76\u786e\u4fdd\u5c06\u5176\u8fde\u63a5\u5230 CloudStack \u7ba1\u7406\u670d\u52a1\u5668\u3002

\u8bf7\u63d0\u4f9b\u4e3b\u673a\u7684 DNS \u6216 IP \u5730\u5740\u3001\u7528\u6237\u540d(\u901a\u5e38\u4e3a root)\u548c\u5bc6\u7801\uff0c\u4ee5\u53ca\u7528\u4e8e\u5bf9\u4e3b\u673a\u8fdb\u884c\u5206\u7c7b\u7684\u4efb\u4f55\u6807\u7b7e\u3002 message.desc.primary.storage=\u6bcf\u4e2a\u7fa4\u96c6\u4e2d\u5fc5\u987b\u5305\u542b\u4e00\u4e2a\u6216\u591a\u4e2a\u4e3b\u5b58\u50a8\u670d\u52a1\u5668\uff0c\u73b0\u5728\u6211\u4eec\u5c06\u6dfb\u52a0\u7b2c\u4e00\u4e2a\u4e3b\u5b58\u50a8\u670d\u52a1\u5668\u3002\u4e3b\u5b58\u50a8\u4e2d\u5305\u542b\u5728\u7fa4\u96c6\u4e2d\u7684\u4e3b\u673a\u4e0a\u8fd0\u884c\u7684\u6240\u6709 VM \u7684\u78c1\u76d8\u5377\u3002\u8bf7\u4f7f\u7528\u5e95\u5c42\u865a\u62df\u673a\u7ba1\u7406\u7a0b\u5e8f\u652f\u6301\u7684\u7b26\u5408\u6807\u51c6\u7684\u534f\u8bae\u3002 -message.desc.secondary.storage=\u6bcf\u4e2a\u533a\u57df\u4e2d\u5fc5\u987b\u81f3\u5c11\u5305\u542b\u4e00\u4e2a NFS \u6216\u8f85\u52a9\u5b58\u50a8\u670d\u52a1\u5668\uff0c\u73b0\u5728\u6211\u4eec\u5c06\u6dfb\u52a0\u7b2c\u4e00\u4e2a NFS \u6216\u8f85\u52a9\u5b58\u50a8\u670d\u52a1\u5668\u3002\u8f85\u52a9\u5b58\u50a8\u7528\u4e8e\u5b58\u50a8 VM \u6a21\u677f\u3001ISO \u6620\u50cf\u548c VM \u78c1\u76d8\u5377\u5feb\u7167\u3002\u6b64\u670d\u52a1\u5668\u5fc5\u987b\u5bf9\u533a\u57df\u4e2d\u7684\u6240\u6709\u670d\u52a1\u5668\u53ef\u7528\u3002

\u8bf7\u63d0\u4f9b IP \u5730\u5740\u548c\u5bfc\u51fa\u8def\u5f84\u3002 -message.desc.zone=\u533a\u57df\u662f CloudStack \u4e2d\u6700\u5927\u7684\u7ec4\u7ec7\u5355\u4f4d\uff0c\u4e00\u4e2a\u533a\u57df\u901a\u5e38\u4e0e\u4e00\u4e2a\u6570\u636e\u4e2d\u5fc3\u76f8\u5bf9\u5e94\u3002\u533a\u57df\u53ef\u63d0\u4f9b\u7269\u7406\u9694\u79bb\u548c\u5197\u4f59\u3002\u4e00\u4e2a\u533a\u57df\u7531\u4e00\u4e2a\u6216\u591a\u4e2a\u63d0\u4f9b\u70b9\u4ee5\u53ca\u7531\u533a\u57df\u4e2d\u7684\u6240\u6709\u63d0\u4f9b\u70b9\u5171\u4eab\u7684\u4e00\u4e2a\u8f85\u52a9\u5b58\u50a8\u670d\u52a1\u5668\u7ec4\u6210\uff0c\u5176\u4e2d\u6bcf\u4e2a\u63d0\u4f9b\u70b9\u4e2d\u5305\u542b\u591a\u4e2a\u4e3b\u673a\u548c\u4e3b\u5b58\u50a8\u670d\u52a1\u5668\u3002 +message.desc.secondary.storage=\u6bcf\u4e2a\u8d44\u6e90\u57df\u4e2d\u5fc5\u987b\u81f3\u5c11\u5305\u542b\u4e00\u4e2a NFS \u6216\u4e8c\u7ea7\u5b58\u50a8\u670d\u52a1\u5668\uff0c\u73b0\u5728\u6211\u4eec\u5c06\u6dfb\u52a0\u7b2c\u4e00\u4e2a NFS \u6216\u4e8c\u7ea7\u5b58\u50a8\u670d\u52a1\u5668\u3002\u4e8c\u7ea7\u5b58\u50a8\u7528\u4e8e\u5b58\u50a8 VM \u6a21\u677f\u3001ISO \u6620\u50cf\u548c VM \u78c1\u76d8\u5377\u5feb\u7167\u3002\u6b64\u670d\u52a1\u5668\u5fc5\u987b\u5bf9\u8d44\u6e90\u57df\u4e2d\u7684\u6240\u6709\u670d\u52a1\u5668\u53ef\u7528\u3002

\u8bf7\u63d0\u4f9b IP \u5730\u5740\u548c\u5bfc\u51fa\u8def\u5f84\u3002 +message.desc.zone=\u8d44\u6e90\u57df\u662f CloudStack \u4e2d\u6700\u5927\u7684\u7ec4\u7ec7\u5355\u4f4d\uff0c\u4e00\u4e2a\u8d44\u6e90\u57df\u901a\u5e38\u4e0e\u4e00\u4e2a\u6570\u636e\u4e2d\u5fc3\u76f8\u5bf9\u5e94\u3002\u8d44\u6e90\u57df\u53ef\u63d0\u4f9b\u7269\u7406\u9694\u79bb\u548c\u5197\u4f59\u3002\u4e00\u4e2a\u8d44\u6e90\u57df\u7531\u4e00\u4e2a\u6216\u591a\u4e2a\u63d0\u4f9b\u70b9\u4ee5\u53ca\u7531\u8d44\u6e90\u57df\u4e2d\u7684\u6240\u6709\u63d0\u4f9b\u70b9\u5171\u4eab\u7684\u4e00\u4e2a\u4e8c\u7ea7\u5b58\u50a8\u670d\u52a1\u5668\u7ec4\u6210\uff0c\u5176\u4e2d\u6bcf\u4e2a\u63d0\u4f9b\u70b9\u4e2d\u5305\u542b\u591a\u4e2a\u4e3b\u673a\u548c\u4e3b\u5b58\u50a8\u670d\u52a1\u5668\u3002 message.detach.disk=\u662f\u5426\u786e\u5b9e\u8981\u53d6\u6d88\u9644\u52a0\u6b64\u78c1\u76d8? message.detach.iso.confirm=\u8bf7\u786e\u8ba4\u60a8\u786e\u5b9e\u8981\u4ece\u6b64\u865a\u62df\u673a\u4e2d\u53d6\u6d88\u9644\u52a0\u6b64 ISO\u3002 message.disable.account=\u8bf7\u786e\u8ba4\u60a8\u786e\u5b9e\u8981\u7981\u7528\u6b64\u5e10\u6237\u3002\u7981\u7528\u540e\uff0c\u6b64\u5e10\u6237\u7684\u6240\u6709\u7528\u6237\u5c06\u4e0d\u518d\u6709\u6743\u8bbf\u95ee\u5404\u81ea\u7684\u4e91\u8d44\u6e90\u3002\u6240\u6709\u6b63\u5728\u8fd0\u884c\u7684\u865a\u62df\u673a\u5c06\u7acb\u5373\u5173\u95ed\u3002 @@ -1490,7 +1653,7 @@ message.download.volume=\u8bf7\u5355\u51fb 00000 \u4e0b\u8f7d\ message.edit.account=\u7f16\u8f91(\u201c-1\u201d\u8868\u793a\u5bf9\u8981\u521b\u5efa\u7684\u8d44\u6e90\u6570\u91cf\u6ca1\u6709\u4efb\u4f55\u9650\u5236) message.edit.confirm=\u8bf7\u5148\u786e\u8ba4\u60a8\u6240\u505a\u7684\u66f4\u6539\uff0c\u7136\u540e\u5355\u51fb\u201c\u4fdd\u5b58\u201d\u3002 message.edit.limits=\u8bf7\u6307\u5b9a\u5bf9\u4ee5\u4e0b\u8d44\u6e90\u7684\u9650\u5236\u3002\u201c-1\u201d\u8868\u793a\u4e0d\u9650\u5236\u8981\u521b\u5efa\u7684\u8d44\u6e90\u6570\u3002 -message.edit.traffic.type=\u8bf7\u6307\u5b9a\u60a8\u5e0c\u671b\u4e0e\u6b64\u901a\u4fe1\u7c7b\u578b\u5173\u8054\u7684\u901a\u4fe1\u6807\u7b7e\u3002 +message.edit.traffic.type=\u8bf7\u6307\u5b9a\u60a8\u5e0c\u671b\u4e0e\u6b64\u6d41\u91cf\u7c7b\u578b\u5173\u8054\u7684\u6d41\u91cf\u6807\u7b7e\u3002 message.enable.account=\u8bf7\u786e\u8ba4\u60a8\u786e\u5b9e\u8981\u542f\u7528\u6b64\u5e10\u6237\u3002 message.enable.user=\u8bf7\u786e\u8ba4\u60a8\u786e\u5b9e\u8981\u542f\u7528\u6b64\u7528\u6237\u3002 message.enable.vpn.access=\u5f53\u524d\u5df2\u5bf9\u6b64 IP \u5730\u5740\u7981\u7528\u4e86 VPN\u3002\u662f\u5426\u8981\u542f\u7528 VPN \u8bbf\u95ee? @@ -1498,51 +1661,51 @@ message.enable.vpn=\u8bf7\u786e\u8ba4\u60a8\u786e\u5b9e\u8981\u5bf9\u6b64 IP \u5 message.enabled.vpn.ip.sec=\u60a8\u7684 IPSec \u9884\u5171\u4eab\u5bc6\u94a5 message.enabled.vpn=\u60a8\u7684 VPN \u8bbf\u95ee\u529f\u80fd\u5f53\u524d\u5df2\u542f\u7528\uff0c\u53ef\u4ee5\u901a\u8fc7 IP \u8fdb\u884c\u8bbf\u95ee message.enabling.security.group.provider=\u6b63\u5728\u542f\u7528\u5b89\u5168\u7ec4\u63d0\u4f9b\u7a0b\u5e8f -message.enabling.zone=\u6b63\u5728\u542f\u7528\u533a\u57df +message.enabling.zone=\u6b63\u5728\u542f\u7528\u8d44\u6e90\u57df message.enter.token=\u8bf7\u8f93\u5165\u60a8\u5728\u9080\u8bf7\u7535\u5b50\u90ae\u4ef6\u4e2d\u6536\u5230\u7684\u4ee4\u724c\u3002 message.generate.keys=\u8bf7\u786e\u8ba4\u60a8\u786e\u5b9e\u8981\u4e3a\u6b64\u7528\u6237\u751f\u6210\u65b0\u5bc6\u94a5\u3002 -message.guest.traffic.in.advanced.zone=\u6765\u5bbe\u7f51\u7edc\u901a\u4fe1\u662f\u6307\u6700\u7ec8\u7528\u6237\u865a\u62df\u673a\u4e4b\u95f4\u7684\u901a\u4fe1\u3002\u6307\u5b9a\u4e00\u4e2a VLAN ID \u8303\u56f4\u53ef\u4f20\u9001\u6bcf\u4e2a\u7269\u7406\u7f51\u7edc\u7684\u6765\u5bbe\u901a\u4fe1\u3002 -message.guest.traffic.in.basic.zone=\u6765\u5bbe\u7f51\u7edc\u901a\u4fe1\u662f\u6307\u6700\u7ec8\u7528\u6237\u865a\u62df\u673a\u4e4b\u95f4\u7684\u901a\u4fe1\u3002\u5e94\u6307\u5b9a\u4e00\u4e2a CloudStack \u53ef\u4ee5\u5206\u914d\u7ed9\u6765\u5bbe VM \u7684 IP \u5730\u5740\u8303\u56f4\u3002\u8bf7\u786e\u4fdd\u6b64\u8303\u56f4\u4e0e\u9884\u7559\u7684\u7cfb\u7edf IP \u8303\u56f4\u4e0d\u91cd\u53e0\u3002 +message.guest.traffic.in.advanced.zone=\u6765\u5bbe\u7f51\u7edc\u6d41\u91cf\u662f\u6307\u6700\u7ec8\u7528\u6237\u865a\u62df\u673a\u4e4b\u95f4\u7684\u901a\u4fe1\u3002\u6307\u5b9a\u4e00\u4e2a VLAN ID \u8303\u56f4\u53ef\u4f20\u9001\u6bcf\u4e2a\u7269\u7406\u7f51\u7edc\u7684\u6765\u5bbe\u6d41\u91cf\u3002 +message.guest.traffic.in.basic.zone=\u6765\u5bbe\u7f51\u7edc\u6d41\u91cf\u662f\u6307\u6700\u7ec8\u7528\u6237\u865a\u62df\u673a\u4e4b\u95f4\u7684\u901a\u4fe1\u3002\u5e94\u6307\u5b9a\u4e00\u4e2a CloudStack \u53ef\u4ee5\u5206\u914d\u7ed9\u6765\u5bbe VM \u7684 IP \u5730\u5740\u8303\u56f4\u3002\u8bf7\u786e\u4fdd\u6b64\u8303\u56f4\u4e0e\u9884\u7559\u7684\u7cfb\u7edf IP \u8303\u56f4\u4e0d\u91cd\u53e0\u3002 message.installWizard.click.retry=\u8bf7\u5355\u51fb\u6b64\u6309\u94ae\u91cd\u65b0\u5c1d\u8bd5\u542f\u52a8\u3002 -message.installWizard.copy.whatIsACluster=\u7fa4\u96c6\u63d0\u4f9b\u4e86\u4e00\u79cd\u7f16\u7ec4\u4e3b\u673a\u7684\u65b9\u6cd5\u3002\u7fa4\u96c6\u4e2d\u7684\u6240\u6709\u4e3b\u673a\u90fd\u5177\u6709\u76f8\u540c\u7684\u786c\u4ef6\uff0c\u8fd0\u884c\u76f8\u540c\u7684\u865a\u62df\u673a\u7ba1\u7406\u7a0b\u5e8f\uff0c\u4f4d\u4e8e\u540c\u4e00\u5b50\u7f51\u4e2d\uff0c\u5e76\u8bbf\u95ee\u76f8\u540c\u7684\u5171\u4eab\u5b58\u50a8\u3002\u53ef\u4ee5\u5b9e\u65f6\u5c06\u865a\u62df\u673a\u5b9e\u4f8b(VM)\u4ece\u4e00\u53f0\u4e3b\u673a\u8fc1\u79fb\u5230\u540c\u4e00\u7fa4\u96c6\u5185\u7684\u5176\u4ed6\u4e3b\u673a\uff0c\u800c\u65e0\u9700\u4e2d\u65ad\u5411\u7528\u6237\u63d0\u4f9b\u670d\u52a1\u3002\u7fa4\u96c6\u662f CloudStack&\#8482; \u90e8\u7f72\u4e2d\u7684\u7b2c\u4e09\u5927\u7ec4\u7ec7\u5355\u4f4d\u3002\u7fa4\u96c6\u5305\u542b\u5728\u63d0\u4f9b\u70b9\u4e2d\uff0c\u63d0\u4f9b\u70b9\u5305\u542b\u5728\u533a\u57df\u4e2d\u3002

CloudStack&\#8482; \u5141\u8bb8\u4e91\u90e8\u7f72\u4e2d\u5b58\u5728\u591a\u4e2a\u7fa4\u96c6\uff0c\u4f46\u5bf9\u4e8e\u57fa\u672c\u5b89\u88c5\uff0c\u6211\u4eec\u53ea\u9700\u8981\u4e00\u4e2a\u7fa4\u96c6\u3002 -message.installWizard.copy.whatIsAHost=\u4e3b\u673a\u662f\u6307\u4e00\u53f0\u8ba1\u7b97\u673a\u3002\u4e3b\u673a\u63d0\u4f9b\u8fd0\u884c\u6765\u5bbe\u865a\u62df\u673a\u7684\u8ba1\u7b97\u8d44\u6e90\u3002\u6bcf\u53f0\u4e3b\u673a\u4e0a\u90fd\u5b89\u88c5\u6709\u865a\u62df\u673a\u7ba1\u7406\u7a0b\u5e8f\u8f6f\u4ef6\uff0c\u7528\u4e8e\u7ba1\u7406\u6765\u5bbe VM (\u88f8\u673a\u4e3b\u673a\u9664\u5916\uff0c\u5c06\u5728\u201c\u9ad8\u7ea7\u5b89\u88c5\u6307\u5357\u201d\u4e2d\u8ba8\u8bba\u8fd9\u4e00\u7279\u6b8a\u6848\u4f8b)\u3002\u4f8b\u5982\uff0c\u542f\u7528\u4e86 KVM \u7684 Linux \u670d\u52a1\u5668\u3001Citrix XenServer \u670d\u52a1\u5668\u548c ESXi \u670d\u52a1\u5668\u90fd\u53ef\u7528\u4f5c\u4e3b\u673a\u3002\u5728\u57fa\u672c\u5b89\u88c5\u4e2d\uff0c\u6211\u4eec\u5c06\u4f7f\u7528\u4e00\u53f0\u8fd0\u884c XenServer \u7684\u4e3b\u673a\u3002

\u4e3b\u673a\u662f CloudStack&\#8482; \u90e8\u7f72\u4e2d\u6700\u5c0f\u7684\u7ec4\u7ec7\u5355\u4f4d\u3002\u4e3b\u673a\u5305\u542b\u5728\u7fa4\u96c6\u4e2d\uff0c\u7fa4\u96c6\u5305\u542b\u5728\u63d0\u4f9b\u70b9\u4e2d\uff0c\u63d0\u4f9b\u70b9\u5305\u542b\u5728\u533a\u57df\u4e2d\u3002 -message.installWizard.copy.whatIsAPod=\u4e00\u4e2a\u63d0\u4f9b\u70b9\u901a\u5e38\u4ee3\u8868\u4e00\u4e2a\u673a\u67b6\u3002\u540c\u4e00\u63d0\u4f9b\u70b9\u4e2d\u7684\u4e3b\u673a\u4f4d\u4e8e\u540c\u4e00\u5b50\u7f51\u4e2d\u3002

\u63d0\u4f9b\u70b9\u662f CloudStack&\#8482; \u90e8\u7f72\u4e2d\u7684\u7b2c\u4e8c\u5927\u7ec4\u7ec7\u5355\u4f4d\u3002\u63d0\u4f9b\u70b9\u5305\u542b\u5728\u533a\u57df\u4e2d\u3002\u6bcf\u4e2a\u533a\u57df\u4e2d\u53ef\u4ee5\u5305\u542b\u4e00\u4e2a\u6216\u591a\u4e2a\u63d0\u4f9b\u70b9\uff1b\u5728\u57fa\u672c\u5b89\u88c5\u4e2d\uff0c\u60a8\u7684\u533a\u57df\u4e2d\u5c06\u4ec5\u5305\u542b\u4e00\u4e2a\u63d0\u4f9b\u70b9\u3002 -message.installWizard.copy.whatIsAZone=\u533a\u57df\u662f CloudStack&\#8482; \u90e8\u7f72\u4e2d\u6700\u5927\u7684\u7ec4\u7ec7\u5355\u4f4d\u3002\u867d\u7136\u5141\u8bb8\u4e00\u4e2a\u6570\u636e\u4e2d\u5fc3\u4e2d\u5b58\u5728\u591a\u4e2a\u533a\u57df\uff0c\u4f46\u662f\u4e00\u4e2a\u533a\u57df\u901a\u5e38\u4e0e\u4e00\u4e2a\u6570\u636e\u4e2d\u5fc3\u76f8\u5bf9\u5e94\u3002\u5c06\u57fa\u7840\u67b6\u6784\u7f16\u7ec4\u5230\u533a\u57df\u4e2d\u7684\u597d\u5904\u662f\u53ef\u4ee5\u63d0\u4f9b\u7269\u7406\u9694\u79bb\u548c\u5197\u4f59\u3002\u4f8b\u5982\uff0c\u6bcf\u4e2a\u533a\u57df\u90fd\u53ef\u4ee5\u62e5\u6709\u5404\u81ea\u7684\u7535\u6e90\u4f9b\u5e94\u548c\u7f51\u7edc\u4e0a\u884c\u65b9\u6848\uff0c\u5e76\u4e14\u5404\u533a\u57df\u53ef\u4ee5\u5728\u5730\u7406\u4f4d\u7f6e\u4e0a\u76f8\u9694\u5f88\u8fdc(\u867d\u7136\u5e76\u975e\u5fc5\u987b\u76f8\u9694\u5f88\u8fdc)\u3002 -message.installWizard.copy.whatIsCloudStack=CloudStack&\#8482 \u662f\u4e00\u4e2a\u8f6f\u4ef6\u5e73\u53f0\uff0c\u53ef\u5c06\u8ba1\u7b97\u8d44\u6e90\u96c6\u4e2d\u5728\u4e00\u8d77\u4ee5\u6784\u5efa\u516c\u5171\u3001\u79c1\u6709\u548c\u6df7\u5408\u57fa\u7840\u8bbe\u65bd\u5373\u670d\u52a1(IaaS)\u4e91\u3002CloudStack&\#8482 \u8d1f\u8d23\u7ba1\u7406\u7ec4\u6210\u4e91\u57fa\u7840\u67b6\u6784\u7684\u7f51\u7edc\u3001\u5b58\u50a8\u548c\u8ba1\u7b97\u8282\u70b9\u3002\u4f7f\u7528 CloudStack&\#8482 \u53ef\u4ee5\u90e8\u7f72\u3001\u7ba1\u7406\u548c\u914d\u7f6e\u4e91\u8ba1\u7b97\u73af\u5883\u3002

CloudStack&\#8482 \u901a\u8fc7\u6269\u5c55\u5546\u7528\u786c\u4ef6\u4e0a\u8fd0\u884c\u7684\u6bcf\u4e2a\u865a\u62df\u673a\u6620\u50cf\u7684\u8303\u56f4\uff0c\u63d0\u4f9b\u4e86\u4e00\u4e2a\u5b9e\u65f6\u53ef\u7528\u7684\u4e91\u57fa\u7840\u67b6\u6784\u8f6f\u4ef6\u5806\u6808\u7528\u4e8e\u4ee5\u670d\u52a1\u65b9\u5f0f\u4ea4\u4ed8\u865a\u62df\u6570\u636e\u4e2d\u5fc3\uff0c\u5373\u4ea4\u4ed8\u6784\u5efa\u3001\u90e8\u7f72\u548c\u7ba1\u7406\u591a\u5c42\u6b21\u548c\u591a\u79df\u6237\u4e91\u5e94\u7528\u7a0b\u5e8f\u5fc5\u9700\u7684\u6240\u6709\u7ec4\u4ef6\u3002\u5f00\u6e90\u7248\u672c\u548c Premium \u7248\u672c\u90fd\u5df2\u53ef\u7528\uff0c\u4e14\u63d0\u4f9b\u7684\u529f\u80fd\u51e0\u4e4e\u5b8c\u5168\u76f8\u540c\u3002 -message.installWizard.copy.whatIsPrimaryStorage=CloudStack&\#8482; \u4e91\u57fa\u7840\u67b6\u6784\u4f7f\u7528\u4ee5\u4e0b\u4e24\u79cd\u7c7b\u578b\u7684\u5b58\u50a8\: \u4e3b\u5b58\u50a8\u548c\u8f85\u52a9\u5b58\u50a8\u3002\u8fd9\u4e24\u79cd\u7c7b\u578b\u7684\u5b58\u50a8\u53ef\u4ee5\u662f iSCSI \u6216 NFS \u670d\u52a1\u5668\uff0c\u4e5f\u53ef\u4ee5\u662f\u672c\u5730\u78c1\u76d8\u3002

\u4e3b\u5b58\u50a8\u4e0e\u7fa4\u96c6\u76f8\u5173\u8054\uff0c\u7528\u4e8e\u5b58\u50a8\u8be5\u7fa4\u96c6\u4e2d\u7684\u4e3b\u673a\u4e0a\u6b63\u5728\u8fd0\u884c\u7684\u6240\u6709 VM \u5bf9\u5e94\u7684\u6bcf\u4e2a\u6765\u5bbe VM \u7684\u78c1\u76d8\u5377\u3002\u4e3b\u5b58\u50a8\u670d\u52a1\u5668\u901a\u5e38\u4f4d\u4e8e\u9760\u8fd1\u4e3b\u673a\u7684\u4f4d\u7f6e\u3002 -message.installWizard.copy.whatIsSecondaryStorage=\u8f85\u52a9\u5b58\u50a8\u4e0e\u533a\u57df\u76f8\u5173\u8054\uff0c\u7528\u4e8e\u5b58\u50a8\u4ee5\u4e0b\u9879\u76ee\:
  • \u6a21\u677f - \u53ef\u7528\u4e8e\u542f\u52a8 VM \u5e76\u53ef\u4ee5\u5305\u542b\u5176\u4ed6\u914d\u7f6e\u4fe1\u606f(\u4f8b\u5982\uff0c\u5df2\u5b89\u88c5\u7684\u5e94\u7528\u7a0b\u5e8f)\u7684\u64cd\u4f5c\u7cfb\u7edf\u6620\u50cf
  • ISO \u6620\u50cf - \u53ef\u91cd\u65b0\u542f\u52a8\u6216\u4e0d\u53ef\u91cd\u65b0\u542f\u52a8\u7684\u64cd\u4f5c\u7cfb\u7edf\u6620\u50cf
  • \u78c1\u76d8\u5377\u5feb\u7167 - \u5df2\u4fdd\u5b58\u7684 VM \u6570\u636e\u526f\u672c\uff0c\u53ef\u7528\u4e8e\u6267\u884c\u6570\u636e\u6062\u590d\u6216\u521b\u5efa\u65b0\u6a21\u677f
+message.installWizard.copy.whatIsACluster=\u7fa4\u96c6\u63d0\u4f9b\u4e86\u4e00\u79cd\u7f16\u7ec4\u4e3b\u673a\u7684\u65b9\u6cd5\u3002\u7fa4\u96c6\u4e2d\u7684\u6240\u6709\u4e3b\u673a\u90fd\u5177\u6709\u76f8\u540c\u7684\u786c\u4ef6\uff0c\u8fd0\u884c\u76f8\u540c\u7684\u865a\u62df\u673a\u7ba1\u7406\u7a0b\u5e8f\uff0c\u4f4d\u4e8e\u540c\u4e00\u5b50\u7f51\u4e2d\uff0c\u5e76\u8bbf\u95ee\u76f8\u540c\u7684\u5171\u4eab\u5b58\u50a8\u3002\u53ef\u4ee5\u5b9e\u65f6\u5c06\u865a\u62df\u673a\u5b9e\u4f8b(VM)\u4ece\u4e00\u53f0\u4e3b\u673a\u8fc1\u79fb\u5230\u540c\u4e00\u7fa4\u96c6\u5185\u7684\u5176\u4ed6\u4e3b\u673a\uff0c\u800c\u65e0\u9700\u4e2d\u65ad\u5411\u7528\u6237\u63d0\u4f9b\u670d\u52a1\u3002\u7fa4\u96c6\u662f CloudStack&\#8482; \u90e8\u7f72\u4e2d\u7684\u7b2c\u4e09\u5927\u7ec4\u7ec7\u5355\u4f4d\u3002\u7fa4\u96c6\u5305\u542b\u5728\u63d0\u4f9b\u70b9\u4e2d\uff0c\u63d0\u4f9b\u70b9\u5305\u542b\u5728\u8d44\u6e90\u57df\u4e2d\u3002

CloudStack&\#8482; \u5141\u8bb8\u4e91\u90e8\u7f72\u4e2d\u5b58\u5728\u591a\u4e2a\u7fa4\u96c6\uff0c\u4f46\u5bf9\u4e8e\u57fa\u672c\u5b89\u88c5\uff0c\u6211\u4eec\u53ea\u9700\u8981\u4e00\u4e2a\u7fa4\u96c6\u3002 +message.installWizard.copy.whatIsAHost=\u4e3b\u673a\u662f\u6307\u4e00\u53f0\u8ba1\u7b97\u673a\u3002\u4e3b\u673a\u63d0\u4f9b\u8fd0\u884c\u6765\u5bbe\u865a\u62df\u673a\u7684\u8ba1\u7b97\u8d44\u6e90\u3002\u6bcf\u53f0\u4e3b\u673a\u4e0a\u90fd\u5b89\u88c5\u6709\u865a\u62df\u673a\u7ba1\u7406\u7a0b\u5e8f\u8f6f\u4ef6\uff0c\u7528\u4e8e\u7ba1\u7406\u6765\u5bbe VM (\u88f8\u673a\u4e3b\u673a\u9664\u5916\uff0c\u5c06\u5728\u201c\u9ad8\u7ea7\u5b89\u88c5\u6307\u5357\u201d\u4e2d\u8ba8\u8bba\u8fd9\u4e00\u7279\u6b8a\u6848\u4f8b)\u3002\u4f8b\u5982\uff0c\u542f\u7528\u4e86 KVM \u7684 Linux \u670d\u52a1\u5668\u3001Citrix XenServer \u670d\u52a1\u5668\u548c ESXi \u670d\u52a1\u5668\u90fd\u53ef\u7528\u4f5c\u4e3b\u673a\u3002\u5728\u57fa\u672c\u5b89\u88c5\u4e2d\uff0c\u6211\u4eec\u5c06\u4f7f\u7528\u4e00\u53f0\u8fd0\u884c XenServer \u7684\u4e3b\u673a\u3002

\u4e3b\u673a\u662f CloudStack&\#8482; \u90e8\u7f72\u4e2d\u6700\u5c0f\u7684\u7ec4\u7ec7\u5355\u4f4d\u3002\u4e3b\u673a\u5305\u542b\u5728\u7fa4\u96c6\u4e2d\uff0c\u7fa4\u96c6\u5305\u542b\u5728\u63d0\u4f9b\u70b9\u4e2d\uff0c\u63d0\u4f9b\u70b9\u5305\u542b\u5728\u8d44\u6e90\u57df\u4e2d\u3002 +message.installWizard.copy.whatIsAPod=\u4e00\u4e2a\u63d0\u4f9b\u70b9\u901a\u5e38\u4ee3\u8868\u4e00\u4e2a\u673a\u67b6\u3002\u540c\u4e00\u63d0\u4f9b\u70b9\u4e2d\u7684\u4e3b\u673a\u4f4d\u4e8e\u540c\u4e00\u5b50\u7f51\u4e2d\u3002

\u63d0\u4f9b\u70b9\u662f CloudStack&\#8482; \u90e8\u7f72\u4e2d\u7684\u7b2c\u4e8c\u5927\u7ec4\u7ec7\u5355\u4f4d\u3002\u63d0\u4f9b\u70b9\u5305\u542b\u5728\u8d44\u6e90\u57df\u4e2d\u3002\u6bcf\u4e2a\u8d44\u6e90\u57df\u4e2d\u53ef\u4ee5\u5305\u542b\u4e00\u4e2a\u6216\u591a\u4e2a\u63d0\u4f9b\u70b9\uff1b\u5728\u57fa\u672c\u5b89\u88c5\u4e2d\uff0c\u60a8\u7684\u8d44\u6e90\u57df\u4e2d\u5c06\u4ec5\u5305\u542b\u4e00\u4e2a\u63d0\u4f9b\u70b9\u3002 +message.installWizard.copy.whatIsAZone=\u8d44\u6e90\u57df\u662f CloudStack&\#8482; \u90e8\u7f72\u4e2d\u6700\u5927\u7684\u7ec4\u7ec7\u5355\u4f4d\u3002\u867d\u7136\u5141\u8bb8\u4e00\u4e2a\u6570\u636e\u4e2d\u5fc3\u4e2d\u5b58\u5728\u591a\u4e2a\u8d44\u6e90\u57df\uff0c\u4f46\u662f\u4e00\u4e2a\u8d44\u6e90\u57df\u901a\u5e38\u4e0e\u4e00\u4e2a\u6570\u636e\u4e2d\u5fc3\u76f8\u5bf9\u5e94\u3002\u5c06\u57fa\u7840\u67b6\u6784\u7f16\u7ec4\u5230\u8d44\u6e90\u57df\u4e2d\u7684\u597d\u5904\u662f\u53ef\u4ee5\u63d0\u4f9b\u7269\u7406\u9694\u79bb\u548c\u5197\u4f59\u3002\u4f8b\u5982\uff0c\u6bcf\u4e2a\u8d44\u6e90\u57df\u90fd\u53ef\u4ee5\u62e5\u6709\u5404\u81ea\u7684\u7535\u6e90\u4f9b\u5e94\u548c\u7f51\u7edc\u4e0a\u884c\u65b9\u6848\uff0c\u5e76\u4e14\u5404\u8d44\u6e90\u57df\u53ef\u4ee5\u5728\u5730\u7406\u4f4d\u7f6e\u4e0a\u76f8\u9694\u5f88\u8fdc(\u867d\u7136\u5e76\u975e\u5fc5\u987b\u76f8\u9694\u5f88\u8fdc)\u3002 +message.installWizard.copy.whatIsCloudStack=CloudStack&\#8482 \u662f\u4e00\u4e2a\u8f6f\u4ef6\u5e73\u53f0\uff0c\u53ef\u5c06\u8ba1\u7b97\u8d44\u6e90\u96c6\u4e2d\u5728\u4e00\u8d77\u4ee5\u6784\u5efa\u516c\u6709\u3001\u79c1\u6709\u548c\u6df7\u5408\u57fa\u7840\u8bbe\u65bd\u5373\u670d\u52a1(IaaS)\u4e91\u3002CloudStack&\#8482 \u8d1f\u8d23\u7ba1\u7406\u7ec4\u6210\u4e91\u57fa\u7840\u67b6\u6784\u7684\u7f51\u7edc\u3001\u5b58\u50a8\u548c\u8ba1\u7b97\u8282\u70b9\u3002\u4f7f\u7528 CloudStack&\#8482 \u53ef\u4ee5\u90e8\u7f72\u3001\u7ba1\u7406\u548c\u914d\u7f6e\u4e91\u8ba1\u7b97\u73af\u5883\u3002

CloudStack&\#8482 \u901a\u8fc7\u6269\u5c55\u5546\u7528\u786c\u4ef6\u4e0a\u8fd0\u884c\u7684\u6bcf\u4e2a\u865a\u62df\u673a\u6620\u50cf\u7684\u8303\u56f4\uff0c\u63d0\u4f9b\u4e86\u4e00\u4e2a\u5b9e\u65f6\u53ef\u7528\u7684\u4e91\u57fa\u7840\u67b6\u6784\u8f6f\u4ef6\u5806\u6808\u7528\u4e8e\u4ee5\u670d\u52a1\u65b9\u5f0f\u4ea4\u4ed8\u865a\u62df\u6570\u636e\u4e2d\u5fc3\uff0c\u5373\u4ea4\u4ed8\u6784\u5efa\u3001\u90e8\u7f72\u548c\u7ba1\u7406\u591a\u5c42\u6b21\u548c\u591a\u79df\u6237\u4e91\u5e94\u7528\u7a0b\u5e8f\u5fc5\u9700\u7684\u6240\u6709\u7ec4\u4ef6\u3002\u5f00\u6e90\u7248\u672c\u548c Premium \u7248\u672c\u90fd\u5df2\u53ef\u7528\uff0c\u4e14\u63d0\u4f9b\u7684\u529f\u80fd\u51e0\u4e4e\u5b8c\u5168\u76f8\u540c\u3002 +message.installWizard.copy.whatIsPrimaryStorage=CloudStack&\#8482; \u4e91\u57fa\u7840\u67b6\u6784\u4f7f\u7528\u4ee5\u4e0b\u4e24\u79cd\u7c7b\u578b\u7684\u5b58\u50a8\: \u4e3b\u5b58\u50a8\u548c\u4e8c\u7ea7\u5b58\u50a8\u3002\u8fd9\u4e24\u79cd\u7c7b\u578b\u7684\u5b58\u50a8\u53ef\u4ee5\u662f iSCSI \u6216 NFS \u670d\u52a1\u5668\uff0c\u4e5f\u53ef\u4ee5\u662f\u672c\u5730\u78c1\u76d8\u3002

\u4e3b\u5b58\u50a8\u4e0e\u7fa4\u96c6\u76f8\u5173\u8054\uff0c\u7528\u4e8e\u5b58\u50a8\u8be5\u7fa4\u96c6\u4e2d\u7684\u4e3b\u673a\u4e0a\u6b63\u5728\u8fd0\u884c\u7684\u6240\u6709 VM \u5bf9\u5e94\u7684\u6bcf\u4e2a\u6765\u5bbe VM \u7684\u78c1\u76d8\u5377\u3002\u4e3b\u5b58\u50a8\u670d\u52a1\u5668\u901a\u5e38\u4f4d\u4e8e\u9760\u8fd1\u4e3b\u673a\u7684\u4f4d\u7f6e\u3002 +message.installWizard.copy.whatIsSecondaryStorage=\u4e8c\u7ea7\u5b58\u50a8\u4e0e\u8d44\u6e90\u57df\u76f8\u5173\u8054\uff0c\u7528\u4e8e\u5b58\u50a8\u4ee5\u4e0b\u9879\u76ee\:
  • \u6a21\u677f - \u53ef\u7528\u4e8e\u542f\u52a8 VM \u5e76\u53ef\u4ee5\u5305\u542b\u5176\u4ed6\u914d\u7f6e\u4fe1\u606f(\u4f8b\u5982\uff0c\u5df2\u5b89\u88c5\u7684\u5e94\u7528\u7a0b\u5e8f)\u7684\u64cd\u4f5c\u7cfb\u7edf\u6620\u50cf
  • ISO \u6620\u50cf - \u53ef\u91cd\u65b0\u542f\u52a8\u6216\u4e0d\u53ef\u91cd\u65b0\u542f\u52a8\u7684\u64cd\u4f5c\u7cfb\u7edf\u6620\u50cf
  • \u78c1\u76d8\u5377\u5feb\u7167 - \u5df2\u4fdd\u5b58\u7684 VM \u6570\u636e\u526f\u672c\uff0c\u53ef\u7528\u4e8e\u6267\u884c\u6570\u636e\u6062\u590d\u6216\u521b\u5efa\u65b0\u6a21\u677f
message.installWizard.now.building=\u73b0\u5728\u6b63\u5728\u6784\u5efa\u60a8\u7684\u4e91... message.installWizard.tooltip.addCluster.name=\u7fa4\u96c6\u7684\u540d\u79f0\u3002\u6b64\u540d\u79f0\u53ef\u4ee5\u662f\u60a8\u9009\u62e9\u7684\u6587\u672c\uff0c\u4e14\u672a\u7531 CloudStack \u4f7f\u7528\u3002 message.installWizard.tooltip.addHost.hostname=\u4e3b\u673a\u7684 DNS \u540d\u79f0\u6216 IP \u5730\u5740\u3002 message.installWizard.tooltip.addHost.password=\u6b64\u4e3a\u4e0a\u8ff0\u7528\u6237\u7684\u5bc6\u7801(\u6765\u81ea XenServer \u5b89\u88c5)\u3002 message.installWizard.tooltip.addHost.username=\u901a\u5e38\u4e3a root\u3002 message.installWizard.tooltip.addPod.name=\u63d0\u4f9b\u70b9\u7684\u540d\u79f0 -message.installWizard.tooltip.addPod.reservedSystemEndIp=\u6b64\u4e3a CloudStack \u7528\u4e8e\u7ba1\u7406\u8f85\u52a9\u5b58\u50a8 VM \u548c\u63a7\u5236\u53f0\u4ee3\u7406 VM \u7684\u4e13\u7528\u7f51\u7edc\u4e2d\u7684 IP \u8303\u56f4\u3002\u8fd9\u4e9b IP \u5730\u5740\u6765\u81ea\u4e0e\u8ba1\u7b97\u670d\u52a1\u5668\u76f8\u540c\u7684\u5b50\u7f51\u3002 +message.installWizard.tooltip.addPod.reservedSystemEndIp=\u6b64\u4e3a CloudStack \u7528\u4e8e\u7ba1\u7406\u4e8c\u7ea7\u5b58\u50a8 VM \u548c\u63a7\u5236\u53f0\u4ee3\u7406 VM \u7684\u4e13\u7528\u7f51\u7edc\u4e2d\u7684 IP \u8303\u56f4\u3002\u8fd9\u4e9b IP \u5730\u5740\u6765\u81ea\u4e0e\u8ba1\u7b97\u670d\u52a1\u5668\u76f8\u540c\u7684\u5b50\u7f51\u3002 message.installWizard.tooltip.addPod.reservedSystemGateway=\u8be5\u63d0\u4f9b\u70b9\u4e2d\u7684\u4e3b\u673a\u7f51\u5173\u3002 message.installWizard.tooltip.addPod.reservedSystemNetmask=\u6765\u5bbe\u5c06\u8981\u4f7f\u7528\u7684\u5b50\u7f51\u4e0a\u6b63\u5728\u4f7f\u7528\u7684\u7f51\u7edc\u63a9\u7801\u3002 -message.installWizard.tooltip.addPod.reservedSystemStartIp=\u6b64\u4e3a CloudStack \u7528\u4e8e\u7ba1\u7406\u8f85\u52a9\u5b58\u50a8 VM \u548c\u63a7\u5236\u53f0\u4ee3\u7406 VM \u7684\u4e13\u7528\u7f51\u7edc\u4e2d\u7684 IP \u8303\u56f4\u3002\u8fd9\u4e9b IP \u5730\u5740\u6765\u81ea\u4e0e\u8ba1\u7b97\u670d\u52a1\u5668\u76f8\u540c\u7684\u5b50\u7f51\u3002 +message.installWizard.tooltip.addPod.reservedSystemStartIp=\u6b64\u4e3a CloudStack \u7528\u4e8e\u7ba1\u7406\u4e8c\u7ea7\u5b58\u50a8 VM \u548c\u63a7\u5236\u53f0\u4ee3\u7406 VM \u7684\u4e13\u7528\u7f51\u7edc\u4e2d\u7684 IP \u8303\u56f4\u3002\u8fd9\u4e9b IP \u5730\u5740\u6765\u81ea\u4e0e\u8ba1\u7b97\u670d\u52a1\u5668\u76f8\u540c\u7684\u5b50\u7f51\u3002 message.installWizard.tooltip.addPrimaryStorage.name=\u5b58\u50a8\u8bbe\u5907\u7684\u540d\u79f0\u3002 -message.installWizard.tooltip.addPrimaryStorage.path=(\u9002\u7528\u4e8e NFS)\u5728 NFS \u4e2d\uff0c\u6b64\u8def\u5f84\u4e3a\u670d\u52a1\u5668\u7684\u5bfc\u51fa\u8def\u5f84\u3002\u8def\u5f84(\u9488\u5bf9 SharedMountPoint)\u3002\u5bf9\u4e8e KVM\uff0c\u6b64\u8def\u5f84\u4e3a\u88c5\u8f7d\u4e86\u8f85\u52a9\u5b58\u50a8\u7684\u6bcf\u4e2a\u4e3b\u673a\u4e0a\u7684\u8def\u5f84\u3002\u4f8b\u5982\uff0c/mnt/primary\u3002 +message.installWizard.tooltip.addPrimaryStorage.path=(\u9002\u7528\u4e8e NFS)\u5728 NFS \u4e2d\uff0c\u6b64\u8def\u5f84\u4e3a\u670d\u52a1\u5668\u7684\u5bfc\u51fa\u8def\u5f84\u3002\u8def\u5f84(\u9488\u5bf9 SharedMountPoint)\u3002\u5bf9\u4e8e KVM\uff0c\u6b64\u8def\u5f84\u4e3a\u88c5\u8f7d\u4e86\u4e8c\u7ea7\u5b58\u50a8\u7684\u6bcf\u4e2a\u4e3b\u673a\u4e0a\u7684\u8def\u5f84\u3002\u4f8b\u5982\uff0c/mnt/primary\u3002 message.installWizard.tooltip.addPrimaryStorage.server=(\u9002\u7528\u4e8e NFS\u3001iSCSI \u6216 PreSetup)\u5b58\u50a8\u8bbe\u5907\u7684 IP \u5730\u5740\u6216 DNS \u540d\u79f0\u3002 -message.installWizard.tooltip.addSecondaryStorage.nfsServer=\u6258\u7ba1\u8f85\u52a9\u5b58\u50a8\u7684 NFS \u670d\u52a1\u5668\u7684 IP \u5730\u5740 +message.installWizard.tooltip.addSecondaryStorage.nfsServer=\u6258\u7ba1\u4e8c\u7ea7\u5b58\u50a8\u7684 NFS \u670d\u52a1\u5668\u7684 IP \u5730\u5740 message.installWizard.tooltip.addSecondaryStorage.path=\u5bfc\u51fa\u8def\u5f84(\u4f4d\u4e8e\u4e0a\u8ff0\u6307\u5b9a\u670d\u52a1\u5668\u4e0a) -message.installWizard.tooltip.addZone.dns1=\u8fd9\u4e9b\u670d\u52a1\u5668\u662f\u4f9b\u6b64\u533a\u57df\u4e2d\u7684\u6765\u5bbe VM \u4f7f\u7528\u7684 DNS \u670d\u52a1\u5668\uff0c\u5c06\u901a\u8fc7\u60a8\u7a0d\u540e\u8981\u6dfb\u52a0\u7684\u516c\u7528\u7f51\u7edc\u8fdb\u884c\u8bbf\u95ee\u3002\u6b64\u533a\u57df\u7684\u516c\u7528 IP \u5730\u5740\u5fc5\u987b\u8def\u7531\u5230\u5728\u6b64\u5904\u6307\u5b9a\u7684 DNS \u670d\u52a1\u5668\u3002 -message.installWizard.tooltip.addZone.dns2=\u8fd9\u4e9b\u670d\u52a1\u5668\u662f\u4f9b\u6b64\u533a\u57df\u4e2d\u7684\u6765\u5bbe VM \u4f7f\u7528\u7684 DNS \u670d\u52a1\u5668\uff0c\u5c06\u901a\u8fc7\u60a8\u7a0d\u540e\u8981\u6dfb\u52a0\u7684\u516c\u7528\u7f51\u7edc\u8fdb\u884c\u8bbf\u95ee\u3002\u6b64\u533a\u57df\u7684\u516c\u7528 IP \u5730\u5740\u5fc5\u987b\u8def\u7531\u5230\u5728\u6b64\u5904\u6307\u5b9a\u7684 DNS \u670d\u52a1\u5668\u3002 -message.installWizard.tooltip.addZone.internaldns1=\u8fd9\u4e9b\u670d\u52a1\u5668\u662f\u4f9b\u6b64\u533a\u57df\u4e2d\u7684\u7cfb\u7edf VM \u4f7f\u7528\u7684 DNS \u670d\u52a1\u5668\uff0c\u5c06\u901a\u8fc7\u7cfb\u7edf VM \u7684\u4e13\u7528\u7f51\u7edc\u63a5\u53e3\u8fdb\u884c\u8bbf\u95ee\u3002\u60a8\u4e3a\u63d0\u4f9b\u70b9\u63d0\u4f9b\u7684\u4e13\u7528 IP \u5730\u5740\u5fc5\u987b\u8def\u7531\u5230\u5728\u6b64\u5904\u6307\u5b9a\u7684 DNS \u670d\u52a1\u5668\u3002 -message.installWizard.tooltip.addZone.internaldns2=\u8fd9\u4e9b\u670d\u52a1\u5668\u662f\u4f9b\u6b64\u533a\u57df\u4e2d\u7684\u7cfb\u7edf VM \u4f7f\u7528\u7684 DNS \u670d\u52a1\u5668\uff0c\u5c06\u901a\u8fc7\u7cfb\u7edf VM \u7684\u4e13\u7528\u7f51\u7edc\u63a5\u53e3\u8fdb\u884c\u8bbf\u95ee\u3002\u60a8\u4e3a\u63d0\u4f9b\u70b9\u63d0\u4f9b\u7684\u4e13\u7528 IP \u5730\u5740\u5fc5\u987b\u8def\u7531\u5230\u5728\u6b64\u5904\u6307\u5b9a\u7684 DNS \u670d\u52a1\u5668\u3002 -message.installWizard.tooltip.addZone.name=\u533a\u57df\u540d\u79f0 +message.installWizard.tooltip.addZone.dns1=\u8fd9\u4e9b\u670d\u52a1\u5668\u662f\u4f9b\u6b64\u8d44\u6e90\u57df\u4e2d\u7684\u6765\u5bbe VM \u4f7f\u7528\u7684 DNS \u670d\u52a1\u5668\uff0c\u5c06\u901a\u8fc7\u60a8\u7a0d\u540e\u8981\u6dfb\u52a0\u7684\u516c\u7528\u7f51\u7edc\u8fdb\u884c\u8bbf\u95ee\u3002\u6b64\u8d44\u6e90\u57df\u7684\u516c\u7528 IP \u5730\u5740\u5fc5\u987b\u8def\u7531\u5230\u5728\u6b64\u5904\u6307\u5b9a\u7684 DNS \u670d\u52a1\u5668\u3002 +message.installWizard.tooltip.addZone.dns2=\u8fd9\u4e9b\u670d\u52a1\u5668\u662f\u4f9b\u6b64\u8d44\u6e90\u57df\u4e2d\u7684\u6765\u5bbe VM \u4f7f\u7528\u7684 DNS \u670d\u52a1\u5668\uff0c\u5c06\u901a\u8fc7\u60a8\u7a0d\u540e\u8981\u6dfb\u52a0\u7684\u516c\u7528\u7f51\u7edc\u8fdb\u884c\u8bbf\u95ee\u3002\u6b64\u8d44\u6e90\u57df\u7684\u516c\u7528 IP \u5730\u5740\u5fc5\u987b\u8def\u7531\u5230\u5728\u6b64\u5904\u6307\u5b9a\u7684 DNS \u670d\u52a1\u5668\u3002 +message.installWizard.tooltip.addZone.internaldns1=\u8fd9\u4e9b\u670d\u52a1\u5668\u662f\u4f9b\u6b64\u8d44\u6e90\u57df\u4e2d\u7684\u7cfb\u7edf VM \u4f7f\u7528\u7684 DNS \u670d\u52a1\u5668\uff0c\u5c06\u901a\u8fc7\u7cfb\u7edf VM \u7684\u4e13\u7528\u7f51\u7edc\u63a5\u53e3\u8fdb\u884c\u8bbf\u95ee\u3002\u60a8\u4e3a\u63d0\u4f9b\u70b9\u63d0\u4f9b\u7684\u4e13\u7528 IP \u5730\u5740\u5fc5\u987b\u8def\u7531\u5230\u5728\u6b64\u5904\u6307\u5b9a\u7684 DNS \u670d\u52a1\u5668\u3002 +message.installWizard.tooltip.addZone.internaldns2=\u8fd9\u4e9b\u670d\u52a1\u5668\u662f\u4f9b\u6b64\u8d44\u6e90\u57df\u4e2d\u7684\u7cfb\u7edf VM \u4f7f\u7528\u7684 DNS \u670d\u52a1\u5668\uff0c\u5c06\u901a\u8fc7\u7cfb\u7edf VM \u7684\u4e13\u7528\u7f51\u7edc\u63a5\u53e3\u8fdb\u884c\u8bbf\u95ee\u3002\u60a8\u4e3a\u63d0\u4f9b\u70b9\u63d0\u4f9b\u7684\u4e13\u7528 IP \u5730\u5740\u5fc5\u987b\u8def\u7531\u5230\u5728\u6b64\u5904\u6307\u5b9a\u7684 DNS \u670d\u52a1\u5668\u3002 +message.installWizard.tooltip.addZone.name=\u8d44\u6e90\u57df\u540d\u79f0 message.installWizard.tooltip.configureGuestTraffic.description=\u60a8\u7684\u7f51\u7edc\u8bf4\u660e -message.installWizard.tooltip.configureGuestTraffic.guestEndIp=\u80fd\u591f\u5206\u914d\u7ed9\u6b64\u533a\u57df\u4e2d\u7684\u6765\u5bbe\u7684 IP \u5730\u5740\u8303\u56f4\u3002\u5982\u679c\u4f7f\u7528\u4e00\u4e2a NIC\uff0c\u8fd9\u4e9b IP \u5e94\u4f4d\u4e8e\u4e0e\u63d0\u4f9b\u70b9 CIDR \u76f8\u540c\u7684 CIDR \u4e2d\u3002 +message.installWizard.tooltip.configureGuestTraffic.guestEndIp=\u80fd\u591f\u5206\u914d\u7ed9\u6b64\u8d44\u6e90\u57df\u4e2d\u7684\u6765\u5bbe\u7684 IP \u5730\u5740\u8303\u56f4\u3002\u5982\u679c\u4f7f\u7528\u4e00\u4e2a NIC\uff0c\u8fd9\u4e9b IP \u5e94\u4f4d\u4e8e\u4e0e\u63d0\u4f9b\u70b9 CIDR \u76f8\u540c\u7684 CIDR \u4e2d\u3002 message.installWizard.tooltip.configureGuestTraffic.guestGateway=\u6765\u5bbe\u5e94\u4f7f\u7528\u7684\u7f51\u5173 message.installWizard.tooltip.configureGuestTraffic.guestNetmask=\u6765\u5bbe\u5e94\u4f7f\u7528\u7684\u5b50\u7f51\u4e0a\u6b63\u5728\u4f7f\u7528\u7684\u7f51\u7edc\u63a9\u7801 -message.installWizard.tooltip.configureGuestTraffic.guestStartIp=\u80fd\u591f\u5206\u914d\u7ed9\u6b64\u533a\u57df\u4e2d\u7684\u6765\u5bbe\u7684 IP \u5730\u5740\u8303\u56f4\u3002\u5982\u679c\u4f7f\u7528\u4e00\u4e2a NIC\uff0c\u8fd9\u4e9b IP \u5e94\u4f4d\u4e8e\u4e0e\u63d0\u4f9b\u70b9 CIDR \u76f8\u540c\u7684 CIDR \u4e2d\u3002 +message.installWizard.tooltip.configureGuestTraffic.guestStartIp=\u80fd\u591f\u5206\u914d\u7ed9\u6b64\u8d44\u6e90\u57df\u4e2d\u7684\u6765\u5bbe\u7684 IP \u5730\u5740\u8303\u56f4\u3002\u5982\u679c\u4f7f\u7528\u4e00\u4e2a NIC\uff0c\u8fd9\u4e9b IP \u5e94\u4f4d\u4e8e\u4e0e\u63d0\u4f9b\u70b9 CIDR \u76f8\u540c\u7684 CIDR \u4e2d\u3002 message.installWizard.tooltip.configureGuestTraffic.name=\u60a8\u7684\u7f51\u7edc\u540d\u79f0 message.instanceWizard.noTemplates=\u60a8\u6ca1\u6709\u4efb\u4f55\u53ef\u7528\u6a21\u677f\uff1b\u8bf7\u6dfb\u52a0\u4e00\u4e2a\u517c\u5bb9\u7684\u6a21\u677f\uff0c\u7136\u540e\u91cd\u65b0\u542f\u52a8\u5b9e\u4f8b\u5411\u5bfc\u3002 message.ip.address.changed=\u60a8\u7684 IP \u5730\u5740\u53ef\u80fd\u5df2\u53d1\u751f\u53d8\u5316\uff1b\u662f\u5426\u8981\u5237\u65b0\u6b64\u5217\u8868? \u8bf7\u6ce8\u610f\uff0c\u5237\u65b0\u6b64\u5217\u8868\u65f6\uff0c\u201c\u8be6\u7ec6\u4fe1\u606f\u201d\u7a97\u683c\u5c06\u5173\u95ed\u3002 message.iso.desc=\u78c1\u76d8\u6620\u50cf\uff0c\u5176\u4e2d\u5305\u542b\u64cd\u4f5c\u7cfb\u7edf\u7684\u6570\u636e\u6216\u53ef\u542f\u52a8\u4ecb\u8d28 message.join.project=\u60a8\u73b0\u5728\u5df2\u52a0\u5165\u4e86\u4e00\u4e2a\u9879\u76ee\u3002\u8bf7\u5207\u6362\u5230\u201c\u9879\u76ee\u89c6\u56fe\u201d\u4ee5\u67e5\u770b\u9879\u76ee\u3002 message.launch.vm.on.private.network=\u662f\u5426\u8981\u5728\u60a8\u7684\u79c1\u4eba\u4e13\u7528\u7f51\u7edc\u4e2d\u542f\u52a8\u5b9e\u4f8b? -message.launch.zone=\u533a\u57df\u5df2\u51c6\u5907\u5c31\u7eea\uff0c\u53ef\u968f\u65f6\u542f\u52a8\uff1b\u8bf7\u7ee7\u7eed\u6267\u884c\u4e0b\u4e00\u6b65\u9aa4\u3002 +message.launch.zone=\u8d44\u6e90\u57df\u5df2\u51c6\u5907\u5c31\u7eea\uff0c\u53ef\u968f\u65f6\u542f\u52a8\uff1b\u8bf7\u7ee7\u7eed\u6267\u884c\u4e0b\u4e00\u6b65\u9aa4\u3002 message.lock.account=\u8bf7\u786e\u8ba4\u60a8\u786e\u5b9e\u8981\u9501\u5b9a\u6b64\u5e10\u6237\u3002\u901a\u8fc7\u9501\u5b9a\u6b64\u5e10\u6237\uff0c\u6b64\u5e10\u6237\u7684\u6240\u6709\u7528\u6237\u5c06\u4e0d\u518d\u80fd\u591f\u7ba1\u7406\u5404\u81ea\u7684\u4e91\u8d44\u6e90\uff0c\u4f46\u4ecd\u7136\u53ef\u4ee5\u8bbf\u95ee\u73b0\u6709\u8d44\u6e90\u3002 message.migrate.instance.confirm=\u8bf7\u786e\u8ba4\u8981\u5c06\u865a\u62df\u5b9e\u4f8b\u8fc1\u79fb\u5230\u7684\u4e3b\u673a\u3002 message.migrate.instance.to.host=\u8bf7\u786e\u8ba4\u60a8\u786e\u5b9e\u8981\u5c06\u5b9e\u4f8b\u8fc1\u79fb\u5230\u5176\u4ed6\u4e3b\u673a\u3002 @@ -1551,7 +1714,7 @@ message.migrate.router.confirm=\u8bf7\u786e\u8ba4\u60a8\u8981\u5c06\u8def\u7531\ message.migrate.systemvm.confirm=\u8bf7\u786e\u8ba4\u60a8\u8981\u5c06\u7cfb\u7edf VM \u8fc1\u79fb\u5230\u7684\u4e3b\u673a\: message.migrate.volume=\u8bf7\u786e\u8ba4\u60a8\u786e\u5b9e\u8981\u5c06\u5377\u8fc1\u79fb\u5230\u5176\u4ed6\u4e3b\u5b58\u50a8\u3002 message.new.user=\u8bf7\u6307\u5b9a\u4ee5\u4e0b\u4fe1\u606f\u4ee5\u5411\u5e10\u6237\u4e2d\u6dfb\u52a0\u4e00\u4e2a\u65b0\u7528\u6237 -message.no.network.support.configuration.not.true=\u60a8\u7684\u6240\u6709\u533a\u57df\u90fd\u672a\u542f\u7528\u5b89\u5168\u7ec4\uff0c\u56e0\u6b64\u65e0\u5176\u4ed6\u7f51\u7edc\u529f\u80fd\u3002\u8bf7\u7ee7\u7eed\u6267\u884c\u6b65\u9aa4 5\u3002 +message.no.network.support.configuration.not.true=\u60a8\u7684\u6240\u6709\u8d44\u6e90\u57df\u90fd\u672a\u542f\u7528\u5b89\u5168\u7ec4\uff0c\u56e0\u6b64\u65e0\u5176\u4ed6\u7f51\u7edc\u529f\u80fd\u3002\u8bf7\u7ee7\u7eed\u6267\u884c\u6b65\u9aa4 5\u3002 message.no.network.support=\u60a8\u9009\u62e9\u7684\u865a\u62df\u673a\u7ba1\u7406\u7a0b\u5e8f vSphere \u6ca1\u6709\u4efb\u4f55\u5176\u4ed6\u7f51\u7edc\u529f\u80fd\u3002\u8bf7\u7ee7\u7eed\u6267\u884c\u6b65\u9aa4 5\u3002 message.no.projects.adminOnly=\u60a8\u6ca1\u6709\u4efb\u4f55\u9879\u76ee\u3002
\u8bf7\u8981\u6c42\u7ba1\u7406\u5458\u521b\u5efa\u4e00\u4e2a\u65b0\u9879\u76ee\u3002 message.no.projects=\u60a8\u6ca1\u6709\u4efb\u4f55\u9879\u76ee\u3002
\u8bf7\u4ece\u201c\u9879\u76ee\u201d\u90e8\u5206\u4e2d\u521b\u5efa\u4e00\u4e2a\u65b0\u9879\u76ee\u3002 @@ -1559,20 +1722,20 @@ message.number.clusters=

\u7fa4\u96c6\u6570

message.number.hosts=

\u4e3b\u673a\u6570

message.number.pods=

\u63d0\u4f9b\u70b9\u6570

message.number.storage=

\u4e3b\u5b58\u50a8\u5377\u6570

-message.number.zones=

\u533a\u57df\u6570

+message.number.zones=

\u8d44\u6e90\u57df\u6570

message.pending.projects.1=\u60a8\u6709\u5f85\u5b9a\u9879\u76ee\u9080\u8bf7\: message.pending.projects.2=\u8981\u67e5\u770b\uff0c\u8bf7\u8f6c\u81f3\u201c\u9879\u76ee\u201d\u90e8\u5206\uff0c\u7136\u540e\u4ece\u4e0b\u62c9\u5217\u8868\u4e2d\u9009\u62e9\u201c\u9080\u8bf7\u201d\u3002 -message.please.add.at.lease.one.traffic.range=\u8bf7\u81f3\u5c11\u6dfb\u52a0\u4e00\u4e2a\u901a\u4fe1\u8303\u56f4\u3002 +message.please.add.at.lease.one.traffic.range=\u8bf7\u81f3\u5c11\u6dfb\u52a0\u4e00\u4e2a\u6d41\u91cf\u8303\u56f4\u3002 message.please.proceed=\u8bf7\u7ee7\u7eed\u6267\u884c\u4e0b\u4e2a\u6b65\u9aa4\u3002 -message.please.select.a.configuration.for.your.zone=\u8bf7\u4e3a\u60a8\u7684\u533a\u57df\u9009\u62e9\u4e00\u79cd\u914d\u7f6e\u3002 -message.please.select.a.different.public.and.management.network.before.removing=\u8bf7\u5148\u9009\u62e9\u5176\u4ed6\u516c\u5171\u7ba1\u7406\u7f51\u7edc\uff0c\u7136\u540e\u518d\u5220\u9664 +message.please.select.a.configuration.for.your.zone=\u8bf7\u4e3a\u60a8\u7684\u8d44\u6e90\u57df\u9009\u62e9\u4e00\u79cd\u914d\u7f6e\u3002 +message.please.select.a.different.public.and.management.network.before.removing=\u8bf7\u5148\u9009\u62e9\u5176\u4ed6\u516c\u7528\u7ba1\u7406\u7f51\u7edc\uff0c\u7136\u540e\u518d\u5220\u9664 message.please.select.networks=\u8bf7\u4e3a\u60a8\u7684\u865a\u62df\u673a\u9009\u62e9\u7f51\u7edc\u3002 -message.please.wait.while.zone.is.being.created=\u6b63\u5728\u521b\u5efa\u533a\u57df\uff0c\u8bf7\u7a0d\u5019\uff1b\u6b64\u64cd\u4f5c\u53ef\u80fd\u9700\u8981\u4e00\u6bb5\u65f6\u95f4\u624d\u80fd\u5b8c\u6210... +message.please.wait.while.zone.is.being.created=\u6b63\u5728\u521b\u5efa\u8d44\u6e90\u57df\uff0c\u8bf7\u7a0d\u5019\uff1b\u6b64\u64cd\u4f5c\u53ef\u80fd\u9700\u8981\u4e00\u6bb5\u65f6\u95f4\u624d\u80fd\u5b8c\u6210... message.project.invite.sent=\u53d1\u9001\u7ed9\u7528\u6237\u7684\u9080\u8bf7\uff1b\u7528\u6237\u63a5\u53d7\u9080\u8bf7\u540e\uff0c\u5c06\u52a0\u5165\u5230\u9879\u76ee\u4e2d -message.public.traffic.in.advanced.zone=\u4e91\u4e2d\u7684 VM \u8bbf\u95ee Internet \u65f6\u5c06\u751f\u6210\u516c\u5171\u901a\u4fe1\uff0c\u4f46\u5fc5\u987b\u5206\u914d\u53ef\u516c\u5f00\u8bbf\u95ee\u7684 IP \u624d\u80fd\u5b9e\u73b0\u3002\u6700\u7ec8\u7528\u6237\u53ef\u4ee5\u4f7f\u7528 CloudStack UI \u83b7\u53d6\u8fd9\u4e9b IP\uff0c\u4ee5\u5728\u5176\u6765\u5bbe\u7f51\u7edc\u4e0e\u516c\u7528\u7f51\u7edc\u4e4b\u95f4\u6267\u884c NAT\u3002

\u8bf7\u81f3\u5c11\u4e3a Internet \u901a\u4fe1\u63d0\u4f9b\u4e00\u4e2a IP \u5730\u5740\u8303\u56f4\u3002 -message.public.traffic.in.basic.zone=\u4e91\u4e2d\u7684 VM \u8bbf\u95ee Internet \u6216\u901a\u8fc7 Internet \u5411\u5ba2\u6237\u7aef\u63d0\u4f9b\u670d\u52a1\u65f6\u5c06\u751f\u6210\u516c\u5171\u901a\u4fe1\uff0c\u4f46\u5fc5\u987b\u5206\u914d\u53ef\u516c\u5f00\u8bbf\u95ee\u7684 IP \u624d\u80fd\u5b9e\u73b0\u3002\u521b\u5efa\u5b9e\u4f8b\u65f6\uff0c\u5c06\u628a\u8fd9\u4e00\u7ec4\u516c\u7528 IP \u4e2d\u7684 IP (\u6765\u5bbe IP \u5730\u5740\u9664\u5916)\u5206\u914d\u7ed9\u6b64\u5b9e\u4f8b\u3002\u9759\u6001 1-1 NAT \u5c06\u5728\u516c\u7528 IP \u4e0e\u6765\u5bbe IP \u4e4b\u95f4\u81ea\u52a8\u8bbe\u7f6e\u3002\u6700\u7ec8\u7528\u6237\u8fd8\u53ef\u4ee5\u4f7f\u7528 CloudStack UI \u83b7\u53d6\u5176\u4ed6 IP\uff0c\u4ee5\u5728\u5176\u5b9e\u4f8b\u4e0e\u516c\u7528 IP \u4e4b\u95f4\u6267\u884c\u9759\u6001 NAT\u3002 -message.redirecting.region=\u6b63\u5728\u91cd\u5b9a\u5411\u5230\u533a\u57df... -message.remove.region=\u662f\u5426\u786e\u5b9e\u8981\u4ece\u6b64\u7ba1\u7406\u670d\u52a1\u5668\u4e2d\u5220\u9664\u6b64\u533a\u57df? +message.public.traffic.in.advanced.zone=\u4e91\u4e2d\u7684 VM \u8bbf\u95ee Internet \u65f6\u5c06\u751f\u6210\u516c\u5171\u6d41\u91cf\uff0c\u4f46\u5fc5\u987b\u5206\u914d\u53ef\u516c\u5f00\u8bbf\u95ee\u7684 IP \u624d\u80fd\u5b9e\u73b0\u3002\u6700\u7ec8\u7528\u6237\u53ef\u4ee5\u4f7f\u7528 CloudStack UI \u83b7\u53d6\u8fd9\u4e9b IP\uff0c\u4ee5\u5728\u5176\u6765\u5bbe\u7f51\u7edc\u4e0e\u516c\u7528\u7f51\u7edc\u4e4b\u95f4\u6267\u884c NAT\u3002

\u8bf7\u81f3\u5c11\u4e3a Internet \u6d41\u91cf\u63d0\u4f9b\u4e00\u4e2a IP \u5730\u5740\u8303\u56f4\u3002 +message.public.traffic.in.basic.zone=\u4e91\u4e2d\u7684 VM \u8bbf\u95ee Internet \u6216\u901a\u8fc7 Internet \u5411\u5ba2\u6237\u7aef\u63d0\u4f9b\u670d\u52a1\u65f6\u5c06\u751f\u6210\u516c\u5171\u6d41\u91cf\uff0c\u4f46\u5fc5\u987b\u5206\u914d\u53ef\u516c\u5f00\u8bbf\u95ee\u7684 IP \u624d\u80fd\u5b9e\u73b0\u3002\u521b\u5efa\u5b9e\u4f8b\u65f6\uff0c\u5c06\u628a\u8fd9\u4e00\u7ec4\u516c\u7528 IP \u4e2d\u7684 IP (\u6765\u5bbe IP \u5730\u5740\u9664\u5916)\u5206\u914d\u7ed9\u6b64\u5b9e\u4f8b\u3002\u9759\u6001 1-1 NAT \u5c06\u5728\u516c\u7528 IP \u4e0e\u6765\u5bbe IP \u4e4b\u95f4\u81ea\u52a8\u8bbe\u7f6e\u3002\u6700\u7ec8\u7528\u6237\u8fd8\u53ef\u4ee5\u4f7f\u7528 CloudStack UI \u83b7\u53d6\u5176\u4ed6 IP\uff0c\u4ee5\u5728\u5176\u5b9e\u4f8b\u4e0e\u516c\u7528 IP \u4e4b\u95f4\u6267\u884c\u9759\u6001 NAT\u3002 +message.redirecting.region=\u6b63\u5728\u91cd\u5b9a\u5411\u5230\u5730\u7406\u533a\u57df... +message.remove.region=\u662f\u5426\u786e\u5b9e\u8981\u4ece\u6b64\u7ba1\u7406\u670d\u52a1\u5668\u4e2d\u5220\u9664\u6b64\u5730\u7406\u533a\u57df? message.remove.vpc=\u8bf7\u786e\u8ba4\u60a8\u786e\u5b9e\u8981\u5220\u9664 VPC message.remove.vpn.access=\u8bf7\u786e\u8ba4\u60a8\u786e\u5b9e\u8981\u5220\u9664\u4ee5\u4e0b\u7528\u6237\u7684 VPN \u8bbf\u95ee\u3002 message.reset.password.warning.notPasswordEnabled=\u521b\u5efa\u6b64\u5b9e\u4f8b\u7684\u6a21\u677f\u65f6\u672a\u542f\u7528\u5bc6\u7801 @@ -1583,14 +1746,14 @@ message.restart.mgmt.usage.server=\u8bf7\u91cd\u65b0\u542f\u52a8\u7ba1\u7406\u67 message.restart.network=\u6b64\u7f51\u7edc\u63d0\u4f9b\u7684\u6240\u6709\u670d\u52a1\u90fd\u5c06\u4e2d\u65ad\u3002\u8bf7\u786e\u8ba4\u60a8\u786e\u5b9e\u8981\u91cd\u65b0\u542f\u52a8\u6b64\u7f51\u7edc\u3002 message.restart.vpc=\u8bf7\u786e\u8ba4\u60a8\u786e\u5b9e\u8981\u91cd\u65b0\u542f\u52a8 VPC message.security.group.usage=(\u6309\u4f4f Ctrl \u952e\u5e76\u5355\u51fb\u9f20\u6807\u53ef\u9009\u62e9\u6240\u6709\u9002\u7528\u7684\u5b89\u5168\u7ec4) -message.select.a.zone=\u4e00\u4e2a\u533a\u57df\u901a\u5e38\u4e0e\u4e00\u4e2a\u6570\u636e\u4e2d\u5fc3\u76f8\u5bf9\u5e94\u3002\u591a\u4e2a\u533a\u57df\u53ef\u4ee5\u63d0\u4f9b\u7269\u7406\u9694\u79bb\u548c\u5197\u4f59\uff0c\u6709\u52a9\u4e8e\u4f7f\u4e91\u66f4\u52a0\u53ef\u9760\u3002 +message.select.a.zone=\u4e00\u4e2a\u8d44\u6e90\u57df\u901a\u5e38\u4e0e\u4e00\u4e2a\u6570\u636e\u4e2d\u5fc3\u76f8\u5bf9\u5e94\u3002\u591a\u4e2a\u8d44\u6e90\u57df\u53ef\u4ee5\u63d0\u4f9b\u7269\u7406\u9694\u79bb\u548c\u5197\u4f59\uff0c\u6709\u52a9\u4e8e\u4f7f\u4e91\u66f4\u52a0\u53ef\u9760\u3002 message.select.instance=\u8bf7\u9009\u62e9\u4e00\u4e2a\u5b9e\u4f8b\u3002 message.select.iso=\u8bf7\u4e3a\u60a8\u7684\u65b0\u865a\u62df\u5b9e\u4f8b\u9009\u62e9\u4e00\u4e2a ISO\u3002 message.select.item=\u8bf7\u9009\u62e9\u4e00\u4e2a\u9879\u76ee\u3002 message.select.security.groups=\u8bf7\u4e3a\u60a8\u7684\u65b0 VM \u9009\u62e9\u5b89\u5168\u7ec4 message.select.template=\u8bf7\u4e3a\u60a8\u7684\u65b0\u865a\u62df\u5b9e\u4f8b\u9009\u62e9\u4e00\u4e2a\u6a21\u677f\u3002 -message.setup.physical.network.during.zone.creation.basic=\u6dfb\u52a0\u57fa\u7840\u533a\u57df\u65f6\uff0c\u53ef\u4ee5\u8bbe\u7f6e\u4e00\u4e2a\u7269\u7406\u7f51\u7edc\uff0c\u6b64\u7f51\u7edc\u5e94\u4e0e\u865a\u62df\u673a\u7ba1\u7406\u7a0b\u5e8f\u4e2d\u7684 NIC \u76f8\u5bf9\u5e94\u3002\u6b64\u7f51\u7edc\u53ef\u4ee5\u627f\u8f7d\u591a\u79cd\u901a\u4fe1\u7c7b\u578b\u3002

\u6b64\u5916\uff0c\u8fd8\u53ef\u4ee5\u5c06\u5176\u4ed6\u901a\u4fe1\u7c7b\u578b\u62d6\u653e\u5230\u6b64\u7269\u7406\u7f51\u7edc\u3002 -message.setup.physical.network.during.zone.creation=\u6dfb\u52a0\u9ad8\u7ea7\u533a\u57df\u65f6\uff0c\u9700\u8981\u8bbe\u7f6e\u4e00\u4e2a\u6216\u591a\u4e2a\u7269\u7406\u7f51\u7edc\u3002\u6bcf\u4e2a\u7f51\u7edc\u90fd\u4e0e\u865a\u62df\u673a\u7ba1\u7406\u7a0b\u5e8f\u4e2d\u7684\u4e00\u4e2a NIC \u76f8\u5bf9\u5e94\u3002\u6bcf\u4e2a\u7269\u7406\u7f51\u7edc\u4e2d\u53ef\u4ee5\u5305\u542b\u4e00\u79cd\u6216\u591a\u79cd\u901a\u4fe1\u7c7b\u578b\uff0c\u5e76\u5bf9\u8fd9\u4e9b\u901a\u4fe1\u7c7b\u578b\u53ef\u80fd\u7684\u7ec4\u5408\u65b9\u5f0f\u8bbe\u7f6e\u4e86\u67d0\u4e9b\u9650\u5236\u3002

\u53ef\u4ee5\u5c06\u4e00\u79cd\u6216\u591a\u79cd\u901a\u4fe1\u7c7b\u578b\u62d6\u653e\u5230\u6bcf\u4e2a\u7269\u7406\u7f51\u7edc\u4e2d\u3002 +message.setup.physical.network.during.zone.creation.basic=\u6dfb\u52a0\u57fa\u7840\u8d44\u6e90\u57df\u65f6\uff0c\u53ef\u4ee5\u8bbe\u7f6e\u4e00\u4e2a\u7269\u7406\u7f51\u7edc\uff0c\u6b64\u7f51\u7edc\u5e94\u4e0e\u865a\u62df\u673a\u7ba1\u7406\u7a0b\u5e8f\u4e2d\u7684 NIC \u76f8\u5bf9\u5e94\u3002\u6b64\u7f51\u7edc\u53ef\u4ee5\u627f\u8f7d\u591a\u79cd\u6d41\u91cf\u7c7b\u578b\u3002

\u6b64\u5916\uff0c\u8fd8\u53ef\u4ee5\u5c06\u5176\u4ed6\u6d41\u91cf\u7c7b\u578b\u62d6\u653e\u5230\u6b64\u7269\u7406\u7f51\u7edc\u3002 +message.setup.physical.network.during.zone.creation=\u6dfb\u52a0\u9ad8\u7ea7\u8d44\u6e90\u57df\u65f6\uff0c\u9700\u8981\u8bbe\u7f6e\u4e00\u4e2a\u6216\u591a\u4e2a\u7269\u7406\u7f51\u7edc\u3002\u6bcf\u4e2a\u7f51\u7edc\u90fd\u4e0e\u865a\u62df\u673a\u7ba1\u7406\u7a0b\u5e8f\u4e2d\u7684\u4e00\u4e2a NIC \u76f8\u5bf9\u5e94\u3002\u6bcf\u4e2a\u7269\u7406\u7f51\u7edc\u4e2d\u53ef\u4ee5\u5305\u542b\u4e00\u79cd\u6216\u591a\u79cd\u6d41\u91cf\u7c7b\u578b\uff0c\u5e76\u5bf9\u8fd9\u4e9b\u6d41\u91cf\u7c7b\u578b\u53ef\u80fd\u7684\u7ec4\u5408\u65b9\u5f0f\u8bbe\u7f6e\u4e86\u67d0\u4e9b\u9650\u5236\u3002

\u53ef\u4ee5\u5c06\u4e00\u79cd\u6216\u591a\u79cd\u6d41\u91cf\u7c7b\u578b\u62d6\u653e\u5230\u6bcf\u4e2a\u7269\u7406\u7f51\u7edc\u4e2d\u3002 message.setup.successful=\u5df2\u6210\u529f\u8bbe\u7f6e\u4e91\! message.snapshot.schedule=\u53ef\u4ee5\u901a\u8fc7\u4ece\u4ee5\u4e0b\u53ef\u7528\u9009\u9879\u4e2d\u8fdb\u884c\u9009\u62e9\u5e76\u5e94\u7528\u60a8\u7684\u7b56\u7565\u9996\u9009\u9879\u6765\u8bbe\u7f6e\u91cd\u73b0\u5feb\u7167\u8ba1\u5212 message.specify.url=\u8bf7\u6307\u5b9a URL @@ -1602,18 +1765,18 @@ message.step.3.continue=\u8bf7\u9009\u62e9\u4e00\u79cd\u78c1\u76d8\u65b9\u6848\u message.step.3.desc= message.step.4.continue=\u8bf7\u81f3\u5c11\u9009\u62e9\u4e00\u4e2a\u7f51\u7edc\u4ee5\u7ee7\u7eed message.step.4.desc=\u8bf7\u9009\u62e9\u865a\u62df\u5b9e\u4f8b\u8981\u8fde\u63a5\u5230\u7684\u4e3b\u7f51\u7edc\u3002 -message.storage.traffic=CloudStack \u5185\u90e8\u8d44\u6e90(\u5305\u62ec\u4e0e\u7ba1\u7406\u670d\u52a1\u5668\u901a\u4fe1\u7684\u4efb\u4f55\u7ec4\u4ef6\uff0c\u4f8b\u5982\u4e3b\u673a\u548c CloudStack \u7cfb\u7edf VM)\u4e4b\u95f4\u7684\u901a\u4fe1\u3002\u8bf7\u5728\u6b64\u5904\u914d\u7f6e\u5b58\u50a8\u901a\u4fe1\u3002 +message.storage.traffic=CloudStack \u5185\u90e8\u8d44\u6e90(\u5305\u62ec\u4e0e\u7ba1\u7406\u670d\u52a1\u5668\u901a\u4fe1\u7684\u4efb\u4f55\u7ec4\u4ef6\uff0c\u4f8b\u5982\u4e3b\u673a\u548c CloudStack \u7cfb\u7edf VM)\u4e4b\u95f4\u7684\u6d41\u91cf\u3002\u8bf7\u5728\u6b64\u5904\u914d\u7f6e\u5b58\u50a8\u6d41\u91cf\u3002 message.suspend.project=\u662f\u5426\u786e\u5b9e\u8981\u6682\u505c\u6b64\u9879\u76ee? message.template.desc=\u64cd\u4f5c\u7cfb\u7edf\u6620\u50cf\uff0c\u53ef\u7528\u4e8e\u542f\u52a8 VM -message.tooltip.dns.1=\u4f9b\u533a\u57df\u4e2d\u7684 VM \u4f7f\u7528\u7684 DNS \u670d\u52a1\u5668\u540d\u79f0\u3002\u533a\u57df\u7684\u516c\u7528 IP \u5730\u5740\u5fc5\u987b\u8def\u7531\u5230\u6b64\u670d\u52a1\u5668\u3002 -message.tooltip.dns.2=\u4f9b\u533a\u57df\u4e2d\u7684 VM \u4f7f\u7528\u7684\u8f85\u52a9 DNS \u670d\u52a1\u5668\u540d\u79f0\u3002\u533a\u57df\u7684\u516c\u7528 IP \u5730\u5740\u5fc5\u987b\u8def\u7531\u5230\u6b64\u670d\u52a1\u5668\u3002 -message.tooltip.internal.dns.1=\u4f9b\u533a\u57df\u4e2d\u7684 CloudStack \u5185\u90e8\u7cfb\u7edf VM \u4f7f\u7528\u7684 DNS \u670d\u52a1\u5668\u540d\u79f0\u3002\u63d0\u4f9b\u70b9\u7684\u4e13\u7528 IP \u5730\u5740\u5fc5\u987b\u8def\u7531\u5230\u6b64\u670d\u52a1\u5668\u3002 -message.tooltip.internal.dns.2=\u4f9b\u533a\u57df\u4e2d\u7684 CloudStack \u5185\u90e8\u7cfb\u7edf VM \u4f7f\u7528\u7684 DNS \u670d\u52a1\u5668\u540d\u79f0\u3002\u63d0\u4f9b\u70b9\u7684\u4e13\u7528 IP \u5730\u5740\u5fc5\u987b\u8def\u7531\u5230\u6b64\u670d\u52a1\u5668\u3002 +message.tooltip.dns.1=\u4f9b\u8d44\u6e90\u57df\u4e2d\u7684 VM \u4f7f\u7528\u7684 DNS \u670d\u52a1\u5668\u540d\u79f0\u3002\u8d44\u6e90\u57df\u7684\u516c\u7528 IP \u5730\u5740\u5fc5\u987b\u8def\u7531\u5230\u6b64\u670d\u52a1\u5668\u3002 +message.tooltip.dns.2=\u4f9b\u8d44\u6e90\u57df\u4e2d\u7684 VM \u4f7f\u7528\u7684\u4e8c\u7ea7 DNS \u670d\u52a1\u5668\u540d\u79f0\u3002\u8d44\u6e90\u57df\u7684\u516c\u7528 IP \u5730\u5740\u5fc5\u987b\u8def\u7531\u5230\u6b64\u670d\u52a1\u5668\u3002 +message.tooltip.internal.dns.1=\u4f9b\u8d44\u6e90\u57df\u4e2d\u7684 CloudStack \u5185\u90e8\u7cfb\u7edf VM \u4f7f\u7528\u7684 DNS \u670d\u52a1\u5668\u540d\u79f0\u3002\u63d0\u4f9b\u70b9\u7684\u4e13\u7528 IP \u5730\u5740\u5fc5\u987b\u8def\u7531\u5230\u6b64\u670d\u52a1\u5668\u3002 +message.tooltip.internal.dns.2=\u4f9b\u8d44\u6e90\u57df\u4e2d\u7684 CloudStack \u5185\u90e8\u7cfb\u7edf VM \u4f7f\u7528\u7684 DNS \u670d\u52a1\u5668\u540d\u79f0\u3002\u63d0\u4f9b\u70b9\u7684\u4e13\u7528 IP \u5730\u5740\u5fc5\u987b\u8def\u7531\u5230\u6b64\u670d\u52a1\u5668\u3002 message.tooltip.network.domain=DNS \u540e\u7f00\uff0c\u5c06\u4e3a\u7531\u6765\u5bbe VM \u8bbf\u95ee\u7684\u7f51\u7edc\u521b\u5efa\u4e00\u4e2a\u81ea\u5b9a\u4e49\u57df\u540d\u3002 message.tooltip.pod.name=\u6b64\u63d0\u4f9b\u70b9\u7684\u540d\u79f0\u3002 message.tooltip.reserved.system.gateway=\u63d0\u4f9b\u70b9\u4e2d\u7684\u4e3b\u673a\u7f51\u5173\u3002 message.tooltip.reserved.system.netmask=\u7528\u4e8e\u5b9a\u4e49\u63d0\u4f9b\u70b9\u5b50\u7f51\u7684\u7f51\u7edc\u524d\u7f00\u3002\u8bf7\u4f7f\u7528 CIDR \u7b26\u53f7\u3002 -message.tooltip.zone.name=\u533a\u57df\u540d\u79f0\u3002 +message.tooltip.zone.name=\u8d44\u6e90\u57df\u540d\u79f0\u3002 message.update.os.preference=\u8bf7\u4e3a\u6b64\u4e3b\u673a\u9009\u62e9\u4e00\u4e2a\u64cd\u4f5c\u7cfb\u7edf\u9996\u9009\u9879\u3002\u9996\u5148\u5c06\u5177\u6709\u76f8\u4f3c\u9996\u9009\u9879\u7684\u6240\u6709\u865a\u62df\u5b9e\u4f8b\u5206\u914d\u81f3\u6b64\u4e3b\u673a\uff0c\u7136\u540e\u518d\u9009\u62e9\u5176\u4ed6\u5b9e\u4f8b\u3002 message.update.resource.count=\u8bf7\u786e\u8ba4\u60a8\u786e\u5b9e\u8981\u66f4\u65b0\u6b64\u5e10\u6237\u7684\u8d44\u6e90\u6570\u3002 message.update.ssl=\u8bf7\u63d0\u4ea4\u4e00\u4e2a\u65b0\u7684 X.509 \u517c\u5bb9\u7684 SSL \u8bc1\u4e66\uff0c\u4ee5\u4fbf\u5c06\u5176\u66f4\u65b0\u5230\u6bcf\u4e2a\u63a7\u5236\u53f0\u4ee3\u7406\u865a\u62df\u5b9e\u4f8b\: @@ -1623,32 +1786,32 @@ message.vm.create.template.confirm=\u521b\u5efa\u6a21\u677f\u5c06\u81ea\u52a8\u9 message.vm.review.launch=\u8bf7\u5148\u6838\u5bf9\u4ee5\u4e0b\u4fe1\u606f\uff0c\u786e\u8ba4\u60a8\u7684\u865a\u62df\u5b9e\u4f8b\u6b63\u786e\u65e0\u8bef\uff0c\u7136\u540e\u518d\u542f\u52a8\u3002 message.volume.create.template.confirm=\u8bf7\u786e\u8ba4\u60a8\u786e\u5b9e\u8981\u4e3a\u6b64\u78c1\u76d8\u5377\u521b\u5efa\u4e00\u4e2a\u6a21\u677f\u3002\u521b\u5efa\u6a21\u677f\u53ef\u80fd\u9700\u8981\u51e0\u5206\u949f\u5230\u66f4\u957f\u7684\u65f6\u95f4\uff0c\u5177\u4f53\u53d6\u51b3\u4e8e\u5377\u7684\u5927\u5c0f\u3002 message.you.must.have.at.least.one.physical.network=\u60a8\u5fc5\u987b\u81f3\u5c11\u62e5\u6709\u4e00\u4e2a\u7269\u7406\u7f51\u7edc -message.zone.creation.complete.would.you.like.to.enable.this.zone=\u5df2\u5b8c\u6210\u521b\u5efa\u533a\u57df\u3002\u662f\u5426\u8981\u542f\u7528\u6b64\u533a\u57df? -message.Zone.creation.complete=\u5df2\u5b8c\u6210\u521b\u5efa\u533a\u57df -message.zone.no.network.selection=\u6240\u9009\u533a\u57df\u65e0\u4efb\u4f55\u7f51\u7edc\u9009\u9879\u3002 -message.zone.step.1.desc=\u8bf7\u4e3a\u60a8\u7684\u533a\u57df\u9009\u62e9\u4e00\u79cd\u7f51\u7edc\u6a21\u5f0f\u3002 -message.zone.step.2.desc=\u8bf7\u8f93\u5165\u4ee5\u4e0b\u4fe1\u606f\u4ee5\u6dfb\u52a0\u4e00\u4e2a\u65b0\u533a\u57df +message.zone.creation.complete.would.you.like.to.enable.this.zone=\u5df2\u5b8c\u6210\u521b\u5efa\u8d44\u6e90\u57df\u3002\u662f\u5426\u8981\u542f\u7528\u6b64\u8d44\u6e90\u57df? +message.Zone.creation.complete=\u5df2\u5b8c\u6210\u521b\u5efa\u8d44\u6e90\u57df +message.zone.no.network.selection=\u6240\u9009\u8d44\u6e90\u57df\u65e0\u4efb\u4f55\u7f51\u7edc\u9009\u9879\u3002 +message.zone.step.1.desc=\u8bf7\u4e3a\u60a8\u7684\u8d44\u6e90\u57df\u9009\u62e9\u4e00\u79cd\u7f51\u7edc\u6a21\u5f0f\u3002 +message.zone.step.2.desc=\u8bf7\u8f93\u5165\u4ee5\u4e0b\u4fe1\u606f\u4ee5\u6dfb\u52a0\u4e00\u4e2a\u65b0\u8d44\u6e90\u57df message.zone.step.3.desc=\u8bf7\u8f93\u5165\u4ee5\u4e0b\u4fe1\u606f\u4ee5\u6dfb\u52a0\u4e00\u4e2a\u65b0\u63d0\u4f9b\u70b9 -message.zoneWizard.enable.local.storage=\u8b66\u544a\: \u5982\u679c\u4e3a\u6b64\u533a\u57df\u542f\u7528\u4e86\u672c\u5730\u5b58\u50a8\uff0c\u5219\u5fc5\u987b\u6267\u884c\u4ee5\u4e0b\u64cd\u4f5c\uff0c\u5177\u4f53\u53d6\u51b3\u4e8e\u60a8\u5e0c\u671b\u542f\u52a8\u7cfb\u7edf VM \u7684\u4f4d\u7f6e\:

1. \u5982\u679c\u9700\u8981\u5728\u4e3b\u5b58\u50a8\u4e2d\u542f\u52a8\u7cfb\u7edf VM\uff0c\u5219\u5fc5\u987b\u5728\u5b8c\u6210\u521b\u5efa\u540e\u5c06\u4e3b\u5b58\u50a8\u6dfb\u52a0\u5230\u6b64\u533a\u57df\u4e2d\u3002

2. \u5982\u679c\u9700\u8981\u5728\u672c\u5730\u5b58\u50a8\u4e2d\u542f\u52a8\u7cfb\u7edf VM\uff0c\u5219\u5fc5\u987b\u5c06 system.vm.use.local.storage \u8bbe\u7f6e\u4e3a true\u3002


\u662f\u5426\u8981\u7ee7\u7eed? +message.zoneWizard.enable.local.storage=\u8b66\u544a\: \u5982\u679c\u4e3a\u6b64\u8d44\u6e90\u57df\u542f\u7528\u4e86\u672c\u5730\u5b58\u50a8\uff0c\u5219\u5fc5\u987b\u6267\u884c\u4ee5\u4e0b\u64cd\u4f5c\uff0c\u5177\u4f53\u53d6\u51b3\u4e8e\u60a8\u5e0c\u671b\u542f\u52a8\u7cfb\u7edf VM \u7684\u4f4d\u7f6e\:

1. \u5982\u679c\u9700\u8981\u5728\u4e3b\u5b58\u50a8\u4e2d\u542f\u52a8\u7cfb\u7edf VM\uff0c\u5219\u5fc5\u987b\u5728\u5b8c\u6210\u521b\u5efa\u540e\u5c06\u4e3b\u5b58\u50a8\u6dfb\u52a0\u5230\u6b64\u8d44\u6e90\u57df\u4e2d\u3002

2. \u5982\u679c\u9700\u8981\u5728\u672c\u5730\u5b58\u50a8\u4e2d\u542f\u52a8\u7cfb\u7edf VM\uff0c\u5219\u5fc5\u987b\u5c06 system.vm.use.local.storage \u8bbe\u7f6e\u4e3a true\u3002


\u662f\u5426\u8981\u7ee7\u7eed? message.validate.fieldrequired=\u6b64\u5b57\u6bb5\u4e3a\u5fc5\u586b\u5b57\u6bb5\u3002 message.validate.fixfield=\u8bf7\u4fee\u590d\u6b64\u5b57\u6bb5\u3002 -message.validate.email.address=Please enter a valid email address. -message.validate.URL=Please enter a valid URL. -message.validate.date=Please enter a valid date. -message.validate.date.ISO=Please enter a valid date (ISO). -message.validate.number=Please enter a valid number. -message.validate.digits=Please enter only digits. -message.validate.creditcard=Please enter a valid credit card number. -message.validate.equalto=Please enter the same value again. -message.validate.accept=Please enter a value with a valid extension. -message.validate.maxlength=Please enter no more than {0} characters. -message.validate.minlength=Please enter at least {0} characters. -message.validate.range.length=Please enter a value between {0} and {1} characters long. -message.validate.range=Please enter a value between {0} and {1}. -message.validate.max=Please enter a value less than or equal to {0}. -messgae.validate.min=Please enter a value greater than or equal to {0}. +message.validate.email.address=\u8bf7\u8f93\u5165\u4e00\u4e2a\u6709\u6548\u7684\u7535\u5b50\u90ae\u4ef6\u5730\u5740\u3002 +message.validate.URL=\u8bf7\u8f93\u5165\u6709\u6548\u7684 URL\u3002 +message.validate.date=\u8bf7\u8f93\u5165\u6709\u6548\u7684\u65e5\u671f\u3002 +message.validate.date.ISO=\u8bf7\u8f93\u5165\u6709\u6548\u7684\u65e5\u671f(ISO)\u3002 +message.validate.number=\u8bf7\u8f93\u5165\u4e00\u4e2a\u6709\u6548\u6570\u5b57\u3002 +message.validate.digits=\u8bf7\u4ec5\u8f93\u5165\u6570\u5b57\u3002 +message.validate.creditcard=\u8bf7\u8f93\u5165\u4e00\u4e2a\u6709\u6548\u7684\u4fe1\u7528\u5361\u5361\u53f7\u3002 +message.validate.equalto=\u8bf7\u91cd\u65b0\u8f93\u5165\u76f8\u540c\u7684\u503c\u3002 +message.validate.accept=\u8bf7\u8f93\u5165\u4e00\u4e2a\u5e26\u6709\u6709\u6548\u6269\u5c55\u540d\u7684\u503c\u3002 +message.validate.maxlength=\u8bf7\u6700\u591a\u8f93\u5165 {0} \u4e2a\u5b57\u7b26\u3002 +message.validate.minlength=\u8bf7\u81f3\u5c11\u8f93\u5165 {0} \u4e2a\u5b57\u7b26\u3002 +message.validate.range.length=\u8bf7\u8f93\u5165\u4e00\u4e2a\u957f\u5ea6\u4ecb\u4e8e {0} \u5230 {1} \u4e4b\u95f4\u7684\u503c\u3002 +message.validate.range=\u8bf7\u8f93\u5165\u4e00\u4e2a\u4ecb\u4e8e {0} \u5230 {1} \u4e4b\u95f4\u7684\u503c\u3002 +message.validate.max=\u8bf7\u8f93\u5165\u4e00\u4e2a\u5c0f\u4e8e\u6216\u7b49\u4e8e {0} \u7684\u503c\u3002 +messgae.validate.min=\u8bf7\u8f93\u5165\u4e00\u4e2a\u5927\u4e8e\u6216\u7b49\u4e8e {0} \u7684\u503c\u3002 message.creating.systemVM=\u6b63\u5728\u521b\u5efa\u7cfb\u7edf VM (\u6b64\u64cd\u4f5c\u53ef\u80fd\u9700\u8981\u4e00\u4e9b\u65f6\u95f4) -message.enabling.zone.dots=\u6b63\u5728\u542f\u7528\u533a\u57df... +message.enabling.zone.dots=\u6b63\u5728\u542f\u7528\u8d44\u6e90\u57df... message.restoreVM=\u662f\u5426\u8981\u8fd8\u539f\u6b64 VM? message.no.host.available=\u6ca1\u6709\u53ef\u7528\u4e8e\u8fc1\u79fb\u7684\u4e3b\u673a message.network.addVM.desc=\u8bf7\u6307\u5b9a\u8981\u5c06\u6b64 VM \u6dfb\u52a0\u5230\u7684\u7f51\u7edc\u3002\u5c06\u4e3a\u6b64\u7f51\u7edc\u6dfb\u52a0\u4e00\u4e2a\u65b0 NIC\u3002 @@ -1667,6 +1830,53 @@ message.tier.required=\u201c\u5c42\u201d\u4e3a\u5fc5\u586b\u9879 message.remove.ldap=\u662f\u5426\u786e\u5b9e\u8981\u5220\u9664 LDAP \u914d\u7f6e? message.action.downloading.template=\u6b63\u5728\u4e0b\u8f7d\u6a21\u677f\u3002 message.configure.ldap=\u8bf7\u786e\u8ba4\u60a8\u786e\u5b9e\u8981\u914d\u7f6e LDAP\u3002 +message.confirm.delete.ciscovnmc.resource=\u8bf7\u786e\u8ba4\u60a8\u786e\u5b9e\u8981\u5220\u9664 CiscoVNMC \u8d44\u6e90 +message.confirm.add.vnmc.provider=\u8bf7\u786e\u8ba4\u60a8\u786e\u5b9e\u8981\u6dfb\u52a0 VNMC \u63d0\u4f9b\u7a0b\u5e8f\u3002 +message.confirm.enable.vnmc.provider=\u8bf7\u786e\u8ba4\u60a8\u786e\u5b9e\u8981\u542f\u7528 VNMC \u63d0\u4f9b\u7a0b\u5e8f\u3002 +message.confirm.disable.vnmc.provider=\u8bf7\u786e\u8ba4\u60a8\u786e\u5b9e\u8981\u7981\u7528 VNMC \u63d0\u4f9b\u7a0b\u5e8f\u3002 +message.vnmc.available.list=\u63d0\u4f9b\u7a0b\u5e8f\u5217\u8868\u4e2d\u672a\u63d0\u4f9b VNMC\u3002 +message.vnmc.not.available.list=\u63d0\u4f9b\u7a0b\u5e8f\u5217\u8868\u4e2d\u672a\u63d0\u4f9b VNMC\u3002 +message.confirm.release.dedicate.vlan.range=\u8bf7\u786e\u8ba4\u60a8\u786e\u5b9e\u8981\u91ca\u653e\u4e13\u7528 VLAN \u8303\u56f4 +message.confirm.start.lb.vm=\u8bf7\u786e\u8ba4\u60a8\u786e\u5b9e\u8981\u542f\u52a8 LB VM +message.confirm.stop.lb.vm=\u8bf7\u786e\u8ba4\u60a8\u786e\u5b9e\u8981\u505c\u6b62 LB VM +message.confirm.remove.vmware.datacenter=\u8bf7\u786e\u8ba4\u60a8\u786e\u5b9e\u8981\u5220\u9664 VMware \u6570\u636e\u4e2d\u5fc3 +message.confirm.dedicate.zone=\u662f\u5426\u8981\u5c06\u6b64\u8d44\u6e90\u57df\u4e13\u7528\u4e8e\u57df/\u5e10\u6237? +message.confirm.release.dedicated.zone=\u662f\u5426\u8981\u91ca\u653e\u6b64\u4e13\u7528\u8d44\u6e90\u57df? +message.dedicated.zone.released=\u5df2\u91ca\u653e\u4e13\u7528\u8d44\u6e90\u57df +message.read.admin.guide.scaling.up=\u5f00\u59cb\u6269\u5c55\u4e4b\u524d\uff0c\u8bf7\u9605\u8bfb\u7ba1\u7406\u6307\u5357\u4e2d\u7684\u52a8\u6001\u6269\u5c55\u90e8\u5206\u3002 +message.confirm.scale.up.system.vm=\u662f\u5426\u786e\u5b9e\u8981\u6269\u5c55\u7cfb\u7edf VM? +message.confirm.upgrade.router.newer.template=\u8bf7\u786e\u8ba4\u60a8\u786e\u5b9e\u8981\u5347\u7ea7\u8def\u7531\u5668\u4ee5\u4f7f\u7528\u66f4\u65b0\u7684\u6a21\u677f +message.confirm.scale.up.router.vm=\u662f\u5426\u786e\u5b9e\u8981\u6269\u5c55\u8def\u7531\u5668 VM? +message.confirm.upgrade.routers.newtemplate=\u8bf7\u786e\u8ba4\u60a8\u786e\u5b9e\u8981\u5347\u7ea7\u6b64\u8d44\u6e90\u57df\u4e2d\u7684\u6240\u6709\u8def\u7531\u5668\u4ee5\u4f7f\u7528\u66f4\u65b0\u7684\u6a21\u677f +message.confirm.upgrade.routers.pod.newtemplate=\u8bf7\u786e\u8ba4\u60a8\u786e\u5b9e\u8981\u5347\u7ea7\u6b64\u63d0\u4f9b\u70b9\u4e2d\u7684\u6240\u6709\u8def\u7531\u5668\u4ee5\u4f7f\u7528\u66f4\u65b0\u7684\u6a21\u677f +message.confirm.upgrade.routers.cluster.newtemplate=\u8bf7\u786e\u8ba4\u60a8\u786e\u5b9e\u8981\u5347\u7ea7\u6b64\u7fa4\u96c6\u4e2d\u7684\u6240\u6709\u8def\u7531\u5668\u4ee5\u4f7f\u7528\u66f4\u65b0\u7684\u6a21\u677f +message.confirm.upgrade.routers.account.newtemplate=\u8bf7\u786e\u8ba4\u60a8\u786e\u5b9e\u8981\u5347\u7ea7\u6b64\u5e10\u6237\u4e2d\u7684\u6240\u6709\u8def\u7531\u5668\u4ee5\u4f7f\u7528\u66f4\u65b0\u7684\u6a21\u677f +message.confirm.dedicate.pod.domain.account=\u662f\u5426\u786e\u5b9e\u8981\u5c06\u6b64\u63d0\u4f9b\u70b9\u4e13\u7528\u4e8e\u57df/\u5e10\u6237? +message.confirm.release.dedicated.pod=\u662f\u5426\u8981\u91ca\u653e\u6b64\u4e13\u7528\u63d0\u4f9b\u70b9? +message.pod.dedication.released=\u5df2\u91ca\u653e\u4e13\u7528\u63d0\u4f9b\u70b9 +message.confirm.dedicate.cluster.domain.account=\u662f\u5426\u786e\u5b9e\u8981\u5c06\u6b64\u7fa4\u96c6\u4e13\u7528\u4e8e\u57df/\u5e10\u6237? +message.cluster.dedicated=\u7fa4\u96c6\u5df2\u4e13\u7528 +message.confirm.release.dedicated.cluster=\u662f\u5426\u8981\u91ca\u653e\u6b64\u4e13\u7528\u7fa4\u96c6? +message.cluster.dedication.released=\u5df2\u91ca\u653e\u4e13\u7528\u7fa4\u96c6 +message.confirm.dedicate.host.domain.account=\u662f\u5426\u786e\u5b9e\u8981\u5c06\u6b64\u4e3b\u673a\u4e13\u7528\u4e8e\u57df/\u5e10\u6237? +message.host.dedicated=\u4e3b\u673a\u5df2\u4e13\u7528 +message.confirm.release.dedicated.host=\u662f\u5426\u8981\u91ca\u653e\u6b64\u4e13\u7528\u4e3b\u673a? +message.host.dedication.released=\u5df2\u91ca\u653e\u4e13\u7528\u4e3b\u673a +message.confirm.delete.ucs.manager=\u8bf7\u786e\u8ba4\u60a8\u786e\u5b9e\u8981\u5220\u9664 UCS Manager +message.confirm.refresh.blades=\u8bf7\u786e\u8ba4\u60a8\u786e\u5b9e\u8981\u5237\u65b0\u5200\u7247\u5f0f\u670d\u52a1\u5668\u3002 +message.confirm.delete.secondary.staging.store=\u8bf7\u786e\u8ba4\u60a8\u786e\u5b9e\u8981\u5220\u9664\u4e8c\u7ea7\u6682\u5b58\u5b58\u50a8\u3002 +message.select.tier=\u8bf7\u9009\u62e9\u4e00\u4e2a\u5c42 +message.disallowed.characters=\u7981\u7528\u5b57\u7b26: \<\,\> +message.waiting.for.builtin.templates.to.load=\u6b63\u5728\u7b49\u5f85\u52a0\u8f7d\u5185\u7f6e\u6a21\u677f... +message.systems.vms.ready=\u7cfb\u7edf VM \u5df2\u5c31\u7eea\u3002 +message.your.cloudstack.is.ready=\u60a8\u7684 CloudStack \u5df2\u5c31\u7eea\! +message.specifiy.tag.key.value=\u8bf7\u6307\u5b9a\u6807\u8bb0\u5bc6\u94a5\u548c\u503c +message.enter.seperated.list.multiple.cidrs=\u5982\u679c\u5b58\u5728\u591a\u4e2a CIDR\uff0c\u8bf7\u8f93\u5165\u7528\u9017\u53f7\u5206\u9694\u7684 CIDR \u5217\u8868 +message.disabling.network.offering=\u6b63\u5728\u7981\u7528\u7f51\u7edc\u65b9\u6848 +message.confirm.enable.network.offering=\u662f\u5426\u786e\u5b9e\u8981\u542f\u7528\u6b64\u7f51\u7edc\u65b9\u6848? +message.enabling.network.offering=\u6b63\u5728\u542f\u7528\u7f51\u7edc\u65b9\u6848 +message.confirm.remove.network.offering=\u662f\u5426\u786e\u5b9e\u8981\u5220\u9664\u6b64\u7f51\u7edc\u65b9\u6848? +message.confirm.disable.network.offering=\u662f\u5426\u786e\u5b9e\u8981\u7981\u7528\u6b64\u7f51\u7edc\u65b9\u6848? mode=\u6a21\u5f0f network.rate=\u7f51\u7edc\u901f\u7387 notification.reboot.instance=\u91cd\u65b0\u542f\u52a8\u5b9e\u4f8b diff --git a/tools/ngui/static/js/app/accounts/accounts.js b/tools/ngui/static/js/app/accounts/accounts.js index eae5070a604..61d825b3b99 100644 --- a/tools/ngui/static/js/app/accounts/accounts.js +++ b/tools/ngui/static/js/app/accounts/accounts.js @@ -43,32 +43,32 @@ angular.module('accounts').controller('AccountsListCtrl', ['$scope', 'accounts', { model: 'username', type: 'input-text', - label: 'username' + label: 'label.username.lower' }, { model: 'password', type: 'input-password', - label: 'password' + label: 'label.password.lower' }, { model: 'email', type: 'input-text', - label: 'email' + label: 'label.email.lower' }, { model: 'firstname', type: 'input-text', - label: 'firstname' + label: 'label.firstname.lower' }, { model: 'lastname', type: 'input-text', - label: 'lastname' + label: 'label.lastname.lower' }, { model: 'domainid', type: 'select', - label: 'domain', + label: 'label.domain.lower', options: Domains.fetch, getName: function(model){ return model.name; @@ -80,12 +80,12 @@ angular.module('accounts').controller('AccountsListCtrl', ['$scope', 'accounts', { model: 'account', type: 'input-text', - label: 'account' + label: 'label.account.lower' }, { model: 'accounttype', type: 'select', - label: 'type', + label: 'label.type.lower', options: function(){ return ['User', 'Admin'] }, diff --git a/tools/ngui/static/js/app/storage/storage.js b/tools/ngui/static/js/app/storage/storage.js index e562a958f1a..af36167e93c 100644 --- a/tools/ngui/static/js/app/storage/storage.js +++ b/tools/ngui/static/js/app/storage/storage.js @@ -47,7 +47,7 @@ angular.module("storage").controller("VolumesListCtrl", ["$scope", "$location", $scope.toDisplay = ['name', 'type', 'hypervisor', 'vmdisplayname']; $scope.addVolumeForm = { - title: 'Add Volume', + title: 'label.add.volume', onSubmit: Volumes.getAll, fields: [ { diff --git a/ui/dictionary.jsp b/ui/dictionary.jsp index 11dbeb5179c..074db7f061b 100644 --- a/ui/dictionary.jsp +++ b/ui/dictionary.jsp @@ -43,7 +43,6 @@ dictionary = { 'label.hypervisors': '', 'label.home': '', 'label.sockets': '', -'label.add.ucs.manager': '', 'label.root.disk.size': '', 'label.s3.nfs.path': '', 'label.s3.nfs.server': '', @@ -704,9 +703,6 @@ dictionary = { 'label.keyboard.type': '', 'label.key': '', 'label.kvm.traffic.label': '', -'label.ovm.traffic.label': '', -'label.lxc.traffic.label': '', -'label.hyperv.traffic.label': '', 'label.lang.chinese': '', 'label.lang.english': '', 'label.lang.japanese': '', @@ -933,7 +929,6 @@ dictionary = { 'label.projects': '', 'label.project.view': '', 'label.protocol': '', -'label.provider': '', 'label.providers': '', 'label.provider': '', 'label.public': '', @@ -1023,7 +1018,6 @@ dictionary = { 'label.security.group': '', 'label.security.group.name': '', 'label.security.groups.enabled': '', -'label.security.groups': '', 'label.select.a.template': '', 'label.select.a.zone': '', 'label.select': '', @@ -1184,7 +1178,6 @@ dictionary = { 'label.virtual.network': '', 'label.virtual.router': '', 'label.virtual.routers': '', -'label.vlan': '', 'label.vlan.id': '', 'label.vlan.range': '', 'label.vxlan': '', @@ -1247,7 +1240,6 @@ dictionary = { 'label.ldap.group.name': '', 'label.password.reset.confirm': '', 'label.openDaylight': '', -'label.change.affinity': '', 'label.assign.instance.another': '', 'label.network.addVM': '', 'label.set.default.NIC': '', @@ -1260,9 +1252,7 @@ dictionary = { 'label.ipv6.gateway': '', 'label.ipv6.CIDR': '', 'label.VPC.limits': '', -'label.gslb.domain.name': '', 'label.edit.region': '', -'label.gslb.domain.name': '', 'label.add.gslb': '', 'label.gslb.servicetype': '', 'label.gslb.details': '', @@ -1653,6 +1643,214 @@ dictionary = { 'state.Stopping': '', 'state.Suspended': '', 'ui.listView.filters.all': '', -'ui.listView.filters.mine': '' +'ui.listView.filters.mine': '', +'label.security.groups': '', +'label.opendaylight.controller': '', +'label.resource.name': '', +'label.reource.id': '', +'label.vnmc.devices': '', +'label.add.vnmc.provider': '', +'label.enable.vnmc.provider': '', +'label.add.vnmc.device': '', +'label.ciscovnmc.resource.details': '', +'label.delete.ciscovnmc.resource': '', +'label.enable.vnmc.device': '', +'label.disbale.vnmc.device': '', +'label.disable.vnmc.provider': '', +'label.services': '', +'label.secondary.staging.store': '', +'label.release.account': '', +'label.release.account.lowercase': '', +'label.vlan.vni.ranges': '', +'label.dedicated.vlan.vni.ranges': '', +'label.dedicate.vlan.vni.range': '', +'label.vlan.vni.range': '', +'label.vlan.range.details': '', +'label.broadcat.uri': '', +'label.ipv4.cidr': '', +'label.guest.network.details': '', +'label.ipv4.gateway': '', +'label.vlan.ranges': '', +'label.virtual.appliance.details': '', +'label.start.lb.vm': '', +'label.stop.lb.vm': '', +'label.migrate.lb.vm': '', +'label.vpc.virtual.router': '', +'label.ovs': '', +'label.gslb.service': '', +'label.gslb.service.public.ip': '', +'label.gslb.service.private.ip': '', +'label.baremetal.dhcp.provider': '', +'label.add.baremetal.dhcp.device': '', +'label.baremetal.pxe.provider': '', +'label.baremetal.pxe.device': '', +'label.tftp.root.directory': '', +'label.add.vmware.datacenter': '', +'label.remove.vmware.datacenter': '', +'label.dc.name': '', +'label.vcenter': '', +'label.dedicate.zone': '', +'label.zone.dedicated': '', +'label.release.dedicated.zone': '', +'label.ipv6.dns1': '', +'label.ipv6.dns2': '', +'label.vmware.datacenter.name': '', +'label.vmware.datacenter.vcenter': '', +'label.vmware.datacenter.id': '', +'label.system.vm.details': '', +'label.system.vm.scaled.up': '', +'label.console.proxy.vm': '', +'label.settings': '', +'label.requires.upgrade': '', +'label.upgrade.router.newer.template': '', +'label.router.vm.scaled.up': '', +'label.total.virtual.routers': '', +'label.upgrade.required': '', +'label.virtual.routers.group.zone': '', +'label.total.virtual.routers.upgrade': '', +'label.virtual.routers.group.pod': '', +'label.virtual.routers.group.cluster': '', +'label.zone.lower': '', +'label.virtual.routers.group.account': '', +'label.netscaler.details': '', +'label.baremetal.dhcp.devices': '', +'label.baremetal.pxe.devices': '', +'label.addes.new.f5': '', +'label.f5.details': '', +'label.srx.details': '', +'label.palo.alto.details': '', +'label.added.nicira.nvp.controller': '', +'label.nicira.nvp.details': '', +'label.added.new.bigswitch.vns.controller': '', +'label.bigswitch.vns.details': '', +'label.dedicate': '', +'label.dedicate.pod': '', +'label.pod.dedicated': '', +'label.release.dedicated.pod': '', +'label.override.public.traffic': '', +'label.public.traffic.vswitch.type': '', +'label.public.traffic.vswitch.name': '', +'label.override.guest.traffic': '', +'label.guest.traffic.vswitch.type': '', +'label.guest.traffic.vswitch.name': '', +'label.cisco.nexus1000v.ip.address': '', +'label.cisco.nexus1000v.username': '', +'label.cisco.nexus1000v.password': '', +'label.dedicate.cluster': '', +'label.release.dedicated.cluster': '', +'label.dedicate.host': '', +'label.release.dedicated.host': '', +'label.number.of.cpu.sockets': '', +'label.delete.ucs.manager': '', +'label.blades': '', +'label.chassis': '', +'label.blade.id': '', +'label.associated.profile': '', +'label.refresh.blades': '', +'label.instanciate.template.associate.profile.blade': '', +'label.select.template': '', +'label.profile': '', +'label.delete.profile': '', +'label.disassociate.profile.blade': '', +'label.secondary.storage.details': '', +'label.secondary.staging.store.details': '', +'label.add.nfs.secondary.staging.store': '', +'label.delete.secondary.staging.store': '', +'label.ipv4.start.ip': '', +'label.ipv4.end.ip': '', +'label.ipv6.start.ip': '', +'label.ipv6.end.ip': '', +'label.vm.password': '', +'label.group.by.zone': '', +'label.group.by.pod': '', +'label.group.by.cluster': '', +'label.group.by.account': '', +'label.no.grouping': '', +'label.create.nfs.secondary.staging.storage': '', +'label.username.lower': '', +'label.password.lower': '', +'label.email.lower': '', +'label.firstname.lower': '', +'label.lastname.lower': '', +'label.domain.lower': '', +'label.account.lower': '', +'label.type.lower': '', +'label.rule.number': '', +'label.action': '', +'label.name.lower': '', +'label.ucs': '', +'label.change.affinity': '', +'label.persistent': '', +'label.broadcasturi': '', +'label.network.cidr': '', +'label.reserved.ip.range': '', +'label.autoscale': '', +'label.health.check': '', +'label.public.load.balancer.provider': '', +'label.add.isolated.network': '', +'label.vlan': '', +'label.secondary.isolated.vlan.id': '', +'label.ipv4.netmask': '', +'label.custom': '', +'label.disable.network.offering': '', +'label.enable.network.offering': '', +'label.remove.network.offering': '', +'label.system.offering.for.router': '', +'label.mode': '', +'label.associate.public.ip': '', +'label.acl': '', +'label.user.data': '', +'label.virtual.networking': '', +'label.allow': '', +'label.deny': '', +'label.default.egress.policy': '', +'label.xenserver.tools.version.61.plus': '', +'message.confirm.delete.ciscovnmc.resource': '', +'message.confirm.add.vnmc.provider': '', +'message.confirm.enable.vnmc.provider': '', +'message.confirm.disable.vnmc.provider': '', +'message.vnmc.available.list': '', +'message.vnmc.not.available.list': '', +'message.confirm.release.dedicate.vlan.range': '', +'message.confirm.start.lb.vm': '', +'message.confirm.stop.lb.vm': '', +'message.confirm.remove.vmware.datacenter': '', +'message.confirm.dedicate.zone': '', +'message.confirm.release.dedicated.zone': '', +'message.dedicated.zone.released': '', +'message.read.admin.guide.scaling.up': '', +'message.confirm.scale.up.system.vm': '', +'message.confirm.upgrade.router.newer.template': '', +'message.confirm.scale.up.router.vm': '', +'message.confirm.upgrade.routers.newtemplate': '', +'message.confirm.upgrade.routers.pod.newtemplate': '', +'message.confirm.upgrade.routers.cluster.newtemplate': '', +'message.confirm.upgrade.routers.account.newtemplate': '', +'message.confirm.dedicate.pod.domain.account': '', +'message.confirm.release.dedicated.pod': '', +'message.pod.dedication.released': '', +'message.confirm.dedicate.cluster.domain.account': '', +'message.cluster.dedicated': '', +'message.confirm.release.dedicated.cluster': '', +'message.cluster.dedication.released': '', +'message.confirm.dedicate.host.domain.account': '', +'message.host.dedicated': '', +'message.confirm.release.dedicated.host': '', +'message.host.dedication.released': '', +'message.confirm.delete.ucs.manager': '', +'message.confirm.refresh.blades': '', +'message.confirm.delete.secondary.staging.store': '', +'message.select.tier': '', +'message.disallowed.characters': '', +'message.waiting.for.builtin.templates.to.load': '', +'message.systems.vms.ready': '', +'message.your.cloudstack.is.ready': '', +'message.specifiy.tag.key.value': '', +'message.enter.seperated.list.multiple.cidrs': '', +'message.disabling.network.offering': '', +'message.confirm.enable.network.offering': '', +'message.enabling.network.offering': '', +'message.confirm.remove.network.offering': '', +'message.confirm.disable.network.offering': '', }; diff --git a/ui/modules/vnmcNetworkProvider/vnmcNetworkProvider.js b/ui/modules/vnmcNetworkProvider/vnmcNetworkProvider.js index d618b232d27..c9295a35e89 100644 --- a/ui/modules/vnmcNetworkProvider/vnmcNetworkProvider.js +++ b/ui/modules/vnmcNetworkProvider/vnmcNetworkProvider.js @@ -17,7 +17,7 @@ (function ($, cloudStack) { cloudStack.modules.vnmcNetworkProvider = function (module) { var vnmcDeviceViewAll = window._m = [{ - label: 'VNMC Devices', + label: 'label.vnmc.devices', path: '_zone.vnmcDevices' }]; @@ -25,10 +25,10 @@ id: 'vnmcDevices', fields: { resourcename: { - label: 'Resource Name' + label: 'label.resource.name' }, provider: { - label: 'Provider' + label: 'label.provider' } }, dataProvider: function (args) { @@ -47,16 +47,16 @@ }, actions: { add: { - label: 'Add VNMC device', + label: 'label.add.vnmc.device', messages: { notification: function (args) { - return 'Add VNMC device'; + return 'label.add.vnmc.device'; } }, createForm: { - title: 'Add VNMC device', + title: 'label.add.vnmc.device', fields: { hostname: { label: 'label.host', @@ -203,16 +203,16 @@ }, detailView: { - name: 'CiscoVNMC resource details', + name: 'label.ciscovnmc.resource.details', actions: { remove: { - label: 'delete CiscoVNMC resource', + label: 'label.delete.ciscovnmc.resource', messages: { confirm: function (args) { - return 'Please confirm you want to delete CiscoVNMC resource'; + return 'message.confirm.delete.ciscovnmc.resource'; }, notification: function (args) { - return 'delete CiscoVNMC resource'; + return 'label.delete.ciscovnmc.resource'; } }, action: function (args) { @@ -242,14 +242,14 @@ title: 'label.details', fields: [{ resourcename: { - label: 'Resource Name' + label: 'label.resource.name' } }, { resourceid: { - label: 'Resource ID' + label: 'label.reource.id' }, provider: { - label: 'Provider' + label: 'label.provider' } }], dataProvider: function (args) { @@ -277,14 +277,14 @@ viewAll: vnmcDeviceViewAll, actions: { add: { - label: 'Add VNMC provider', + label: 'label.add.vnmc.provider', messages: { confirm: function (args) { - return 'Please confirm you would like to add the VNMC provider.'; + return 'message.confirm.add.vnmc.provider'; }, notification: function (args) { - return 'Add VNMC device'; + return 'label.add.vnmc.device'; } }, @@ -327,14 +327,14 @@ } }, enable: { - label: 'Enable VNMC provider', + label: 'label.enable.vnmc.provider', messages: { confirm: function (args) { - return 'Please confirm you would like to enable the VNMC provider.'; + return 'message.confirm.enable.vnmc.provider'; }, notification: function (args) { - return 'Enable VNMC device'; + return 'label.enable.vnmc.device'; } }, @@ -352,7 +352,7 @@ enableCiscoVnmcProviderFn(ciscoVnmcProvider); } else { - args.response.error('VNMC is not available from provider list.'); + args.response.error('message.vnmc.available.list'); } } }); @@ -419,14 +419,14 @@ }, disable: { - label: 'Disable VNMC provider', + label: 'label.disable.vnmc.provider', messages: { confirm: function (args) { - return 'Please confirm you would like to disable the VNMC provider.'; + return 'message.confirm.disable.vnmc.provider'; }, notification: function (args) { - return 'Disable VNMC device'; + return 'label.disbale.vnmc.device'; } }, @@ -444,7 +444,7 @@ disableCiscoVnmcProviderFn(ciscoVnmcProvider); } else { - args.response.error('VNMC is not available from provider list.'); + args.response.error('message.vnmc.not.available.list'); } } }); @@ -525,7 +525,7 @@ label: 'label.id' }, servicelist: { - label: 'Services', + label: 'label.services', converter: function (args) { if (args) return args.join(', '); diff --git a/ui/scripts/configuration.js b/ui/scripts/configuration.js index cb54c318135..401262c73f2 100644 --- a/ui/scripts/configuration.js +++ b/ui/scripts/configuration.js @@ -96,7 +96,7 @@ } }, isCustomized: { - label: 'Custom', + label: 'label.custom', isBoolean: true, isReverse: true, isChecked: false @@ -2320,34 +2320,34 @@ // Sanitize names switch (serviceName) { case 'Vpn': - serviceDisplayName = 'VPN'; + serviceDisplayName = dictionary['label.vpn']; break; case 'Dhcp': serviceDisplayName = dictionary['label.dhcp']; break; case 'Dns': - serviceDisplayName = 'DNS'; + serviceDisplayName = dictionary['label.dns']; break; case 'Lb': - serviceDisplayName = 'Load Balancer'; + serviceDisplayName = dictionary['label.load.balancer']; break; case 'SourceNat': - serviceDisplayName = 'Source NAT'; + serviceDisplayName = dictionary['label.source.nat']; break; case 'StaticNat': - serviceDisplayName = 'Static NAT'; + serviceDisplayName = dictionary['label.static.nat']; break; case 'PortForwarding': - serviceDisplayName = 'Port Forwarding'; + serviceDisplayName = dictionary['label.port.forwarding']; break; case 'SecurityGroup': - serviceDisplayName = 'Security Groups'; + serviceDisplayName = dictionary['label.security.groups']; break; case 'UserData': - serviceDisplayName = 'User Data'; + serviceDisplayName = dictionary['label.user.data']; break; case 'Connectivity': - serviceDisplayName = 'Virtual Networking'; + serviceDisplayName = dictionary['label.virtual.networking']; break; default: serviceDisplayName = serviceName; @@ -2454,7 +2454,7 @@ //show or hide upon checked services and selected providers above (begin) serviceofferingid: { - label: 'System Offering for Router', + label: 'label.system.offering.for.router', isHidden: true, docID: 'helpNetworkOfferingSystemOffering', select: function(args) { @@ -2488,7 +2488,7 @@ }, "service.SourceNat.redundantRouterCapabilityCheckbox": { - label: "label.redundant.router.capability", + label: 'label.redundant.router.capability', isHidden: true, dependsOn: 'service.SourceNat.isEnabled', docID: 'helpNetworkOfferingRedundantRouterCapability', @@ -2534,7 +2534,7 @@ } }, "service.Lb.inlineModeDropdown": { - label: 'Mode', + label: 'label.mode', docID: 'helpNetworkOfferingMode', select: function(args) { var items = []; @@ -2559,7 +2559,7 @@ }, "service.StaticNat.associatePublicIP": { - label: 'Associate Public IP', + label: 'label.associate.public.ip', docID: 'helpNetworkOfferingAssociatePublicIP', isBoolean: true, isHidden: true @@ -2585,23 +2585,23 @@ args.response.success({ data: [{ id: 'Optional', - description: 'Optional' + description: 'label.optional' }, { id: 'Required', - description: 'Required' + description: 'label.required' }] }); } }, egresspolicy: { - label: 'Default egress policy', + label: 'label.default.egress.policy', isHidden: true, select: function(args) { args.response.success({ data: [ - { id: 'ALLOW', description: 'Allow' }, - { id: 'DENY', description: 'Deny' } + { id: 'ALLOW', description: 'label.allow' }, + { id: 'DENY', description: 'label.deny' } ] }); } @@ -2829,13 +2829,13 @@ }, enable: { - label: 'Enable network offering', + label: 'label.enable.network.offering', messages: { confirm: function(args) { - return 'Are you sure you want to enable this network offering?'; + return 'message.confirm.enable.network.offering'; }, notification: function(args) { - return 'Enabling network offering'; + return 'message.enabling.network.offering'; } }, action: function(args) { @@ -2864,13 +2864,13 @@ }, disable: { - label: 'Disable network offering', + label: 'label.disable.network.offering', messages: { confirm: function(args) { - return 'Are you sure you want to disable this network offering?'; + return 'message.confirm.disable.network.offering'; }, notification: function(args) { - return 'Disabling network offering'; + return 'message.disabling.network.offering'; } }, action: function(args) { @@ -2899,7 +2899,7 @@ }, remove: { - label: 'Remove network offering', + label: 'label.remove.network.offering', action: function(args) { $.ajax({ url: createURL('deleteNetworkOffering'), @@ -2919,10 +2919,10 @@ }, messages: { confirm: function() { - return 'Are you sure you want to remove this network offering?'; + return 'message.confirm.remove.network.offering'; }, notification: function() { - return 'Remove network offering'; + return 'label.remove.network.offering'; } }, notification: { @@ -2968,7 +2968,7 @@ }, ispersistent: { - label: 'Persistent ', + label: 'label.persistent ', converter: cloudStack.converters.toBooleanText }, diff --git a/ui/scripts/installWizard.js b/ui/scripts/installWizard.js index 25de4aaa0ad..85eaff00c3f 100644 --- a/ui/scripts/installWizard.js +++ b/ui/scripts/installWizard.js @@ -314,7 +314,7 @@ return vm.state == 'Running'; }).length) { clearInterval(poll); - message('System VMs ready.'); + message('message.systems.vms.ready'); setTimeout(pollBuiltinTemplates, 500); } } @@ -325,7 +325,7 @@ // Wait for builtin template to be present -- otherwise VMs cannot launch var pollBuiltinTemplates = function() { - message('Waiting for builtin templates to load...'); + message('message.waiting.for.builtin.templates.to.load'); var poll = setInterval(function() { $.ajax({ url: createURL('listTemplates'), @@ -341,7 +341,7 @@ if (builtinTemplates.length) { clearInterval(poll); - message('Your CloudStack is ready!'); + message('message.your.cloudstack.is.ready'); setTimeout(success, 1000); } } diff --git a/ui/scripts/instances.js b/ui/scripts/instances.js index 53c9e98af98..e5b2e85d34f 100644 --- a/ui/scripts/instances.js +++ b/ui/scripts/instances.js @@ -172,10 +172,10 @@ advSearchFields: { name: { - label: 'Name' + label: 'label.name' }, zoneid: { - label: 'Zone', + label: 'label.zone', select: function(args) { $.ajax({ url: createURL('listZones'), @@ -199,7 +199,7 @@ }, domainid: { - label: 'Domain', + label: 'label.domain', select: function(args) { if (isAdmin() || isDomainAdmin()) { $.ajax({ @@ -241,7 +241,7 @@ } }, account: { - label: 'Account', + label: 'label.account', isHidden: function(args) { if (isAdmin() || isDomainAdmin()) return false; @@ -251,10 +251,10 @@ }, tagKey: { - label: 'Tag Key' + label: 'label.tag.key' }, tagValue: { - label: 'Tag Value' + label: 'label.tag.value' } }, @@ -464,7 +464,7 @@ }, complete: function(args) { if (args.password != null) { - return 'Password of the VM is ' + args.password; + return 'label.vm.password' + ' ' + args.password; } return false; @@ -478,7 +478,7 @@ label: 'label.action.stop.instance', compactLabel: 'label.stop', createForm: { - title: 'Stop instance', + title: 'notification.stop.instance', desc: 'message.action.stop.instance', fields: { forced: { @@ -764,7 +764,7 @@ var networks = json.listnetworksresponse.network; var items = [{ id: -1, - description: 'Please select a tier' + description: 'message.select.tier' }]; $(networks).each(function() { items.push({ @@ -1434,7 +1434,7 @@ var description = ''; var vmObj = args.jsonObj; if (vmObj.state == 'Running' && vmObj.hypervisor == 'VMware') { - description = 'Please read the dynamic scaling section in the admin guide before scaling up.'; + description = 'message.read.admin.guide.scaling.up'; } return description; }, diff --git a/ui/scripts/network.js b/ui/scripts/network.js index 6ce66e8da22..f82a295aee7 100755 --- a/ui/scripts/network.js +++ b/ui/scripts/network.js @@ -410,7 +410,7 @@ listView: { actions: { add: { - label: 'Add Isolated Network', + label: 'label.add.isolated.network', preFilter: function(args) { if (advZoneObjs != null && advZoneObjs.length > 0) { @@ -766,13 +766,13 @@ label: 'label.cidr' }, ip6cidr: { - label: 'IPv6 CIDR' + label: 'label.ipv6.CIDR' } }, advSearchFields: { zoneid: { - label: 'Zone', + label: 'label.zone', select: function(args) { $.ajax({ url: createURL('listZones'), @@ -796,7 +796,7 @@ }, domainid: { - label: 'Domain', + label: 'label.domain', select: function(args) { if (isAdmin() || isDomainAdmin()) { $.ajax({ @@ -839,7 +839,7 @@ }, account: { - label: 'Account', + label: 'label.account', isHidden: function(args) { if (isAdmin() || isDomainAdmin()) return false; @@ -848,10 +848,10 @@ } }, tagKey: { - label: 'Tag Key' + label: 'label.tag.key' }, tagValue: { - label: 'Tag Value' + label: 'label.tag.value' } }, @@ -875,7 +875,7 @@ }, detailView: { - name: 'Guest network details', + name: 'label.guest.network.details', viewAll: { path: 'network.ipAddresses', label: 'label.menu.ipaddresses', @@ -1245,7 +1245,7 @@ }, ispersistent: { - label: 'Persistent ', + label: 'label.persistent', converter: cloudStack.converters.toBooleanText }, @@ -1263,7 +1263,7 @@ }, broadcasturi: { - label: 'broadcasturi' + label: 'label.broadcasturi' }, networkofferingid: { @@ -1323,20 +1323,20 @@ }, networkcidr: { - label: 'Network CIDR' + label: 'label.network.cidr' }, ip6gateway: { - label: 'IPv6 Gateway' + label: 'label.ipv6.gateway' }, ip6cidr: { - label: 'IPv6 CIDR' + label: 'label.ipv6.CIDR' }, reservediprange: { - label: 'Reserved IP Range' + label: 'label.reserved.ip.range' }, @@ -1688,7 +1688,7 @@ } }, 'autoScale': { - label: 'AutoScale', + label: 'label.autoscale', custom: { requireValidation: true, buttonLabel: 'label.configure', @@ -2785,7 +2785,7 @@ label: 'label.zone' }, vlanname: { - label: 'label.vlan' + label: 'label.vlan.only' } }], @@ -3479,7 +3479,7 @@ }, 'health-check': { - label: 'Health Check', + label: 'label.health.check', custom: { requireValidation: true, buttonLabel: 'Configure', @@ -3489,7 +3489,7 @@ }, 'autoScale': { - label: 'AutoScale', + label: 'label.autoscale', custom: { requireValidation: true, buttonLabel: 'label.configure', @@ -4475,10 +4475,10 @@ advSearchFields: { tagKey: { - label: 'Tag Key' + label: 'label.tag.key' }, tagValue: { - label: 'Tag Value' + label: 'label.tag.value' } }, @@ -5013,10 +5013,10 @@ advSearchFields: { name: { - label: 'Name' + label: 'label.name' }, zoneid: { - label: 'Zone', + label: 'label.zone', select: function(args) { $.ajax({ url: createURL('listZones'), @@ -5040,7 +5040,7 @@ }, domainid: { - label: 'Domain', + label: 'label.domain', select: function(args) { if (isAdmin() || isDomainAdmin()) { $.ajax({ @@ -5083,7 +5083,7 @@ }, account: { - label: 'Account', + label: 'label.account', isHidden: function(args) { if (isAdmin() || isDomainAdmin()) return false; @@ -5092,10 +5092,10 @@ } }, tagKey: { - label: 'Tag Key' + label: 'label.tag.key' }, tagValue: { - label: 'Tag Value' + label: 'label.tag.value' } }, @@ -5186,7 +5186,7 @@ label: 'label.DNS.domain.for.guest.networks' }, publicLoadBalancerProvider: { - label: 'Public Load Balancer Provider', + label: 'label.public.load.balancer.provider', select: function(args) { var items = []; items.push({ @@ -5429,7 +5429,7 @@ label: 'label.state' }, ispersistent: { - label: 'Persistent ', + label: 'label.persistent', converter: cloudStack.converters.toBooleanText }, @@ -5604,8 +5604,8 @@ } }, cidrlist: { - label: 'CIDR list', - desc: 'Please enter a comma separated list of CIDRs if more than one', + label: 'label.CIDR.list', + desc: 'message.enter.seperated.list.multiple.cidrs', validation: { required: true } @@ -5619,7 +5619,7 @@ }, cidrlist: { label: 'label.CIDR.list', - desc: 'Please enter a comma separated list of CIDRs if more than one', + desc: 'message.enter.seperated.list.multiple.cidrs', docID: 'helpVPNGatewayCIDRList', validation: { required: true diff --git a/ui/scripts/sharedFunctions.js b/ui/scripts/sharedFunctions.js index f0afea508cc..9c24f404890 100644 --- a/ui/scripts/sharedFunctions.js +++ b/ui/scripts/sharedFunctions.js @@ -297,7 +297,7 @@ var addGuestNetworkDialog = { docID: 'helpGuestNetworkZoneVLANID' }, isolatedpvlanId: { - label: 'Secondary Isolated VLAN ID' + label: 'label.secondary.isolated.vlan.id' }, scope: { @@ -319,24 +319,24 @@ var addGuestNetworkDialog = { if (selectedZoneObj.networktype == "Advanced" && selectedZoneObj.securitygroupsenabled == true) { array1.push({ id: 'zone-wide', - description: 'All' + description: 'ui.listView.filters.all' }); } else { array1.push({ id: 'zone-wide', - description: 'All' + description: 'ui.listView.filters.all' }); array1.push({ id: 'domain-specific', - description: 'Domain' + description: 'label.domain' }); array1.push({ id: 'account-specific', - description: 'Account' + description: 'label.account' }); array1.push({ id: 'project-specific', - description: 'Project' + description: 'label.project' }); } args.response.success({ @@ -584,37 +584,37 @@ var addGuestNetworkDialog = { //IPv4 (begin) ip4gateway: { - label: 'IPv4 Gateway', + label: 'label.ipv4.gateway', docID: 'helpGuestNetworkZoneGateway' }, ip4Netmask: { - label: 'IPv4 Netmask', + label: 'label.ipv4.netmask', docID: 'helpGuestNetworkZoneNetmask' }, startipv4: { - label: 'IPv4 Start IP', + label: 'label.ipv4.start.ip', docID: 'helpGuestNetworkZoneStartIP' }, endipv4: { - label: 'IPv4 End IP', + label: 'label.ipv4.end.ip', docID: 'helpGuestNetworkZoneEndIP' }, //IPv4 (end) //IPv6 (begin) ip6gateway: { - label: 'IPv6 Gateway', + label: 'label.ipv6.gateway', docID: 'helpGuestNetworkZoneGateway' }, ip6cidr: { - label: 'IPv6 CIDR' + label: 'label.ipv6.CIDR' }, startipv6: { - label: 'IPv6 Start IP', + label: 'label.ipv6.start.ip', docID: 'helpGuestNetworkZoneStartIP' }, endipv6: { - label: 'IPv6 End IP', + label: 'label.ipv6.end.ip', docID: 'helpGuestNetworkZoneEndIP' }, //IPv6 (end) diff --git a/ui/scripts/storage.js b/ui/scripts/storage.js index 1cd8d2e594e..e69a07e115c 100644 --- a/ui/scripts/storage.js +++ b/ui/scripts/storage.js @@ -1093,11 +1093,11 @@ isBoolean: true }, isFeatured: { - label: "label.featured", + label: 'label.featured', isBoolean: true }, isdynamicallyscalable: { - label: "Dynamically Scalable", + label: 'label.dynamically.scalable', isBoolean: true } } @@ -1688,7 +1688,7 @@ isBoolean: true }, isdynamicallyscalable: { - label: "Dynamically Scalable", + label: 'label.dynamically.scalable', isBoolean: true } } diff --git a/ui/scripts/system.js b/ui/scripts/system.js index c21e277cf8c..bfdc8d5b60f 100644 --- a/ui/scripts/system.js +++ b/ui/scripts/system.js @@ -44,11 +44,11 @@ }; var fields = { account: { - label: 'Account', + label: 'label.account', defaultValue: data.account }, domainid: { - label: 'Domain', + label: 'label.domain', defaultValue: data.domainid, select: function (args) { $.ajax({ @@ -753,7 +753,7 @@ }, releaseFromAccount: { - label: 'Release from Account', + label: 'label.release.account', action: function (args) { $.ajax({ url: createURL('releasePublicIpRange'), @@ -763,7 +763,7 @@ success: function (json) { args.response.success({ notification: { - label: 'release from account', + label: 'label.release.account.lowercase', poll: function (args) { args.complete(); } @@ -778,15 +778,15 @@ }, addAccount: { - label: 'Add Account', + label: 'label.add.account', createForm: { - title: 'Add Account', + title: 'label.add.account', fields: { account: { - label: 'Account' + label: 'label.account' }, domainid: { - label: 'Domain', + label: 'label.domain', select: function (args) { $.ajax({ url: createURL('listDomains'), @@ -821,7 +821,7 @@ success: function (json) { args.response.success({ notification: { - label: 'Add Account', + label: 'label.add.account', poll: function (args) { args.complete(); } @@ -902,15 +902,15 @@ isEditable: true }, ovmnetworklabel: { - label: 'OVM traffic label', + label: 'label.ovm.traffic.label', isEditable: true }, lxcnetworklabel: { - label: 'LXC Traffic Label', + label: 'label.lxc.traffic.label', isEditable: true }, hypervnetworklabel: { - label: 'HyperV Traffic Label', + label: 'label.hyperv.traffic.label', isEditable: true } }], @@ -1114,15 +1114,15 @@ isEditable: true }, ovmnetworklabel: { - label: 'OVM traffic label', + label: 'label.ovm.traffic.label', isEditable: true }, lxcnetworklabel: { - label: 'LXC Traffic Label', + label: 'label.lxc.traffic.label', isEditable: true }, hypervnetworklabel: { - label: 'HyperV Traffic Label', + label: 'label.hyperv.traffic.label', isEditable: true } }], @@ -1277,7 +1277,7 @@ label: 'label.state' }, vlan: { - label: 'VLAN/VNI Range(s)', + label: 'label.vlan.vni.ranges', isEditable: true }, tags: { @@ -1303,15 +1303,15 @@ isEditable: true }, ovmnetworklabel: { - label: 'OVM traffic label', + label: 'label.ovm.traffic.label', isEditable: true }, lxcnetworklabel: { - label: 'LXC Traffic Label', + label: 'label.lxc.traffic.label', isEditable: true }, hypervnetworklabel: { - label: 'HyperV Traffic Label', + label: 'label.hyperv.traffic.label', isEditable: true } }], @@ -1524,13 +1524,13 @@ label: 'label.vnet.id' }, broadcasturi: { - label: 'broadcast URI' + label: 'label.broadcat.uri' }, cidr: { - label: 'IPv4 CIDR' + label: 'label.ipv4.cidr' }, ip6cidr: { - label: 'IPv6 CIDR' + label: 'label.ipv6.cidr' } //scope: { label: 'label.scope' } }, @@ -1593,7 +1593,7 @@ }, detailView: { - name: 'Guest network details', + name: 'label.guest.network.details', noCompact: true, viewAll: { path: '_zone.guestIpRanges', @@ -1850,7 +1850,7 @@ label: 'label.vlan.id' }, broadcasturi: { - label: 'broadcast URI' + label: 'label.broadcat.uri' }, scope: { label: 'label.scope' @@ -1895,18 +1895,18 @@ }, gateway: { - label: 'IPv4 Gateway' + label: 'label.ipv4.gateway' }, //netmask: { label: 'label.netmask' }, cidr: { - label: 'IPv4 CIDR' + label: 'label.ipv4.cidr' }, ip6gateway: { - label: 'IPv6 Gateway' + label: 'label.ipv6.gateway' }, ip6cidr: { - label: 'IPv6 CIDR' + label: 'label.ipv6.CIDR' }, networkdomaintext: { @@ -1968,13 +1968,13 @@ }, dedicatedGuestVlanRanges: { - title: 'Dedicated VLAN/VNI Ranges', + title: 'label.dedicated.vlan.vni.ranges', listView: { section: 'dedicatedGuestVlanRanges', id: 'dedicatedGuestVlanRanges', fields: { guestvlanrange: { - label: 'VLAN/VNI Range(s)' + label: 'label.vlan.vni.ranges' }, domain: { label: 'label.domain' @@ -1999,17 +1999,17 @@ }, actions: { add: { - label: 'Dedicate VLAN/VNI Range', + label: 'label.dedicate.vlan.vni.range', messages: { notification: function (args) { - return 'Dedicate VLAN/VNI Range'; + return 'label.dedicate.vlan.vni.range'; } }, createForm: { - title: 'Dedicate VLAN/VNI Range', + title: 'label.dedicate.vlan.vni.range', fields: { vlanrange: { - label: 'VLAN/VNI Range', + label: 'label.vlan.vni.range', /* select: function(args) { var items = []; if(args.context.physicalNetworks[0].vlan != null && args.context.physicalNetworks[0].vlan.length > 0) { @@ -2083,16 +2083,16 @@ }, detailView: { - name: 'VLAN Range details', + name: 'label.vlan.range.details', actions: { remove: { - label: 'Release dedicated VLAN range', + label: 'label.release.dedicated.vlan.range', messages: { confirm: function (args) { - return 'Please confirm you want to release dedicated VLAN range'; + return 'message.confirm.release.dedicate.vlan.range'; }, notification: function (args) { - return 'Release dedicated VLAN range'; + return 'label.release.dedicated.vlan.range'; } }, action: function (args) { @@ -2124,7 +2124,7 @@ title: 'label.details', fields:[ { guestvlanrange: { - label: 'VLAN Range(s)' + label: 'label.vlan.ranges' } }, { @@ -2417,7 +2417,7 @@ }); }, detailView: { - name: 'Virtual applicance details', + name: 'label.virtual.appliance.details', actions: { start: { label: 'label.action.start.router', @@ -2974,16 +2974,16 @@ }); }, detailView: { - name: 'Virtual applicance details', + name: 'label.virtual.appliance.details', actions: { start: { - label: 'Start LB VM', + label: 'label.start.lb.vm', messages: { confirm: function (args) { - return 'Please confirm you want to start LB VM'; + return 'message.confirm.start.lb.vm'; }, notification: function (args) { - return 'Start LB VM'; + return 'label.start.lb.vm'; } }, action: function (args) { @@ -3013,10 +3013,10 @@ }, stop: { - label: 'Stop LB VM', + label: 'label.stop.lb.vm', createForm: { - title: 'Please confirm you want to stop LB VM', - desc: 'Stop LB VM', + title: 'message.confirm.stop.lb.vm', + desc: 'label.stop.lb.vm', fields: { forced: { label: 'force.stop', @@ -3027,7 +3027,7 @@ }, messages: { notification: function (args) { - return 'Stop LB VM'; + return 'label.stop.lb.vm'; } }, action: function (args) { @@ -3059,9 +3059,9 @@ }, migrate: { - label: 'Migrate LB VM', + label: 'label.migrate.lb.vm', createForm: { - title: 'Migrate LB VM', + title: 'label.migrate.lb.vm', fields: { hostId: { label: 'label.host', @@ -3097,7 +3097,7 @@ }, messages: { notification: function (args) { - return 'Migrate LB VM'; + return 'label.migrate.lb.vm'; } }, action: function (args) { @@ -3375,7 +3375,7 @@ vpcVirtualRouter: { id: 'vpcVirtualRouterProviders', - label: 'VPC Virtual Router', + label: 'label.vpc.virtual.router', isMaximized: true, type: 'detailView', fields: { @@ -3512,7 +3512,7 @@ }); }, detailView: { - name: 'Virtual applicance details', + name: 'label.virtual.appliance.details', actions: { start: { label: 'label.action.start.router', @@ -3828,7 +3828,7 @@ label: 'label.redundant.state' }, vpcid: { - label: 'VPC ID' + label: 'label.vpc.id' } }], dataProvider: function (args) { @@ -3920,7 +3920,7 @@ Ovs: { id: "Ovs", - label: "Ovs", + label: "label.ovs", isMaximized: true, type: 'detailView', fields: { @@ -4122,15 +4122,15 @@ }, gslbprovider: { - label: 'GSLB service', + label: 'label.gslb.service', isBoolean: true, isChecked: false }, gslbproviderpublicip: { - label: 'GSLB service Public IP' + label: 'label.gslb.service.public.ip' }, gslbproviderprivateip: { - label: 'GSLB service Private IP' + label: 'label.gslb.service.private.ip' }, numretries: { @@ -4310,7 +4310,7 @@ BaremetalDhcpProvider: { type: 'detailView', id: 'BaremetalDhcpProvider', - label: 'Baremetal DHCP Provider', + label: 'label.baremetal.dhcp.provider', viewAll: { label: 'label.devices', path: '_zone.BaremetalDhcpDevices' @@ -4346,9 +4346,9 @@ }, actions: { add: { - label: 'Add Baremetal DHCP Device', + label: 'label.add.baremetal.dhcp.device', createForm: { - title: 'Add Baremetal DHCP Device', + title: 'label.add.baremetal.dhcp.device', fields: { url: { label: 'label.url', @@ -4376,7 +4376,7 @@ }, messages: { notification: function (args) { - return 'Add Baremetal DHCP Device'; + return 'label.add.baremetal.dhcp.device'; } }, notification: { @@ -4482,7 +4482,7 @@ BaremetalPxeProvider: { type: 'detailView', id: 'BaremetalPxeProvider', - label: 'Baremetal PXE Provider', + label: 'label.baremetal.pxe.provider', viewAll: { label: 'label.devices', path: '_zone.BaremetalPxeDevices' @@ -4518,9 +4518,9 @@ }, actions: { add: { - label: 'Add Baremetal PXE Device', + label: 'label.baremetal.pxe.device', createForm: { - title: 'Add Baremetal PXE Device', + title: 'label.baremetal.pxe.device', fields: { url: { label: 'label.url', @@ -4542,7 +4542,7 @@ } }, tftpdir: { - label: 'Tftp root directory', + label: 'label.tftp.root.directory', validation: { required: true } @@ -4554,7 +4554,7 @@ }, messages: { notification: function (args) { - return 'Add Baremetal PXE Device'; + return 'label.baremetal.pxe.device'; } }, notification: { @@ -5474,7 +5474,7 @@ // Security groups detail view securityGroups: { id: 'securityGroup-providers', - label: 'Security Groups', + label: 'label.menu.security.groups', type: 'detailView', viewAll: { label: 'label.rules', @@ -6255,7 +6255,7 @@ }); }, detailView: { - name: 'Virtual applicance details', + name: 'label.virtual.appliance.details', actions: { start: { label: 'label.action.start.router', @@ -6984,7 +6984,7 @@ sections: { physicalResources: { type: 'select', - title: 'Physical Resources', + title: 'label.menu.physical.resources', listView: { zones: { id: 'physicalResources', @@ -7070,24 +7070,24 @@ isMaximized: true, actions: { addVmwareDc: { - label: 'Add VMware datacenter', - textLabel: 'Add VMware datacenter', + label: 'label.add.vmware.datacenter', + textLabel: 'label.add.vmware.datacenter', messages: { notification: function (args) { - return 'Add VMware datacenter'; + return 'label.add.vmware.datacenter'; } }, createForm: { - title: 'Add VMware datacenter', + title: 'label.add.vmware.datacenter', fields: { name: { - label: 'DC Name', + label: 'label.dc.name', validation: { required: true } }, vcenter: { - label: 'vcenter', + label: 'label.vcenter', validation: { required: true } @@ -7143,13 +7143,13 @@ }, removeVmwareDc: { - label: 'Remove VMware datacenter', + label: 'label.remove.vmware.datacenter', messages: { confirm: function (args) { - return 'Please confirm you want to remove VMware datacenter'; + return 'message.confirm.remove.vmware.datacenter'; }, notification: function (args) { - return 'Remove VMware datacenter'; + return 'label.remove.vmware.datacenter'; } }, action: function (args) { @@ -7246,20 +7246,20 @@ }, dedicateZone: { - label: 'Dedicate Zone', + label: 'label.dedicate.zone', messages: { confirm: function (args) { - return 'Do you really want to dedicate this zone to a domain/account? '; + return 'message.confirm.dedicate.zone'; }, notification: function (args) { - return 'Zone Dedicated'; + return 'label.zone.dedicated'; } }, createForm: { - title: 'Dedicate Zone', + title: 'label.dedicate.zone', fields: { domainId: { - label: 'Domain', + label: 'label.domain', validation: { required: true }, @@ -7287,7 +7287,7 @@ } }, accountId: { - label: 'Account', + label: 'label.account', docID: 'helpAccountForDedication', validation: { required: false @@ -7324,13 +7324,13 @@ } }, releaseDedicatedZone: { - label: 'Release Dedicated Zone', + label: 'label.release.dedicated.zone', messages: { confirm: function (args) { - return 'Do you want to release this dedicated zone ?'; + return 'message.confirm.release.dedicated.zone'; }, notification: function (args) { - return 'Zone dedication released'; + return 'message.dedicated.zone.released'; } }, action: function (args) { @@ -7470,11 +7470,11 @@ isEditable: true }, ip6dns1: { - label: 'IPv6 DNS1', + label: 'label.ipv6.dns1', isEditable: true }, ip6dns2: { - label: 'IPv6 DNS2', + label: 'label.ipv6.dns2', isEditable: true }, internaldns1: { @@ -7511,21 +7511,21 @@ }, { isdedicated: { - label: 'Dedicated' + label: 'label.dedicated' }, domainid: { - label: 'Domain ID' + label: 'label.domain.id' } }, { vmwaredcName: { - label: 'VMware datacenter Name' + label: 'label.vmware.datacenter.name' }, vmwaredcVcenter: { - label: 'VMware datacenter vcenter' + label: 'label.vmware.datacenter.vcenter' }, vmwaredcId: { - label: 'VMware datacenter Id' + label: 'label.vmware.datacenter.id' } }], dataProvider: function (args) { @@ -7678,7 +7678,7 @@ detailView: { noCompact: true, - name: 'System VM details', + name: 'label.system.vm.details', actions: { start: { label: 'label.action.start.systemvm', @@ -7914,7 +7914,7 @@ var vmObj = args.jsonObj; //if (vmObj.state == 'Running' && vmObj.hypervisor == 'VMware') { //needs to wait for API fix that will return hypervisor property if (vmObj.state == 'Running') { - description = 'Please read the dynamic scaling section in the admin guide before scaling up.'; + description = 'message.read.admin.guide.scaling.up'; } return description; }, @@ -7977,11 +7977,11 @@ }, messages: { confirm: function (args) { - return 'Do you really want to scale up the system VM ?'; + return 'message.confirm.scale.up.system.vm'; }, notification: function (args) { - return 'System VM Scaled Up'; + return 'label.system.vm.scaled.up'; } }, notification: { @@ -8026,8 +8026,8 @@ label: 'label.type', converter: function (args) { if (args == "consoleproxy") - return "Console Proxy VM"; else if (args == "secondarystoragevm") - return "Secondary Storage VM"; else + return 'label.console.proxy.vm'; else if (args == "secondarystoragevm") + return 'label.secondary.storage.vm'; else return args; } }, @@ -8078,7 +8078,7 @@ // Granular settings for zone settings: { - title: 'Settings', + title: 'label.settings', custom: cloudStack.uiCustom.granularSettings({ dataProvider: function (args) { $.ajax({ @@ -8741,7 +8741,7 @@ routerNoGroup: { id: 'routers', type: 'select', - title: '(no grouping)', + title: 'label.no.grouping', listView: { id: 'routers', label: 'label.virtual.appliances', @@ -8768,7 +8768,7 @@ } }, requiresupgrade: { - label: 'Requires Upgrade', + label: 'label.requires.upgrade', converter: cloudStack.converters.toBooleanText } }, @@ -8830,7 +8830,7 @@ }); }, detailView: { - name: 'Virtual applicance details', + name: 'label.virtual.appliance.details', actions: { start: { label: 'label.action.start.router', @@ -8915,13 +8915,13 @@ }, upgradeRouterToUseNewerTemplate: { - label: 'Upgrade Router to Use Newer Template', + label: 'label.upgrade.router.newer.template', messages: { confirm: function (args) { - return 'Please confirm that you want to upgrade router to use newer template'; + return 'message.confirm.upgrade.router.newer.template'; }, notification: function (args) { - return 'Upgrade Router to Use Newer Template'; + return 'label.upgrade.router.newer.template'; } }, action: function (args) { @@ -9102,7 +9102,7 @@ var vmObj = args.jsonObj; //if (vmObj.state == 'Running' && vmObj.hypervisor == 'VMware') { //needs to wait for API fix that will return hypervisor property if (vmObj.state == 'Running') { - description = 'Please read the dynamic scaling section in the admin guide before scaling up.'; + description = 'message.read.admin.guide.scaling.up'; } return description; }, @@ -9163,11 +9163,11 @@ }, messages: { confirm: function (args) { - return 'Do you really want to scale up the Router VM ?'; + return 'message.confirm.scale.up.router.vm'; }, notification: function (args) { - return 'Router VM Scaled Up'; + return 'label.router.vm.scaled.up'; } }, notification: { @@ -9243,7 +9243,7 @@ label: 'label.version' }, requiresupgrade: { - label: 'Requires Upgrade', + label: 'label.requires.upgrade', converter: cloudStack.converters.toBooleanText }, guestnetworkid: { @@ -9285,7 +9285,7 @@ label: 'label.redundant.state' }, vpcid: { - label: 'VPC ID' + label: 'label.vpc.id' } }], dataProvider: function (args) { @@ -9371,7 +9371,7 @@ routerGroupByZone: { id: 'routerGroupByZone', type: 'select', - title: 'group by zone', + title: 'label.group.by.zone', listView: { id: 'routerGroupByZone', label: 'label.virtual.appliances', @@ -9380,15 +9380,15 @@ label: 'label.zone' }, routerCount: { - label: 'Total of Virtual Routers' + label: 'label.total.virtual.routers' }, routerRequiresUpgrade: { - label: 'Upgrade is required', + label: 'label.upgrade.required', converter: function (args) { if (args > 0) { - return 'Yes'; + return 'label.yes'; } else { - return 'No'; + return 'label.no'; } } } @@ -9422,16 +9422,16 @@ }); }, detailView: { - name: 'Virtual Routers group by zone', + name: 'label.virtual.routers.group.zone', actions: { upgradeRouterToUseNewerTemplate: { - label: 'Upgrade Router to Use Newer Template', + label: 'label.upgrade.router.newer.template', messages: { confirm: function (args) { - return 'Please confirm that you want to upgrade all routers in this zone to use newer template'; + return 'message.confirm.upgrade.routers.newtemplate'; }, notification: function (args) { - return 'Upgrade Router to Use Newer Template'; + return 'label.upgrade.router.newer.template'; } }, action: function (args) { @@ -9459,7 +9459,7 @@ }, tabs: { details: { - title: 'Virtual Routers group by zone', + title: 'label.virtual.routers.group.zone', fields:[ { name: { label: 'label.zone' @@ -9467,10 +9467,10 @@ }, { routerCount: { - label: 'Total of Virtual Routers' + label: 'label.total.virtual.routers' }, routerRequiresUpgrade: { - label: 'Upgrade is required', + label: 'label.upgrade.required', converter: function (args) { if (args > 0) { return 'Yes'; @@ -9480,7 +9480,7 @@ } }, numberOfRouterRequiresUpgrade: { - label: 'Total of Virtual Routers that require upgrade' + label: 'label.total.virtual.routers.upgrade' } }], dataProvider: function (args) { @@ -9498,7 +9498,7 @@ routerGroupByPod: { id: 'routerGroupByPod', type: 'select', - title: 'group by pod', + title: 'label.group.by.pod', listView: { id: 'routerGroupByPod', label: 'label.virtual.appliances', @@ -9507,15 +9507,15 @@ label: 'label.pod' }, routerCount: { - label: 'Total of Virtual Routers' + label: 'label.total.virtual.routers' }, routerRequiresUpgrade: { - label: 'Upgrade is required', + label: 'label.upgrade.required', converter: function (args) { if (args > 0) { - return 'Yes'; + return 'label.yes'; } else { - return 'No'; + return 'label.no'; } } } @@ -9549,16 +9549,16 @@ }); }, detailView: { - name: 'Virtual Routers group by pod', + name: 'label.virtual.routers.group.pod', actions: { upgradeRouterToUseNewerTemplate: { - label: 'Upgrade Router to Use Newer Template', + label: 'label.upgrade.router.newer.template', messages: { confirm: function (args) { - return 'Please confirm that you want to upgrade all routers in this pod to use newer template'; + return 'message.confirm.upgrade.routers.pod.newtemplate'; }, notification: function (args) { - return 'Upgrade Router to Use Newer Template'; + return 'label.upgrade.router.newer.template'; } }, action: function (args) { @@ -9586,7 +9586,7 @@ }, tabs: { details: { - title: 'Virtual Routers group by pod', + title: 'label.virtual.routers.group.pod', fields:[ { name: { label: 'label.pod' @@ -9594,20 +9594,20 @@ }, { routerCount: { - label: 'Total of Virtual Routers' + label: 'label.total.virtual.routers' }, routerRequiresUpgrade: { - label: 'Upgrade is required', + label: 'label.upgrade.required', converter: function (args) { if (args > 0) { - return 'Yes'; + return 'label.yes'; } else { - return 'No'; + return 'label.no'; } } }, numberOfRouterRequiresUpgrade: { - label: 'Total of Virtual Routers that require upgrade' + label: 'label.total.virtual.routers.upgrade' }, zonename: { label: 'label.zone' @@ -9628,7 +9628,7 @@ routerGroupByCluster: { id: 'routerGroupByCluster', type: 'select', - title: 'group by cluster', + title: 'label.group.by.cluster', listView: { id: 'routerGroupByCluster', label: 'label.virtual.appliances', @@ -9637,15 +9637,15 @@ label: 'label.cluster' }, routerCount: { - label: 'Total of Virtual Routers' + label: 'label.total.virtual.routers' }, routerRequiresUpgrade: { - label: 'Upgrade is required', + label: 'label.upgrade.required', converter: function (args) { if (args > 0) { - return 'Yes'; + return 'label.yes'; } else { - return 'No'; + return 'label.no'; } } } @@ -9679,16 +9679,16 @@ }); }, detailView: { - name: 'Virtual Routers group by cluster', + name: 'label.virtual.routers.group.cluster', actions: { upgradeRouterToUseNewerTemplate: { - label: 'Upgrade Router to Use Newer Template', + label: 'label.upgrade.router.newer.template', messages: { confirm: function (args) { - return 'Please confirm that you want to upgrade all routers in this cluster to use newer template'; + return 'message.confirm.upgrade.routers.cluster.newtemplate'; }, notification: function (args) { - return 'Upgrade Router to Use Newer Template'; + return 'label.upgrade.router.newer.template'; } }, action: function (args) { @@ -9716,7 +9716,7 @@ }, tabs: { details: { - title: 'Virtual Routers group by cluster', + title: 'label.virtual.routers.group.cluster', fields:[ { name: { label: 'label.cluster' @@ -9724,26 +9724,26 @@ }, { routerCount: { - label: 'Total of Virtual Routers' + label: 'label.total.virtual.routers' }, routerRequiresUpgrade: { - label: 'Upgrade is required', + label: 'label.upgrade.required', converter: function (args) { if (args > 0) { - return 'Yes'; + return 'label.yes'; } else { - return 'No'; + return 'label.no'; } } }, numberOfRouterRequiresUpgrade: { - label: 'Total of Virtual Routers that require upgrade' + label: 'label.total.virtual.routers that require upgrade' }, podname: { label: 'label.pod' }, zonename: { - label: 'zone' + label: 'label.zone.lower' } }], dataProvider: function (args) { @@ -9773,15 +9773,15 @@ label: 'label.domain' }, routerCount: { - label: 'Total of Virtual Routers' + label: 'label.total.virtual.routers' }, routerRequiresUpgrade: { - label: 'Upgrade is required', + label: 'label.upgrade.required', converter: function (args) { if (args > 0) { - return 'Yes'; + return 'label.yes'; } else { - return 'No'; + return 'label.no'; } } } @@ -9876,16 +9876,16 @@ }); }, detailView: { - name: 'Virtual Routers group by account', + name: 'label.virtual.routers.group.account', actions: { upgradeRouterToUseNewerTemplate: { - label: 'Upgrade Router to Use Newer Template', + label: 'label.upgrade.router.newer.template', messages: { confirm: function (args) { - return 'Please confirm that you want to upgrade all routers in this account to use newer template'; + return 'message.confirm.upgrade.routers.account.newtemplate'; }, notification: function (args) { - return 'Upgrade Router to Use Newer Template'; + return 'label.upgrade.router.newer.template'; } }, action: function (args) { @@ -9914,7 +9914,7 @@ }, tabs: { details: { - title: 'Virtual Routers group by account', + title: 'label.virtual.routers.group.account', fields:[ { name: { label: 'label.account' @@ -9925,20 +9925,20 @@ }, { routerCount: { - label: 'Total of Virtual Routers' + label: 'label.total.virtual.routers' }, routerRequiresUpgrade: { - label: 'Upgrade is required', + label: 'label.upgrade.required', converter: function (args) { if (args > 0) { - return 'Yes'; + return 'label.yes'; } else { - return 'No'; + return 'label.no'; } } }, numberOfRouterRequiresUpgrade: { - label: 'Total of Virtual Routers that require upgrade' + label: 'label.total.virtual.routers that require upgrade' } }], dataProvider: function (args) { @@ -10041,7 +10041,7 @@ label: 'label.zone' }, state: { - label: 'VM state', + label: 'label.vm.state', converter: function (str) { // For localization return str; @@ -10091,7 +10091,7 @@ }, detailView: { - name: 'System VM details', + name: 'label.system.vm.details', actions: { start: { label: 'label.action.start.systemvm', @@ -10327,7 +10327,7 @@ var vmObj = args.jsonObj; //if (vmObj.state == 'Running' && vmObj.hypervisor == 'VMware') { //needs to wait for API fix that will return hypervisor property if (vmObj.state == 'Running') { - description = 'Please read the dynamic scaling section in the admin guide before scaling up.'; + description = 'message.read.admin.guide.scaling.up'; } return description; }, @@ -10390,11 +10390,11 @@ }, messages: { confirm: function (args) { - return 'Do you really want to scale up the system VM ?'; + return 'message.confirm.scale.up.system.vm'; }, notification: function (args) { - return 'System VM Scaled Up'; + return 'label.system.vm.scaled.up'; } }, notification: { @@ -10570,15 +10570,15 @@ }, gslbprovider: { - label: 'GSLB service', + label: 'label.gslb.service', isBoolean: true, isChecked: false }, gslbproviderpublicip: { - label: 'GSLB service Public IP' + label: 'label.gslb.service.public.ip' }, gslbproviderprivateip: { - label: 'GSLB service Private IP' + label: 'label.gslb.service.private.ip' }, numretries: { @@ -10658,7 +10658,7 @@ } }, detailView: { - name: 'NetScaler details', + name: 'label.netscaler.details', actions: { 'remove': { label: 'label.delete.NetScaler', @@ -10722,10 +10722,10 @@ converter: cloudStack.converters.toBooleanText }, gslbproviderpublicip: { - label: 'GSLB service Public IP' + label: 'label.gslb.service.public.ip' }, gslbproviderprivateip: { - label: 'GSLB service Private IP' + label: 'label.gslb.service.private.ip' } }], dataProvider: function (args) { @@ -10750,7 +10750,7 @@ // Baremetal DHCP devices listView BaremetalDhcpDevices: { id: 'BaremetalDhcpDevices', - title: 'Baremetal DHCP Devices', + title: 'label.baremetal.dhcp.devices', listView: { id: 'BaremetalDhcpDevices', fields: { @@ -10760,9 +10760,9 @@ }, actions: { add: { - label: 'Add Baremetal DHCP Device', + label: 'label.add.baremetal.dhcp.device', createForm: { - title: 'Add Baremetal DHCP Device', + title: 'label.add.baremetal.dhcp.device', fields: { url: { label: 'label.url', @@ -10790,7 +10790,7 @@ }, messages: { notification: function (args) { - return 'Add Baremetal DHCP Device'; + return 'label.add.baremetal.dhcp.device'; } }, notification: { @@ -10822,7 +10822,7 @@ // Baremetal PXE devices listView BaremetalPxeDevices: { id: 'BaremetalPxeDevices', - title: 'Baremetal PXE Devices', + title: 'label.baremetal.pxe.devices', listView: { id: 'BaremetalPxeDevices', fields: { @@ -10832,9 +10832,9 @@ }, actions: { add: { - label: 'Add Baremetal PXE Device', + label: 'label.baremetal.pxe.device', createForm: { - title: 'Add Baremetal PXE Device', + title: 'label.baremetal.pxe.device', fields: { url: { label: 'label.url', @@ -10856,7 +10856,7 @@ } }, tftpdir: { - label: 'Tftp root directory', + label: 'label.tftp.root.directory', validation: { required: true } @@ -10868,7 +10868,7 @@ }, messages: { notification: function (args) { - return 'Add Baremetal PXE Device'; + return 'label.baremetal.pxe.device'; } }, notification: { @@ -11022,7 +11022,7 @@ }, messages: { notification: function (args) { - return 'Added new F5'; + return 'label.addes.new.f5'; } }, notification: { @@ -11048,7 +11048,7 @@ }); }, detailView: { - name: 'F5 details', + name: 'label.f5.details', actions: { 'remove': { label: 'label.delete.F5', @@ -11286,7 +11286,7 @@ }); }, detailView: { - name: 'SRX details', + name: 'label.srx.details', actions: { 'remove': { label: 'label.delete.SRX', @@ -11530,7 +11530,7 @@ }); }, detailView: { - name: 'Palo Alto details', + name: 'label.palo.alto.details', actions: { 'remove': { label: 'label.delete.PA', @@ -11695,7 +11695,7 @@ messages: { notification: function (args) { - return 'Added new Nicira Nvp Controller'; + return 'label.added.nicira.nvp.controller'; } }, notification: { @@ -11721,7 +11721,7 @@ }); }, detailView: { - name: 'Nicira Nvp details', + name: 'label.nicira.nvp.details', actions: { 'remove': { label: 'label.delete.NiciaNvp', @@ -11857,7 +11857,7 @@ messages: { notification: function (args) { - return 'Added new BigSwitch Vns Controller'; + return 'label.added.new.bigswitch.vns.controller'; } }, notification: { @@ -11883,7 +11883,7 @@ }); }, detailView: { - name: 'BigSwitch Vns details', + name: 'label.bigswitch.vns.details', actions: { 'remove': { label: 'label.delete.BigSwitchVns', @@ -12070,14 +12070,14 @@ }, isDedicated: { - label: 'Dedicate', + label: 'label.dedicate', isBoolean: true, isChecked: false, docID: 'helpDedicateResource' }, domainId: { - label: 'Domain', + label: 'label.domain', isHidden: true, validation: { required: true @@ -12108,7 +12108,7 @@ }, accountId: { - label: 'Account', + label: 'label.account', isHidden: true, dependsOn: 'isDedicated', docID: 'helpAccountForDedication', @@ -12204,7 +12204,7 @@ detailView: { viewAll: { path: '_zone.clusters', - label: 'Clusters' + label: 'label.clusters' }, tabFilter: function (args) { var hiddenTabs =[]; @@ -12281,20 +12281,20 @@ }, dedicate: { - label: 'Dedicate Pod', + label: 'label.dedicate.pod', messages: { confirm: function (args) { - return 'Do you really want to dedicate this pod to a domain/account? '; + return 'message.confirm.dedicate.pod.domain.account'; }, notification: function (args) { - return 'Pod Dedicated'; + return 'label.pod.dedicated'; } }, createForm: { - title: 'Dedicate Pod', + title: 'label.dedicate.pod', fields: { domainId: { - label: 'Domain', + label: 'label.domain', validation: { required: true }, @@ -12322,7 +12322,7 @@ } }, accountId: { - label: 'Account', + label: 'label.account', docID: 'helpAccountForDedication', validation: { required: false @@ -12362,13 +12362,13 @@ } }, release: { - label: 'Release Dedicated Pod', + label: 'label.release.dedicated.pod', messages: { confirm: function (args) { - return 'Do you want to release this dedicated pod ?'; + return 'message.confirm.release.dedicated.pod'; }, notification: function (args) { - return 'Pod dedication released'; + return 'message.pod.dedication.released'; } }, action: function (args) { @@ -12510,10 +12510,10 @@ }, { isdedicated: { - label: 'Dedicated' + label: 'label.dedicated' }, domainid: { - label: 'Domain ID' + label: 'label.domain.id' } }], @@ -12532,12 +12532,12 @@ var podItem = json.listdedicatedpodsresponse.dedicatedpod[0]; if (podItem.domainid != null) { $.extend(item, podItem, { - isdedicated: 'Yes' + isdedicated: 'label.yes' }); } } else $.extend(item, { - isdedicated: 'No' + isdedicated: 'label.no' }); args.response.success({ @@ -12792,7 +12792,7 @@ }, fields: { zoneid: { - label: 'Zone Name', + label: 'label.zone.name', docID: 'helpClusterZone', validation: { required: true @@ -12847,7 +12847,7 @@ } }, podId: { - label: 'Pod Name', + label: 'label.pod.name', docID: 'helpClusterPod', dependsOn: 'zoneid', select: function (args) { @@ -12885,14 +12885,14 @@ }, isDedicated: { - label: 'Dedicate', + label: 'label.dedicate', isBoolean: true, isChecked: false, docID: 'helpDedicateResource' }, domainId: { - label: 'Domain', + label: 'label.domain', isHidden: true, validation: { required: true @@ -12923,7 +12923,7 @@ }, accountId: { - label: 'Account', + label: 'label.account', isHidden: true, dependsOn: 'isDedicated', docID: 'helpAccountForDedication', @@ -12964,7 +12964,7 @@ }, overridepublictraffic: { - label: 'Override Public-Traffic', + label: 'label.override.public.traffic', isBoolean: true, isHidden: true, isChecked: false, @@ -12973,7 +12973,7 @@ vSwitchPublicType: { - label: 'Public Traffic vSwitch Type', + label: 'label.public.traffic.vswitch.type', select: function (args) { var useNexusDvs = false; var items =[] @@ -13026,12 +13026,12 @@ }, vSwitchPublicName: { - label: 'Public Traffic vSwitch Name', + label: 'label.public.traffic.vswitch.name', isHidden: true }, overrideguesttraffic: { - label: 'Override Guest-Traffic', + label: 'label.override.guest.traffic', isBoolean: true, isHidden: true, isChecked: false, @@ -13039,7 +13039,7 @@ }, vSwitchGuestType: { - label: 'Guest Traffic vSwitch Type', + label: 'label.guest.traffic.vswitch.type', select: function (args) { var items =[] @@ -13094,41 +13094,41 @@ }, vSwitchGuestName: { - label: ' Guest Traffic vSwitch Name', + label: ' label.guest.traffic.vswitch.name', isHidden: true }, vsmipaddress: { - label: 'Nexus 1000v IP Address', + label: 'label.cisco.nexus1000v.ip.address', validation: { required: false }, isHidden: true }, vsmipaddress_req: { - label: 'Nexus 1000v IP Address', + label: 'label.cisco.nexus1000v.ip.address', validation: { required: true }, isHidden: true }, vsmusername: { - label: 'Nexus 1000v Username', + label: 'label.cisco.nexus1000v.username', validation: { required: false }, isHidden: true }, vsmusername_req: { - label: 'Nexus 1000v Username', + label: 'label.cisco.nexus1000v.username', validation: { required: true }, isHidden: true }, vsmpassword: { - label: 'Nexus 1000v Password', + label: 'label.cisco.nexus1000v.password', validation: { required: false }, @@ -13136,7 +13136,7 @@ isHidden: true }, vsmpassword_req: { - label: 'Nexus 1000v Password', + label: 'label.cisco.nexus1000v.password', validation: { required: true }, @@ -13417,20 +13417,20 @@ }, dedicate: { - label: 'Dedicate Cluster', + label: 'label.dedicate.cluster', messages: { confirm: function (args) { - return 'Do you really want to dedicate this cluster to a domain/account? '; + return 'message.confirm.dedicate.cluster.domain.account'; }, notification: function (args) { - return 'Cluster Dedicated'; + return 'message.cluster.dedicated'; } }, createForm: { - title: 'Dedicate Cluster', + title: 'label.dedicate.cluster', fields: { domainId: { - label: 'Domain', + label: 'label.domain', validation: { required: true }, @@ -13458,7 +13458,7 @@ } }, accountId: { - label: 'Account', + label: 'label.account', docID: 'helpAccountForDedication', validation: { required: false @@ -13494,13 +13494,13 @@ } }, release: { - label: 'Release Dedicated Cluster', + label: 'label.release.dedicated.cluster', messages: { confirm: function (args) { - return 'Do you want to release this dedicated cluster ?'; + return 'message.confirm.release.dedicated.cluster'; }, notification: function (args) { - return 'Cluster dedication released'; + return 'message.cluster.dedication.released'; } }, action: function (args) { @@ -13656,10 +13656,10 @@ } }, { isdedicated: { - label: 'Dedicated' + label: 'label.dedicated' }, domainid: { - label: 'Domain ID' + label: 'label.domain.id' } }], dataProvider: function (args) { @@ -13678,12 +13678,12 @@ var clusterItem = json.listdedicatedclustersresponse.dedicatedcluster[0]; if (clusterItem.domainid != null) { $.extend(item, clusterItem, { - isdedicated: 'Yes' + isdedicated: 'label.yes' }); } } else $.extend(item, { - isdedicated: 'No' + isdedicated: 'label.no' }) }, error: function (json) { @@ -13893,7 +13893,7 @@ // Granular settings for cluster settings: { - title: 'Settings', + title: 'label.settings', custom: cloudStack.uiCustom.granularSettings({ dataProvider: function (args) { $.ajax({ @@ -14255,14 +14255,14 @@ }, isDedicated: { - label: 'Dedicate', + label: 'label.dedicate', isBoolean: true, isChecked: false, docID: 'helpDedicateResource' }, domainId: { - label: 'Domain', + label: 'label.domain', isHidden: true, validation: { required: true @@ -14292,7 +14292,7 @@ }, accountId: { - label: 'Account', + label: 'label.account', isHidden: true, dependsOn: 'isDedicated', docID: 'helpAccountForDedication', @@ -14532,20 +14532,20 @@ }, dedicate: { - label: 'Dedicate Host', + label: 'label.dedicate.host', messages: { confirm: function (args) { - return 'Do you really want to dedicate this host to a domain/account? '; + return 'message.confirm.dedicate.host.domain.account'; }, notification: function (args) { - return 'Host Dedicated'; + return 'message.host.dedicated'; } }, createForm: { - title: 'Dedicate Host', + title: 'label.dedicate.host', fields: { domainId: { - label: 'Domain', + label: 'label.domain', validation: { required: true }, @@ -14573,7 +14573,7 @@ } }, accountId: { - label: 'Account', + label: 'label.account', docID: 'helpAccountForDedication', validation: { required: false @@ -14611,13 +14611,13 @@ } }, release: { - label: 'Release Dedicated Host', + label: 'label.release.dedicated.host', messages: { confirm: function (args) { - return 'Do you want to release this dedicated host ?'; + return 'message.confirm.release.dedicated.host'; }, notification: function (args) { - return 'Host dedication released'; + return 'message.host.dedication.released'; } }, action: function (args) { @@ -14897,15 +14897,15 @@ label: 'label.last.disconnected' }, cpusockets: { - label: 'The Number of CPU Sockets' + label: 'label.number.of.cpu.sockets' } }, { isdedicated: { - label: 'Dedicated' + label: 'label.dedicated' }, domainid: { - label: 'Domain ID' + label: 'label.domain.id' } }], @@ -14925,12 +14925,12 @@ var hostItem = json.listdedicatedhostsresponse.dedicatedhost[0]; if (hostItem.domainid != null) { $.extend(item, hostItem, { - isdedicated: 'Yes' + isdedicated: 'label.yes' }); } } else $.extend(item, { - isdedicated: 'No' + isdedicated: 'label.no' }) }, error: function (json) { @@ -15024,7 +15024,7 @@ truncate: true }, scope: { - label: 'Scope' + label: 'label.scope' } }, @@ -15387,7 +15387,7 @@ $form.find('.form-item[rel=path]').css('display', 'inline-block'); var $required = $form.find('.form-item[rel=path]').find(".name").find("label span"); - $form.find('.form-item[rel=path]').find(".name").find("label").text("Path:").prepend($required); + $form.find('.form-item[rel=path]').find(".name").find("label").text('label.path'+":").prepend($required); $form.find('.form-item[rel=smbUsername]').hide(); $form.find('.form-item[rel=smbPassword]').hide(); @@ -15414,7 +15414,7 @@ $form.find('.form-item[rel=path]').css('display', 'inline-block'); var $required = $form.find('.form-item[rel=path]').find(".name").find("label span"); - $form.find('.form-item[rel=path]').find(".name").find("label").text("Path:").prepend($required); + $form.find('.form-item[rel=path]').find(".name").find("label").text('label.path'+":").prepend($required); $form.find('.form-item[rel=smbUsername]').css('display', 'inline-block'); $form.find('.form-item[rel=smbPassword]').css('display', 'inline-block'); @@ -15441,7 +15441,7 @@ $form.find('.form-item[rel=path]').css('display', 'inline-block'); var $required = $form.find('.form-item[rel=path]').find(".name").find("label span"); - $form.find('.form-item[rel=path]').find(".name").find("label").text("Path:").prepend($required); + $form.find('.form-item[rel=path]').find(".name").find("label").text('label.path'+":").prepend($required); $form.find('.form-item[rel=smbUsername]').hide(); $form.find('.form-item[rel=smbPassword]').hide(); @@ -15467,7 +15467,7 @@ $form.find('.form-item[rel=path]').css('display', 'inline-block'); var $required = $form.find('.form-item[rel=path]').find(".name").find("label span"); - $form.find('.form-item[rel=path]').find(".name").find("label").text("SR Name-Label:").prepend($required); + $form.find('.form-item[rel=path]').find(".name").find("label").text('label.SR.name'+":").prepend($required); $form.find('.form-item[rel=smbUsername]').hide(); $form.find('.form-item[rel=smbPassword]').hide(); @@ -15566,7 +15566,7 @@ $form.find('.form-item[rel=path]').css('display', 'inline-block'); var $required = $form.find('.form-item[rel=path]').find(".name").find("label span"); - $form.find('.form-item[rel=path]').find(".name").find("label").text("Path:").prepend($required); + $form.find('.form-item[rel=path]').find(".name").find("label").text('label.path'+":").prepend($required); $form.find('.form-item[rel=smbUsername]').hide(); $form.find('.form-item[rel=smbPassword]').hide(); @@ -16148,7 +16148,7 @@ // Granular settings for storage pool settings: { - title: 'Settings', + title: 'label.settings', custom: cloudStack.uiCustom.granularSettings({ dataProvider: function (args) { @@ -16331,13 +16331,13 @@ noCompact: true, actions: { remove: { - label: 'Delete UCS Manager', + label: 'label.delete.ucs.manager', messages: { confirm: function (args) { - return 'Please confirm that you want to delete UCS Manager'; + return 'message.confirm.delete.ucs.manager'; }, notification: function (args) { - return 'Delete UCS Manager'; + return 'label.delete.ucs.manager'; } }, action: function (args) { @@ -16416,19 +16416,19 @@ }, blades: { - title: 'Blades', + title: 'label.blades', listView: { id: 'blades', hideSearchBar: true, fields: { chassis: { - label: 'Chassis' + label: 'label.chassis' }, bladeid: { - label: 'Blade ID' + label: 'label.blade.id' }, profiledn: { - label: 'Associated Profile' + label: 'label.associated.profile' } }, dataProvider: function (args) { @@ -16486,13 +16486,13 @@ actions: { refreshUcsBlades: { isHeader: true, - label: 'Refresh Blades', + label: 'label.refresh.blades', messages: { confirm: function (args) { - return 'Please confirm that you want to refresh blades.'; + return 'message.confirm.refresh.blades'; }, notification: function (args) { - return 'Refresh Blades'; + return 'label.refresh.blades'; } }, action: function (args) { @@ -16568,18 +16568,18 @@ }, associateTemplateToBlade: { - label: 'Instanciate Template and Associate Profile to Blade', + label: 'label.instanciate.template.associate.profile.blade', addRow: 'false', messages: { notification: function (args) { - return 'Instanciate Template and Associate Profile to Blade'; + return 'label.instanciate.template.associate.profile.blade'; } }, createForm: { - title: 'Instanciate Template and Associate Profile to Blade', + title: 'label.instanciate.template.associate.profile.blade', fields: { templatedn: { - label: 'Select Template', + label: 'label.select.template', select: function (args) { var items =[]; @@ -16626,7 +16626,7 @@ } }, profilename: { - label: 'Profile' + label: 'label.profile' } } }, @@ -16702,18 +16702,18 @@ }, disassociateProfileFromBlade: { - label: 'Disassociate Profile from Blade', + label: 'label.disassociate.profile.blade', addRow: 'false', messages: { notification: function (args) { - return 'Disassociate Profile from Blade'; + return 'label.disassociate.profile.blade'; } }, createForm: { - title: 'Disassociate Profile from Blade', + title: 'label.disassociate.profile.blade', fields: { deleteprofile: { - label: 'Delete Profile', + label: 'label.delete.profile', isBoolean: true, isChecked: true } @@ -16850,7 +16850,7 @@ label: 'label.name' }, provider: { - label: 'Provider', + label: 'label.provider', select: function (args) { /* UI no longer gets providers from "listStorageProviders&type=image" because: @@ -17020,7 +17020,7 @@ //NFS, SMB (begin) zoneid: { - label: 'Zone', + label: 'label.zone', docID: 'helpSecondaryStorageZone', validation: { required: true @@ -17145,7 +17145,7 @@ }, nfsCacheZoneid: { dependsOn: 'createNfsCache', - label: 'Zone', + label: 'label.zone', validation: { required: true }, @@ -17413,7 +17413,7 @@ }, detailView: { - name: 'Secondary storage details', + name: 'label.secondary.storage.details', isMaximized: true, actions: { remove: { @@ -17463,7 +17463,7 @@ label: 'label.protocol' }, providername: { - label: 'Provider' + label: 'label.provider' }, scope: { label: 'label.scope' @@ -17534,7 +17534,7 @@ }, cacheStorage: { type: 'select', - title: 'Secondary Staging Store', + title: 'label.secondary.staging.store', listView: { id: 'secondarystorages', section: 'seconary-storage', @@ -17546,7 +17546,7 @@ label: 'label.url' }, providername: { - label: 'Provider' + label: 'label.provider' } }, @@ -17582,12 +17582,12 @@ actions: { add: { - label: 'Add NFS Secondary Staging Store', + label: 'label.add.nfs.secondary.staging.store', createForm: { - title: 'Add NFS Secondary Staging Store', + title: 'label.add.nfs.secondary.staging.store', fields: { zoneid: { - label: 'Zone', + label: 'label.zone', validation: { required: true }, @@ -17660,24 +17660,24 @@ }, messages: { notification: function (args) { - return 'Add NFS Secondary Staging Store'; + return 'label.add.nfs.secondary.staging.store'; } } } }, detailView: { - name: 'Secondary Staging Store details', + name: 'label.secondary.staging.store.details', isMaximized: true, actions: { remove: { - label: 'Delete Secondary Staging Store', + label: 'label.delete.secondary.staging.store', messages: { confirm: function (args) { - return 'Please confirm you want to delete Secondary Staging Store.'; + return 'message.confirm.delete.secondary.staging.store'; }, notification: function (args) { - return 'Delete Secondary Staging Store'; + return 'label.delete.secondary.staging.store'; } }, action: function (args) { @@ -17796,16 +17796,16 @@ section: 'guest-IP-range', fields: { startip: { - label: 'IPv4 Start IP' + label: 'label.ipv4.start.ip' }, endip: { - label: 'IPv4 End IP' + label: 'label.ipv4.end.ip' }, startipv6: { - label: 'IPv6 Start IP' + label: 'label.ipv6.start.ip' }, endipv6: { - label: 'IPv6 End IP' + label: 'label.ipv6.end.ip' } }, @@ -17836,22 +17836,22 @@ label: 'label.netmask' }, startipv4: { - label: 'IPv4 Start IP' + label: 'label.ipv4.start.ip' }, endipv4: { - label: 'IPv4 End IP' + label: 'label.ipv4.end.ip' }, ip6cidr: { - label: 'IPv6 CIDR' + label: 'label.ipv6.CIDR' }, ip6gateway: { - label: 'IPv6 Gateway' + label: 'label.ipv6.gateway' }, startipv6: { - label: 'IPv6 Start IP' + label: 'label.ipv6.start.ip' }, endipv6: { - label: 'IPv6 End IP' + label: 'label.ipv6.end.ip' } } }, @@ -19260,8 +19260,8 @@ } nspHardcodingArray.push({ - id: "Ovs", - name: "Ovs", + id: 'OVS', + name: 'OVS', state: nspMap.Ovs ? nspMap.Ovs.state : 'Disabled' }); }; diff --git a/ui/scripts/templates.js b/ui/scripts/templates.js index 35516130482..7a45463d8a6 100644 --- a/ui/scripts/templates.js +++ b/ui/scripts/templates.js @@ -237,7 +237,7 @@ }, xenserverToolsVersion61plus: { - label: 'XenServer Tools Version 6.1+', + label: 'label.xenserver.tools.version.61.plus', isBoolean: true, isChecked: function (args) { var b = false; @@ -434,7 +434,7 @@ }, isdynamicallyscalable: { - label: "Dynamically Scalable", + label: "label.dynamically.scalable", docID: 'helpRegisterTemplateDynamicallyScalable', isBoolean: true }, @@ -951,7 +951,7 @@ label: 'label.hypervisor' }, xenserverToolsVersion61plus: { - label: 'XenServer Tools Version 6.1+', + label: 'label.xenserver.tools.version.61.plus', isBoolean: true, isEditable: function () { if (isAdmin()) diff --git a/ui/scripts/ui-custom/zoneChart.js b/ui/scripts/ui-custom/zoneChart.js index e847a199d8a..bc30d510539 100644 --- a/ui/scripts/ui-custom/zoneChart.js +++ b/ui/scripts/ui-custom/zoneChart.js @@ -24,7 +24,7 @@ */ var viewAllButton = function(args) { var $viewAll = $('
').addClass('button view-all'); - var $label = $('').addClass('view-all-label').html(args.label ? args.label : 'View all'); + var $label = $('').addClass('view-all-label').html(args.label ? args.label : 'label.view.all'); var $browser = args.$browser; var action = args.action; // Launch a list view @@ -111,46 +111,46 @@ // Resource items var computeResources = { zone: { - label: 'Zone' + label: 'label.zone' }, pods: { - label: 'Pods', + label: 'label.pods', viewAll: { action: actions.listView('pods', context) } }, clusters: { - label: 'Clusters', + label: 'label.clusters', viewAll: { action: actions.listView('clusters', context) } }, hosts: { - label: 'Hosts', + label: 'label.hosts', viewAll: { action: actions.listView('hosts', context) } }, primaryStorage: { - label: 'Primary Storage', + label: 'label.primary.storage', viewAll: { action: actions.listView('primary-storage', context) } }, ucs: { - label: 'UCS', + label: 'label.ucs', viewAll: { action: actions.listView('ucs', context) } }, secondaryStorage: { - label: 'Secondary Storage', + label: 'label.secondary.storage', viewAll: { action: actions.listView('secondary-storage', context) } diff --git a/ui/scripts/ui/core.js b/ui/scripts/ui/core.js index 06be12b7b6b..add7d06dedb 100644 --- a/ui/scripts/ui/core.js +++ b/ui/scripts/ui/core.js @@ -363,7 +363,7 @@ function(value, element) { return (value.indexOf("<") == -1 && value.indexOf(">") == -1); }, - jQuery.format("Disallowed characters: <, >") + jQuery.format('message.disallowed.characters') ); // Check for pending project invitations diff --git a/ui/scripts/ui/widgets/tagger.js b/ui/scripts/ui/widgets/tagger.js index 673bd43ce6a..3ffd80b8d84 100644 --- a/ui/scripts/ui/widgets/tagger.js +++ b/ui/scripts/ui/widgets/tagger.js @@ -22,7 +22,7 @@ if (!key || !value) { cloudStack.dialog.notice({ - message: 'Please specify a tag key and value' + message: 'message.specifiy.tag.key.value' }); return false; } @@ -42,7 +42,7 @@ var $valueField = $('
').addClass('field value'); var $valueLabel = $('
+ +
+
+ + +
+
+ + +
+
diff --git a/ui/scripts/instanceWizard.js b/ui/scripts/instanceWizard.js index 3ee9af1b9e4..5c04d0e1455 100644 --- a/ui/scripts/instanceWizard.js +++ b/ui/scripts/instanceWizard.js @@ -301,6 +301,7 @@ args.response.success({ customFlag: 'iscustomized', //customFlag: 'offerha', //for testing only + customIopsFlag: 'iscustomizediops', data: { serviceOfferings: serviceOfferingObjs } @@ -631,7 +632,20 @@ }); } } - + + if (args.$wizard.find('input[name=disk-min-iops]').parent().parent().css('display') != 'none') { + if (args.$wizard.find('input[name=disk-min-iops]').val().length > 0) { + $.extend(deployVmData, { + 'details[0].minIops' : args.$wizard.find('input[name=disk-min-iops]').val() + }); + } + if (args.$wizard.find('input[name=disk-max-iops]').val().length > 0) { + $.extend(deployVmData, { + 'details[0].maxIops' : args.$wizard.find('input[name=disk-max-iops]').val() + }); + } + } + //step 4: select disk offering if (args.data.diskofferingid != null && args.data.diskofferingid != "0") { $.extend(deployVmData, { diff --git a/ui/scripts/ui-custom/instanceWizard.js b/ui/scripts/ui-custom/instanceWizard.js index 8884ebe6ec8..f5f7b10cfaf 100644 --- a/ui/scripts/ui-custom/instanceWizard.js +++ b/ui/scripts/ui-custom/instanceWizard.js @@ -458,6 +458,14 @@ $step.removeClass('custom-size'); } + var customIops = item[args.customIopsFlag]; + + if (customIops) { + $step.addClass('custom-iops'); + } else { + $step.removeClass('custom-iops'); + } + return true; }); From 548c81082b377e87cc6ba18ac21fe297af8996c5 Mon Sep 17 00:00:00 2001 From: Mike Tutkowski Date: Fri, 7 Mar 2014 16:43:03 -0700 Subject: [PATCH 27/70] Adding license header --- .../com/cloud/offering/DiskOfferingInfo.java | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/api/src/com/cloud/offering/DiskOfferingInfo.java b/api/src/com/cloud/offering/DiskOfferingInfo.java index e9e7da1aff8..75a520e2d5a 100644 --- a/api/src/com/cloud/offering/DiskOfferingInfo.java +++ b/api/src/com/cloud/offering/DiskOfferingInfo.java @@ -1,3 +1,21 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ package com.cloud.offering; public class DiskOfferingInfo { From ded7e682dc0a84f41c9953522016a86f4948ea35 Mon Sep 17 00:00:00 2001 From: Nitin Mehta Date: Fri, 7 Mar 2014 16:50:21 -0800 Subject: [PATCH 28/70] CLOUDSTACK-5478: Enable publishing uuid for all the async apis in the CallContext. The advantage would be that event publishing can pick up the uuid and publish them. --- api/src/com/cloud/event/EventTypes.java | 5 +++++ server/src/com/cloud/api/ApiDispatcher.java | 7 +++++++ server/src/com/cloud/api/ApiServer.java | 11 ++++++++++- server/src/com/cloud/event/ActionEventUtils.java | 12 ++++++++---- server/src/com/cloud/vm/UserVmManagerImpl.java | 1 - 5 files changed, 30 insertions(+), 6 deletions(-) diff --git a/api/src/com/cloud/event/EventTypes.java b/api/src/com/cloud/event/EventTypes.java index ec54ea14521..7994adab82e 100755 --- a/api/src/com/cloud/event/EventTypes.java +++ b/api/src/com/cloud/event/EventTypes.java @@ -493,10 +493,13 @@ public class EventTypes { entityEventDetails.put(EVENT_VM_REBOOT, VirtualMachine.class.getName()); entityEventDetails.put(EVENT_VM_UPDATE, VirtualMachine.class.getName()); entityEventDetails.put(EVENT_VM_UPGRADE, VirtualMachine.class.getName()); + entityEventDetails.put(EVENT_VM_DYNAMIC_SCALE, VirtualMachine.class.getName()); entityEventDetails.put(EVENT_VM_RESETPASSWORD, VirtualMachine.class.getName()); + entityEventDetails.put(EVENT_VM_RESETSSHKEY, VirtualMachine.class.getName()); entityEventDetails.put(EVENT_VM_MIGRATE, VirtualMachine.class.getName()); entityEventDetails.put(EVENT_VM_MOVE, VirtualMachine.class.getName()); entityEventDetails.put(EVENT_VM_RESTORE, VirtualMachine.class.getName()); + entityEventDetails.put(EVENT_VM_EXPUNGE, VirtualMachine.class.getName()); entityEventDetails.put(EVENT_ROUTER_CREATE, VirtualRouter.class.getName()); entityEventDetails.put(EVENT_ROUTER_DESTROY, VirtualRouter.class.getName()); @@ -544,9 +547,11 @@ public class EventTypes { entityEventDetails.put(EVENT_LB_CERT_REMOVE, LoadBalancer.class.getName()); // Account events + entityEventDetails.put(EVENT_ACCOUNT_ENABLE, Account.class.getName()); entityEventDetails.put(EVENT_ACCOUNT_DISABLE, Account.class.getName()); entityEventDetails.put(EVENT_ACCOUNT_CREATE, Account.class.getName()); entityEventDetails.put(EVENT_ACCOUNT_DELETE, Account.class.getName()); + entityEventDetails.put(EVENT_ACCOUNT_UPDATE, Account.class.getName()); entityEventDetails.put(EVENT_ACCOUNT_MARK_DEFAULT_ZONE, Account.class.getName()); // UserVO Events diff --git a/server/src/com/cloud/api/ApiDispatcher.java b/server/src/com/cloud/api/ApiDispatcher.java index 5d4b4d3368c..8f980d99038 100755 --- a/server/src/com/cloud/api/ApiDispatcher.java +++ b/server/src/com/cloud/api/ApiDispatcher.java @@ -21,6 +21,7 @@ import java.util.Map; import javax.annotation.PostConstruct; import javax.inject.Inject; +import com.cloud.event.EventTypes; import org.apache.cloudstack.api.ApiConstants; import org.apache.cloudstack.api.BaseAsyncCmd; import org.apache.cloudstack.api.BaseAsyncCreateCmd; @@ -82,8 +83,14 @@ public class ApiDispatcher { final BaseAsyncCmd asyncCmd = (BaseAsyncCmd)cmd; final String startEventId = params.get(ApiConstants.CTX_START_EVENT_ID); + String uuid = params.get("uuid"); ctx.setStartEventId(Long.valueOf(startEventId)); + // Fow now use the key from EventTypes.java rather than getInstanceType bcz the later doesn't refer to the interfaces + if(EventTypes.getEntityForEvent(asyncCmd.getEventType()) != null){ + ctx.putContextParameter(EventTypes.getEntityForEvent(asyncCmd.getEventType()), uuid); + } + // Synchronise job on the object if needed if (asyncCmd.getJob() != null && asyncCmd.getSyncObjId() != null && asyncCmd.getSyncObjType() != null) { Long queueSizeLimit = null; diff --git a/server/src/com/cloud/api/ApiServer.java b/server/src/com/cloud/api/ApiServer.java index a9b1130eed1..7ad7c106952 100755 --- a/server/src/com/cloud/api/ApiServer.java +++ b/server/src/com/cloud/api/ApiServer.java @@ -53,6 +53,7 @@ import javax.naming.ConfigurationException; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; +import com.cloud.event.EventTypes; import org.apache.cloudstack.acl.APIChecker; import org.apache.cloudstack.api.APICommand; import org.apache.cloudstack.api.ApiConstants; @@ -517,6 +518,8 @@ public class ApiServer extends ManagerBase implements HttpRequestHandler, ApiSer objectUuid = createCmd.getEntityUuid(); params.put("id", objectId.toString()); } else { + // Extract the uuid before params are processed and id reflects internal db id + objectUuid = params.get("id"); dispatchChainFactory.getStandardDispatchChain().dispatch(new DispatchTask(cmdObj, params)); } @@ -528,10 +531,16 @@ public class ApiServer extends ManagerBase implements HttpRequestHandler, ApiSer if (caller != null) { params.put("ctxAccountId", String.valueOf(caller.getId())); } + if(objectUuid != null){ + params.put("uuid", objectUuid); + } long startEventId = ctx.getStartEventId(); asyncCmd.setStartEventId(startEventId); + if(EventTypes.getEntityForEvent(asyncCmd.getEventType()) != null){ + ctx.putContextParameter(EventTypes.getEntityForEvent(asyncCmd.getEventType()), objectUuid); + } // save the scheduled event final Long eventId = ActionEventUtils.onScheduledActionEvent((callerUserId == null) ? User.UID_SYSTEM : callerUserId, asyncCmd.getEntityOwnerId(), asyncCmd.getEventType(), @@ -577,7 +586,7 @@ public class ApiServer extends ManagerBase implements HttpRequestHandler, ApiSer !(cmdObj instanceof ListVolumesCmd) && !(cmdObj instanceof ListUsersCmd) && !(cmdObj instanceof ListAccountsCmd) && !(cmdObj instanceof ListStoragePoolsCmd) && !(cmdObj instanceof ListDiskOfferingsCmd) && !(cmdObj instanceof ListServiceOfferingsCmd) && !(cmdObj instanceof ListZonesByCmd)) { - buildAsyncListResponse((BaseListCmd)cmdObj, caller); + buildAsyncListResponse((BaseListCmd) cmdObj, caller); } SerializationContext.current().setUuidTranslation(true); diff --git a/server/src/com/cloud/event/ActionEventUtils.java b/server/src/com/cloud/event/ActionEventUtils.java index 9724d99e5e6..59546708bce 100755 --- a/server/src/com/cloud/event/ActionEventUtils.java +++ b/server/src/com/cloud/event/ActionEventUtils.java @@ -25,7 +25,6 @@ import java.util.Map; import javax.annotation.PostConstruct; import javax.inject.Inject; -import com.cloud.vm.VirtualMachine; import org.apache.log4j.Logger; import org.springframework.beans.factory.NoSuchBeanDefinitionException; @@ -186,13 +185,19 @@ public class ActionEventUtils { // get the entity details for which ActionEvent is generated String entityType = null; String entityUuid = null; + CallContext context = CallContext.current(); Class entityKey = getEntityKey(eventType); if (entityKey != null) { - CallContext context = CallContext.current(); + //FIXME - Remove this entityUuid = (String)context.getContextParameter(entityKey); if (entityUuid != null) entityType = entityKey.getName(); + }else if (EventTypes.getEntityForEvent(eventType) != null){ + entityType = EventTypes.getEntityForEvent(eventType); + if (entityType != null){ + entityUuid = (String)context.getContextParameter(entityType); + } } org.apache.cloudstack.framework.events.Event event = @@ -240,6 +245,7 @@ public class ActionEventUtils { private static Class getEntityKey(String eventType) { + // FIXME - Remove this if (eventType.startsWith("DOMAIN.")) { return Domain.class; @@ -251,8 +257,6 @@ public class ActionEventUtils { else if (eventType.startsWith("USER.")) { return User.class; - }else if (eventType.startsWith("VM.")){ - return VirtualMachine.class; } return null; diff --git a/server/src/com/cloud/vm/UserVmManagerImpl.java b/server/src/com/cloud/vm/UserVmManagerImpl.java index 9c38430ab1c..d1df3c11a61 100755 --- a/server/src/com/cloud/vm/UserVmManagerImpl.java +++ b/server/src/com/cloud/vm/UserVmManagerImpl.java @@ -2982,7 +2982,6 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir long vmId = cmd.getEntityId(); Long hostId = cmd.getHostId(); UserVmVO vm = _vmDao.findById(vmId); - CallContext.current().putContextParameter(VirtualMachine.class, vm.getUuid()); Pair> vmParamPair = null; try { From cb26b4c3375cdf4f8ecedf618f98e6b24a2cba6e Mon Sep 17 00:00:00 2001 From: Mike Tutkowski Date: Fri, 7 Mar 2014 22:20:38 -0700 Subject: [PATCH 29/70] CLOUDSTACK-6170 --- .../com/cloud/hypervisor/XenServerGuru.java | 33 +++++++++---------- 1 file changed, 16 insertions(+), 17 deletions(-) diff --git a/plugins/hypervisors/xen/src/com/cloud/hypervisor/XenServerGuru.java b/plugins/hypervisors/xen/src/com/cloud/hypervisor/XenServerGuru.java index 529e26125f3..059e6e4139a 100644 --- a/plugins/hypervisors/xen/src/com/cloud/hypervisor/XenServerGuru.java +++ b/plugins/hypervisors/xen/src/com/cloud/hypervisor/XenServerGuru.java @@ -34,7 +34,6 @@ import com.cloud.host.HostVO; import com.cloud.host.dao.HostDao; import com.cloud.hypervisor.Hypervisor.HypervisorType; import com.cloud.storage.GuestOSVO; -import com.cloud.storage.Volume; import com.cloud.storage.VolumeVO; import com.cloud.storage.dao.GuestOSDao; import com.cloud.storage.dao.VolumeDao; @@ -103,30 +102,30 @@ public class XenServerGuru extends HypervisorGuruBase implements HypervisorGuru List volumes = _volumeDao.findByInstance(vm.getId()); + // it's OK in this case to send a detach command to the host for a root volume as this + // will simply lead to the SR that supports the root volume being removed if (volumes != null) { for (VolumeVO volume : volumes) { - if (volume.getVolumeType() == Volume.Type.DATADISK) { - StoragePoolVO storagePool = _storagePoolDao.findById(volume.getPoolId()); + StoragePoolVO storagePool = _storagePoolDao.findById(volume.getPoolId()); - // storagePool should be null if we are expunging a volume that was never - // attached to a VM that was started (the "trick" for storagePool to be null - // is that none of the VMs this volume may have been attached to were ever started, - // so the volume was never assigned to a storage pool) - if (storagePool != null && storagePool.isManaged()) { - DataTO volTO = _volFactory.getVolume(volume.getId()).getTO(); - DiskTO disk = new DiskTO(volTO, volume.getDeviceId(), volume.getPath(), volume.getVolumeType()); + // storagePool should be null if we are expunging a volume that was never + // attached to a VM that was started (the "trick" for storagePool to be null + // is that none of the VMs this volume may have been attached to were ever started, + // so the volume was never assigned to a storage pool) + if (storagePool != null && storagePool.isManaged()) { + DataTO volTO = _volFactory.getVolume(volume.getId()).getTO(); + DiskTO disk = new DiskTO(volTO, volume.getDeviceId(), volume.getPath(), volume.getVolumeType()); - DettachCommand cmd = new DettachCommand(disk, vm.getInstanceName()); + DettachCommand cmd = new DettachCommand(disk, vm.getInstanceName()); - cmd.setManaged(true); + cmd.setManaged(true); - cmd.setStorageHost(storagePool.getHostAddress()); - cmd.setStoragePort(storagePool.getPort()); + cmd.setStorageHost(storagePool.getHostAddress()); + cmd.setStoragePort(storagePool.getPort()); - cmd.set_iScsiName(volume.get_iScsiName()); + cmd.set_iScsiName(volume.get_iScsiName()); - commands.add(cmd); - } + commands.add(cmd); } } } From 09c375379ddae2d85ce9549bb6a58860c53bfecd Mon Sep 17 00:00:00 2001 From: John Kinsella Date: Sun, 9 Mar 2014 13:46:57 -0700 Subject: [PATCH 30/70] CLOUDSTACK-6204: removing realhostip dependency Moving default transport for console proxy, SSVM to http. See https://cwiki.apache.org/confluence/display/CLOUDSTACK/Realhost+IP+changes for more info. jlk ported Amogh's patch for 4.3 to master - code base is different enough that patch has multiple issues. Author: Amogh Vasekar Signed-off-by: John Kinsella 1394398017 -0700 --- core/src/com/cloud/info/ConsoleProxyInfo.java | 19 ++++++++++--------- .../storage/image/TemplateServiceImpl.java | 13 +++++++++++-- .../CloudStackImageStoreDriverImpl.java | 12 ++++++++---- .../src/com/cloud/configuration/Config.java | 4 ++-- .../consoleproxy/ConsoleProxyManagerImpl.java | 11 +++++++++-- .../SecondaryStorageManagerImpl.java | 7 +++++++ setup/db/db/schema-421to430.sql | 4 ++++ systemvm/conf/consoleproxy.properties | 2 +- 8 files changed, 52 insertions(+), 20 deletions(-) diff --git a/core/src/com/cloud/info/ConsoleProxyInfo.java b/core/src/com/cloud/info/ConsoleProxyInfo.java index 9a94474efda..0e57b7551fc 100644 --- a/core/src/com/cloud/info/ConsoleProxyInfo.java +++ b/core/src/com/cloud/info/ConsoleProxyInfo.java @@ -32,16 +32,17 @@ public class ConsoleProxyInfo { this.sslEnabled = sslEnabled; if (sslEnabled) { - StringBuffer sb = new StringBuffer(proxyIpAddress); - for (int i = 0; i < sb.length(); i++) - if (sb.charAt(i) == '.') - sb.setCharAt(i, '-'); - if (consoleProxyUrlDomain != null && consoleProxyUrlDomain.length() > 0) { - sb.append("."); + StringBuffer sb = new StringBuffer(); + if (consoleProxyUrlDomain.startsWith("*")) { + sb.append(proxyIpAddress); + for (int i = 0; i < proxyIpAddress.length(); i++) + if (sb.charAt(i) == '.') + sb.setCharAt(i, '-'); + sb.append(consoleProxyUrlDomain.substring(1));//skip the * + } else { + //LB address sb.append(consoleProxyUrlDomain); - } else - sb.append(".realhostip.com"); - + } proxyAddress = sb.toString(); proxyPort = port; this.proxyUrlPort = proxyUrlPort; diff --git a/engine/storage/image/src/org/apache/cloudstack/storage/image/TemplateServiceImpl.java b/engine/storage/image/src/org/apache/cloudstack/storage/image/TemplateServiceImpl.java index 166b523e387..4e6ab6ba300 100644 --- a/engine/storage/image/src/org/apache/cloudstack/storage/image/TemplateServiceImpl.java +++ b/engine/storage/image/src/org/apache/cloudstack/storage/image/TemplateServiceImpl.java @@ -777,12 +777,21 @@ public class TemplateServiceImpl implements TemplateService { String scheme = "http"; boolean _sslCopy = false; String sslCfg = _configDao.getValue(Config.SecStorageEncryptCopy.toString()); + String _ssvmUrlDomain = _configDao.getValue("secstorage.ssl.cert.domain"); if (sslCfg != null) { _sslCopy = Boolean.parseBoolean(sslCfg); } + if(_sslCopy && (_ssvmUrlDomain == null || _ssvmUrlDomain.isEmpty())){ + s_logger.warn("Empty secondary storage url domain, ignoring SSL"); + _sslCopy = false; + } if (_sslCopy) { - hostname = ipAddress.replace(".", "-"); - hostname = hostname + ".realhostip.com"; + if(_ssvmUrlDomain.startsWith("*")) { + hostname = ipAddress.replace(".", "-"); + hostname = hostname + _ssvmUrlDomain.substring(1); + } else { + hostname = _ssvmUrlDomain; + } scheme = "https"; } return scheme + "://" + hostname + "/copy/SecStorage/" + dir + "/" + path; diff --git a/plugins/storage/image/default/src/org/apache/cloudstack/storage/datastore/driver/CloudStackImageStoreDriverImpl.java b/plugins/storage/image/default/src/org/apache/cloudstack/storage/datastore/driver/CloudStackImageStoreDriverImpl.java index d6e1a01b49c..c2e26d52f65 100644 --- a/plugins/storage/image/default/src/org/apache/cloudstack/storage/datastore/driver/CloudStackImageStoreDriverImpl.java +++ b/plugins/storage/image/default/src/org/apache/cloudstack/storage/datastore/driver/CloudStackImageStoreDriverImpl.java @@ -93,12 +93,16 @@ public class CloudStackImageStoreDriverImpl extends BaseImageStoreDriverImpl { if (sslCfg != null) { _sslCopy = Boolean.parseBoolean(sslCfg); } + if(_sslCopy && (_ssvmUrlDomain == null || _ssvmUrlDomain.isEmpty())){ + s_logger.warn("Empty secondary storage url domain, ignoring SSL"); + _sslCopy = false; + } if (_sslCopy) { - hostname = ipAddress.replace(".", "-"); - if (_ssvmUrlDomain != null && _ssvmUrlDomain.length() > 0) { - hostname = hostname + "." + _ssvmUrlDomain; + if(_ssvmUrlDomain.startsWith("*")) { + hostname = ipAddress.replace(".", "-"); + hostname = hostname + _ssvmUrlDomain.substring(1); } else { - hostname = hostname + ".realhostip.com"; + hostname = _ssvmUrlDomain; } scheme = "https"; } diff --git a/server/src/com/cloud/configuration/Config.java b/server/src/com/cloud/configuration/Config.java index 98e5d3424a2..f2fe68a78a9 100755 --- a/server/src/com/cloud/configuration/Config.java +++ b/server/src/com/cloud/configuration/Config.java @@ -439,7 +439,7 @@ public enum Config { "Console proxy command port that is used to communicate with management server", null), ConsoleProxyRestart("Console Proxy", AgentManager.class, Boolean.class, "consoleproxy.restart", "true", "Console proxy restart flag, defaulted to true", null), - ConsoleProxyUrlDomain("Console Proxy", AgentManager.class, String.class, "consoleproxy.url.domain", "realhostip.com", "Console proxy url domain", null), + ConsoleProxyUrlDomain("Console Proxy", AgentManager.class, String.class, "consoleproxy.url.domain", "", "Console proxy url domain", null), ConsoleProxyLoadscanInterval( "Console Proxy", AgentManager.class, @@ -782,7 +782,7 @@ public enum Config { ManagementServer.class, String.class, "secstorage.ssl.cert.domain", - "realhostip.com", + "", "SSL certificate used to encrypt copy traffic between zones", null), SecStorageCapacityStandby( diff --git a/server/src/com/cloud/consoleproxy/ConsoleProxyManagerImpl.java b/server/src/com/cloud/consoleproxy/ConsoleProxyManagerImpl.java index 3e4c57e6852..05120963961 100755 --- a/server/src/com/cloud/consoleproxy/ConsoleProxyManagerImpl.java +++ b/server/src/com/cloud/consoleproxy/ConsoleProxyManagerImpl.java @@ -233,6 +233,7 @@ public class ConsoleProxyManagerImpl extends ManagerBase implements ConsoleProxy private int _proxySessionTimeoutValue = DEFAULT_PROXY_SESSION_TIMEOUT; private boolean _sslEnabled = true; + private String _consoleProxyUrlDomain; // global load picture at zone basis private SystemVmLoadScanner _loadScanner; @@ -384,9 +385,9 @@ public class ConsoleProxyManagerImpl extends ManagerBase implements ConsoleProxy assert (ksVo != null); if (_staticPublicIp == null) { - return new ConsoleProxyInfo(proxy.isSslEnabled(), proxy.getPublicIpAddress(), _consoleProxyPort, proxy.getPort(), ksVo.getDomainSuffix()); + return new ConsoleProxyInfo(proxy.isSslEnabled(), proxy.getPublicIpAddress(), _consoleProxyPort, proxy.getPort(), _consoleProxyUrlDomain); } else { - return new ConsoleProxyInfo(proxy.isSslEnabled(), _staticPublicIp, _consoleProxyPort, _staticPort, ksVo.getDomainSuffix()); + return new ConsoleProxyInfo(proxy.isSslEnabled(), _staticPublicIp, _consoleProxyPort, _staticPort, _consoleProxyUrlDomain); } } @@ -1191,6 +1192,12 @@ public class ConsoleProxyManagerImpl extends ManagerBase implements ConsoleProxy _sslEnabled = true; } + _consoleProxyUrlDomain = configs.get(Config.ConsoleProxyUrlDomain.key()); + if( _sslEnabled && (_consoleProxyUrlDomain == null || _consoleProxyUrlDomain.isEmpty())) { + s_logger.warn("Empty console proxy domain, explicitly disabling SSL"); + _sslEnabled = false; + } + value = configs.get(Config.ConsoleProxyCapacityScanInterval.key()); _capacityScanInterval = NumbersUtil.parseLong(value, DEFAULT_CAPACITY_SCAN_INTERVAL); diff --git a/services/secondary-storage/controller/src/org/apache/cloudstack/secondarystorage/SecondaryStorageManagerImpl.java b/services/secondary-storage/controller/src/org/apache/cloudstack/secondarystorage/SecondaryStorageManagerImpl.java index dd0c26774d2..f8edefa39a1 100755 --- a/services/secondary-storage/controller/src/org/apache/cloudstack/secondarystorage/SecondaryStorageManagerImpl.java +++ b/services/secondary-storage/controller/src/org/apache/cloudstack/secondarystorage/SecondaryStorageManagerImpl.java @@ -807,6 +807,13 @@ public class SecondaryStorageManagerImpl extends ManagerBase implements Secondar _useSSlCopy = true; } + //default to HTTP in case of missing domain + String ssvmUrlDomain = _configDao.getValue("secstorage.ssl.cert.domain"); + if(_useSSlCopy && (ssvmUrlDomain == null || ssvmUrlDomain.isEmpty())){ + s_logger.warn("Empty secondary storage url domain, explicitly disabling SSL"); + _useSSlCopy = false; + } + _allowedInternalSites = _configDao.getValue("secstorage.allowed.internal.sites"); String value = configs.get("secstorage.capacityscan.interval"); diff --git a/setup/db/db/schema-421to430.sql b/setup/db/db/schema-421to430.sql index b49fd965fb7..3f2ad023d26 100644 --- a/setup/db/db/schema-421to430.sql +++ b/setup/db/db/schema-421to430.sql @@ -110,6 +110,10 @@ CREATE TABLE `cloud`.`async_job_join_map` ( INDEX `i_async_job_join_map__expiration`(`expiration`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; +#realhostip changes, before changing table and adding default value +UPDATE `cloud`.`configuration` SET value = CONCAT("*.",(SELECT `temptable`.`value` FROM (SELECT * FROM `cloud`.`configuration` WHERE `name`="consoleproxy.url.domain") AS `temptable` WHERE `temptable`.`name`="consoleproxy.url.domain")) WHERE `name`="consoleproxy.url.domain"; +UPDATE `cloud`.`configuration` SET `value` = CONCAT("*.",(SELECT `temptable`.`value` FROM (SELECT * FROM `cloud`.`configuration` WHERE `name`="secstorage.ssl.cert.domain") AS `temptable` WHERE `temptable`.`name`="secstorage.ssl.cert.domain")) WHERE `name`="secstorage.ssl.cert.domain"; + ALTER TABLE `cloud`.`configuration` ADD COLUMN `default_value` VARCHAR(4095) COMMENT 'Default value for a configuration parameter'; ALTER TABLE `cloud`.`configuration` ADD COLUMN `updated` datetime COMMENT 'Time this was updated by the server. null means this row is obsolete.'; ALTER TABLE `cloud`.`configuration` ADD COLUMN `scope` VARCHAR(255) DEFAULT NULL COMMENT 'Can this parameter be scoped'; diff --git a/systemvm/conf/consoleproxy.properties b/systemvm/conf/consoleproxy.properties index bb452f5823c..a3cddbcab96 100644 --- a/systemvm/conf/consoleproxy.properties +++ b/systemvm/conf/consoleproxy.properties @@ -16,7 +16,7 @@ # under the License. consoleproxy.tcpListenPort=0 -consoleproxy.httpListenPort=8088 +consoleproxy.httpListenPort=80 consoleproxy.httpCmdListenPort=8001 consoleproxy.jarDir=./applet/ consoleproxy.viewerLinger=180 From 3b3ae024591fae4db9a6ca991d4838d98b96154e Mon Sep 17 00:00:00 2001 From: Gaurav Aradhye Date: Thu, 6 Mar 2014 21:38:41 -0500 Subject: [PATCH 31/70] CLOUDSTACK-5626: Simplifying VM Migrate code Signed-off-by: SrikanteswaraRao Talluri --- .../component/test_cpu_domain_limits.py | 11 +- test/integration/component/test_cpu_limits.py | 15 ++- .../component/test_cpu_project_limits.py | 7 +- .../component/test_memory_limits.py | 15 ++- .../component/test_mm_domain_limits.py | 7 +- .../component/test_mm_project_limits.py | 7 +- .../component/test_vpc_vm_life_cycle.py | 108 +++--------------- tools/marvin/marvin/codes.py | 1 + tools/marvin/marvin/integration/lib/common.py | 25 ++-- 9 files changed, 80 insertions(+), 116 deletions(-) diff --git a/test/integration/component/test_cpu_domain_limits.py b/test/integration/component/test_cpu_domain_limits.py index c427e4fcf41..1247a799c89 100644 --- a/test/integration/component/test_cpu_domain_limits.py +++ b/test/integration/component/test_cpu_domain_limits.py @@ -30,10 +30,11 @@ from marvin.integration.lib.base import ( from marvin.integration.lib.common import (get_domain, get_zone, get_template, - find_suitable_host, + findSuitableHostForMigration, get_resource_type ) from marvin.integration.lib.utils import cleanup_resources +from marvin.codes import ERROR_NO_HOST_FOR_MIGRATION class Services: """Test resource limit services @@ -329,7 +330,9 @@ class TestDomainCPULimitsUpdateResources(cloudstackTestCase): self.assertEqual(resource_count, expected_resource_count, "Initial resource count should match with the expected resource count") - host = find_suitable_host(self.apiclient, vm) + host = findSuitableHostForMigration(self.apiclient, vm.id) + if host is None: + self.skipTest(ERROR_NO_HOST_FOR_MIGRATION) self.debug("Migrating instance: %s to host: %s" % (vm.name, host.name)) try: @@ -477,7 +480,9 @@ class TestDomainCPULimitsUpdateResources(cloudstackTestCase): self.assertEqual(resource_count_after_delete, expected_resource_count, "Resource count should match with the expected count") - host = find_suitable_host(self.apiclient, vm_2) + host = findSuitableHostForMigration(self.apiclient, vm_2.id) + if host is None: + self.skipTest(ERROR_NO_HOST_FOR_MIGRATION) self.debug("Migrating instance: %s to host: %s" % (vm_2.name, host.name)) try: diff --git a/test/integration/component/test_cpu_limits.py b/test/integration/component/test_cpu_limits.py index bdf2869c7c1..f043773e7b1 100644 --- a/test/integration/component/test_cpu_limits.py +++ b/test/integration/component/test_cpu_limits.py @@ -30,10 +30,11 @@ from marvin.integration.lib.base import ( from marvin.integration.lib.common import (get_domain, get_zone, get_template, - find_suitable_host, + findSuitableHostForMigration, get_resource_type ) from marvin.integration.lib.utils import cleanup_resources +from marvin.codes import ERROR_NO_HOST_FOR_MIGRATION class Services: @@ -251,7 +252,9 @@ class TestCPULimits(cloudstackTestCase): self.assertEqual(resource_count, expected_resource_count, "Resource count should match with the expected resource count") - host = find_suitable_host(self.apiclient, self.vm) + host = findSuitableHostForMigration(self.apiclient, self.vm.id) + if host is None: + self.skipTest(ERROR_NO_HOST_FOR_MIGRATION) self.debug("Migrating instance: %s to host: %s" % (self.vm.name, host.name)) try: self.vm.migrate(self.apiclient, host.id) @@ -570,7 +573,9 @@ class TestDomainCPULimitsConfiguration(cloudstackTestCase): self.assertEqual(resource_count, expected_resource_count, "Initial resource count should with the expected resource count") - host = find_suitable_host(self.apiclient, vm) + host = findSuitableHostForMigration(self.apiclient, vm.id) + if host is None: + self.skipTest(ERROR_NO_HOST_FOR_MIGRATION) self.debug("Migrating instance: %s to host: %s" % (vm.name, host.name)) try: @@ -725,7 +730,9 @@ class TestDomainCPULimitsConfiguration(cloudstackTestCase): self.assertEqual(resource_count_after_delete, expected_resource_count, "Resource count should be less than before after deleting the instance") - host = find_suitable_host(self.apiclient, vm_2) + host = findSuitableHostForMigration(self.apiclient, vm_2.id) + if host is None: + self.skipTest(ERROR_NO_HOST_FOR_MIGRATION) self.debug("Migrating instance: %s to host: %s" % (vm_2.name, host.name)) try: diff --git a/test/integration/component/test_cpu_project_limits.py b/test/integration/component/test_cpu_project_limits.py index a8a1b3c3b24..ed7cd88248a 100644 --- a/test/integration/component/test_cpu_project_limits.py +++ b/test/integration/component/test_cpu_project_limits.py @@ -30,10 +30,11 @@ from marvin.integration.lib.base import ( from marvin.integration.lib.common import (get_domain, get_zone, get_template, - find_suitable_host, + findSuitableHostForMigration, get_resource_type ) from marvin.integration.lib.utils import cleanup_resources +from marvin.codes import ERROR_NO_HOST_FOR_MIGRATION class Services: """Test resource limit services @@ -291,7 +292,9 @@ class TestProjectsCPULimits(cloudstackTestCase): self.assertEqual(resource_count, expected_resource_count, "Resource count should match with the expected resource count") - host = find_suitable_host(self.apiclient, self.vm) + host = findSuitableHostForMigration(self.apiclient, self.vm.id) + if host is None: + self.skipTest(ERROR_NO_HOST_FOR_MIGRATION) self.debug("Migrating instance: %s to host: %s" % (self.vm.name, host.name)) try: diff --git a/test/integration/component/test_memory_limits.py b/test/integration/component/test_memory_limits.py index 7921e4be9ed..231307f693e 100644 --- a/test/integration/component/test_memory_limits.py +++ b/test/integration/component/test_memory_limits.py @@ -30,10 +30,11 @@ from marvin.integration.lib.common import (get_domain, get_zone, get_template, wait_for_cleanup, - find_suitable_host, + findSuitableHostForMigration, get_resource_type ) from marvin.integration.lib.utils import cleanup_resources +from marvin.codes import ERROR_NO_HOST_FOR_MIGRATION class Services: """Test memory resource limit services @@ -248,7 +249,9 @@ class TestMemoryLimits(cloudstackTestCase): self.assertEqual(resource_count, expected_resource_count, "Resource count should match with the expected resource count") - host = find_suitable_host(self.apiclient, self.vm) + host = findSuitableHostForMigration(self.apiclient, self.vm.id) + if host is None: + self.skipTest(ERROR_NO_HOST_FOR_MIGRATION) self.debug("Migrating instance: %s to host: %s" % (self.vm.name, host.name)) try: self.vm.migrate(self.apiclient, host.id) @@ -587,7 +590,9 @@ class TestDomainMemoryLimitsConfiguration(cloudstackTestCase): self.assertEqual(resource_count, expected_resource_count, "Initial resource count should with the expected resource count") - host = find_suitable_host(self.apiclient, vm) + host = findSuitableHostForMigration(self.apiclient, vm.id) + if host is None: + self.skipTest(ERROR_NO_HOST_FOR_MIGRATION) self.debug("Migrating instance: %s to host: %s" % (vm.name, host.name)) try: @@ -743,7 +748,9 @@ class TestDomainMemoryLimitsConfiguration(cloudstackTestCase): self.assertEqual(resource_count_after_delete, expected_resource_count, "Resource count should match with the expected resource count") - host = find_suitable_host(self.apiclient, vm_2) + host = findSuitableHostForMigration(self.apiclient, vm_2.id) + if host is None: + self.skipTest(ERROR_NO_HOST_FOR_MIGRATION) self.debug("Migrating instance: %s to host: %s" % (vm_2.name, host.name)) try: diff --git a/test/integration/component/test_mm_domain_limits.py b/test/integration/component/test_mm_domain_limits.py index 68660c13cf5..a2b7395cd13 100644 --- a/test/integration/component/test_mm_domain_limits.py +++ b/test/integration/component/test_mm_domain_limits.py @@ -30,11 +30,12 @@ from marvin.integration.lib.common import (get_domain, get_zone, get_template, wait_for_cleanup, - find_suitable_host, + findSuitableHostForMigration, get_resource_type, update_resource_count ) from marvin.integration.lib.utils import cleanup_resources +from marvin.codes import ERROR_NO_HOST_FOR_MIGRATION class Services: """Test memory resource limit services @@ -388,7 +389,9 @@ class TestDomainMemoryLimits(cloudstackTestCase): self.assertEqual(resource_count, expected_resource_count, "Resource count should match with the expected resource count") - host = find_suitable_host(self.apiclient, vm) + host = findSuitableHostForMigration(self.apiclient, vm.id) + if host is None: + self.skipTest(ERROR_NO_HOST_FOR_MIGRATION) self.debug("Migrating instance: %s to host: %s" % (vm.name, host.name)) try: diff --git a/test/integration/component/test_mm_project_limits.py b/test/integration/component/test_mm_project_limits.py index c314011090c..29a3b549729 100644 --- a/test/integration/component/test_mm_project_limits.py +++ b/test/integration/component/test_mm_project_limits.py @@ -30,10 +30,11 @@ from marvin.integration.lib.common import (get_domain, get_zone, get_template, wait_for_cleanup, - find_suitable_host, + findSuitableHostForMigration, get_resource_type ) from marvin.integration.lib.utils import cleanup_resources +from marvin.codes import ERROR_NO_HOST_FOR_MIGRATION class Services: """Test memory resource limit services @@ -291,7 +292,9 @@ class TestProjectsMemoryLimits(cloudstackTestCase): resource_count = project_list[0].memorytotal self.debug(resource_count) - host = find_suitable_host(self.apiclient, self.vm) + host = findSuitableHostForMigration(self.apiclient, self.vm.id) + if host is None: + self.skipTest(ERROR_NO_HOST_FOR_MIGRATION) self.debug("Migrating instance: %s to host: %s" % (self.vm.name, host.name)) try: diff --git a/test/integration/component/test_vpc_vm_life_cycle.py b/test/integration/component/test_vpc_vm_life_cycle.py index 01373ac5a73..e40067ea86d 100644 --- a/test/integration/component/test_vpc_vm_life_cycle.py +++ b/test/integration/component/test_vpc_vm_life_cycle.py @@ -41,9 +41,10 @@ from marvin.integration.lib.common import (get_domain, get_free_vlan, wait_for_cleanup, list_virtual_machines, - list_hosts) + list_hosts, + findSuitableHostForMigration) -from marvin.codes import PASS +from marvin.codes import PASS, ERROR_NO_HOST_FOR_MIGRATION import time @@ -715,35 +716,13 @@ class TestVMLifeCycleVPC(cloudstackTestCase): # works as expected. # 3. Make sure that we are able to access google.com from this user Vm - vm_list = VirtualMachine.list(self.apiclient, id=self.vm_1.id) - self.assertEqual(validateList(vm_list)[0], PASS, "vm list validation failed, vm list is %s" % vm_list) - - vm_hostid = vm_list[0].hostid - - self.debug("Checking if the host is available for migration?") - hosts = Host.list( - self.apiclient, - zoneid=self.zone.id, - type='Routing' - ) - - self.assertEqual( - isinstance(hosts, list), - True, - "List hosts should return a valid list" - ) - if len(hosts) < 2: - raise unittest.SkipTest( - "No host available for migration. Test requires atleast 2 hosts") - - # Remove the host of current VM from the hosts list - hosts[:] = [host for host in hosts if host.id != vm_hostid] - - host = hosts[0] - self.debug("Validating if the network rules work properly or not?") self.validate_network_rules() + host = findSuitableHostForMigration(self.apiclient, self.vm_1.id) + if host is None: + self.skipTest(ERROR_NO_HOST_FOR_MIGRATION) + self.debug("Migrating VM-ID: %s to Host: %s" % ( self.vm_1.id, host.id @@ -1506,30 +1485,13 @@ class TestVMLifeCycleSharedNwVPC(cloudstackTestCase): # works as expected. # 3. Make sure that we are able to access google.com from this user Vm - self.debug("Checking if the host is available for migration?") - hosts = Host.list( - self.apiclient, - zoneid=self.zone.id, - type='Routing' - ) - - self.assertEqual( - isinstance(hosts, list), - True, - "List hosts should return a valid list" - ) - if len(hosts) < 2: - raise unittest.SkipTest( - "No host available for migration. Test requires atleast 2 hosts") - - # Remove the host of current VM from the hosts list - hosts[:] = [host for host in hosts if host.id != self.vm_1.hostid] - - host = hosts[0] - self.debug("Validating if network rules are coonfigured properly?") self.validate_network_rules() + host = findSuitableHostForMigration(self.apiclient, self.vm_1.id) + if host is None: + self.skipTest(ERROR_NO_HOST_FOR_MIGRATION) + self.debug("Migrating VM-ID: %s to Host: %s" % ( self.vm_1.id, host.id @@ -2559,30 +2521,13 @@ class TestVMLifeCycleStoppedVPCVR(cloudstackTestCase): # works as expected. # 3. Make sure that we are able to access google.com from this user Vm - self.debug("Checking if the host is available for migration?") - hosts = Host.list( - self.apiclient, - zoneid=self.zone.id, - type='Routing' - ) - - self.assertEqual( - isinstance(hosts, list), - True, - "List hosts should return a valid list" - ) - if len(hosts) < 2: - raise unittest.SkipTest( - "No host available for migration. Test requires atleast 2 hosts") - - # Remove the host of current VM from the hosts list - hosts[:] = [host for host in hosts if host.id != self.vm_1.hostid] - - host = hosts[0] - self.debug("Validating if the network rules work properly or not?") self.validate_network_rules() + host = findSuitableHostForMigration(self.apiclient, self.vm_1.id) + if host is None: + self.skipTest(ERROR_NO_HOST_FOR_MIGRATION) + self.debug("Migrating VM-ID: %s on Host: %s to Host: %s" % ( self.vm_1.id, self.vm_1.hostid, @@ -3459,28 +3404,13 @@ class TestVMLifeCycleDiffHosts(cloudstackTestCase): # works as expected. # 3. Make sure that we are able to access google.com from this user Vm - self.debug("Checking if the host is available for migration?") - hosts = Host.listForMigration( - self.apiclient, - virtualmachineid=self.vm_1.id, - ) - self.debug("Hosts vm can be migrated to are : %s" %(hosts)) - self.assertEqual( - isinstance(hosts, list), - True, - "List hosts should return a valid list" - ) - # Remove the host of current VM from the hosts list - hosts[:] = [host for host in hosts if host.id != self.vm_1.hostid] - if len(hosts) <= 0: - self.skipTest( - "No host available for migration. Test requires atleast 2 hosts tagged with host1") - - host = hosts[0] - self.debug("Validating if the network rules work properly or not?") self.validate_network_rules() + host = findSuitableHostForMigration(self.apiclient, self.vm_1.id) + if host is None: + self.skipTest(ERROR_NO_HOST_FOR_MIGRATION) + self.debug("Migrating VM-ID: %s to Host: %s" % ( self.vm_1.id, host.id diff --git a/tools/marvin/marvin/codes.py b/tools/marvin/marvin/codes.py index 3882f0d59b8..e4a0f6a789a 100644 --- a/tools/marvin/marvin/codes.py +++ b/tools/marvin/marvin/codes.py @@ -51,3 +51,4 @@ BASIC_ZONE = "basic" ISOLATED_NETWORK = "ISOLATED" SHARED_NETWORK = "SHARED" VPC_NETWORK = "VPC" +ERROR_NO_HOST_FOR_MIGRATION = "Could not find suitable host for migration, please ensure setup has required no. of hosts" diff --git a/tools/marvin/marvin/integration/lib/common.py b/tools/marvin/marvin/integration/lib/common.py index b2da3ffef24..d3d634b72c0 100644 --- a/tools/marvin/marvin/integration/lib/common.py +++ b/tools/marvin/marvin/integration/lib/common.py @@ -712,18 +712,23 @@ def update_resource_count(apiclient, domainid, accountid=None, ) return -def find_suitable_host(apiclient, vm): - """Returns a suitable host for VM migration""" +def findSuitableHostForMigration(apiclient, vmid): + """Returns a suitable host for VM migration""" + suitableHost = None + try: + hosts = Host.listForMigration(apiclient, virtualmachineid=vmid, + ) + except Exception as e: + raise Exception("Exception while getting hosts list suitable for migration: %s" % e) - hosts = Host.list(apiclient, - virtualmachineid=vm.id, - listall=True) + suitablehosts = [] + if isinstance(hosts, list) and len(hosts) > 0: + suitablehosts = [host for host in hosts if (str(host.resourcestate).lower() == "enabled"\ + and str(host.state).lower() == "up")] + if len(suitablehosts)>0: + suitableHost = suitablehosts[0] - if isinstance(hosts, list): - assert len(hosts) > 0, "List host should return valid response" - else: - raise Exception("Exception: List host should return valid response") - return hosts[0] + return suitableHost def get_resource_type(resource_id): """Returns resource type""" From 3f7b628c707cd9c30542efd670416be5fbb473f0 Mon Sep 17 00:00:00 2001 From: Gaurav Aradhye Date: Fri, 28 Feb 2014 01:46:24 -0500 Subject: [PATCH 32/70] CLOUDSTACK-6147: Adding first set of test caess for Dynamic Compute Offering feature Signed-off-by: SrikanteswaraRao Talluri --- .../test_dynamic_compute_offering.py | 409 ++++++++++++++++++ tools/marvin/marvin/integration/lib/base.py | 29 +- tools/marvin/marvin/integration/lib/common.py | 14 + 3 files changed, 451 insertions(+), 1 deletion(-) create mode 100644 test/integration/component/test_dynamic_compute_offering.py diff --git a/test/integration/component/test_dynamic_compute_offering.py b/test/integration/component/test_dynamic_compute_offering.py new file mode 100644 index 00000000000..75cf0d658f4 --- /dev/null +++ b/test/integration/component/test_dynamic_compute_offering.py @@ -0,0 +1,409 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. + +""" Tests for Dynamic Compute Offering Feature + + Test Plan: https://cwiki.apache.org/confluence/display/CLOUDSTACK/Dynamic+ComputeOffering + + Issue Link: https://issues.apache.org/jira/browse/CLOUDSTACK-6147 + + Feature Specifications: https://cwiki.apache.org/confluence/display/CLOUDSTACK/Dynamic+Compute+Offering+FS +""" +from marvin.cloudstackTestCase import cloudstackTestCase +from marvin.integration.lib.utils import (cleanup_resources, + validateList) +from marvin.integration.lib.base import (ServiceOffering, + VirtualMachine, + Account) +from marvin.integration.lib.common import (get_domain, + get_zone, + get_template, + verifyComputeOfferingCreation) + +from nose.plugins.attrib import attr +from marvin.codes import PASS, ADMIN_ACCOUNT, USER_ACCOUNT +from ddt import ddt, data + +@ddt +class TestDynamicServiceOffering(cloudstackTestCase): + """Test Dynamic Service Offerings + """ + + @classmethod + def setUpClass(cls): + cloudstackTestClient = super(TestDynamicServiceOffering,cls).getClsTestClient() + cls.api_client = cloudstackTestClient.getApiClient() + + # Fill services from the external config file + cls.services = cloudstackTestClient.getConfigParser().parsedDict + + # Get Zone, Domain and templates + cls.domain = get_domain(cls.api_client, cls.services) + cls.zone = get_zone(cls.api_client, cls.services) + cls.mode = str(cls.zone.networktype).lower() + cls.template = get_template( + cls.api_client, + cls.zone.id, + cls.services["ostype"] + ) + cls.services["virtual_machine"]["zoneid"] = cls.zone.id + cls.services["virtual_machine"]["template"] = cls.template.id + cls._cleanup = [] + return + + @classmethod + def tearDownClass(cls): + try: + # Cleanup resources used + cleanup_resources(cls.api_client, cls._cleanup) + except Exception as e: + raise Exception("Warning: Exception during cleanup : %s" % e) + return + + def setUp(self): + self.apiclient = self.testClient.getApiClient() + self.dbclient = self.testClient.getDbConnection() + self.cleanup_co = [] + self.cleanup = [] + return + + def tearDown(self): + try: + # Clean up compute offerings + cleanup_resources(self.apiclient, self.cleanup) + + # Clean up compute offerings + cleanup_resources(self.apiclient, self.cleanup_co) + + self.cleanup_co[:] = [] + self.cleanup[:] = [] + except Exception as e: + raise Exception("Warning: Exception during cleanup : %s" % e) + return + + @attr(tags=["basic","advanced"]) + def test_create_normal_compute_offering(self): + """ Create normal compute offering with non zero values for cpu, + cpu number and memory""" + + # Steps: + # 1. Create normal compute offering with non zero values for cpu number, + # cpu speed, memory + + # Validations: + # 1. Compute offering should be created + + self.services["service_offering"]["cpunumber"] = 2 + self.services["service_offering"]["cpuspeed"] = 256 + self.services["service_offering"]["memory"] = 128 + + serviceOffering = ServiceOffering.create(self.api_client, + self.services["service_offering"] + ) + self.assertEqual(verifyComputeOfferingCreation(self.apiclient, serviceOffering.id), + PASS, "Compute Offering verification failed") + + self.cleanup_co.append(serviceOffering) + return + + @attr(tags=["basic","advanced"]) + def test_create_dynamic_compute_offering(self): + """ Create dynamic compute offering with cpunumber, cpuspeed and memory + not specified""" + + # Steps: + # 1. Create dynamic compute offering with values for cpu number, + # cpu speed, memory not specified + + # Validations: + # 1. Compute offering should be created + + self.services["service_offering"]["cpunumber"] = "" + self.services["service_offering"]["cpuspeed"] = "" + self.services["service_offering"]["memory"] = "" + + serviceOffering = ServiceOffering.create(self.api_client, + self.services["service_offering"] + ) + self.assertEqual(verifyComputeOfferingCreation(self.apiclient, serviceOffering.id), + PASS, "Compute Offering verification failed") + + self.cleanup_co.append(serviceOffering) + return + + @attr(tags=["basic","advanced"]) + def test_create_dynamic_compute_offering_no_cpunumber(self): + """ Create dynamic compute offering with only cpunumber unspecified""" + + # Validations: + # 1. Compute Offering creation should fail + + self.services["service_offering"]["cpunumber"] = "" + self.services["service_offering"]["cpuspeed"] = 256 + self.services["service_offering"]["memory"] = 128 + + try: + serviceOffering = ServiceOffering.create(self.api_client, + self.services["service_offering"] + ) + self.cleanup_co.append(serviceOffering) + self.fail("Compute Offering creation succeded, it should have failed") + except Exception: + self.debug("Compute Offering Creation failed as expected") + return + + @attr(tags=["basic","advanced"]) + def test_create_dynamic_compute_offering_no_cpuspeed(self): + """ Create dynamic compute offering with only cpuspeed unspecified""" + + # Validations: + # 1. Compute offering creation should fail + + self.services["service_offering"]["cpunumber"] = 2 + self.services["service_offering"]["cpuspeed"] = "" + self.services["service_offering"]["memory"] = 128 + + try: + serviceOffering = ServiceOffering.create(self.api_client, + self.services["service_offering"] + ) + self.cleanup_co.append(serviceOffering) + self.fail("Compute Offering creation succeded, it should have failed") + except Exception: + self.debug("Compute Offering Creation failed as expected") + return + + @attr(tags=["basic","advanced"]) + def test_create_dynamic_compute_offering_no_memory(self): + """ Create dynamic compute offering with only memory unspecified""" + + # Validations: + # 1. Compute offering creation should fail + + self.services["service_offering"]["cpunumber"] = 2 + self.services["service_offering"]["cpuspeed"] = 256 + self.services["service_offering"]["memory"] = "" + + try: + serviceOffering = ServiceOffering.create(self.api_client, + self.services["service_offering"] + ) + self.cleanup_co.append(serviceOffering) + self.fail("Compute Offering creation succeded, it should have failed") + except Exception: + self.debug("Compute Offering Creation failed as expected") + return + + @data(ADMIN_ACCOUNT, USER_ACCOUNT) + @attr(tags=["basic","advanced"]) + def test_deploy_virtual_machines_static_offering(self, value): + """Test deploy VM with static offering""" + + # Steps: + # 1. Create admin/user account and create its user api client + # 2. Create a static compute offering + # 3. Deploy a VM with account api client and static service offering + # 4. Repeat step 3 but also pass custom values for cpu number, cpu speed and memory + # while deploying VM + + # Validations: + # 1. Step 3 should succeed + # 2. Step 4 should fail + + isadmin=True + if value == USER_ACCOUNT: + isadmin=False + + # Create Account + self.account = Account.create(self.apiclient,self.services["account"],domainid=self.domain.id, admin=isadmin) + apiclient = self.testClient.createUserApiClient( + UserName=self.account.name, + DomainName=self.account.domain) + self.cleanup.append(self.account) + + # Create service offering + self.services["service_offering"]["cpunumber"] = 2 + self.services["service_offering"]["cpuspeed"] = 256 + self.services["service_offering"]["memory"] = 128 + + serviceOffering = ServiceOffering.create(self.apiclient, + self.services["service_offering"]) + + self.cleanup_co.append(serviceOffering) + + # Deploy VM with static service offering + try: + VirtualMachine.create(apiclient,self.services["virtual_machine"], + serviceofferingid=serviceOffering.id, + accountid=self.account.name,domainid=self.account.domainid) + except Exception as e: + self.fail("vm creation failed: %s" % e) + + # Deploy VM with static service offering, also with custom values + try: + VirtualMachine.create(apiclient,self.services["virtual_machine"], + serviceofferingid=serviceOffering.id, + customcpunumber=4, + customcpuspeed=512, + custommemory=256, + accountid=self.account.name,domainid=self.account.domainid) + self.fail("VM creation should have failed, it succeeded") + except Exception as e: + self.debug("vm creation failed as expected: %s" % e) + return + + @data(ADMIN_ACCOUNT, USER_ACCOUNT) + @attr(tags=["basic","advanced"]) + def test_deploy_virtual_machines_dynamic_offering(self, value): + """Test deploy VM with dynamic compute offering""" + + # Steps: + # 1. Create admin/user account and create its user api client + # 2. Create a dynamic service offering + # 3. Deploy a VM with account api client and dynamic service offering + # without providing custom values for cpu number, cpu speed and memory + # 4. Deploy a VM with account api client and dynamic service offering providing + # custom values for cpu number, cpu speed and memory + # 5. Deploy a VM with account api client and dynamic service offering providing + # custom values only for cpu number + + # Validations: + # 1. Step 3 should fail + # 2. Step 4 should succeed + # 3. Step 5 should fail + + isadmin=True + if value == USER_ACCOUNT: + isadmin=False + + # Create Account and its api client + self.account = Account.create(self.apiclient,self.services["account"],domainid=self.domain.id, admin=isadmin) + apiclient = self.testClient.createUserApiClient( + UserName=self.account.name, + DomainName=self.account.domain) + self.cleanup.append(self.account) + + # Create dynamic service offering + self.services["service_offering"]["cpunumber"] = "" + self.services["service_offering"]["cpuspeed"] = "" + self.services["service_offering"]["memory"] = "" + + serviceOffering = ServiceOffering.create(self.apiclient, + self.services["service_offering"]) + + self.cleanup_co.append(serviceOffering) + + # Deploy VM with dynamic compute offering without providing custom values for + # cpu number, cpu speed and memory + try: + VirtualMachine.create(apiclient,self.services["virtual_machine"], + serviceofferingid=serviceOffering.id, + accountid=self.account.name,domainid=self.account.domainid) + self.fail("VM creation succeded, it should have failed") + except Exception as e: + self.debug("vm creation failed as expected with error: %s" % e) + + # Deploy VM with dynamic compute offering providing custom values for + # cpu number, cpu speed and memory + try: + VirtualMachine.create(apiclient,self.services["virtual_machine"], + serviceofferingid=serviceOffering.id, + customcpunumber=2, + customcpuspeed=256, + custommemory=128, + accountid=self.account.name,domainid=self.account.domainid) + except Exception as e: + self.fail("vm creation failed: %s" % e) + + # Deploy VM with dynamic compute offering providing custom values for only + # cpu number + try: + VirtualMachine.create(apiclient,self.services["virtual_machine"], + serviceofferingid=serviceOffering.id, + customcpunumber=2, + accountid=self.account.name,domainid=self.account.domainid) + self.fail("VM deployment should have failed, it succeded") + except Exception as e: + self.debug("vm creation failed as expected: %s" % e) + return + + @data(ADMIN_ACCOUNT, USER_ACCOUNT) + @attr(tags=["basic","advanced"]) + def test_check_vm_stats(self, value): + """Deploy VM with dynamic service offering and check VM stats""" + + # Steps: + # 1. Create admin/user account and create its user api client + # 2. Create a dynamic service offering + # 3. Deploy a VM with account api client and dynamic service offering + # providing custom values for cpu number, cpu speed and memory + # 4. List the VM and verify the dynamic parameters are same as passed + + isadmin=True + if value == USER_ACCOUNT: + isadmin=False + + # Create Account and api client + self.account = Account.create(self.apiclient,self.services["account"],domainid=self.domain.id, admin=isadmin) + apiclient = self.testClient.createUserApiClient( + UserName=self.account.name, + DomainName=self.account.domain) + self.cleanup.append(self.account) + + # Create dynamic compute offering + self.services["service_offering"]["cpunumber"] = "" + self.services["service_offering"]["cpuspeed"] = "" + self.services["service_offering"]["memory"] = "" + + serviceOffering = ServiceOffering.create(self.apiclient, + self.services["service_offering"]) + + self.cleanup_co.append(serviceOffering) + + # Custom values + customcpunumber = 2 + customcpuspeed = 256 + custommemory = 128 + + # Deploy VM with dynamic service offering and the custom values + try: + virtualMachine = VirtualMachine.create(apiclient,self.services["virtual_machine"], + serviceofferingid=serviceOffering.id, + customcpunumber=customcpunumber, + customcpuspeed=customcpuspeed, + custommemory=custommemory, + accountid=self.account.name,domainid=self.account.domainid) + except Exception as e: + self.fail("vm creation failed: %s" % e) + + vmlist = VirtualMachine.list(self.apiclient, id=virtualMachine.id) + self.assertEqual(validateList(vmlist)[0], PASS, "vm list validation failed") + vm = vmlist[0] + + # Verify the custom values + self.assertEqual(str(vm.cpunumber), str(customcpunumber), "vm cpu number %s\ + not matching with provided custom cpu number %s" % \ + (vm.cpunumber, customcpunumber)) + + self.assertEqual(str(vm.cpuspeed), str(customcpuspeed), "vm cpu speed %s\ + not matching with provided custom cpu speed %s" % \ + (vm.cpuspeed, customcpuspeed)) + + self.assertEqual(str(vm.memory), str(custommemory), "vm memory %s\ + not matching with provided custom memory %s" % \ + (vm.memory, custommemory)) + return diff --git a/tools/marvin/marvin/integration/lib/base.py b/tools/marvin/marvin/integration/lib/base.py index 0a7ad9404a6..7449d8c9d11 100755 --- a/tools/marvin/marvin/integration/lib/base.py +++ b/tools/marvin/marvin/integration/lib/base.py @@ -324,7 +324,8 @@ class VirtualMachine: domainid=None, zoneid=None, networkids=None, serviceofferingid=None, securitygroupids=None, projectid=None, startvm=None, diskofferingid=None, affinitygroupnames=None, affinitygroupids=None, group=None, - hostid=None, keypair=None, ipaddress=None, mode='default', method='GET'): + hostid=None, keypair=None, ipaddress=None, mode='default', method='GET', + customcpunumber=None, customcpuspeed=None, custommemory=None): """Create the instance""" cmd = deployVirtualMachine.deployVirtualMachineCmd() @@ -412,6 +413,17 @@ class VirtualMachine: if "userdata" in services: cmd.userdata = base64.urlsafe_b64encode(services["userdata"]) + cmd.details = [{"cpuNumber": "","cpuSpeed":"","memory":""}] + + if customcpunumber: + cmd.details[0]["cpuNumber"] = customcpunumber + + if customcpuspeed: + cmd.details[0]["cpuSpeed"] = customcpuspeed + + if custommemory: + cmd.details[0]["memory"] = custommemory + if group: cmd.group = group @@ -636,6 +648,21 @@ class VirtualMachine: return apiclient.updateVMAffinityGroup(cmd) + def scale(self, apiclient, serviceOfferingId, + customcpunumber=None, customcpuspeed=None, custommemory=None): + """Change service offering of the instance""" + cmd = scaleVirtualMachine.scaleVirtualMachineCmd() + cmd.id = self.id + cmd.serviceofferingid = serviceOfferingId + cmd.details = [{"cpuNumber": "","cpuSpeed":"","memory":""}] + if customcpunumber: + cmd.details[0]["cpuNumber"] = customcpunumber + if customcpuspeed: + cmd.details[0]["cpuSpeed"] = customcpuspeed + if custommemory: + cmd.details[0]["memory"] = custommemory + return apiclient.scaleVirtualMachine(cmd) + class Volume: """Manage Volume Life cycle diff --git a/tools/marvin/marvin/integration/lib/common.py b/tools/marvin/marvin/integration/lib/common.py index d3d634b72c0..3b292bf920f 100644 --- a/tools/marvin/marvin/integration/lib/common.py +++ b/tools/marvin/marvin/integration/lib/common.py @@ -985,3 +985,17 @@ def verifyNetworkState(apiclient, networkid, state): assert validateList(networks)[0] == PASS, "Networks list validation failed, list is %s" % networks assert str(networks[0].state).lower() == state, "network state should be %s, it is %s" % (state, networks[0].state) return + +def verifyComputeOfferingCreation(apiclient, computeofferingid): + """List Compute offerings by ID and verify that the offering exists""" + + cmd = listServiceOfferings.listServiceOfferingsCmd() + cmd.id = computeofferingid + serviceOfferings = None + try: + serviceOfferings = apiclient.listServiceOfferings(cmd) + except Exception as e: + return FAIL + if not (isinstance(serviceOfferings, list) and len(serviceOfferings) > 0): + return FAIL + return PASS From 4eece72eb178d468e4b86c371e88d5f1ff4dde93 Mon Sep 17 00:00:00 2001 From: sanjeevneelarapu Date: Mon, 10 Mar 2014 17:56:22 +0530 Subject: [PATCH 33/70] Bug-Id: CS-19455 Add support for Hyper-v in regression test test_routers.py Signed-off-by: sanjeevneelarapu --- test/integration/component/test_routers.py | 28 ++++++++++---------- tools/marvin/marvin/integration/lib/utils.py | 3 ++- 2 files changed, 16 insertions(+), 15 deletions(-) diff --git a/test/integration/component/test_routers.py b/test/integration/component/test_routers.py index f8359f0e2c5..ced3f525ca2 100644 --- a/test/integration/component/test_routers.py +++ b/test/integration/component/test_routers.py @@ -1254,21 +1254,10 @@ class TestRouterStopCreateFW(cloudstackTestCase): str(self.services["fw_rule"]["endport"]), "Check end port of firewall rule" ) - hosts = list_hosts( - self.apiclient, - id=router.hostid, - ) - self.assertEqual( - isinstance(hosts, list), - True, - "Check for list hosts response return valid data" - ) - host = hosts[0] - host.user, host.passwd = get_host_credentials(self.config, host.ipaddress) - # For DNS and DHCP check 'dnsmasq' process status - if self.apiclient.hypervisor.lower() == 'vmware': - result = get_process_status( + if (self.apiclient.hypervisor.lower() == 'vmware' + or self.apiclient.hypervisor.lower() == 'hyperv'): + result = get_process_status( self.apiclient.connection.mgtSvr, 22, self.apiclient.connection.user, @@ -1278,6 +1267,17 @@ class TestRouterStopCreateFW(cloudstackTestCase): hypervisor=self.apiclient.hypervisor ) else: + hosts = list_hosts( + self.apiclient, + id=router.hostid, + ) + self.assertEqual( + isinstance(hosts, list), + True, + "Check for list hosts response return valid data" + ) + host = hosts[0] + host.user, host.passwd = get_host_credentials(self.config, host.ipaddress) try: result = get_process_status( host.ipaddress, diff --git a/tools/marvin/marvin/integration/lib/utils.py b/tools/marvin/marvin/integration/lib/utils.py index e870158cfb5..709fddebe78 100644 --- a/tools/marvin/marvin/integration/lib/utils.py +++ b/tools/marvin/marvin/integration/lib/utils.py @@ -191,7 +191,8 @@ def get_process_status(hostip, port, username, password, linklocalip, process, h #SSH to the machine ssh = SshClient(hostip, port, username, password) - if str(hypervisor).lower() == 'vmware': + if (str(hypervisor).lower() == 'vmware' + or str(hypervisor).lower() == 'hyperv'): ssh_command = "ssh -i /var/cloudstack/management/.ssh/id_rsa -ostricthostkeychecking=no " else: ssh_command = "ssh -i ~/.ssh/id_rsa.cloud -ostricthostkeychecking=no " From 07102b400f11284009f283aa23faf2d24d543b21 Mon Sep 17 00:00:00 2001 From: Daan Hoogland Date: Mon, 10 Mar 2014 09:39:35 +0100 Subject: [PATCH 34/70] findbugs: scope and final to mitgate possible abuse of fields --- .../com/cloud/api/dispatch/ParamGenericValidationWorker.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/server/src/com/cloud/api/dispatch/ParamGenericValidationWorker.java b/server/src/com/cloud/api/dispatch/ParamGenericValidationWorker.java index 0c829e8db07..f456468948b 100644 --- a/server/src/com/cloud/api/dispatch/ParamGenericValidationWorker.java +++ b/server/src/com/cloud/api/dispatch/ParamGenericValidationWorker.java @@ -37,9 +37,9 @@ import org.apache.log4j.Logger; */ public class ParamGenericValidationWorker implements DispatchWorker { - protected static Logger s_logger = Logger.getLogger(ParamGenericValidationWorker.class.getName()); + static Logger s_logger = Logger.getLogger(ParamGenericValidationWorker.class.getName()); - protected static List defaultParamNames = new ArrayList(); + protected static final List defaultParamNames = new ArrayList(); static { defaultParamNames.add(ApiConstants.CTX_START_EVENT_ID); From 1075bed06c32f14152a8c5c7e534955392e5f662 Mon Sep 17 00:00:00 2001 From: Daan Hoogland Date: Mon, 10 Mar 2014 10:44:10 +0100 Subject: [PATCH 35/70] findbugs: String for Service type mismatch (plus test for dummy data) --- .../com/cloud/network/vpc/VpcManagerImpl.java | 4 +- .../cloud/network/vpc/VpcManagerImplTest.java | 53 +++++++++++++++++++ 2 files changed, 55 insertions(+), 2 deletions(-) create mode 100644 server/test/com/cloud/network/vpc/VpcManagerImplTest.java diff --git a/server/src/com/cloud/network/vpc/VpcManagerImpl.java b/server/src/com/cloud/network/vpc/VpcManagerImpl.java index 403b95e3a1b..762cc6f3993 100644 --- a/server/src/com/cloud/network/vpc/VpcManagerImpl.java +++ b/server/src/com/cloud/network/vpc/VpcManagerImpl.java @@ -424,14 +424,14 @@ public class VpcManagerImpl extends ManagerBase implements VpcManager, VpcProvis List map = _vpcOffSvcMapDao.listByVpcOffId(vpcOffId); for (VpcOfferingServiceMapVO instance : map) { - String service = instance.getService(); + Service service = Service.getService(instance.getService()); Set providers; providers = serviceProviderMap.get(service); if (providers == null) { providers = new HashSet(); } providers.add(Provider.getProvider(instance.getProvider())); - serviceProviderMap.put(Service.getService(service), providers); + serviceProviderMap.put(service, providers); } return serviceProviderMap; diff --git a/server/test/com/cloud/network/vpc/VpcManagerImplTest.java b/server/test/com/cloud/network/vpc/VpcManagerImplTest.java new file mode 100644 index 00000000000..a0237b4805e --- /dev/null +++ b/server/test/com/cloud/network/vpc/VpcManagerImplTest.java @@ -0,0 +1,53 @@ +package com.cloud.network.vpc; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import org.apache.cloudstack.context.CallContext; +import org.junit.Before; +import org.junit.Test; +import org.mockito.Mock; +import org.mockito.Mockito; +import org.mockito.MockitoAnnotations; + +import static org.mockito.Mockito.when; + +import com.cloud.network.Network.Provider; +import com.cloud.network.Network.Service; +import com.cloud.network.vpc.dao.VpcOfferingServiceMapDao; +import com.cloud.user.Account; +import com.cloud.user.User; + +public class VpcManagerImplTest { + + @Mock + VpcOfferingServiceMapDao vpcOffSvcMapDao; + VpcManagerImpl manager; + + @Before + public void setup() + { + MockitoAnnotations.initMocks(this); + manager = new VpcManagerImpl(); + manager._vpcOffSvcMapDao = vpcOffSvcMapDao; + } + @Test + public void getVpcOffSvcProvidersMapForEmptyServiceTest() { + long vpcOffId = 1L; + List list = new ArrayList(); + list.add(Mockito.mock(VpcOfferingServiceMapVO.class)); + when(manager._vpcOffSvcMapDao.listByVpcOffId(vpcOffId)).thenReturn(list); + + Map> map = manager.getVpcOffSvcProvidersMap(vpcOffId); + + assertNotNull(map); + assertEquals(map.size(),1); + } + +} From 2386ad73da43c42ecb019973786a73f0b12d474d Mon Sep 17 00:00:00 2001 From: Daan Hoogland Date: Mon, 10 Mar 2014 10:54:31 +0100 Subject: [PATCH 36/70] rat --- .../cloud/network/vpc/VpcManagerImplTest.java | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/server/test/com/cloud/network/vpc/VpcManagerImplTest.java b/server/test/com/cloud/network/vpc/VpcManagerImplTest.java index a0237b4805e..189b793fefe 100644 --- a/server/test/com/cloud/network/vpc/VpcManagerImplTest.java +++ b/server/test/com/cloud/network/vpc/VpcManagerImplTest.java @@ -1,3 +1,21 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ package com.cloud.network.vpc; import static org.junit.Assert.assertEquals; From 0aca7cfab6f9fe70b9ace590da91e9b7661438f7 Mon Sep 17 00:00:00 2001 From: Daan Hoogland Date: Mon, 10 Mar 2014 10:56:37 +0100 Subject: [PATCH 37/70] unneeded imports removed --- server/test/com/cloud/network/vpc/VpcManagerImplTest.java | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/server/test/com/cloud/network/vpc/VpcManagerImplTest.java b/server/test/com/cloud/network/vpc/VpcManagerImplTest.java index 189b793fefe..3918a374034 100644 --- a/server/test/com/cloud/network/vpc/VpcManagerImplTest.java +++ b/server/test/com/cloud/network/vpc/VpcManagerImplTest.java @@ -20,27 +20,22 @@ package com.cloud.network.vpc; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; +import static org.mockito.Mockito.when; import java.util.ArrayList; -import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Set; -import org.apache.cloudstack.context.CallContext; import org.junit.Before; import org.junit.Test; import org.mockito.Mock; import org.mockito.Mockito; import org.mockito.MockitoAnnotations; -import static org.mockito.Mockito.when; - import com.cloud.network.Network.Provider; import com.cloud.network.Network.Service; import com.cloud.network.vpc.dao.VpcOfferingServiceMapDao; -import com.cloud.user.Account; -import com.cloud.user.User; public class VpcManagerImplTest { From 579cb9c479b67e9385f1235f4f71f2fef81b0bd0 Mon Sep 17 00:00:00 2001 From: Daan Hoogland Date: Mon, 10 Mar 2014 13:04:10 +0100 Subject: [PATCH 38/70] findbugs: output vlanids in errormessage instead of array object pointer --- server/src/com/cloud/network/IpAddressManagerImpl.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/src/com/cloud/network/IpAddressManagerImpl.java b/server/src/com/cloud/network/IpAddressManagerImpl.java index 8903d1d1137..ed709e939fe 100644 --- a/server/src/com/cloud/network/IpAddressManagerImpl.java +++ b/server/src/com/cloud/network/IpAddressManagerImpl.java @@ -693,7 +693,7 @@ public class IpAddressManagerImpl extends ManagerBase implements IpAddressManage errorMessage.append(", vlanId id=" + Arrays.toString(dedicatedVlanDbIds.toArray())); } else if (nonDedicatedVlanDbIds != null && !nonDedicatedVlanDbIds.isEmpty()) { sc.setParameters("vlanId", nonDedicatedVlanDbIds.toArray()); - errorMessage.append(", vlanId id=" + nonDedicatedVlanDbIds.toArray()); + errorMessage.append(", vlanId id=" + Arrays.toString(nonDedicatedVlanDbIds.toArray())); } else { if (podId != null) { InsufficientAddressCapacityException ex = new InsufficientAddressCapacityException("Insufficient address capacity", Pod.class, podId); From e0d20fb6eb7b9550ad8b543e2df0ad00d8c9965e Mon Sep 17 00:00:00 2001 From: Daan Hoogland Date: Mon, 10 Mar 2014 13:08:15 +0100 Subject: [PATCH 39/70] findbugs: null check before use of pointer --- server/src/com/cloud/network/NetworkModelImpl.java | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/server/src/com/cloud/network/NetworkModelImpl.java b/server/src/com/cloud/network/NetworkModelImpl.java index 9212a89b838..7b4b2bebdb2 100755 --- a/server/src/com/cloud/network/NetworkModelImpl.java +++ b/server/src/com/cloud/network/NetworkModelImpl.java @@ -1533,28 +1533,34 @@ public class NetworkModelImpl extends ManagerBase implements NetworkModel { @Override public void checkNetworkPermissions(Account owner, Network network) { + // dahn 20140310: I was thinking of making this an assert but + // as we hardly ever test with asserts I think + // we better make sure at runtime. + if (network == null) { + throw new CloudRuntimeException("cannot check permissions on (Network) "); + } // Perform account permission check if (network.getGuestType() != Network.GuestType.Shared || (network.getGuestType() == Network.GuestType.Shared && network.getAclType() == ACLType.Account)) { AccountVO networkOwner = _accountDao.findById(network.getAccountId()); if (networkOwner == null) - throw new PermissionDeniedException("Unable to use network with id= " + ((network != null) ? ((NetworkVO)network).getUuid() : "") + + throw new PermissionDeniedException("Unable to use network with id= " + ((NetworkVO)network).getUuid() + ", network does not have an owner"); if (owner.getType() != Account.ACCOUNT_TYPE_PROJECT && networkOwner.getType() == Account.ACCOUNT_TYPE_PROJECT) { if (!_projectAccountDao.canAccessProjectAccount(owner.getAccountId(), network.getAccountId())) { - throw new PermissionDeniedException("Unable to use network with id= " + ((network != null) ? ((NetworkVO)network).getUuid() : "") + + throw new PermissionDeniedException("Unable to use network with id= " + ((NetworkVO)network).getUuid() + ", permission denied"); } } else { List networkMap = _networksDao.listBy(owner.getId(), network.getId()); if (networkMap == null || networkMap.isEmpty()) { - throw new PermissionDeniedException("Unable to use network with id= " + ((network != null) ? ((NetworkVO)network).getUuid() : "") + + throw new PermissionDeniedException("Unable to use network with id= " + ((NetworkVO)network).getUuid() + ", permission denied"); } } } else { if (!isNetworkAvailableInDomain(network.getId(), owner.getDomainId())) { - throw new PermissionDeniedException("Shared network id=" + ((network != null) ? ((NetworkVO)network).getUuid() : "") + " is not available in domain id=" + + throw new PermissionDeniedException("Shared network id=" + ((NetworkVO)network).getUuid() + " is not available in domain id=" + owner.getDomainId()); } } From d182a51162ad081f1e24faa7a2bd45246de5e326 Mon Sep 17 00:00:00 2001 From: Daan Hoogland Date: Mon, 10 Mar 2014 13:21:13 +0100 Subject: [PATCH 40/70] findbugs: another array pointer in error message --- server/src/com/cloud/network/IpAddressManagerImpl.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/src/com/cloud/network/IpAddressManagerImpl.java b/server/src/com/cloud/network/IpAddressManagerImpl.java index ed709e939fe..15d1458fb59 100644 --- a/server/src/com/cloud/network/IpAddressManagerImpl.java +++ b/server/src/com/cloud/network/IpAddressManagerImpl.java @@ -733,7 +733,7 @@ public class IpAddressManagerImpl extends ManagerBase implements IpAddressManage if (useSystemIps && nonDedicatedVlanDbIds != null && !nonDedicatedVlanDbIds.isEmpty()) { fetchFromDedicatedRange = false; sc.setParameters("vlanId", nonDedicatedVlanDbIds.toArray()); - errorMessage.append(", vlanId id=" + nonDedicatedVlanDbIds.toArray()); + errorMessage.append(", vlanId id=" + Arrays.toString(nonDedicatedVlanDbIds.toArray())); addrs = _ipAddressDao.lockRows(sc, filter, true); } } From a1b778fc2c7f0ec84014f9e7329944032fb3c2a7 Mon Sep 17 00:00:00 2001 From: Brian Federle Date: Mon, 10 Mar 2014 07:43:28 -0700 Subject: [PATCH 41/70] Fix truncation issue with refresh, add button icons --- ui/css/cloudstack3.css | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ui/css/cloudstack3.css b/ui/css/cloudstack3.css index 11c1c7ee95c..2b88e033662 100644 --- a/ui/css/cloudstack3.css +++ b/ui/css/cloudstack3.css @@ -3080,7 +3080,7 @@ div.toolbar div.button.refresh span { div.toolbar div.button.add span, .detail-group .button.add span.icon { - padding: 0px 0 0px 18px; + padding: 0px 0 3px 18px; background: url(../images/icons.png) no-repeat -626px -209px; /*+placement:shift 0px 0px;*/ position: relative; From 1d74daf6fe7c87931b6308d4e2e0e39f109a85ac Mon Sep 17 00:00:00 2001 From: Mike Tutkowski Date: Mon, 10 Mar 2014 11:42:56 -0600 Subject: [PATCH 42/70] CLOUDSTACK-6170 --- .../cloudstack/engine/orchestration/CloudOrchestrator.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/engine/orchestration/src/org/apache/cloudstack/engine/orchestration/CloudOrchestrator.java b/engine/orchestration/src/org/apache/cloudstack/engine/orchestration/CloudOrchestrator.java index 7969e43cdc5..fc1b85c0802 100755 --- a/engine/orchestration/src/org/apache/cloudstack/engine/orchestration/CloudOrchestrator.java +++ b/engine/orchestration/src/org/apache/cloudstack/engine/orchestration/CloudOrchestrator.java @@ -188,7 +188,7 @@ public class CloudOrchestrator implements OrchestrationService { rootDiskOfferingInfo.setDiskOffering(offering); rootDiskOfferingInfo.setSize(rootDiskSize); - if (offering.isCustomizedIops()) { + if (offering.isCustomizedIops() != null && offering.isCustomizedIops()) { Map userVmDetails = _userVmDetailsDao.listDetailsKeyPairs(vm.getId()); if (userVmDetails != null) { From bf9375b8b9c437bf314d0459233f17860d85d3f3 Mon Sep 17 00:00:00 2001 From: Alena Prokharchyk Date: Fri, 7 Mar 2014 15:06:35 -0800 Subject: [PATCH 43/70] CLOUDSTACK-6214: apply network rules when plug new guest nic to router for the network in Setup state Conflicts: server/src/com/cloud/network/router/VpcVirtualNetworkApplianceManager.java server/src/com/cloud/network/router/VpcVirtualNetworkApplianceManagerImpl.java Conflicts: api/src/com/cloud/network/VpcVirtualNetworkApplianceService.java server/src/com/cloud/network/router/VpcVirtualNetworkApplianceManager.java server/src/com/cloud/network/router/VpcVirtualNetworkApplianceManagerImpl.java server/test/com/cloud/vpc/MockVpcVirtualNetworkApplianceManager.java --- .../VpcVirtualNetworkApplianceService.java | 8 +++-- .../element/VpcVirtualRouterElement.java | 14 ++++++-- ...VpcVirtualNetworkApplianceManagerImpl.java | 34 ++++++++++++++++--- ...MockVpcVirtualNetworkApplianceManager.java | 7 ++-- 4 files changed, 51 insertions(+), 12 deletions(-) diff --git a/api/src/com/cloud/network/VpcVirtualNetworkApplianceService.java b/api/src/com/cloud/network/VpcVirtualNetworkApplianceService.java index eee62ceea76..382c460725d 100644 --- a/api/src/com/cloud/network/VpcVirtualNetworkApplianceService.java +++ b/api/src/com/cloud/network/VpcVirtualNetworkApplianceService.java @@ -16,10 +16,13 @@ // under the License. package com.cloud.network; +import java.util.Map; + import com.cloud.exception.ConcurrentOperationException; import com.cloud.exception.InsufficientCapacityException; import com.cloud.exception.ResourceUnavailableException; import com.cloud.network.router.VirtualRouter; +import com.cloud.vm.VirtualMachineProfile; public interface VpcVirtualNetworkApplianceService extends VirtualNetworkApplianceService { @@ -27,13 +30,14 @@ public interface VpcVirtualNetworkApplianceService extends VirtualNetworkApplian * @param router * @param network * @param isRedundant + * @param params TODO * @return * @throws ConcurrentOperationException * @throws ResourceUnavailableException * @throws InsufficientCapacityException */ - boolean addVpcRouterToGuestNetwork(VirtualRouter router, Network network, boolean isRedundant) throws ConcurrentOperationException, ResourceUnavailableException, - InsufficientCapacityException; + boolean addVpcRouterToGuestNetwork(VirtualRouter router, Network network, boolean isRedundant, Map params) + throws ConcurrentOperationException, ResourceUnavailableException, InsufficientCapacityException; /** * @param router diff --git a/server/src/com/cloud/network/element/VpcVirtualRouterElement.java b/server/src/com/cloud/network/element/VpcVirtualRouterElement.java index 5695a2c9fcd..b433fe4532f 100644 --- a/server/src/com/cloud/network/element/VpcVirtualRouterElement.java +++ b/server/src/com/cloud/network/element/VpcVirtualRouterElement.java @@ -36,6 +36,7 @@ import com.cloud.network.Network; import com.cloud.network.Network.Capability; import com.cloud.network.Network.Provider; import com.cloud.network.Network.Service; +import com.cloud.network.Network.State; import com.cloud.network.NetworkModel; import com.cloud.network.PublicIpAddress; import com.cloud.network.RemoteAccessVpn; @@ -179,7 +180,11 @@ public class VpcVirtualRouterElement extends VirtualRouterElement implements Vpc DomainRouterVO router = routers.get(0); //Add router to guest network if needed if (!_networkMgr.isVmPartOfNetwork(router.getId(), network.getId())) { - if (!_vpcRouterMgr.addVpcRouterToGuestNetwork(router, network, false)) { + Map paramsForRouter = new HashMap(1); + if (network.getState() == State.Setup) { + paramsForRouter.put(VirtualMachineProfile.Param.ReProgramGuestNetworks, true); + } + if (!_vpcRouterMgr.addVpcRouterToGuestNetwork(router, network, false, paramsForRouter)) { throw new CloudRuntimeException("Failed to add VPC router " + router + " to guest network " + network); } else { s_logger.debug("Successfully added VPC router " + router + " to guest network " + network); @@ -220,7 +225,12 @@ public class VpcVirtualRouterElement extends VirtualRouterElement implements Vpc DomainRouterVO router = routers.get(0); //Add router to guest network if needed if (!_networkMgr.isVmPartOfNetwork(router.getId(), network.getId())) { - if (!_vpcRouterMgr.addVpcRouterToGuestNetwork(router, network, false)) { + Map paramsForRouter = new HashMap(1); + // need to reprogram guest network if it comes in a setup state + if (network.getState() == State.Setup) { + paramsForRouter.put(VirtualMachineProfile.Param.ReProgramGuestNetworks, true); + } + if (!_vpcRouterMgr.addVpcRouterToGuestNetwork(router, network, false, paramsForRouter)) { throw new CloudRuntimeException("Failed to add VPC router " + router + " to guest network " + network); } else { s_logger.debug("Successfully added VPC router " + router + " to guest network " + network); diff --git a/server/src/com/cloud/network/router/VpcVirtualNetworkApplianceManagerImpl.java b/server/src/com/cloud/network/router/VpcVirtualNetworkApplianceManagerImpl.java index bed30df8d2a..f7fdd08aee0 100644 --- a/server/src/com/cloud/network/router/VpcVirtualNetworkApplianceManagerImpl.java +++ b/server/src/com/cloud/network/router/VpcVirtualNetworkApplianceManagerImpl.java @@ -36,6 +36,7 @@ import org.springframework.stereotype.Component; import com.cloud.agent.api.Answer; import com.cloud.agent.api.Command; +import com.cloud.agent.api.Command.OnError; import com.cloud.agent.api.NetworkUsageCommand; import com.cloud.agent.api.PlugNicCommand; import com.cloud.agent.api.SetupGuestNetworkCommand; @@ -246,9 +247,8 @@ public class VpcVirtualNetworkApplianceManagerImpl extends VirtualNetworkApplian } @Override - public boolean addVpcRouterToGuestNetwork(VirtualRouter router, Network network, boolean isRedundant) throws ConcurrentOperationException, - ResourceUnavailableException, InsufficientCapacityException { - + public boolean addVpcRouterToGuestNetwork(VirtualRouter router, Network network, boolean isRedundant, Map params) + throws ConcurrentOperationException, ResourceUnavailableException, InsufficientCapacityException { if (network.getTrafficType() != TrafficType.Guest) { s_logger.warn("Network " + network + " is not of type " + TrafficType.Guest); return false; @@ -257,16 +257,23 @@ public class VpcVirtualNetworkApplianceManagerImpl extends VirtualNetworkApplian //Add router to the Guest network boolean result = true; try { + + // 1) add nic to the router _routerDao.addRouterToGuestNetwork(router, network); NicProfile guestNic = _itMgr.addVmToNetwork(router, network, null); - //setup guest network + //2) setup guest network if (guestNic != null) { result = setupVpcGuestNetwork(network, router, true, guestNic); } else { s_logger.warn("Failed to add router " + router + " to guest network " + network); result = false; } + //3) apply networking rules + if (result && params.get(Param.ReProgramGuestNetworks) != null + && (Boolean) params.get(Param.ReProgramGuestNetworks) == true) { + sendNetworkRulesToRouter(router.getId(), network.getId()); + } } catch (Exception ex) { s_logger.warn("Failed to add router " + router + " to network " + network + " due to ", ex); result = false; @@ -885,6 +892,25 @@ public class VpcVirtualNetworkApplianceManagerImpl extends VirtualNetworkApplian } } + + protected boolean sendNetworkRulesToRouter(long routerId, long networkId) + throws ResourceUnavailableException { + DomainRouterVO router = _routerDao.findById(routerId); + Commands cmds = new Commands(OnError.Continue); + + VirtualRouterProvider vrProvider = _vrProviderDao.findById(router.getElementId()); + if (vrProvider == null) { + throw new CloudRuntimeException("Cannot find related virtual router provider of router: " + router.getHostName()); + } + Provider provider = Network.Provider.getProvider(vrProvider.getType().toString()); + if (provider == null) { + throw new CloudRuntimeException("Cannot find related provider of virtual router provider: " + vrProvider.getType().toString()); + } + + finalizeNetworkRulesForNetwork(cmds, router, provider, networkId); + return sendCommandsToRouter(router, cmds); + } + @Override public boolean setupPrivateGateway(PrivateGateway gateway, VirtualRouter router) throws ConcurrentOperationException, ResourceUnavailableException { boolean result = true; diff --git a/server/test/com/cloud/vpc/MockVpcVirtualNetworkApplianceManager.java b/server/test/com/cloud/vpc/MockVpcVirtualNetworkApplianceManager.java index 4802cfff93b..e0c599deeb4 100644 --- a/server/test/com/cloud/vpc/MockVpcVirtualNetworkApplianceManager.java +++ b/server/test/com/cloud/vpc/MockVpcVirtualNetworkApplianceManager.java @@ -23,10 +23,9 @@ import java.util.Map; import javax.ejb.Local; import javax.naming.ConfigurationException; -import org.springframework.stereotype.Component; - import org.apache.cloudstack.api.command.admin.router.UpgradeRouterCmd; import org.apache.cloudstack.api.command.admin.router.UpgradeRouterTemplateCmd; +import org.springframework.stereotype.Component; import com.cloud.deploy.DeployDestination; import com.cloud.exception.ConcurrentOperationException; @@ -313,8 +312,8 @@ public class MockVpcVirtualNetworkApplianceManager extends ManagerBase implement * @see com.cloud.network.VpcVirtualNetworkApplianceService#addVpcRouterToGuestNetwork(com.cloud.network.router.VirtualRouter, com.cloud.network.Network, boolean) */ @Override - public boolean addVpcRouterToGuestNetwork(VirtualRouter router, Network network, boolean isRedundant) throws ConcurrentOperationException, - ResourceUnavailableException, InsufficientCapacityException { + public boolean addVpcRouterToGuestNetwork(VirtualRouter router, Network network, boolean isRedundant, Map params) + throws ConcurrentOperationException, ResourceUnavailableException, InsufficientCapacityException { // TODO Auto-generated method stub return false; } From d033ca486bf9bc22a2afe314d00150ec6019c809 Mon Sep 17 00:00:00 2001 From: Marcus Sorensen Date: Mon, 10 Mar 2014 15:34:55 -0600 Subject: [PATCH 44/70] CLOUDSTACK-6220: Fix cloudstack init scripts so that they don't use fully qualified path as script name. Fix for commit 9dd57c22b02afcddb1d6c8ddc3e1b578961454e3 --- agent/distro/centos/SYSCONFDIR/rc.d/init.d/cloud-agent.in | 2 +- agent/distro/fedora/SYSCONFDIR/rc.d/init.d/cloud-agent.in | 2 +- agent/distro/opensuse/sles/SYSCONFDIR/init.d/cloud-agent.in | 2 +- agent/distro/rhel/SYSCONFDIR/rc.d/init.d/cloud-agent.in | 2 +- agent/distro/sles/SYSCONFDIR/init.d/cloud-agent.in | 2 +- packaging/centos63/cloud-agent.rc | 2 +- packaging/centos63/cloud-ipallocator.rc | 2 +- .../distro/centos/SYSCONFDIR/rc.d/init.d/cloud-ipallocator.in | 2 +- .../distro/fedora/SYSCONFDIR/rc.d/init.d/cloud-ipallocator.in | 2 +- python/distro/opensuse/SYSCONFDIR/init.d/cloud-ipallocator.in | 2 +- python/distro/rhel/SYSCONFDIR/rc.d/init.d/cloud-ipallocator.in | 2 +- python/distro/sles/SYSCONFDIR/init.d/cloud-ipallocator.in | 2 +- python/distro/ubuntu/SYSCONFDIR/init.d/cloud-ipallocator.in | 2 +- .../distro/centos/SYSCONFDIR/rc.d/init.d/cloud-console-proxy.in | 2 +- .../distro/fedora/SYSCONFDIR/rc.d/init.d/cloud-console-proxy.in | 2 +- .../distro/rhel/SYSCONFDIR/rc.d/init.d/cloud-console-proxy.in | 2 +- systemvm/distro/ubuntu/SYSCONFDIR/init.d/cloud-console-proxy.in | 2 +- 17 files changed, 17 insertions(+), 17 deletions(-) diff --git a/agent/distro/centos/SYSCONFDIR/rc.d/init.d/cloud-agent.in b/agent/distro/centos/SYSCONFDIR/rc.d/init.d/cloud-agent.in index 60e1e045b24..704ef6b05b4 100755 --- a/agent/distro/centos/SYSCONFDIR/rc.d/init.d/cloud-agent.in +++ b/agent/distro/centos/SYSCONFDIR/rc.d/init.d/cloud-agent.in @@ -26,7 +26,7 @@ # set environment variables -SHORTNAME="$0" +SHORTNAME="basename $0" PIDFILE=@PIDDIR@/"$SHORTNAME".pid LOCKFILE=@LOCKDIR@/"$SHORTNAME" LOGFILE=@AGENTLOG@ diff --git a/agent/distro/fedora/SYSCONFDIR/rc.d/init.d/cloud-agent.in b/agent/distro/fedora/SYSCONFDIR/rc.d/init.d/cloud-agent.in index 60e1e045b24..704ef6b05b4 100755 --- a/agent/distro/fedora/SYSCONFDIR/rc.d/init.d/cloud-agent.in +++ b/agent/distro/fedora/SYSCONFDIR/rc.d/init.d/cloud-agent.in @@ -26,7 +26,7 @@ # set environment variables -SHORTNAME="$0" +SHORTNAME="basename $0" PIDFILE=@PIDDIR@/"$SHORTNAME".pid LOCKFILE=@LOCKDIR@/"$SHORTNAME" LOGFILE=@AGENTLOG@ diff --git a/agent/distro/opensuse/sles/SYSCONFDIR/init.d/cloud-agent.in b/agent/distro/opensuse/sles/SYSCONFDIR/init.d/cloud-agent.in index 2422268f416..e684888b86e 100644 --- a/agent/distro/opensuse/sles/SYSCONFDIR/init.d/cloud-agent.in +++ b/agent/distro/opensuse/sles/SYSCONFDIR/init.d/cloud-agent.in @@ -33,7 +33,7 @@ # set environment variables -SHORTNAME="$0" +SHORTNAME="basename $0" PIDFILE=@PIDDIR@/"$SHORTNAME".pid LOCKFILE=@LOCKDIR@/"$SHORTNAME" LOGFILE=@AGENTLOG@ diff --git a/agent/distro/rhel/SYSCONFDIR/rc.d/init.d/cloud-agent.in b/agent/distro/rhel/SYSCONFDIR/rc.d/init.d/cloud-agent.in index 60e1e045b24..704ef6b05b4 100644 --- a/agent/distro/rhel/SYSCONFDIR/rc.d/init.d/cloud-agent.in +++ b/agent/distro/rhel/SYSCONFDIR/rc.d/init.d/cloud-agent.in @@ -26,7 +26,7 @@ # set environment variables -SHORTNAME="$0" +SHORTNAME="basename $0" PIDFILE=@PIDDIR@/"$SHORTNAME".pid LOCKFILE=@LOCKDIR@/"$SHORTNAME" LOGFILE=@AGENTLOG@ diff --git a/agent/distro/sles/SYSCONFDIR/init.d/cloud-agent.in b/agent/distro/sles/SYSCONFDIR/init.d/cloud-agent.in index 2422268f416..e684888b86e 100644 --- a/agent/distro/sles/SYSCONFDIR/init.d/cloud-agent.in +++ b/agent/distro/sles/SYSCONFDIR/init.d/cloud-agent.in @@ -33,7 +33,7 @@ # set environment variables -SHORTNAME="$0" +SHORTNAME="basename $0" PIDFILE=@PIDDIR@/"$SHORTNAME".pid LOCKFILE=@LOCKDIR@/"$SHORTNAME" LOGFILE=@AGENTLOG@ diff --git a/packaging/centos63/cloud-agent.rc b/packaging/centos63/cloud-agent.rc index 40c358e36b6..af1c624eda2 100755 --- a/packaging/centos63/cloud-agent.rc +++ b/packaging/centos63/cloud-agent.rc @@ -26,7 +26,7 @@ # set environment variables -SHORTNAME="$0" +SHORTNAME="basename $0" PIDFILE=/var/run/"$SHORTNAME".pid LOCKFILE=/var/lock/subsys/"$SHORTNAME" LOGDIR=/var/log/cloudstack/agent diff --git a/packaging/centos63/cloud-ipallocator.rc b/packaging/centos63/cloud-ipallocator.rc index 9a24d8dfc8a..9d1adb43506 100755 --- a/packaging/centos63/cloud-ipallocator.rc +++ b/packaging/centos63/cloud-ipallocator.rc @@ -25,7 +25,7 @@ # set environment variables -SHORTNAME="$0" +SHORTNAME="basename $0" PIDFILE=/var/run/"$SHORTNAME".pid LOCKFILE=/var/lock/subsys/"$SHORTNAME" LOGFILE=/var/log/cloudstack/ipallocator/ipallocator.log diff --git a/python/distro/centos/SYSCONFDIR/rc.d/init.d/cloud-ipallocator.in b/python/distro/centos/SYSCONFDIR/rc.d/init.d/cloud-ipallocator.in index b6720f5b639..ae8d2157541 100755 --- a/python/distro/centos/SYSCONFDIR/rc.d/init.d/cloud-ipallocator.in +++ b/python/distro/centos/SYSCONFDIR/rc.d/init.d/cloud-ipallocator.in @@ -25,7 +25,7 @@ # set environment variables -SHORTNAME="$0" +SHORTNAME="basename $0" PIDFILE=@PIDDIR@/"$SHORTNAME".pid LOCKFILE=@LOCKDIR@/"$SHORTNAME" LOGFILE=@IPALOCATORLOG@ diff --git a/python/distro/fedora/SYSCONFDIR/rc.d/init.d/cloud-ipallocator.in b/python/distro/fedora/SYSCONFDIR/rc.d/init.d/cloud-ipallocator.in index aa7e8cf8820..49fd9b6f237 100755 --- a/python/distro/fedora/SYSCONFDIR/rc.d/init.d/cloud-ipallocator.in +++ b/python/distro/fedora/SYSCONFDIR/rc.d/init.d/cloud-ipallocator.in @@ -25,7 +25,7 @@ # set environment variables -SHORTNAME="$0" +SHORTNAME="basename $0" PIDFILE=@PIDDIR@/"$SHORTNAME".pid LOCKFILE=@LOCKDIR@/"$SHORTNAME" LOGFILE=@AGENTLOG@ diff --git a/python/distro/opensuse/SYSCONFDIR/init.d/cloud-ipallocator.in b/python/distro/opensuse/SYSCONFDIR/init.d/cloud-ipallocator.in index 7aa456df51c..901d5845f39 100755 --- a/python/distro/opensuse/SYSCONFDIR/init.d/cloud-ipallocator.in +++ b/python/distro/opensuse/SYSCONFDIR/init.d/cloud-ipallocator.in @@ -32,7 +32,7 @@ # set environment variables -SHORTNAME="$0" +SHORTNAME="basename $0" PIDFILE=@PIDDIR@/"$SHORTNAME".pid LOCKFILE=@LOCKDIR@/"$SHORTNAME" LOGFILE=@AGENTLOG@ diff --git a/python/distro/rhel/SYSCONFDIR/rc.d/init.d/cloud-ipallocator.in b/python/distro/rhel/SYSCONFDIR/rc.d/init.d/cloud-ipallocator.in index aa7e8cf8820..49fd9b6f237 100644 --- a/python/distro/rhel/SYSCONFDIR/rc.d/init.d/cloud-ipallocator.in +++ b/python/distro/rhel/SYSCONFDIR/rc.d/init.d/cloud-ipallocator.in @@ -25,7 +25,7 @@ # set environment variables -SHORTNAME="$0" +SHORTNAME="basename $0" PIDFILE=@PIDDIR@/"$SHORTNAME".pid LOCKFILE=@LOCKDIR@/"$SHORTNAME" LOGFILE=@AGENTLOG@ diff --git a/python/distro/sles/SYSCONFDIR/init.d/cloud-ipallocator.in b/python/distro/sles/SYSCONFDIR/init.d/cloud-ipallocator.in index 7aa456df51c..901d5845f39 100755 --- a/python/distro/sles/SYSCONFDIR/init.d/cloud-ipallocator.in +++ b/python/distro/sles/SYSCONFDIR/init.d/cloud-ipallocator.in @@ -32,7 +32,7 @@ # set environment variables -SHORTNAME="$0" +SHORTNAME="basename $0" PIDFILE=@PIDDIR@/"$SHORTNAME".pid LOCKFILE=@LOCKDIR@/"$SHORTNAME" LOGFILE=@AGENTLOG@ diff --git a/python/distro/ubuntu/SYSCONFDIR/init.d/cloud-ipallocator.in b/python/distro/ubuntu/SYSCONFDIR/init.d/cloud-ipallocator.in index ec84962b669..5ec6da07f23 100755 --- a/python/distro/ubuntu/SYSCONFDIR/init.d/cloud-ipallocator.in +++ b/python/distro/ubuntu/SYSCONFDIR/init.d/cloud-ipallocator.in @@ -26,7 +26,7 @@ # set environment variables -SHORTNAME="$0" +SHORTNAME="basename $0" PIDFILE=@PIDDIR@/"$SHORTNAME".pid LOCKFILE=@LOCKDIR@/"$SHORTNAME" LOGFILE=@AGENTLOG@ diff --git a/systemvm/distro/centos/SYSCONFDIR/rc.d/init.d/cloud-console-proxy.in b/systemvm/distro/centos/SYSCONFDIR/rc.d/init.d/cloud-console-proxy.in index 76ee681dbe9..e43f6413c67 100644 --- a/systemvm/distro/centos/SYSCONFDIR/rc.d/init.d/cloud-console-proxy.in +++ b/systemvm/distro/centos/SYSCONFDIR/rc.d/init.d/cloud-console-proxy.in @@ -26,7 +26,7 @@ # set environment variables -SHORTNAME="$0" +SHORTNAME="basename $0" PIDFILE=@PIDDIR@/"$SHORTNAME".pid LOCKFILE=@LOCKDIR@/"$SHORTNAME" LOGFILE=@CPLOG@ diff --git a/systemvm/distro/fedora/SYSCONFDIR/rc.d/init.d/cloud-console-proxy.in b/systemvm/distro/fedora/SYSCONFDIR/rc.d/init.d/cloud-console-proxy.in index 76ee681dbe9..e43f6413c67 100644 --- a/systemvm/distro/fedora/SYSCONFDIR/rc.d/init.d/cloud-console-proxy.in +++ b/systemvm/distro/fedora/SYSCONFDIR/rc.d/init.d/cloud-console-proxy.in @@ -26,7 +26,7 @@ # set environment variables -SHORTNAME="$0" +SHORTNAME="basename $0" PIDFILE=@PIDDIR@/"$SHORTNAME".pid LOCKFILE=@LOCKDIR@/"$SHORTNAME" LOGFILE=@CPLOG@ diff --git a/systemvm/distro/rhel/SYSCONFDIR/rc.d/init.d/cloud-console-proxy.in b/systemvm/distro/rhel/SYSCONFDIR/rc.d/init.d/cloud-console-proxy.in index 76ee681dbe9..e43f6413c67 100644 --- a/systemvm/distro/rhel/SYSCONFDIR/rc.d/init.d/cloud-console-proxy.in +++ b/systemvm/distro/rhel/SYSCONFDIR/rc.d/init.d/cloud-console-proxy.in @@ -26,7 +26,7 @@ # set environment variables -SHORTNAME="$0" +SHORTNAME="basename $0" PIDFILE=@PIDDIR@/"$SHORTNAME".pid LOCKFILE=@LOCKDIR@/"$SHORTNAME" LOGFILE=@CPLOG@ diff --git a/systemvm/distro/ubuntu/SYSCONFDIR/init.d/cloud-console-proxy.in b/systemvm/distro/ubuntu/SYSCONFDIR/init.d/cloud-console-proxy.in index c83f00aa76d..87a653e920b 100755 --- a/systemvm/distro/ubuntu/SYSCONFDIR/init.d/cloud-console-proxy.in +++ b/systemvm/distro/ubuntu/SYSCONFDIR/init.d/cloud-console-proxy.in @@ -27,7 +27,7 @@ # set environment variables -SHORTNAME="$0" +SHORTNAME="basename $0" PIDFILE=@PIDDIR@/"$SHORTNAME".pid LOCKFILE=@LOCKDIR@/"$SHORTNAME" LOGFILE=@CPLOG@ From a4d3ec476fce815ef32e8273c7311850b5617f06 Mon Sep 17 00:00:00 2001 From: Marcus Sorensen Date: Mon, 10 Mar 2014 16:11:04 -0600 Subject: [PATCH 45/70] CLOUDSTACK-6220: Take 2, Fix cloudstack init scripts so that they don't use fully qualified path as script name. Fix for commit 9dd57c22b02afcddb1d6c8ddc3e1b578961454e3 --- agent/distro/centos/SYSCONFDIR/rc.d/init.d/cloud-agent.in | 2 +- agent/distro/fedora/SYSCONFDIR/rc.d/init.d/cloud-agent.in | 2 +- agent/distro/opensuse/sles/SYSCONFDIR/init.d/cloud-agent.in | 2 +- agent/distro/rhel/SYSCONFDIR/rc.d/init.d/cloud-agent.in | 2 +- agent/distro/sles/SYSCONFDIR/init.d/cloud-agent.in | 2 +- packaging/centos63/cloud-agent.rc | 2 +- packaging/centos63/cloud-ipallocator.rc | 2 +- .../distro/centos/SYSCONFDIR/rc.d/init.d/cloud-ipallocator.in | 2 +- .../distro/fedora/SYSCONFDIR/rc.d/init.d/cloud-ipallocator.in | 2 +- python/distro/opensuse/SYSCONFDIR/init.d/cloud-ipallocator.in | 2 +- python/distro/rhel/SYSCONFDIR/rc.d/init.d/cloud-ipallocator.in | 2 +- python/distro/sles/SYSCONFDIR/init.d/cloud-ipallocator.in | 2 +- python/distro/ubuntu/SYSCONFDIR/init.d/cloud-ipallocator.in | 2 +- .../distro/centos/SYSCONFDIR/rc.d/init.d/cloud-console-proxy.in | 2 +- .../distro/fedora/SYSCONFDIR/rc.d/init.d/cloud-console-proxy.in | 2 +- .../distro/rhel/SYSCONFDIR/rc.d/init.d/cloud-console-proxy.in | 2 +- systemvm/distro/ubuntu/SYSCONFDIR/init.d/cloud-console-proxy.in | 2 +- 17 files changed, 17 insertions(+), 17 deletions(-) diff --git a/agent/distro/centos/SYSCONFDIR/rc.d/init.d/cloud-agent.in b/agent/distro/centos/SYSCONFDIR/rc.d/init.d/cloud-agent.in index 704ef6b05b4..d1769ccdfb0 100755 --- a/agent/distro/centos/SYSCONFDIR/rc.d/init.d/cloud-agent.in +++ b/agent/distro/centos/SYSCONFDIR/rc.d/init.d/cloud-agent.in @@ -26,7 +26,7 @@ # set environment variables -SHORTNAME="basename $0" +SHORTNAME=`basename $0` PIDFILE=@PIDDIR@/"$SHORTNAME".pid LOCKFILE=@LOCKDIR@/"$SHORTNAME" LOGFILE=@AGENTLOG@ diff --git a/agent/distro/fedora/SYSCONFDIR/rc.d/init.d/cloud-agent.in b/agent/distro/fedora/SYSCONFDIR/rc.d/init.d/cloud-agent.in index 704ef6b05b4..d1769ccdfb0 100755 --- a/agent/distro/fedora/SYSCONFDIR/rc.d/init.d/cloud-agent.in +++ b/agent/distro/fedora/SYSCONFDIR/rc.d/init.d/cloud-agent.in @@ -26,7 +26,7 @@ # set environment variables -SHORTNAME="basename $0" +SHORTNAME=`basename $0` PIDFILE=@PIDDIR@/"$SHORTNAME".pid LOCKFILE=@LOCKDIR@/"$SHORTNAME" LOGFILE=@AGENTLOG@ diff --git a/agent/distro/opensuse/sles/SYSCONFDIR/init.d/cloud-agent.in b/agent/distro/opensuse/sles/SYSCONFDIR/init.d/cloud-agent.in index e684888b86e..741317bde43 100644 --- a/agent/distro/opensuse/sles/SYSCONFDIR/init.d/cloud-agent.in +++ b/agent/distro/opensuse/sles/SYSCONFDIR/init.d/cloud-agent.in @@ -33,7 +33,7 @@ # set environment variables -SHORTNAME="basename $0" +SHORTNAME=`basename $0` PIDFILE=@PIDDIR@/"$SHORTNAME".pid LOCKFILE=@LOCKDIR@/"$SHORTNAME" LOGFILE=@AGENTLOG@ diff --git a/agent/distro/rhel/SYSCONFDIR/rc.d/init.d/cloud-agent.in b/agent/distro/rhel/SYSCONFDIR/rc.d/init.d/cloud-agent.in index 704ef6b05b4..d1769ccdfb0 100644 --- a/agent/distro/rhel/SYSCONFDIR/rc.d/init.d/cloud-agent.in +++ b/agent/distro/rhel/SYSCONFDIR/rc.d/init.d/cloud-agent.in @@ -26,7 +26,7 @@ # set environment variables -SHORTNAME="basename $0" +SHORTNAME=`basename $0` PIDFILE=@PIDDIR@/"$SHORTNAME".pid LOCKFILE=@LOCKDIR@/"$SHORTNAME" LOGFILE=@AGENTLOG@ diff --git a/agent/distro/sles/SYSCONFDIR/init.d/cloud-agent.in b/agent/distro/sles/SYSCONFDIR/init.d/cloud-agent.in index e684888b86e..741317bde43 100644 --- a/agent/distro/sles/SYSCONFDIR/init.d/cloud-agent.in +++ b/agent/distro/sles/SYSCONFDIR/init.d/cloud-agent.in @@ -33,7 +33,7 @@ # set environment variables -SHORTNAME="basename $0" +SHORTNAME=`basename $0` PIDFILE=@PIDDIR@/"$SHORTNAME".pid LOCKFILE=@LOCKDIR@/"$SHORTNAME" LOGFILE=@AGENTLOG@ diff --git a/packaging/centos63/cloud-agent.rc b/packaging/centos63/cloud-agent.rc index af1c624eda2..ece4c2732f8 100755 --- a/packaging/centos63/cloud-agent.rc +++ b/packaging/centos63/cloud-agent.rc @@ -26,7 +26,7 @@ # set environment variables -SHORTNAME="basename $0" +SHORTNAME=`basename $0` PIDFILE=/var/run/"$SHORTNAME".pid LOCKFILE=/var/lock/subsys/"$SHORTNAME" LOGDIR=/var/log/cloudstack/agent diff --git a/packaging/centos63/cloud-ipallocator.rc b/packaging/centos63/cloud-ipallocator.rc index 9d1adb43506..d26287dcb3c 100755 --- a/packaging/centos63/cloud-ipallocator.rc +++ b/packaging/centos63/cloud-ipallocator.rc @@ -25,7 +25,7 @@ # set environment variables -SHORTNAME="basename $0" +SHORTNAME=`basename $0` PIDFILE=/var/run/"$SHORTNAME".pid LOCKFILE=/var/lock/subsys/"$SHORTNAME" LOGFILE=/var/log/cloudstack/ipallocator/ipallocator.log diff --git a/python/distro/centos/SYSCONFDIR/rc.d/init.d/cloud-ipallocator.in b/python/distro/centos/SYSCONFDIR/rc.d/init.d/cloud-ipallocator.in index ae8d2157541..3921484e54c 100755 --- a/python/distro/centos/SYSCONFDIR/rc.d/init.d/cloud-ipallocator.in +++ b/python/distro/centos/SYSCONFDIR/rc.d/init.d/cloud-ipallocator.in @@ -25,7 +25,7 @@ # set environment variables -SHORTNAME="basename $0" +SHORTNAME=`basename $0` PIDFILE=@PIDDIR@/"$SHORTNAME".pid LOCKFILE=@LOCKDIR@/"$SHORTNAME" LOGFILE=@IPALOCATORLOG@ diff --git a/python/distro/fedora/SYSCONFDIR/rc.d/init.d/cloud-ipallocator.in b/python/distro/fedora/SYSCONFDIR/rc.d/init.d/cloud-ipallocator.in index 49fd9b6f237..23ec8f3cd66 100755 --- a/python/distro/fedora/SYSCONFDIR/rc.d/init.d/cloud-ipallocator.in +++ b/python/distro/fedora/SYSCONFDIR/rc.d/init.d/cloud-ipallocator.in @@ -25,7 +25,7 @@ # set environment variables -SHORTNAME="basename $0" +SHORTNAME=`basename $0` PIDFILE=@PIDDIR@/"$SHORTNAME".pid LOCKFILE=@LOCKDIR@/"$SHORTNAME" LOGFILE=@AGENTLOG@ diff --git a/python/distro/opensuse/SYSCONFDIR/init.d/cloud-ipallocator.in b/python/distro/opensuse/SYSCONFDIR/init.d/cloud-ipallocator.in index 901d5845f39..558f5a2ee98 100755 --- a/python/distro/opensuse/SYSCONFDIR/init.d/cloud-ipallocator.in +++ b/python/distro/opensuse/SYSCONFDIR/init.d/cloud-ipallocator.in @@ -32,7 +32,7 @@ # set environment variables -SHORTNAME="basename $0" +SHORTNAME=`basename $0` PIDFILE=@PIDDIR@/"$SHORTNAME".pid LOCKFILE=@LOCKDIR@/"$SHORTNAME" LOGFILE=@AGENTLOG@ diff --git a/python/distro/rhel/SYSCONFDIR/rc.d/init.d/cloud-ipallocator.in b/python/distro/rhel/SYSCONFDIR/rc.d/init.d/cloud-ipallocator.in index 49fd9b6f237..23ec8f3cd66 100644 --- a/python/distro/rhel/SYSCONFDIR/rc.d/init.d/cloud-ipallocator.in +++ b/python/distro/rhel/SYSCONFDIR/rc.d/init.d/cloud-ipallocator.in @@ -25,7 +25,7 @@ # set environment variables -SHORTNAME="basename $0" +SHORTNAME=`basename $0` PIDFILE=@PIDDIR@/"$SHORTNAME".pid LOCKFILE=@LOCKDIR@/"$SHORTNAME" LOGFILE=@AGENTLOG@ diff --git a/python/distro/sles/SYSCONFDIR/init.d/cloud-ipallocator.in b/python/distro/sles/SYSCONFDIR/init.d/cloud-ipallocator.in index 901d5845f39..558f5a2ee98 100755 --- a/python/distro/sles/SYSCONFDIR/init.d/cloud-ipallocator.in +++ b/python/distro/sles/SYSCONFDIR/init.d/cloud-ipallocator.in @@ -32,7 +32,7 @@ # set environment variables -SHORTNAME="basename $0" +SHORTNAME=`basename $0` PIDFILE=@PIDDIR@/"$SHORTNAME".pid LOCKFILE=@LOCKDIR@/"$SHORTNAME" LOGFILE=@AGENTLOG@ diff --git a/python/distro/ubuntu/SYSCONFDIR/init.d/cloud-ipallocator.in b/python/distro/ubuntu/SYSCONFDIR/init.d/cloud-ipallocator.in index 5ec6da07f23..e2cb36197a6 100755 --- a/python/distro/ubuntu/SYSCONFDIR/init.d/cloud-ipallocator.in +++ b/python/distro/ubuntu/SYSCONFDIR/init.d/cloud-ipallocator.in @@ -26,7 +26,7 @@ # set environment variables -SHORTNAME="basename $0" +SHORTNAME=`basename $0` PIDFILE=@PIDDIR@/"$SHORTNAME".pid LOCKFILE=@LOCKDIR@/"$SHORTNAME" LOGFILE=@AGENTLOG@ diff --git a/systemvm/distro/centos/SYSCONFDIR/rc.d/init.d/cloud-console-proxy.in b/systemvm/distro/centos/SYSCONFDIR/rc.d/init.d/cloud-console-proxy.in index e43f6413c67..3ec4d0655cd 100644 --- a/systemvm/distro/centos/SYSCONFDIR/rc.d/init.d/cloud-console-proxy.in +++ b/systemvm/distro/centos/SYSCONFDIR/rc.d/init.d/cloud-console-proxy.in @@ -26,7 +26,7 @@ # set environment variables -SHORTNAME="basename $0" +SHORTNAME=`basename $0` PIDFILE=@PIDDIR@/"$SHORTNAME".pid LOCKFILE=@LOCKDIR@/"$SHORTNAME" LOGFILE=@CPLOG@ diff --git a/systemvm/distro/fedora/SYSCONFDIR/rc.d/init.d/cloud-console-proxy.in b/systemvm/distro/fedora/SYSCONFDIR/rc.d/init.d/cloud-console-proxy.in index e43f6413c67..3ec4d0655cd 100644 --- a/systemvm/distro/fedora/SYSCONFDIR/rc.d/init.d/cloud-console-proxy.in +++ b/systemvm/distro/fedora/SYSCONFDIR/rc.d/init.d/cloud-console-proxy.in @@ -26,7 +26,7 @@ # set environment variables -SHORTNAME="basename $0" +SHORTNAME=`basename $0` PIDFILE=@PIDDIR@/"$SHORTNAME".pid LOCKFILE=@LOCKDIR@/"$SHORTNAME" LOGFILE=@CPLOG@ diff --git a/systemvm/distro/rhel/SYSCONFDIR/rc.d/init.d/cloud-console-proxy.in b/systemvm/distro/rhel/SYSCONFDIR/rc.d/init.d/cloud-console-proxy.in index e43f6413c67..3ec4d0655cd 100644 --- a/systemvm/distro/rhel/SYSCONFDIR/rc.d/init.d/cloud-console-proxy.in +++ b/systemvm/distro/rhel/SYSCONFDIR/rc.d/init.d/cloud-console-proxy.in @@ -26,7 +26,7 @@ # set environment variables -SHORTNAME="basename $0" +SHORTNAME=`basename $0` PIDFILE=@PIDDIR@/"$SHORTNAME".pid LOCKFILE=@LOCKDIR@/"$SHORTNAME" LOGFILE=@CPLOG@ diff --git a/systemvm/distro/ubuntu/SYSCONFDIR/init.d/cloud-console-proxy.in b/systemvm/distro/ubuntu/SYSCONFDIR/init.d/cloud-console-proxy.in index 87a653e920b..0c7be737353 100755 --- a/systemvm/distro/ubuntu/SYSCONFDIR/init.d/cloud-console-proxy.in +++ b/systemvm/distro/ubuntu/SYSCONFDIR/init.d/cloud-console-proxy.in @@ -27,7 +27,7 @@ # set environment variables -SHORTNAME="basename $0" +SHORTNAME=`basename $0` PIDFILE=@PIDDIR@/"$SHORTNAME".pid LOCKFILE=@LOCKDIR@/"$SHORTNAME" LOGFILE=@CPLOG@ From 466825a167b3ee465a92297b96fb517bb35a810f Mon Sep 17 00:00:00 2001 From: Alena Prokharchyk Date: Mon, 10 Mar 2014 15:27:13 -0700 Subject: [PATCH 46/70] Fixed nonoss build --- .../src/com/cloud/network/element/CiscoNexusVSMElement.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/plugins/hypervisors/vmware/src/com/cloud/network/element/CiscoNexusVSMElement.java b/plugins/hypervisors/vmware/src/com/cloud/network/element/CiscoNexusVSMElement.java index c33af27d244..0e2a9117f10 100644 --- a/plugins/hypervisors/vmware/src/com/cloud/network/element/CiscoNexusVSMElement.java +++ b/plugins/hypervisors/vmware/src/com/cloud/network/element/CiscoNexusVSMElement.java @@ -79,6 +79,8 @@ public class CiscoNexusVSMElement extends CiscoNexusVSMDeviceManagerImpl impleme ClusterDao _clusterDao; @Inject ClusterVSMMapDao _clusterVSMDao; + @Inject + ManagementService _mgr; @Override public Map> getCapabilities() { @@ -190,7 +192,8 @@ public class CiscoNexusVSMElement extends CiscoNexusVSMDeviceManagerImpl impleme // Else if there is only a zoneId defined, get a list of all vmware clusters // in the zone, and then for each cluster, pull the VSM and prepare a list. if (zoneId != null && zoneId.longValue() != 0) { - ManagementService ref = cmd.getMgmtServiceRef(); + ManagementService ref = _mgr; + ; List clusterList = ref.searchForClusters(zoneId, cmd.getStartIndex(), cmd.getPageSizeVal(), "VMware"); if (clusterList.size() == 0) { From 33a0dec965c96483c8cd55e309250662fca5e2da Mon Sep 17 00:00:00 2001 From: Nitin Mehta Date: Mon, 10 Mar 2014 16:22:34 -0700 Subject: [PATCH 47/70] CLOUDSTACK-6221: Publish first class objects involved in an operation (for now vm uuid) on the event bus . Example - during attach/detachIso along with iso id, vm id should be available as well. --- api/src/com/cloud/event/EventTypes.java | 1 + server/src/com/cloud/api/ApiDispatcher.java | 9 ++++++++- server/src/com/cloud/api/ApiServer.java | 11 ++++++++++- server/src/com/cloud/event/ActionEventUtils.java | 8 +++++++- utils/src/com/cloud/utils/ReflectUtil.java | 13 +++++++++++++ 5 files changed, 39 insertions(+), 3 deletions(-) diff --git a/api/src/com/cloud/event/EventTypes.java b/api/src/com/cloud/event/EventTypes.java index 7994adab82e..a5fc0f0f7d3 100755 --- a/api/src/com/cloud/event/EventTypes.java +++ b/api/src/com/cloud/event/EventTypes.java @@ -483,6 +483,7 @@ public class EventTypes { // TODO: need a way to force author adding event types to declare the entity details as well, with out braking // current ActionEvent annotation semantics + // TODO #2 - The map should be from event type to class. entityEventDetails = new HashMap(); diff --git a/server/src/com/cloud/api/ApiDispatcher.java b/server/src/com/cloud/api/ApiDispatcher.java index 8f980d99038..27ff9521974 100755 --- a/server/src/com/cloud/api/ApiDispatcher.java +++ b/server/src/com/cloud/api/ApiDispatcher.java @@ -22,6 +22,8 @@ import javax.annotation.PostConstruct; import javax.inject.Inject; import com.cloud.event.EventTypes; +import com.cloud.utils.ReflectUtil; +import com.cloud.vm.VirtualMachine; import org.apache.cloudstack.api.ApiConstants; import org.apache.cloudstack.api.BaseAsyncCmd; import org.apache.cloudstack.api.BaseAsyncCreateCmd; @@ -83,13 +85,18 @@ public class ApiDispatcher { final BaseAsyncCmd asyncCmd = (BaseAsyncCmd)cmd; final String startEventId = params.get(ApiConstants.CTX_START_EVENT_ID); - String uuid = params.get("uuid"); + String uuid = params.get(ApiConstants.UUID); ctx.setStartEventId(Long.valueOf(startEventId)); // Fow now use the key from EventTypes.java rather than getInstanceType bcz the later doesn't refer to the interfaces + // Add the resource id in the call context, also add some other first class object ids (for now vm) if available. + // TODO - this should be done for all the uuids passed in the cmd - so should be moved where uuid to id conversion happens. if(EventTypes.getEntityForEvent(asyncCmd.getEventType()) != null){ ctx.putContextParameter(EventTypes.getEntityForEvent(asyncCmd.getEventType()), uuid); } + if(params.get(ApiConstants.VIRTUAL_MACHINE_ID) != null){ + ctx.putContextParameter(ReflectUtil.getEntityName(VirtualMachine.class), params.get(ApiConstants.VIRTUAL_MACHINE_ID)); + } // Synchronise job on the object if needed if (asyncCmd.getJob() != null && asyncCmd.getSyncObjId() != null && asyncCmd.getSyncObjType() != null) { diff --git a/server/src/com/cloud/api/ApiServer.java b/server/src/com/cloud/api/ApiServer.java index 7ad7c106952..35026897d79 100755 --- a/server/src/com/cloud/api/ApiServer.java +++ b/server/src/com/cloud/api/ApiServer.java @@ -54,6 +54,8 @@ import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; import com.cloud.event.EventTypes; +import com.cloud.utils.ReflectUtil; +import com.cloud.vm.VirtualMachine; import org.apache.cloudstack.acl.APIChecker; import org.apache.cloudstack.api.APICommand; import org.apache.cloudstack.api.ApiConstants; @@ -503,6 +505,7 @@ public class ApiServer extends ManagerBase implements HttpRequestHandler, ApiSer final CallContext ctx = CallContext.current(); final Long callerUserId = ctx.getCallingUserId(); final Account caller = ctx.getCallingAccount(); + String vmUUID = params.get(ApiConstants.VIRTUAL_MACHINE_ID); // Queue command based on Cmd super class: // BaseCmd: cmd is dispatched to ApiDispatcher, executed, serialized and returned. @@ -519,7 +522,7 @@ public class ApiServer extends ManagerBase implements HttpRequestHandler, ApiSer params.put("id", objectId.toString()); } else { // Extract the uuid before params are processed and id reflects internal db id - objectUuid = params.get("id"); + objectUuid = params.get(ApiConstants.ID); dispatchChainFactory.getStandardDispatchChain().dispatch(new DispatchTask(cmdObj, params)); } @@ -538,9 +541,15 @@ public class ApiServer extends ManagerBase implements HttpRequestHandler, ApiSer long startEventId = ctx.getStartEventId(); asyncCmd.setStartEventId(startEventId); + // Add the resource id in the call context, also add some other first class object ids (for now vm) if available. + // TODO - this should be done for all the uuids passed in the cmd - so should be moved where uuid to id conversion happens. if(EventTypes.getEntityForEvent(asyncCmd.getEventType()) != null){ ctx.putContextParameter(EventTypes.getEntityForEvent(asyncCmd.getEventType()), objectUuid); } + if(vmUUID != null){ + ctx.putContextParameter(ReflectUtil.getEntityName(VirtualMachine.class), vmUUID); + } + // save the scheduled event final Long eventId = ActionEventUtils.onScheduledActionEvent((callerUserId == null) ? User.UID_SYSTEM : callerUserId, asyncCmd.getEntityOwnerId(), asyncCmd.getEventType(), diff --git a/server/src/com/cloud/event/ActionEventUtils.java b/server/src/com/cloud/event/ActionEventUtils.java index 59546708bce..28e5680b630 100755 --- a/server/src/com/cloud/event/ActionEventUtils.java +++ b/server/src/com/cloud/event/ActionEventUtils.java @@ -25,6 +25,8 @@ import java.util.Map; import javax.annotation.PostConstruct; import javax.inject.Inject; +import com.cloud.utils.ReflectUtil; +import com.cloud.vm.VirtualMachine; import org.apache.log4j.Logger; import org.springframework.beans.factory.NoSuchBeanDefinitionException; @@ -186,10 +188,12 @@ public class ActionEventUtils { String entityType = null; String entityUuid = null; CallContext context = CallContext.current(); + String vmEntityName = ReflectUtil.getEntityName(VirtualMachine.class); + String vmuuid = (String) context.getContextParameter(vmEntityName); Class entityKey = getEntityKey(eventType); if (entityKey != null) { - //FIXME - Remove this + //FIXME - Remove this since it should be covered by the else if condition below. entityUuid = (String)context.getContextParameter(entityKey); if (entityUuid != null) entityType = entityKey.getName(); @@ -220,6 +224,8 @@ public class ActionEventUtils { eventDescription.put("status", state.toString()); eventDescription.put("entity", entityType); eventDescription.put("entityuuid", entityUuid); + //Put all the first class entities that are touched during the action. For now atleast put in the vmid. + eventDescription.put(vmEntityName, vmuuid); eventDescription.put("description", description); String eventDate = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss Z").format(new Date()); diff --git a/utils/src/com/cloud/utils/ReflectUtil.java b/utils/src/com/cloud/utils/ReflectUtil.java index 379f1c0bd27..9c09980e0fc 100755 --- a/utils/src/com/cloud/utils/ReflectUtil.java +++ b/utils/src/com/cloud/utils/ReflectUtil.java @@ -189,4 +189,17 @@ public class ReflectUtil { } + public static String getEntityName(Class clz){ + if(clz == null) + return null; + + String entityName = clz.getName(); + int index = entityName.lastIndexOf("."); + if (index != -1) { + return entityName.substring(index + 1); + }else{ + return entityName; + } + } + } From 540d020aa5c0cd5d3b4657973b1c8a852bdf6d58 Mon Sep 17 00:00:00 2001 From: Rajesh Battala Date: Tue, 11 Mar 2014 13:09:18 +0530 Subject: [PATCH 48/70] CLOUDSTACK-6179 Execute VR commands on Virtual Resource when commands received to Hyper-V --- .../hypervisor/hyperv/guru/HypervGuru.java | 9 +- .../resource/HypervDirectConnectResource.java | 216 +++++++++++++++++- .../config/etc/init.d/cloud-early-config | 8 +- 3 files changed, 222 insertions(+), 11 deletions(-) diff --git a/plugins/hypervisors/hyperv/src/com/cloud/hypervisor/hyperv/guru/HypervGuru.java b/plugins/hypervisors/hyperv/src/com/cloud/hypervisor/hyperv/guru/HypervGuru.java index 1d9e7f619f9..bf0795df059 100644 --- a/plugins/hypervisors/hyperv/src/com/cloud/hypervisor/hyperv/guru/HypervGuru.java +++ b/plugins/hypervisors/hyperv/src/com/cloud/hypervisor/hyperv/guru/HypervGuru.java @@ -53,7 +53,7 @@ public class HypervGuru extends HypervisorGuruBase implements HypervisorGuru { @Inject HypervManager _hypervMgr; @Inject NetworkDao _networkDao; @Inject NetworkModel _networkMgr; - + int MaxNicSupported = 8; @Override public final HypervisorType getHypervisorType() { return HypervisorType.Hyperv; @@ -85,7 +85,7 @@ public class HypervGuru extends HypervisorGuruBase implements HypervisorGuru { NicTO[] nics = to.getNics(); // reserve extra NICs - NicTO[] expandedNics = new NicTO[nics.length + _hypervMgr.getRouterExtraPublicNics()]; + NicTO[] expandedNics = new NicTO[MaxNicSupported]; int i = 0; int deviceId = -1; for(i = 0; i < nics.length; i++) { @@ -97,8 +97,9 @@ public class HypervGuru extends HypervisorGuruBase implements HypervisorGuru { long networkId = publicNicProfile.getNetworkId(); NetworkVO network = _networkDao.findById(networkId); - - for(; i < nics.length + _hypervMgr.getRouterExtraPublicNics(); i++) { + // for Hyperv Hot Nic plug is not supported and it will support upto 8 nics. + // creating the VR with extra nics (actual nics(3) + extra nics) will be 8 + for(; i < MaxNicSupported; i++) { NicTO nicTo = new NicTO(); nicTo.setDeviceId(deviceId++); nicTo.setBroadcastType(publicNicProfile.getBroadcastType()); diff --git a/plugins/hypervisors/hyperv/src/com/cloud/hypervisor/hyperv/resource/HypervDirectConnectResource.java b/plugins/hypervisors/hyperv/src/com/cloud/hypervisor/hyperv/resource/HypervDirectConnectResource.java index 549f06d9ef1..a3ffa758f8e 100644 --- a/plugins/hypervisors/hyperv/src/com/cloud/hypervisor/hyperv/resource/HypervDirectConnectResource.java +++ b/plugins/hypervisors/hyperv/src/com/cloud/hypervisor/hyperv/resource/HypervDirectConnectResource.java @@ -83,6 +83,7 @@ import com.cloud.agent.api.NetworkUsageCommand; import com.cloud.agent.api.PingCommand; import com.cloud.agent.api.PingRoutingCommand; import com.cloud.agent.api.PingTestCommand; +import com.cloud.agent.api.SetupGuestNetworkCommand; import com.cloud.agent.api.StartCommand; import com.cloud.agent.api.StartupCommand; import com.cloud.agent.api.StartupRoutingCommand; @@ -98,6 +99,7 @@ import com.cloud.agent.api.routing.DnsMasqConfigCommand; import com.cloud.agent.api.routing.IpAliasTO; import com.cloud.agent.api.routing.IpAssocAnswer; import com.cloud.agent.api.routing.IpAssocCommand; +import com.cloud.agent.api.routing.IpAssocVpcCommand; import com.cloud.agent.api.routing.LoadBalancerConfigCommand; import com.cloud.agent.api.routing.NetworkElementCommand; import com.cloud.agent.api.routing.RemoteAccessVpnCfgCommand; @@ -105,6 +107,7 @@ import com.cloud.agent.api.routing.SavePasswordCommand; import com.cloud.agent.api.routing.SetFirewallRulesAnswer; import com.cloud.agent.api.routing.SetFirewallRulesCommand; import com.cloud.agent.api.routing.SetMonitorServiceCommand; +import com.cloud.agent.api.routing.SetNetworkACLCommand; import com.cloud.agent.api.routing.SetPortForwardingRulesAnswer; import com.cloud.agent.api.routing.SetPortForwardingRulesCommand; import com.cloud.agent.api.routing.SetSourceNatAnswer; @@ -119,9 +122,12 @@ import com.cloud.agent.api.routing.VpnUsersCfgCommand; import com.cloud.agent.api.to.DhcpTO; import com.cloud.agent.api.to.FirewallRuleTO; import com.cloud.agent.api.to.IpAddressTO; +import com.cloud.agent.api.to.NicTO; import com.cloud.agent.api.to.PortForwardingRuleTO; import com.cloud.agent.api.to.StaticNatRuleTO; import com.cloud.agent.api.to.VirtualMachineTO; +import com.cloud.agent.resource.virtualnetwork.VirtualRouterDeployer; +import com.cloud.agent.resource.virtualnetwork.VirtualRoutingResource; import com.cloud.dc.DataCenter.NetworkType; import com.cloud.exception.InternalErrorException; import com.cloud.host.Host.Type; @@ -135,6 +141,7 @@ import com.cloud.network.rules.FirewallRule; import com.cloud.resource.ServerResource; import com.cloud.resource.ServerResourceBase; import com.cloud.serializer.GsonHelper; +import com.cloud.utils.ExecutionResult; import com.cloud.utils.Pair; import com.cloud.utils.StringUtils; import com.cloud.utils.net.NetUtils; @@ -148,7 +155,7 @@ import com.cloud.vm.VirtualMachineName; * Implementation of dummy resource to be returned from discoverer. **/ @Local(value = ServerResource.class) -public class HypervDirectConnectResource extends ServerResourceBase implements ServerResource { +public class HypervDirectConnectResource extends ServerResourceBase implements ServerResource, VirtualRouterDeployer { public static final int DEFAULT_AGENT_PORT = 8250; public static final String HOST_VM_STATE_REPORT_COMMAND = "org.apache.cloudstack.HostVmStateReportCommand"; private static final Logger s_logger = Logger.getLogger(HypervDirectConnectResource.class.getName()); @@ -178,6 +185,7 @@ public class HypervDirectConnectResource extends ServerResourceBase implements S private static HypervManager s_hypervMgr; @Inject HypervManager _hypervMgr; + protected VirtualRoutingResource _vrResource; @PostConstruct void init() { @@ -421,8 +429,9 @@ public class HypervDirectConnectResource extends ServerResourceBase implements S s_logger.error(errMsg, e); return null; } - - if (clazz == CheckSshCommand.class) { + if (cmd instanceof NetworkElementCommand) { + return _vrResource.executeRequest((NetworkElementCommand)cmd); + }if (clazz == CheckSshCommand.class) { answer = execute((CheckSshCommand)cmd); } else if (clazz == GetDomRVersionCmd.class) { answer = execute((GetDomRVersionCmd)cmd); @@ -499,6 +508,203 @@ public class HypervDirectConnectResource extends ServerResourceBase implements S } return answer; } + + @Override + public ExecutionResult executeInVR(String routerIP, String script, String args) { + Pair result; + + //TODO: Password should be masked, cannot output to log directly + if (s_logger.isDebugEnabled()) { + s_logger.debug("Run command on VR: " + routerIP + ", script: " + script + " with args: " + args); + } + + try { + result = SshHelper.sshExecute(routerIP, DEFAULT_DOMR_SSHPORT, "root", getSystemVMKeyFile(), null, "/opt/cloud/bin/" + script + " " + args); + } catch (Exception e) { + String msg = "Command failed due to " + e ; + s_logger.error(msg); + result = new Pair(false, msg); + } + if (s_logger.isDebugEnabled()) { + s_logger.debug(script + " execution result: " + result.first().toString()); + } + return new ExecutionResult(result.first(), result.second()); + } + + @Override + public ExecutionResult createFileInVR(String routerIp, String filePath, String fileName, String content) { + File keyFile = getSystemVMKeyFile(); + try { + SshHelper.scpTo(routerIp, 3922, "root", keyFile, null, filePath, content.getBytes(), fileName, null); + } catch (Exception e) { + s_logger.warn("Fail to create file " + filePath + fileName + " in VR " + routerIp, e); + return new ExecutionResult(false, e.getMessage()); + } + return new ExecutionResult(true, null); + } + + @Override + public ExecutionResult prepareCommand(NetworkElementCommand cmd) { + //Update IP used to access router + cmd.setRouterAccessIp(getRouterSshControlIp(cmd)); + assert cmd.getRouterAccessIp() != null; + + if (cmd instanceof IpAssocVpcCommand) { + return prepareNetworkElementCommand((IpAssocVpcCommand)cmd); + } else if (cmd instanceof IpAssocCommand) { + return prepareNetworkElementCommand((IpAssocCommand)cmd); + } else if (cmd instanceof SetSourceNatCommand) { + return prepareNetworkElementCommand((SetSourceNatCommand)cmd); + } else if (cmd instanceof SetupGuestNetworkCommand) { + return prepareNetworkElementCommand((SetupGuestNetworkCommand)cmd); + } else if (cmd instanceof SetNetworkACLCommand) { + return prepareNetworkElementCommand((SetNetworkACLCommand)cmd); + } + return new ExecutionResult(true, null); + } + + private ExecutionResult prepareNetworkElementCommand(IpAssocCommand cmd) { + try { + + IpAddressTO[] ips = cmd.getIpAddresses(); + String routerName = cmd.getAccessDetail(NetworkElementCommand.ROUTER_NAME); + String controlIp = getRouterSshControlIp(cmd); + + for (IpAddressTO ip : ips) { + /** + * TODO support other networks + */ + URI broadcastUri = BroadcastDomainType.fromString(ip.getBroadcastUri()); + if (BroadcastDomainType.getSchemeValue(broadcastUri) != BroadcastDomainType.Vlan) { + throw new InternalErrorException("Unable to assign a public IP to a VIF on network " + ip.getBroadcastUri()); + } + int vlanId = Integer.parseInt(BroadcastDomainType.getValue(broadcastUri)); + int publicNicInfo = -1; + publicNicInfo = getVmNics(routerName, vlanId); + + boolean addVif = false; + if (ip.isAdd() && publicNicInfo == -1) { + if (s_logger.isDebugEnabled()) { + s_logger.debug("Plug new NIC to associate" + controlIp + " to " + ip.getPublicIp()); + } + addVif = true; + } + + if (addVif) { + Pair nicdevice = findRouterFreeEthDeviceIndex(controlIp); + publicNicInfo = nicdevice.first(); + if (publicNicInfo > 0) { + modifyNicVlan(routerName, vlanId, nicdevice.second()); + // After modifying the vnic on VR, check the VR VNics config in the host and get the device position + publicNicInfo = getVmNics(routerName, vlanId); + // As a new nic got activated in the VR. add the entry in the NIC's table. + networkUsage(controlIp, "addVif", "eth" + publicNicInfo); + } + else { + // we didn't find any eth device available in VR to configure the ip range with new VLAN + String msg = "No Nic is available on DomR VIF to associate/disassociate IP with."; + s_logger.error(msg); + throw new InternalErrorException(msg); + } + ip.setNicDevId(publicNicInfo); + ip.setNewNic(addVif); + } else { + ip.setNicDevId(publicNicInfo); + } + } + } catch (Throwable e) { + s_logger.error("Unexpected exception: " + e.toString() + " will shortcut rest of IPAssoc commands", e); + return new ExecutionResult(false, e.toString()); + } + return new ExecutionResult(true, null); + } + + protected ExecutionResult prepareNetworkElementCommand(SetupGuestNetworkCommand cmd) { + NicTO nic = cmd.getNic(); + String routerIp = getRouterSshControlIp(cmd); + String domrName = + cmd.getAccessDetail(NetworkElementCommand.ROUTER_NAME); + + try { + int ethDeviceNum = findRouterEthDeviceIndex(domrName, routerIp, + nic.getMac()); + nic.setDeviceId(ethDeviceNum); + } catch (Exception e) { + String msg = "Prepare SetupGuestNetwork failed due to " + e.toString(); + s_logger.warn(msg, e); + return new ExecutionResult(false, msg); + } + return new ExecutionResult(true, null); + } + + + private ExecutionResult prepareNetworkElementCommand(IpAssocVpcCommand cmd) { + String routerName = cmd.getAccessDetail(NetworkElementCommand.ROUTER_NAME); + String routerIp = getRouterSshControlIp(cmd); + + try { + IpAddressTO[] ips = cmd.getIpAddresses(); + for (IpAddressTO ip : ips) { + + int ethDeviceNum = findRouterEthDeviceIndex(routerName, routerIp, ip.getVifMacAddress()); + if (ethDeviceNum < 0) { + if (ip.isAdd()) { + throw new InternalErrorException("Failed to find DomR VIF to associate/disassociate IP with."); + } else { + s_logger.debug("VIF to deassociate IP with does not exist, return success"); + continue; + } + } + + ip.setNicDevId(ethDeviceNum); + } + } catch (Exception e) { + s_logger.error("Prepare Ip Assoc failure on applying one ip due to exception: ", e); + return new ExecutionResult(false, e.toString()); + } + + return new ExecutionResult(true, null); + } + + protected ExecutionResult prepareNetworkElementCommand(SetSourceNatCommand cmd) { + String routerName = cmd.getAccessDetail(NetworkElementCommand.ROUTER_NAME); + String routerIp = getRouterSshControlIp(cmd); + IpAddressTO pubIp = cmd.getIpAddress(); + + try { + int ethDeviceNum = findRouterEthDeviceIndex(routerName, routerIp, pubIp.getVifMacAddress()); + pubIp.setNicDevId(ethDeviceNum); + } catch (Exception e) { + String msg = "Prepare Ip SNAT failure due to " + e.toString(); + s_logger.error(msg, e); + return new ExecutionResult(false, e.toString()); + } + return new ExecutionResult(true, null); + } + + private ExecutionResult prepareNetworkElementCommand(SetNetworkACLCommand cmd) { + NicTO nic = cmd.getNic(); + String routerName = + cmd.getAccessDetail(NetworkElementCommand.ROUTER_NAME); + String routerIp = getRouterSshControlIp(cmd); + + try { + int ethDeviceNum = findRouterEthDeviceIndex(routerName, routerIp, + nic.getMac()); + nic.setDeviceId(ethDeviceNum); + } catch (Exception e) { + String msg = "Prepare SetNetworkACL failed due to " + e.toString(); + s_logger.error(msg, e); + return new ExecutionResult(false, msg); + } + return new ExecutionResult(true, null); + } + + @Override + public ExecutionResult cleanupCommand(NetworkElementCommand cmd) { + return new ExecutionResult(true, null); + } + protected Answer execute(final RemoteAccessVpnCfgCommand cmd) { String controlIp = getRouterSshControlIp(cmd); StringBuffer argsBuf = new StringBuffer(); @@ -1926,6 +2132,10 @@ public class HypervDirectConnectResource extends ServerResourceBase implements S _configureCalled = true; } + _vrResource = new VirtualRoutingResource(this); + if (!_vrResource.configure(name, new HashMap())) { + throw new ConfigurationException("Unable to configure VirtualRoutingResource"); + } return true; } diff --git a/systemvm/patches/debian/config/etc/init.d/cloud-early-config b/systemvm/patches/debian/config/etc/init.d/cloud-early-config index fa95fdadb16..c287d43452b 100755 --- a/systemvm/patches/debian/config/etc/init.d/cloud-early-config +++ b/systemvm/patches/debian/config/etc/init.d/cloud-early-config @@ -1221,10 +1221,6 @@ start() { patch_log4j parse_cmd_line change_password - if [ "$hyp" == "hyperv" ]; then - # eject the systemvm.iso - eject - fi case $TYPE in router) [ "$NAME" == "" ] && NAME=router @@ -1259,6 +1255,10 @@ start() { setup_default; ;; esac + if [ "$hyp" == "hyperv" ]; then + # eject the systemvm.iso + eject + fi return 0 } From c7d31fe288b13ff4f0f046f83f9eb4a9c2bf06c5 Mon Sep 17 00:00:00 2001 From: Sanjay Tripathi Date: Thu, 6 Feb 2014 15:08:53 +0530 Subject: [PATCH 49/70] CLOUDSTACK-4760 : Enabling GPU support for XenServer. CLOUDSTACK-4762 : Enabling VGPU support for XenServer. This feature is to enable the GPU-passthrough and vGPU functionality, with the help of this feature, admins/users will be able to leverage the GPU graphics unit power by deploying a virtul machine with GPU or vGPU support or by changing the service offering of an existing VM at any later point of time. There GPU/vGPU enabled VMs are able to run graphical applications. For now, this feature is only supported with XenServer hypervisor but can be extended to add the support of other hypervisors. --- .../com/cloud/agent/api/to/GPUDeviceTO.java | 56 +++++ .../cloud/agent/api/to/VirtualMachineTO.java | 9 + api/src/com/cloud/gpu/GPU.java | 49 ++++ .../apache/cloudstack/api/ApiConstants.java | 5 + .../offering/CreateServiceOfferingCmd.java | 18 +- .../cloudstack/api/response/GpuResponse.java | 46 ++++ .../cloudstack/api/response/HostResponse.java | 8 + .../api/response/UserVmResponse.java | 10 + .../cloudstack/api/response/VgpuResponse.java | 52 ++++ .../cloud/agent/api/GetGPUStatsAnswer.java | 36 +++ .../cloud/agent/api/GetGPUStatsCommand.java | 47 ++++ .../agent/api/StartupRoutingCommand.java | 9 + core/src/com/cloud/agent/api/StopCommand.java | 9 + .../com/cloud/resource/ResourceManager.java | 41 ++++ .../cloud/vm/VirtualMachineManagerImpl.java | 18 ++ ...spring-engine-schema-core-daos-context.xml | 2 + .../src/com/cloud/gpu/HostGpuGroupsVO.java | 70 ++++++ .../schema/src/com/cloud/gpu/VGPUTypesVO.java | 82 +++++++ .../com/cloud/gpu/dao/HostGpuGroupsDao.java | 60 +++++ .../cloud/gpu/dao/HostGpuGroupsDaoImpl.java | 94 ++++++++ .../src/com/cloud/gpu/dao/VGPUTypesDao.java | 48 ++++ .../com/cloud/gpu/dao/VGPUTypesDaoImpl.java | 95 ++++++++ engine/schema/src/com/cloud/host/HostVO.java | 13 + .../src/com/cloud/host/dao/HostDaoImpl.java | 18 ++ .../service/ServiceOfferingDetailsVO.java | 4 + .../xen/resource/CitrixResourceBase.java | 108 +++++++++ .../allocator/impl/FirstFitAllocator.java | 17 +- server/src/com/cloud/api/ApiDBUtils.java | 30 +++ .../cloud/api/query/dao/HostJoinDaoImpl.java | 25 ++ .../api/query/dao/UserVmJoinDaoImpl.java | 6 + .../ConfigurationManagerImpl.java | 54 ++++- .../deploy/DeploymentPlanningManagerImpl.java | 14 +- .../cloud/hypervisor/HypervisorGuruBase.java | 15 ++ .../network/NetworkUsageManagerImpl.java | 4 + .../cloud/resource/ResourceManagerImpl.java | 97 +++++++- .../cloud/server/ManagementServerImpl.java | 12 + .../src/com/cloud/server/StatsCollector.java | 21 ++ .../cloud/storage/VolumeApiServiceImpl.java | 8 + .../src/com/cloud/vm/UserVmManagerImpl.java | 10 + .../resource/MockResourceManagerImpl.java | 31 +++ .../vm/DeploymentPlanningManagerImplTest.java | 12 + .../test/resources/createNetworkOffering.xml | 4 +- setup/db/db/schema-430to440.sql | 18 ++ .../smoke/test_deploy_vgpu_enabled_vm.py | 227 ++++++++++++++++++ tools/marvin/marvin/integration/lib/base.py | 3 + ui/scripts/configuration.js | 73 ++++++ ui/scripts/instances.js | 4 +- 47 files changed, 1671 insertions(+), 21 deletions(-) create mode 100644 api/src/com/cloud/agent/api/to/GPUDeviceTO.java create mode 100644 api/src/com/cloud/gpu/GPU.java create mode 100644 api/src/org/apache/cloudstack/api/response/GpuResponse.java create mode 100644 api/src/org/apache/cloudstack/api/response/VgpuResponse.java create mode 100644 core/src/com/cloud/agent/api/GetGPUStatsAnswer.java create mode 100644 core/src/com/cloud/agent/api/GetGPUStatsCommand.java create mode 100644 engine/schema/src/com/cloud/gpu/HostGpuGroupsVO.java create mode 100644 engine/schema/src/com/cloud/gpu/VGPUTypesVO.java create mode 100644 engine/schema/src/com/cloud/gpu/dao/HostGpuGroupsDao.java create mode 100644 engine/schema/src/com/cloud/gpu/dao/HostGpuGroupsDaoImpl.java create mode 100644 engine/schema/src/com/cloud/gpu/dao/VGPUTypesDao.java create mode 100644 engine/schema/src/com/cloud/gpu/dao/VGPUTypesDaoImpl.java create mode 100644 test/integration/smoke/test_deploy_vgpu_enabled_vm.py diff --git a/api/src/com/cloud/agent/api/to/GPUDeviceTO.java b/api/src/com/cloud/agent/api/to/GPUDeviceTO.java new file mode 100644 index 00000000000..8bc9e5229de --- /dev/null +++ b/api/src/com/cloud/agent/api/to/GPUDeviceTO.java @@ -0,0 +1,56 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. +package com.cloud.agent.api.to; + +import java.util.HashMap; + +public class GPUDeviceTO { + + private String gpuGroup; + private String vgpuType; + private HashMap> groupDetails = new HashMap>(); + + public GPUDeviceTO( String gpuGroup, String vgpuType, HashMap> groupDetails) { + this.gpuGroup = gpuGroup; + this.vgpuType = vgpuType; + this.groupDetails = groupDetails; + } + + public String getGpuGroup() { + return gpuGroup; + } + + public String getVgpuType() { + return vgpuType; + } + + public void setGpuGroup(String gpuGroup) { + this.gpuGroup = gpuGroup; + } + + public void setVgpuType(String vgpuType) { + this.vgpuType = vgpuType; + } + + public HashMap> getGroupDetails() { + return groupDetails; + } + + public void setGroupDetails(HashMap> groupDetails) { + this.groupDetails = groupDetails; + } +} diff --git a/api/src/com/cloud/agent/api/to/VirtualMachineTO.java b/api/src/com/cloud/agent/api/to/VirtualMachineTO.java index bed3e1d6aaf..bbd83852abf 100644 --- a/api/src/com/cloud/agent/api/to/VirtualMachineTO.java +++ b/api/src/com/cloud/agent/api/to/VirtualMachineTO.java @@ -60,6 +60,7 @@ public class VirtualMachineTO { DiskTO[] disks; NicTO[] nics; + GPUDeviceTO gpuDevice; public VirtualMachineTO(long id, String instanceName, VirtualMachine.Type type, int cpus, Integer speed, long minRam, long maxRam, BootloaderType bootloader, String os, boolean enableHA, boolean limitCpuUse, String vncPassword) { @@ -266,4 +267,12 @@ public class VirtualMachineTO { this.uuid = uuid; } + public GPUDeviceTO getGpuDevice() { + return gpuDevice; + } + + public void setGpuDevice(GPUDeviceTO gpuDevice) { + this.gpuDevice = gpuDevice; + } + } diff --git a/api/src/com/cloud/gpu/GPU.java b/api/src/com/cloud/gpu/GPU.java new file mode 100644 index 00000000000..0eb466758fc --- /dev/null +++ b/api/src/com/cloud/gpu/GPU.java @@ -0,0 +1,49 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. +package com.cloud.gpu; + + +public class GPU { + + public enum Keys { + pciDevice, + vgpuType + } + public enum Type { + GPU_Passthrough, + VGPU + } + + public enum vGPUType { + GRID_K100("GRID K100"), + GRID_K140Q("GRID K140Q"), + GRID_K200("GRID K200"), + GRID_K240Q("GRID K240Q"), + GRID_K260("GRID K260Q"), + passthrough("passthrough"); + + private String type; + + vGPUType(String type) { + this.type = type; + } + + public String getType() { + return type; + } + } +} diff --git a/api/src/org/apache/cloudstack/api/ApiConstants.java b/api/src/org/apache/cloudstack/api/ApiConstants.java index f0de48e0c0e..0a3fafda312 100755 --- a/api/src/org/apache/cloudstack/api/ApiConstants.java +++ b/api/src/org/apache/cloudstack/api/ApiConstants.java @@ -581,6 +581,11 @@ public class ApiConstants { public static final String PASSIVE = "passive"; public static final String VERSION = "version"; public static final String START = "start"; + public static final String GPUGROUP = "gpugroup"; + public static final String GPUGROUPNAME = "gpugroupname"; + public static final String VGPU = "vgpu"; + public static final String VGPUTYPE = "vgputype"; + public static final String REMAININGCAPACITY = "remainingcapacity"; public enum HostDetails { all, capacity, events, stats, min; diff --git a/api/src/org/apache/cloudstack/api/command/admin/offering/CreateServiceOfferingCmd.java b/api/src/org/apache/cloudstack/api/command/admin/offering/CreateServiceOfferingCmd.java index 4143c2e44c7..42bd95dd7ce 100644 --- a/api/src/org/apache/cloudstack/api/command/admin/offering/CreateServiceOfferingCmd.java +++ b/api/src/org/apache/cloudstack/api/command/admin/offering/CreateServiceOfferingCmd.java @@ -17,6 +17,8 @@ package org.apache.cloudstack.api.command.admin.offering; import java.util.Collection; +import java.util.HashMap; +import java.util.Iterator; import java.util.Map; import org.apache.log4j.Logger; @@ -206,13 +208,17 @@ public class CreateServiceOfferingCmd extends BaseCmd { } public Map getDetails() { - if (details == null || details.isEmpty()) { - return null; + Map detailsMap = null; + if (details != null && !details.isEmpty()) { + detailsMap = new HashMap(); + Collection props = details.values(); + Iterator iter = props.iterator(); + while (iter.hasNext()) { + HashMap detail = (HashMap) iter.next(); + detailsMap.putAll(detail); + } } - - Collection paramsCollection = details.values(); - Map params = (Map)(paramsCollection.toArray())[0]; - return params; + return detailsMap; } public Long getBytesReadRate() { diff --git a/api/src/org/apache/cloudstack/api/response/GpuResponse.java b/api/src/org/apache/cloudstack/api/response/GpuResponse.java new file mode 100644 index 00000000000..b655749126e --- /dev/null +++ b/api/src/org/apache/cloudstack/api/response/GpuResponse.java @@ -0,0 +1,46 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. +package org.apache.cloudstack.api.response; + +import java.util.List; + +import com.google.gson.annotations.SerializedName; + +import org.apache.cloudstack.api.ApiConstants; +import org.apache.cloudstack.api.BaseResponse; + +import com.cloud.serializer.Param; + +public class GpuResponse extends BaseResponse { + + @SerializedName(ApiConstants.GPUGROUPNAME) + @Param(description = "GPU cards present in the host") + private String gpuGroupName; + + @SerializedName(ApiConstants.VGPU) + @Param(description = "the list of enabled vGPUs", responseObject = VgpuResponse.class) + private List vgpu; + + public void setGpuGroupName(String gpuGroupName) { + this.gpuGroupName = gpuGroupName; + } + + public void setVgpu(List vgpu) { + this.vgpu = vgpu; + } + +} diff --git a/api/src/org/apache/cloudstack/api/response/HostResponse.java b/api/src/org/apache/cloudstack/api/response/HostResponse.java index e2d8eb5c473..1fbc6684e13 100644 --- a/api/src/org/apache/cloudstack/api/response/HostResponse.java +++ b/api/src/org/apache/cloudstack/api/response/HostResponse.java @@ -17,6 +17,7 @@ package org.apache.cloudstack.api.response; import java.util.Date; +import java.util.List; import com.google.gson.annotations.SerializedName; @@ -135,6 +136,10 @@ public class HostResponse extends BaseResponse { @Param(description = "the amount of the host's memory currently used") private Long memoryUsed; + @SerializedName(ApiConstants.GPUGROUP) + @Param(description = "GPU cards present in the host", responseObject = GpuResponse.class) + private List gpuGroup; + @SerializedName("disksizetotal") @Param(description = "the total disk size of the host") private Long diskSizeTotal; @@ -320,6 +325,9 @@ public class HostResponse extends BaseResponse { this.memoryUsed = memoryUsed; } + public void setGpuGroups(List gpuGroup) { + this.gpuGroup = gpuGroup; + } public void setDiskSizeTotal(Long diskSizeTotal) { this.diskSizeTotal = diskSizeTotal; } diff --git a/api/src/org/apache/cloudstack/api/response/UserVmResponse.java b/api/src/org/apache/cloudstack/api/response/UserVmResponse.java index 84d532bbc17..d6ce84f4951 100644 --- a/api/src/org/apache/cloudstack/api/response/UserVmResponse.java +++ b/api/src/org/apache/cloudstack/api/response/UserVmResponse.java @@ -164,6 +164,10 @@ public class UserVmResponse extends BaseResponse implements ControlledEntityResp @Param(description = "the memory allocated for the virtual machine") private Integer memory; + @SerializedName(ApiConstants.VGPU) + @Param(description = "the vgpu type used by the virtual machine") + private String vgpu; + @SerializedName("cpuused") @Param(description = "the amount of the vm's CPU currently used") private String cpuUsed; @@ -420,6 +424,9 @@ public class UserVmResponse extends BaseResponse implements ControlledEntityResp return memory; } + public String getVgpu() { + return vgpu; + } public String getCpuUsed() { return cpuUsed; } @@ -643,6 +650,9 @@ public class UserVmResponse extends BaseResponse implements ControlledEntityResp this.memory = memory; } + public void setVgpu(String vgpu) { + this.vgpu = vgpu; + } public void setCpuUsed(String cpuUsed) { this.cpuUsed = cpuUsed; } diff --git a/api/src/org/apache/cloudstack/api/response/VgpuResponse.java b/api/src/org/apache/cloudstack/api/response/VgpuResponse.java new file mode 100644 index 00000000000..17e194be5b1 --- /dev/null +++ b/api/src/org/apache/cloudstack/api/response/VgpuResponse.java @@ -0,0 +1,52 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. +package org.apache.cloudstack.api.response; + +import com.google.gson.annotations.SerializedName; + +import org.apache.cloudstack.api.ApiConstants; +import org.apache.cloudstack.api.BaseResponse; + +import com.cloud.serializer.Param; + +public class VgpuResponse extends BaseResponse { + + @SerializedName(ApiConstants.VGPUTYPE) + @Param(description = "Model Name of vGPU") + private String name; + + @SerializedName(ApiConstants.REMAININGCAPACITY) + @Param(description = "No. of more VMs can be deployped with this vGPU type") + private Long capacity; + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public Long getCapacity() { + return capacity; + } + + public void setCapacity(Long capacity) { + this.capacity = capacity; + } + +} diff --git a/core/src/com/cloud/agent/api/GetGPUStatsAnswer.java b/core/src/com/cloud/agent/api/GetGPUStatsAnswer.java new file mode 100644 index 00000000000..566eed5ab63 --- /dev/null +++ b/core/src/com/cloud/agent/api/GetGPUStatsAnswer.java @@ -0,0 +1,36 @@ +//Licensed to the Apache Software Foundation (ASF) under one +//or more contributor license agreements. See the NOTICE file +//distributed with this work for additional information +//regarding copyright ownership. The ASF licenses this file +//to you under the Apache License, Version 2.0 (the +//"License"); you may not use this file except in compliance +//with the License. You may obtain a copy of the License at +// +//http://www.apache.org/licenses/LICENSE-2.0 +// +//Unless required by applicable law or agreed to in writing, +//software distributed under the License is distributed on an +//"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +//KIND, either express or implied. See the License for the +//specific language governing permissions and limitations +//under the License. +package com.cloud.agent.api; + +import java.util.HashMap; + +import com.cloud.agent.api.LogLevel.Log4jLevel; + +@LogLevel(Log4jLevel.Trace) +public class GetGPUStatsAnswer extends Answer { + + private HashMap> groupDetails; + + public GetGPUStatsAnswer(GetGPUStatsCommand cmd, HashMap> groupDetails) { + super(cmd); + this.groupDetails = groupDetails; + } + + public HashMap> getGroupDetails() { + return this.groupDetails; + } +} diff --git a/core/src/com/cloud/agent/api/GetGPUStatsCommand.java b/core/src/com/cloud/agent/api/GetGPUStatsCommand.java new file mode 100644 index 00000000000..047f56283e0 --- /dev/null +++ b/core/src/com/cloud/agent/api/GetGPUStatsCommand.java @@ -0,0 +1,47 @@ +//Licensed to the Apache Software Foundation (ASF) under one +//or more contributor license agreements. See the NOTICE file +//distributed with this work for additional information +//regarding copyright ownership. The ASF licenses this file +//to you under the Apache License, Version 2.0 (the +//"License"); you may not use this file except in compliance +//with the License. You may obtain a copy of the License at +// +//http://www.apache.org/licenses/LICENSE-2.0 +// +//Unless required by applicable law or agreed to in writing, +//software distributed under the License is distributed on an +//"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +//KIND, either express or implied. See the License for the +//specific language governing permissions and limitations +//under the License. +package com.cloud.agent.api; + +import com.cloud.agent.api.LogLevel.Log4jLevel; + +@LogLevel(Log4jLevel.Trace) +public class GetGPUStatsCommand extends Command +{ + String hostGuid; + String hostName; + + protected GetGPUStatsCommand() { + } + + public GetGPUStatsCommand(String hostGuid, String hostName) { + this.hostGuid = hostGuid; + this.hostName = hostName; + } + + public String getHostGuid(){ + return this.hostGuid; + } + + public String getHostName(){ + return this.hostName; + } + + @Override + public boolean executeInSequence() { + return false; + } +} diff --git a/core/src/com/cloud/agent/api/StartupRoutingCommand.java b/core/src/com/cloud/agent/api/StartupRoutingCommand.java index 8c0eb8a4ecd..dc371133861 100755 --- a/core/src/com/cloud/agent/api/StartupRoutingCommand.java +++ b/core/src/com/cloud/agent/api/StartupRoutingCommand.java @@ -70,6 +70,7 @@ public class StartupRoutingCommand extends StartupCommand { HypervisorType hypervisorType; Map hostDetails; //stuff like host os, cpu capabilities String hypervisorVersion; + HashMap> groupDetails = new HashMap>(); public StartupRoutingCommand() { super(Host.Type.Routing); @@ -244,4 +245,12 @@ public class StartupRoutingCommand extends StartupCommand { public void setHostVmStateReport(Map hostVmStateReport) { this._hostVmStateReport = hostVmStateReport; } + + public HashMap> getGpuGroupDetails() { + return groupDetails; + } + + public void setGpuGroupDetails(HashMap> groupDetails) { + this.groupDetails = groupDetails; + } } diff --git a/core/src/com/cloud/agent/api/StopCommand.java b/core/src/com/cloud/agent/api/StopCommand.java index 6a29aa69ba9..00d7f5fff6c 100755 --- a/core/src/com/cloud/agent/api/StopCommand.java +++ b/core/src/com/cloud/agent/api/StopCommand.java @@ -16,6 +16,7 @@ // under the License. package com.cloud.agent.api; +import com.cloud.agent.api.to.GPUDeviceTO; import com.cloud.vm.VirtualMachine; public class StopCommand extends RebootCommand { @@ -23,6 +24,7 @@ public class StopCommand extends RebootCommand { private String urlPort = null; private String publicConsoleProxyIpAddress = null; boolean executeInSequence = false; + private GPUDeviceTO gpuDevice; protected StopCommand() { } @@ -62,4 +64,11 @@ public class StopCommand extends RebootCommand { return this.publicConsoleProxyIpAddress; } + public GPUDeviceTO getGpuDevice() { + return this.gpuDevice; + } + + public void setGpuDevice(GPUDeviceTO gpuDevice) { + this.gpuDevice = gpuDevice; + } } diff --git a/engine/components-api/src/com/cloud/resource/ResourceManager.java b/engine/components-api/src/com/cloud/resource/ResourceManager.java index 95fb3853717..5a9bddb1863 100755 --- a/engine/components-api/src/com/cloud/resource/ResourceManager.java +++ b/engine/components-api/src/com/cloud/resource/ResourceManager.java @@ -17,15 +17,18 @@ // under the License. package com.cloud.resource; +import java.util.HashMap; import java.util.List; import java.util.Map; import com.cloud.agent.api.StartupCommand; import com.cloud.agent.api.StartupRoutingCommand; +import com.cloud.agent.api.to.GPUDeviceTO; import com.cloud.dc.DataCenterVO; import com.cloud.dc.HostPodVO; import com.cloud.dc.PodCluster; import com.cloud.exception.AgentUnavailableException; +import com.cloud.gpu.HostGpuGroupsVO; import com.cloud.host.Host; import com.cloud.host.Host.Type; import com.cloud.host.HostStats; @@ -137,4 +140,42 @@ public interface ResourceManager extends ResourceService { * @return */ List listAllUpAndEnabledNonHAHosts(Type type, Long clusterId, Long podId, long dcId); + + /** + * Check if host has GPU devices available + * @param hostId the host to be checked + * @param vgpuType the VGPU type + * @return true when the host has the capacity with given VGPU type + */ + boolean isGPUDeviceAvailable(long hostId, String vgpuType); + + /** + * Get available GPU device + * @param hostId the host to be checked + * @param vgpuType the VGPU type + * @return GPUDeviceTO[] + */ + GPUDeviceTO getGPUDevice(long hostId, String vgpuType); + + /** + * Return listof available GPU devices + * @param hostId, the host to be checked + * @param vgpuType the VGPU type + * @return List of HostGpuGroupsVO. + */ + List listAvailableGPUDevice(long hostId, String vgpuType); + + /** + * Update GPU device details (post VM deployment) + * @param hostId, the dest host Id + * @param groupDetails, capacity of GPU group. + */ + void updateGPUDetails(long hostId, HashMap> groupDetails); + + /** + * Get GPU details for a host + * @param host, the Host object + * @return Details of groupNames and enabled VGPU type with remaining capacity. + */ + HashMap> getGPUStatistics(HostVO host); } diff --git a/engine/orchestration/src/com/cloud/vm/VirtualMachineManagerImpl.java b/engine/orchestration/src/com/cloud/vm/VirtualMachineManagerImpl.java index 8edbb76793c..609aefa4b2a 100755 --- a/engine/orchestration/src/com/cloud/vm/VirtualMachineManagerImpl.java +++ b/engine/orchestration/src/com/cloud/vm/VirtualMachineManagerImpl.java @@ -103,6 +103,7 @@ import com.cloud.agent.api.StopCommand; import com.cloud.agent.api.UnPlugNicAnswer; import com.cloud.agent.api.UnPlugNicCommand; import com.cloud.agent.api.to.DiskTO; +import com.cloud.agent.api.to.GPUDeviceTO; import com.cloud.agent.api.to.NicTO; import com.cloud.agent.api.to.VirtualMachineTO; import com.cloud.agent.manager.Commands; @@ -139,6 +140,7 @@ import com.cloud.exception.InvalidParameterValueException; import com.cloud.exception.OperationTimedoutException; import com.cloud.exception.ResourceUnavailableException; import com.cloud.exception.StorageUnavailableException; +import com.cloud.gpu.dao.VGPUTypesDao; import com.cloud.ha.HighAvailabilityManager; import com.cloud.ha.HighAvailabilityManager.WorkType; import com.cloud.host.Host; @@ -276,6 +278,8 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac @Inject protected AffinityGroupVMMapDao _affinityGroupVMMapDao; @Inject + protected VGPUTypesDao _vgpuTypesDao; + @Inject protected EntityManager _entityMgr; @Inject @@ -1026,6 +1030,12 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac throw new ConcurrentOperationException("Unable to transition to a new state."); } + // Update GPU device capacity + GPUDeviceTO gpuDevice = startAnswer.getVirtualMachine().getGpuDevice(); + if (gpuDevice != null) { + _resourceMgr.updateGPUDetails(destHostId, gpuDevice.getGroupDetails()); + } + startedVm = vm; if (s_logger.isDebugEnabled()) { s_logger.debug("Start completed for VM " + vm); @@ -1221,6 +1231,10 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac } } + GPUDeviceTO gpuDevice = stop.getGpuDevice(); + if (gpuDevice != null) { + _resourceMgr.updateGPUDetails(vm.getHostId(), gpuDevice.getGroupDetails()); + } if (!answer.getResult()) { s_logger.debug("Unable to stop VM due to " + answer.getDetails()); return false; @@ -1483,6 +1497,10 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac throw new CloudRuntimeException("Unable to stop the virtual machine due to " + answer.getDetails()); } vmGuru.finalizeStop(profile, answer); + GPUDeviceTO gpuDevice = stop.getGpuDevice(); + if (gpuDevice != null) { + _resourceMgr.updateGPUDetails(vm.getHostId(), gpuDevice.getGroupDetails()); + } } else { throw new CloudRuntimeException("Invalid answer received in response to a StopCommand on " + vm.instanceName); } diff --git a/engine/schema/resources/META-INF/cloudstack/core/spring-engine-schema-core-daos-context.xml b/engine/schema/resources/META-INF/cloudstack/core/spring-engine-schema-core-daos-context.xml index 08efb8345f5..765d86c34ad 100644 --- a/engine/schema/resources/META-INF/cloudstack/core/spring-engine-schema-core-daos-context.xml +++ b/engine/schema/resources/META-INF/cloudstack/core/spring-engine-schema-core-daos-context.xml @@ -316,6 +316,8 @@ + + diff --git a/engine/schema/src/com/cloud/gpu/HostGpuGroupsVO.java b/engine/schema/src/com/cloud/gpu/HostGpuGroupsVO.java new file mode 100644 index 00000000000..1c186a162e3 --- /dev/null +++ b/engine/schema/src/com/cloud/gpu/HostGpuGroupsVO.java @@ -0,0 +1,70 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. +package com.cloud.gpu; + +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.GenerationType; +import javax.persistence.Id; +import javax.persistence.Table; + +import org.apache.cloudstack.api.InternalIdentity; + +@Entity +@Table(name="host_gpu_groups") +public class HostGpuGroupsVO implements InternalIdentity { + @Id + @GeneratedValue(strategy=GenerationType.IDENTITY) + @Column(name="id") + private long id; + + @Column(name="group_name") + private String groupName; + + @Column(name="host_id") + private long hostId; + + protected HostGpuGroupsVO() { + } + + public HostGpuGroupsVO(long hostId, String groupName) { + this.hostId = hostId; + this.groupName = groupName; + } + + public long getHostId() { + return hostId; + } + + public void setHostId(long hostId) { + this.hostId = hostId; + } + + public String getGroupName() { + return groupName; + } + + public void setGroupName(String groupName) { + this.groupName = groupName; + } + + @Override + public long getId() { + return id; + } +} diff --git a/engine/schema/src/com/cloud/gpu/VGPUTypesVO.java b/engine/schema/src/com/cloud/gpu/VGPUTypesVO.java new file mode 100644 index 00000000000..586a0c92798 --- /dev/null +++ b/engine/schema/src/com/cloud/gpu/VGPUTypesVO.java @@ -0,0 +1,82 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. +package com.cloud.gpu; + +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.GenerationType; +import javax.persistence.Id; +import javax.persistence.Table; + +import org.apache.cloudstack.api.InternalIdentity; + +@Entity +@Table(name="vgpu_types") +public class VGPUTypesVO implements InternalIdentity { + @Id + @GeneratedValue(strategy=GenerationType.IDENTITY) + @Column(name="id") + private long id; + + @Column(name="vgpu_type") + private String vgpuType; + + @Column(name="gpu_group_id") + private long gpuGroupId; + + @Column(name="remaining_vm_capacity") + private long remainingCapacity; + + protected VGPUTypesVO() { + } + + public VGPUTypesVO(String vgpuType, long gpuGroupId, long remainingCapacity) { + this.vgpuType = vgpuType; + this.gpuGroupId = gpuGroupId; + this.remainingCapacity = remainingCapacity; + } + + public String getVgpuType() { + return vgpuType; + } + + public void setVgpuType(String vgpuType) { + this.vgpuType = vgpuType; + } + + public long getGpuGroupId() { + return gpuGroupId; + } + + public void setGpuGroupId(long gpuGroupId) { + this.gpuGroupId = gpuGroupId; + } + + public long getRemainingCapacity() { + return remainingCapacity; + } + + public void setRemainingCapacity(long remainingCapacity) { + this.remainingCapacity = remainingCapacity; + } + + @Override + public long getId() { + return id; + } +} diff --git a/engine/schema/src/com/cloud/gpu/dao/HostGpuGroupsDao.java b/engine/schema/src/com/cloud/gpu/dao/HostGpuGroupsDao.java new file mode 100644 index 00000000000..58641443972 --- /dev/null +++ b/engine/schema/src/com/cloud/gpu/dao/HostGpuGroupsDao.java @@ -0,0 +1,60 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. +package com.cloud.gpu.dao; + +import java.util.List; + +import com.cloud.gpu.HostGpuGroupsVO; +import com.cloud.utils.db.GenericDao; + +public interface HostGpuGroupsDao extends GenericDao { + + /** + * Find host device by hostId and PCI ID + * @param hostId the host + * @param groupName GPU group + * @return HostGpuGroupsVO + */ + HostGpuGroupsVO findByHostIdGroupName(long hostId, String groupName); + + /** + * List all the host Ids, that are GPU enabled. + * @return list of hostIds + */ + List listHostIds(); + + /** + * Return a list by hostId. + * @param hostId the host + * @return HostGpuGroupsVO + */ + List listByHostId(long hostId); + + /** + * Delete entries by hostId. + * @param hostId the host + */ + void deleteGpuEntries(long hostId); + + /** + * Save the list of GPU groups belonging to a host + * @param hostId the host + * @param gpuGroups the list of GPU groups to save + */ + void persist(long hostId, List gpuGroups); + +} diff --git a/engine/schema/src/com/cloud/gpu/dao/HostGpuGroupsDaoImpl.java b/engine/schema/src/com/cloud/gpu/dao/HostGpuGroupsDaoImpl.java new file mode 100644 index 00000000000..6bddea262ed --- /dev/null +++ b/engine/schema/src/com/cloud/gpu/dao/HostGpuGroupsDaoImpl.java @@ -0,0 +1,94 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. +package com.cloud.gpu.dao; + +import java.util.List; + +import javax.ejb.Local; + +import org.apache.log4j.Logger; +import org.springframework.stereotype.Component; + +import com.cloud.gpu.HostGpuGroupsVO; +import com.cloud.utils.db.GenericDaoBase; +import com.cloud.utils.db.GenericSearchBuilder; +import com.cloud.utils.db.SearchBuilder; +import com.cloud.utils.db.SearchCriteria; + +@Component +@Local(value = HostGpuGroupsDao.class) +public class HostGpuGroupsDaoImpl extends GenericDaoBase implements HostGpuGroupsDao { + private static final Logger s_logger = Logger.getLogger(HostGpuGroupsDaoImpl.class); + + private final SearchBuilder _hostIdGroupNameSearch; + private final SearchBuilder _searchByHostId; + private final GenericSearchBuilder _searchHostIds; + + public HostGpuGroupsDaoImpl() { + + _hostIdGroupNameSearch = createSearchBuilder(); + _hostIdGroupNameSearch.and("hostId", _hostIdGroupNameSearch.entity().getHostId(), SearchCriteria.Op.EQ); + _hostIdGroupNameSearch.and("groupName", _hostIdGroupNameSearch.entity().getGroupName(), SearchCriteria.Op.EQ); + _hostIdGroupNameSearch.done(); + + _searchByHostId = createSearchBuilder(); + _searchByHostId.and("hostId", _searchByHostId.entity().getHostId(), SearchCriteria.Op.EQ); + _searchByHostId.done(); + + _searchHostIds = createSearchBuilder(Long.class); + _searchHostIds.selectFields(_searchHostIds.entity().getHostId()); + _searchHostIds.done(); + } + + @Override + public HostGpuGroupsVO findByHostIdGroupName(long hostId, String groupName) { + SearchCriteria sc = _hostIdGroupNameSearch.create(); + sc.setParameters("hostId", hostId); + sc.setParameters("groupName", groupName); + return findOneBy(sc); + } + + @Override + public List listHostIds() { + SearchCriteria sc = _searchHostIds.create(); + return customSearch(sc, null); + } + + @Override + public List listByHostId(long hostId) { + SearchCriteria sc = _searchByHostId.create(); + sc.setParameters("hostId", hostId); + return listBy(sc); + } + + @Override + public void persist(long hostId, List gpuGroups) { + for (String groupName : gpuGroups) { + if (findByHostIdGroupName(hostId, groupName) == null) { + HostGpuGroupsVO record = new HostGpuGroupsVO(hostId, groupName); + persist(record); + } + } + } + + @Override + public void deleteGpuEntries(long hostId) { + SearchCriteria sc = _searchByHostId.create(); + sc.setParameters("hostId", hostId); + remove(sc); + } +} diff --git a/engine/schema/src/com/cloud/gpu/dao/VGPUTypesDao.java b/engine/schema/src/com/cloud/gpu/dao/VGPUTypesDao.java new file mode 100644 index 00000000000..2872cfda886 --- /dev/null +++ b/engine/schema/src/com/cloud/gpu/dao/VGPUTypesDao.java @@ -0,0 +1,48 @@ +//Licensed to the Apache Software Foundation (ASF) under one +//or more contributor license agreements. See the NOTICE file +//distributed with this work for additional information +//regarding copyright ownership. The ASF licenses this file +//to you under the Apache License, Version 2.0 (the +//"License"); you may not use this file except in compliance +//with the License. You may obtain a copy of the License at +// +//http://www.apache.org/licenses/LICENSE-2.0 +// +//Unless required by applicable law or agreed to in writing, +//software distributed under the License is distributed on an +//"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +//KIND, either express or implied. See the License for the +//specific language governing permissions and limitations +//under the License. +package com.cloud.gpu.dao; + +import java.util.HashMap; +import java.util.List; + +import com.cloud.gpu.VGPUTypesVO; +import com.cloud.utils.db.GenericDao; + +public interface VGPUTypesDao extends GenericDao { + + /** + * Find VGPU types by group Id + * @param groupId of the GPU group + * @return list of VGPUTypesVO + */ + List listByGroupId(long groupId); + + /** + * Find VGPU type by group Id and VGPU type + * @param groupId of the GPU group + * @param vgpuType name of VGPU type + * @return VGPUTypesVO + */ + VGPUTypesVO findByGroupIdVGPUType(long groupId, String vgpuType); + + /** + * Save the list of enabled VGPU types + * @param hostId the host + * @param groupDetails with enabled VGPU types + */ + void persist(long hostId, HashMap> groupDetails); +} diff --git a/engine/schema/src/com/cloud/gpu/dao/VGPUTypesDaoImpl.java b/engine/schema/src/com/cloud/gpu/dao/VGPUTypesDaoImpl.java new file mode 100644 index 00000000000..7cc83cc9eb8 --- /dev/null +++ b/engine/schema/src/com/cloud/gpu/dao/VGPUTypesDaoImpl.java @@ -0,0 +1,95 @@ +//Licensed to the Apache Software Foundation (ASF) under one +//or more contributor license agreements. See the NOTICE file +//distributed with this work for additional information +//regarding copyright ownership. The ASF licenses this file +//to you under the Apache License, Version 2.0 (the +//"License"); you may not use this file except in compliance +//with the License. You may obtain a copy of the License at +// +//http://www.apache.org/licenses/LICENSE-2.0 +// +//Unless required by applicable law or agreed to in writing, +//software distributed under the License is distributed on an +//"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +//KIND, either express or implied. See the License for the +//specific language governing permissions and limitations +//under the License. +package com.cloud.gpu.dao; + +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map.Entry; + +import javax.ejb.Local; +import javax.inject.Inject; + +import org.apache.log4j.Logger; +import org.springframework.stereotype.Component; + +import com.cloud.gpu.HostGpuGroupsVO; +import com.cloud.gpu.VGPUTypesVO; +import com.cloud.utils.db.GenericDaoBase; +import com.cloud.utils.db.SearchBuilder; +import com.cloud.utils.db.SearchCriteria; + +@Component +@Local(value = VGPUTypesDao.class) +public class VGPUTypesDaoImpl extends GenericDaoBase implements VGPUTypesDao { + private static final Logger s_logger = Logger.getLogger(VGPUTypesDaoImpl.class); + + private final SearchBuilder _searchByGroupId; + private final SearchBuilder _searchByGroupIdVGPUType; + // private final SearchBuilder _searchByHostId; + // private final SearchBuilder _searchForStaleEntries; + + @Inject protected HostGpuGroupsDao _hostGpuGroupsDao; + + public VGPUTypesDaoImpl() { + + _searchByGroupId = createSearchBuilder(); + _searchByGroupId.and("groupId", _searchByGroupId.entity().getGpuGroupId(), SearchCriteria.Op.EQ); + _searchByGroupId.done(); + + _searchByGroupIdVGPUType = createSearchBuilder(); + _searchByGroupIdVGPUType.and("groupId", _searchByGroupIdVGPUType.entity().getGpuGroupId(), SearchCriteria.Op.EQ); + _searchByGroupIdVGPUType.and("vgpuType", _searchByGroupIdVGPUType.entity().getVgpuType(), SearchCriteria.Op.EQ); + _searchByGroupIdVGPUType.done(); + } + + @Override + public List listByGroupId(long groupId) { + SearchCriteria sc = _searchByGroupId.create(); + sc.setParameters("groupId", groupId); + return listBy(sc); + } + + @Override + public VGPUTypesVO findByGroupIdVGPUType(long groupId, String vgpuType) { + SearchCriteria sc = _searchByGroupIdVGPUType.create(); + sc.setParameters("groupId", groupId); + sc.setParameters("vgpuType", vgpuType); + return findOneBy(sc); + } + + @Override + public void persist(long hostId, HashMap> groupDetails) { + Iterator>> it1 = groupDetails.entrySet().iterator(); + while (it1.hasNext()) { + Entry> entry = it1.next(); + HostGpuGroupsVO gpuGroup = _hostGpuGroupsDao.findByHostIdGroupName(hostId, entry.getKey()); + HashMap values = entry.getValue(); + Iterator> it2 = values.entrySet().iterator(); + while (it2.hasNext()) { + Entry record = it2.next(); + VGPUTypesVO vgpuType = null; + if ((vgpuType = findByGroupIdVGPUType(gpuGroup.getId(), record.getKey())) == null) { + persist(new VGPUTypesVO(record.getKey(), gpuGroup.getId(), record.getValue())); + } else { + vgpuType.setRemainingCapacity(record.getValue()); + update(vgpuType.getId(), vgpuType); + } + } + } + } +} diff --git a/engine/schema/src/com/cloud/host/HostVO.java b/engine/schema/src/com/cloud/host/HostVO.java index 56c066b1b72..25cc9544da2 100755 --- a/engine/schema/src/com/cloud/host/HostVO.java +++ b/engine/schema/src/com/cloud/host/HostVO.java @@ -17,6 +17,7 @@ package com.cloud.host; import java.util.Date; +import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.UUID; @@ -153,6 +154,10 @@ public class HostVO implements Host { @Transient List hostTags; + // This value is only for saving and current cannot be loaded. + @Transient + HashMap> groupDetails = new HashMap>(); + @Override public String getStorageIpAddressDeux() { return storageIpAddressDeux; @@ -313,6 +318,14 @@ public class HostVO implements Host { this.hostTags = hostTags; } + public HashMap> getGpuGroupDetails() { + return groupDetails; + } + + public void setGpuGroups(HashMap> groupDetails) { + this.groupDetails = groupDetails; + } + @Column(name = "data_center_id", nullable = false) private long dataCenterId; diff --git a/engine/schema/src/com/cloud/host/dao/HostDaoImpl.java b/engine/schema/src/com/cloud/host/dao/HostDaoImpl.java index 08a436644ba..c2a9826405d 100755 --- a/engine/schema/src/com/cloud/host/dao/HostDaoImpl.java +++ b/engine/schema/src/com/cloud/host/dao/HostDaoImpl.java @@ -38,6 +38,8 @@ import com.cloud.cluster.agentlb.HostTransferMapVO; import com.cloud.cluster.agentlb.dao.HostTransferMapDao; import com.cloud.dc.ClusterVO; import com.cloud.dc.dao.ClusterDao; +import com.cloud.gpu.dao.HostGpuGroupsDao; +import com.cloud.gpu.dao.VGPUTypesDao; import com.cloud.host.Host; import com.cloud.host.Host.Type; import com.cloud.host.HostTagVO; @@ -126,6 +128,10 @@ public class HostDaoImpl extends GenericDaoBase implements HostDao @Inject protected HostDetailsDao _detailsDao; @Inject + protected HostGpuGroupsDao _hostGpuGroupsDao; + @Inject + protected VGPUTypesDao _vgpuTypesDao; + @Inject protected HostTagsDao _hostTagsDao; @Inject protected HostTransferMapDao _hostTransferDao; @@ -775,6 +781,16 @@ public class HostDaoImpl extends GenericDaoBase implements HostDao _hostTagsDao.persist(host.getId(), hostTags); } + protected void saveGpuRecords(HostVO host) { + HashMap> groupDetails = host.getGpuGroupDetails(); + if (groupDetails != null) { + // Create/Update GPU group entries + _hostGpuGroupsDao.persist(host.getId(), new ArrayList(groupDetails.keySet())); + // Create/Update VGPU types entries + _vgpuTypesDao.persist(host.getId(), groupDetails); + } + } + @Override @DB public HostVO persist(HostVO host) { @@ -797,6 +813,7 @@ public class HostDaoImpl extends GenericDaoBase implements HostDao loadDetails(dbHost); saveHostTags(host); loadHostTags(dbHost); + saveGpuRecords(host); txn.commit(); @@ -816,6 +833,7 @@ public class HostDaoImpl extends GenericDaoBase implements HostDao saveDetails(host); saveHostTags(host); + saveGpuRecords(host); txn.commit(); diff --git a/engine/schema/src/com/cloud/service/ServiceOfferingDetailsVO.java b/engine/schema/src/com/cloud/service/ServiceOfferingDetailsVO.java index ed8090b3bc7..8dfe5273b94 100644 --- a/engine/schema/src/com/cloud/service/ServiceOfferingDetailsVO.java +++ b/engine/schema/src/com/cloud/service/ServiceOfferingDetailsVO.java @@ -60,6 +60,10 @@ public class ServiceOfferingDetailsVO implements ResourceDetail { return resourceId; } + public void setResourceId(long serviceOfferingId) { + this.resourceId = serviceOfferingId; + } + @Override public String getName() { return name; diff --git a/plugins/hypervisors/xen/src/com/cloud/hypervisor/xen/resource/CitrixResourceBase.java b/plugins/hypervisors/xen/src/com/cloud/hypervisor/xen/resource/CitrixResourceBase.java index b1ad63a044c..d80bddc3773 100644 --- a/plugins/hypervisors/xen/src/com/cloud/hypervisor/xen/resource/CitrixResourceBase.java +++ b/plugins/hypervisors/xen/src/com/cloud/hypervisor/xen/resource/CitrixResourceBase.java @@ -56,11 +56,13 @@ import com.trilead.ssh2.SCPClient; import com.xensource.xenapi.Bond; import com.xensource.xenapi.Connection; import com.xensource.xenapi.Console; +import com.xensource.xenapi.GPUGroup; import com.xensource.xenapi.Host; import com.xensource.xenapi.HostCpu; import com.xensource.xenapi.HostMetrics; import com.xensource.xenapi.Network; import com.xensource.xenapi.PBD; +import com.xensource.xenapi.PGPU; import com.xensource.xenapi.PIF; import com.xensource.xenapi.Pool; import com.xensource.xenapi.SR; @@ -73,6 +75,8 @@ import com.xensource.xenapi.Types.XenAPIException; import com.xensource.xenapi.VBD; import com.xensource.xenapi.VBDMetrics; import com.xensource.xenapi.VDI; +import com.xensource.xenapi.VGPU; +import com.xensource.xenapi.VGPUType; import com.xensource.xenapi.VIF; import com.xensource.xenapi.VLAN; import com.xensource.xenapi.VM; @@ -108,6 +112,8 @@ import com.cloud.agent.api.CreateVMSnapshotCommand; import com.cloud.agent.api.DeleteStoragePoolCommand; import com.cloud.agent.api.DeleteVMSnapshotAnswer; import com.cloud.agent.api.DeleteVMSnapshotCommand; +import com.cloud.agent.api.GetGPUStatsAnswer; +import com.cloud.agent.api.GetGPUStatsCommand; import com.cloud.agent.api.GetHostStatsAnswer; import com.cloud.agent.api.GetHostStatsCommand; import com.cloud.agent.api.GetStorageStatsAnswer; @@ -201,6 +207,7 @@ import com.cloud.agent.api.storage.ResizeVolumeCommand; import com.cloud.agent.api.to.DataStoreTO; import com.cloud.agent.api.to.DataTO; import com.cloud.agent.api.to.DiskTO; +import com.cloud.agent.api.to.GPUDeviceTO; import com.cloud.agent.api.to.IpAddressTO; import com.cloud.agent.api.to.NfsTO; import com.cloud.agent.api.to.NicTO; @@ -433,6 +440,8 @@ public abstract class CitrixResourceBase implements ServerResource, HypervisorRe return execute((GetHostStatsCommand)cmd); } else if (clazz == GetVmStatsCommand.class) { return execute((GetVmStatsCommand)cmd); + } else if (clazz == GetGPUStatsCommand.class) { + return execute((GetGPUStatsCommand) cmd); } else if (clazz == GetVmDiskStatsCommand.class) { return execute((GetVmDiskStatsCommand)cmd); } else if (clazz == CheckHealthCommand.class) { @@ -1288,6 +1297,65 @@ public abstract class CitrixResourceBase implements ServerResource, HypervisorRe return dynamicMinRam; } + private HashMap> getGPUGroupDetails(Connection conn) throws XenAPIException, XmlRpcException { + HashMap> groupDetails = new HashMap>(); + Host host = Host.getByUuid(conn, _host.uuid); + Set pgpus = host.getPGPUs(conn); + Iterator iter = pgpus.iterator(); + while (iter.hasNext()) { + PGPU pgpu = iter.next(); + GPUGroup gpuGroup = pgpu.getGPUGroup(conn); + Set enabledVGPUTypes = gpuGroup.getEnabledVGPUTypes(conn); + String groupName = gpuGroup.getNameLabel(conn); + HashMap gpuCapacity = new HashMap(); + if (groupDetails.get(groupName) != null) { + gpuCapacity = groupDetails.get(groupName); + } + // Get remaining capacity of all the enabled VGPU in a PGPU + if(enabledVGPUTypes != null) { + Iterator it = enabledVGPUTypes.iterator(); + while (it.hasNext()) { + VGPUType type = it.next(); + String modelName = type.getModelName(conn); + Long remainingCapacity = pgpu.getRemainingCapacity(conn, type); + if (gpuCapacity.get(modelName) != null) { + long newRemainingCapacity = gpuCapacity.get(modelName) + remainingCapacity; + gpuCapacity.put(modelName, newRemainingCapacity); + } else { + gpuCapacity.put(modelName, remainingCapacity); + } + } + } + groupDetails.put(groupName, gpuCapacity); + } + return groupDetails; + } + + protected void createVGPU(Connection conn, StartCommand cmd, VM vm, GPUDeviceTO gpuDevice) throws XenAPIException, XmlRpcException { + Set groups = GPUGroup.getByNameLabel(conn, gpuDevice.getGpuGroup()); + assert groups.size() == 1 : "Should only have 1 group but found " + groups.size(); + GPUGroup gpuGroup = groups.iterator().next(); + + Set vgpuTypes = gpuGroup.getEnabledVGPUTypes(conn); + Iterator iter = vgpuTypes.iterator(); + VGPUType vgpuType = null; + while (iter.hasNext()) { + VGPUType entry = iter.next(); + if (entry.getModelName(conn).equals(gpuDevice.getVgpuType())) { + vgpuType = entry; + } + } + String device = "0"; // Only allow device = "0" for now, as XenServer supports just a single vGPU per VM. + Map other_config = new HashMap(); + VGPU.create(conn, vm, gpuGroup, device, other_config, vgpuType); + + if (s_logger.isDebugEnabled()) { + s_logger.debug("Created VGPU of VGPU type [ " + gpuDevice.getVgpuType() + " ] for VM " + cmd.getVirtualMachine().getName()); + } + // Calculate and set remaining GPU capacity in the host. + cmd.getVirtualMachine().getGpuDevice().setGroupDetails(getGPUGroupDetails(conn)); + } + protected VM createVmFromTemplate(Connection conn, VirtualMachineTO vmSpec, Host host) throws XenAPIException, XmlRpcException { String guestOsTypeName = getGuestOsType(vmSpec.getOs(), vmSpec.getBootloader() == BootloaderType.CD); Set templates = VM.getByNameLabel(conn, guestOsTypeName); @@ -1721,6 +1789,13 @@ public abstract class CitrixResourceBase implements ServerResource, HypervisorRe Host host = Host.getByUuid(conn, _host.uuid); vm = createVmFromTemplate(conn, vmSpec, host); + GPUDeviceTO gpuDevice = vmSpec.getGpuDevice(); + if (gpuDevice != null) { + s_logger.debug("Creating VGPU for of VGPU type: " + gpuDevice.getVgpuType() + " in GPU group " + + gpuDevice.getGpuGroup() + " for VM " + vmName ); + createVGPU(conn, cmd, vm, gpuDevice); + } + for (DiskTO disk : vmSpec.getDisks()) { VDI newVdi = prepareManagedDisk(conn, disk, vmName); @@ -2245,6 +2320,18 @@ public abstract class CitrixResourceBase implements ServerResource, HypervisorRe return hostStats; } + protected GetGPUStatsAnswer execute(GetGPUStatsCommand cmd) { + Connection conn = getConnection(); + HashMap> groupDetails = new HashMap>(); + try { + groupDetails = getGPUGroupDetails(conn); + } catch (Exception e) { + String msg = "Unable to get GPU stats" + e.toString(); + s_logger.warn(msg, e); + } + return new GetGPUStatsAnswer(cmd, groupDetails); + } + protected GetVmStatsAnswer execute(GetVmStatsCommand cmd) { Connection conn = getConnection(); List vmNames = cmd.getVmNames(); @@ -3566,6 +3653,18 @@ public abstract class CitrixResourceBase implements ServerResource, HypervisorRe try { if (vm.getPowerState(conn) == VmPowerState.HALTED) { + Set vGPUs = null; + // Get updated GPU details + try { + vGPUs = vm.getVGPUs(conn); + } catch (XenAPIException e2) { + s_logger.debug("VM " + vmName + " does not have GPU support."); + } + if (vGPUs != null && !vGPUs.isEmpty()) { + HashMap> groupDetails = getGPUGroupDetails(conn); + cmd.setGpuDevice(new GPUDeviceTO(null, null, groupDetails)); + } + Set vifs = vm.getVIFs(conn); List networks = new ArrayList(); for (VIF vif : vifs) { @@ -5400,6 +5499,15 @@ public abstract class CitrixResourceBase implements ServerResource, HypervisorRe details.put("private.network.device", _privateNetworkName); } + try { + HashMap> groupDetails = getGPUGroupDetails(conn); + cmd.setGpuGroupDetails(groupDetails); + } catch (Exception e) { + if (s_logger.isDebugEnabled()) { + s_logger.debug("GPU device not found in host " + hr.hostname); + } + } + cmd.setHostDetails(details); cmd.setName(hr.nameLabel); cmd.setGuid(_host.uuid); diff --git a/server/src/com/cloud/agent/manager/allocator/impl/FirstFitAllocator.java b/server/src/com/cloud/agent/manager/allocator/impl/FirstFitAllocator.java index b77f8acce4d..8abb5cd316f 100755 --- a/server/src/com/cloud/agent/manager/allocator/impl/FirstFitAllocator.java +++ b/server/src/com/cloud/agent/manager/allocator/impl/FirstFitAllocator.java @@ -26,11 +26,10 @@ import javax.ejb.Local; import javax.inject.Inject; import javax.naming.ConfigurationException; +import org.apache.cloudstack.framework.config.dao.ConfigurationDao; import org.apache.log4j.Logger; import org.springframework.stereotype.Component; -import org.apache.cloudstack.framework.config.dao.ConfigurationDao; - import com.cloud.agent.manager.allocator.HostAllocator; import com.cloud.capacity.CapacityManager; import com.cloud.dc.ClusterDetailsDao; @@ -38,6 +37,7 @@ import com.cloud.dc.ClusterDetailsVO; import com.cloud.dc.dao.ClusterDao; import com.cloud.deploy.DeploymentPlan; import com.cloud.deploy.DeploymentPlanner.ExcludeList; +import com.cloud.gpu.GPU; import com.cloud.host.DetailVO; import com.cloud.host.Host; import com.cloud.host.Host.Type; @@ -47,7 +47,9 @@ import com.cloud.host.dao.HostDetailsDao; import com.cloud.offering.ServiceOffering; import com.cloud.org.Cluster; import com.cloud.resource.ResourceManager; +import com.cloud.service.ServiceOfferingDetailsVO; import com.cloud.service.dao.ServiceOfferingDao; +import com.cloud.service.dao.ServiceOfferingDetailsDao; import com.cloud.storage.GuestOSCategoryVO; import com.cloud.storage.GuestOSVO; import com.cloud.storage.VMTemplateVO; @@ -99,6 +101,8 @@ public class FirstFitAllocator extends AdapterBase implements HostAllocator { ClusterDao _clusterDao; @Inject ClusterDetailsDao _clusterDetailsDao; + @Inject + ServiceOfferingDetailsDao _serviceOfferingDetailsDao; float _factor = 1; boolean _checkHvm = true; protected String _allocationAlgorithm = "random"; @@ -264,7 +268,9 @@ public class FirstFitAllocator extends AdapterBase implements HostAllocator { s_logger.debug("Looking for speed=" + (offering.getCpu() * offering.getSpeed()) + "Mhz, Ram=" + offering.getRamSize()); } + long serviceOfferingId = offering.getId(); List suitableHosts = new ArrayList(); + ServiceOfferingDetailsVO offeringDetails = null; for (Host host : hosts) { if (suitableHosts.size() == returnUpTo) { @@ -286,6 +292,13 @@ public class FirstFitAllocator extends AdapterBase implements HostAllocator { continue; } + // Check if GPU device is required by offering and host has the availability + if ((offeringDetails = _serviceOfferingDetailsDao.findDetail(serviceOfferingId, GPU.Keys.vgpuType.toString())) != null + && !_resourceMgr.isGPUDeviceAvailable(host.getId(), offeringDetails.getValue())){ + s_logger.info("Host name: " + host.getName() + ", hostId: "+ host.getId() +" does not have required GPU devices available"); + continue; + } + int cpu_requested = offering.getCpu() * offering.getSpeed(); long ram_requested = offering.getRamSize() * 1024L * 1024L; Cluster cluster = _clusterDao.findById(host.getClusterId()); diff --git a/server/src/com/cloud/api/ApiDBUtils.java b/server/src/com/cloud/api/ApiDBUtils.java index a23244b86f0..539eb704005 100755 --- a/server/src/com/cloud/api/ApiDBUtils.java +++ b/server/src/com/cloud/api/ApiDBUtils.java @@ -130,6 +130,10 @@ import com.cloud.domain.dao.DomainDao; import com.cloud.event.Event; import com.cloud.event.dao.EventJoinDao; import com.cloud.exception.InvalidParameterValueException; +import com.cloud.gpu.HostGpuGroupsVO; +import com.cloud.gpu.VGPUTypesVO; +import com.cloud.gpu.dao.HostGpuGroupsDao; +import com.cloud.gpu.dao.VGPUTypesDao; import com.cloud.ha.HighAvailabilityManager; import com.cloud.host.Host; import com.cloud.host.HostStats; @@ -221,8 +225,10 @@ import com.cloud.server.ResourceTag; import com.cloud.server.ResourceTag.ResourceObjectType; import com.cloud.server.StatsCollector; import com.cloud.server.TaggedResourceService; +import com.cloud.service.ServiceOfferingDetailsVO; import com.cloud.service.ServiceOfferingVO; import com.cloud.service.dao.ServiceOfferingDao; +import com.cloud.service.dao.ServiceOfferingDetailsDao; import com.cloud.storage.DiskOfferingVO; import com.cloud.storage.GuestOS; import com.cloud.storage.GuestOSCategoryVO; @@ -325,6 +331,7 @@ public class ApiDBUtils { static NetworkRuleConfigDao s_networkRuleConfigDao; static HostPodDao s_podDao; static ServiceOfferingDao s_serviceOfferingDao; + static ServiceOfferingDetailsDao s_serviceOfferingDetailsDao; static SnapshotDao s_snapshotDao; static PrimaryDataStoreDao s_storagePoolDao; static VMTemplateDao s_templateDao; @@ -400,6 +407,8 @@ public class ApiDBUtils { static NetworkACLDao s_networkACLDao; static AccountService s_accountService; static ResourceMetaDataService s_resourceDetailsService; + static HostGpuGroupsDao s_hostGpuGroupsDao; + static VGPUTypesDao s_vgpuTypesDao; @Inject private ManagementServer ms; @@ -467,6 +476,8 @@ public class ApiDBUtils { @Inject private ServiceOfferingDao serviceOfferingDao; @Inject + private ServiceOfferingDetailsDao serviceOfferingDetailsDao; + @Inject private SnapshotDao snapshotDao; @Inject private PrimaryDataStoreDao storagePoolDao; @@ -616,6 +627,10 @@ public class ApiDBUtils { private ConfigurationManager configMgr; @Inject private ResourceMetaDataService resourceDetailsService; + @Inject + private HostGpuGroupsDao hostGpuGroupsDao; + @Inject + private VGPUTypesDao vgpuTypesDao; @PostConstruct void init() { @@ -649,6 +664,7 @@ public class ApiDBUtils { s_networkRuleConfigDao = networkRuleConfigDao; s_podDao = podDao; s_serviceOfferingDao = serviceOfferingDao; + s_serviceOfferingDetailsDao = serviceOfferingDetailsDao; s_serviceOfferingJoinDao = serviceOfferingJoinDao; s_snapshotDao = snapshotDao; s_storagePoolDao = storagePoolDao; @@ -727,6 +743,8 @@ public class ApiDBUtils { s_networkACLDao = networkACLDao; s_accountService = accountService; s_resourceDetailsService = resourceDetailsService; + s_hostGpuGroupsDao = hostGpuGroupsDao; + s_vgpuTypesDao = vgpuTypesDao; } @@ -960,6 +978,10 @@ public class ApiDBUtils { return s_serviceOfferingDao.findByIdIncludingRemoved(serviceOfferingId); } + public static ServiceOfferingDetailsVO findServiceOfferingDetail(long serviceOfferingId, String key) { + return s_serviceOfferingDetailsDao.findDetail(serviceOfferingId, key); + } + public static Snapshot findSnapshotById(long snapshotId) { SnapshotVO snapshot = s_snapshotDao.findById(snapshotId); if (snapshot != null && snapshot.getRemoved() == null && snapshot.getState() == Snapshot.State.BackedUp) { @@ -1057,6 +1079,14 @@ public class ApiDBUtils { return type; } + public static List getGpuGroups(long hostId) { + return s_hostGpuGroupsDao.listByHostId(hostId); + } + + public static List getVgpus(long groupId) { + return s_vgpuTypesDao.listByGroupId(groupId); + } + public static List listUserStatsBy(Long accountId) { return s_userStatsDao.listBy(accountId); } diff --git a/server/src/com/cloud/api/query/dao/HostJoinDaoImpl.java b/server/src/com/cloud/api/query/dao/HostJoinDaoImpl.java index 1b95d9b24cc..6c890fc830c 100644 --- a/server/src/com/cloud/api/query/dao/HostJoinDaoImpl.java +++ b/server/src/com/cloud/api/query/dao/HostJoinDaoImpl.java @@ -31,12 +31,16 @@ import org.apache.log4j.Logger; import org.springframework.stereotype.Component; import org.apache.cloudstack.api.ApiConstants.HostDetails; +import org.apache.cloudstack.api.response.GpuResponse; import org.apache.cloudstack.api.response.HostForMigrationResponse; import org.apache.cloudstack.api.response.HostResponse; +import org.apache.cloudstack.api.response.VgpuResponse; import org.apache.cloudstack.framework.config.dao.ConfigurationDao; import com.cloud.api.ApiDBUtils; import com.cloud.api.query.vo.HostJoinVO; +import com.cloud.gpu.HostGpuGroupsVO; +import com.cloud.gpu.VGPUTypesVO; import com.cloud.host.Host; import com.cloud.host.HostStats; import com.cloud.storage.StorageStats; @@ -92,6 +96,27 @@ public class HostJoinDaoImpl extends GenericDaoBase implements hostResponse.setVersion(host.getVersion()); hostResponse.setCreated(host.getCreated()); + List gpuGroups = ApiDBUtils.getGpuGroups(host.getId()); + if (gpuGroups != null && !gpuGroups.isEmpty()) { + List gpus = new ArrayList(); + for (HostGpuGroupsVO entry : gpuGroups) { + GpuResponse gpuResponse = new GpuResponse(); + gpuResponse.setGpuGroupName(entry.getGroupName()); + List vgpuTypes = ApiDBUtils.getVgpus(entry.getId()); + if (vgpuTypes != null && !vgpuTypes.isEmpty()) { + List vgpus = new ArrayList(); + for (VGPUTypesVO vgpuType : vgpuTypes) { + VgpuResponse vgpuResponse = new VgpuResponse(); + vgpuResponse.setName(vgpuType.getVgpuType()); + vgpuResponse.setCapacity(vgpuType.getRemainingCapacity()); + vgpus.add(vgpuResponse); + } + gpuResponse.setVgpu(vgpus); + } + gpus.add(gpuResponse); + } + hostResponse.setGpuGroups(gpus); + } if (details.contains(HostDetails.all) || details.contains(HostDetails.capacity) || details.contains(HostDetails.stats) || details.contains(HostDetails.events)) { hostResponse.setOsCategoryId(host.getOsCategoryUuid()); diff --git a/server/src/com/cloud/api/query/dao/UserVmJoinDaoImpl.java b/server/src/com/cloud/api/query/dao/UserVmJoinDaoImpl.java index 08478e2958b..235902cc7bd 100644 --- a/server/src/com/cloud/api/query/dao/UserVmJoinDaoImpl.java +++ b/server/src/com/cloud/api/query/dao/UserVmJoinDaoImpl.java @@ -40,7 +40,9 @@ import org.springframework.stereotype.Component; import com.cloud.api.ApiDBUtils; import com.cloud.api.query.vo.ResourceTagJoinVO; import com.cloud.api.query.vo.UserVmJoinVO; +import com.cloud.gpu.GPU; import com.cloud.hypervisor.Hypervisor.HypervisorType; +import com.cloud.service.ServiceOfferingDetailsVO; import com.cloud.user.Account; import com.cloud.uservm.UserVm; import com.cloud.utils.db.GenericDaoBase; @@ -157,6 +159,10 @@ public class UserVmJoinDaoImpl extends GenericDaoBase implem userVmResponse.setCpuNumber(userVm.getCpu()); userVmResponse.setCpuSpeed(userVm.getSpeed()); userVmResponse.setMemory(userVm.getRamSize()); + ServiceOfferingDetailsVO serviceOfferingDetail = ApiDBUtils.findServiceOfferingDetail(userVm.getServiceOfferingId(), GPU.Keys.vgpuType.toString()); + if (serviceOfferingDetail != null) { + userVmResponse.setVgpu(serviceOfferingDetail.getValue()); + } } userVmResponse.setGuestOsId(userVm.getGuestOsUuid()); if (details.contains(VMDetails.all) || details.contains(VMDetails.volume)) { diff --git a/server/src/com/cloud/configuration/ConfigurationManagerImpl.java b/server/src/com/cloud/configuration/ConfigurationManagerImpl.java index 08cc5a63f50..863d71b843b 100755 --- a/server/src/com/cloud/configuration/ConfigurationManagerImpl.java +++ b/server/src/com/cloud/configuration/ConfigurationManagerImpl.java @@ -130,6 +130,7 @@ import com.cloud.exception.InvalidParameterValueException; import com.cloud.exception.PermissionDeniedException; import com.cloud.exception.ResourceAllocationException; import com.cloud.exception.ResourceUnavailableException; +import com.cloud.gpu.GPU; import com.cloud.hypervisor.Hypervisor.HypervisorType; import com.cloud.network.IpAddressManager; import com.cloud.network.Network; @@ -2079,13 +2080,56 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati offering.setHypervisorSnapshotReserve(hypervisorSnapshotReserve); - if ((offering = _serviceOfferingDao.persist(offering)) != null) { - if (details != null) { - List detailsVO = new ArrayList(); - for (Entry detailEntry : details.entrySet()) { - detailsVO.add(new ServiceOfferingDetailsVO(offering.getId(), detailEntry.getKey(), detailEntry.getValue(), true)); + List detailsVO = null; + if (details != null) { + // Check if the user has passed the gpu-type before passing the VGPU type + if (!details.containsKey(GPU.Keys.pciDevice.toString()) && details.containsKey(GPU.Keys.vgpuType.toString())) { + throw new InvalidParameterValueException("Please specify the gpu type"); + } + detailsVO = new ArrayList(); + for (Entry detailEntry : details.entrySet()) { + String value = null; + if (detailEntry.getKey().equals(GPU.Keys.pciDevice.toString())) { + for (GPU.Type type : GPU.Type.values()) { + if (detailEntry.getValue().equals(type.toString())) { + value = detailEntry.getValue(); + } + } + if (value == null) { + throw new InvalidParameterValueException("Please specify valid gpu type"); + } } + if (detailEntry.getKey().equals(GPU.Keys.vgpuType.toString())) { + if (details.get(GPU.Keys.pciDevice.toString()).equals(GPU.Type.GPU_Passthrough.toString())) { + throw new InvalidParameterValueException("vgpuTypes are supported only with vGPU pciDevice"); + } + if (detailEntry.getValue() == null) { + throw new InvalidParameterValueException("With vGPU as pciDevice, vGPUType value cannot be null"); + } + for (GPU.vGPUType entry : GPU.vGPUType.values()) { + if (detailEntry.getValue().equals(entry.getType())) { + value = entry.getType(); + } + } + if (value == null || detailEntry.getValue().equals(GPU.vGPUType.passthrough.getType())) { + throw new InvalidParameterValueException("Please specify valid vGPU type"); + } + } + detailsVO.add(new ServiceOfferingDetailsVO(offering.getId(), detailEntry.getKey(), detailEntry.getValue(), true)); + } + // If pciDevice type is passed, put the default VGPU type as 'passthrough' + if (details.containsKey(GPU.Keys.pciDevice.toString()) + && !details.containsKey(GPU.Keys.vgpuType.toString())) { + detailsVO.add(new ServiceOfferingDetailsVO(offering.getId(), + GPU.Keys.vgpuType.toString(), GPU.vGPUType.passthrough.getType(), true)); + } + } + if ((offering = _serviceOfferingDao.persist(offering)) != null) { + if (detailsVO != null && !detailsVO.isEmpty()) { + for (int index = 0; index < detailsVO.size(); index++) { + detailsVO.get(index).setResourceId(offering.getId()); + } _serviceOfferingDetailsDao.saveDetails(detailsVO); } CallContext.current().setEventDetails("Service offering id=" + offering.getId()); diff --git a/server/src/com/cloud/deploy/DeploymentPlanningManagerImpl.java b/server/src/com/cloud/deploy/DeploymentPlanningManagerImpl.java index 3c87b249990..f76e4852849 100644 --- a/server/src/com/cloud/deploy/DeploymentPlanningManagerImpl.java +++ b/server/src/com/cloud/deploy/DeploymentPlanningManagerImpl.java @@ -81,6 +81,7 @@ import com.cloud.deploy.dao.PlannerHostReservationDao; import com.cloud.exception.AffinityConflictException; import com.cloud.exception.ConnectionException; import com.cloud.exception.InsufficientServerCapacityException; +import com.cloud.gpu.GPU; import com.cloud.host.Host; import com.cloud.host.HostVO; import com.cloud.host.Status; @@ -89,7 +90,10 @@ import com.cloud.hypervisor.Hypervisor.HypervisorType; import com.cloud.offering.ServiceOffering; import com.cloud.org.Cluster; import com.cloud.org.Grouping; +import com.cloud.resource.ResourceManager; import com.cloud.resource.ResourceState; +import com.cloud.service.ServiceOfferingDetailsVO; +import com.cloud.service.dao.ServiceOfferingDetailsDao; import com.cloud.storage.DiskOfferingVO; import com.cloud.storage.ScopeType; import com.cloud.storage.Storage; @@ -213,6 +217,10 @@ public class DeploymentPlanningManagerImpl extends ManagerBase implements Deploy DataStoreManager dataStoreMgr; @Inject protected ClusterDetailsDao _clusterDetailsDao; + @Inject + protected ResourceManager _resourceMgr; + @Inject + protected ServiceOfferingDetailsDao _serviceOfferingDetailsDao; protected List _planners; @@ -353,6 +361,7 @@ public class DeploymentPlanningManagerImpl extends ManagerBase implements Deploy s_logger.debug("This VM has last host_id specified, trying to choose the same host: " + vm.getLastHostId()); HostVO host = _hostDao.findById(vm.getLastHostId()); + ServiceOfferingDetailsVO offeringDetails = null; if (host == null) { s_logger.debug("The last host of this VM cannot be found"); } else if (avoids.shouldAvoid(host)) { @@ -360,6 +369,9 @@ public class DeploymentPlanningManagerImpl extends ManagerBase implements Deploy } else if (_capacityMgr.checkIfHostReachMaxGuestLimit(host)) { s_logger.debug("The last Host, hostId: " + host.getId() + " already has max Running VMs(count includes system VMs), skipping this and trying other available hosts"); + } else if ((offeringDetails = _serviceOfferingDetailsDao.findDetail(offering.getId(), GPU.Keys.vgpuType.toString())) != null + && !_resourceMgr.isGPUDeviceAvailable(host.getId(), offeringDetails.getValue())){ + s_logger.debug("The last host of this VM does not have required GPU devices available"); } else { if (host.getStatus() == Status.Up && host.getResourceState() == ResourceState.Enabled) { boolean hostTagsMatch = true; @@ -1397,4 +1409,4 @@ public class DeploymentPlanningManagerImpl extends ManagerBase implements Deploy } return true; } -} \ No newline at end of file +} diff --git a/server/src/com/cloud/hypervisor/HypervisorGuruBase.java b/server/src/com/cloud/hypervisor/HypervisorGuruBase.java index 7fb79fa1578..4af20c6f00d 100644 --- a/server/src/com/cloud/hypervisor/HypervisorGuruBase.java +++ b/server/src/com/cloud/hypervisor/HypervisorGuruBase.java @@ -25,8 +25,12 @@ import com.cloud.agent.api.Command; import com.cloud.agent.api.to.DiskTO; import com.cloud.agent.api.to.NicTO; import com.cloud.agent.api.to.VirtualMachineTO; +import com.cloud.gpu.GPU; import com.cloud.offering.ServiceOffering; +import com.cloud.resource.ResourceManager; import com.cloud.server.ConfigurationServer; +import com.cloud.service.ServiceOfferingDetailsVO; +import com.cloud.service.dao.ServiceOfferingDetailsDao; import com.cloud.storage.dao.VMTemplateDetailsDao; import com.cloud.utils.Pair; import com.cloud.utils.component.AdapterBase; @@ -55,6 +59,10 @@ public abstract class HypervisorGuruBase extends AdapterBase implements Hypervis NicSecondaryIpDao _nicSecIpDao; @Inject ConfigurationServer _configServer; + @Inject + ResourceManager _resourceMgr; + @Inject + ServiceOfferingDetailsDao _serviceOfferingDetailsDao; protected HypervisorGuruBase() { super(); @@ -125,6 +133,13 @@ public abstract class HypervisorGuruBase extends AdapterBase implements Hypervis if (detailsInVm != null) { to.setDetails(detailsInVm); } + + // Set GPU details + ServiceOfferingDetailsVO offeringDetail = null; + if ((offeringDetail = _serviceOfferingDetailsDao.findDetail(offering.getId(), GPU.Keys.vgpuType.toString())) != null) { + to.setGpuDevice(_resourceMgr.getGPUDevice(vm.getHostId(), offeringDetail.getValue())); + } + // Workaround to make sure the TO has the UUID we need for Niciri integration VMInstanceVO vmInstance = _virtualMachineDao.findById(to.getId()); // check if XStools/VMWare tools are present in the VM and dynamic scaling feature is enabled (per zone/global) diff --git a/server/src/com/cloud/network/NetworkUsageManagerImpl.java b/server/src/com/cloud/network/NetworkUsageManagerImpl.java index e9b039369aa..13eb2107e8b 100755 --- a/server/src/com/cloud/network/NetworkUsageManagerImpl.java +++ b/server/src/com/cloud/network/NetworkUsageManagerImpl.java @@ -57,6 +57,7 @@ import com.cloud.event.UsageEventVO; import com.cloud.event.dao.UsageEventDao; import com.cloud.exception.AgentUnavailableException; import com.cloud.exception.InvalidParameterValueException; +import com.cloud.gpu.dao.HostGpuGroupsDao; import com.cloud.host.DetailVO; import com.cloud.host.Host; import com.cloud.host.HostVO; @@ -116,6 +117,8 @@ public class NetworkUsageManagerImpl extends ManagerBase implements NetworkUsage @Inject HostDetailsDao _detailsDao; @Inject + HostGpuGroupsDao _hostGpuGroupsDao; + @Inject AccountManager _accountMgr; @Inject NetworkDao _networksDao = null; @@ -537,6 +540,7 @@ public class NetworkUsageManagerImpl extends ManagerBase implements NetworkUsage long hostId = host.getId(); _agentMgr.disconnectWithoutInvestigation(hostId, Status.Event.Remove); _detailsDao.deleteDetails(hostId); + _hostGpuGroupsDao.deleteGpuEntries(hostId); host.setGuid(null); _hostDao.update(hostId, host); _hostDao.remove(hostId); diff --git a/server/src/com/cloud/resource/ResourceManagerImpl.java b/server/src/com/cloud/resource/ResourceManagerImpl.java index adad85ca8a6..26258852b17 100755 --- a/server/src/com/cloud/resource/ResourceManagerImpl.java +++ b/server/src/com/cloud/resource/ResourceManagerImpl.java @@ -30,11 +30,6 @@ import javax.ejb.Local; import javax.inject.Inject; import javax.naming.ConfigurationException; -import org.apache.log4j.Logger; -import org.springframework.stereotype.Component; - -import com.google.gson.Gson; - import org.apache.cloudstack.api.ApiConstants; import org.apache.cloudstack.api.command.admin.cluster.AddClusterCmd; import org.apache.cloudstack.api.command.admin.cluster.DeleteClusterCmd; @@ -51,10 +46,14 @@ import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao; import org.apache.cloudstack.storage.datastore.db.StoragePoolVO; import org.apache.cloudstack.utils.identity.ManagementServerNode; import org.apache.commons.lang.ObjectUtils; +import org.apache.log4j.Logger; +import org.springframework.stereotype.Component; import com.cloud.agent.AgentManager; import com.cloud.agent.api.Answer; import com.cloud.agent.api.Command; +import com.cloud.agent.api.GetGPUStatsAnswer; +import com.cloud.agent.api.GetGPUStatsCommand; import com.cloud.agent.api.GetHostStatsAnswer; import com.cloud.agent.api.GetHostStatsCommand; import com.cloud.agent.api.MaintainAnswer; @@ -64,6 +63,7 @@ import com.cloud.agent.api.StartupCommand; import com.cloud.agent.api.StartupRoutingCommand; import com.cloud.agent.api.UnsupportedAnswer; import com.cloud.agent.api.UpdateHostPasswordCommand; +import com.cloud.agent.api.to.GPUDeviceTO; import com.cloud.agent.transport.Request; import com.cloud.api.ApiDBUtils; import com.cloud.capacity.Capacity; @@ -97,6 +97,11 @@ import com.cloud.exception.DiscoveryException; import com.cloud.exception.InvalidParameterValueException; import com.cloud.exception.PermissionDeniedException; import com.cloud.exception.ResourceInUseException; +import com.cloud.gpu.GPU.vGPUType; +import com.cloud.gpu.HostGpuGroupsVO; +import com.cloud.gpu.VGPUTypesVO; +import com.cloud.gpu.dao.HostGpuGroupsDao; +import com.cloud.gpu.dao.VGPUTypesDao; import com.cloud.ha.HighAvailabilityManager; import com.cloud.ha.HighAvailabilityManager.WorkType; import com.cloud.host.DetailVO; @@ -137,11 +142,14 @@ import com.cloud.utils.UriUtils; import com.cloud.utils.component.Manager; import com.cloud.utils.component.ManagerBase; import com.cloud.utils.db.DB; +import com.cloud.utils.db.Filter; import com.cloud.utils.db.GenericSearchBuilder; import com.cloud.utils.db.GlobalLock; +import com.cloud.utils.db.JoinBuilder; import com.cloud.utils.db.QueryBuilder; import com.cloud.utils.db.SearchBuilder; import com.cloud.utils.db.SearchCriteria; +import com.cloud.utils.db.TransactionLegacy; import com.cloud.utils.db.SearchCriteria.Func; import com.cloud.utils.db.SearchCriteria.Op; import com.cloud.utils.db.Transaction; @@ -158,6 +166,7 @@ import com.cloud.vm.VMInstanceVO; import com.cloud.vm.VirtualMachine.State; import com.cloud.vm.VirtualMachineManager; import com.cloud.vm.dao.VMInstanceDao; +import com.google.gson.Gson; @Component @Local({ResourceManager.class, ResourceService.class}) @@ -193,6 +202,10 @@ public class ResourceManagerImpl extends ManagerBase implements ResourceManager, @Inject private GuestOSCategoryDao _guestOSCategoryDao; @Inject + protected HostGpuGroupsDao _hostGpuGroupsDao; + @Inject + protected VGPUTypesDao _vgpuTypesDao; + @Inject private PrimaryDataStoreDao _storagePoolDao; @Inject private DataCenterIpAddressDao _privateIPAddressDao; @@ -244,6 +257,8 @@ public class ResourceManagerImpl extends ManagerBase implements ResourceManager, private GenericSearchBuilder _hypervisorsInDC; + private SearchBuilder _gpuAvailability; + private void insertListener(Integer event, ResourceListener listener) { List lst = _lifeCycleListeners.get(event); if (lst == null) { @@ -827,6 +842,9 @@ public class ResourceManagerImpl extends ManagerBase implements ResourceManager, // delete host details _hostDetailsDao.deleteDetails(hostId); + // if host is GPU enabled, delete GPU entries + _hostGpuGroupsDao.deleteGpuEntries(hostId); + host.setGuid(null); Long clusterId = host.getClusterId(); host.setClusterId(null); @@ -1329,6 +1347,14 @@ public class ResourceManagerImpl extends ManagerBase implements ResourceManager, _hypervisorsInDC.and("type", _hypervisorsInDC.entity().getType(), SearchCriteria.Op.EQ); _hypervisorsInDC.done(); + _gpuAvailability = _hostGpuGroupsDao.createSearchBuilder(); + _gpuAvailability.and("hostId", _gpuAvailability.entity().getHostId(), Op.EQ); + SearchBuilder join1 = _vgpuTypesDao.createSearchBuilder(); + join1.and("vgpuType", join1.entity().getVgpuType(), Op.EQ); + join1.and("remainingCapacity", join1.entity().getRemainingCapacity(), Op.GT); + _gpuAvailability.join("groupId", join1, _gpuAvailability.entity().getId(), join1.entity().getGpuGroupId(), JoinBuilder.JoinType.INNER); + _gpuAvailability.done(); + return true; } @@ -1958,6 +1984,7 @@ public class ResourceManagerImpl extends ManagerBase implements ResourceManager, host.setSpeed(ssCmd.getSpeed()); host.setHypervisorType(hyType); host.setHypervisorVersion(ssCmd.getHypervisorVersion()); + host.setGpuGroups(ssCmd.getGpuGroupDetails()); return host; } @@ -2473,6 +2500,66 @@ public class ResourceManagerImpl extends ManagerBase implements ResourceManager, return sc.list(); } + @Override + public List listAvailableGPUDevice(long hostId, String vgpuType) { + if (vgpuType == null) { + vgpuType = vGPUType.passthrough.getType(); + } + Filter searchFilter = new Filter(VGPUTypesVO.class, "remainingCapacity", false, null, null); + SearchCriteria sc = _gpuAvailability.create(); + sc.setParameters("hostId", hostId); + sc.setJoinParameters("groupId", "vgpuType", vgpuType); + sc.setJoinParameters("groupId", "remainingCapacity", 0); + return _hostGpuGroupsDao.customSearch(sc, searchFilter); + } + + @Override + public boolean isGPUDeviceAvailable(long hostId, String vgpuType) { + if(!listAvailableGPUDevice(hostId, vgpuType).isEmpty()) { + return true; + } else { + if (s_logger.isDebugEnabled()) { + s_logger.debug("Host ID: "+ hostId +" does not have GPU device available"); + } + return false; + } + } + + @Override + public GPUDeviceTO getGPUDevice(long hostId, String vgpuType) { + HostGpuGroupsVO gpuDevice = listAvailableGPUDevice(hostId, vgpuType).get(0); + return new GPUDeviceTO(gpuDevice.getGroupName(), vgpuType, null); + } + + @Override + public void updateGPUDetails(long hostId, HashMap> groupDetails) { + // Update GPU group capacity + TransactionLegacy txn = TransactionLegacy.currentTxn(); + txn.start(); + _hostGpuGroupsDao.persist(hostId, new ArrayList(groupDetails.keySet())); + _vgpuTypesDao.persist(hostId, groupDetails); + txn.commit(); + } + + @Override + public HashMap> getGPUStatistics(HostVO host) { + Answer answer = _agentMgr.easySend(host.getId(), new GetGPUStatsCommand(host.getGuid(), host.getName())); + if (answer != null && (answer instanceof UnsupportedAnswer)) { + return null; + } + if (answer == null || !answer.getResult()) { + String msg = "Unable to obtain GPU stats for host " + host.getName(); + s_logger.warn(msg); + return null; + } else { + // now construct the result object + if (answer instanceof GetGPUStatsAnswer) { + return ((GetGPUStatsAnswer)answer).getGroupDetails(); + } + } + return null; + } + @Override @DB @ActionEvent(eventType = EventTypes.EVENT_HOST_RESERVATION_RELEASE, eventDescription = "releasing host reservation", async = true) diff --git a/server/src/com/cloud/server/ManagementServerImpl.java b/server/src/com/cloud/server/ManagementServerImpl.java index 49a9eb53e5d..663d4e505c5 100755 --- a/server/src/com/cloud/server/ManagementServerImpl.java +++ b/server/src/com/cloud/server/ManagementServerImpl.java @@ -508,6 +508,7 @@ import com.cloud.exception.OperationTimedoutException; import com.cloud.exception.PermissionDeniedException; import com.cloud.exception.ResourceUnavailableException; import com.cloud.exception.VirtualMachineMigrationException; +import com.cloud.gpu.GPU; import com.cloud.ha.HighAvailabilityManager; import com.cloud.host.DetailVO; import com.cloud.host.Host; @@ -539,6 +540,7 @@ import com.cloud.server.ResourceTag.ResourceObjectType; import com.cloud.server.auth.UserAuthenticator; import com.cloud.service.ServiceOfferingVO; import com.cloud.service.dao.ServiceOfferingDao; +import com.cloud.service.dao.ServiceOfferingDetailsDao; import com.cloud.storage.DiskOfferingVO; import com.cloud.storage.GuestOS; import com.cloud.storage.GuestOSCategoryVO; @@ -700,6 +702,9 @@ public class ManagementServerImpl extends ManagerBase implements ManagementServe private ResourceTagDao _resourceTagDao; @Inject private ImageStoreDao _imgStoreDao; + @Inject + private ServiceOfferingDetailsDao _serviceOfferingDetailsDao; + @Inject private ProjectManager _projectMgr; @@ -1059,6 +1064,13 @@ public class ManagementServerImpl extends ManagerBase implements ManagementServe throw ex; } + if(_serviceOfferingDetailsDao.findDetail(vm.getServiceOfferingId(), GPU.Keys.pciDevice.toString()) != null) { + s_logger.info(" Live Migration of GPU enabled VM : " + vm.getInstanceName()+ " is not supported"); + // Return empty list. + return new Ternary, Integer>, List, Map>(new Pair, + Integer>(new ArrayList(), new Integer(0)), new ArrayList(), new HashMap()); + } + if (!vm.getHypervisorType().equals(HypervisorType.XenServer) && !vm.getHypervisorType().equals(HypervisorType.VMware) && !vm.getHypervisorType().equals(HypervisorType.KVM) && !vm.getHypervisorType().equals(HypervisorType.Ovm) && !vm.getHypervisorType().equals(HypervisorType.Hyperv)) { if (s_logger.isDebugEnabled()) { diff --git a/server/src/com/cloud/server/StatsCollector.java b/server/src/com/cloud/server/StatsCollector.java index 548587cfa8e..067ed003f39 100755 --- a/server/src/com/cloud/server/StatsCollector.java +++ b/server/src/com/cloud/server/StatsCollector.java @@ -54,6 +54,7 @@ import com.cloud.agent.api.VmStatsEntry; import com.cloud.cluster.ManagementServerHostVO; import com.cloud.cluster.dao.ManagementServerHostDao; import com.cloud.exception.StorageUnavailableException; +import com.cloud.gpu.dao.HostGpuGroupsDao; import com.cloud.host.Host; import com.cloud.host.HostStats; import com.cloud.host.HostVO; @@ -175,6 +176,8 @@ public class StatsCollector extends ManagerBase implements ComponentMethodInterc private AutoScaleVmProfileDao _asProfileDao; @Inject private ServiceOfferingDao _serviceOfferingDao; + @Inject + private HostGpuGroupsDao _hostGpuGroupsDao; private ConcurrentHashMap _hostStats = new ConcurrentHashMap(); private final ConcurrentHashMap _VmStats = new ConcurrentHashMap(); @@ -188,6 +191,7 @@ public class StatsCollector extends ManagerBase implements ComponentMethodInterc long volumeStatsInterval = -1L; long autoScaleStatsInterval = -1L; int vmDiskStatsInterval = 0; + List hostIds = null; private ScheduledExecutorService _diskStatsUpdateExecutor; private int _usageAggregationRange = 1440; @@ -325,6 +329,23 @@ public class StatsCollector extends ManagerBase implements ComponentMethodInterc } } _hostStats = hostStats; + // Get a subset of hosts with GPU support from the list of "hosts" + List gpuEnabledHosts = new ArrayList(); + if (hostIds != null) { + for (HostVO host : hosts) { + if (hostIds.contains(host.getId())) { + gpuEnabledHosts.add(host); + } + } + } else { + // Check for all the hosts managed by CloudStack. + gpuEnabledHosts = hosts; + } + for (HostVO host : gpuEnabledHosts) { + HashMap> groupDetails = _resourceMgr.getGPUStatistics(host); + _resourceMgr.updateGPUDetails(host.getId(), groupDetails); + } + hostIds = _hostGpuGroupsDao.listHostIds(); } catch (Throwable t) { s_logger.error("Error trying to retrieve host stats", t); } diff --git a/server/src/com/cloud/storage/VolumeApiServiceImpl.java b/server/src/com/cloud/storage/VolumeApiServiceImpl.java index 17461c08774..acc922fab40 100644 --- a/server/src/com/cloud/storage/VolumeApiServiceImpl.java +++ b/server/src/com/cloud/storage/VolumeApiServiceImpl.java @@ -92,12 +92,14 @@ import com.cloud.exception.InvalidParameterValueException; import com.cloud.exception.PermissionDeniedException; import com.cloud.exception.ResourceAllocationException; import com.cloud.exception.StorageUnavailableException; +import com.cloud.gpu.GPU; import com.cloud.host.HostVO; import com.cloud.host.dao.HostDao; import com.cloud.hypervisor.Hypervisor.HypervisorType; import com.cloud.hypervisor.HypervisorCapabilitiesVO; import com.cloud.hypervisor.dao.HypervisorCapabilitiesDao; import com.cloud.org.Grouping; +import com.cloud.service.dao.ServiceOfferingDetailsDao; import com.cloud.storage.Storage.ImageFormat; import com.cloud.storage.dao.DiskOfferingDao; import com.cloud.storage.dao.SnapshotDao; @@ -171,6 +173,8 @@ public class VolumeApiServiceImpl extends ManagerBase implements VolumeApiServic @Inject private SnapshotDao _snapshotDao; @Inject + protected ServiceOfferingDetailsDao _serviceOfferingDetailsDao; + @Inject StoragePoolDetailsDao storagePoolDetailsDao; @Inject private UserVmDao _userVmDao; @@ -1466,6 +1470,10 @@ public class VolumeApiServiceImpl extends ManagerBase implements VolumeApiServic } if (vm != null && vm.getState() == State.Running) { + // Check if the VM is GPU enabled. + if(_serviceOfferingDetailsDao.findDetail(vm.getServiceOfferingId(), GPU.Keys.pciDevice.toString()) != null) { + throw new InvalidParameterValueException("Live Migration of GPU enabled VM is not supported"); + } // Check if the underlying hypervisor supports storage motion. Long hostId = vm.getHostId(); if (hostId != null) { diff --git a/server/src/com/cloud/vm/UserVmManagerImpl.java b/server/src/com/cloud/vm/UserVmManagerImpl.java index d1df3c11a61..be00aa8c569 100755 --- a/server/src/com/cloud/vm/UserVmManagerImpl.java +++ b/server/src/com/cloud/vm/UserVmManagerImpl.java @@ -137,6 +137,7 @@ import com.cloud.exception.ResourceAllocationException; import com.cloud.exception.ResourceUnavailableException; import com.cloud.exception.StorageUnavailableException; import com.cloud.exception.VirtualMachineMigrationException; +import com.cloud.gpu.GPU; import com.cloud.ha.HighAvailabilityManager; import com.cloud.host.Host; import com.cloud.host.HostVO; @@ -3853,6 +3854,11 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir ex.addProxyObject(vm.getUuid(), "vmId"); throw ex; } + + if(serviceOfferingDetailsDao.findDetail(vm.getServiceOfferingId(), GPU.Keys.pciDevice.toString()) != null) { + throw new InvalidParameterValueException("Live Migration of GPU enabled VM is not supported"); + } + if (!vm.getHypervisorType().equals(HypervisorType.XenServer) && !vm.getHypervisorType().equals(HypervisorType.VMware) && !vm.getHypervisorType().equals(HypervisorType.KVM) && !vm.getHypervisorType().equals(HypervisorType.Ovm) && !vm.getHypervisorType().equals(HypervisorType.Hyperv) && !vm.getHypervisorType().equals(HypervisorType.Simulator)) { @@ -4164,6 +4170,10 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir throw ex; } + if(serviceOfferingDetailsDao.findDetail(vm.getServiceOfferingId(), GPU.Keys.pciDevice.toString()) != null) { + throw new InvalidParameterValueException("Live Migration of GPU enabled VM is not supported"); + } + if (!vm.getHypervisorType().equals(HypervisorType.XenServer) && !vm.getHypervisorType().equals(HypervisorType.VMware) && !vm.getHypervisorType().equals(HypervisorType.KVM) && !vm.getHypervisorType().equals(HypervisorType.Ovm) && !vm.getHypervisorType().equals(HypervisorType.Simulator)) { throw new InvalidParameterValueException("Unsupported hypervisor type for vm migration, we support" + " XenServer/VMware/KVM only"); diff --git a/server/test/com/cloud/resource/MockResourceManagerImpl.java b/server/test/com/cloud/resource/MockResourceManagerImpl.java index 5599e8c42b9..e6bf9a26b2c 100644 --- a/server/test/com/cloud/resource/MockResourceManagerImpl.java +++ b/server/test/com/cloud/resource/MockResourceManagerImpl.java @@ -17,6 +17,7 @@ package com.cloud.resource; +import java.util.HashMap; import java.util.List; import java.util.Map; @@ -35,6 +36,7 @@ import org.apache.cloudstack.api.command.admin.host.UpdateHostPasswordCmd; import com.cloud.agent.api.StartupCommand; import com.cloud.agent.api.StartupRoutingCommand; +import com.cloud.agent.api.to.GPUDeviceTO; import com.cloud.dc.DataCenterVO; import com.cloud.dc.HostPodVO; import com.cloud.dc.PodCluster; @@ -42,6 +44,7 @@ import com.cloud.exception.AgentUnavailableException; import com.cloud.exception.DiscoveryException; import com.cloud.exception.InvalidParameterValueException; import com.cloud.exception.ResourceInUseException; +import com.cloud.gpu.HostGpuGroupsVO; import com.cloud.host.Host; import com.cloud.host.Host.Type; import com.cloud.host.HostStats; @@ -554,4 +557,32 @@ public class MockResourceManagerImpl extends ManagerBase implements ResourceMana return false; } + @Override + public boolean isGPUDeviceAvailable(long hostId, String vgpuType) { + // TODO Auto-generated method stub + return false; + } + + @Override + public GPUDeviceTO getGPUDevice(long hostId, String vgpuType) { + // TODO Auto-generated method stub + return null; + } + + @Override + public List listAvailableGPUDevice(long hostId, String vgpuType) { + // TODO Auto-generated method stub + return null; + } + + @Override + public void updateGPUDetails(long hostId, HashMap> deviceDetails) { + // TODO Auto-generated method stub + } + + @Override + public HashMap> getGPUStatistics(HostVO host) { + // TODO Auto-generated method stub + return null; + } } diff --git a/server/test/com/cloud/vm/DeploymentPlanningManagerImplTest.java b/server/test/com/cloud/vm/DeploymentPlanningManagerImplTest.java index 751a3bdd43f..fb63766e378 100644 --- a/server/test/com/cloud/vm/DeploymentPlanningManagerImplTest.java +++ b/server/test/com/cloud/vm/DeploymentPlanningManagerImplTest.java @@ -78,7 +78,9 @@ import com.cloud.exception.AffinityConflictException; import com.cloud.exception.InsufficientServerCapacityException; import com.cloud.host.dao.HostDao; import com.cloud.hypervisor.Hypervisor.HypervisorType; +import com.cloud.resource.ResourceManager; import com.cloud.service.ServiceOfferingVO; +import com.cloud.service.dao.ServiceOfferingDetailsDao; import com.cloud.storage.StorageManager; import com.cloud.storage.dao.DiskOfferingDao; import com.cloud.storage.dao.GuestOSCategoryDao; @@ -238,6 +240,16 @@ public class DeploymentPlanningManagerImplTest { return Mockito.mock(ClusterDetailsDao.class); } + @Bean + public ResourceManager resourceManager() { + return Mockito.mock(ResourceManager.class); + } + + @Bean + public ServiceOfferingDetailsDao serviceOfferingDetailsDao() { + return Mockito.mock(ServiceOfferingDetailsDao.class); + } + @Bean public DataStoreManager cataStoreManager() { return Mockito.mock(DataStoreManager.class); diff --git a/server/test/resources/createNetworkOffering.xml b/server/test/resources/createNetworkOffering.xml index c6228dab707..6ae1978f40f 100644 --- a/server/test/resources/createNetworkOffering.xml +++ b/server/test/resources/createNetworkOffering.xml @@ -43,7 +43,9 @@ - + + + diff --git a/setup/db/db/schema-430to440.sql b/setup/db/db/schema-430to440.sql index be49b838a85..ee4cf215fb7 100644 --- a/setup/db/db/schema-430to440.sql +++ b/setup/db/db/schema-430to440.sql @@ -592,4 +592,22 @@ CREATE VIEW `cloud`.`event_view` AS `cloud`.`event` eve ON event.start_id = eve.id; +DROP TABLE IF EXISTS `cloud`.`host_gpu_groups`; +CREATE TABLE `cloud`.`host_gpu_groups` ( + `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT, + `group_name` varchar(255) NOT NULL, + `host_id` bigint(20) unsigned NOT NULL, + PRIMARY KEY (`id`), + CONSTRAINT `fk_host_gpu_groups__host_id` FOREIGN KEY (`host_id`) REFERENCES `host` (`id`) ON DELETE CASCADE +) ENGINE=InnoDB CHARSET=utf8; + +DROP TABLE IF EXISTS `cloud`.`vgpu_types`; +CREATE TABLE `cloud`.`vgpu_types` ( + `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT, + `gpu_group_id` bigint(20) unsigned NOT NULL, + `vgpu_type` varchar(40) NOT NULL COMMENT 'vgpu type supported by this gpu group', + `remaining_vm_capacity` bigint(20) unsigned DEFAULT NULL COMMENT 'remaining vgpu can be created with this vgpu_type on the given gpu group', + PRIMARY KEY (`id`), + CONSTRAINT `fk_vgpu_types__gpu_group_id` FOREIGN KEY (`gpu_group_id`) REFERENCES `host_gpu_groups` (`id`) ON DELETE CASCADE +) ENGINE=InnoDB CHARSET=utf8; diff --git a/test/integration/smoke/test_deploy_vgpu_enabled_vm.py b/test/integration/smoke/test_deploy_vgpu_enabled_vm.py new file mode 100644 index 00000000000..a09e87e6f2d --- /dev/null +++ b/test/integration/smoke/test_deploy_vgpu_enabled_vm.py @@ -0,0 +1,227 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. + +#Test from the Marvin - Testing in Python wiki + +#All tests inherit from cloudstackTestCase +from marvin.cloudstackTestCase import cloudstackTestCase + +#Import Integration Libraries + +#base - contains all resources as entities and defines create, delete, list operations on them +from marvin.integration.lib.base import Account, VirtualMachine, ServiceOffering + +#utils - utility classes for common cleanup, external library wrappers etc +from marvin.integration.lib.utils import cleanup_resources + +#common - commonly used methods for all tests are listed here +from marvin.integration.lib.common import get_zone, get_domain, get_template + +from nose.plugins.attrib import attr + +class Services: + """Test VM Life Cycle Services + """ + + def __init__(self): + self.services = { + "disk_offering":{ + "displaytext": "Small", + "name": "Small", + "disksize": 1 + }, + "account": { + "email": "test@test.com", + "firstname": "Test", + "lastname": "User", + "username": "test", + # Random characters are appended in create account to + # ensure unique username generated each time + "password": "password", + }, + "vgpu260q": # Create a virtual machine instance with vgpu type as 260q + { + "displayname": "testserver", + "username": "root", # VM creds for SSH + "password": "password", + "ssh_port": 22, + "hypervisor": 'XenServer', + "privateport": 22, + "publicport": 22, + "protocol": 'TCP', + }, + "vgpu140q": # Create a virtual machine instance with vgpu type as 140q + { + "displayname": "testserver", + "username": "root", + "password": "password", + "ssh_port": 22, + "hypervisor": 'XenServer', + "privateport": 22, + "publicport": 22, + "protocol": 'TCP', + }, + "service_offerings": + { + "vgpu260qwin": + { + "name": "Windows Instance with vGPU260Q", + "displaytext": "Windows Instance with vGPU260Q", + "cpunumber": 2, + "cpuspeed": 1600, # in MHz + "memory": 3072, # In MBs + }, + "vgpu140qwin": + { + # Small service offering ID to for change VM + # service offering from medium to small + "name": "Windows Instance with vGPU140Q", + "displaytext": "Windows Instance with vGPU140Q", + "cpunumber": 2, + "cpuspeed": 1600, + "memory": 3072, + } + }, + "diskdevice": ['/dev/vdc', '/dev/vdb', '/dev/hdb', '/dev/hdc', '/dev/xvdd', '/dev/cdrom', '/dev/sr0', '/dev/cdrom1' ], + # Disk device where ISO is attached to instance + "mount_dir": "/mnt/tmp", + "sleep": 60, + "timeout": 10, + #Migrate VM to hostid + "ostype": 'Windows 7 (32-bit)', + # CentOS 5.3 (64-bit) + } + + +class TestDeployvGPUenabledVM(cloudstackTestCase): + """Test deploy a vGPU enabled VM into a user account + """ + + def setUp(self): + self.services = Services().services + self.apiclient = self.testClient.getApiClient() + + # Get Zone, Domain and Default Built-in template + self.domain = get_domain(self.apiclient, self.services) + self.zone = get_zone(self.apiclient, self.services) + self.services["mode"] = self.zone.networktype + # Before running this test, register a windows template with ostype as 'Windows 7 (32-bit)' + self.template = get_template(self.apiclient, self.zone.id, self.services["ostype"], templatetype='USER') + + #create a user account + self.account = Account.create( + self.apiclient, + self.services["account"], + domainid=self.domain.id + ) + + self.services["vgpu260q"]["zoneid"] = self.zone.id + self.services["vgpu260q"]["template"] = self.template.id + + self.services["vgpu140q"]["zoneid"] = self.zone.id + self.services["vgpu140q"]["template"] = self.template.id + #create a service offering + self.service_offering = ServiceOffering.create( + self.apiclient, + self.services["service_offerings"]["vgpu260qwin"], + serviceofferingdetails={'pciDevice': 'VGPU'} + ) + #build cleanup list + self.cleanup = [ + self.service_offering, + self.account + ] + + @attr(tags = ['advanced', 'simulator', 'basic', 'vgpu']) + def test_deploy_vgpu_enabled_vm(self): + """Test Deploy Virtual Machine + + # Validate the following: + # 1. Virtual Machine is accessible via SSH + # 2. Virtual Machine is vGPU enabled (via SSH) + # 3. listVirtualMachines returns accurate information + """ + self.virtual_machine = VirtualMachine.create( + self.apiclient, + self.services["vgpu260q"], + accountid=self.account.name, + domainid=self.account.domainid, + serviceofferingid=self.service_offering.id, + mode=self.services['mode'] + ) + + list_vms = VirtualMachine.list(self.apiclient, id=self.virtual_machine.id) + + self.debug( + "Verify listVirtualMachines response for virtual machine: %s"\ + % self.virtual_machine.id + ) + + self.assertEqual( + isinstance(list_vms, list), + True, + "List VM response was not a valid list" + ) + self.assertNotEqual( + len(list_vms), + 0, + "List VM response was empty" + ) + + vm = list_vms[0] + self.assertEqual( + vm.id, + self.virtual_machine.id, + "Virtual Machine ids do not match" + ) + self.assertEqual( + vm.name, + self.virtual_machine.name, + "Virtual Machine names do not match" + ) + self.assertEqual( + vm.state, + "Running", + msg="VM is not in Running state" + ) + list_hosts = list_hosts( + self.apiclient, + id=vm.hostid + ) + hostip = list_hosts[0].ipaddress + try: + sshClient = SshClient(host=hostip, port=22, user='root',passwd=self.services["host_password"]) + res = sshClient.execute("xe vgpu-list vm-name-label=%s params=type-uuid %s" % ( + vm.instancename + )) + self.debug("SSH result: %s" % res) + except Exception as e: + self.fail("SSH Access failed for %s: %s" % \ + (hostip, e) + ) + result = str(res) + self.assertEqual( + result.count("type-uuid"), + 1, + "VM is vGPU enabled." + ) + + def tearDown(self): + try: + cleanup_resources(self.apiclient, self.cleanup) + except Exception as e: + self.debug("Warning! Exception in tearDown: %s" % e) \ No newline at end of file diff --git a/tools/marvin/marvin/integration/lib/base.py b/tools/marvin/marvin/integration/lib/base.py index 7449d8c9d11..27a26b807d6 100755 --- a/tools/marvin/marvin/integration/lib/base.py +++ b/tools/marvin/marvin/integration/lib/base.py @@ -1462,6 +1462,9 @@ class ServiceOffering: if "deploymentplanner" in services: cmd.deploymentplanner = services["deploymentplanner"] + if "serviceofferingdetails" in services: + cmd.serviceofferingdetails.append({services['serviceofferingdetails']}) + if "isvolatile" in services: cmd.isvolatile = services["isvolatile"] diff --git a/ui/scripts/configuration.js b/ui/scripts/configuration.js index e3c35af3859..86660420fb4 100644 --- a/ui/scripts/configuration.js +++ b/ui/scripts/configuration.js @@ -361,6 +361,71 @@ } }, + pciDevice: { + label: 'GPU Type', + select: function(args) { + var items = []; + items.push({ + id: '', + description: '' + }); + items.push({ + id: 'GPU_Passthrough', + description: 'GPU-Passthrough' + }); + items.push({ + id: 'VGPU', + description: 'VGPU' + }); + args.response.success({ + data: items + }); + args.$select.change(function() { + var $form = $(this).closest('form'); + var $fields = $form.find('.field'); + if (($(this).val() == "") || $(this).val() == "GPU-Passthrough") { + $form.find('[rel=vgpuType]').hide(); + } else if ($(this).val() == "VGPU") { + $form.find('[rel=vgpuType]').css('display', 'block'); + } + }); + } + }, + + vgpuType: { + label: 'VGPU Type', + select: function(args) { + var items = []; + items.push({ + id: '', + description: '' + }); + items.push({ + id: 'GRID K100', + description: 'GRID K100' + }); + items.push({ + id: 'GRID K140Q', + description: 'GRID K140Q' + }); + items.push({ + id: 'GRID K200', + description: 'GRID K200' + }); + items.push({ + id: 'GRID K240Q', + description: 'GRID K240Q' + }); + items.push({ + id: 'GRID K260Q', + description: 'GRID K260Q' + }); + args.response.success({ + data: items + }); + } + }, + domainId: { label: 'label.domain', docID: 'helpComputeOfferingDomain', @@ -428,6 +493,14 @@ array1.push("&serviceofferingdetails[0].ImplicitDedicationMode" + "=" + args.data.plannerMode); } + if (args.data.pciDevice != "") { + array1.push("&serviceofferingdetails[1].pciDevice" + "=" + args.data.pciDevice); + } + + if (args.data.pciDevice == "VGPU") { + array1.push("&serviceofferingdetails[2].vgpuType" + "=" + args.data.vgpuType); + } + if (args.data.networkRate != null && args.data.networkRate.length > 0) { $.extend(data, { networkrate: args.data.networkRate diff --git a/ui/scripts/instances.js b/ui/scripts/instances.js index e5b2e85d34f..10d25917f91 100644 --- a/ui/scripts/instances.js +++ b/ui/scripts/instances.js @@ -1804,7 +1804,9 @@ memory: { label: 'label.memory.mb' }, - + vgpu: { + label: 'VGPU' + }, haenable: { label: 'label.ha.enabled', converter: cloudStack.converters.toBooleanText From 991e1eb6b119a62dedbc0e39a612941af9999103 Mon Sep 17 00:00:00 2001 From: SrikanteswaraRao Talluri Date: Tue, 11 Mar 2014 16:07:28 +0530 Subject: [PATCH 50/70] CLOUDSTACK-6222: Fix the marvin config generator scripts to include new syntax changes in marvin code and fix the logFolderPath --- tools/marvin/marvin/configGenerator.py | 5 ++-- .../marvin/sandbox/advanced/advanced_env.py | 23 ++++++++----------- .../sandbox/advancedsg/advancedsg_env.py | 18 +++++---------- .../marvin/marvin/sandbox/basic/basic_env.py | 16 ++++--------- .../sandbox/demo/simulator/simulator_setup.py | 16 ++++--------- 5 files changed, 27 insertions(+), 51 deletions(-) diff --git a/tools/marvin/marvin/configGenerator.py b/tools/marvin/marvin/configGenerator.py index 0d79e8ea6ad..0b4a0a132bc 100644 --- a/tools/marvin/marvin/configGenerator.py +++ b/tools/marvin/marvin/configGenerator.py @@ -51,8 +51,7 @@ class configuration(object): class logger(object): def __init__(self): '''TestCase/TestClient''' - self.name = None - self.file = None + self.logFolderPath = None class cloudstackConfiguration(object): @@ -61,7 +60,7 @@ class cloudstackConfiguration(object): self.mgtSvr = [] self.dbSvr = None self.globalConfig = [] - self.logger = [] + self.logger = None class zone(object): diff --git a/tools/marvin/marvin/sandbox/advanced/advanced_env.py b/tools/marvin/marvin/sandbox/advanced/advanced_env.py index 1728e61fb19..f3d30643f21 100644 --- a/tools/marvin/marvin/sandbox/advanced/advanced_env.py +++ b/tools/marvin/marvin/sandbox/advanced/advanced_env.py @@ -54,22 +54,22 @@ def describeResources(config): lbprovider = provider() lbprovider.name = 'InternalLbVm' - pn = physical_network() + pn = physicalNetwork() pn.name = "Sandbox-pnet" pn.vlan = config.get('cloudstack', 'pnet.vlan') pn.tags = ["cloud-simulator-public"] - pn.traffictypes = [traffictype("Guest"), - traffictype("Management", {"simulator" : "cloud-simulator-mgmt"}), - traffictype("Public", {"simulator":"cloud-simulator-public"})] + pn.traffictypes = [trafficType("Guest"), + trafficType("Management", {"simulator" : "cloud-simulator-mgmt"}), + trafficType("Public", {"simulator":"cloud-simulator-public"})] pn.isolationmethods = ["VLAN"] pn.providers.append(vpcprovider) pn.providers.append(lbprovider) - pn2 = physical_network() + pn2 = physicalNetwork() pn2.name = "Sandbox-pnet2" pn2.vlan = config.get('cloudstack', 'pnet2.vlan') pn2.tags = ["cloud-simulator-guest"] - pn2.traffictypes = [traffictype('Guest', {'simulator': 'cloud-simulator-guest'})] + pn2.traffictypes = [trafficType('Guest', {'simulator': 'cloud-simulator-guest'})] pn2.isolationmethods = ["VLAN"] pn2.providers.append(vpcprovider) pn2.providers.append(lbprovider) @@ -137,16 +137,11 @@ def describeResources(config): [zs.globalConfig.append(cfg) for cfg in getGlobalSettings(config)] ''''add loggers''' - testClientLogger = logger() - testClientLogger.name = 'TestClient' - testClientLogger.file = 'testclient.log' + testLogger = logger() + testLogger.logFolderPath = '/tmp/' + zs.logger = testLogger - testCaseLogger = logger() - testCaseLogger.name = 'TestCase' - testCaseLogger.file = 'testcase.log' - zs.logger.append(testClientLogger) - zs.logger.append(testCaseLogger) return zs diff --git a/tools/marvin/marvin/sandbox/advancedsg/advancedsg_env.py b/tools/marvin/marvin/sandbox/advancedsg/advancedsg_env.py index 9cf4a0aa98f..284ea2eb25b 100644 --- a/tools/marvin/marvin/sandbox/advancedsg/advancedsg_env.py +++ b/tools/marvin/marvin/sandbox/advancedsg/advancedsg_env.py @@ -51,11 +51,11 @@ def describeResources(config): sgprovider.broadcastdomainrange = 'ZONE' sgprovider.name = 'SecurityGroupProvider' - pn = physical_network() + pn = physicalNetwork() pn.name = "Sandbox-pnet" pn.tags = ["cloud-simulator-pnet"] - pn.traffictypes = [traffictype("Guest"), - traffictype("Management", {"simulator" : "cloud-simulator-mgmt"})] + pn.traffictypes = [trafficType("Guest"), + trafficType("Management", {"simulator" : "cloud-simulator-mgmt"})] pn.isolationmethods = ["VLAN"] pn.providers.append(sgprovider) @@ -121,16 +121,10 @@ def describeResources(config): [zs.globalConfig.append(cfg) for cfg in getGlobalSettings(config)] ''''add loggers''' - testClientLogger = logger() - testClientLogger.name = 'TestClient' - testClientLogger.file = 'testclient.log' + testLogger = logger() + testLogger.logFolderPath = '/tmp/' + zs.logger = testLogger - testCaseLogger = logger() - testCaseLogger.name = 'TestCase' - testCaseLogger.file = 'testcase.log' - - zs.logger.append(testClientLogger) - zs.logger.append(testCaseLogger) return zs diff --git a/tools/marvin/marvin/sandbox/basic/basic_env.py b/tools/marvin/marvin/sandbox/basic/basic_env.py index bf106fcb8de..6198163a866 100644 --- a/tools/marvin/marvin/sandbox/basic/basic_env.py +++ b/tools/marvin/marvin/sandbox/basic/basic_env.py @@ -52,9 +52,9 @@ def describeResources(config): sgprovider.broadcastdomainrange = 'Pod' sgprovider.name = 'SecurityGroupProvider' - pn = physical_network() + pn = physicalNetwork() pn.name = "Sandbox-pnet" - pn.traffictypes = [traffictype("Guest"), traffictype("Management")] + pn.traffictypes = [trafficType("Guest"), trafficType("Management")] pn.isolationmethods = ["L3"] pn.providers.append(sgprovider) @@ -119,16 +119,10 @@ def describeResources(config): [zs.globalConfig.append(cfg) for cfg in getGlobalSettings(config)] ''''add loggers''' - testClientLogger = logger() - testClientLogger.name = 'TestClient' - testClientLogger.file = '/var/log/testclient.log' + testLogger = logger() + testLogger.logFolderPath = '/tmp/' + zs.logger = testLogger - testCaseLogger = logger() - testCaseLogger.name = 'TestCase' - testCaseLogger.file = '/var/log/testcase.log' - - zs.logger.append(testClientLogger) - zs.logger.append(testCaseLogger) return zs diff --git a/tools/marvin/marvin/sandbox/demo/simulator/simulator_setup.py b/tools/marvin/marvin/sandbox/demo/simulator/simulator_setup.py index d45d48243bd..08b20cce67b 100644 --- a/tools/marvin/marvin/sandbox/demo/simulator/simulator_setup.py +++ b/tools/marvin/marvin/sandbox/demo/simulator/simulator_setup.py @@ -46,9 +46,9 @@ def describeResources(config): vpcprovider = provider() vpcprovider.name = 'VpcVirtualRouter' - pn = physical_network() + pn = physicalNetwork() pn.name = "Sandbox-pnet" - pn.traffictypes = [traffictype("Guest"), traffictype("Management"), traffictype("Public")] + pn.traffictypes = [trafficType("Guest"), trafficType("Management"), trafficType("Public")] pn.isolationmethods = ["VLAN"] pn.providers.append(vpcprovider) pn.vlan = config.get('cloudstack', 'zone.vlan') @@ -120,16 +120,10 @@ def describeResources(config): [zs.globalConfig.append(cfg) for cfg in getGlobalSettings(config)] ''''add loggers''' - testClientLogger = logger() - testClientLogger.name = 'TestClient' - testClientLogger.file = '/var/log/testclient.log' + testLogger = logger() + testLogger.logFolderPath = '/tmp/' + zs.logger = testLogger - testCaseLogger = logger() - testCaseLogger.name = 'TestCase' - testCaseLogger.file = '/var/log/testcase.log' - - zs.logger.append(testClientLogger) - zs.logger.append(testCaseLogger) return zs From c874e20c24e8bcf7b606c55ef924606b857c1f6d Mon Sep 17 00:00:00 2001 From: Marcus Sorensen Date: Tue, 11 Mar 2014 11:13:12 -0600 Subject: [PATCH 51/70] CLOUDSTACK-6225: Check libvirt version and volume format before adding flag VIR_STORAGE_VOL_RESIZE_ALLOCATE to resize volume libvirt call --- .../hypervisor/kvm/resource/LibvirtComputingResource.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/LibvirtComputingResource.java b/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/LibvirtComputingResource.java index 5912dd34d2a..f4f6c740c1d 100755 --- a/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/LibvirtComputingResource.java +++ b/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/LibvirtComputingResource.java @@ -1804,8 +1804,11 @@ public class LibvirtComputingResource extends ServerResourceBase implements Serv try { Connect conn = LibvirtConnection.getConnection(); StorageVol v = conn.storageVolLookupByPath(path); + int flags = 0; - int flags = 1; + if (conn.getLibVirVersion() > 1001000 && vol.getFormat() == PhysicalDiskFormat.RAW) { + flags = 1; + } if (shrinkOk) { flags = 4; } From 415e4bffd652d0a92b36cc6ff1bec0e3ea0462da Mon Sep 17 00:00:00 2001 From: Jessica Wang Date: Tue, 11 Mar 2014 11:18:49 -0700 Subject: [PATCH 52/70] CLOUDSTACK-6226: UI > multi widget > dropdown field > translate option value. --- ui/scripts/ui/widgets/multiEdit.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ui/scripts/ui/widgets/multiEdit.js b/ui/scripts/ui/widgets/multiEdit.js index 873775d7221..713ebdeffd3 100755 --- a/ui/scripts/ui/widgets/multiEdit.js +++ b/ui/scripts/ui/widgets/multiEdit.js @@ -927,7 +927,7 @@ response: { success: function(args) { $(args.data).each(function() { - $('