diff --git a/api/src/main/java/com/cloud/network/NetworkModel.java b/api/src/main/java/com/cloud/network/NetworkModel.java index e933a1cc7bd3..0f05b1afa13f 100644 --- a/api/src/main/java/com/cloud/network/NetworkModel.java +++ b/api/src/main/java/com/cloud/network/NetworkModel.java @@ -107,6 +107,10 @@ public interface NetworkModel { List listNetworksUsedByVm(long vmId, boolean isSystem); + default List listNetworksUsedByVm(long vmId) { + throw new UnsupportedOperationException(); + } + Nic getNicInNetwork(long vmId, long networkId); List getNicsForTraffic(long vmId, TrafficType type); diff --git a/api/src/main/java/com/cloud/storage/VolumeApiService.java b/api/src/main/java/com/cloud/storage/VolumeApiService.java index 5c4130158cd8..c9a5139043f6 100644 --- a/api/src/main/java/com/cloud/storage/VolumeApiService.java +++ b/api/src/main/java/com/cloud/storage/VolumeApiService.java @@ -21,6 +21,8 @@ import java.net.MalformedURLException; import java.util.Map; +import com.cloud.exception.StorageUnavailableException; +import org.apache.cloudstack.api.command.user.vm.CloneVMCmd; import org.apache.cloudstack.api.command.user.volume.AttachVolumeCmd; import org.apache.cloudstack.api.command.user.volume.CreateVolumeCmd; import org.apache.cloudstack.api.command.user.volume.DetachVolumeCmd; @@ -92,6 +94,8 @@ public interface VolumeApiService { Volume detachVolumeViaDestroyVM(long vmId, long volumeId); + Volume cloneDataVolume(CloneVMCmd cmd, long snapshotId, Volume volume) throws StorageUnavailableException; + Volume detachVolumeFromVM(DetachVolumeCmd cmd); Snapshot takeSnapshot(Long volumeId, Long policyId, Long snapshotId, Account account, boolean quiescevm, Snapshot.LocationType locationType, boolean asyncBackup, Map tags) @@ -101,6 +105,8 @@ Snapshot takeSnapshot(Long volumeId, Long policyId, Long snapshotId, Account acc Volume updateVolume(long volumeId, String path, String state, Long storageId, Boolean displayVolume, String customId, long owner, String chainInfo); + Volume attachVolumeToVm(CloneVMCmd cmd, Long volumeId, Long deviceId); + /** * Extracts the volume to a particular location. * diff --git a/api/src/main/java/com/cloud/template/TemplateApiService.java b/api/src/main/java/com/cloud/template/TemplateApiService.java index bcda2bc2f2dc..fd45499ef6b4 100644 --- a/api/src/main/java/com/cloud/template/TemplateApiService.java +++ b/api/src/main/java/com/cloud/template/TemplateApiService.java @@ -20,7 +20,7 @@ import java.net.URISyntaxException; import java.util.List; -import com.cloud.exception.ResourceUnavailableException; +import com.cloud.storage.VolumeApiService; import org.apache.cloudstack.api.BaseListTemplateOrIsoPermissionsCmd; import org.apache.cloudstack.api.BaseUpdateTemplateOrIsoPermissionsCmd; import org.apache.cloudstack.api.command.user.iso.DeleteIsoCmd; @@ -104,9 +104,9 @@ public interface TemplateApiService { /** * create a template record for later usage of creating a real template by createPrivateTemplate * */ - VirtualMachineTemplate createPrivateTemplateRecord(CloneVMCmd cmd, Account templateOwner) throws ResourceAllocationException; + VirtualMachineTemplate createPrivateTemplateRecord(CloneVMCmd cmd, Account templateOwner, VolumeApiService serviceObj) throws ResourceAllocationException; - VirtualMachineTemplate createPrivateTemplateRecord(CloneVMCmd cmd) throws CloudRuntimeException; + VirtualMachineTemplate createPrivateTemplate(CloneVMCmd cmd) throws CloudRuntimeException; VirtualMachineTemplate createPrivateTemplateRecord(CreateTemplateCmd cmd, Account templateOwner) throws ResourceAllocationException; diff --git a/api/src/main/java/com/cloud/vm/UserVmService.java b/api/src/main/java/com/cloud/vm/UserVmService.java index 02b67c8e7695..da8c2373ca79 100644 --- a/api/src/main/java/com/cloud/vm/UserVmService.java +++ b/api/src/main/java/com/cloud/vm/UserVmService.java @@ -20,6 +20,8 @@ import java.util.Map; import java.util.Optional; +import com.cloud.storage.VolumeApiService; +import com.cloud.storage.snapshot.SnapshotApiService; import org.apache.cloudstack.api.BaseCmd.HTTPMethod; import org.apache.cloudstack.api.command.admin.vm.AssignVMCmd; import org.apache.cloudstack.api.command.admin.vm.RecoverVMCmd; @@ -94,9 +96,9 @@ public interface UserVmService { * - the command specifying vmId to be cloned * @return the VM if cloneVM operation is successful * */ - Optional cloneVirtualMachine(CloneVMCmd cmd) throws ResourceUnavailableException, ConcurrentOperationException; + Optional cloneVirtualMachine(CloneVMCmd cmd, VolumeApiService volumeService, SnapshotApiService snapshotService) throws ResourceUnavailableException, ConcurrentOperationException, InsufficientCapacityException, ResourceAllocationException; - void checkCloneCondition(CloneVMCmd cmd) throws ResourceUnavailableException, ConcurrentOperationException; + void checkCloneCondition(CloneVMCmd cmd) throws ResourceUnavailableException, ConcurrentOperationException, ResourceAllocationException; /** * Resets the password of a virtual machine. @@ -442,6 +444,9 @@ UserVm createAdvancedVirtualMachine(DataCenter zone, ServiceOffering serviceOffe UserVm createVirtualMachine(DeployVMCmd cmd) throws InsufficientCapacityException, ResourceUnavailableException, ConcurrentOperationException, StorageUnavailableException, ResourceAllocationException; + UserVm recordVirtualMachineToDB(CloneVMCmd cmd) throws InsufficientCapacityException, ResourceUnavailableException, ConcurrentOperationException, + StorageUnavailableException, ResourceAllocationException; + UserVm getUserVm(long vmId); /** diff --git a/api/src/main/java/org/apache/cloudstack/api/ApiConstants.java b/api/src/main/java/org/apache/cloudstack/api/ApiConstants.java index 28e4ba3bb30f..b060b5a21762 100644 --- a/api/src/main/java/org/apache/cloudstack/api/ApiConstants.java +++ b/api/src/main/java/org/apache/cloudstack/api/ApiConstants.java @@ -711,6 +711,7 @@ public class ApiConstants { public static final String UCS_BLADE_DN = "bladedn"; public static final String UCS_BLADE_ID = "bladeid"; public static final String VM_GUEST_IP = "vmguestip"; + public static final String HEALTHCHECK_FAILED = "healthchecksfailed"; public static final String HEALTHCHECK_RESPONSE_TIMEOUT = "responsetimeout"; public static final String HEALTHCHECK_INTERVAL_TIME = "intervaltime"; public static final String HEALTHCHECK_HEALTHY_THRESHOLD = "healthythreshold"; diff --git a/api/src/main/java/org/apache/cloudstack/api/BaseAsyncCreateCmd.java b/api/src/main/java/org/apache/cloudstack/api/BaseAsyncCreateCmd.java index 60c2a183ad33..10fee857dfcf 100644 --- a/api/src/main/java/org/apache/cloudstack/api/BaseAsyncCreateCmd.java +++ b/api/src/main/java/org/apache/cloudstack/api/BaseAsyncCreateCmd.java @@ -48,5 +48,4 @@ public String getCreateEventType() { public String getCreateEventDescription() { return null; } - } diff --git a/api/src/main/java/org/apache/cloudstack/api/command/admin/acl/BaseRolePermissionCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/admin/acl/BaseRolePermissionCmd.java index adf514fab0f8..a6c6e20369a7 100644 --- a/api/src/main/java/org/apache/cloudstack/api/command/admin/acl/BaseRolePermissionCmd.java +++ b/api/src/main/java/org/apache/cloudstack/api/command/admin/acl/BaseRolePermissionCmd.java @@ -19,7 +19,6 @@ import org.apache.cloudstack.acl.RolePermissionEntity.Permission; import org.apache.cloudstack.acl.Rule; -import org.apache.cloudstack.api.ApiArgValidator; import org.apache.cloudstack.api.ApiConstants; import org.apache.cloudstack.api.BaseCmd; import org.apache.cloudstack.api.Parameter; @@ -32,8 +31,7 @@ public abstract class BaseRolePermissionCmd extends BaseCmd { //////////////// API parameters ///////////////////// ///////////////////////////////////////////////////// - @Parameter(name = ApiConstants.RULE, type = CommandType.STRING, required = true, description = "The API name or wildcard rule such as list*", - validations = {ApiArgValidator.NotNullOrEmpty}) + @Parameter(name = ApiConstants.RULE, type = CommandType.STRING, required = true, description = "The API name or wildcard rule such as list*") private String rule; @Parameter(name = ApiConstants.PERMISSION, type = CommandType.STRING, required = true, description = "The rule permission, allow or deny. Default: deny.") diff --git a/api/src/main/java/org/apache/cloudstack/api/command/admin/acl/CreateRoleCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/admin/acl/CreateRoleCmd.java index e4ff3e3666c8..69d70273264a 100644 --- a/api/src/main/java/org/apache/cloudstack/api/command/admin/acl/CreateRoleCmd.java +++ b/api/src/main/java/org/apache/cloudstack/api/command/admin/acl/CreateRoleCmd.java @@ -26,7 +26,6 @@ import org.apache.cloudstack.api.BaseCmd; import org.apache.cloudstack.api.Parameter; import org.apache.cloudstack.api.ServerApiException; -import org.apache.cloudstack.api.ApiArgValidator; import org.apache.cloudstack.api.response.RoleResponse; import org.apache.cloudstack.context.CallContext; @@ -42,7 +41,7 @@ public class CreateRoleCmd extends RoleCmd { ///////////////////////////////////////////////////// @Parameter(name = ApiConstants.NAME, type = CommandType.STRING, required = true, - description = "Creates a role with this unique name", validations = {ApiArgValidator.NotNullOrEmpty}) + description = "Creates a role with this unique name") private String roleName; @Parameter(name = ApiConstants.ROLE_ID, type = CommandType.UUID, entityType = RoleResponse.class, diff --git a/api/src/main/java/org/apache/cloudstack/api/command/admin/acl/ImportRoleCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/admin/acl/ImportRoleCmd.java index c5d9c3f99e66..2ad07e7fe0cb 100644 --- a/api/src/main/java/org/apache/cloudstack/api/command/admin/acl/ImportRoleCmd.java +++ b/api/src/main/java/org/apache/cloudstack/api/command/admin/acl/ImportRoleCmd.java @@ -30,7 +30,6 @@ import org.apache.cloudstack.acl.RoleType; import org.apache.cloudstack.acl.Rule; import org.apache.cloudstack.api.APICommand; -import org.apache.cloudstack.api.ApiArgValidator; import org.apache.cloudstack.api.ApiConstants; import org.apache.cloudstack.api.ApiErrorCode; import org.apache.cloudstack.api.ApiServerService; @@ -56,7 +55,7 @@ public class ImportRoleCmd extends RoleCmd { ///////////////////////////////////////////////////// @Parameter(name = ApiConstants.NAME, type = CommandType.STRING, required = true, - description = "Creates a role with this unique name", validations = {ApiArgValidator.NotNullOrEmpty}) + description = "Creates a role with this unique name") private String roleName; @Parameter(name = ApiConstants.RULES, type = CommandType.MAP, required = true, diff --git a/api/src/main/java/org/apache/cloudstack/api/command/admin/acl/project/CreateProjectRoleCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/admin/acl/project/CreateProjectRoleCmd.java index a3fa14955c15..d3adbc88fd5e 100644 --- a/api/src/main/java/org/apache/cloudstack/api/command/admin/acl/project/CreateProjectRoleCmd.java +++ b/api/src/main/java/org/apache/cloudstack/api/command/admin/acl/project/CreateProjectRoleCmd.java @@ -20,7 +20,6 @@ import org.apache.cloudstack.acl.ProjectRole; import org.apache.cloudstack.acl.RoleType; import org.apache.cloudstack.api.APICommand; -import org.apache.cloudstack.api.ApiArgValidator; import org.apache.cloudstack.api.ApiConstants; import org.apache.cloudstack.api.ApiErrorCode; import org.apache.cloudstack.api.BaseCmd; @@ -42,7 +41,7 @@ public class CreateProjectRoleCmd extends ProjectRoleCmd { ///////////////////////////////////////////////////// @Parameter(name = ApiConstants.NAME, type = BaseCmd.CommandType.STRING, required = true, - description = "creates a project role with this unique name", validations = {ApiArgValidator.NotNullOrEmpty}) + description = "creates a project role with this unique name") private String projectRoleName; ///////////////////////////////////////////////////// diff --git a/api/src/main/java/org/apache/cloudstack/api/command/admin/acl/project/CreateProjectRolePermissionCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/admin/acl/project/CreateProjectRolePermissionCmd.java index f4fbcf4475a3..7b04764b6a09 100644 --- a/api/src/main/java/org/apache/cloudstack/api/command/admin/acl/project/CreateProjectRolePermissionCmd.java +++ b/api/src/main/java/org/apache/cloudstack/api/command/admin/acl/project/CreateProjectRolePermissionCmd.java @@ -47,7 +47,7 @@ public class CreateProjectRolePermissionCmd extends BaseRolePermissionCmd { private Long projectRoleId; @Parameter(name = ApiConstants.PROJECT_ID, type = CommandType.UUID, required = true, entityType = ProjectResponse.class, - description = "ID of project where project role permission is to be created", validations = {ApiArgValidator.NotNullOrEmpty}) + description = "ID of project where project role permission is to be created") private Long projectId; ///////////////////////////////////////////////////// diff --git a/api/src/main/java/org/apache/cloudstack/api/command/admin/acl/project/ProjectRoleCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/admin/acl/project/ProjectRoleCmd.java index f43cd3d99853..09c3132651a0 100644 --- a/api/src/main/java/org/apache/cloudstack/api/command/admin/acl/project/ProjectRoleCmd.java +++ b/api/src/main/java/org/apache/cloudstack/api/command/admin/acl/project/ProjectRoleCmd.java @@ -18,7 +18,6 @@ package org.apache.cloudstack.api.command.admin.acl.project; import org.apache.cloudstack.acl.ProjectRole; -import org.apache.cloudstack.api.ApiArgValidator; import org.apache.cloudstack.api.ApiConstants; import org.apache.cloudstack.api.BaseCmd; import org.apache.cloudstack.api.Parameter; @@ -31,7 +30,7 @@ public abstract class ProjectRoleCmd extends BaseCmd { //////////////// API parameters ///////////////////// ///////////////////////////////////////////////////// @Parameter(name = ApiConstants.PROJECT_ID, type = CommandType.UUID, required = true, entityType = ProjectResponse.class, - description = "ID of project where role is being created", validations = {ApiArgValidator.NotNullOrEmpty}) + description = "ID of project where role is being created") private Long projectId; @Parameter(name = ApiConstants.DESCRIPTION, type = BaseCmd.CommandType.STRING, description = "The description of the Project role") diff --git a/api/src/main/java/org/apache/cloudstack/api/command/admin/acl/project/UpdateProjectRolePermissionCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/admin/acl/project/UpdateProjectRolePermissionCmd.java index b20dc7b5be2b..6f02962d683a 100644 --- a/api/src/main/java/org/apache/cloudstack/api/command/admin/acl/project/UpdateProjectRolePermissionCmd.java +++ b/api/src/main/java/org/apache/cloudstack/api/command/admin/acl/project/UpdateProjectRolePermissionCmd.java @@ -53,7 +53,7 @@ public class UpdateProjectRolePermissionCmd extends BaseCmd { private Long projectRoleId; @Parameter(name = ApiConstants.PROJECT_ID, type = CommandType.UUID, required = true, entityType = ProjectResponse.class, - description = "ID of project where project role permission is to be updated", validations = {ApiArgValidator.NotNullOrEmpty}) + description = "ID of project where project role permission is to be updated") private Long projectId; @Parameter(name = ApiConstants.RULE_ORDER, type = CommandType.LIST, collectionType = CommandType.UUID, entityType = ProjectRolePermissionResponse.class, diff --git a/api/src/main/java/org/apache/cloudstack/api/command/admin/diagnostics/RunDiagnosticsCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/admin/diagnostics/RunDiagnosticsCmd.java index 03d603923e05..d7f3b3933107 100644 --- a/api/src/main/java/org/apache/cloudstack/api/command/admin/diagnostics/RunDiagnosticsCmd.java +++ b/api/src/main/java/org/apache/cloudstack/api/command/admin/diagnostics/RunDiagnosticsCmd.java @@ -70,12 +70,10 @@ public class RunDiagnosticsCmd extends BaseAsyncCmd { private Long id; @Parameter(name = ApiConstants.IP_ADDRESS, type = CommandType.STRING, required = true, - validations = {ApiArgValidator.NotNullOrEmpty}, description = "The IP/Domain address to test connection to") private String address; @Parameter(name = ApiConstants.TYPE, type = CommandType.STRING, required = true, - validations = {ApiArgValidator.NotNullOrEmpty}, description = "The system VM diagnostics type valid options are: ping, traceroute, arping") private String type; diff --git a/api/src/main/java/org/apache/cloudstack/api/command/admin/ha/ConfigureHAForHostCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/admin/ha/ConfigureHAForHostCmd.java index f85dbb235045..2fe764207814 100644 --- a/api/src/main/java/org/apache/cloudstack/api/command/admin/ha/ConfigureHAForHostCmd.java +++ b/api/src/main/java/org/apache/cloudstack/api/command/admin/ha/ConfigureHAForHostCmd.java @@ -61,7 +61,7 @@ public final class ConfigureHAForHostCmd extends BaseAsyncCmd { private Long hostId; @Parameter(name = ApiConstants.PROVIDER, type = CommandType.STRING, - description = "HA provider", required = true, validations = {ApiArgValidator.NotNullOrEmpty}) + description = "HA provider", required = true) private String haProvider; ///////////////////////////////////////////////////// diff --git a/api/src/main/java/org/apache/cloudstack/api/command/admin/ha/ListHostHAProvidersCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/admin/ha/ListHostHAProvidersCmd.java index 64b9a6a8e5cd..58f227cca137 100644 --- a/api/src/main/java/org/apache/cloudstack/api/command/admin/ha/ListHostHAProvidersCmd.java +++ b/api/src/main/java/org/apache/cloudstack/api/command/admin/ha/ListHostHAProvidersCmd.java @@ -26,7 +26,6 @@ import com.google.common.base.Enums; import org.apache.cloudstack.acl.RoleType; import org.apache.cloudstack.api.APICommand; -import org.apache.cloudstack.api.ApiArgValidator; import org.apache.cloudstack.api.ApiConstants; import org.apache.cloudstack.api.ApiErrorCode; import org.apache.cloudstack.api.BaseCmd; @@ -57,7 +56,7 @@ public final class ListHostHAProvidersCmd extends BaseCmd { ///////////////////////////////////////////////////// @Parameter(name = ApiConstants.HYPERVISOR, type = CommandType.STRING, required = true, - description = "Hypervisor type of the resource", validations = {ApiArgValidator.NotNullOrEmpty}) + description = "Hypervisor type of the resource") private String hypervisorType; ///////////////////////////////////////////////////// diff --git a/api/src/main/java/org/apache/cloudstack/api/command/admin/network/CreateManagementNetworkIpRangeCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/admin/network/CreateManagementNetworkIpRangeCmd.java index f7957469cd13..3d4013c8bc70 100644 --- a/api/src/main/java/org/apache/cloudstack/api/command/admin/network/CreateManagementNetworkIpRangeCmd.java +++ b/api/src/main/java/org/apache/cloudstack/api/command/admin/network/CreateManagementNetworkIpRangeCmd.java @@ -62,22 +62,19 @@ public class CreateManagementNetworkIpRangeCmd extends BaseAsyncCmd { @Parameter(name = ApiConstants.GATEWAY, type = CommandType.STRING, required = true, - description = "The gateway for the management network.", - validations = {ApiArgValidator.NotNullOrEmpty}) + description = "The gateway for the management network.") private String gateway; @Parameter(name = ApiConstants.NETMASK, type = CommandType.STRING, required = true, - description = "The netmask for the management network.", - validations = {ApiArgValidator.NotNullOrEmpty}) + description = "The netmask for the management network.") private String netmask; @Parameter(name = ApiConstants.START_IP, type = CommandType.STRING, required = true, - description = "The starting IP address.", - validations = {ApiArgValidator.NotNullOrEmpty}) + description = "The starting IP address.") private String startIp; @Parameter(name = ApiConstants.END_IP, diff --git a/api/src/main/java/org/apache/cloudstack/api/command/admin/network/CreateNetworkOfferingCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/admin/network/CreateNetworkOfferingCmd.java index cd003a740591..7172633f5f92 100644 --- a/api/src/main/java/org/apache/cloudstack/api/command/admin/network/CreateNetworkOfferingCmd.java +++ b/api/src/main/java/org/apache/cloudstack/api/command/admin/network/CreateNetworkOfferingCmd.java @@ -94,7 +94,6 @@ public class CreateNetworkOfferingCmd extends BaseCmd { @Parameter(name = ApiConstants.SUPPORTED_SERVICES, type = CommandType.LIST, - required = true, collectionType = CommandType.STRING, description = "services supported by the network offering") private List supportedServices; @@ -205,7 +204,7 @@ public Long getServiceOfferingId() { } public List getSupportedServices() { - return supportedServices; + return supportedServices == null ? new ArrayList() : supportedServices; } public String getGuestIpType() { diff --git a/api/src/main/java/org/apache/cloudstack/api/command/admin/network/DeleteManagementNetworkIpRangeCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/admin/network/DeleteManagementNetworkIpRangeCmd.java index d6481846f431..ae7a0f70473c 100644 --- a/api/src/main/java/org/apache/cloudstack/api/command/admin/network/DeleteManagementNetworkIpRangeCmd.java +++ b/api/src/main/java/org/apache/cloudstack/api/command/admin/network/DeleteManagementNetworkIpRangeCmd.java @@ -61,15 +61,13 @@ public class DeleteManagementNetworkIpRangeCmd extends BaseAsyncCmd { @Parameter(name = ApiConstants.START_IP, type = CommandType.STRING, required = true, - description = "The starting IP address.", - validations = ApiArgValidator.NotNullOrEmpty) + description = "The starting IP address.") private String startIp; @Parameter(name = ApiConstants.END_IP, type = CommandType.STRING, required = true, - description = "The ending IP address.", - validations = ApiArgValidator.NotNullOrEmpty) + description = "The ending IP address.") private String endIp; @Parameter(name = ApiConstants.VLAN, diff --git a/api/src/main/java/org/apache/cloudstack/api/command/admin/outofbandmanagement/IssueOutOfBandManagementPowerActionCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/admin/outofbandmanagement/IssueOutOfBandManagementPowerActionCmd.java index 7593a3cbc522..49eab1f176c6 100644 --- a/api/src/main/java/org/apache/cloudstack/api/command/admin/outofbandmanagement/IssueOutOfBandManagementPowerActionCmd.java +++ b/api/src/main/java/org/apache/cloudstack/api/command/admin/outofbandmanagement/IssueOutOfBandManagementPowerActionCmd.java @@ -62,7 +62,7 @@ public class IssueOutOfBandManagementPowerActionCmd extends BaseAsyncCmd { private Long actionTimeout; @Parameter(name = ApiConstants.ACTION, type = CommandType.STRING, required = true, - validations = {ApiArgValidator.NotNullOrEmpty}, description = "out-of-band management power actions, valid actions are: ON, OFF, CYCLE, RESET, SOFT, STATUS") + description = "out-of-band management power actions, valid actions are: ON, OFF, CYCLE, RESET, SOFT, STATUS") private String powerAction; ///////////////////////////////////////////////////// diff --git a/api/src/main/java/org/apache/cloudstack/api/command/admin/router/ListRoutersCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/admin/router/ListRoutersCmd.java index 4fabcf5df768..3c9b684c0c86 100644 --- a/api/src/main/java/org/apache/cloudstack/api/command/admin/router/ListRoutersCmd.java +++ b/api/src/main/java/org/apache/cloudstack/api/command/admin/router/ListRoutersCmd.java @@ -81,6 +81,10 @@ public class ListRoutersCmd extends BaseListProjectAndAccountResourcesCmd { @Parameter(name = ApiConstants.VERSION, type = CommandType.STRING, description = "list virtual router elements by version") private String version; + @Parameter(name = ApiConstants.HEALTHCHECK_FAILED, type = CommandType.BOOLEAN, since = "4.16", + description = "if this parameter is passed, list only routers by health check results") + private Boolean healthCheckFailed; + @Parameter(name = ApiConstants.FETCH_ROUTER_HEALTH_CHECK_RESULTS, type = CommandType.BOOLEAN, since = "4.14", description = "if true is passed for this parameter, also fetch last executed health check results for the router. Default is false") private Boolean fetchHealthCheckResults; @@ -137,6 +141,10 @@ public String getRole() { return Role.VIRTUAL_ROUTER.toString(); } + public Boolean isHealthCheckFailed() { + return healthCheckFailed; + } + public boolean shouldFetchHealthCheckResults() { return BooleanUtils.isTrue(fetchHealthCheckResults); } diff --git a/api/src/main/java/org/apache/cloudstack/api/command/user/firewall/CreateFirewallRuleCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/user/firewall/CreateFirewallRuleCmd.java index ea5657cf9657..e0310a184122 100644 --- a/api/src/main/java/org/apache/cloudstack/api/command/user/firewall/CreateFirewallRuleCmd.java +++ b/api/src/main/java/org/apache/cloudstack/api/command/user/firewall/CreateFirewallRuleCmd.java @@ -73,7 +73,7 @@ public class CreateFirewallRuleCmd extends BaseAsyncCreateCmd implements Firewal @Parameter(name = ApiConstants.END_PORT, type = CommandType.INTEGER, description = "the ending port of firewall rule") private Integer publicEndPort; - @Parameter(name = ApiConstants.CIDR_LIST, type = CommandType.LIST, collectionType = CommandType.STRING, description = "the CIDR list to forward traffic from. Multiple entries must be separated by a single comma character (,).") + @Parameter(name = ApiConstants.CIDR_LIST, type = CommandType.LIST, collectionType = CommandType.STRING, description = "the CIDR list to forward traffic from. Multiple entries must be separated by a single comma character (,). This parameter is deprecated. Do not use.") private List cidrlist; @Parameter(name = ApiConstants.ICMP_TYPE, type = CommandType.INTEGER, description = "type of the ICMP message being sent") diff --git a/api/src/main/java/org/apache/cloudstack/api/command/user/firewall/CreatePortForwardingRuleCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/user/firewall/CreatePortForwardingRuleCmd.java index c569afc7460d..f3c9e590851d 100644 --- a/api/src/main/java/org/apache/cloudstack/api/command/user/firewall/CreatePortForwardingRuleCmd.java +++ b/api/src/main/java/org/apache/cloudstack/api/command/user/firewall/CreatePortForwardingRuleCmd.java @@ -108,7 +108,7 @@ public class CreatePortForwardingRuleCmd extends BaseAsyncCreateCmd implements P description = "the ID of the virtual machine for the port forwarding rule") private Long virtualMachineId; - @Parameter(name = ApiConstants.CIDR_LIST, type = CommandType.LIST, collectionType = CommandType.STRING, description = "the cidr list to forward traffic from. Multiple entries must be separated by a single comma character (,).") + @Parameter(name = ApiConstants.CIDR_LIST, type = CommandType.LIST, collectionType = CommandType.STRING, description = "the cidr list to forward traffic from. Multiple entries must be separated by a single comma character (,). This parameter is deprecated. Do not use.") private List cidrlist; @Parameter(name = ApiConstants.OPEN_FIREWALL, type = CommandType.BOOLEAN, description = "if true, firewall rule for source/end public port is automatically created; " diff --git a/api/src/main/java/org/apache/cloudstack/api/command/user/network/MoveNetworkAclItemCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/user/network/MoveNetworkAclItemCmd.java index 0343e5012e4a..acc7fdff90f2 100644 --- a/api/src/main/java/org/apache/cloudstack/api/command/user/network/MoveNetworkAclItemCmd.java +++ b/api/src/main/java/org/apache/cloudstack/api/command/user/network/MoveNetworkAclItemCmd.java @@ -43,7 +43,7 @@ public class MoveNetworkAclItemCmd extends BaseAsyncCustomIdCmd { @Parameter(name = ApiConstants.NEXT_ACL_RULE_ID, type = CommandType.STRING, description = "The ID of the rule that is right after the new position where the rule being moved is going to be placed. This value can be 'NULL' if the rule is being moved to the last position of the network ACL list.") private String nextAclRuleUuid; - @Parameter(name = ApiConstants.MOVE_ACL_CONSISTENCY_HASH, type = CommandType.STRING, description = "Md5 hash used to check the consistency of the ACL rule list before applying the ACL rule move. This check is useful to manage concurrency problems that may happen when multiple users are editing the same ACL rule listing. The parameter is not required. Therefore, if the user does not send it, he/she is assuming the risk of moving ACL rules without checking the consistency of the access control list before executing the move. We use MD5 hash function on a String that is composed of all UUIDs of the ACL rules in concatenated in their respective order (order defined via 'number' field).") + @Parameter(name = ApiConstants.MOVE_ACL_CONSISTENCY_HASH, type = CommandType.STRING, description = "Md5 hash used to check the consistency of the ACL rule list before applying the ACL rule move. This check is useful to manage concurrency problems that may happen when multiple users are editing the same ACL rule listing. The parameter is not required. Therefore, if the user does not send it, they assume the risk of moving ACL rules without checking the consistency of the access control list before executing the move. We use MD5 hash function on a String that is composed of all UUIDs of the ACL rules in concatenated in their respective order (order defined via 'number' field).") private String aclConsistencyHash; @Override diff --git a/api/src/main/java/org/apache/cloudstack/api/command/user/project/CreateProjectCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/user/project/CreateProjectCmd.java index 64de9a706420..00fff78622ec 100644 --- a/api/src/main/java/org/apache/cloudstack/api/command/user/project/CreateProjectCmd.java +++ b/api/src/main/java/org/apache/cloudstack/api/command/user/project/CreateProjectCmd.java @@ -17,7 +17,6 @@ package org.apache.cloudstack.api.command.user.project; import org.apache.cloudstack.api.APICommand; -import org.apache.cloudstack.api.ApiArgValidator; import org.apache.cloudstack.api.ApiConstants; import org.apache.cloudstack.api.ApiErrorCode; import org.apache.cloudstack.api.BaseAsyncCreateCmd; @@ -60,7 +59,7 @@ public class CreateProjectCmd extends BaseAsyncCreateCmd { @Parameter(name = ApiConstants.ACCOUNT_ID, type = CommandType.UUID, entityType = AccountResponse.class, description = "ID of the account owning a project") private Long accountId; - @Parameter(name = ApiConstants.NAME, type = CommandType.STRING, required = true, validations = ApiArgValidator.NotNullOrEmpty, description = "name of the project") + @Parameter(name = ApiConstants.NAME, type = CommandType.STRING, required = true, description = "name of the project") private String name; @Parameter(name = ApiConstants.DISPLAY_TEXT, type = CommandType.STRING, required = true, description = "display text of the project") diff --git a/api/src/main/java/org/apache/cloudstack/api/command/user/resource/ListDetailOptionsCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/user/resource/ListDetailOptionsCmd.java index e53754c099ca..5007e63f5c68 100644 --- a/api/src/main/java/org/apache/cloudstack/api/command/user/resource/ListDetailOptionsCmd.java +++ b/api/src/main/java/org/apache/cloudstack/api/command/user/resource/ListDetailOptionsCmd.java @@ -18,7 +18,6 @@ import org.apache.cloudstack.acl.RoleType; import org.apache.cloudstack.api.APICommand; -import org.apache.cloudstack.api.ApiArgValidator; import org.apache.cloudstack.api.ApiConstants; import org.apache.cloudstack.api.BaseCmd; import org.apache.cloudstack.api.Parameter; @@ -43,9 +42,7 @@ public class ListDetailOptionsCmd extends BaseCmd { ///////////////////////////////////////////////////// @Parameter(name = ApiConstants.RESOURCE_TYPE, type = CommandType.STRING, required = true, - description = "the resource type such as UserVm, Template etc.", - validations = {ApiArgValidator.NotNullOrEmpty} - ) + description = "the resource type such as UserVm, Template etc.") private String resourceType; @Parameter(name = ApiConstants.RESOURCE_ID, type = CommandType.STRING, diff --git a/api/src/main/java/org/apache/cloudstack/api/command/user/vm/CloneVMCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/user/vm/CloneVMCmd.java index a740c6031baf..136f5b9ce087 100644 --- a/api/src/main/java/org/apache/cloudstack/api/command/user/vm/CloneVMCmd.java +++ b/api/src/main/java/org/apache/cloudstack/api/command/user/vm/CloneVMCmd.java @@ -2,17 +2,28 @@ import com.cloud.event.EventTypes; import com.cloud.exception.ConcurrentOperationException; +import com.cloud.exception.InsufficientCapacityException; +import com.cloud.exception.InvalidParameterValueException; import com.cloud.exception.ResourceAllocationException; import com.cloud.exception.ResourceUnavailableException; import com.cloud.template.VirtualMachineTemplate; import com.cloud.user.Account; import com.cloud.uservm.UserVm; -import com.cloud.utils.exception.CloudRuntimeException; import com.cloud.vm.VirtualMachine; import org.apache.cloudstack.acl.SecurityChecker.AccessType; -import org.apache.cloudstack.api.*; +import org.apache.cloudstack.api.ACL; +import org.apache.cloudstack.api.APICommand; +import org.apache.cloudstack.api.ApiCommandJobType; +import org.apache.cloudstack.api.ApiConstants; +import org.apache.cloudstack.api.ApiErrorCode; +import org.apache.cloudstack.api.BaseAsyncCreateCustomIdCmd; +import org.apache.cloudstack.api.Parameter; +import org.apache.cloudstack.api.ResponseObject; +import org.apache.cloudstack.api.ServerApiException; import org.apache.cloudstack.api.command.user.UserCmd; +import org.apache.cloudstack.api.response.DomainResponse; import org.apache.cloudstack.api.response.UserVmResponse; +//import org.apache.cloudstack.context.CallContext; import org.apache.cloudstack.context.CallContext; import org.apache.log4j.Logger; @@ -32,6 +43,25 @@ public class CloneVMCmd extends BaseAsyncCreateCustomIdCmd implements UserCmd { required = true, description = "The ID of the virtual machine") private Long id; + //Owner information + @Parameter(name = ApiConstants.ACCOUNT, type = CommandType.STRING, description = "an optional account for the virtual machine. Must be used with domainId.") + private String accountName; + + @Parameter(name = ApiConstants.DOMAIN_ID, type = CommandType.UUID, entityType = DomainResponse.class, description = "an optional domainId for the virtual machine. If the account parameter is used, domainId must also be used.") + private Long domainId; + + private Long temporaryTemlateId; + + private Long temporarySnapShotId; + + public String getAccountName() { + return accountName; + } + + public Long getDomainId() { + return domainId; + } + public Long getId() { return this.id; } @@ -50,19 +80,57 @@ public String getEventDescription() { return "Cloning user VM: " + this._uuidMgr.getUuid(VirtualMachine.class, getId()); } + public Long getTemporaryTemlateId() { + return this.temporaryTemlateId; + } + + public void setTemporarySnapShotId(Long snapshotId) { + this.temporarySnapShotId = snapshotId; + } + + public Long getTemporarySnapShotId() { + return temporarySnapShotId; + } + + + public void setTemporaryTemlateId(long tempId) { + this.temporaryTemlateId = tempId; + } + @Override public void create() throws ResourceAllocationException { - VirtualMachineTemplate template = null; try { _userVmService.checkCloneCondition(this); - } catch (ResourceUnavailableException e) { + VirtualMachineTemplate template = _templateService.createPrivateTemplateRecord(this, _accountService.getAccount(getEntityOwnerId()), _volumeService); + if (template == null) { + throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "failed to create a template to db"); + } + s_logger.info("The template id recorded is: " + template.getId()); + setTemporaryTemlateId(template.getId()); + _templateService.createPrivateTemplate(this); + _snapshotService.deleteSnapshot(getTemporarySnapShotId()); + UserVm vmRecord = _userVmService.recordVirtualMachineToDB(this); + if (vmRecord == null) { + throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "unable to record a new VM to db!"); + } + setEntityId(vmRecord.getId()); + setEntityUuid(vmRecord.getUuid()); + } catch (ResourceUnavailableException | InsufficientCapacityException e) { s_logger.warn("Exception: ", e); throw new ServerApiException(ApiErrorCode.RESOURCE_UNAVAILABLE_ERROR, e.getMessage()); + } catch (InvalidParameterValueException e) { + s_logger.warn("Exception: ", e); + throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, e.getMessage()); + } finally { + if (getTemporaryTemlateId() != null) { + // TODO: delete template in the service + s_logger.warn("clearing the temporary template: " + getTemporaryTemlateId()); + } } - template = _templateService.createPrivateTemplateRecord(this, _accountService.getAccount(getEntityOwnerId())); - if (template == null) { - throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Unable to generate a template during clone!"); - } + } + + public boolean isPublic() { + return false; } public String getVMName() { @@ -77,8 +145,9 @@ public String getTemplateName() { public void execute() { Optional result; try { - CallContext.current().setEventDetails("Vm Id for full clone: " + getId()); - result = _userVmService.cloneVirtualMachine(this); + CallContext.current().setEventDetails("Vm Id for full clone: " + getEntityId()); + s_logger.info("starting actual VM id: " + getEntityId()); + result = _userVmService.cloneVirtualMachine(this, _volumeService, _snapshotService); } catch (ResourceUnavailableException ex) { s_logger.warn("Exception: ", ex); throw new ServerApiException(ApiErrorCode.RESOURCE_UNAVAILABLE_ERROR, ex.getMessage()); @@ -86,9 +155,13 @@ public void execute() { s_logger.warn("Exception: ", ex); throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, ex.getMessage()); } + catch (ResourceAllocationException | InsufficientCapacityException ex) { + s_logger.warn("Exception: ", ex); + throw new ServerApiException(ApiErrorCode.RESOURCE_ALLOCATION_ERROR, ex.getMessage()); + } result.ifPresentOrElse((userVm)-> { - UserVmResponse response = _responseGenerator.createUserVmResponse(getResponseView(), "virtualmachine", userVm).get(0); - response.setResponseName("test_clone"); + UserVmResponse response = _responseGenerator.createUserVmResponse(getResponseView(), "virtualmachine", result.get()).get(0); + response.setResponseName("full_clone"); setResponseObject(response); }, ()-> { throw new ServerApiException(ApiErrorCode.INSUFFICIENT_CAPACITY_ERROR, "failed to clone VM: " + getId()); diff --git a/api/src/main/java/org/apache/cloudstack/api/response/DomainRouterResponse.java b/api/src/main/java/org/apache/cloudstack/api/response/DomainRouterResponse.java index 0a4a456aed2a..563d6a9f961c 100644 --- a/api/src/main/java/org/apache/cloudstack/api/response/DomainRouterResponse.java +++ b/api/src/main/java/org/apache/cloudstack/api/response/DomainRouterResponse.java @@ -225,7 +225,7 @@ public class DomainRouterResponse extends BaseResponse implements ControlledView @Param(description = "true if the router template requires upgrader") private boolean requiresUpgrade; - @SerializedName("healthchecksfailed") + @SerializedName(ApiConstants.HEALTHCHECK_FAILED) @Param(description = "true if any health checks had failed") private boolean healthChecksFailed; diff --git a/debian/cloudstack-management.postinst b/debian/cloudstack-management.postinst index 2cc3b9b7b533..e3dd52821a59 100755 --- a/debian/cloudstack-management.postinst +++ b/debian/cloudstack-management.postinst @@ -63,6 +63,14 @@ if [ "$1" = configure ]; then grep -s -q "db.cloud.driver=jdbc:mysql" ${CONFDIR}/${DBPROPS} || sed -i -e "\$adb.cloud.driver=jdbc:mysql" ${CONFDIR}/${DBPROPS} grep -s -q "db.usage.driver=jdbc:mysql" ${CONFDIR}/${DBPROPS} || sed -i -e "\$adb.usage.driver=jdbc:mysql" ${CONFDIR}/${DBPROPS} grep -s -q "db.simulator.driver=jdbc:mysql" ${CONFDIR}/${DBPROPS} || sed -i -e "\$adb.simulator.driver=jdbc:mysql" ${CONFDIR}/${DBPROPS} + + # Update DB properties having master and slave(s), with source and replica(s) respectively (for inclusiveness) + grep -s -q "^db.cloud.slaves=" ${CONFDIR}/${DBPROPS} && sed -i "s/^db.cloud.slaves=/db.cloud.replicas=/g" ${CONFDIR}/${DBPROPS} + grep -s -q "^db.cloud.secondsBeforeRetryMaster=" ${CONFDIR}/${DBPROPS} && sed -i "s/^db.cloud.secondsBeforeRetryMaster=/db.cloud.secondsBeforeRetrySource=/g" ${CONFDIR}/${DBPROPS} + grep -s -q "^db.cloud.queriesBeforeRetryMaster=" ${CONFDIR}/${DBPROPS} && sed -i "s/^db.cloud.queriesBeforeRetryMaster=/db.cloud.queriesBeforeRetrySource=/g" ${CONFDIR}/${DBPROPS} + grep -s -q "^db.usage.slaves=" ${CONFDIR}/${DBPROPS} && sed -i "s/^db.usage.slaves=/db.usage.replicas=/g" ${CONFDIR}/${DBPROPS} + grep -s -q "^db.usage.secondsBeforeRetryMaster=" ${CONFDIR}/${DBPROPS} && sed -i "s/^db.usage.secondsBeforeRetryMaster=/db.usage.secondsBeforeRetrySource=/g" ${CONFDIR}/${DBPROPS} + grep -s -q "^db.usage.queriesBeforeRetryMaster=" ${CONFDIR}/${DBPROPS} && sed -i "s/^db.usage.queriesBeforeRetryMaster=/db.usage.queriesBeforeRetrySource=/g" ${CONFDIR}/${DBPROPS} fi #DEBHELPER# diff --git a/engine/components-api/src/main/java/com/cloud/storage/StorageManager.java b/engine/components-api/src/main/java/com/cloud/storage/StorageManager.java index db41a2f099ac..b9a45f0dcdc3 100644 --- a/engine/components-api/src/main/java/com/cloud/storage/StorageManager.java +++ b/engine/components-api/src/main/java/com/cloud/storage/StorageManager.java @@ -19,7 +19,6 @@ import java.math.BigDecimal; import java.util.List; -import com.cloud.agent.api.ModifyStoragePoolAnswer; import org.apache.cloudstack.engine.subsystem.api.storage.DataStore; import org.apache.cloudstack.engine.subsystem.api.storage.HypervisorHostListener; import org.apache.cloudstack.framework.config.ConfigKey; @@ -27,6 +26,7 @@ import com.cloud.agent.api.Answer; import com.cloud.agent.api.Command; +import com.cloud.agent.api.ModifyStoragePoolAnswer; import com.cloud.agent.api.StoragePoolInfo; import com.cloud.agent.api.to.DataTO; import com.cloud.agent.api.to.DiskTO; @@ -124,7 +124,16 @@ public interface StorageManager extends StorageService { "Storage", "60", "Timeout (in secs) for the storage pool client connection timeout (for managed pools). Currently only supported for PowerFlex.", - true, + false, + ConfigKey.Scope.StoragePool, + null); + + ConfigKey STORAGE_POOL_CLIENT_MAX_CONNECTIONS = new ConfigKey<>(Integer.class, + "storage.pool.client.max.connections", + "Storage", + "100", + "Maximum connections for the storage pool client (for managed pools). Currently only supported for PowerFlex.", + false, ConfigKey.Scope.StoragePool, null); @@ -243,7 +252,7 @@ public interface StorageManager extends StorageService { boolean storagePoolCompatibleWithVolumePool(StoragePool pool, Volume volume); - boolean isStoragePoolComplaintWithStoragePolicy(List volumes, StoragePool pool) throws StorageUnavailableException; + boolean isStoragePoolCompliantWithStoragePolicy(List volumes, StoragePool pool) throws StorageUnavailableException; boolean registerHostListener(String providerUuid, HypervisorHostListener listener); diff --git a/engine/components-api/src/main/java/com/cloud/template/TemplateManager.java b/engine/components-api/src/main/java/com/cloud/template/TemplateManager.java index 35fed56ac8e5..7207a96a9efa 100644 --- a/engine/components-api/src/main/java/com/cloud/template/TemplateManager.java +++ b/engine/components-api/src/main/java/com/cloud/template/TemplateManager.java @@ -30,7 +30,6 @@ import com.cloud.exception.ResourceAllocationException; import com.cloud.exception.StorageUnavailableException; import com.cloud.storage.StoragePool; -import com.cloud.storage.VMTemplateHostVO; import com.cloud.storage.VMTemplateStoragePoolVO; import com.cloud.storage.VMTemplateVO; import com.cloud.utils.Pair; @@ -102,8 +101,6 @@ public interface TemplateManager { */ void evictTemplateFromStoragePool(VMTemplateStoragePoolVO templatePoolVO); - boolean templateIsDeleteable(VMTemplateHostVO templateHostRef); - boolean templateIsDeleteable(long templateId); Pair getAbsoluteIsoPath(long templateId, long dataCenterId); diff --git a/engine/orchestration/src/main/java/com/cloud/agent/manager/ClusteredAgentManagerImpl.java b/engine/orchestration/src/main/java/com/cloud/agent/manager/ClusteredAgentManagerImpl.java index 7a16971ee71d..fa24df290d34 100644 --- a/engine/orchestration/src/main/java/com/cloud/agent/manager/ClusteredAgentManagerImpl.java +++ b/engine/orchestration/src/main/java/com/cloud/agent/manager/ClusteredAgentManagerImpl.java @@ -286,7 +286,7 @@ protected AgentAttache createAttacheForConnect(final HostVO host, final Link lin @Override protected AgentAttache createAttacheForDirectConnect(final Host host, final ServerResource resource) { - s_logger.debug("create ClusteredDirectAgentAttache for " + host.getId()); + s_logger.debug(String.format("Create ClusteredDirectAgentAttache for %s.", host)); final DirectAgentAttache attache = new ClusteredDirectAgentAttache(this, host.getId(), host.getName(), _nodeId, resource, host.isInMaintenanceStates()); AgentAttache old = null; synchronized (_agents) { diff --git a/engine/orchestration/src/main/java/com/cloud/vm/VirtualMachineManagerImpl.java b/engine/orchestration/src/main/java/com/cloud/vm/VirtualMachineManagerImpl.java index e37884275f83..eca0852060d8 100755 --- a/engine/orchestration/src/main/java/com/cloud/vm/VirtualMachineManagerImpl.java +++ b/engine/orchestration/src/main/java/com/cloud/vm/VirtualMachineManagerImpl.java @@ -881,8 +881,9 @@ public Ternary doInTransaction(final } if (state != State.Stopped) { - s_logger.debug("VM " + vm + " is not in a state to be started: " + state); - return null; + String msg = String.format("Cannot start %s in %s state", vm, state); + s_logger.warn(msg); + throw new CloudRuntimeException(msg); } } @@ -2409,6 +2410,9 @@ private void markVolumesInPool(VMInstanceVO vm, Answer[] hypervisorMigrationResu } volume.setPath(result.getPath()); volume.setPoolId(pool.getId()); + if (result.getChainInfo() != null) { + volume.setChainInfo(result.getChainInfo()); + } _volsDao.update(volume.getId(), volume); } } @@ -4342,19 +4346,25 @@ private void orchestrateMigrateForScale(final String vmUuid, final long srcHostI throws ResourceUnavailableException, ConcurrentOperationException { VMInstanceVO vm = _vmDao.findByUuid(vmUuid); - s_logger.info("Migrating " + vm + " to " + dest); + s_logger.info(String.format("Migrating %s to %s", vm, dest)); vm.getServiceOfferingId(); final long dstHostId = dest.getHost().getId(); final Host fromHost = _hostDao.findById(srcHostId); + Host srcHost = _hostDao.findById(srcHostId); if (fromHost == null) { - s_logger.info("Unable to find the host to migrate from: " + srcHostId); - throw new CloudRuntimeException("Unable to find the host to migrate from: " + srcHostId); + String logMessageUnableToFindHost = String.format("Unable to find host to migrate from %s.", srcHost); + s_logger.info(logMessageUnableToFindHost); + throw new CloudRuntimeException(logMessageUnableToFindHost); } - if (fromHost.getClusterId().longValue() != dest.getCluster().getId()) { - s_logger.info("Source and destination host are not in same cluster, unable to migrate to host: " + dstHostId); - throw new CloudRuntimeException("Source and destination host are not in same cluster, unable to migrate to host: " + dest.getHost().getId()); + Host dstHost = _hostDao.findById(dstHostId); + long destHostClusterId = dest.getCluster().getId(); + long fromHostClusterId = fromHost.getClusterId(); + if (fromHostClusterId != destHostClusterId) { + String logMessageHostsOnDifferentCluster = String.format("Source and destination host are not in same cluster, unable to migrate to %s", srcHost); + s_logger.info(logMessageHostsOnDifferentCluster); + throw new CloudRuntimeException(logMessageHostsOnDifferentCluster); } final VirtualMachineGuru vmGuru = getVmGuru(vm); @@ -4471,13 +4481,13 @@ private void orchestrateMigrateForScale(final String vmUuid, final long srcHostI try { _agentMgr.send(srcHostId, new Commands(cleanup(vm.getInstanceName())), null); } catch (final AgentUnavailableException e) { - s_logger.error("AgentUnavailableException while cleanup on source host: " + srcHostId); + s_logger.error(String.format("Unable to cleanup source %s. ", srcHost), e); } cleanup(vmGuru, new VirtualMachineProfileImpl(vm), work, Event.AgentReportStopped, true); throw new CloudRuntimeException("Unable to complete migration for " + vm); } } catch (final OperationTimedoutException e) { - s_logger.debug("Error while checking the vm " + vm + " on host " + dstHostId, e); + s_logger.debug(String.format("Error while checking the %s on %s", vm, dstHost), e); } migrated = true; @@ -4485,9 +4495,10 @@ private void orchestrateMigrateForScale(final String vmUuid, final long srcHostI if (!migrated) { s_logger.info("Migration was unsuccessful. Cleaning up: " + vm); - _alertMgr.sendAlert(alertType, fromHost.getDataCenterId(), fromHost.getPodId(), - "Unable to migrate vm " + vm.getInstanceName() + " from host " + fromHost.getName() + " in zone " + dest.getDataCenter().getName() + " and pod " + - dest.getPod().getName(), "Migrate Command failed. Please check logs."); + String alertSubject = String.format("Unable to migrate %s from %s in Zone [%s] and Pod [%s].", + vm.getInstanceName(), fromHost, dest.getDataCenter().getName(), dest.getPod().getName()); + String alertBody = "Migrate Command failed. Please check logs."; + _alertMgr.sendAlert(alertType, fromHost.getDataCenterId(), fromHost.getPodId(), alertSubject, alertBody); try { _agentMgr.send(dstHostId, new Commands(cleanup(vm.getInstanceName())), null); } catch (final AgentUnavailableException ae) { @@ -4837,6 +4848,8 @@ private void handlePowerOnReportWithNoPendingJobsOnVM(final VMInstanceVO vm) { // 3) handle out of sync stationary states, marking VM from Stopped to Running with // alert messages // + Host host = _hostDao.findById(vm.getHostId()); + Host poweredHost = _hostDao.findById(vm.getPowerHostId()); switch (vm.getState()) { case Starting: s_logger.info("VM " + vm.getInstanceName() + " is at " + vm.getState() + " and we received a power-on report while there is no pending jobs on it"); @@ -4858,7 +4871,7 @@ private void handlePowerOnReportWithNoPendingJobsOnVM(final VMInstanceVO vm) { case Running: try { if (vm.getHostId() != null && vm.getHostId().longValue() != vm.getPowerHostId().longValue()) { - s_logger.info("Detected out of band VM migration from host " + vm.getHostId() + " to host " + vm.getPowerHostId()); + s_logger.info(String.format("Detected out of band VM migration from %s to %s", host, poweredHost)); } stateTransitTo(vm, VirtualMachine.Event.FollowAgentPowerOnReport, vm.getPowerHostId()); } catch (final NoTransitionException e) { diff --git a/engine/orchestration/src/main/java/org/apache/cloudstack/engine/cloud/entity/api/VMEntityManagerImpl.java b/engine/orchestration/src/main/java/org/apache/cloudstack/engine/cloud/entity/api/VMEntityManagerImpl.java index 567675ab0534..02ffb37ba158 100644 --- a/engine/orchestration/src/main/java/org/apache/cloudstack/engine/cloud/entity/api/VMEntityManagerImpl.java +++ b/engine/orchestration/src/main/java/org/apache/cloudstack/engine/cloud/entity/api/VMEntityManagerImpl.java @@ -253,6 +253,8 @@ public void deployVirtualMachine(String reservationId, VMEntityVO vmEntityVO, St } _itMgr.start(vm.getUuid(), params, plan, null); + } else { + throw ex; } } } else { diff --git a/engine/schema/src/main/java/com/cloud/dc/ClusterVO.java b/engine/schema/src/main/java/com/cloud/dc/ClusterVO.java index 2a76789136a9..f60765e28566 100644 --- a/engine/schema/src/main/java/com/cloud/dc/ClusterVO.java +++ b/engine/schema/src/main/java/com/cloud/dc/ClusterVO.java @@ -196,4 +196,9 @@ public void setUuid(String uuid) { public PartitionType partitionType() { return PartitionType.Cluster; } + + @Override + public String toString() { + return String.format("Cluster {id: \"%s\", name: \"%s\", uuid: \"%s\"}", id, name, uuid); + } } diff --git a/engine/schema/src/main/java/com/cloud/dc/DomainVlanMapVO.java b/engine/schema/src/main/java/com/cloud/dc/DomainVlanMapVO.java index 22d39dc16c9f..86e29e4bafd5 100644 --- a/engine/schema/src/main/java/com/cloud/dc/DomainVlanMapVO.java +++ b/engine/schema/src/main/java/com/cloud/dc/DomainVlanMapVO.java @@ -26,7 +26,7 @@ import org.apache.cloudstack.api.InternalIdentity; @Entity -@Table(name="domain_vlan_map") +@Table(name = "domain_vlan_map") public class DomainVlanMapVO implements InternalIdentity { @Id diff --git a/engine/schema/src/main/java/com/cloud/gpu/HostGpuGroupsVO.java b/engine/schema/src/main/java/com/cloud/gpu/HostGpuGroupsVO.java index 1c186a162e3c..f8e116cbc99c 100644 --- a/engine/schema/src/main/java/com/cloud/gpu/HostGpuGroupsVO.java +++ b/engine/schema/src/main/java/com/cloud/gpu/HostGpuGroupsVO.java @@ -26,7 +26,7 @@ import org.apache.cloudstack.api.InternalIdentity; @Entity -@Table(name="host_gpu_groups") +@Table(name = "host_gpu_groups") public class HostGpuGroupsVO implements InternalIdentity { @Id @GeneratedValue(strategy=GenerationType.IDENTITY) diff --git a/engine/schema/src/main/java/com/cloud/gpu/VGPUTypesVO.java b/engine/schema/src/main/java/com/cloud/gpu/VGPUTypesVO.java index fa6674c2c7e7..5bbf90854ee6 100644 --- a/engine/schema/src/main/java/com/cloud/gpu/VGPUTypesVO.java +++ b/engine/schema/src/main/java/com/cloud/gpu/VGPUTypesVO.java @@ -26,7 +26,7 @@ import org.apache.cloudstack.api.InternalIdentity; @Entity -@Table(name="vgpu_types") +@Table(name = "vgpu_types") public class VGPUTypesVO implements InternalIdentity { @Id @GeneratedValue(strategy=GenerationType.IDENTITY) diff --git a/engine/schema/src/main/java/com/cloud/hypervisor/dao/HypervisorCapabilitiesDao.java b/engine/schema/src/main/java/com/cloud/hypervisor/dao/HypervisorCapabilitiesDao.java index 45c88060496b..9255fae0c9ea 100644 --- a/engine/schema/src/main/java/com/cloud/hypervisor/dao/HypervisorCapabilitiesDao.java +++ b/engine/schema/src/main/java/com/cloud/hypervisor/dao/HypervisorCapabilitiesDao.java @@ -38,5 +38,5 @@ public interface HypervisorCapabilitiesDao extends GenericDao getHypervisorsWithDefaultEntries(); - Boolean isStorageMotionSupported(HypervisorType hypervisorType, String hypervisorVersion); + boolean isStorageMotionSupported(HypervisorType hypervisorType, String hypervisorVersion); } diff --git a/engine/schema/src/main/java/com/cloud/hypervisor/dao/HypervisorCapabilitiesDaoImpl.java b/engine/schema/src/main/java/com/cloud/hypervisor/dao/HypervisorCapabilitiesDaoImpl.java index 09b39749ec29..35f765b554ac 100644 --- a/engine/schema/src/main/java/com/cloud/hypervisor/dao/HypervisorCapabilitiesDaoImpl.java +++ b/engine/schema/src/main/java/com/cloud/hypervisor/dao/HypervisorCapabilitiesDaoImpl.java @@ -121,7 +121,7 @@ public List getHypervisorsWithDefaultEntries() { } @Override - public Boolean isStorageMotionSupported(HypervisorType hypervisorType, String hypervisorVersion) { + public boolean isStorageMotionSupported(HypervisorType hypervisorType, String hypervisorVersion) { HypervisorCapabilitiesVO hostCapabilities = findByHypervisorTypeAndVersion(hypervisorType, hypervisorVersion); if (hostCapabilities == null && HypervisorType.KVM.equals(hypervisorType)) { List hypervisorCapabilitiesList = listAllByHypervisorType(HypervisorType.KVM); diff --git a/engine/schema/src/main/java/com/cloud/network/LBHealthCheckPolicyVO.java b/engine/schema/src/main/java/com/cloud/network/LBHealthCheckPolicyVO.java index 72dbf5cbdccd..22bb2c26b652 100644 --- a/engine/schema/src/main/java/com/cloud/network/LBHealthCheckPolicyVO.java +++ b/engine/schema/src/main/java/com/cloud/network/LBHealthCheckPolicyVO.java @@ -29,7 +29,7 @@ import com.cloud.network.rules.HealthCheckPolicy; @Entity -@Table(name = ("load_balancer_healthcheck_policies")) +@Table(name = "load_balancer_healthcheck_policies") @PrimaryKeyJoinColumn(name = "load_balancer_id", referencedColumnName = "id") public class LBHealthCheckPolicyVO implements HealthCheckPolicy { @Id diff --git a/engine/schema/src/main/java/com/cloud/network/UserIpv6AddressVO.java b/engine/schema/src/main/java/com/cloud/network/UserIpv6AddressVO.java index 397c7b3b319e..e97961a2dae7 100644 --- a/engine/schema/src/main/java/com/cloud/network/UserIpv6AddressVO.java +++ b/engine/schema/src/main/java/com/cloud/network/UserIpv6AddressVO.java @@ -31,7 +31,7 @@ import com.cloud.utils.db.GenericDao; @Entity -@Table(name = ("user_ipv6_address")) +@Table(name = "user_ipv6_address") public class UserIpv6AddressVO implements UserIpv6Address { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) diff --git a/engine/schema/src/main/java/com/cloud/network/VpnUserVO.java b/engine/schema/src/main/java/com/cloud/network/VpnUserVO.java index 10f6bc00ae39..9e403e4ec99a 100644 --- a/engine/schema/src/main/java/com/cloud/network/VpnUserVO.java +++ b/engine/schema/src/main/java/com/cloud/network/VpnUserVO.java @@ -30,7 +30,7 @@ import com.cloud.utils.db.Encrypt; @Entity -@Table(name = ("vpn_users")) +@Table(name = "vpn_users") public class VpnUserVO implements VpnUser { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) diff --git a/engine/schema/src/main/java/com/cloud/network/as/AutoScalePolicyConditionMapVO.java b/engine/schema/src/main/java/com/cloud/network/as/AutoScalePolicyConditionMapVO.java index 834422f10656..6a3118bd5b3a 100644 --- a/engine/schema/src/main/java/com/cloud/network/as/AutoScalePolicyConditionMapVO.java +++ b/engine/schema/src/main/java/com/cloud/network/as/AutoScalePolicyConditionMapVO.java @@ -26,7 +26,7 @@ import org.apache.cloudstack.api.InternalIdentity; @Entity -@Table(name = ("autoscale_policy_condition_map")) +@Table(name = "autoscale_policy_condition_map") public class AutoScalePolicyConditionMapVO implements InternalIdentity { @Id diff --git a/engine/schema/src/main/java/com/cloud/network/as/AutoScaleVmGroupPolicyMapVO.java b/engine/schema/src/main/java/com/cloud/network/as/AutoScaleVmGroupPolicyMapVO.java index b2753641e22a..403d2c0a2b1e 100644 --- a/engine/schema/src/main/java/com/cloud/network/as/AutoScaleVmGroupPolicyMapVO.java +++ b/engine/schema/src/main/java/com/cloud/network/as/AutoScaleVmGroupPolicyMapVO.java @@ -26,7 +26,7 @@ import org.apache.cloudstack.api.InternalIdentity; @Entity -@Table(name = ("autoscale_vmgroup_policy_map")) +@Table(name = "autoscale_vmgroup_policy_map") public class AutoScaleVmGroupPolicyMapVO implements InternalIdentity { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) diff --git a/engine/schema/src/main/java/com/cloud/network/as/AutoScaleVmGroupVmMapVO.java b/engine/schema/src/main/java/com/cloud/network/as/AutoScaleVmGroupVmMapVO.java index 038f0d768250..0d9139b799fc 100644 --- a/engine/schema/src/main/java/com/cloud/network/as/AutoScaleVmGroupVmMapVO.java +++ b/engine/schema/src/main/java/com/cloud/network/as/AutoScaleVmGroupVmMapVO.java @@ -26,7 +26,7 @@ import org.apache.cloudstack.api.InternalIdentity; @Entity -@Table(name = ("autoscale_vmgroup_vm_map")) +@Table(name = "autoscale_vmgroup_vm_map") public class AutoScaleVmGroupVmMapVO implements InternalIdentity { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) diff --git a/engine/schema/src/main/java/com/cloud/network/dao/FirewallRulesCidrsVO.java b/engine/schema/src/main/java/com/cloud/network/dao/FirewallRulesCidrsVO.java index ce50e170c64f..bad7479cde70 100644 --- a/engine/schema/src/main/java/com/cloud/network/dao/FirewallRulesCidrsVO.java +++ b/engine/schema/src/main/java/com/cloud/network/dao/FirewallRulesCidrsVO.java @@ -26,7 +26,7 @@ import org.apache.cloudstack.api.InternalIdentity; @Entity -@Table(name = ("firewall_rules_cidrs")) +@Table(name = "firewall_rules_cidrs") public class FirewallRulesCidrsVO implements InternalIdentity { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) diff --git a/engine/schema/src/main/java/com/cloud/network/dao/FirewallRulesDestCidrsVO.java b/engine/schema/src/main/java/com/cloud/network/dao/FirewallRulesDestCidrsVO.java index ce00e0ecfb96..ad05394ba59f 100644 --- a/engine/schema/src/main/java/com/cloud/network/dao/FirewallRulesDestCidrsVO.java +++ b/engine/schema/src/main/java/com/cloud/network/dao/FirewallRulesDestCidrsVO.java @@ -26,7 +26,7 @@ import javax.persistence.Table; @Entity -@Table(name = ("firewall_rules_dcidrs")) +@Table(name = "firewall_rules_dcidrs") public class FirewallRulesDestCidrsVO implements InternalIdentity{ @Id @GeneratedValue(strategy = GenerationType.IDENTITY) diff --git a/engine/schema/src/main/java/com/cloud/network/dao/IPAddressVO.java b/engine/schema/src/main/java/com/cloud/network/dao/IPAddressVO.java index 0b8801161590..686f4975edb8 100644 --- a/engine/schema/src/main/java/com/cloud/network/dao/IPAddressVO.java +++ b/engine/schema/src/main/java/com/cloud/network/dao/IPAddressVO.java @@ -40,7 +40,7 @@ * */ @Entity -@Table(name = ("user_ip_address")) +@Table(name = "user_ip_address") public class IPAddressVO implements IpAddress { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) diff --git a/engine/schema/src/main/java/com/cloud/network/dao/InlineLoadBalancerNicMapVO.java b/engine/schema/src/main/java/com/cloud/network/dao/InlineLoadBalancerNicMapVO.java index 3bfb076c7f4e..923a26164084 100644 --- a/engine/schema/src/main/java/com/cloud/network/dao/InlineLoadBalancerNicMapVO.java +++ b/engine/schema/src/main/java/com/cloud/network/dao/InlineLoadBalancerNicMapVO.java @@ -26,7 +26,7 @@ import org.apache.cloudstack.api.InternalIdentity; @Entity -@Table(name = ("inline_load_balancer_nic_map")) +@Table(name = "inline_load_balancer_nic_map") public class InlineLoadBalancerNicMapVO implements InternalIdentity { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) diff --git a/engine/schema/src/main/java/com/cloud/network/dao/LBStickinessPolicyVO.java b/engine/schema/src/main/java/com/cloud/network/dao/LBStickinessPolicyVO.java index 9628a32ae4c4..e9f50a75a7b7 100644 --- a/engine/schema/src/main/java/com/cloud/network/dao/LBStickinessPolicyVO.java +++ b/engine/schema/src/main/java/com/cloud/network/dao/LBStickinessPolicyVO.java @@ -35,7 +35,7 @@ import com.cloud.utils.Pair; @Entity -@Table(name = ("load_balancer_stickiness_policies")) +@Table(name = "load_balancer_stickiness_policies") @PrimaryKeyJoinColumn(name = "load_balancer_id", referencedColumnName = "id") public class LBStickinessPolicyVO implements StickinessPolicy { @Id diff --git a/engine/schema/src/main/java/com/cloud/network/dao/LoadBalancerVMMapVO.java b/engine/schema/src/main/java/com/cloud/network/dao/LoadBalancerVMMapVO.java index 08b918475c34..721349613d88 100644 --- a/engine/schema/src/main/java/com/cloud/network/dao/LoadBalancerVMMapVO.java +++ b/engine/schema/src/main/java/com/cloud/network/dao/LoadBalancerVMMapVO.java @@ -26,7 +26,7 @@ import org.apache.cloudstack.api.InternalIdentity; @Entity -@Table(name = ("load_balancer_vm_map")) +@Table(name = "load_balancer_vm_map") public class LoadBalancerVMMapVO implements InternalIdentity { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) diff --git a/engine/schema/src/main/java/com/cloud/network/dao/LoadBalancerVO.java b/engine/schema/src/main/java/com/cloud/network/dao/LoadBalancerVO.java index 865e7d2c365e..d0775253a2ed 100644 --- a/engine/schema/src/main/java/com/cloud/network/dao/LoadBalancerVO.java +++ b/engine/schema/src/main/java/com/cloud/network/dao/LoadBalancerVO.java @@ -35,7 +35,7 @@ * */ @Entity -@Table(name = ("load_balancing_rules")) +@Table(name = "load_balancing_rules") @DiscriminatorValue(value = "LoadBalancing") @PrimaryKeyJoinColumn(name = "id") public class LoadBalancerVO extends FirewallRuleVO implements LoadBalancer { diff --git a/engine/schema/src/main/java/com/cloud/network/dao/NetworkRuleConfigVO.java b/engine/schema/src/main/java/com/cloud/network/dao/NetworkRuleConfigVO.java index e87d656f53d8..7c2467f8d573 100644 --- a/engine/schema/src/main/java/com/cloud/network/dao/NetworkRuleConfigVO.java +++ b/engine/schema/src/main/java/com/cloud/network/dao/NetworkRuleConfigVO.java @@ -26,7 +26,7 @@ import org.apache.cloudstack.api.InternalIdentity; @Entity -@Table(name = ("network_rule_config")) +@Table(name = "network_rule_config") public class NetworkRuleConfigVO implements InternalIdentity { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) diff --git a/engine/schema/src/main/java/com/cloud/network/dao/RemoteAccessVpnVO.java b/engine/schema/src/main/java/com/cloud/network/dao/RemoteAccessVpnVO.java index fdb98b9dd9d8..366a6cc52d41 100644 --- a/engine/schema/src/main/java/com/cloud/network/dao/RemoteAccessVpnVO.java +++ b/engine/schema/src/main/java/com/cloud/network/dao/RemoteAccessVpnVO.java @@ -28,7 +28,7 @@ import java.util.UUID; @Entity -@Table(name = ("remote_access_vpn")) +@Table(name = "remote_access_vpn") public class RemoteAccessVpnVO implements RemoteAccessVpn { @Column(name = "account_id") private long accountId; diff --git a/engine/schema/src/main/java/com/cloud/network/dao/Site2SiteCustomerGatewayVO.java b/engine/schema/src/main/java/com/cloud/network/dao/Site2SiteCustomerGatewayVO.java index c8241518d63e..52741fdd9a54 100644 --- a/engine/schema/src/main/java/com/cloud/network/dao/Site2SiteCustomerGatewayVO.java +++ b/engine/schema/src/main/java/com/cloud/network/dao/Site2SiteCustomerGatewayVO.java @@ -32,7 +32,7 @@ @Entity -@Table(name = ("s2s_customer_gateway")) +@Table(name = "s2s_customer_gateway") public class Site2SiteCustomerGatewayVO implements Site2SiteCustomerGateway { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) diff --git a/engine/schema/src/main/java/com/cloud/network/dao/Site2SiteVpnConnectionVO.java b/engine/schema/src/main/java/com/cloud/network/dao/Site2SiteVpnConnectionVO.java index 85643fc04377..04a9d1ca1d46 100644 --- a/engine/schema/src/main/java/com/cloud/network/dao/Site2SiteVpnConnectionVO.java +++ b/engine/schema/src/main/java/com/cloud/network/dao/Site2SiteVpnConnectionVO.java @@ -35,7 +35,7 @@ @Entity -@Table(name = ("s2s_vpn_connection")) +@Table(name = "s2s_vpn_connection") public class Site2SiteVpnConnectionVO implements Site2SiteVpnConnection, InternalIdentity { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) diff --git a/engine/schema/src/main/java/com/cloud/network/dao/Site2SiteVpnGatewayVO.java b/engine/schema/src/main/java/com/cloud/network/dao/Site2SiteVpnGatewayVO.java index 260e5fc4c0b3..184162ad92ba 100644 --- a/engine/schema/src/main/java/com/cloud/network/dao/Site2SiteVpnGatewayVO.java +++ b/engine/schema/src/main/java/com/cloud/network/dao/Site2SiteVpnGatewayVO.java @@ -31,7 +31,7 @@ @Entity -@Table(name = ("s2s_vpn_gateway")) +@Table(name = "s2s_vpn_gateway") public class Site2SiteVpnGatewayVO implements Site2SiteVpnGateway { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) diff --git a/engine/schema/src/main/java/com/cloud/network/element/OvsProviderVO.java b/engine/schema/src/main/java/com/cloud/network/element/OvsProviderVO.java index 09ea59d04409..db82845dd4bb 100644 --- a/engine/schema/src/main/java/com/cloud/network/element/OvsProviderVO.java +++ b/engine/schema/src/main/java/com/cloud/network/element/OvsProviderVO.java @@ -30,7 +30,7 @@ import com.cloud.utils.db.GenericDao; @Entity -@Table(name = ("ovs_providers")) +@Table(name = "ovs_providers") public class OvsProviderVO implements OvsProvider { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) diff --git a/engine/schema/src/main/java/com/cloud/network/element/VirtualRouterProviderVO.java b/engine/schema/src/main/java/com/cloud/network/element/VirtualRouterProviderVO.java index 17bc16536b6a..08dc1a95f432 100644 --- a/engine/schema/src/main/java/com/cloud/network/element/VirtualRouterProviderVO.java +++ b/engine/schema/src/main/java/com/cloud/network/element/VirtualRouterProviderVO.java @@ -32,7 +32,7 @@ import com.cloud.utils.db.GenericDao; @Entity -@Table(name = ("virtual_router_providers")) +@Table(name = "virtual_router_providers") public class VirtualRouterProviderVO implements VirtualRouterProvider { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) diff --git a/engine/schema/src/main/java/com/cloud/network/rules/PortForwardingRuleVO.java b/engine/schema/src/main/java/com/cloud/network/rules/PortForwardingRuleVO.java index 4c27a3fc2b44..e1a698881f33 100644 --- a/engine/schema/src/main/java/com/cloud/network/rules/PortForwardingRuleVO.java +++ b/engine/schema/src/main/java/com/cloud/network/rules/PortForwardingRuleVO.java @@ -29,7 +29,7 @@ import com.cloud.utils.net.Ip; @Entity -@Table(name = ("port_forwarding_rules")) +@Table(name = "port_forwarding_rules") @DiscriminatorValue(value = "PortForwarding") @PrimaryKeyJoinColumn(name = "id") public class PortForwardingRuleVO extends FirewallRuleVO implements PortForwardingRule { diff --git a/engine/schema/src/main/java/com/cloud/network/security/SecurityGroupRuleVO.java b/engine/schema/src/main/java/com/cloud/network/security/SecurityGroupRuleVO.java index e230eae00082..1980cd33d146 100644 --- a/engine/schema/src/main/java/com/cloud/network/security/SecurityGroupRuleVO.java +++ b/engine/schema/src/main/java/com/cloud/network/security/SecurityGroupRuleVO.java @@ -26,7 +26,7 @@ import javax.persistence.Table; @Entity -@Table(name = ("security_group_rule")) +@Table(name = "security_group_rule") public class SecurityGroupRuleVO implements SecurityRule { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) diff --git a/engine/schema/src/main/java/com/cloud/network/security/SecurityGroupRulesVO.java b/engine/schema/src/main/java/com/cloud/network/security/SecurityGroupRulesVO.java index 3ec5cec59e60..0bfc8a68bddc 100644 --- a/engine/schema/src/main/java/com/cloud/network/security/SecurityGroupRulesVO.java +++ b/engine/schema/src/main/java/com/cloud/network/security/SecurityGroupRulesVO.java @@ -29,7 +29,7 @@ import com.cloud.utils.db.JoinType; @Entity -@Table(name = ("security_group")) +@Table(name = "security_group") @JoinType(type = "left") @SecondaryTable(name = "security_group_rule", pkJoinColumns = {@PrimaryKeyJoinColumn(name = "id", referencedColumnName = "security_group_id")}) public class SecurityGroupRulesVO implements SecurityGroupRules { diff --git a/engine/schema/src/main/java/com/cloud/network/security/SecurityGroupVMMapVO.java b/engine/schema/src/main/java/com/cloud/network/security/SecurityGroupVMMapVO.java index 55020ea8e027..d12b9f9443fd 100644 --- a/engine/schema/src/main/java/com/cloud/network/security/SecurityGroupVMMapVO.java +++ b/engine/schema/src/main/java/com/cloud/network/security/SecurityGroupVMMapVO.java @@ -31,7 +31,7 @@ import com.cloud.vm.VirtualMachine.State; @Entity -@Table(name = ("security_group_vm_map")) +@Table(name = "security_group_vm_map") @SecondaryTables({@SecondaryTable(name = "nics", pkJoinColumns = {@PrimaryKeyJoinColumn(name = "instance_id", referencedColumnName = "instance_id")}), @SecondaryTable(name = "vm_instance", pkJoinColumns = {@PrimaryKeyJoinColumn(name = "instance_id", referencedColumnName = "id")}), @SecondaryTable(name = "security_group", pkJoinColumns = {@PrimaryKeyJoinColumn(name = "security_group_id", referencedColumnName = "id")})}) diff --git a/engine/schema/src/main/java/com/cloud/network/security/SecurityGroupVO.java b/engine/schema/src/main/java/com/cloud/network/security/SecurityGroupVO.java index 3b7ceb8eb64b..ec1cfae43b63 100644 --- a/engine/schema/src/main/java/com/cloud/network/security/SecurityGroupVO.java +++ b/engine/schema/src/main/java/com/cloud/network/security/SecurityGroupVO.java @@ -26,7 +26,7 @@ import javax.persistence.Table; @Entity -@Table(name = ("security_group")) +@Table(name = "security_group") public class SecurityGroupVO implements SecurityGroup { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) diff --git a/engine/schema/src/main/java/com/cloud/storage/VMTemplateHostVO.java b/engine/schema/src/main/java/com/cloud/storage/VMTemplateHostVO.java deleted file mode 100644 index fc4d9c1599ef..000000000000 --- a/engine/schema/src/main/java/com/cloud/storage/VMTemplateHostVO.java +++ /dev/null @@ -1,334 +0,0 @@ -// 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.storage; - -import java.util.Date; - -import javax.persistence.Column; -import javax.persistence.Entity; -import javax.persistence.EnumType; -import javax.persistence.Enumerated; -import javax.persistence.GeneratedValue; -import javax.persistence.GenerationType; -import javax.persistence.Id; -import javax.persistence.Table; -import javax.persistence.Temporal; -import javax.persistence.TemporalType; - -import org.apache.cloudstack.engine.subsystem.api.storage.DataObjectInStore; -import org.apache.cloudstack.engine.subsystem.api.storage.ObjectInDataStoreStateMachine; -import org.apache.cloudstack.engine.subsystem.api.storage.ObjectInDataStoreStateMachine.State; - -import com.cloud.utils.db.GenericDaoBase; - -/** - * Join table for storage hosts and templates - * - */ -@Entity -@Table(name = "template_host_ref") -public class VMTemplateHostVO implements VMTemplateStorageResourceAssoc, DataObjectInStore { - @Id - @GeneratedValue(strategy = GenerationType.IDENTITY) - Long id; - - @Column(name = "host_id") - private long hostId; - - @Column(name = "template_id") - private long templateId; - - @Column(name = GenericDaoBase.CREATED_COLUMN) - private Date created = null; - - @Column(name = "last_updated") - @Temporal(value = TemporalType.TIMESTAMP) - private Date lastUpdated = null; - - @Column(name = "download_pct") - private int downloadPercent; - - @Column(name = "size") - private long size; - - @Column(name = "physical_size") - private long physicalSize; - - @Column(name = "download_state") - @Enumerated(EnumType.STRING) - private Status downloadState; - - @Column(name = "local_path") - private String localDownloadPath; - - @Column(name = "error_str") - private String errorString; - - @Column(name = "job_id") - private String jobId; - - @Column(name = "install_path") - private String installPath; - - @Column(name = "url", length = 2048) - private String downloadUrl; - - @Column(name = "is_copy") - private boolean isCopy = false; - - @Column(name = "destroyed") - boolean destroyed = false; - - @Column(name = "update_count", updatable = true, nullable = false) - protected long updatedCount; - - @Column(name = "updated") - @Temporal(value = TemporalType.TIMESTAMP) - Date updated; - - @Column(name = "state") - @Enumerated(EnumType.STRING) - ObjectInDataStoreStateMachine.State state; - - @Override - public String getInstallPath() { - return installPath; - } - - public long getHostId() { - return hostId; - } - - public void setHostId(long hostId) { - this.hostId = hostId; - } - - @Override - public long getTemplateId() { - return templateId; - } - - @Override - public void setTemplateId(long templateId) { - this.templateId = templateId; - } - - @Override - public int getDownloadPercent() { - return downloadPercent; - } - - @Override - public void setDownloadPercent(int downloadPercent) { - this.downloadPercent = downloadPercent; - } - - @Override - public void setDownloadState(Status downloadState) { - this.downloadState = downloadState; - } - - @Override - public long getId() { - return id; - } - - @Override - public Date getCreated() { - return created; - } - - @Override - public Date getLastUpdated() { - return lastUpdated; - } - - @Override - public void setLastUpdated(Date date) { - lastUpdated = date; - } - - @Override - public void setInstallPath(String installPath) { - this.installPath = installPath; - } - - @Override - public Status getDownloadState() { - return downloadState; - } - - public VMTemplateHostVO(long hostId, long templateId) { - super(); - this.hostId = hostId; - this.templateId = templateId; - this.state = ObjectInDataStoreStateMachine.State.Allocated; - } - - public VMTemplateHostVO(long hostId, long templateId, Date lastUpdated, int downloadPercent, Status downloadState, String localDownloadPath, String errorString, - String jobId, String installPath, String downloadUrl) { - super(); - this.hostId = hostId; - this.templateId = templateId; - this.lastUpdated = lastUpdated; - this.downloadPercent = downloadPercent; - this.downloadState = downloadState; - this.localDownloadPath = localDownloadPath; - this.errorString = errorString; - this.jobId = jobId; - this.installPath = installPath; - this.setDownloadUrl(downloadUrl); - } - - protected VMTemplateHostVO() { - - } - - @Override - public void setLocalDownloadPath(String localPath) { - this.localDownloadPath = localPath; - } - - @Override - public String getLocalDownloadPath() { - return localDownloadPath; - } - - @Override - public void setErrorString(String errorString) { - this.errorString = errorString; - } - - @Override - public String getErrorString() { - return errorString; - } - - @Override - public void setJobId(String jobId) { - this.jobId = jobId; - } - - @Override - public String getJobId() { - return jobId; - } - - @Override - public boolean equals(Object obj) { - if (obj instanceof VMTemplateHostVO) { - VMTemplateHostVO other = (VMTemplateHostVO)obj; - return (this.templateId == other.getTemplateId() && this.hostId == other.getHostId()); - } - return false; - } - - @Override - public int hashCode() { - Long tid = new Long(templateId); - Long hid = new Long(hostId); - return tid.hashCode() + hid.hashCode(); - } - - public void setSize(long size) { - this.size = size; - } - - public long getSize() { - return size; - } - - public void setPhysicalSize(long physicalSize) { - this.physicalSize = physicalSize; - } - - public long getPhysicalSize() { - return physicalSize; - } - - public void setDestroyed(boolean destroyed) { - this.destroyed = destroyed; - } - - public boolean getDestroyed() { - return destroyed; - } - - public void setDownloadUrl(String downloadUrl) { - this.downloadUrl = downloadUrl; - } - - public String getDownloadUrl() { - return downloadUrl; - } - - public void setCopy(boolean isCopy) { - this.isCopy = isCopy; - } - - public boolean isCopy() { - return isCopy; - } - - @Override - public long getTemplateSize() { - return -1; - } - - @Override - public String toString() { - return new StringBuilder("TmplHost[").append(id).append("-").append(templateId).append("-").append(hostId).append(installPath).append("]").toString(); - } - - @Override - public ObjectInDataStoreStateMachine.State getState() { - // TODO Auto-generated method stub - return this.state; - } - - public long getUpdatedCount() { - return this.updatedCount; - } - - public void incrUpdatedCount() { - this.updatedCount++; - } - - public void decrUpdatedCount() { - this.updatedCount--; - } - - public Date getUpdated() { - return updated; - } - - @Override - public long getObjectId() { - return this.getTemplateId(); - } - - @Override - public long getDataStoreId() { - return this.getHostId(); - } - - @Override - public State getObjectInStoreState() { - return this.state; - } - -} diff --git a/engine/schema/src/main/java/com/cloud/storage/VolumeHostVO.java b/engine/schema/src/main/java/com/cloud/storage/VolumeHostVO.java deleted file mode 100644 index d086f2dd0aa2..000000000000 --- a/engine/schema/src/main/java/com/cloud/storage/VolumeHostVO.java +++ /dev/null @@ -1,346 +0,0 @@ -// 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.storage; - -import java.util.Date; - -import javax.persistence.Column; -import javax.persistence.Entity; -import javax.persistence.EnumType; -import javax.persistence.Enumerated; -import javax.persistence.GeneratedValue; -import javax.persistence.GenerationType; -import javax.persistence.Id; -import javax.persistence.Table; -import javax.persistence.Temporal; -import javax.persistence.TemporalType; - -import org.apache.cloudstack.api.InternalIdentity; -import org.apache.cloudstack.engine.subsystem.api.storage.DataObjectInStore; -import org.apache.cloudstack.engine.subsystem.api.storage.ObjectInDataStoreStateMachine; -import org.apache.cloudstack.engine.subsystem.api.storage.ObjectInDataStoreStateMachine.State; - -import com.cloud.storage.Storage.ImageFormat; -import com.cloud.storage.VMTemplateStorageResourceAssoc.Status; -import com.cloud.utils.db.GenericDaoBase; - -/** - * Join table for storage hosts and volumes - * - */ -@Entity -@Table(name = "volume_host_ref") -public class VolumeHostVO implements InternalIdentity, DataObjectInStore { - @Id - @GeneratedValue(strategy = GenerationType.IDENTITY) - Long id; - - @Column(name = "host_id") - private long hostId; - - @Column(name = "volume_id") - private long volumeId; - - @Column(name = "zone_id") - private long zoneId; - - @Column(name = GenericDaoBase.CREATED_COLUMN) - private Date created = null; - - @Column(name = "last_updated") - @Temporal(value = TemporalType.TIMESTAMP) - private Date lastUpdated = null; - - @Column(name = "download_pct") - private int downloadPercent; - - @Column(name = "size") - private long size; - - @Column(name = "physical_size") - private long physicalSize; - - @Column(name = "download_state") - @Enumerated(EnumType.STRING) - private Status downloadState; - - @Column(name = "checksum") - private String checksum; - - @Column(name = "local_path") - private String localDownloadPath; - - @Column(name = "error_str") - private String errorString; - - @Column(name = "job_id") - private String jobId; - - @Column(name = "install_path") - private String installPath; - - @Column(name = "url", length = 2048) - private String downloadUrl; - - @Column(name = "format") - private Storage.ImageFormat format; - - @Column(name = "destroyed") - boolean destroyed = false; - - @Column(name = "update_count", updatable = true, nullable = false) - protected long updatedCount; - - @Column(name = "updated") - @Temporal(value = TemporalType.TIMESTAMP) - Date updated; - - @Column(name = "state") - @Enumerated(EnumType.STRING) - ObjectInDataStoreStateMachine.State state; - - @Override - public String getInstallPath() { - return installPath; - } - - public long getHostId() { - return hostId; - } - - public void setHostId(long hostId) { - this.hostId = hostId; - } - - public long getVolumeId() { - return volumeId; - } - - public void setVolumeId(long volumeId) { - this.volumeId = volumeId; - } - - public long getZoneId() { - return zoneId; - } - - public void setZoneId(long zoneId) { - this.zoneId = zoneId; - } - - public int getDownloadPercent() { - return downloadPercent; - } - - public void setDownloadPercent(int downloadPercent) { - this.downloadPercent = downloadPercent; - } - - public void setDownloadState(Status downloadState) { - this.downloadState = downloadState; - } - - @Override - public long getId() { - return id; - } - - public Date getCreated() { - return created; - } - - public Date getLastUpdated() { - return lastUpdated; - } - - public void setLastUpdated(Date date) { - lastUpdated = date; - } - - @Override - public void setInstallPath(String installPath) { - this.installPath = installPath; - } - - public Status getDownloadState() { - return downloadState; - } - - public String getChecksum() { - return checksum; - } - - public void setChecksum(String checksum) { - this.checksum = checksum; - } - - public VolumeHostVO(long hostId, long volumeId) { - super(); - this.hostId = hostId; - this.volumeId = volumeId; - this.state = ObjectInDataStoreStateMachine.State.Allocated; - } - - public VolumeHostVO(long hostId, long volumeId, long zoneId, Date lastUpdated, int downloadPercent, Status downloadState, String localDownloadPath, - String errorString, String jobId, String installPath, String downloadUrl, String checksum, ImageFormat format) { - // super(); - this.hostId = hostId; - this.volumeId = volumeId; - this.zoneId = zoneId; - this.lastUpdated = lastUpdated; - this.downloadPercent = downloadPercent; - this.downloadState = downloadState; - this.localDownloadPath = localDownloadPath; - this.errorString = errorString; - this.jobId = jobId; - this.installPath = installPath; - this.setDownloadUrl(downloadUrl); - this.checksum = checksum; - this.format = format; - } - - protected VolumeHostVO() { - - } - - public void setLocalDownloadPath(String localPath) { - this.localDownloadPath = localPath; - } - - public String getLocalDownloadPath() { - return localDownloadPath; - } - - public void setErrorString(String errorString) { - this.errorString = errorString; - } - - public String getErrorString() { - return errorString; - } - - public void setJobId(String jobId) { - this.jobId = jobId; - } - - public String getJobId() { - return jobId; - } - - @Override - public boolean equals(Object obj) { - if (obj instanceof VolumeHostVO) { - VolumeHostVO other = (VolumeHostVO)obj; - return (this.volumeId == other.getVolumeId() && this.hostId == other.getHostId()); - } - return false; - } - - @Override - public int hashCode() { - Long tid = new Long(volumeId); - Long hid = new Long(hostId); - return tid.hashCode() + hid.hashCode(); - } - - public void setSize(long size) { - this.size = size; - } - - public long getSize() { - return size; - } - - public void setPhysicalSize(long physicalSize) { - this.physicalSize = physicalSize; - } - - public long getPhysicalSize() { - return physicalSize; - } - - public void setDestroyed(boolean destroyed) { - this.destroyed = destroyed; - } - - public boolean getDestroyed() { - return destroyed; - } - - public void setDownloadUrl(String downloadUrl) { - this.downloadUrl = downloadUrl; - } - - public String getDownloadUrl() { - return downloadUrl; - } - - public Storage.ImageFormat getFormat() { - return format; - } - - public void setFormat(Storage.ImageFormat format) { - this.format = format; - } - - public long getVolumeSize() { - return -1; - } - - @Override - public String toString() { - return new StringBuilder("VolumeHost[").append(id).append("-").append(volumeId).append("-").append(hostId).append(installPath).append("]").toString(); - } - - public long getUpdatedCount() { - return this.updatedCount; - } - - public void incrUpdatedCount() { - this.updatedCount++; - } - - public void decrUpdatedCount() { - this.updatedCount--; - } - - public Date getUpdated() { - return updated; - } - - @Override - public ObjectInDataStoreStateMachine.State getState() { - // TODO Auto-generated method stub - return this.state; - } - - @Override - public long getObjectId() { - return this.getVolumeId(); - } - - @Override - public long getDataStoreId() { - return this.getHostId(); - } - - @Override - public State getObjectInStoreState() { - return this.state; - } - -} diff --git a/engine/schema/src/main/java/com/cloud/storage/dao/VMTemplateDao.java b/engine/schema/src/main/java/com/cloud/storage/dao/VMTemplateDao.java index 95195372ee92..699336bc2c7b 100644 --- a/engine/schema/src/main/java/com/cloud/storage/dao/VMTemplateDao.java +++ b/engine/schema/src/main/java/com/cloud/storage/dao/VMTemplateDao.java @@ -72,14 +72,10 @@ public interface VMTemplateDao extends GenericDao, StateDao< VMTemplateVO findRoutingTemplate(HypervisorType type, String templateName); - List listPrivateTemplatesByHost(Long hostId); - public Long countTemplatesForAccount(long accountId); public List listUnRemovedTemplatesByStates(VirtualMachineTemplate.State ...states); - List findTemplatesToSyncToS3(); - void loadDetails(VMTemplateVO tmpl); void saveDetails(VMTemplateVO tmpl); diff --git a/engine/schema/src/main/java/com/cloud/storage/dao/VMTemplateDaoImpl.java b/engine/schema/src/main/java/com/cloud/storage/dao/VMTemplateDaoImpl.java index 79954307d448..b7e55b69b450 100644 --- a/engine/schema/src/main/java/com/cloud/storage/dao/VMTemplateDaoImpl.java +++ b/engine/schema/src/main/java/com/cloud/storage/dao/VMTemplateDaoImpl.java @@ -16,9 +16,6 @@ // under the License. package com.cloud.storage.dao; -import java.sql.PreparedStatement; -import java.sql.ResultSet; -import java.sql.SQLException; import java.util.ArrayList; import java.util.Date; import java.util.List; @@ -79,13 +76,6 @@ public class VMTemplateDaoImpl extends GenericDaoBase implem @Inject TemplateDataStoreDao _templateDataStoreDao; - private static final String SELECT_S3_CANDIDATE_TEMPLATES = "SELECT t.id, t.unique_name, t.name, t.public, t.featured, " - + "t.type, t.hvm, t.bits, t.url, t.format, t.created, t.account_id, t.checksum, t.display_text, " - + "t.enable_password, t.guest_os_id, t.bootable, t.prepopulate, t.cross_zones, t.hypervisor_type " - + "FROM vm_template t JOIN template_host_ref r ON t.id=r.template_id JOIN host h ON h.id=r.host_id " - + "WHERE t.hypervisor_type IN (SELECT hypervisor_type FROM host) AND r.download_state = 'DOWNLOADED' AND " - + "r.template_id NOT IN (SELECT template_id FROM template_s3_ref) AND r.destroyed = 0 AND t.type <> 'PERHOST'"; - protected SearchBuilder TemplateNameSearch; protected SearchBuilder UniqueNameSearch; protected SearchBuilder tmpltTypeSearch; @@ -231,31 +221,6 @@ public List listAllSystemVMTemplates() { return listBy(sc, filter); } - @Override - public List listPrivateTemplatesByHost(Long hostId) { - - String sql = - "select * from template_host_ref as thr INNER JOIN vm_template as t ON t.id=thr.template_id " - + "where thr.host_id=? and t.public=0 and t.featured=0 and t.type='USER' and t.state='Active'"; - - List l = new ArrayList(); - - TransactionLegacy txn = TransactionLegacy.currentTxn(); - - PreparedStatement pstmt = null; - try { - pstmt = txn.prepareAutoCloseStatement(sql); - pstmt.setLong(1, hostId); - ResultSet rs = pstmt.executeQuery(); - while (rs.next()) { - l.add(rs.getLong(1)); - } - } catch (SQLException e) { - s_logger.debug("Exception: ", e); - } - return l; - } - @Override public List listReadyTemplates() { SearchCriteria sc = createSearchCriteria(); @@ -466,320 +431,6 @@ public void saveDetails(VMTemplateVO tmpl) { _templateDetailsDao.saveDetails(details); } - /* - * @Override public Set> searchSwiftTemplates(String name, - * String keyword, TemplateFilter templateFilter, boolean isIso, - * List hypers, Boolean bootable, DomainVO domain, Long - * pageSize, Long startIndex, Long zoneId, HypervisorType hyperType, boolean - * onlyReady, boolean showDomr, List permittedAccounts, Account - * caller, Map tags) { - * - * StringBuilder builder = new StringBuilder(); if - * (!permittedAccounts.isEmpty()) { for (Account permittedAccount : - * permittedAccounts) { builder.append(permittedAccount.getAccountId() + - * ","); } } - * - * String permittedAccountsStr = builder.toString(); - * - * if (permittedAccountsStr.length() > 0) { // chop the "," off - * permittedAccountsStr = permittedAccountsStr.substring(0, - * permittedAccountsStr.length() - 1); } - * - * TransactionLegacy txn = TransactionLegacy.currentTxn(); txn.start(); - * - * Set> templateZonePairList = new HashSet>(); PreparedStatement pstmt = null; ResultSet rs = null; String sql - * = SELECT_TEMPLATE_SWIFT_REF; try { String joinClause = ""; String - * whereClause = " WHERE t.removed IS NULL"; - * - * if (isIso) { whereClause += " AND t.format = 'ISO'"; if - * (!hyperType.equals(HypervisorType.None)) { joinClause = - * " INNER JOIN guest_os guestOS on (guestOS.id = t.guest_os_id) INNER JOIN guest_os_hypervisor goh on ( goh.guest_os_id = guestOS.id) " - * ; whereClause += " AND goh.hypervisor_type = '" + hyperType.toString() + - * "'"; } } else { whereClause += " AND t.format <> 'ISO'"; if - * (hypers.isEmpty()) { return templateZonePairList; } else { StringBuilder - * relatedHypers = new StringBuilder(); for (HypervisorType hyper : hypers) - * { relatedHypers.append("'"); relatedHypers.append(hyper.toString()); - * relatedHypers.append("'"); relatedHypers.append(","); } - * relatedHypers.setLength(relatedHypers.length() - 1); whereClause += - * " AND t.hypervisor_type IN (" + relatedHypers + ")"; } } joinClause += - * " INNER JOIN template_swift_ref tsr on (t.id = tsr.template_id)"; if - * (keyword != null) { whereClause += " AND t.name LIKE \"%" + keyword + - * "%\""; } else if (name != null) { whereClause += " AND t.name LIKE \"%" + - * name + "%\""; } - * - * if (bootable != null) { whereClause += " AND t.bootable = " + bootable; } - * - * if (!showDomr) { whereClause += " AND t.type != '" + - * Storage.TemplateType.SYSTEM.toString() + "'"; } - * - * if (templateFilter == TemplateFilter.featured) { whereClause += - * " AND t.public = 1 AND t.featured = 1"; } else if ((templateFilter == - * TemplateFilter.self || templateFilter == TemplateFilter.selfexecutable) - * && caller.getType() != Account.ACCOUNT_TYPE_ADMIN) { if (caller.getType() - * == Account.ACCOUNT_TYPE_DOMAIN_ADMIN || caller.getType() == - * Account.ACCOUNT_TYPE_RESOURCE_DOMAIN_ADMIN) { joinClause += - * " INNER JOIN account a on (t.account_id = a.id) INNER JOIN domain d on (a.domain_id = d.id)" - * ; whereClause += " AND d.path LIKE '" + domain.getPath() + "%'"; } else - * { whereClause += " AND t.account_id IN (" + permittedAccountsStr + ")"; } - * } else if ((templateFilter == TemplateFilter.shared || templateFilter == - * TemplateFilter.sharedexecutable) && caller.getType() != - * Account.ACCOUNT_TYPE_ADMIN) { if (caller.getType() == - * Account.ACCOUNT_TYPE_NORMAL) { joinClause += - * " LEFT JOIN launch_permission lp ON t.id = lp.template_id WHERE" + - * " (t.account_id IN (" + permittedAccountsStr + ") OR" + - * " lp.account_id IN (" + permittedAccountsStr + "))"; } else { joinClause - * += " INNER JOIN account a on (t.account_id = a.id) "; } } else if - * (templateFilter == TemplateFilter.executable && - * !permittedAccounts.isEmpty()) { whereClause += - * " AND (t.public = 1 OR t.account_id IN (" + permittedAccountsStr + "))"; - * } else if (templateFilter == TemplateFilter.community) { whereClause += - * " AND t.public = 1 AND t.featured = 0"; } else if (templateFilter == - * TemplateFilter.all && caller.getType() == Account.ACCOUNT_TYPE_ADMIN) { } - * else if (caller.getType() != Account.ACCOUNT_TYPE_ADMIN) { return - * templateZonePairList; } - * - * sql += joinClause + whereClause + getOrderByLimit(pageSize, startIndex); - * pstmt = txn.prepareStatement(sql); rs = pstmt.executeQuery(); while - * (rs.next()) { Pair templateZonePair = new Pair(rs.getLong(1), -1L); templateZonePairList.add(templateZonePair); } - * - * } catch (Exception e) { s_logger.warn("Error listing templates", e); } - * finally { try { if (rs != null) { rs.close(); } if (pstmt != null) { - * pstmt.close(); } txn.commit(); } catch (SQLException sqle) { - * s_logger.warn("Error in cleaning up", sqle); } } - * - * return templateZonePairList; } - * - * - * @Override public Set> searchTemplates(String name, - * String keyword, TemplateFilter templateFilter, boolean isIso, - * List hypers, Boolean bootable, DomainVO domain, Long - * pageSize, Long startIndex, Long zoneId, HypervisorType hyperType, boolean - * onlyReady, boolean showDomr,List permittedAccounts, Account - * caller, ListProjectResourcesCriteria listProjectResourcesCriteria, - * Map tags, String zoneType) { StringBuilder builder = new - * StringBuilder(); if (!permittedAccounts.isEmpty()) { for (Account - * permittedAccount : permittedAccounts) { - * builder.append(permittedAccount.getAccountId() + ","); } } - * - * String permittedAccountsStr = builder.toString(); - * - * if (permittedAccountsStr.length() > 0) { //chop the "," off - * permittedAccountsStr = permittedAccountsStr.substring(0, - * permittedAccountsStr.length()-1); } - * - * TransactionLegacy txn = TransactionLegacy.currentTxn(); txn.start(); - * - * // Use LinkedHashSet here to guarantee iteration order Set> templateZonePairList = new LinkedHashSet>(); - * PreparedStatement pstmt = null; ResultSet rs = null; StringBuilder - * relatedDomainIds = new StringBuilder(); String sql = - * SELECT_TEMPLATE_ZONE_REF; String groupByClause = ""; try { //short - * accountType; //String accountId = null; String guestOSJoin = ""; - * StringBuilder templateHostRefJoin = new StringBuilder(); String - * dataCenterJoin = "", lpjoin = ""; String tagsJoin = ""; - * - * if (isIso && !hyperType.equals(HypervisorType.None)) { guestOSJoin = - * " INNER JOIN guest_os guestOS on (guestOS.id = t.guest_os_id) INNER JOIN guest_os_hypervisor goh on ( goh.guest_os_id = guestOS.id) " - * ; } if (onlyReady){ templateHostRefJoin.append( - * " INNER JOIN template_host_ref thr on (t.id = thr.template_id) INNER JOIN host h on (thr.host_id = h.id)" - * ); sql = SELECT_TEMPLATE_HOST_REF; groupByClause = - * " GROUP BY t.id, h.data_center_id "; } if ((templateFilter == - * TemplateFilter.featured) || (templateFilter == TemplateFilter.community)) - * { dataCenterJoin = - * " INNER JOIN data_center dc on (h.data_center_id = dc.id)"; } - * - * if (zoneType != null) { dataCenterJoin = - * " INNER JOIN template_host_ref thr on (t.id = thr.template_id) INNER JOIN host h on (thr.host_id = h.id)" - * ; dataCenterJoin += - * " INNER JOIN data_center dc on (h.data_center_id = dc.id)"; } - * - * if (templateFilter == TemplateFilter.sharedexecutable || templateFilter - * == TemplateFilter.shared ){ lpjoin = - * " INNER JOIN launch_permission lp ON t.id = lp.template_id "; } - * - * if (tags != null && !tags.isEmpty()) { tagsJoin = - * " INNER JOIN resource_tags r ON t.id = r.resource_id "; } - * - * sql += guestOSJoin + templateHostRefJoin + dataCenterJoin + lpjoin + - * tagsJoin; String whereClause = ""; - * - * //All joins have to be made before we start setting the condition - * settings if ((listProjectResourcesCriteria == - * ListProjectResourcesCriteria.SkipProjectResources || - * (!permittedAccounts.isEmpty() && !(templateFilter == - * TemplateFilter.community || templateFilter == TemplateFilter.featured))) - * && !(caller.getType() != Account.ACCOUNT_TYPE_NORMAL && templateFilter == - * TemplateFilter.all)) { whereClause += - * " INNER JOIN account a on (t.account_id = a.id)"; if ((templateFilter == - * TemplateFilter.self || templateFilter == TemplateFilter.selfexecutable) - * && (caller.getType() == Account.ACCOUNT_TYPE_DOMAIN_ADMIN || - * caller.getType() == Account.ACCOUNT_TYPE_RESOURCE_DOMAIN_ADMIN)) { - * whereClause += - * " INNER JOIN domain d on (a.domain_id = d.id) WHERE d.path LIKE '" + - * domain.getPath() + "%'"; if (listProjectResourcesCriteria == - * ListProjectResourcesCriteria.SkipProjectResources) { whereClause += - * " AND a.type != " + Account.ACCOUNT_TYPE_PROJECT; } } else if - * (listProjectResourcesCriteria == - * ListProjectResourcesCriteria.SkipProjectResources) { whereClause += - * " WHERE a.type != " + Account.ACCOUNT_TYPE_PROJECT; } } - * - * if (!permittedAccounts.isEmpty()) { for (Account account : - * permittedAccounts) { //accountType = account.getType(); //accountId = - * Long.toString(account.getId()); DomainVO accountDomain = - * _domainDao.findById(account.getDomainId()); - * - * // get all parent domain ID's all the way till root domain DomainVO - * domainTreeNode = accountDomain; while (true) { - * relatedDomainIds.append(domainTreeNode.getId()); - * relatedDomainIds.append(","); if (domainTreeNode.getParent() != null) { - * domainTreeNode = _domainDao.findById(domainTreeNode.getParent()); } else - * { break; } } - * - * // get all child domain ID's if (isAdmin(account.getType()) ) { - * List allChildDomains = - * _domainDao.findAllChildren(accountDomain.getPath(), - * accountDomain.getId()); for (DomainVO childDomain : allChildDomains) { - * relatedDomainIds.append(childDomain.getId()); - * relatedDomainIds.append(","); } } - * relatedDomainIds.setLength(relatedDomainIds.length()-1); } } - * - * String attr = " AND "; if (whereClause.endsWith(" WHERE ")) { attr += - * " WHERE "; } - * - * if (!isIso) { if ( hypers.isEmpty() ) { return templateZonePairList; } - * else { StringBuilder relatedHypers = new StringBuilder(); for - * (HypervisorType hyper : hypers ) { relatedHypers.append("'"); - * relatedHypers.append(hyper.toString()); relatedHypers.append("'"); - * relatedHypers.append(","); } - * relatedHypers.setLength(relatedHypers.length()-1); whereClause += attr + - * " t.hypervisor_type IN (" + relatedHypers + ")"; } } - * - * if (!permittedAccounts.isEmpty() && !(templateFilter == - * TemplateFilter.featured || templateFilter == TemplateFilter.community || - * templateFilter == TemplateFilter.executable || templateFilter == - * TemplateFilter.shared || templateFilter == - * TemplateFilter.sharedexecutable) && !isAdmin(caller.getType()) ) { - * whereClause += attr + "t.account_id IN (" + permittedAccountsStr + ")"; } - * - * if (templateFilter == TemplateFilter.featured) { whereClause += attr + - * "t.public = 1 AND t.featured = 1"; if (!permittedAccounts.isEmpty()) { - * whereClause += attr + "(dc.domain_id IN (" + relatedDomainIds + - * ") OR dc.domain_id is NULL)"; } } else if (templateFilter == - * TemplateFilter.self || templateFilter == TemplateFilter.selfexecutable) { - * whereClause += " AND t.account_id IN (" + permittedAccountsStr + ")"; } - * else if (templateFilter == TemplateFilter.sharedexecutable || - * templateFilter == TemplateFilter.shared ) { whereClause += " AND " + - * " (t.account_id IN (" + permittedAccountsStr + ") OR" + - * " lp.account_id IN (" + permittedAccountsStr + "))"; } else if - * (templateFilter == TemplateFilter.executable && - * !permittedAccounts.isEmpty()) { whereClause += attr + - * "(t.public = 1 OR t.account_id IN (" + permittedAccountsStr + "))"; } - * else if (templateFilter == TemplateFilter.community) { whereClause += - * attr + "t.public = 1 AND t.featured = 0"; if - * (!permittedAccounts.isEmpty()) { whereClause += attr + - * "(dc.domain_id IN (" + relatedDomainIds + ") OR dc.domain_id is NULL)"; } - * } else if (caller.getType() != Account.ACCOUNT_TYPE_ADMIN && !isIso) { - * return templateZonePairList; } - * - * if (tags != null && !tags.isEmpty()) { whereClause += " AND ("; boolean - * first = true; for (String key : tags.keySet()) { if (!first) { - * whereClause += " OR "; } whereClause += "(r.key=\"" + key + - * "\" and r.value=\"" + tags.get(key) + "\")"; first = false; } whereClause - * += ")"; } - * - * if (whereClause.equals("")) { whereClause += " WHERE "; } else if - * (!whereClause.equals(" WHERE ")) { whereClause += " AND "; } - * - * sql += whereClause + getExtrasWhere(templateFilter, name, keyword, isIso, - * bootable, hyperType, zoneId, onlyReady, showDomr, zoneType) + - * groupByClause + getOrderByLimit(pageSize, startIndex); - * - * pstmt = txn.prepareStatement(sql); rs = pstmt.executeQuery(); - * - * while (rs.next()) { Pair templateZonePair = new Pair(rs.getLong(1), rs.getLong(2)); - * templateZonePairList.add(templateZonePair); } //for now, defaulting - * pageSize to a large val if null; may need to revisit post 2.2RC2 if(isIso - * && templateZonePairList.size() < (pageSize != null ? pageSize : 500) && - * templateFilter != TemplateFilter.community && !(templateFilter == - * TemplateFilter.self && !BaseCmd.isRootAdmin(caller.getType())) ){ - * //evaluates to true If root admin and filter=self - * - * List publicIsos = publicIsoSearch(bootable, false, tags); - * List userIsos = userIsoSearch(false); - * - * //Listing the ISOs according to the page size.Restricting the total no. - * of ISOs on a page //to be less than or equal to the pageSize parameter - * - * int i=0; - * - * if (startIndex > userIsos.size()) { i=(int) (startIndex - - * userIsos.size()); } - * - * for (; i < publicIsos.size(); i++) { if(templateZonePairList.size() >= - * pageSize){ break; } else { if (keyword != null && - * publicIsos.get(i).getName().contains(keyword)) { - * templateZonePairList.add(new Pair(publicIsos.get(i).getId(), - * null)); continue; } else if (name != null && - * publicIsos.get(i).getName().contains(name)) { - * templateZonePairList.add(new Pair(publicIsos.get(i).getId(), - * null)); continue; } else if (keyword == null && name == null){ - * templateZonePairList.add(new Pair(publicIsos.get(i).getId(), - * null)); } } } } } catch (Exception e) { - * s_logger.warn("Error listing templates", e); } finally { try { if (rs != - * null) { rs.close(); } if (pstmt != null) { pstmt.close(); } txn.commit(); - * } catch( SQLException sqle) { s_logger.warn("Error in cleaning up", - * sqle); } } - * - * return templateZonePairList; } - */ - - /* - * private String getExtrasWhere(TemplateFilter templateFilter, String name, - * String keyword, boolean isIso, Boolean bootable, HypervisorType - * hyperType, Long zoneId, boolean onlyReady, boolean showDomr, String - * zoneType) { String sql = ""; if (keyword != null) { sql += - * " t.name LIKE \"%" + keyword + "%\" AND"; } else if (name != null) { sql - * += " t.name LIKE \"%" + name + "%\" AND"; } - * - * if (isIso) { sql += " t.format = 'ISO'"; if - * (!hyperType.equals(HypervisorType.None)) { sql += - * " AND goh.hypervisor_type = '" + hyperType.toString() + "'"; } } else { - * sql += " t.format <> 'ISO'"; if (!hyperType.equals(HypervisorType.None)) - * { sql += " AND t.hypervisor_type = '" + hyperType.toString() + "'"; } } - * - * if (bootable != null) { sql += " AND t.bootable = " + bootable; } - * - * if (onlyReady){ sql += " AND thr.download_state = '" - * +Status.DOWNLOADED.toString() + "'" + " AND thr.destroyed=0 "; if (zoneId - * != null){ sql += " AND h.data_center_id = " +zoneId; } }else if (zoneId - * != null){ sql += " AND tzr.zone_id = " +zoneId+ - * " AND tzr.removed is null" ; }else{ sql += " AND tzr.removed is null "; } - * - * if (zoneType != null){ sql += " AND dc.networktype = '" + zoneType + "'"; - * } - * - * if (!showDomr){ sql += " AND t.type != '" - * +Storage.TemplateType.SYSTEM.toString() + "'"; } - * - * sql += " AND t.removed IS NULL"; - * - * return sql; } - * - * private String getOrderByLimit(Long pageSize, Long startIndex) { Boolean - * isAscending = - * Boolean.parseBoolean(_configDao.getValue("sortkey.algorithm")); - * isAscending = (isAscending == null ? true : isAscending); - * - * String sql; if (isAscending) { sql = " ORDER BY t.sort_key ASC"; } else { - * sql = " ORDER BY t.sort_key DESC"; } - * - * if ((pageSize != null) && (startIndex != null)) { sql += " LIMIT " + - * startIndex.toString() + "," + pageSize.toString(); } return sql; } - */ - @SuppressWarnings("unchecked") @Override @DB @@ -973,102 +624,6 @@ public boolean remove(Long id) { return result; } - @Override - public List findTemplatesToSyncToS3() { - return executeList(SELECT_S3_CANDIDATE_TEMPLATES, new Object[] {}); - } - - /* - * @Override public Set> searchS3Templates(final String - * name, final String keyword, final TemplateFilter templateFilter, final - * boolean isIso, final List hypers, final Boolean bootable, - * final DomainVO domain, final Long pageSize, final Long startIndex, final - * Long zoneId, final HypervisorType hyperType, final boolean onlyReady, - * final boolean showDomr, final List permittedAccounts, final - * Account caller, final Map tags) { - * - * final String permittedAccountsStr = join(",", permittedAccounts); - * - * final TransactionLegacy txn = TransactionLegacy.currentTxn(); txn.start(); - * - * Set> templateZonePairList = new HashSet>(); PreparedStatement pstmt = null; ResultSet rs = null; try { - * - * final StringBuilder joinClause = new StringBuilder(); final StringBuilder - * whereClause = new StringBuilder(" WHERE t.removed IS NULL"); - * - * if (isIso) { whereClause.append(" AND t.format = 'ISO'"); if - * (!hyperType.equals(HypervisorType.None)) { joinClause.append( - * " INNER JOIN guest_os guestOS on (guestOS.id = t.guest_os_id) INNER JOIN guest_os_hypervisor goh on ( goh.guest_os_id = guestOS.id) " - * ); whereClause.append(" AND goh.hypervisor_type = '"); - * whereClause.append(hyperType); whereClause.append("'"); } } else { - * whereClause.append(" AND t.format <> 'ISO'"); if (hypers.isEmpty()) { - * return templateZonePairList; } else { final StringBuilder relatedHypers = - * new StringBuilder(); for (HypervisorType hyper : hypers) { - * relatedHypers.append("'"); relatedHypers.append(hyper.toString()); - * relatedHypers.append("'"); relatedHypers.append(","); } - * relatedHypers.setLength(relatedHypers.length() - 1); - * whereClause.append(" AND t.hypervisor_type IN ("); - * whereClause.append(relatedHypers); whereClause.append(")"); } } - * - * joinClause.append( - * " INNER JOIN template_s3_ref tsr on (t.id = tsr.template_id)"); - * - * whereClause.append("AND t.name LIKE \"%"); whereClause.append(keyword == - * null ? keyword : name); whereClause.append("%\""); - * - * if (bootable != null) { whereClause.append(" AND t.bootable = "); - * whereClause.append(bootable); } - * - * if (!showDomr) { whereClause.append(" AND t.type != '"); - * whereClause.append(Storage.TemplateType.SYSTEM); whereClause.append("'"); - * } - * - * if (templateFilter == TemplateFilter.featured) { - * whereClause.append(" AND t.public = 1 AND t.featured = 1"); } else if - * ((templateFilter == TemplateFilter.self || templateFilter == - * TemplateFilter.selfexecutable) && caller.getType() != - * Account.ACCOUNT_TYPE_ADMIN) { if (caller.getType() == - * Account.ACCOUNT_TYPE_DOMAIN_ADMIN || caller.getType() == - * Account.ACCOUNT_TYPE_RESOURCE_DOMAIN_ADMIN) { joinClause.append( - * " INNER JOIN account a on (t.account_id = a.id) INNER JOIN domain d on (a.domain_id = d.id)" - * ); whereClause.append(" AND d.path LIKE '"); - * whereClause.append(domain.getPath()); whereClause.append("%'"); } else { - * whereClause.append(" AND t.account_id IN ("); - * whereClause.append(permittedAccountsStr); whereClause.append(")"); } } - * else if (templateFilter == TemplateFilter.sharedexecutable && - * caller.getType() != Account.ACCOUNT_TYPE_ADMIN) { if (caller.getType() == - * Account.ACCOUNT_TYPE_NORMAL) { joinClause.append( - * " LEFT JOIN launch_permission lp ON t.id = lp.template_id WHERE (t.account_id IN (" - * ); joinClause.append(permittedAccountsStr); - * joinClause.append(") OR lp.account_id IN ("); - * joinClause.append(permittedAccountsStr); joinClause.append("))"); } else - * { joinClause.append(" INNER JOIN account a on (t.account_id = a.id) "); } - * } else if (templateFilter == TemplateFilter.executable && - * !permittedAccounts.isEmpty()) { - * whereClause.append(" AND (t.public = 1 OR t.account_id IN ("); - * whereClause.append(permittedAccountsStr); whereClause.append("))"); } - * else if (templateFilter == TemplateFilter.community) { - * whereClause.append(" AND t.public = 1 AND t.featured = 0"); } else if - * (templateFilter == TemplateFilter.all && caller.getType() == - * Account.ACCOUNT_TYPE_ADMIN) { } else if (caller.getType() != - * Account.ACCOUNT_TYPE_ADMIN) { return templateZonePairList; } - * - * final StringBuilder sql = new StringBuilder(SELECT_TEMPLATE_S3_REF); - * sql.append(joinClause); sql.append(whereClause); - * sql.append(getOrderByLimit(pageSize, startIndex)); - * - * pstmt = txn.prepareStatement(sql.toString()); rs = pstmt.executeQuery(); - * while (rs.next()) { final Pair templateZonePair = new - * Pair( rs.getLong(1), -1L); - * templateZonePairList.add(templateZonePair); } txn.commit(); } catch - * (Exception e) { s_logger.warn("Error listing S3 templates", e); if (txn - * != null) { txn.rollback(); } } finally { closeResources(pstmt, rs); if - * (txn != null) { txn.close(); } } - * - * return templateZonePairList; } - */ - @Override public boolean updateState( com.cloud.template.VirtualMachineTemplate.State currentState, diff --git a/engine/schema/src/main/java/com/cloud/storage/dao/VMTemplateHostDao.java b/engine/schema/src/main/java/com/cloud/storage/dao/VMTemplateHostDao.java deleted file mode 100644 index 7190d1c16116..000000000000 --- a/engine/schema/src/main/java/com/cloud/storage/dao/VMTemplateHostDao.java +++ /dev/null @@ -1,68 +0,0 @@ -// 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.storage.dao; - -import java.util.List; - -import org.apache.cloudstack.engine.subsystem.api.storage.DataObjectInStore; -import org.apache.cloudstack.engine.subsystem.api.storage.ObjectInDataStoreStateMachine; - -import com.cloud.storage.VMTemplateHostVO; -import com.cloud.storage.VMTemplateStorageResourceAssoc.Status; -import com.cloud.utils.db.GenericDao; -import com.cloud.utils.fsm.StateDao; - -public interface VMTemplateHostDao extends GenericDao, - StateDao { - List listByHostId(long id); - - List listByTemplateId(long templateId); - - List listByOnlyTemplateId(long templateId); - - VMTemplateHostVO findByHostTemplate(long hostId, long templateId); - - VMTemplateHostVO findByTemplateId(long templateId); - - VMTemplateHostVO findByHostTemplate(long hostId, long templateId, boolean lock); - - List listByHostTemplate(long hostId, long templateId); - - void update(VMTemplateHostVO instance); - - List listByTemplateStatus(long templateId, VMTemplateHostVO.Status downloadState); - - List listByTemplateStatus(long templateId, long datacenterId, VMTemplateHostVO.Status downloadState); - - List listByTemplateStatus(long templateId, long datacenterId, long podId, VMTemplateHostVO.Status downloadState); - - List listByTemplateStates(long templateId, VMTemplateHostVO.Status... states); - - List listDestroyed(long hostId); - - boolean templateAvailable(long templateId, long hostId); - - List listByZoneTemplate(long dcId, long templateId, boolean readyOnly); - - void deleteByHost(Long hostId); - - VMTemplateHostVO findLocalSecondaryStorageByHostTemplate(long hostId, long templateId); - - List listByTemplateHostStatus(long templateId, long hostId, Status... states); - - List listByState(Status state); -} diff --git a/engine/schema/src/main/java/com/cloud/storage/dao/VMTemplateHostDaoImpl.java b/engine/schema/src/main/java/com/cloud/storage/dao/VMTemplateHostDaoImpl.java deleted file mode 100644 index 5f7a2d78e2c6..000000000000 --- a/engine/schema/src/main/java/com/cloud/storage/dao/VMTemplateHostDaoImpl.java +++ /dev/null @@ -1,431 +0,0 @@ -// 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.storage.dao; - -import java.sql.PreparedStatement; -import java.sql.ResultSet; -import java.sql.SQLException; -import java.util.ArrayList; -import java.util.Date; -import java.util.List; -import java.util.Map; -import java.util.TimeZone; - -import javax.inject.Inject; -import javax.naming.ConfigurationException; - -import org.apache.log4j.Logger; -import org.springframework.stereotype.Component; - -import org.apache.cloudstack.engine.subsystem.api.storage.DataObjectInStore; -import org.apache.cloudstack.engine.subsystem.api.storage.ObjectInDataStoreStateMachine.Event; -import org.apache.cloudstack.engine.subsystem.api.storage.ObjectInDataStoreStateMachine.State; - -import com.cloud.host.Host; -import com.cloud.host.HostVO; -import com.cloud.host.dao.HostDao; -import com.cloud.storage.VMTemplateHostVO; -import com.cloud.storage.VMTemplateStorageResourceAssoc.Status; -import com.cloud.utils.DateUtil; -import com.cloud.utils.db.GenericDaoBase; -import com.cloud.utils.db.JoinBuilder; -import com.cloud.utils.db.SearchBuilder; -import com.cloud.utils.db.SearchCriteria; -import com.cloud.utils.db.SearchCriteria.Op; -import com.cloud.utils.db.TransactionLegacy; -import com.cloud.utils.db.UpdateBuilder; - -@Component -public class VMTemplateHostDaoImpl extends GenericDaoBase implements VMTemplateHostDao { - public static final Logger s_logger = Logger.getLogger(VMTemplateHostDaoImpl.class.getName()); - @Inject - HostDao _hostDao; - protected final SearchBuilder HostSearch; - protected final SearchBuilder TemplateSearch; - protected final SearchBuilder HostTemplateSearch; - protected final SearchBuilder HostTemplateStateSearch; - protected final SearchBuilder HostDestroyedSearch; - protected final SearchBuilder TemplateStatusSearch; - protected final SearchBuilder TemplateStatesSearch; - protected final SearchBuilder updateStateSearch; - protected SearchBuilder ZoneTemplateSearch; - protected SearchBuilder LocalSecondaryStorageSearch; - - protected static final String UPDATE_TEMPLATE_HOST_REF = "UPDATE template_host_ref SET download_state = ?, download_pct= ?, last_updated = ? " - + ", error_str = ?, local_path = ?, job_id = ? " + "WHERE host_id = ? and type_id = ?"; - - protected static final String DOWNLOADS_STATE_DC = "SELECT t.id, t.host_id, t.template_id, t.created, t.last_updated, t.job_id, " - + "t.download_pct, t.size, t.physical_size, t.download_state, t.error_str, t.local_path, " - + "t.install_path, t.url, t.destroyed, t.is_copy FROM template_host_ref t, host h " + "where t.host_id = h.id and h.data_center_id=? " - + " and t.template_id=? and t.download_state = ?"; - - protected static final String DOWNLOADS_STATE_DC_POD = "SELECT * FROM template_host_ref t, host h where t.host_id = h.id and h.data_center_id=? and h.pod_id=? " - + " and t.template_id=? and t.download_state=?"; - - protected static final String DOWNLOADS_STATE = "SELECT * FROM template_host_ref t " + " where t.template_id=? and t.download_state=?"; - - public VMTemplateHostDaoImpl() { - HostSearch = createSearchBuilder(); - HostSearch.and("host_id", HostSearch.entity().getHostId(), SearchCriteria.Op.EQ); - HostSearch.done(); - - TemplateSearch = createSearchBuilder(); - TemplateSearch.and("template_id", TemplateSearch.entity().getTemplateId(), SearchCriteria.Op.EQ); - TemplateSearch.and("destroyed", TemplateSearch.entity().getDestroyed(), SearchCriteria.Op.EQ); - TemplateSearch.done(); - - HostTemplateSearch = createSearchBuilder(); - HostTemplateSearch.and("host_id", HostTemplateSearch.entity().getHostId(), SearchCriteria.Op.EQ); - HostTemplateSearch.and("template_id", HostTemplateSearch.entity().getTemplateId(), SearchCriteria.Op.EQ); - HostTemplateSearch.and("destroyed", HostTemplateSearch.entity().getDestroyed(), SearchCriteria.Op.EQ); - HostTemplateSearch.done(); - - HostDestroyedSearch = createSearchBuilder(); - HostDestroyedSearch.and("host_id", HostDestroyedSearch.entity().getHostId(), SearchCriteria.Op.EQ); - HostDestroyedSearch.and("destroyed", HostDestroyedSearch.entity().getDestroyed(), SearchCriteria.Op.EQ); - HostDestroyedSearch.done(); - - TemplateStatusSearch = createSearchBuilder(); - TemplateStatusSearch.and("template_id", TemplateStatusSearch.entity().getTemplateId(), SearchCriteria.Op.EQ); - TemplateStatusSearch.and("download_state", TemplateStatusSearch.entity().getDownloadState(), SearchCriteria.Op.EQ); - TemplateStatusSearch.and("destroyed", TemplateStatusSearch.entity().getDestroyed(), SearchCriteria.Op.EQ); - TemplateStatusSearch.done(); - - TemplateStatesSearch = createSearchBuilder(); - TemplateStatesSearch.and("template_id", TemplateStatesSearch.entity().getTemplateId(), SearchCriteria.Op.EQ); - TemplateStatesSearch.and("states", TemplateStatesSearch.entity().getDownloadState(), SearchCriteria.Op.IN); - TemplateStatesSearch.and("destroyed", TemplateStatesSearch.entity().getDestroyed(), SearchCriteria.Op.EQ); - TemplateStatesSearch.done(); - - HostTemplateStateSearch = createSearchBuilder(); - HostTemplateStateSearch.and("template_id", HostTemplateStateSearch.entity().getTemplateId(), SearchCriteria.Op.EQ); - HostTemplateStateSearch.and("host_id", HostTemplateStateSearch.entity().getHostId(), SearchCriteria.Op.EQ); - HostTemplateStateSearch.and("states", HostTemplateStateSearch.entity().getDownloadState(), SearchCriteria.Op.IN); - HostTemplateStateSearch.and("destroyed", HostTemplateStateSearch.entity().getDestroyed(), SearchCriteria.Op.EQ); - HostTemplateStateSearch.done(); - - updateStateSearch = this.createSearchBuilder(); - updateStateSearch.and("id", updateStateSearch.entity().getId(), Op.EQ); - updateStateSearch.and("state", updateStateSearch.entity().getState(), Op.EQ); - updateStateSearch.and("updatedCount", updateStateSearch.entity().getUpdatedCount(), Op.EQ); - updateStateSearch.done(); - - } - - @Override - public boolean configure(String name, Map params) throws ConfigurationException { - boolean result = super.configure(name, params); - ZoneTemplateSearch = createSearchBuilder(); - ZoneTemplateSearch.and("template_id", ZoneTemplateSearch.entity().getTemplateId(), SearchCriteria.Op.EQ); - ZoneTemplateSearch.and("state", ZoneTemplateSearch.entity().getDownloadState(), SearchCriteria.Op.EQ); - SearchBuilder hostSearch = _hostDao.createSearchBuilder(); - hostSearch.and("zone_id", hostSearch.entity().getDataCenterId(), SearchCriteria.Op.EQ); - ZoneTemplateSearch.join("tmplHost", hostSearch, hostSearch.entity().getId(), ZoneTemplateSearch.entity().getHostId(), JoinBuilder.JoinType.INNER); - ZoneTemplateSearch.done(); - - LocalSecondaryStorageSearch = createSearchBuilder(); - LocalSecondaryStorageSearch.and("template_id", LocalSecondaryStorageSearch.entity().getTemplateId(), SearchCriteria.Op.EQ); - LocalSecondaryStorageSearch.and("state", LocalSecondaryStorageSearch.entity().getDownloadState(), SearchCriteria.Op.EQ); - SearchBuilder localSecondaryHost = _hostDao.createSearchBuilder(); - localSecondaryHost.and("private_ip_address", localSecondaryHost.entity().getPrivateIpAddress(), SearchCriteria.Op.EQ); - localSecondaryHost.and("state", localSecondaryHost.entity().getStatus(), SearchCriteria.Op.EQ); - localSecondaryHost.and("data_center_id", localSecondaryHost.entity().getDataCenterId(), SearchCriteria.Op.EQ); - localSecondaryHost.and("type", localSecondaryHost.entity().getType(), SearchCriteria.Op.EQ); - LocalSecondaryStorageSearch.join("host", localSecondaryHost, localSecondaryHost.entity().getId(), LocalSecondaryStorageSearch.entity().getHostId(), - JoinBuilder.JoinType.INNER); - LocalSecondaryStorageSearch.done(); - - return result; - } - - @Override - public void update(VMTemplateHostVO instance) { - TransactionLegacy txn = TransactionLegacy.currentTxn(); - PreparedStatement pstmt = null; - try { - Date now = new Date(); - String sql = UPDATE_TEMPLATE_HOST_REF; - pstmt = txn.prepareAutoCloseStatement(sql); - pstmt.setString(1, instance.getDownloadState().toString()); - pstmt.setInt(2, instance.getDownloadPercent()); - pstmt.setString(3, DateUtil.getDateDisplayString(TimeZone.getTimeZone("GMT"), now)); - pstmt.setString(4, instance.getErrorString()); - pstmt.setString(5, instance.getLocalDownloadPath()); - pstmt.setString(6, instance.getJobId()); - pstmt.setLong(7, instance.getHostId()); - pstmt.setLong(8, instance.getTemplateId()); - pstmt.executeUpdate(); - } catch (Exception e) { - s_logger.warn("Exception: ", e); - } - } - - @Override - public List listByHostId(long id) { - SearchCriteria sc = HostSearch.create(); - sc.setParameters("host_id", id); - return listIncludingRemovedBy(sc); - } - - @Override - public List listByTemplateId(long templateId) { - SearchCriteria sc = TemplateSearch.create(); - sc.setParameters("template_id", templateId); - sc.setParameters("destroyed", false); - return listIncludingRemovedBy(sc); - } - - @Override - public List listByOnlyTemplateId(long templateId) { - SearchCriteria sc = TemplateSearch.create(); - sc.setParameters("template_id", templateId); - sc.setParameters("destroyed", false); - return listIncludingRemovedBy(sc); - } - - @Override - public VMTemplateHostVO findByHostTemplate(long hostId, long templateId) { - SearchCriteria sc = HostTemplateSearch.create(); - sc.setParameters("host_id", hostId); - sc.setParameters("template_id", templateId); - sc.setParameters("destroyed", false); - return findOneIncludingRemovedBy(sc); - } - - @Override - public VMTemplateHostVO findByTemplateId(long templateId) { - SearchCriteria sc = HostTemplateSearch.create(); - sc.setParameters("template_id", templateId); - sc.setParameters("destroyed", false); - return findOneIncludingRemovedBy(sc); - } - - @Override - public List listByTemplateStatus(long templateId, VMTemplateHostVO.Status downloadState) { - SearchCriteria sc = TemplateStatusSearch.create(); - sc.setParameters("template_id", templateId); - sc.setParameters("download_state", downloadState.toString()); - sc.setParameters("destroyed", false); - return listIncludingRemovedBy(sc); - } - - @Override - public List listByTemplateStatus(long templateId, long datacenterId, VMTemplateHostVO.Status downloadState) { - TransactionLegacy txn = TransactionLegacy.currentTxn(); - PreparedStatement pstmt = null; - List result = new ArrayList(); - try { - String sql = DOWNLOADS_STATE_DC; - pstmt = txn.prepareAutoCloseStatement(sql); - pstmt.setLong(1, datacenterId); - pstmt.setLong(2, templateId); - pstmt.setString(3, downloadState.toString()); - ResultSet rs = pstmt.executeQuery(); - while (rs.next()) { - result.add(toEntityBean(rs, false)); - } - } catch (Exception e) { - s_logger.warn("Exception: ", e); - } - return result; - } - - @Override - public List listByTemplateHostStatus(long templateId, long hostId, VMTemplateHostVO.Status... states) { - SearchCriteria sc = HostTemplateStateSearch.create(); - sc.setParameters("template_id", templateId); - sc.setParameters("host_id", hostId); - sc.setParameters("states", (Object[])states); - return search(sc, null); - } - - @Override - public List listByTemplateStatus(long templateId, long datacenterId, long podId, VMTemplateHostVO.Status downloadState) { - TransactionLegacy txn = TransactionLegacy.currentTxn(); - List result = new ArrayList(); - String sql = DOWNLOADS_STATE_DC_POD; - try(PreparedStatement pstmt = txn.prepareStatement(sql);) { - pstmt.setLong(1, datacenterId); - pstmt.setLong(2, podId); - pstmt.setLong(3, templateId); - pstmt.setString(4, downloadState.toString()); - try(ResultSet rs = pstmt.executeQuery();) { - while (rs.next()) { - // result.add(toEntityBean(rs, false)); TODO: this is buggy in - // GenericDaoBase for hand constructed queries - long id = rs.getLong(1); // ID column - result.add(findById(id)); - } - }catch (SQLException e) { - s_logger.warn("listByTemplateStatus:Exception: "+e.getMessage(), e); - } - } catch (Exception e) { - s_logger.warn("listByTemplateStatus:Exception: "+e.getMessage(), e); - } - return result; - - } - - @Override - public boolean templateAvailable(long templateId, long hostId) { - VMTemplateHostVO tmpltHost = findByHostTemplate(hostId, templateId); - if (tmpltHost == null) - return false; - - return tmpltHost.getDownloadState() == Status.DOWNLOADED; - } - - @Override - public List listByTemplateStates(long templateId, VMTemplateHostVO.Status... states) { - SearchCriteria sc = TemplateStatesSearch.create(); - sc.setParameters("states", (Object[])states); - sc.setParameters("template_id", templateId); - sc.setParameters("destroyed", false); - return search(sc, null); - } - - @Override - public List listByState(VMTemplateHostVO.Status state) { - SearchCriteria sc = createSearchCriteria(); - sc.addAnd("downloadState", SearchCriteria.Op.EQ, state); - sc.addAnd("destroyed", SearchCriteria.Op.EQ, false); - return search(sc, null); - } - - @Override - public List listByHostTemplate(long hostId, long templateId) { - SearchCriteria sc = HostTemplateSearch.create(); - sc.setParameters("host_id", hostId); - sc.setParameters("template_id", templateId); - sc.setParameters("destroyed", false); - return listIncludingRemovedBy(sc); - } - - @Override - public List listByZoneTemplate(long dcId, long templateId, boolean readyOnly) { - SearchCriteria sc = ZoneTemplateSearch.create(); - sc.setParameters("template_id", templateId); - sc.setJoinParameters("tmplHost", "zone_id", dcId); - if (readyOnly) { - sc.setParameters("state", VMTemplateHostVO.Status.DOWNLOADED); - } - return listBy(sc); - } - - @Override - public List listDestroyed(long hostId) { - SearchCriteria sc = HostDestroyedSearch.create(); - sc.setParameters("host_id", hostId); - sc.setParameters("destroyed", true); - return listIncludingRemovedBy(sc); - } - - @Override - public VMTemplateHostVO findByHostTemplate(long hostId, long templateId, boolean lock) { - SearchCriteria sc = HostTemplateSearch.create(); - sc.setParameters("host_id", hostId); - sc.setParameters("template_id", templateId); - sc.setParameters("destroyed", false); - if (!lock) - return findOneIncludingRemovedBy(sc); - else - return lockOneRandomRow(sc, true); - } - - // Based on computing node host id, and template id, find out the - // corresponding template_host_ref, assuming local secondary storage and - // computing node is in the same zone, and private ip - @Override - public VMTemplateHostVO findLocalSecondaryStorageByHostTemplate(long hostId, long templateId) { - HostVO computingHost = _hostDao.findById(hostId); - SearchCriteria sc = LocalSecondaryStorageSearch.create(); - sc.setJoinParameters("host", "private_ip_address", computingHost.getPrivateIpAddress()); - sc.setJoinParameters("host", "state", com.cloud.host.Status.Up); - sc.setJoinParameters("host", "data_center_id", computingHost.getDataCenterId()); - sc.setJoinParameters("host", "type", Host.Type.LocalSecondaryStorage); - sc.setParameters("template_id", templateId); - sc.setParameters("state", VMTemplateHostVO.Status.DOWNLOADED); - sc.setParameters("destroyed", false); - return findOneBy(sc); - } - - @Override - public void deleteByHost(Long hostId) { - List tmpltHosts = listByHostId(hostId); - for (VMTemplateHostVO tmpltHost : tmpltHosts) { - remove(tmpltHost.getId()); - } - } - - @Override - public boolean updateState(State currentState, Event event, State nextState, DataObjectInStore vo, Object data) { - VMTemplateHostVO templateHost = (VMTemplateHostVO)vo; - Long oldUpdated = templateHost.getUpdatedCount(); - Date oldUpdatedTime = templateHost.getUpdated(); - - SearchCriteria sc = updateStateSearch.create(); - sc.setParameters("id", templateHost.getId()); - sc.setParameters("state", currentState); - sc.setParameters("updatedCount", templateHost.getUpdatedCount()); - - templateHost.incrUpdatedCount(); - - UpdateBuilder builder = getUpdateBuilder(vo); - builder.set(vo, "state", nextState); - builder.set(vo, "updated", new Date()); - - int rows = update((VMTemplateHostVO)vo, sc); - if (rows == 0 && s_logger.isDebugEnabled()) { - VMTemplateHostVO dbVol = findByIdIncludingRemoved(templateHost.getId()); - if (dbVol != null) { - StringBuilder str = new StringBuilder("Unable to update ").append(vo.toString()); - str.append(": DB Data={id=") - .append(dbVol.getId()) - .append("; state=") - .append(dbVol.getState()) - .append("; updatecount=") - .append(dbVol.getUpdatedCount()) - .append(";updatedTime=") - .append(dbVol.getUpdated()); - str.append(": New Data={id=") - .append(templateHost.getId()) - .append("; state=") - .append(nextState) - .append("; event=") - .append(event) - .append("; updatecount=") - .append(templateHost.getUpdatedCount()) - .append("; updatedTime=") - .append(templateHost.getUpdated()); - str.append(": stale Data={id=") - .append(templateHost.getId()) - .append("; state=") - .append(currentState) - .append("; event=") - .append(event) - .append("; updatecount=") - .append(oldUpdated) - .append("; updatedTime=") - .append(oldUpdatedTime); - } else { - s_logger.debug("Unable to update objectIndatastore: id=" + templateHost.getId() + ", as there is no such object exists in the database anymore"); - } - } - return rows > 0; - } - -} diff --git a/engine/schema/src/main/java/com/cloud/storage/dao/VMTemplatePoolDaoImpl.java b/engine/schema/src/main/java/com/cloud/storage/dao/VMTemplatePoolDaoImpl.java index 998df5e7987d..c9bd769bc5b7 100644 --- a/engine/schema/src/main/java/com/cloud/storage/dao/VMTemplatePoolDaoImpl.java +++ b/engine/schema/src/main/java/com/cloud/storage/dao/VMTemplatePoolDaoImpl.java @@ -62,7 +62,7 @@ public class VMTemplatePoolDaoImpl extends GenericDaoBase updateStateSearch; protected final SearchBuilder templatePathSearch; - protected static final String UPDATE_TEMPLATE_HOST_REF = "UPDATE template_spool_ref SET download_state = ?, download_pct= ?, last_updated = ? " + protected static final String UPDATE_TEMPLATE_SPOOL_HOST_REF = "UPDATE template_spool_ref SET download_state = ?, download_pct= ?, last_updated = ? " + ", error_str = ?, local_path = ?, job_id = ? " + "WHERE pool_id = ? and template_id = ?"; protected static final String DOWNLOADS_STATE_DC = "SELECT * FROM template_spool_ref t, storage_pool p where t.pool_id = p.id and p.data_center_id=? " diff --git a/engine/schema/src/main/java/com/cloud/storage/dao/VolumeHostDao.java b/engine/schema/src/main/java/com/cloud/storage/dao/VolumeHostDao.java deleted file mode 100644 index ccb276b47f9f..000000000000 --- a/engine/schema/src/main/java/com/cloud/storage/dao/VolumeHostDao.java +++ /dev/null @@ -1,41 +0,0 @@ -// 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.storage.dao; - -import java.util.List; - -import org.apache.cloudstack.engine.subsystem.api.storage.DataObjectInStore; -import org.apache.cloudstack.engine.subsystem.api.storage.ObjectInDataStoreStateMachine; - -import com.cloud.storage.VolumeHostVO; -import com.cloud.utils.db.GenericDao; -import com.cloud.utils.fsm.StateDao; - -public interface VolumeHostDao extends GenericDao, - StateDao { - - VolumeHostVO findByHostVolume(long hostId, long volumeId); - - VolumeHostVO findByVolumeId(long volumeId); - - List listBySecStorage(long sserverId); - - List listDestroyed(long hostId); - - VolumeHostVO findVolumeByZone(long zoneId, long volumeId); - -} diff --git a/engine/schema/src/main/java/com/cloud/storage/dao/VolumeHostDaoImpl.java b/engine/schema/src/main/java/com/cloud/storage/dao/VolumeHostDaoImpl.java deleted file mode 100644 index ce2251300a2b..000000000000 --- a/engine/schema/src/main/java/com/cloud/storage/dao/VolumeHostDaoImpl.java +++ /dev/null @@ -1,181 +0,0 @@ -// 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.storage.dao; - -import java.util.Date; -import java.util.List; - - -import org.apache.log4j.Logger; -import org.springframework.stereotype.Component; - -import org.apache.cloudstack.engine.subsystem.api.storage.DataObjectInStore; -import org.apache.cloudstack.engine.subsystem.api.storage.ObjectInDataStoreStateMachine.Event; -import org.apache.cloudstack.engine.subsystem.api.storage.ObjectInDataStoreStateMachine.State; - -import com.cloud.storage.VolumeHostVO; -import com.cloud.utils.db.GenericDaoBase; -import com.cloud.utils.db.SearchBuilder; -import com.cloud.utils.db.SearchCriteria; -import com.cloud.utils.db.SearchCriteria.Op; -import com.cloud.utils.db.UpdateBuilder; - -@Component -public class VolumeHostDaoImpl extends GenericDaoBase implements VolumeHostDao { - private static final Logger s_logger = Logger.getLogger(VolumeHostDaoImpl.class); - protected final SearchBuilder HostVolumeSearch; - protected final SearchBuilder ZoneVolumeSearch; - protected final SearchBuilder VolumeSearch; - protected final SearchBuilder HostSearch; - protected final SearchBuilder HostDestroyedSearch; - protected final SearchBuilder updateStateSearch; - - public VolumeHostDaoImpl() { - HostVolumeSearch = createSearchBuilder(); - HostVolumeSearch.and("host_id", HostVolumeSearch.entity().getHostId(), SearchCriteria.Op.EQ); - HostVolumeSearch.and("volume_id", HostVolumeSearch.entity().getVolumeId(), SearchCriteria.Op.EQ); - HostVolumeSearch.and("destroyed", HostVolumeSearch.entity().getDestroyed(), SearchCriteria.Op.EQ); - HostVolumeSearch.done(); - - ZoneVolumeSearch = createSearchBuilder(); - ZoneVolumeSearch.and("zone_id", ZoneVolumeSearch.entity().getZoneId(), SearchCriteria.Op.EQ); - ZoneVolumeSearch.and("volume_id", ZoneVolumeSearch.entity().getVolumeId(), SearchCriteria.Op.EQ); - ZoneVolumeSearch.and("destroyed", ZoneVolumeSearch.entity().getDestroyed(), SearchCriteria.Op.EQ); - ZoneVolumeSearch.done(); - - HostSearch = createSearchBuilder(); - HostSearch.and("host_id", HostSearch.entity().getHostId(), SearchCriteria.Op.EQ); - HostSearch.and("destroyed", HostSearch.entity().getDestroyed(), SearchCriteria.Op.EQ); - HostSearch.done(); - - VolumeSearch = createSearchBuilder(); - VolumeSearch.and("volume_id", VolumeSearch.entity().getVolumeId(), SearchCriteria.Op.EQ); - VolumeSearch.and("destroyed", VolumeSearch.entity().getDestroyed(), SearchCriteria.Op.EQ); - VolumeSearch.done(); - - HostDestroyedSearch = createSearchBuilder(); - HostDestroyedSearch.and("host_id", HostDestroyedSearch.entity().getHostId(), SearchCriteria.Op.EQ); - HostDestroyedSearch.and("destroyed", HostDestroyedSearch.entity().getDestroyed(), SearchCriteria.Op.EQ); - HostDestroyedSearch.done(); - - updateStateSearch = this.createSearchBuilder(); - updateStateSearch.and("id", updateStateSearch.entity().getId(), Op.EQ); - updateStateSearch.and("state", updateStateSearch.entity().getState(), Op.EQ); - updateStateSearch.and("updatedCount", updateStateSearch.entity().getUpdatedCount(), Op.EQ); - updateStateSearch.done(); - } - - @Override - public VolumeHostVO findByHostVolume(long hostId, long volumeId) { - SearchCriteria sc = HostVolumeSearch.create(); - sc.setParameters("host_id", hostId); - sc.setParameters("volume_id", volumeId); - sc.setParameters("destroyed", false); - return findOneIncludingRemovedBy(sc); - } - - @Override - public VolumeHostVO findVolumeByZone(long volumeId, long zoneId) { - SearchCriteria sc = ZoneVolumeSearch.create(); - sc.setParameters("zone_id", zoneId); - sc.setParameters("volume_id", volumeId); - sc.setParameters("destroyed", false); - return findOneIncludingRemovedBy(sc); - } - - @Override - public VolumeHostVO findByVolumeId(long volumeId) { - SearchCriteria sc = VolumeSearch.create(); - sc.setParameters("volume_id", volumeId); - sc.setParameters("destroyed", false); - return findOneBy(sc); - } - - @Override - public List listBySecStorage(long ssHostId) { - SearchCriteria sc = HostSearch.create(); - sc.setParameters("host_id", ssHostId); - sc.setParameters("destroyed", false); - return listAll(); - } - - @Override - public List listDestroyed(long hostId) { - SearchCriteria sc = HostDestroyedSearch.create(); - sc.setParameters("host_id", hostId); - sc.setParameters("destroyed", true); - return listIncludingRemovedBy(sc); - } - - @Override - public boolean updateState(State currentState, Event event, State nextState, DataObjectInStore vo, Object data) { - VolumeHostVO volHost = (VolumeHostVO)vo; - Long oldUpdated = volHost.getUpdatedCount(); - Date oldUpdatedTime = volHost.getUpdated(); - - SearchCriteria sc = updateStateSearch.create(); - sc.setParameters("id", volHost.getId()); - sc.setParameters("state", currentState); - sc.setParameters("updatedCount", volHost.getUpdatedCount()); - - volHost.incrUpdatedCount(); - - UpdateBuilder builder = getUpdateBuilder(vo); - builder.set(vo, "state", nextState); - builder.set(vo, "updated", new Date()); - - int rows = update((VolumeHostVO)vo, sc); - if (rows == 0 && s_logger.isDebugEnabled()) { - VolumeHostVO dbVol = findByIdIncludingRemoved(volHost.getId()); - if (dbVol != null) { - StringBuilder str = new StringBuilder("Unable to update ").append(vo.toString()); - str.append(": DB Data={id=") - .append(dbVol.getId()) - .append("; state=") - .append(dbVol.getState()) - .append("; updatecount=") - .append(dbVol.getUpdatedCount()) - .append(";updatedTime=") - .append(dbVol.getUpdated()); - str.append(": New Data={id=") - .append(volHost.getId()) - .append("; state=") - .append(nextState) - .append("; event=") - .append(event) - .append("; updatecount=") - .append(volHost.getUpdatedCount()) - .append("; updatedTime=") - .append(volHost.getUpdated()); - str.append(": stale Data={id=") - .append(volHost.getId()) - .append("; state=") - .append(currentState) - .append("; event=") - .append(event) - .append("; updatecount=") - .append(oldUpdated) - .append("; updatedTime=") - .append(oldUpdatedTime); - } else { - s_logger.debug("Unable to update objectIndatastore: id=" + volHost.getId() + ", as there is no such object exists in the database anymore"); - } - } - return rows > 0; - } - -} diff --git a/engine/schema/src/main/java/com/cloud/usage/ExternalPublicIpStatisticsVO.java b/engine/schema/src/main/java/com/cloud/usage/ExternalPublicIpStatisticsVO.java deleted file mode 100644 index 4337d00b04fe..000000000000 --- a/engine/schema/src/main/java/com/cloud/usage/ExternalPublicIpStatisticsVO.java +++ /dev/null @@ -1,98 +0,0 @@ -// 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.usage; - -import javax.persistence.Column; -import javax.persistence.Entity; -import javax.persistence.GeneratedValue; -import javax.persistence.GenerationType; -import javax.persistence.Id; -import javax.persistence.PrimaryKeyJoinColumn; -import javax.persistence.Table; - -import org.apache.cloudstack.api.InternalIdentity; - -@Entity -@Table(name = "external_public_ip_statistics") -@PrimaryKeyJoinColumn(name = "id") -public class ExternalPublicIpStatisticsVO implements InternalIdentity { - - @Id - @GeneratedValue(strategy = GenerationType.IDENTITY) - @Column(name = "id") - private Long id; - - @Column(name = "data_center_id", updatable = false) - private long zoneId; - - @Column(name = "account_id", updatable = false) - private long accountId; - - @Column(name = "public_ip_address") - private String publicIpAddress; - - @Column(name = "current_bytes_received") - private long currentBytesReceived; - - @Column(name = "current_bytes_sent") - private long currentBytesSent; - - protected ExternalPublicIpStatisticsVO() { - } - - public ExternalPublicIpStatisticsVO(long zoneId, long accountId, String publicIpAddress) { - this.zoneId = zoneId; - this.accountId = accountId; - this.publicIpAddress = publicIpAddress; - this.currentBytesReceived = 0; - this.currentBytesSent = 0; - } - - @Override - public long getId() { - return id; - } - - public long getZoneId() { - return zoneId; - } - - public long getAccountId() { - return accountId; - } - - public String getPublicIpAddress() { - return publicIpAddress; - } - - public long getCurrentBytesReceived() { - return currentBytesReceived; - } - - public void setCurrentBytesReceived(long currentBytesReceived) { - this.currentBytesReceived = currentBytesReceived; - } - - public long getCurrentBytesSent() { - return currentBytesSent; - } - - public void setCurrentBytesSent(long currentBytesSent) { - this.currentBytesSent = currentBytesSent; - } - -} diff --git a/engine/schema/src/main/java/com/cloud/usage/dao/ExternalPublicIpStatisticsDaoImpl.java b/engine/schema/src/main/java/com/cloud/usage/dao/ExternalPublicIpStatisticsDaoImpl.java deleted file mode 100644 index 67b135b64ef8..000000000000 --- a/engine/schema/src/main/java/com/cloud/usage/dao/ExternalPublicIpStatisticsDaoImpl.java +++ /dev/null @@ -1,76 +0,0 @@ -// 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.usage.dao; - -import java.util.List; - - -import org.springframework.stereotype.Component; - -import com.cloud.usage.ExternalPublicIpStatisticsVO; -import com.cloud.utils.db.GenericDaoBase; -import com.cloud.utils.db.SearchBuilder; -import com.cloud.utils.db.SearchCriteria; - -@Component -public class ExternalPublicIpStatisticsDaoImpl extends GenericDaoBase implements ExternalPublicIpStatisticsDao { - - private final SearchBuilder AccountZoneSearch; - private final SearchBuilder SingleRowSearch; - - public ExternalPublicIpStatisticsDaoImpl() { - AccountZoneSearch = createSearchBuilder(); - AccountZoneSearch.and("accountId", AccountZoneSearch.entity().getAccountId(), SearchCriteria.Op.EQ); - AccountZoneSearch.and("zoneId", AccountZoneSearch.entity().getZoneId(), SearchCriteria.Op.EQ); - AccountZoneSearch.done(); - - SingleRowSearch = createSearchBuilder(); - SingleRowSearch.and("accountId", SingleRowSearch.entity().getAccountId(), SearchCriteria.Op.EQ); - SingleRowSearch.and("zoneId", SingleRowSearch.entity().getZoneId(), SearchCriteria.Op.EQ); - SingleRowSearch.and("publicIp", SingleRowSearch.entity().getPublicIpAddress(), SearchCriteria.Op.EQ); - SingleRowSearch.done(); - } - - @Override - public ExternalPublicIpStatisticsVO lock(long accountId, long zoneId, String publicIpAddress) { - SearchCriteria sc = getSingleRowSc(accountId, zoneId, publicIpAddress); - return lockOneRandomRow(sc, true); - } - - @Override - public ExternalPublicIpStatisticsVO findBy(long accountId, long zoneId, String publicIpAddress) { - SearchCriteria sc = getSingleRowSc(accountId, zoneId, publicIpAddress); - return findOneBy(sc); - } - - private SearchCriteria getSingleRowSc(long accountId, long zoneId, String publicIpAddress) { - SearchCriteria sc = SingleRowSearch.create(); - sc.setParameters("accountId", accountId); - sc.setParameters("zoneId", zoneId); - sc.setParameters("publicIp", publicIpAddress); - return sc; - } - - @Override - public List listBy(long accountId, long zoneId) { - SearchCriteria sc = AccountZoneSearch.create(); - sc.setParameters("accountId", accountId); - sc.setParameters("zoneId", zoneId); - return search(sc, null); - } - -} diff --git a/engine/schema/src/main/java/com/cloud/vm/InstanceGroupVMMapVO.java b/engine/schema/src/main/java/com/cloud/vm/InstanceGroupVMMapVO.java index eecb5b165b4c..0957dc4bfafc 100644 --- a/engine/schema/src/main/java/com/cloud/vm/InstanceGroupVMMapVO.java +++ b/engine/schema/src/main/java/com/cloud/vm/InstanceGroupVMMapVO.java @@ -29,7 +29,7 @@ import org.apache.cloudstack.api.InternalIdentity; @Entity -@Table(name = ("instance_group_vm_map")) +@Table(name = "instance_group_vm_map") @SecondaryTables({@SecondaryTable(name = "user_vm", pkJoinColumns = {@PrimaryKeyJoinColumn(name = "instance_id", referencedColumnName = "id")}), @SecondaryTable(name = "instance_group", pkJoinColumns = {@PrimaryKeyJoinColumn(name = "group_id", referencedColumnName = "id")})}) public class InstanceGroupVMMapVO implements InternalIdentity { diff --git a/engine/schema/src/main/java/com/cloud/vm/VMInstanceVO.java b/engine/schema/src/main/java/com/cloud/vm/VMInstanceVO.java index aa2e7360bf4b..afc7134990c9 100644 --- a/engine/schema/src/main/java/com/cloud/vm/VMInstanceVO.java +++ b/engine/schema/src/main/java/com/cloud/vm/VMInstanceVO.java @@ -506,7 +506,7 @@ public void setRemoved(Date removed) { @Override public String toString() { - return String.format("VM instance {\"id\": \"%s\", \"name\": \"%s\", \"uuid\": \"%s\", \"type\"=\"%s\"}", id, getInstanceName(), uuid, type); + return String.format("VM instance {id: \"%s\", name: \"%s\", uuid: \"%s\", type=\"%s\"}", id, getInstanceName(), uuid, type); } @Override diff --git a/engine/schema/src/main/java/org/apache/cloudstack/affinity/AffinityGroupVMMapVO.java b/engine/schema/src/main/java/org/apache/cloudstack/affinity/AffinityGroupVMMapVO.java index 0670060419a7..f03357046ed9 100644 --- a/engine/schema/src/main/java/org/apache/cloudstack/affinity/AffinityGroupVMMapVO.java +++ b/engine/schema/src/main/java/org/apache/cloudstack/affinity/AffinityGroupVMMapVO.java @@ -26,7 +26,7 @@ import org.apache.cloudstack.api.InternalIdentity; @Entity -@Table(name = ("affinity_group_vm_map")) +@Table(name = "affinity_group_vm_map") public class AffinityGroupVMMapVO implements InternalIdentity { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) diff --git a/engine/schema/src/main/java/org/apache/cloudstack/affinity/AffinityGroupVO.java b/engine/schema/src/main/java/org/apache/cloudstack/affinity/AffinityGroupVO.java index 03274ad4388f..536b96c6567e 100644 --- a/engine/schema/src/main/java/org/apache/cloudstack/affinity/AffinityGroupVO.java +++ b/engine/schema/src/main/java/org/apache/cloudstack/affinity/AffinityGroupVO.java @@ -30,7 +30,7 @@ import org.apache.cloudstack.acl.ControlledEntity; @Entity -@Table(name = ("affinity_group")) +@Table(name = "affinity_group") public class AffinityGroupVO implements AffinityGroup { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) diff --git a/engine/schema/src/main/java/org/apache/cloudstack/lb/ApplicationLoadBalancerRuleVO.java b/engine/schema/src/main/java/org/apache/cloudstack/lb/ApplicationLoadBalancerRuleVO.java index 64fa865922e0..cfca0984eb97 100644 --- a/engine/schema/src/main/java/org/apache/cloudstack/lb/ApplicationLoadBalancerRuleVO.java +++ b/engine/schema/src/main/java/org/apache/cloudstack/lb/ApplicationLoadBalancerRuleVO.java @@ -37,7 +37,7 @@ * */ @Entity -@Table(name = ("load_balancing_rules")) +@Table(name = "load_balancing_rules") @DiscriminatorValue(value = "LoadBalancing") @PrimaryKeyJoinColumn(name = "id") public class ApplicationLoadBalancerRuleVO extends FirewallRuleVO implements ApplicationLoadBalancerRule { diff --git a/engine/schema/src/main/java/org/apache/cloudstack/region/RegionSyncVO.java b/engine/schema/src/main/java/org/apache/cloudstack/region/RegionSyncVO.java deleted file mode 100644 index bb92b666af73..000000000000 --- a/engine/schema/src/main/java/org/apache/cloudstack/region/RegionSyncVO.java +++ /dev/null @@ -1,96 +0,0 @@ -// 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.region; - -import java.util.Date; - -import javax.persistence.Column; -import javax.persistence.Entity; -import javax.persistence.Id; -import javax.persistence.Table; - -import com.cloud.utils.db.GenericDao; - -@Entity -@Table(name = "region_sync") -public class RegionSyncVO implements RegionSync { - - @Id - @Column(name = "id") - private long id; - - @Column(name = "region_id") - private int regionId; - - @Column(name = "api") - private String api; - - @Column(name = GenericDao.CREATED_COLUMN) - private Date createDate; - - @Column(name = "processed") - boolean processed; - - public RegionSyncVO() { - } - - public RegionSyncVO(int regionId, String api) { - this.regionId = regionId; - this.api = api; - } - - @Override - public int getRegionId() { - return regionId; - } - - public void setRegionId(int regionId) { - this.regionId = regionId; - } - - @Override - public String getApi() { - return api; - } - - public void setApi(String api) { - this.api = api; - } - - @Override - public Date getCreateDate() { - return createDate; - } - - public void setCreateDate(Date createDate) { - this.createDate = createDate; - } - - public boolean isProcessed() { - return processed; - } - - public void setProcessed(boolean processed) { - this.processed = processed; - } - - @Override - public long getId() { - return id; - } - -} diff --git a/engine/schema/src/main/java/org/apache/cloudstack/region/gslb/GlobalLoadBalancerLbRuleMapVO.java b/engine/schema/src/main/java/org/apache/cloudstack/region/gslb/GlobalLoadBalancerLbRuleMapVO.java index 9445dc916d55..2a4570e7aa99 100644 --- a/engine/schema/src/main/java/org/apache/cloudstack/region/gslb/GlobalLoadBalancerLbRuleMapVO.java +++ b/engine/schema/src/main/java/org/apache/cloudstack/region/gslb/GlobalLoadBalancerLbRuleMapVO.java @@ -27,7 +27,7 @@ import org.apache.cloudstack.api.InternalIdentity; @Entity -@Table(name = ("global_load_balancer_lb_rule_map")) +@Table(name = "global_load_balancer_lb_rule_map") public class GlobalLoadBalancerLbRuleMapVO implements InternalIdentity { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) diff --git a/engine/schema/src/main/java/org/apache/cloudstack/region/gslb/GlobalLoadBalancerRuleVO.java b/engine/schema/src/main/java/org/apache/cloudstack/region/gslb/GlobalLoadBalancerRuleVO.java index 88cd0003a23e..1865b9a67834 100644 --- a/engine/schema/src/main/java/org/apache/cloudstack/region/gslb/GlobalLoadBalancerRuleVO.java +++ b/engine/schema/src/main/java/org/apache/cloudstack/region/gslb/GlobalLoadBalancerRuleVO.java @@ -31,7 +31,7 @@ import com.cloud.region.ha.GlobalLoadBalancerRule; @Entity -@Table(name = ("global_load_balancing_rules")) +@Table(name = "global_load_balancing_rules") public class GlobalLoadBalancerRuleVO implements GlobalLoadBalancerRule { @Id diff --git a/engine/schema/src/main/resources/META-INF/cloudstack/core/spring-engine-schema-core-daos-context.xml b/engine/schema/src/main/resources/META-INF/cloudstack/core/spring-engine-schema-core-daos-context.xml index 67b40101d559..362054ece34b 100644 --- a/engine/schema/src/main/resources/META-INF/cloudstack/core/spring-engine-schema-core-daos-context.xml +++ b/engine/schema/src/main/resources/META-INF/cloudstack/core/spring-engine-schema-core-daos-context.xml @@ -87,7 +87,6 @@ - @@ -240,14 +239,12 @@ - - diff --git a/engine/schema/src/main/resources/META-INF/db/schema-41510to41600.sql b/engine/schema/src/main/resources/META-INF/db/schema-41510to41600.sql index f7a7c4aeb379..ad13853fc1f4 100644 --- a/engine/schema/src/main/resources/META-INF/db/schema-41510to41600.sql +++ b/engine/schema/src/main/resources/META-INF/db/schema-41510to41600.sql @@ -404,4 +404,110 @@ UPDATE `cloud`.`configuration` SET name='denied.routes', description='Routes tha -- Rename 'master_node_count' to 'control_node_count' in kubernetes_cluster table ALTER TABLE `cloud`.`kubernetes_cluster` CHANGE master_node_count control_node_count bigint NOT NULL default '0' COMMENT 'the number of the control nodes deployed for this Kubernetes cluster'; -UPDATE `cloud`.`domain_router` SET redundant_state = 'PRIMARY' WHERE redundant_state = 'MASTER'; \ No newline at end of file +UPDATE `cloud`.`domain_router` SET redundant_state = 'PRIMARY' WHERE redundant_state = 'MASTER'; + +DROP TABLE IF EXISTS `cloud`.`external_bigswitch_vns_devices`; +DROP TABLE IF EXISTS `cloud`.`template_s3_ref`; +DROP TABLE IF EXISTS `cloud`.`template_swift_ref`; +DROP TABLE IF EXISTS `cloud`.`template_ovf_properties`; +DROP TABLE IF EXISTS `cloud`.`op_host_upgrade`; +DROP TABLE IF EXISTS `cloud`.`stack_maid`; +DROP TABLE IF EXISTS `cloud`.`volume_host_ref`; +DROP TABLE IF EXISTS `cloud`.`template_host_ref`; +DROP TABLE IF EXISTS `cloud`.`swift`; + +ALTER TABLE `cloud`.`snapshots` DROP FOREIGN KEY `fk_snapshots__s3_id` ; +ALTER TABLE `cloud`.`snapshots` DROP COLUMN `s3_id` ; +DROP TABLE IF EXISTS `cloud`.`s3`; + +-- Re-create host view to prevent multiple entries for hosts with multiple tags +DROP VIEW IF EXISTS `cloud`.`host_view`; +CREATE VIEW `cloud`.`host_view` AS + SELECT + host.id, + host.uuid, + host.name, + host.status, + host.disconnected, + host.type, + host.private_ip_address, + host.version, + host.hypervisor_type, + host.hypervisor_version, + host.capabilities, + host.last_ping, + host.created, + host.removed, + host.resource_state, + host.mgmt_server_id, + host.cpu_sockets, + host.cpus, + host.speed, + host.ram, + cluster.id cluster_id, + cluster.uuid cluster_uuid, + cluster.name cluster_name, + cluster.cluster_type, + data_center.id data_center_id, + data_center.uuid data_center_uuid, + data_center.name data_center_name, + data_center.networktype data_center_type, + host_pod_ref.id pod_id, + host_pod_ref.uuid pod_uuid, + host_pod_ref.name pod_name, + GROUP_CONCAT(DISTINCT(host_tags.tag)) AS tag, + guest_os_category.id guest_os_category_id, + guest_os_category.uuid guest_os_category_uuid, + guest_os_category.name guest_os_category_name, + mem_caps.used_capacity memory_used_capacity, + mem_caps.reserved_capacity memory_reserved_capacity, + cpu_caps.used_capacity cpu_used_capacity, + cpu_caps.reserved_capacity cpu_reserved_capacity, + async_job.id job_id, + async_job.uuid job_uuid, + async_job.job_status job_status, + async_job.account_id job_account_id, + oobm.enabled AS `oobm_enabled`, + oobm.power_state AS `oobm_power_state`, + ha_config.enabled AS `ha_enabled`, + ha_config.ha_state AS `ha_state`, + ha_config.provider AS `ha_provider`, + `last_annotation_view`.`annotation` AS `annotation`, + `last_annotation_view`.`created` AS `last_annotated`, + `user`.`username` AS `username` + FROM + `cloud`.`host` + LEFT JOIN + `cloud`.`cluster` ON host.cluster_id = cluster.id + LEFT JOIN + `cloud`.`data_center` ON host.data_center_id = data_center.id + LEFT JOIN + `cloud`.`host_pod_ref` ON host.pod_id = host_pod_ref.id + LEFT JOIN + `cloud`.`host_details` ON host.id = host_details.host_id + AND host_details.name = 'guest.os.category.id' + LEFT JOIN + `cloud`.`guest_os_category` ON guest_os_category.id = CONVERT ( host_details.value, UNSIGNED ) + LEFT JOIN + `cloud`.`host_tags` ON host_tags.host_id = host.id + LEFT JOIN + `cloud`.`op_host_capacity` mem_caps ON host.id = mem_caps.host_id + AND mem_caps.capacity_type = 0 + LEFT JOIN + `cloud`.`op_host_capacity` cpu_caps ON host.id = cpu_caps.host_id + AND cpu_caps.capacity_type = 1 + LEFT JOIN + `cloud`.`async_job` ON async_job.instance_id = host.id + AND async_job.instance_type = 'Host' + AND async_job.job_status = 0 + LEFT JOIN + `cloud`.`oobm` ON oobm.host_id = host.id + left join + `cloud`.`ha_config` ON ha_config.resource_id=host.id + and ha_config.resource_type='Host' + LEFT JOIN + `cloud`.`last_annotation_view` ON `last_annotation_view`.`entity_uuid` = `host`.`uuid` + LEFT JOIN + `cloud`.`user` ON `user`.`uuid` = `last_annotation_view`.`user_uuid` + GROUP BY + `host`.`id`; diff --git a/engine/storage/image/src/main/java/org/apache/cloudstack/storage/image/store/TemplateObject.java b/engine/storage/image/src/main/java/org/apache/cloudstack/storage/image/store/TemplateObject.java index d96b6183de1d..c8b78aa9c911 100644 --- a/engine/storage/image/src/main/java/org/apache/cloudstack/storage/image/store/TemplateObject.java +++ b/engine/storage/image/src/main/java/org/apache/cloudstack/storage/image/store/TemplateObject.java @@ -137,24 +137,6 @@ public Long getSize() { if (dataStore == null) { return imageVO.getSize(); } - - /* - * - * // If the template that was passed into this allocator is not - * installed in the storage pool, // add 3 * (template size on secondary - * storage) to the running total VMTemplateHostVO templateHostVO = - * _storageMgr.findVmTemplateHost(templateForVmCreation.getId(), null); - * - * if (templateHostVO == null) { VMTemplateSwiftVO templateSwiftVO = - * _swiftMgr.findByTmpltId(templateForVmCreation.getId()); if - * (templateSwiftVO != null) { long templateSize = - * templateSwiftVO.getPhysicalSize(); if (templateSize == 0) { - * templateSize = templateSwiftVO.getSize(); } totalAllocatedSize += - * (templateSize + _extraBytesPerVolume); } } else { long templateSize = - * templateHostVO.getPhysicalSize(); if ( templateSize == 0 ){ - * templateSize = templateHostVO.getSize(); } totalAllocatedSize += - * (templateSize + _extraBytesPerVolume); } - */ VMTemplateVO image = imageDao.findById(imageVO.getId()); return image.getSize(); } diff --git a/engine/storage/integration-test/src/test/java/org/apache/cloudstack/storage/test/ChildTestConfiguration.java b/engine/storage/integration-test/src/test/java/org/apache/cloudstack/storage/test/ChildTestConfiguration.java index 3af7df7ecfc6..51156246b37c 100644 --- a/engine/storage/integration-test/src/test/java/org/apache/cloudstack/storage/test/ChildTestConfiguration.java +++ b/engine/storage/integration-test/src/test/java/org/apache/cloudstack/storage/test/ChildTestConfiguration.java @@ -73,11 +73,9 @@ import com.cloud.storage.dao.StoragePoolWorkDaoImpl; import com.cloud.storage.dao.VMTemplateDaoImpl; import com.cloud.storage.dao.VMTemplateDetailsDaoImpl; -import com.cloud.storage.dao.VMTemplateHostDaoImpl; import com.cloud.storage.dao.VMTemplatePoolDaoImpl; import com.cloud.storage.dao.VMTemplateZoneDaoImpl; import com.cloud.storage.dao.VolumeDaoImpl; -import com.cloud.storage.dao.VolumeHostDaoImpl; import com.cloud.storage.download.DownloadMonitorImpl; import com.cloud.tags.dao.ResourceTagsDaoImpl; import com.cloud.template.TemplateManager; @@ -96,7 +94,7 @@ import com.cloud.vm.snapshot.dao.VMSnapshotDaoImpl; @Configuration -@ComponentScan(basePackageClasses = {NicDaoImpl.class, VMInstanceDaoImpl.class, VMTemplateHostDaoImpl.class, VolumeHostDaoImpl.class, VolumeDaoImpl.class, +@ComponentScan(basePackageClasses = {NicDaoImpl.class, VMInstanceDaoImpl.class, VolumeDaoImpl.class, VMTemplatePoolDaoImpl.class, ResourceTagsDaoImpl.class, VMTemplateDaoImpl.class, MockStorageMotionStrategy.class, ConfigurationDaoImpl.class, ClusterDaoImpl.class, HostPodDaoImpl.class, VMTemplateZoneDaoImpl.class, VMTemplateDetailsDaoImpl.class, HostDetailsDaoImpl.class, HostTagsDaoImpl.class, HostTransferMapDaoImpl.class, DataCenterIpAddressDaoImpl.class, DataCenterLinkLocalIpAddressDaoImpl.class, diff --git a/engine/storage/snapshot/src/main/java/org/apache/cloudstack/storage/snapshot/CephSnapshotStrategy.java b/engine/storage/snapshot/src/main/java/org/apache/cloudstack/storage/snapshot/CephSnapshotStrategy.java index 87f9e100be7e..039cd82595d1 100644 --- a/engine/storage/snapshot/src/main/java/org/apache/cloudstack/storage/snapshot/CephSnapshotStrategy.java +++ b/engine/storage/snapshot/src/main/java/org/apache/cloudstack/storage/snapshot/CephSnapshotStrategy.java @@ -64,10 +64,6 @@ public StrategyPriority canHandle(Snapshot snapshot, SnapshotOperation op) { return StrategyPriority.HIGHEST; } - if (SnapshotOperation.DELETE.equals(op)) { - return StrategyPriority.HIGHEST; - } - return StrategyPriority.CANT_HANDLE; } diff --git a/engine/storage/snapshot/src/test/java/org/apache/cloudstack/storage/snapshot/CephSnapshotStrategyTest.java b/engine/storage/snapshot/src/test/java/org/apache/cloudstack/storage/snapshot/CephSnapshotStrategyTest.java index 260a21d87a01..dcc6acf983fe 100644 --- a/engine/storage/snapshot/src/test/java/org/apache/cloudstack/storage/snapshot/CephSnapshotStrategyTest.java +++ b/engine/storage/snapshot/src/test/java/org/apache/cloudstack/storage/snapshot/CephSnapshotStrategyTest.java @@ -87,8 +87,6 @@ private void configureAndVerifyCanHandle(Date removed, boolean isSnapshotStoredO StrategyPriority strategyPriority = cephSnapshotStrategy.canHandle(snapshot, snapshotOps[i]); if (snapshotOps[i] == SnapshotOperation.REVERT && isSnapshotStoredOnRbdStoragePool) { Assert.assertEquals(StrategyPriority.HIGHEST, strategyPriority); - } else if (snapshotOps[i] == SnapshotOperation.DELETE && isSnapshotStoredOnRbdStoragePool) { - Assert.assertEquals(StrategyPriority.HIGHEST, strategyPriority); } else { Assert.assertEquals(StrategyPriority.CANT_HANDLE, strategyPriority); } diff --git a/engine/storage/src/main/java/org/apache/cloudstack/storage/allocator/AbstractStoragePoolAllocator.java b/engine/storage/src/main/java/org/apache/cloudstack/storage/allocator/AbstractStoragePoolAllocator.java index 7de40e924de8..10d39ee88fa9 100644 --- a/engine/storage/src/main/java/org/apache/cloudstack/storage/allocator/AbstractStoragePoolAllocator.java +++ b/engine/storage/src/main/java/org/apache/cloudstack/storage/allocator/AbstractStoragePoolAllocator.java @@ -241,7 +241,7 @@ protected boolean filter(ExcludeList avoid, StoragePool pool, DiskProfile dskCh, } try { - boolean isStoragePoolStoragepolicyComplaince = storageMgr.isStoragePoolComplaintWithStoragePolicy(requestVolumes, pool); + boolean isStoragePoolStoragepolicyComplaince = storageMgr.isStoragePoolCompliantWithStoragePolicy(requestVolumes, pool); if (!isStoragePoolStoragepolicyComplaince) { return false; } diff --git a/packaging/centos7/cloud.spec b/packaging/centos7/cloud.spec index 049bc48047bf..b1b69b7549de 100644 --- a/packaging/centos7/cloud.spec +++ b/packaging/centos7/cloud.spec @@ -398,7 +398,7 @@ install -D tools/whisker/LICENSE ${RPM_BUILD_ROOT}%{_defaultdocdir}/%{name}-inte /usr/bin/systemctl off cloudstack-management || true %pre management -id cloud > /dev/null 2>&1 || /usr/sbin/useradd -M -c "CloudStack unprivileged user" \ +id cloud > /dev/null 2>&1 || /usr/sbin/useradd -M -U -c "CloudStack unprivileged user" \ -r -s /bin/sh -d %{_localstatedir}/cloudstack/management cloud|| true rm -rf %{_localstatedir}/cache/cloudstack @@ -432,6 +432,14 @@ grep -s -q "db.cloud.driver=jdbc:mysql" "%{_sysconfdir}/%{name}/management/db.pr grep -s -q "db.usage.driver=jdbc:mysql" "%{_sysconfdir}/%{name}/management/db.properties" || sed -i -e "\$adb.usage.driver=jdbc:mysql" "%{_sysconfdir}/%{name}/management/db.properties" grep -s -q "db.simulator.driver=jdbc:mysql" "%{_sysconfdir}/%{name}/management/db.properties" || sed -i -e "\$adb.simulator.driver=jdbc:mysql" "%{_sysconfdir}/%{name}/management/db.properties" +# Update DB properties having master and slave(s), with source and replica(s) respectively (for inclusiveness) +grep -s -q "^db.cloud.slaves=" "%{_sysconfdir}/%{name}/management/db.properties" && sed -i "s/^db.cloud.slaves=/db.cloud.replicas=/g" "%{_sysconfdir}/%{name}/management/db.properties" +grep -s -q "^db.cloud.secondsBeforeRetryMaster=" "%{_sysconfdir}/%{name}/management/db.properties" && sed -i "s/^db.cloud.secondsBeforeRetryMaster=/db.cloud.secondsBeforeRetrySource=/g" "%{_sysconfdir}/%{name}/management/db.properties" +grep -s -q "^db.cloud.queriesBeforeRetryMaster=" "%{_sysconfdir}/%{name}/management/db.properties" && sed -i "s/^db.cloud.queriesBeforeRetryMaster=/db.cloud.queriesBeforeRetrySource=/g" "%{_sysconfdir}/%{name}/management/db.properties" +grep -s -q "^db.usage.slaves=" "%{_sysconfdir}/%{name}/management/db.properties" && sed -i "s/^db.usage.slaves=/db.usage.replicas=/g" "%{_sysconfdir}/%{name}/management/db.properties" +grep -s -q "^db.usage.secondsBeforeRetryMaster=" "%{_sysconfdir}/%{name}/management/db.properties" && sed -i "s/^db.usage.secondsBeforeRetryMaster=/db.usage.secondsBeforeRetrySource=/g" "%{_sysconfdir}/%{name}/management/db.properties" +grep -s -q "^db.usage.queriesBeforeRetryMaster=" "%{_sysconfdir}/%{name}/management/db.properties" && sed -i "s/^db.usage.queriesBeforeRetryMaster=/db.usage.queriesBeforeRetrySource=/g" "%{_sysconfdir}/%{name}/management/db.properties" + if [ ! -f %{_datadir}/cloudstack-common/scripts/vm/hypervisor/xenserver/vhd-util ] ; then echo Please download vhd-util from http://download.cloudstack.org/tools/vhd-util and put it in echo %{_datadir}/cloudstack-common/scripts/vm/hypervisor/xenserver/ @@ -484,7 +492,7 @@ fi systemctl daemon-reload %pre usage -id cloud > /dev/null 2>&1 || /usr/sbin/useradd -M -c "CloudStack unprivileged user" \ +id cloud > /dev/null 2>&1 || /usr/sbin/useradd -M -U -c "CloudStack unprivileged user" \ -r -s /bin/sh -d %{_localstatedir}/cloudstack/management cloud|| true %preun usage diff --git a/packaging/centos8/cloud.spec b/packaging/centos8/cloud.spec index fd05432b1fd0..9e62691782f9 100644 --- a/packaging/centos8/cloud.spec +++ b/packaging/centos8/cloud.spec @@ -391,7 +391,7 @@ install -D tools/whisker/LICENSE ${RPM_BUILD_ROOT}%{_defaultdocdir}/%{name}-inte /usr/bin/systemctl off cloudstack-management || true %pre management -id cloud > /dev/null 2>&1 || /usr/sbin/useradd -M -c "CloudStack unprivileged user" \ +id cloud > /dev/null 2>&1 || /usr/sbin/useradd -M -U -c "CloudStack unprivileged user" \ -r -s /bin/sh -d %{_localstatedir}/cloudstack/management cloud|| true rm -rf %{_localstatedir}/cache/cloudstack @@ -423,6 +423,14 @@ grep -s -q "db.cloud.driver=jdbc:mysql" "%{_sysconfdir}/%{name}/management/db.pr grep -s -q "db.usage.driver=jdbc:mysql" "%{_sysconfdir}/%{name}/management/db.properties" || sed -i -e "\$adb.usage.driver=jdbc:mysql" "%{_sysconfdir}/%{name}/management/db.properties" grep -s -q "db.simulator.driver=jdbc:mysql" "%{_sysconfdir}/%{name}/management/db.properties" || sed -i -e "\$adb.simulator.driver=jdbc:mysql" "%{_sysconfdir}/%{name}/management/db.properties" +# Update DB properties having master and slave(s), with source and replica(s) respectively (for inclusiveness) +grep -s -q "^db.cloud.slaves=" "%{_sysconfdir}/%{name}/management/db.properties" && sed -i "s/^db.cloud.slaves=/db.cloud.replicas=/g" "%{_sysconfdir}/%{name}/management/db.properties" +grep -s -q "^db.cloud.secondsBeforeRetryMaster=" "%{_sysconfdir}/%{name}/management/db.properties" && sed -i "s/^db.cloud.secondsBeforeRetryMaster=/db.cloud.secondsBeforeRetrySource=/g" "%{_sysconfdir}/%{name}/management/db.properties" +grep -s -q "^db.cloud.queriesBeforeRetryMaster=" "%{_sysconfdir}/%{name}/management/db.properties" && sed -i "s/^db.cloud.queriesBeforeRetryMaster=/db.cloud.queriesBeforeRetrySource=/g" "%{_sysconfdir}/%{name}/management/db.properties" +grep -s -q "^db.usage.slaves=" "%{_sysconfdir}/%{name}/management/db.properties" && sed -i "s/^db.usage.slaves=/db.usage.replicas=/g" "%{_sysconfdir}/%{name}/management/db.properties" +grep -s -q "^db.usage.secondsBeforeRetryMaster=" "%{_sysconfdir}/%{name}/management/db.properties" && sed -i "s/^db.usage.secondsBeforeRetryMaster=/db.usage.secondsBeforeRetrySource=/g" "%{_sysconfdir}/%{name}/management/db.properties" +grep -s -q "^db.usage.queriesBeforeRetryMaster=" "%{_sysconfdir}/%{name}/management/db.properties" && sed -i "s/^db.usage.queriesBeforeRetryMaster=/db.usage.queriesBeforeRetrySource=/g" "%{_sysconfdir}/%{name}/management/db.properties" + if [ ! -f %{_datadir}/cloudstack-common/scripts/vm/hypervisor/xenserver/vhd-util ] ; then echo Please download vhd-util from http://download.cloudstack.org/tools/vhd-util and put it in echo %{_datadir}/cloudstack-common/scripts/vm/hypervisor/xenserver/ @@ -475,7 +483,7 @@ fi systemctl daemon-reload %pre usage -id cloud > /dev/null 2>&1 || /usr/sbin/useradd -M -c "CloudStack unprivileged user" \ +id cloud > /dev/null 2>&1 || /usr/sbin/useradd -M -U -c "CloudStack unprivileged user" \ -r -s /bin/sh -d %{_localstatedir}/cloudstack/management cloud|| true %preun usage diff --git a/plugins/hypervisors/kvm/src/main/java/com/cloud/ha/KVMInvestigator.java b/plugins/hypervisors/kvm/src/main/java/com/cloud/ha/KVMInvestigator.java index a6cddc7dfabb..a76b56a1a4de 100644 --- a/plugins/hypervisors/kvm/src/main/java/com/cloud/ha/KVMInvestigator.java +++ b/plugins/hypervisors/kvm/src/main/java/com/cloud/ha/KVMInvestigator.java @@ -85,6 +85,15 @@ public Status isAgentAlive(Host agent) { break; } } + if (!hasNfs) { + List zonePools = _storagePoolDao.findZoneWideStoragePoolsByHypervisor(agent.getDataCenterId(), agent.getHypervisorType()); + for (StoragePoolVO pool : zonePools) { + if (pool.getPoolType() == StoragePoolType.NetworkFilesystem) { + hasNfs = true; + break; + } + } + } if (!hasNfs) { s_logger.warn( "Agent investigation was requested on host " + agent + ", but host does not support investigation because it has no NFS storage. Skipping investigation."); diff --git a/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/BridgeVifDriver.java b/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/BridgeVifDriver.java index f298670492f7..741aa72172eb 100644 --- a/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/BridgeVifDriver.java +++ b/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/BridgeVifDriver.java @@ -224,7 +224,7 @@ public LibvirtVMDef.InterfaceDef plug(NicTO nic, String guestOsType, String nicA String brName = createVnetBr(vNetId, trafficLabel, protocol); intf.defBridgeNet(brName, null, nic.getMac(), getGuestNicModel(guestOsType, nicAdapter), networkRateKBps); } else { - String brName = createVnetBr(vNetId, "private", protocol); + String brName = createVnetBr(vNetId, _bridges.get("private"), protocol); intf.defBridgeNet(brName, null, nic.getMac(), getGuestNicModel(guestOsType, nicAdapter), networkRateKBps); } } else { @@ -291,7 +291,7 @@ private String generateVxnetBrName(String pifName, String vnetId) { private String createVnetBr(String vNetId, String pifKey, String protocol) throws InternalErrorException { String nic = _pifs.get(pifKey); - if (nic == null) { + if (nic == null || protocol.equals(Networks.BroadcastDomainType.Vxlan.scheme())) { // if not found in bridge map, maybe traffic label refers to pif already? File pif = new File("/sys/class/net/" + pifKey); if (pif.isDirectory()) { @@ -376,7 +376,9 @@ private void deleteVnetBr(String brName, boolean deleteBr) { command.add("-v", vNetId); command.add("-p", pName); command.add("-b", brName); - command.add("-d", String.valueOf(deleteBr)); + if (cmdout != null && !cmdout.contains("vxlan")) { + command.add("-d", String.valueOf(deleteBr)); + } final String result = command.execute(); if (result != null) { diff --git a/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/IvsVifDriver.java b/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/IvsVifDriver.java index 306d70fc1601..fd22c5ecefb6 100644 --- a/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/IvsVifDriver.java +++ b/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/IvsVifDriver.java @@ -161,7 +161,7 @@ private void createControlNetwork() throws LibvirtException { private String createVnetBr(String vNetId, String pifKey, String protocol) throws InternalErrorException { String nic = _pifs.get(pifKey); - if (nic == null) { + if (nic == null || protocol.equals(Networks.BroadcastDomainType.Vxlan.scheme())) { // if not found in bridge map, maybe traffic label refers to pif already? File pif = new File("/sys/class/net/" + pifKey); if (pif.isDirectory()) { diff --git a/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/LibvirtComputingResource.java b/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/LibvirtComputingResource.java index 8b7932652c0b..338a41b6c256 100644 --- a/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/LibvirtComputingResource.java +++ b/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/LibvirtComputingResource.java @@ -253,6 +253,8 @@ public class LibvirtComputingResource extends ServerResourceBase implements Serv protected static final String DEFAULT_OVS_VIF_DRIVER_CLASS_NAME = "com.cloud.hypervisor.kvm.resource.OvsVifDriver"; protected static final String DEFAULT_BRIDGE_VIF_DRIVER_CLASS_NAME = "com.cloud.hypervisor.kvm.resource.BridgeVifDriver"; + private final static long HYPERVISOR_LIBVIRT_VERSION_SUPPORTS_IO_URING = 6003000; + private final static long HYPERVISOR_QEMU_VERSION_SUPPORTS_IO_URING = 5000000; protected HypervisorType _hypervisorType; protected String _hypervisorURI; @@ -306,6 +308,8 @@ public class LibvirtComputingResource extends ServerResourceBase implements Serv protected String _agentHooksVmOnStopScript = "libvirt-vm-state-change.groovy"; protected String _agentHooksVmOnStopMethod = "onStop"; + private static final String CONFIG_DRIVE_ISO_DISK_LABEL = "hdd"; + private static final int CONFIG_DRIVE_ISO_DEVICE_ID = 4; protected File _qemuSocketsPath; private final String _qemuGuestAgentSocketName = "org.qemu.guest_agent.0"; @@ -342,6 +346,14 @@ public class LibvirtComputingResource extends ServerResourceBase implements Serv protected MemStat _memStat = new MemStat(_dom0MinMem, _dom0OvercommitMem); private final LibvirtUtilitiesHelper libvirtUtilitiesHelper = new LibvirtUtilitiesHelper(); + protected long getHypervisorLibvirtVersion() { + return _hypervisorLibvirtVersion; + } + + protected long getHypervisorQemuVersion() { + return _hypervisorQemuVersion; + } + @Override public ExecutionResult executeInVR(final String routerIp, final String script, final String args) { return executeInVR(routerIp, script, args, _timeout); @@ -2613,6 +2625,8 @@ public int compare(final DiskTO arg0, final DiskTO arg1) { disk.setDiscard(DiscardType.UNMAP); } + setDiskIoDriver(disk); + if (pool.getType() == StoragePoolType.RBD) { /* For RBD pools we use the secret mechanism in libvirt. @@ -2713,6 +2727,18 @@ private KVMPhysicalDisk getPhysicalDiskPrimaryStore(PrimaryDataStoreTO primaryDa return storagePool.getPhysicalDisk(data.getPath()); } + /** + * Set Disk IO Driver, if supported by the Libvirt/Qemu version. + * IO Driver works for: + * (i) Qemu >= 5.0; + * (ii) Libvirt >= 6.3.0 + */ + protected void setDiskIoDriver(DiskDef disk) { + if (getHypervisorLibvirtVersion() >= HYPERVISOR_LIBVIRT_VERSION_SUPPORTS_IO_URING && getHypervisorQemuVersion() >= HYPERVISOR_QEMU_VERSION_SUPPORTS_IO_URING) { + disk.setIoDriver(DiskDef.IoDriver.IOURING); + } + } + private KVMPhysicalDisk getPhysicalDiskFromNfsStore(String dataStoreUrl, DataTO data) { final String volPath = dataStoreUrl + File.separator + data.getPath(); final int index = volPath.lastIndexOf("/"); @@ -2793,6 +2819,32 @@ protected KVMStoragePoolManager getPoolManager() { return _storagePoolMgr; } + public void detachAndAttachConfigDriveISO(final Connect conn, final String vmName) { + // detach and re-attach configdrive ISO + List disks = getDisks(conn, vmName); + DiskDef configdrive = null; + for (DiskDef disk : disks) { + if (disk.getDeviceType() == DiskDef.DeviceType.CDROM && disk.getDiskLabel() == CONFIG_DRIVE_ISO_DISK_LABEL) { + configdrive = disk; + } + } + if (configdrive != null) { + try { + String result = attachOrDetachISO(conn, vmName, configdrive.getDiskPath(), false, CONFIG_DRIVE_ISO_DEVICE_ID); + if (result != null) { + s_logger.warn("Detach ConfigDrive ISO with result: " + result); + } + result = attachOrDetachISO(conn, vmName, configdrive.getDiskPath(), true, CONFIG_DRIVE_ISO_DEVICE_ID); + if (result != null) { + s_logger.warn("Attach ConfigDrive ISO with result: " + result); + } + } catch (final LibvirtException | InternalErrorException | URISyntaxException e) { + final String msg = "Detach and attach ConfigDrive ISO failed due to " + e.toString(); + s_logger.warn(msg, e); + } + } + } + public synchronized String attachOrDetachISO(final Connect conn, final String vmName, String isoPath, final boolean isAttach, final Integer diskSeq) throws LibvirtException, URISyntaxException, InternalErrorException { final DiskDef iso = new DiskDef(); diff --git a/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/LibvirtVMDef.java b/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/LibvirtVMDef.java index 1927ddd3569f..c762cbff48a2 100644 --- a/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/LibvirtVMDef.java +++ b/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/LibvirtVMDef.java @@ -530,6 +530,15 @@ public String toString() { devicesBuilder.append(dev.toString()); } } + + if (_emulator != null && _emulator.endsWith("aarch64")) { + devicesBuilder.append("\n"); + for (int i = 0; i < 32; i++) { + devicesBuilder.append("\n"); + } + devicesBuilder.append("\n"); + } + devicesBuilder.append("\n"); return devicesBuilder.toString(); } @@ -651,6 +660,26 @@ public String toString() { } + /** + * This enum specifies IO Drivers, each option controls specific policies on I/O. + * Qemu guests support "threads" and "native" options Since 0.8.8 ; "io_uring" is supported Since 6.3.0 (QEMU 5.0). + */ + public enum IoDriver { + NATIVE("native"), + THREADS("threads"), + IOURING("io_uring"); + String ioDriver; + + IoDriver(String driver) { + ioDriver = driver; + } + + @Override + public String toString() { + return ioDriver; + } + } + private DeviceType _deviceType; /* floppy, disk, cdrom */ private DiskType _diskType; private DiskProtocol _diskProtocol; @@ -681,6 +710,7 @@ public String toString() { private String _serial; private boolean qemuDriver = true; private DiscardType _discard = DiscardType.IGNORE; + private IoDriver ioDriver; public DiscardType getDiscard() { return _discard; @@ -690,6 +720,14 @@ public void setDiscard(DiscardType discard) { this._discard = discard; } + public DiskDef.IoDriver getIoDriver() { + return ioDriver; + } + + public void setIoDriver(IoDriver ioDriver) { + this.ioDriver = ioDriver; + } + public void setDeviceType(DeviceType deviceType) { _deviceType = deviceType; } @@ -1004,6 +1042,11 @@ public String toString() { if(_discard != null && _discard != DiscardType.IGNORE) { diskBuilder.append("discard='" + _discard.toString() + "' "); } + + if(ioDriver != null) { + diskBuilder.append(String.format("io='%s'", ioDriver)); + } + diskBuilder.append("/>\n"); } diff --git a/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtMigrateCommandWrapper.java b/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtMigrateCommandWrapper.java index 63ebd376b5c0..1d5bf1dea28c 100644 --- a/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtMigrateCommandWrapper.java +++ b/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtMigrateCommandWrapper.java @@ -76,6 +76,7 @@ import com.cloud.resource.ResourceWrapper; import com.cloud.utils.Ternary; import com.cloud.utils.exception.CloudRuntimeException; +import com.cloud.vm.VirtualMachine; import com.google.common.base.Strings; @ResourceWrapper(handles = MigrateCommand.class) @@ -181,6 +182,10 @@ Use VIR_DOMAIN_XML_SECURE (value = 1) prior to v1.0.0. dconn = libvirtUtilitiesHelper.retrieveQemuConnection(destinationUri); + if (to.getType() == VirtualMachine.Type.User) { + libvirtComputingResource.detachAndAttachConfigDriveISO(conn, vmName); + } + //run migration in thread so we can monitor it s_logger.info("Live migration of instance " + vmName + " initiated to destination host: " + dconn.getURI()); final ExecutorService executor = Executors.newFixedThreadPool(1); diff --git a/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtPlugNicCommandWrapper.java b/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtPlugNicCommandWrapper.java index 553a71a30dfe..ca78c718886e 100644 --- a/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtPlugNicCommandWrapper.java +++ b/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtPlugNicCommandWrapper.java @@ -72,6 +72,10 @@ public Answer execute(final PlugNicCommand command, final LibvirtComputingResour libvirtComputingResource.applyDefaultNetworkRulesOnNic(conn, vmName, vmId, nic, false, false); } + if (vmType == VirtualMachine.Type.User) { + libvirtComputingResource.detachAndAttachConfigDriveISO(conn, vmName); + } + return new PlugNicAnswer(command, true, "success"); } catch (final LibvirtException e) { final String msg = " Plug Nic failed due to " + e.toString(); diff --git a/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/storage/KVMStorageProcessor.java b/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/storage/KVMStorageProcessor.java index 34c610dd9a14..2ad3089cf371 100644 --- a/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/storage/KVMStorageProcessor.java +++ b/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/storage/KVMStorageProcessor.java @@ -70,6 +70,7 @@ import org.apache.cloudstack.utils.qemu.QemuImgFile; import org.apache.commons.collections.MapUtils; import org.apache.commons.io.FileUtils; +import org.apache.commons.lang.StringUtils; import org.apache.log4j.Logger; import org.libvirt.Connect; import org.libvirt.Domain; @@ -1195,6 +1196,14 @@ protected synchronized String attachOrDetachDevice(final Connect conn, final boo } else { s_logger.debug("Detaching device: " + xml); dm.detachDevice(xml); + LibvirtDomainXMLParser parser = new LibvirtDomainXMLParser(); + parser.parseDomainXML(dm.getXMLDesc(0)); + List disks = parser.getDisks(); + for (DiskDef diskDef : disks) { + if (StringUtils.contains(xml, diskDef.getDiskPath())) { + throw new InternalErrorException("Could not detach volume. Probably the VM is in boot state at the moment"); + } + } } } catch (final LibvirtException e) { if (attach) { diff --git a/plugins/hypervisors/kvm/src/main/java/org/apache/cloudstack/utils/linux/KVMHostInfo.java b/plugins/hypervisors/kvm/src/main/java/org/apache/cloudstack/utils/linux/KVMHostInfo.java index 1f28304806a7..60e98f58e72c 100644 --- a/plugins/hypervisors/kvm/src/main/java/org/apache/cloudstack/utils/linux/KVMHostInfo.java +++ b/plugins/hypervisors/kvm/src/main/java/org/apache/cloudstack/utils/linux/KVMHostInfo.java @@ -42,6 +42,8 @@ public class KVMHostInfo { private long overCommitMemory; private List capabilities = new ArrayList<>(); + private static String cpuInfoMaxFreqFileName = "/sys/devices/system/cpu/cpu0/cpufreq/cpuinfo_max_freq"; + public KVMHostInfo(long reservedMemory, long overCommitMemory) { this.reservedMemory = reservedMemory; this.overCommitMemory = overCommitMemory; @@ -78,11 +80,12 @@ public List getCapabilities() { } protected static long getCpuSpeed(final NodeInfo nodeInfo) { - try (final Reader reader = new FileReader( - "/sys/devices/system/cpu/cpu0/cpufreq/cpuinfo_max_freq")) { - return Long.parseLong(IOUtils.toString(reader).trim()) / 1000; + try (Reader reader = new FileReader(cpuInfoMaxFreqFileName)) { + Long cpuInfoMaxFreq = Long.parseLong(IOUtils.toString(reader).trim()); + LOGGER.info(String.format("Retrieved value [%s] from file [%s]. This corresponds to a CPU speed of [%s] MHz.", cpuInfoMaxFreq, cpuInfoMaxFreqFileName, cpuInfoMaxFreq / 1000)); + return cpuInfoMaxFreq / 1000; } catch (IOException | NumberFormatException e) { - LOGGER.info("Could not read cpuinfo_max_freq, falling back on libvirt"); + LOGGER.error(String.format("Unable to retrieve the CPU speed from file [%s]. Using the value [%s] provided by the Libvirt.", cpuInfoMaxFreqFileName, nodeInfo.mhz), e); return nodeInfo.mhz; } } diff --git a/plugins/hypervisors/kvm/src/test/java/com/cloud/hypervisor/kvm/resource/LibvirtComputingResourceTest.java b/plugins/hypervisors/kvm/src/test/java/com/cloud/hypervisor/kvm/resource/LibvirtComputingResourceTest.java index 84d08531c2bf..1020ff86e3ae 100644 --- a/plugins/hypervisors/kvm/src/test/java/com/cloud/hypervisor/kvm/resource/LibvirtComputingResourceTest.java +++ b/plugins/hypervisors/kvm/src/test/java/com/cloud/hypervisor/kvm/resource/LibvirtComputingResourceTest.java @@ -202,6 +202,9 @@ public class LibvirtComputingResourceTest { @Mock LibvirtVMDef vmDef; + private final static long HYPERVISOR_LIBVIRT_VERSION_SUPPORTS_IOURING = 6003000; + private final static long HYPERVISOR_QEMU_VERSION_SUPPORTS_IOURING = 5000000; + String hyperVisorType = "kvm"; Random random = new Random(); final String memInfo = "MemTotal: 5830236 kB\n" + @@ -5209,4 +5212,37 @@ public void testAddExtraConfigComponentNotEmptyExtraConfig() { libvirtComputingResource.addExtraConfigComponent(extraConfig, vmDef); Mockito.verify(vmDef, times(1)).addComp(any()); } + + @Test + public void setDiskIoDriverTestIoUring() { + DiskDef diskDef = configureAndTestSetDiskIoDriverTest(HYPERVISOR_LIBVIRT_VERSION_SUPPORTS_IOURING, HYPERVISOR_QEMU_VERSION_SUPPORTS_IOURING); + Assert.assertEquals(DiskDef.IoDriver.IOURING, diskDef.getIoDriver()); + } + + @Test + public void setDiskIoDriverTestLibvirtSupportsIoUring() { + DiskDef diskDef = configureAndTestSetDiskIoDriverTest(123l, HYPERVISOR_QEMU_VERSION_SUPPORTS_IOURING); + Assert.assertNotEquals(DiskDef.IoDriver.IOURING, diskDef.getIoDriver()); + } + + @Test + public void setDiskIoDriverTestQemuSupportsIoUring() { + DiskDef diskDef = configureAndTestSetDiskIoDriverTest(HYPERVISOR_LIBVIRT_VERSION_SUPPORTS_IOURING, 123l); + Assert.assertNotEquals(DiskDef.IoDriver.IOURING, diskDef.getIoDriver()); + } + + @Test + public void setDiskIoDriverTestNoSupportToIoUring() { + DiskDef diskDef = configureAndTestSetDiskIoDriverTest(123l, 123l); + Assert.assertNotEquals(DiskDef.IoDriver.IOURING, diskDef.getIoDriver()); + } + + private DiskDef configureAndTestSetDiskIoDriverTest(long hypervisorLibvirtVersion, long hypervisorQemuVersion) { + DiskDef diskDef = new DiskDef(); + LibvirtComputingResource libvirtComputingResourceSpy = Mockito.spy(new LibvirtComputingResource()); + Mockito.when(libvirtComputingResourceSpy.getHypervisorLibvirtVersion()).thenReturn(hypervisorLibvirtVersion); + Mockito.when(libvirtComputingResourceSpy.getHypervisorQemuVersion()).thenReturn(hypervisorQemuVersion); + libvirtComputingResourceSpy.setDiskIoDriver(diskDef); + return diskDef; + } } diff --git a/plugins/hypervisors/simulator/src/main/java/com/cloud/resource/SimulatorDiscoverer.java b/plugins/hypervisors/simulator/src/main/java/com/cloud/resource/SimulatorDiscoverer.java index c942c8ff55ce..8f1b07f027b6 100644 --- a/plugins/hypervisors/simulator/src/main/java/com/cloud/resource/SimulatorDiscoverer.java +++ b/plugins/hypervisors/simulator/src/main/java/com/cloud/resource/SimulatorDiscoverer.java @@ -251,25 +251,6 @@ public void processHostAdded(long hostId) { @Override public void processConnect(Host host, StartupCommand cmd, boolean forRebalance) throws ConnectionException { - - /*if(forRebalance) - return; - if ( Host.Type.SecondaryStorage == host.getType() ) { - List tmplts = _vmTemplateDao.listAll(); - for( VMTemplateVO tmplt : tmplts ) { - VMTemplateHostVO vmTemplateHost = _vmTemplateHostDao.findByHostTemplate(host.getId(), tmplt.getId()); - if (vmTemplateHost == null) { - vmTemplateHost = new VMTemplateHostVO(host.getId(), tmplt.getId(), new Date(), 100, - com.cloud.storage.VMTemplateStorageResourceAssoc.Status.DOWNLOADED, null, null, null, null, tmplt.getUrl()); - _vmTemplateHostDao.persist(vmTemplateHost); - } else { - vmTemplateHost.setDownloadState(com.cloud.storage.VMTemplateStorageResourceAssoc.Status.DOWNLOADED); - vmTemplateHost.setDownloadPercent(100); - _vmTemplateHostDao.update(vmTemplateHost.getId(), vmTemplateHost); - } - } - }*/ - } @Override diff --git a/plugins/hypervisors/vmware/src/main/java/com/cloud/hypervisor/vmware/resource/VmwareResource.java b/plugins/hypervisors/vmware/src/main/java/com/cloud/hypervisor/vmware/resource/VmwareResource.java index a9a953af5137..e2a7969af060 100644 --- a/plugins/hypervisors/vmware/src/main/java/com/cloud/hypervisor/vmware/resource/VmwareResource.java +++ b/plugins/hypervisors/vmware/src/main/java/com/cloud/hypervisor/vmware/resource/VmwareResource.java @@ -4865,7 +4865,7 @@ private Answer execute(MigrateVolumeCommand cmd) { } } VirtualMachineDiskInfoBuilder diskInfoBuilder = vmMo.getDiskInfoBuilder(); - String chainInfo = _gson.toJson(diskInfoBuilder.getDiskInfoByBackingFileBaseName(volumePath, poolTo.getUuid().replace("-", ""))); + String chainInfo = _gson.toJson(diskInfoBuilder.getDiskInfoByBackingFileBaseName(volumePath, targetDsMo.getName())); MigrateVolumeAnswer answer = new MigrateVolumeAnswer(cmd, true, null, volumePath); answer.setVolumeChainInfo(chainInfo); return answer; @@ -7337,7 +7337,7 @@ private List relocateVirtualMachine(final VmwareHypervisorHost h if (targetHyperHost != null) { ManagedObjectReference morTargetHostDc = targetHyperHost.getHyperHostDatacenter(); if (!morSourceHostDc.getValue().equalsIgnoreCase(morTargetHostDc.getValue())) { - String msg = "VM " + vmName + " cannot be migrated between different datacenter"; + String msg = String.format("VM: %s cannot be migrated between different datacenter", vmName); throw new CloudRuntimeException(msg); } } @@ -7345,12 +7345,12 @@ private List relocateVirtualMachine(final VmwareHypervisorHost h // find VM through source host (VM is not at the target host yet) vmMo = sourceHyperHost.findVmOnHyperHost(vmName); if (vmMo == null) { - String msg = "VM " + vmName + " does not exist on host: " + sourceHyperHost.getHyperHostName(); + String msg = String.format("VM: %s does not exist on host: %s", vmName, sourceHyperHost.getHyperHostName()); s_logger.warn(msg); // find VM through source host (VM is not at the target host yet) vmMo = dcMo.findVm(vmName); if (vmMo == null) { - msg = "VM " + vmName + " does not exist on datacenter: " + dcMo.getName(); + msg = String.format("VM: %s does not exist on datacenter: %s", vmName, dcMo.getName()); s_logger.error(msg); throw new Exception(msg); } @@ -7364,11 +7364,9 @@ private List relocateVirtualMachine(final VmwareHypervisorHost h if (StringUtils.isNotBlank(poolUuid)) { VmwareHypervisorHost dsHost = targetHyperHost == null ? sourceHyperHost : targetHyperHost; ManagedObjectReference morDatastore = null; - String msg; morDatastore = getTargetDatastoreMOReference(poolUuid, dsHost); if (morDatastore == null) { - msg = "Unable to find the target datastore: " + poolUuid + " on host: " + dsHost.getHyperHostName() + - " to execute migration"; + String msg = String.format("Unable to find the target datastore: %s on host: %s to execute migration", poolUuid, dsHost.getHyperHostName()); s_logger.error(msg); throw new CloudRuntimeException(msg); } @@ -7384,7 +7382,7 @@ private List relocateVirtualMachine(final VmwareHypervisorHost h } ManagedObjectReference morVolumeDatastore = getTargetDatastoreMOReference(filerTo.getUuid(), dsHost); if (morVolumeDatastore == null) { - String msg = "Unable to find the target datastore: " + filerTo.getUuid() + " in datacenter: " + dcMo.getName() + " to execute migration"; + String msg = String.format("Unable to find the target datastore: %s in datacenter: %s to execute migration", filerTo.getUuid(), dcMo.getName()); s_logger.error(msg); throw new CloudRuntimeException(msg); } @@ -7445,8 +7443,7 @@ private List relocateVirtualMachine(final VmwareHypervisorHost h mgr.prepareSecondaryStorageStore(secStoreUrl, secStoreId); ManagedObjectReference morSecDs = prepareSecondaryDatastoreOnSpecificHost(secStoreUrl, targetHyperHost); if (morSecDs == null) { - String msg = "Failed to prepare secondary storage on host, secondary store url: " + secStoreUrl; - throw new Exception(msg); + throw new Exception(String.format("Failed to prepare secondary storage on host, secondary store url: %s", secStoreUrl)); } } @@ -7455,7 +7452,7 @@ private List relocateVirtualMachine(final VmwareHypervisorHost h if (!vmMo.changeDatastore(relocateSpec)) { throw new Exception("Change datastore operation failed during storage migration"); } else { - s_logger.debug("Successfully migrated storage of VM " + vmName + " to target datastore(s)"); + s_logger.debug(String.format("Successfully migrated storage of VM: %s to target datastore(s)", vmName)); } // Migrate VM to target host. if (targetHyperHost != null) { @@ -7463,7 +7460,7 @@ private List relocateVirtualMachine(final VmwareHypervisorHost h if (!vmMo.migrate(morPool, targetHyperHost.getMor())) { throw new Exception("VM migration to target host failed during storage migration"); } else { - s_logger.debug("Successfully migrated VM " + vmName + " from " + sourceHyperHost.getHyperHostName() + " to " + targetHyperHost.getHyperHostName()); + s_logger.debug(String.format("Successfully migrated VM: %s from host %s to %s", vmName , sourceHyperHost.getHyperHostName(), targetHyperHost.getHyperHostName())); } } } else { @@ -7475,9 +7472,11 @@ private List relocateVirtualMachine(final VmwareHypervisorHost h if (!vmMo.changeDatastore(relocateSpec)) { throw new Exception("Change datastore operation failed during storage migration"); } else { - s_logger.debug("Successfully migrated VM " + vmName + - (hostInTargetCluster != null ? " from " + sourceHyperHost.getHyperHostName() + " to " + targetHyperHost.getHyperHostName() + " and " : " with ") + - "its storage to target datastore(s)"); + String msg = String.format("Successfully migrated VM: %s with its storage to target datastore(s)", vmName); + if (targetHyperHost != null) { + msg = String.format("% from host %s to %s", msg, sourceHyperHost.getHyperHostName(), targetHyperHost.getHyperHostName()); + } + s_logger.debug(msg); } } @@ -7486,7 +7485,7 @@ private List relocateVirtualMachine(final VmwareHypervisorHost h if (!vmMo.consolidateVmDisks()) { s_logger.warn("VM disk consolidation failed after storage migration. Yet proceeding with VM migration."); } else { - s_logger.debug("Successfully consolidated disks of VM " + vmName + "."); + s_logger.debug(String.format("Successfully consolidated disks of VM: %s", vmName)); } if (MapUtils.isNotEmpty(volumeDeviceKey)) { @@ -7501,8 +7500,9 @@ private List relocateVirtualMachine(final VmwareHypervisorHost h VolumeObjectTO newVol = new VolumeObjectTO(); newVol.setDataStoreUuid(entry.second().getUuid()); String newPath = vmMo.getVmdkFileBaseName(disk); - String poolName = entry.second().getUuid().replace("-", ""); - VirtualMachineDiskInfo diskInfo = diskInfoBuilder.getDiskInfoByBackingFileBaseName(newPath, poolName); + ManagedObjectReference morDs = HypervisorHostHelper.findDatastoreWithBackwardsCompatibility(targetHyperHost != null ? targetHyperHost : sourceHyperHost, entry.second().getUuid()); + DatastoreMO dsMo = new DatastoreMO(getServiceContext(), morDs); + VirtualMachineDiskInfo diskInfo = diskInfoBuilder.getDiskInfoByBackingFileBaseName(newPath, dsMo.getName()); newVol.setId(volumeId); newVol.setPath(newPath); newVol.setChainInfo(_gson.toJson(diskInfo)); diff --git a/plugins/integrations/kubernetes-service/src/main/java/com/cloud/kubernetes/cluster/actionworkers/KubernetesClusterResourceModifierActionWorker.java b/plugins/integrations/kubernetes-service/src/main/java/com/cloud/kubernetes/cluster/actionworkers/KubernetesClusterResourceModifierActionWorker.java index 28f925915c95..e60807ec56d7 100644 --- a/plugins/integrations/kubernetes-service/src/main/java/com/cloud/kubernetes/cluster/actionworkers/KubernetesClusterResourceModifierActionWorker.java +++ b/plugins/integrations/kubernetes-service/src/main/java/com/cloud/kubernetes/cluster/actionworkers/KubernetesClusterResourceModifierActionWorker.java @@ -142,8 +142,8 @@ protected void init() { private String getKubernetesNodeConfig(final String joinIp, final boolean ejectIso) throws IOException { String k8sNodeConfig = readResourceFile("/conf/k8s-node.yml"); final String sshPubKey = "{{ k8s.ssh.pub.key }}"; - final String joinIpKey = "{{ k8s_master.join_ip }}"; - final String clusterTokenKey = "{{ k8s_master.cluster.token }}"; + final String joinIpKey = "{{ k8s_control_node.join_ip }}"; + final String clusterTokenKey = "{{ k8s_control_node.cluster.token }}"; final String ejectIsoKey = "{{ k8s.eject.iso }}"; String pubKey = "- \"" + configurationDao.getValue("ssh.publickey") + "\""; String sshKeyPair = kubernetesCluster.getKeyPair(); diff --git a/plugins/integrations/kubernetes-service/src/main/java/com/cloud/kubernetes/cluster/actionworkers/KubernetesClusterStartWorker.java b/plugins/integrations/kubernetes-service/src/main/java/com/cloud/kubernetes/cluster/actionworkers/KubernetesClusterStartWorker.java index c6f939cf4269..9a30fdd82357 100644 --- a/plugins/integrations/kubernetes-service/src/main/java/com/cloud/kubernetes/cluster/actionworkers/KubernetesClusterStartWorker.java +++ b/plugins/integrations/kubernetes-service/src/main/java/com/cloud/kubernetes/cluster/actionworkers/KubernetesClusterStartWorker.java @@ -89,8 +89,8 @@ public KubernetesSupportedVersion getKubernetesClusterVersion() { return kubernetesClusterVersion; } - private Pair> getKubernetesControlIpAddresses(final DataCenter zone, final Network network, final Account account) throws InsufficientAddressCapacityException { - String controlIp = null; + private Pair> getKubernetesControlNodeIpAddresses(final DataCenter zone, final Network network, final Account account) throws InsufficientAddressCapacityException { + String controlNodeIp = null; Map requestedIps = null; if (Network.GuestType.Shared.equals(network.getGuestType())) { List vlanIds = new ArrayList<>(); @@ -100,16 +100,16 @@ private Pair> getKubernetesControlIpAddre } PublicIp ip = ipAddressManager.getAvailablePublicIpAddressFromVlans(zone.getId(), null, account, Vlan.VlanType.DirectAttached, vlanIds,network.getId(), null, false); if (ip != null) { - controlIp = ip.getAddress().toString(); + controlNodeIp = ip.getAddress().toString(); } requestedIps = new HashMap<>(); Ip ipAddress = ip.getAddress(); boolean isIp6 = ipAddress.isIp6(); requestedIps.put(network.getId(), new Network.IpAddresses(ipAddress.isIp4() ? ip.getAddress().addr() : null, null)); } else { - controlIp = ipAddressManager.acquireGuestIpAddress(networkDao.findById(kubernetesCluster.getNetworkId()), null); + controlNodeIp = ipAddressManager.acquireGuestIpAddress(networkDao.findById(kubernetesCluster.getNetworkId()), null); } - return new Pair<>(controlIp, requestedIps); + return new Pair<>(controlNodeIp, requestedIps); } private boolean isKubernetesVersionSupportsHA() { @@ -127,20 +127,20 @@ private boolean isKubernetesVersionSupportsHA() { return haSupported; } - private String getKubernetesControlConfig(final String controlIp, final String serverIp, - final String hostName, final boolean haSupported, - final boolean ejectIso) throws IOException { - String k8sControlConfig = readResourceFile("/conf/k8s-control-node.yml"); - final String apiServerCert = "{{ k8s_master.apiserver.crt }}"; - final String apiServerKey = "{{ k8s_master.apiserver.key }}"; - final String caCert = "{{ k8s_master.ca.crt }}"; + private String getKubernetesControlNodeConfig(final String controlNodeIp, final String serverIp, + final String hostName, final boolean haSupported, + final boolean ejectIso) throws IOException { + String k8sControlNodeConfig = readResourceFile("/conf/k8s-control-node.yml"); + final String apiServerCert = "{{ k8s_control_node.apiserver.crt }}"; + final String apiServerKey = "{{ k8s_control_node.apiserver.key }}"; + final String caCert = "{{ k8s_control_node.ca.crt }}"; final String sshPubKey = "{{ k8s.ssh.pub.key }}"; - final String clusterToken = "{{ k8s_master.cluster.token }}"; - final String clusterInitArgsKey = "{{ k8s_master.cluster.initargs }}"; + final String clusterToken = "{{ k8s_control_node.cluster.token }}"; + final String clusterInitArgsKey = "{{ k8s_control_node.cluster.initargs }}"; final String ejectIsoKey = "{{ k8s.eject.iso }}"; final List addresses = new ArrayList<>(); - addresses.add(controlIp); - if (!serverIp.equals(controlIp)) { + addresses.add(controlNodeIp); + if (!serverIp.equals(controlNodeIp)) { addresses.add(serverIp); } final Certificate certificate = caManager.issueCertificate(null, Arrays.asList(hostName, "kubernetes", @@ -149,9 +149,9 @@ private String getKubernetesControlConfig(final String controlIp, final String s final String tlsClientCert = CertUtils.x509CertificateToPem(certificate.getClientCertificate()); final String tlsPrivateKey = CertUtils.privateKeyToPem(certificate.getPrivateKey()); final String tlsCaCert = CertUtils.x509CertificatesToPem(certificate.getCaCertificates()); - k8sControlConfig = k8sControlConfig.replace(apiServerCert, tlsClientCert.replace("\n", "\n ")); - k8sControlConfig = k8sControlConfig.replace(apiServerKey, tlsPrivateKey.replace("\n", "\n ")); - k8sControlConfig = k8sControlConfig.replace(caCert, tlsCaCert.replace("\n", "\n ")); + k8sControlNodeConfig = k8sControlNodeConfig.replace(apiServerCert, tlsClientCert.replace("\n", "\n ")); + k8sControlNodeConfig = k8sControlNodeConfig.replace(apiServerKey, tlsPrivateKey.replace("\n", "\n ")); + k8sControlNodeConfig = k8sControlNodeConfig.replace(caCert, tlsCaCert.replace("\n", "\n ")); String pubKey = "- \"" + configurationDao.getValue("ssh.publickey") + "\""; String sshKeyPair = kubernetesCluster.getKeyPair(); if (!Strings.isNullOrEmpty(sshKeyPair)) { @@ -160,8 +160,8 @@ private String getKubernetesControlConfig(final String controlIp, final String s pubKey += "\n - \"" + sshkp.getPublicKey() + "\""; } } - k8sControlConfig = k8sControlConfig.replace(sshPubKey, pubKey); - k8sControlConfig = k8sControlConfig.replace(clusterToken, KubernetesClusterUtil.generateClusterToken(kubernetesCluster)); + k8sControlNodeConfig = k8sControlNodeConfig.replace(sshPubKey, pubKey); + k8sControlNodeConfig = k8sControlNodeConfig.replace(clusterToken, KubernetesClusterUtil.generateClusterToken(kubernetesCluster)); String initArgs = ""; if (haSupported) { initArgs = String.format("--control-plane-endpoint %s:%d --upload-certs --certificate-key %s ", @@ -171,9 +171,9 @@ private String getKubernetesControlConfig(final String controlIp, final String s } initArgs += String.format("--apiserver-cert-extra-sans=%s", serverIp); initArgs += String.format(" --kubernetes-version=%s", getKubernetesClusterVersion().getSemanticVersion()); - k8sControlConfig = k8sControlConfig.replace(clusterInitArgsKey, initArgs); - k8sControlConfig = k8sControlConfig.replace(ejectIsoKey, String.valueOf(ejectIso)); - return k8sControlConfig; + k8sControlNodeConfig = k8sControlNodeConfig.replace(clusterInitArgsKey, initArgs); + k8sControlNodeConfig = k8sControlNodeConfig.replace(ejectIsoKey, String.valueOf(ejectIso)); + return k8sControlNodeConfig; } private UserVm createKubernetesControlNode(final Network network, String serverIp) throws ManagementServerException, @@ -183,13 +183,13 @@ private UserVm createKubernetesControlNode(final Network network, String serverI ServiceOffering serviceOffering = serviceOfferingDao.findById(kubernetesCluster.getServiceOfferingId()); List networkIds = new ArrayList(); networkIds.add(kubernetesCluster.getNetworkId()); - Pair> ipAddresses = getKubernetesControlIpAddresses(zone, network, owner); - String controlIp = ipAddresses.first(); + Pair> ipAddresses = getKubernetesControlNodeIpAddresses(zone, network, owner); + String controlNodeIp = ipAddresses.first(); Map requestedIps = ipAddresses.second(); if (Network.GuestType.Shared.equals(network.getGuestType()) && Strings.isNullOrEmpty(serverIp)) { - serverIp = controlIp; + serverIp = controlNodeIp; } - Network.IpAddresses addrs = new Network.IpAddresses(controlIp, null); + Network.IpAddresses addrs = new Network.IpAddresses(controlNodeIp, null); long rootDiskSize = kubernetesCluster.getNodeRootDiskSize(); Map customParameterMap = new HashMap(); if (rootDiskSize > 0) { @@ -201,13 +201,13 @@ private UserVm createKubernetesControlNode(final Network network, String serverI } hostName = getKubernetesClusterNodeAvailableName(hostName); boolean haSupported = isKubernetesVersionSupportsHA(); - String k8sControlConfig = null; + String k8sControlNodeConfig = null; try { - k8sControlConfig = getKubernetesControlConfig(controlIp, serverIp, hostName, haSupported, Hypervisor.HypervisorType.VMware.equals(clusterTemplate.getHypervisorType())); + k8sControlNodeConfig = getKubernetesControlNodeConfig(controlNodeIp, serverIp, hostName, haSupported, Hypervisor.HypervisorType.VMware.equals(clusterTemplate.getHypervisorType())); } catch (IOException e) { - logAndThrow(Level.ERROR, "Failed to read Kubernetes control configuration file", e); + logAndThrow(Level.ERROR, "Failed to read Kubernetes control node configuration file", e); } - String base64UserData = Base64.encodeBase64String(k8sControlConfig.getBytes(StringUtils.getPreferredCharset())); + String base64UserData = Base64.encodeBase64String(k8sControlNodeConfig.getBytes(StringUtils.getPreferredCharset())); controlVm = userVmService.createAdvancedVirtualMachine(zone, serviceOffering, clusterTemplate, networkIds, owner, hostName, hostName, null, null, null, Hypervisor.HypervisorType.None, BaseCmd.HTTPMethod.POST, base64UserData, kubernetesCluster.getKeyPair(), @@ -218,12 +218,12 @@ private UserVm createKubernetesControlNode(final Network network, String serverI return controlVm; } - private String getKubernetesAdditionalControlConfig(final String joinIp, final boolean ejectIso) throws IOException { - String k8sControlConfig = readResourceFile("/conf/k8s-control-node-add.yml"); - final String joinIpKey = "{{ k8s_master.join_ip }}"; - final String clusterTokenKey = "{{ k8s_master.cluster.token }}"; + private String getKubernetesAdditionalControlNodeConfig(final String joinIp, final boolean ejectIso) throws IOException { + String k8sControlNodeConfig = readResourceFile("/conf/k8s-control-node-add.yml"); + final String joinIpKey = "{{ k8s_control_node.join_ip }}"; + final String clusterTokenKey = "{{ k8s_control_node.cluster.token }}"; final String sshPubKey = "{{ k8s.ssh.pub.key }}"; - final String clusterHACertificateKey = "{{ k8s_master.cluster.ha.certificate.key }}"; + final String clusterHACertificateKey = "{{ k8s_control_node.cluster.ha.certificate.key }}"; final String ejectIsoKey = "{{ k8s.eject.iso }}"; String pubKey = "- \"" + configurationDao.getValue("ssh.publickey") + "\""; String sshKeyPair = kubernetesCluster.getKeyPair(); @@ -233,12 +233,12 @@ private String getKubernetesAdditionalControlConfig(final String joinIp, final b pubKey += "\n - \"" + sshkp.getPublicKey() + "\""; } } - k8sControlConfig = k8sControlConfig.replace(sshPubKey, pubKey); - k8sControlConfig = k8sControlConfig.replace(joinIpKey, joinIp); - k8sControlConfig = k8sControlConfig.replace(clusterTokenKey, KubernetesClusterUtil.generateClusterToken(kubernetesCluster)); - k8sControlConfig = k8sControlConfig.replace(clusterHACertificateKey, KubernetesClusterUtil.generateClusterHACertificateKey(kubernetesCluster)); - k8sControlConfig = k8sControlConfig.replace(ejectIsoKey, String.valueOf(ejectIso)); - return k8sControlConfig; + k8sControlNodeConfig = k8sControlNodeConfig.replace(sshPubKey, pubKey); + k8sControlNodeConfig = k8sControlNodeConfig.replace(joinIpKey, joinIp); + k8sControlNodeConfig = k8sControlNodeConfig.replace(clusterTokenKey, KubernetesClusterUtil.generateClusterToken(kubernetesCluster)); + k8sControlNodeConfig = k8sControlNodeConfig.replace(clusterHACertificateKey, KubernetesClusterUtil.generateClusterHACertificateKey(kubernetesCluster)); + k8sControlNodeConfig = k8sControlNodeConfig.replace(ejectIsoKey, String.valueOf(ejectIso)); + return k8sControlNodeConfig; } private UserVm createKubernetesAdditionalControlNode(final String joinIp, final int additionalControlNodeInstance) throws ManagementServerException, @@ -255,13 +255,13 @@ private UserVm createKubernetesAdditionalControlNode(final String joinIp, final customParameterMap.put("rootdisksize", String.valueOf(rootDiskSize)); } String hostName = getKubernetesClusterNodeAvailableName(String.format("%s-control-%d", kubernetesClusterNodeNamePrefix, additionalControlNodeInstance + 1)); - String k8sControlConfig = null; + String k8sControlNodeConfig = null; try { - k8sControlConfig = getKubernetesAdditionalControlConfig(joinIp, Hypervisor.HypervisorType.VMware.equals(clusterTemplate.getHypervisorType())); + k8sControlNodeConfig = getKubernetesAdditionalControlNodeConfig(joinIp, Hypervisor.HypervisorType.VMware.equals(clusterTemplate.getHypervisorType())); } catch (IOException e) { logAndThrow(Level.ERROR, "Failed to read Kubernetes control configuration file", e); } - String base64UserData = Base64.encodeBase64String(k8sControlConfig.getBytes(StringUtils.getPreferredCharset())); + String base64UserData = Base64.encodeBase64String(k8sControlNodeConfig.getBytes(StringUtils.getPreferredCharset())); additionalControlVm = userVmService.createAdvancedVirtualMachine(zone, serviceOffering, clusterTemplate, networkIds, owner, hostName, hostName, null, null, null, Hypervisor.HypervisorType.None, BaseCmd.HTTPMethod.POST, base64UserData, kubernetesCluster.getKeyPair(), diff --git a/plugins/integrations/kubernetes-service/src/main/java/org/apache/cloudstack/api/response/KubernetesClusterResponse.java b/plugins/integrations/kubernetes-service/src/main/java/org/apache/cloudstack/api/response/KubernetesClusterResponse.java index 682aaaca8126..cbfa6accff5b 100644 --- a/plugins/integrations/kubernetes-service/src/main/java/org/apache/cloudstack/api/response/KubernetesClusterResponse.java +++ b/plugins/integrations/kubernetes-service/src/main/java/org/apache/cloudstack/api/response/KubernetesClusterResponse.java @@ -101,9 +101,9 @@ public class KubernetesClusterResponse extends BaseResponse implements Controlle @Param(description = "keypair details") private String keypair; - @Deprecated + @Deprecated(since = "4.16") @SerializedName(ApiConstants.MASTER_NODES) - @Param(description = "the master nodes count for the Kubernetes cluster") + @Param(description = "the master nodes count for the Kubernetes cluster. This parameter is deprecated, please use 'controlnodes' parameter.") private Long masterNodes; @SerializedName(ApiConstants.CONTROL_NODES) diff --git a/plugins/integrations/kubernetes-service/src/main/resources/conf/k8s-control-node-add.yml b/plugins/integrations/kubernetes-service/src/main/resources/conf/k8s-control-node-add.yml index 787ea97491ce..a8650ac957b3 100644 --- a/plugins/integrations/kubernetes-service/src/main/resources/conf/k8s-control-node-add.yml +++ b/plugins/integrations/kubernetes-service/src/main/resources/conf/k8s-control-node-add.yml @@ -196,7 +196,7 @@ write-files: if [[ "$PATH" != *:/opt/bin && "$PATH" != *:/opt/bin:* ]]; then export PATH=$PATH:/opt/bin fi - kubeadm join {{ k8s_master.join_ip }}:6443 --token {{ k8s_master.cluster.token }} --control-plane --certificate-key {{ k8s_master.cluster.ha.certificate.key }} --discovery-token-unsafe-skip-ca-verification + kubeadm join {{ k8s_control_node.join_ip }}:6443 --token {{ k8s_control_node.cluster.token }} --control-plane --certificate-key {{ k8s_control_node.cluster.ha.certificate.key }} --discovery-token-unsafe-skip-ca-verification sudo touch /home/core/success echo "true" > /home/core/success @@ -229,7 +229,7 @@ coreos: Type=simple StartLimitInterval=0 Restart=on-failure - ExecStartPre=/usr/bin/curl -k https://{{ k8s_master.join_ip }}:6443/version + ExecStartPre=/usr/bin/curl -k https://{{ k8s_control_node.join_ip }}:6443/version ExecStart=/opt/bin/deploy-kube-system update: diff --git a/plugins/integrations/kubernetes-service/src/main/resources/conf/k8s-control-node.yml b/plugins/integrations/kubernetes-service/src/main/resources/conf/k8s-control-node.yml index db7d7530ed88..c2cecc4a0994 100644 --- a/plugins/integrations/kubernetes-service/src/main/resources/conf/k8s-control-node.yml +++ b/plugins/integrations/kubernetes-service/src/main/resources/conf/k8s-control-node.yml @@ -29,17 +29,17 @@ write-files: - path: /etc/kubernetes/pki/cloudstack/ca.crt permissions: '0644' content: | - {{ k8s_master.ca.crt }} + {{ k8s_control_node.ca.crt }} - path: /etc/kubernetes/pki/cloudstack/apiserver.crt permissions: '0644' content: | - {{ k8s_master.apiserver.crt }} + {{ k8s_control_node.apiserver.crt }} - path: /etc/kubernetes/pki/cloudstack/apiserver.key permissions: '0600' content: | - {{ k8s_master.apiserver.key }} + {{ k8s_control_node.apiserver.key }} - path: /opt/bin/setup-kube-system permissions: 0700 @@ -204,7 +204,7 @@ write-files: fi retval=0 set +e - kubeadm init --token {{ k8s_master.cluster.token }} --token-ttl 0 {{ k8s_master.cluster.initargs }} + kubeadm init --token {{ k8s_control_node.cluster.token }} --token-ttl 0 {{ k8s_control_node.cluster.initargs }} retval=$? set -e if [ $retval -eq 0 ]; then diff --git a/plugins/integrations/kubernetes-service/src/main/resources/conf/k8s-node.yml b/plugins/integrations/kubernetes-service/src/main/resources/conf/k8s-node.yml index d2f5454a669d..f65cc9c82963 100644 --- a/plugins/integrations/kubernetes-service/src/main/resources/conf/k8s-node.yml +++ b/plugins/integrations/kubernetes-service/src/main/resources/conf/k8s-node.yml @@ -196,7 +196,7 @@ write-files: if [[ "$PATH" != *:/opt/bin && "$PATH" != *:/opt/bin:* ]]; then export PATH=$PATH:/opt/bin fi - kubeadm join {{ k8s_master.join_ip }}:6443 --token {{ k8s_master.cluster.token }} --discovery-token-unsafe-skip-ca-verification + kubeadm join {{ k8s_control_node.join_ip }}:6443 --token {{ k8s_control_node.cluster.token }} --discovery-token-unsafe-skip-ca-verification sudo touch /home/core/success echo "true" > /home/core/success @@ -229,7 +229,7 @@ coreos: Type=simple StartLimitInterval=0 Restart=on-failure - ExecStartPre=/usr/bin/curl -k https://{{ k8s_master.join_ip }}:6443/version + ExecStartPre=/usr/bin/curl -k https://{{ k8s_control_node.join_ip }}:6443/version ExecStart=/opt/bin/deploy-kube-system update: diff --git a/plugins/network-elements/elastic-loadbalancer/src/main/java/com/cloud/network/ElasticLbVmMapVO.java b/plugins/network-elements/elastic-loadbalancer/src/main/java/com/cloud/network/ElasticLbVmMapVO.java index 835dc5448f55..b9bad7f65754 100644 --- a/plugins/network-elements/elastic-loadbalancer/src/main/java/com/cloud/network/ElasticLbVmMapVO.java +++ b/plugins/network-elements/elastic-loadbalancer/src/main/java/com/cloud/network/ElasticLbVmMapVO.java @@ -33,7 +33,7 @@ import com.cloud.utils.net.Ip; @Entity -@Table(name = ("elastic_lb_vm_map")) +@Table(name = "elastic_lb_vm_map") @SecondaryTables({@SecondaryTable(name = "user_ip_address", pkJoinColumns = {@PrimaryKeyJoinColumn(name = "ip_addr_id", referencedColumnName = "id")})}) public class ElasticLbVmMapVO implements InternalIdentity { @Id diff --git a/plugins/network-elements/juniper-contrail/src/test/java/org/apache/cloudstack/network/contrail/management/IntegrationTestConfiguration.java b/plugins/network-elements/juniper-contrail/src/test/java/org/apache/cloudstack/network/contrail/management/IntegrationTestConfiguration.java index 4105a617e6c2..989d74b6c950 100644 --- a/plugins/network-elements/juniper-contrail/src/test/java/org/apache/cloudstack/network/contrail/management/IntegrationTestConfiguration.java +++ b/plugins/network-elements/juniper-contrail/src/test/java/org/apache/cloudstack/network/contrail/management/IntegrationTestConfiguration.java @@ -256,10 +256,8 @@ import com.cloud.storage.dao.UploadDaoImpl; import com.cloud.storage.dao.VMTemplateDaoImpl; import com.cloud.storage.dao.VMTemplateDetailsDaoImpl; -import com.cloud.storage.dao.VMTemplateHostDaoImpl; import com.cloud.storage.dao.VMTemplateZoneDaoImpl; import com.cloud.storage.dao.VolumeDaoImpl; -import com.cloud.storage.dao.VolumeHostDaoImpl; import com.cloud.storage.snapshot.SnapshotApiService; import com.cloud.storage.snapshot.SnapshotManager; import com.cloud.tags.dao.ResourceTagDao; @@ -332,8 +330,8 @@ StoragePoolJoinDaoImpl.class, SyncQueueItemDaoImpl.class, TemplateDataStoreDaoImpl.class, TemplateJoinDaoImpl.class, UploadDaoImpl.class, UsageEventDaoImpl.class, UserAccountJoinDaoImpl.class, UserDaoImpl.class, UserIpv6AddressDaoImpl.class, UserStatisticsDaoImpl.class, UserStatsLogDaoImpl.class, UserVmCloneSettingDaoImpl.class, UserVmDaoImpl.class, UserVmDetailsDaoImpl.class, UserVmJoinDaoImpl.class, UserVmManagerImpl.class, VMInstanceDaoImpl.class, VMSnapshotDaoImpl.class, - VMTemplateDaoImpl.class, VMTemplateDetailsDaoImpl.class, VMTemplateHostDaoImpl.class, VMTemplateZoneDaoImpl.class, VirtualMachineManagerImpl.class, VirtualRouterProviderDaoImpl.class, - VlanDaoImpl.class, VmDiskStatisticsDaoImpl.class, VmRulesetLogDaoImpl.class, VolumeDaoImpl.class, VolumeHostDaoImpl.class, VolumeJoinDaoImpl.class, VpcDaoImpl.class, + VMTemplateDaoImpl.class, VMTemplateDetailsDaoImpl.class, VMTemplateZoneDaoImpl.class, VirtualMachineManagerImpl.class, VirtualRouterProviderDaoImpl.class, + VlanDaoImpl.class, VmDiskStatisticsDaoImpl.class, VmRulesetLogDaoImpl.class, VolumeDaoImpl.class, VolumeJoinDaoImpl.class, VpcDaoImpl.class, VpcGatewayDaoImpl.class, VpcManagerImpl.class, VpcOfferingDaoImpl.class, VpcOfferingServiceMapDaoImpl.class, VpcServiceMapDaoImpl.class, VpcVirtualNetworkApplianceManagerImpl.class, VpnUserDaoImpl.class, XenServerGuru.class}, includeFilters = {@Filter(value = IntegrationTestConfiguration.ComponentFilter.class, type = FilterType.CUSTOM)}, useDefaultFilters = false) diff --git a/plugins/network-elements/netscaler/src/main/java/com/cloud/network/NetScalerServicePackageVO.java b/plugins/network-elements/netscaler/src/main/java/com/cloud/network/NetScalerServicePackageVO.java index 82b3fef85077..1ad99b1dab2c 100644 --- a/plugins/network-elements/netscaler/src/main/java/com/cloud/network/NetScalerServicePackageVO.java +++ b/plugins/network-elements/netscaler/src/main/java/com/cloud/network/NetScalerServicePackageVO.java @@ -34,7 +34,7 @@ * By using the service package, CloudStack can choose the kind of NetScaler offering it wants to use. */ @Entity -@Table(name = " netscaler_servicepackages") +@Table(name = "netscaler_servicepackages") public class NetScalerServicePackageVO implements InternalIdentity { diff --git a/plugins/network-elements/ovs/src/main/java/com/cloud/network/ovs/dao/OvsTunnelInterfaceVO.java b/plugins/network-elements/ovs/src/main/java/com/cloud/network/ovs/dao/OvsTunnelInterfaceVO.java index ff40efac8f68..462794ba9a17 100644 --- a/plugins/network-elements/ovs/src/main/java/com/cloud/network/ovs/dao/OvsTunnelInterfaceVO.java +++ b/plugins/network-elements/ovs/src/main/java/com/cloud/network/ovs/dao/OvsTunnelInterfaceVO.java @@ -27,7 +27,7 @@ import org.apache.cloudstack.api.InternalIdentity; @Entity -@Table(name = ("ovs_tunnel_interface")) +@Table(name = "ovs_tunnel_interface") public class OvsTunnelInterfaceVO implements InternalIdentity { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) diff --git a/plugins/network-elements/ovs/src/main/java/com/cloud/network/ovs/dao/OvsTunnelNetworkVO.java b/plugins/network-elements/ovs/src/main/java/com/cloud/network/ovs/dao/OvsTunnelNetworkVO.java index 88a759130864..dd46e4846f69 100644 --- a/plugins/network-elements/ovs/src/main/java/com/cloud/network/ovs/dao/OvsTunnelNetworkVO.java +++ b/plugins/network-elements/ovs/src/main/java/com/cloud/network/ovs/dao/OvsTunnelNetworkVO.java @@ -27,7 +27,7 @@ import org.apache.cloudstack.api.InternalIdentity; @Entity -@Table(name = ("ovs_tunnel_network")) +@Table(name = "ovs_tunnel_network") public class OvsTunnelNetworkVO implements InternalIdentity { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) diff --git a/plugins/storage/volume/scaleio/pom.xml b/plugins/storage/volume/scaleio/pom.xml index e95087e7257f..36a385c0d09a 100644 --- a/plugins/storage/volume/scaleio/pom.xml +++ b/plugins/storage/volume/scaleio/pom.xml @@ -33,6 +33,12 @@ cloud-engine-storage-volume ${project.version} + + com.github.tomakehurst + wiremock-standalone + ${cs.wiremock.version} + test + diff --git a/plugins/storage/volume/scaleio/src/main/java/org/apache/cloudstack/storage/datastore/client/ScaleIOGatewayClient.java b/plugins/storage/volume/scaleio/src/main/java/org/apache/cloudstack/storage/datastore/client/ScaleIOGatewayClient.java index f6b10f888320..f497b10127d3 100644 --- a/plugins/storage/volume/scaleio/src/main/java/org/apache/cloudstack/storage/datastore/client/ScaleIOGatewayClient.java +++ b/plugins/storage/volume/scaleio/src/main/java/org/apache/cloudstack/storage/datastore/client/ScaleIOGatewayClient.java @@ -40,8 +40,8 @@ public interface ScaleIOGatewayClient { String STORAGE_POOL_SYSTEM_ID = "powerflex.storagepool.system.id"; static ScaleIOGatewayClient getClient(final String url, final String username, final String password, - final boolean validateCertificate, final int timeout) throws NoSuchAlgorithmException, KeyManagementException, URISyntaxException { - return new ScaleIOGatewayClientImpl(url, username, password, validateCertificate, timeout); + final boolean validateCertificate, final int timeout, final int maxConnections) throws NoSuchAlgorithmException, KeyManagementException, URISyntaxException { + return new ScaleIOGatewayClientImpl(url, username, password, validateCertificate, timeout, maxConnections); } // Volume APIs diff --git a/plugins/storage/volume/scaleio/src/main/java/org/apache/cloudstack/storage/datastore/client/ScaleIOGatewayClientConnectionPool.java b/plugins/storage/volume/scaleio/src/main/java/org/apache/cloudstack/storage/datastore/client/ScaleIOGatewayClientConnectionPool.java index 2daf8e4635ce..e557e0881328 100644 --- a/plugins/storage/volume/scaleio/src/main/java/org/apache/cloudstack/storage/datastore/client/ScaleIOGatewayClientConnectionPool.java +++ b/plugins/storage/volume/scaleio/src/main/java/org/apache/cloudstack/storage/datastore/client/ScaleIOGatewayClientConnectionPool.java @@ -62,8 +62,9 @@ public ScaleIOGatewayClient getClient(Long storagePoolId, StoragePoolDetailsDao final String encryptedPassword = storagePoolDetailsDao.findDetail(storagePoolId, ScaleIOGatewayClient.GATEWAY_API_PASSWORD).getValue(); final String password = DBEncryptionUtil.decrypt(encryptedPassword); final int clientTimeout = StorageManager.STORAGE_POOL_CLIENT_TIMEOUT.valueIn(storagePoolId); + final int clientMaxConnections = StorageManager.STORAGE_POOL_CLIENT_MAX_CONNECTIONS.valueIn(storagePoolId); - client = new ScaleIOGatewayClientImpl(url, username, password, false, clientTimeout); + client = new ScaleIOGatewayClientImpl(url, username, password, false, clientTimeout, clientMaxConnections); gatewayClients.put(storagePoolId, client); LOGGER.debug("Added gateway client for the storage pool: " + storagePoolId); } diff --git a/plugins/storage/volume/scaleio/src/main/java/org/apache/cloudstack/storage/datastore/client/ScaleIOGatewayClientImpl.java b/plugins/storage/volume/scaleio/src/main/java/org/apache/cloudstack/storage/datastore/client/ScaleIOGatewayClientImpl.java index 5e8568dede1f..fa195414b67f 100644 --- a/plugins/storage/volume/scaleio/src/main/java/org/apache/cloudstack/storage/datastore/client/ScaleIOGatewayClientImpl.java +++ b/plugins/storage/volume/scaleio/src/main/java/org/apache/cloudstack/storage/datastore/client/ScaleIOGatewayClientImpl.java @@ -56,11 +56,16 @@ import org.apache.http.client.config.RequestConfig; import org.apache.http.client.methods.HttpGet; import org.apache.http.client.methods.HttpPost; +import org.apache.http.config.Registry; +import org.apache.http.config.RegistryBuilder; import org.apache.http.conn.ConnectTimeoutException; +import org.apache.http.conn.socket.ConnectionSocketFactory; import org.apache.http.conn.ssl.NoopHostnameVerifier; import org.apache.http.conn.ssl.SSLConnectionSocketFactory; import org.apache.http.entity.StringEntity; import org.apache.http.impl.client.HttpClientBuilder; +import org.apache.http.impl.conn.PoolingHttpClientConnectionManager; +import org.apache.http.pool.PoolStats; import org.apache.http.util.EntityUtils; import org.apache.log4j.Logger; @@ -80,25 +85,27 @@ public class ScaleIOGatewayClientImpl implements ScaleIOGatewayClient { private final URI apiURI; private final HttpClient httpClient; - private static final String SESSION_HEADER = "X-RestSvcSessionId"; + private final PoolingHttpClientConnectionManager connectionManager; private static final String MDM_CONNECTED_STATE = "Connected"; - private String host; private String username; private String password; private String sessionKey = null; // The session token is valid for 8 hours from the time it was created, unless there has been no activity for 10 minutes // Reference: https://cpsdocs.dellemc.com/bundle/PF_REST_API_RG/page/GUID-92430F19-9F44-42B6-B898-87D5307AE59B.html - private static final long MAX_VALID_SESSION_TIME_IN_MILLISECS = 8 * 60 * 60 * 1000; // 8 hrs - private static final long MAX_IDLE_TIME_IN_MILLISECS = 10 * 60 * 1000; // 10 mins + private static final long MAX_VALID_SESSION_TIME_IN_HRS = 8; + private static final long MAX_VALID_SESSION_TIME_IN_MILLISECS = MAX_VALID_SESSION_TIME_IN_HRS * 60 * 60 * 1000; + private static final long MAX_IDLE_TIME_IN_MINS = 10; + private static final long MAX_IDLE_TIME_IN_MILLISECS = MAX_IDLE_TIME_IN_MINS * 60 * 1000; private static final long BUFFER_TIME_IN_MILLISECS = 30 * 1000; // keep 30 secs buffer before the expiration (to avoid any last-minute operations) + private boolean authenticating = false; private long createTime = 0; private long lastUsedTime = 0; public ScaleIOGatewayClientImpl(final String url, final String username, final String password, - final boolean validateCertificate, final int timeout) + final boolean validateCertificate, final int timeout, final int maxConnections) throws NoSuchAlgorithmException, KeyManagementException, URISyntaxException { Preconditions.checkArgument(!Strings.isNullOrEmpty(url), "Gateway client url cannot be null"); Preconditions.checkArgument(!Strings.isNullOrEmpty(username) && !Strings.isNullOrEmpty(password), "Gateway client credentials cannot be null"); @@ -109,83 +116,141 @@ public ScaleIOGatewayClientImpl(final String url, final String username, final S .setSocketTimeout(timeout * 1000) .build(); + SSLConnectionSocketFactory factory = SSLConnectionSocketFactory.getSocketFactory(); if (!validateCertificate) { final SSLContext sslcontext = SSLUtils.getSSLContext(); sslcontext.init(null, new X509TrustManager[]{new TrustAllManager()}, new SecureRandom()); - final SSLConnectionSocketFactory factory = new SSLConnectionSocketFactory(sslcontext, NoopHostnameVerifier.INSTANCE); - this.httpClient = HttpClientBuilder.create() - .setDefaultRequestConfig(config) - .setSSLSocketFactory(factory) - .build(); - } else { - this.httpClient = HttpClientBuilder.create() - .setDefaultRequestConfig(config) - .build(); + factory = new SSLConnectionSocketFactory(sslcontext, NoopHostnameVerifier.INSTANCE); } + final Registry socketFactoryRegistry = RegistryBuilder. create() + .register("https", factory) + .build(); + connectionManager = new PoolingHttpClientConnectionManager(socketFactoryRegistry); + connectionManager.setMaxTotal(maxConnections); + connectionManager.setDefaultMaxPerRoute(maxConnections); + + this.httpClient = HttpClientBuilder.create() + .setConnectionManager(connectionManager) + .setDefaultRequestConfig(config) + .setSSLSocketFactory(factory) + .build(); + this.apiURI = new URI(url); - this.host = apiURI.getHost(); this.username = username; this.password = password; authenticate(); + LOG.debug("API client for the PowerFlex gateway " + apiURI.getHost() + " is created successfully, with max connections: " + + maxConnections + " and timeout: " + timeout + " secs"); } ///////////////////////////////////////////////////////////// //////////////// Private Helper Methods ///////////////////// ///////////////////////////////////////////////////////////// - private void authenticate() { + private synchronized void authenticate() { final HttpGet request = new HttpGet(apiURI.toString() + "/login"); request.setHeader(HttpHeaders.AUTHORIZATION, "Basic " + Base64.getEncoder().encodeToString((username + ":" + password).getBytes())); + HttpResponse response = null; try { - final HttpResponse response = httpClient.execute(request); - checkAuthFailure(response); - this.sessionKey = EntityUtils.toString(response.getEntity()); - if (Strings.isNullOrEmpty(this.sessionKey)) { - throw new CloudRuntimeException("Failed to create a valid PowerFlex Gateway Session to perform API requests"); + authenticating = true; + LOG.debug("Authenticating gateway " + apiURI.getHost() + " with the request: " + request.toString()); + response = httpClient.execute(request); + if (isNullResponse(response)) { + LOG.warn("Invalid response received while authenticating, for the request: " + request.toString()); + throw new CloudRuntimeException("Failed to authenticate PowerFlex API Gateway due to invalid response from the Gateway " + apiURI.getHost()); } - this.sessionKey = this.sessionKey.replace("\"", ""); + + LOG.debug("Received response: " + response.getStatusLine().getStatusCode() + " " + response.getStatusLine().getReasonPhrase() + + ", for the authenticate request: " + request.toString()); if (response.getStatusLine().getStatusCode() != HttpStatus.SC_OK) { - throw new CloudRuntimeException("PowerFlex Gateway login failed, please check the provided settings"); + throw new CloudRuntimeException("PowerFlex Gateway " + apiURI.getHost() + " login failed, please check the provided settings"); } + + String sessionKeyInResponse = EntityUtils.toString(response.getEntity()); + if (Strings.isNullOrEmpty(sessionKeyInResponse)) { + throw new CloudRuntimeException("Failed to create a valid session for PowerFlex Gateway " + apiURI.getHost() + " to perform API requests"); + } + + LOG.info("PowerFlex API Gateway " + apiURI.getHost() + " authenticated successfully"); + this.sessionKey = sessionKeyInResponse.replace("\"", ""); + + long now = System.currentTimeMillis(); + createTime = lastUsedTime = now; } catch (final IOException e) { - throw new CloudRuntimeException("Failed to authenticate PowerFlex API Gateway due to:" + e.getMessage()); + LOG.error("Failed to authenticate PowerFlex API Gateway " + apiURI.getHost() + " due to: " + e.getMessage() + getConnectionManagerStats()); + throw new CloudRuntimeException("Failed to authenticate PowerFlex API Gateway " + apiURI.getHost() + " due to: " + e.getMessage()); + } finally { + authenticating = false; + if (response != null) { + EntityUtils.consumeQuietly(response.getEntity()); + } } - long now = System.currentTimeMillis(); - createTime = lastUsedTime = now; } private synchronized void renewClientSessionOnExpiry() { if (isSessionExpired()) { - LOG.debug("Session expired, renewing"); + LOG.debug("Session expired for the PowerFlex API Gateway " + apiURI.getHost() + ", renewing"); authenticate(); } } private boolean isSessionExpired() { long now = System.currentTimeMillis() + BUFFER_TIME_IN_MILLISECS; - if ((now - createTime) > MAX_VALID_SESSION_TIME_IN_MILLISECS || - (now - lastUsedTime) > MAX_IDLE_TIME_IN_MILLISECS) { + if ((now - createTime) > MAX_VALID_SESSION_TIME_IN_MILLISECS) { + LOG.debug("Session expired for the Gateway " + apiURI.getHost() + ", token is invalid after " + MAX_VALID_SESSION_TIME_IN_HRS + + " hours from the time it was created"); + return true; + } + + if ((now - lastUsedTime) > MAX_IDLE_TIME_IN_MILLISECS) { + LOG.debug("Session expired for the Gateway " + apiURI.getHost() + ", as there has been no activity for " + MAX_IDLE_TIME_IN_MINS + " mins"); return true; } + return false; } - private void checkAuthFailure(final HttpResponse response) { - if (response != null && response.getStatusLine().getStatusCode() == HttpStatus.SC_UNAUTHORIZED) { - throw new ServerApiException(ApiErrorCode.UNAUTHORIZED, "PowerFlex Gateway API call unauthorized, please check the provided settings"); + private boolean isNullResponse(final HttpResponse response) { + if (response == null) { + LOG.warn("Nil response"); + return true; + } + + if (response.getStatusLine() == null) { + LOG.warn("No status line in the response"); + return true; } + + return false; + } + + private boolean checkAuthFailure(final HttpResponse response, final boolean renewAndRetryOnAuthFailure) { + if (!isNullResponse(response) && response.getStatusLine().getStatusCode() == HttpStatus.SC_UNAUTHORIZED) { + if (!renewAndRetryOnAuthFailure) { + throw new ServerApiException(ApiErrorCode.UNAUTHORIZED, "PowerFlex Gateway API call unauthorized, please check the provided settings"); + } + LOG.debug("PowerFlex Gateway API call unauthorized. Current token might be invalid, renew the session." + getConnectionManagerStats()); + return true; + } + return false; } private void checkResponseOK(final HttpResponse response) { + if (isNullResponse(response)) { + return; + } + if (response.getStatusLine().getStatusCode() == HttpStatus.SC_NO_CONTENT) { - LOG.debug("Requested resource does not exist"); + LOG.warn("Requested resource does not exist"); return; } + if (response.getStatusLine().getStatusCode() == HttpStatus.SC_BAD_REQUEST) { throw new ServerApiException(ApiErrorCode.MALFORMED_PARAMETER_ERROR, "Bad API request"); } + if (!(response.getStatusLine().getStatusCode() == HttpStatus.SC_OK || response.getStatusLine().getStatusCode() == HttpStatus.SC_ACCEPTED)) { String responseBody = response.toString(); @@ -193,54 +258,118 @@ private void checkResponseOK(final HttpResponse response) { responseBody = EntityUtils.toString(response.getEntity()); } catch (IOException ignored) { } - LOG.debug("HTTP request failed, status code is " + response.getStatusLine().getStatusCode() + ", response is: " + responseBody); + LOG.debug("HTTP request failed, status code: " + response.getStatusLine().getStatusCode() + ", response: " + + responseBody + getConnectionManagerStats()); throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "API failed due to: " + responseBody); } } private void checkResponseTimeOut(final Exception e) { if (e instanceof ConnectTimeoutException || e instanceof SocketTimeoutException) { - throw new ServerApiException(ApiErrorCode.RESOURCE_UNAVAILABLE_ERROR, "API operation timed out, please try again."); + throw new ServerApiException(ApiErrorCode.RESOURCE_UNAVAILABLE_ERROR, "Gateway API operation timed out, please try again."); } } - private HttpResponse get(final String path) throws IOException { + private T get(final String path, final Class type) { + return get(path, type, true); + } + + private T get(final String path, final Class type, final boolean renewAndRetryOnAuthFailure) { renewClientSessionOnExpiry(); - final HttpGet request = new HttpGet(apiURI.toString() + path); - request.setHeader(HttpHeaders.AUTHORIZATION, "Basic " + Base64.getEncoder().encodeToString((this.username + ":" + this.sessionKey).getBytes())); - final HttpResponse response = httpClient.execute(request); - synchronized (this) { - lastUsedTime = System.currentTimeMillis(); + HttpResponse response = null; + boolean responseConsumed = false; + try { + while (authenticating); // wait for authentication request (if any) to complete (and to pick the new session key) + final HttpGet request = new HttpGet(apiURI.toString() + path); + request.setHeader(HttpHeaders.AUTHORIZATION, "Basic " + Base64.getEncoder().encodeToString((this.username + ":" + this.sessionKey).getBytes())); + LOG.debug("Sending GET request: " + request.toString()); + response = httpClient.execute(request); + String responseStatus = (!isNullResponse(response)) ? (response.getStatusLine().getStatusCode() + " " + response.getStatusLine().getReasonPhrase()) : "nil"; + LOG.debug("Received response: " + responseStatus + ", for the sent GET request: " + request.toString()); + if (checkAuthFailure(response, renewAndRetryOnAuthFailure)) { + EntityUtils.consumeQuietly(response.getEntity()); + responseConsumed = true; + + authenticate(); + return get(path, type, false); + } + return processResponse(response, type); + } catch (final IOException e) { + LOG.error("Failed in GET method due to: " + e.getMessage() + getConnectionManagerStats(), e); + checkResponseTimeOut(e); + } finally { + if (!responseConsumed && response != null) { + EntityUtils.consumeQuietly(response.getEntity()); + } } - String responseStatus = (response != null) ? (response.getStatusLine().getStatusCode() + " " + response.getStatusLine().getReasonPhrase()) : "nil"; - LOG.debug("GET request path: " + path + ", response: " + responseStatus); - checkAuthFailure(response); - return response; + return null; } - private HttpResponse post(final String path, final Object obj) throws IOException { + private T post(final String path, final Object obj, final Class type) { + return post(path, obj, type, true); + } + + private T post(final String path, final Object obj, final Class type, final boolean renewAndRetryOnAuthFailure) { renewClientSessionOnExpiry(); - final HttpPost request = new HttpPost(apiURI.toString() + path); - request.setHeader(HttpHeaders.AUTHORIZATION, "Basic " + Base64.getEncoder().encodeToString((this.username + ":" + this.sessionKey).getBytes())); - request.setHeader("Content-type", "application/json"); - if (obj != null) { - if (obj instanceof String) { - request.setEntity(new StringEntity((String) obj)); - } else { - JsonMapper mapper = new JsonMapper(); - mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL); - String json = mapper.writer().writeValueAsString(obj); - request.setEntity(new StringEntity(json)); + HttpResponse response = null; + boolean responseConsumed = false; + try { + while (authenticating); // wait for authentication request (if any) to complete (and to pick the new session key) + final HttpPost request = new HttpPost(apiURI.toString() + path); + request.setHeader(HttpHeaders.AUTHORIZATION, "Basic " + Base64.getEncoder().encodeToString((this.username + ":" + this.sessionKey).getBytes())); + request.setHeader("Content-type", "application/json"); + if (obj != null) { + if (obj instanceof String) { + request.setEntity(new StringEntity((String) obj)); + } else { + JsonMapper mapper = new JsonMapper(); + mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL); + String json = mapper.writer().writeValueAsString(obj); + request.setEntity(new StringEntity(json)); + } + } + LOG.debug("Sending POST request: " + request.toString()); + response = httpClient.execute(request); + String responseStatus = (!isNullResponse(response)) ? (response.getStatusLine().getStatusCode() + " " + response.getStatusLine().getReasonPhrase()) : "nil"; + LOG.debug("Received response: " + responseStatus + ", for the sent POST request: " + request.toString()); + if (checkAuthFailure(response, renewAndRetryOnAuthFailure)) { + EntityUtils.consumeQuietly(response.getEntity()); + responseConsumed = true; + + authenticate(); + return post(path, obj, type, false); + } + return processResponse(response, type); + } catch (final IOException e) { + LOG.error("Failed in POST method due to: " + e.getMessage() + getConnectionManagerStats(), e); + checkResponseTimeOut(e); + } finally { + if (!responseConsumed && response != null) { + EntityUtils.consumeQuietly(response.getEntity()); } } - final HttpResponse response = httpClient.execute(request); + return null; + } + + private T processResponse(HttpResponse response, final Class type) throws IOException { + if (isNullResponse(response)) { + return null; + } + + checkResponseOK(response); synchronized (this) { lastUsedTime = System.currentTimeMillis(); } - String responseStatus = (response != null) ? (response.getStatusLine().getStatusCode() + " " + response.getStatusLine().getReasonPhrase()) : "nil"; - LOG.debug("POST request path: " + path + ", response: " + responseStatus); - checkAuthFailure(response); - return response; + if (type == Boolean.class) { + return (T) Boolean.TRUE; + } else if (type == String.class) { + return (T) EntityUtils.toString(response.getEntity()); + } else if (type == JsonNode.class) { + return (T) new ObjectMapper().readTree(response.getEntity().getContent()); + } else { + ObjectMapper mapper = new ObjectMapper().configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); + return mapper.readValue(response.getEntity().getContent(), type); + } } ////////////////////////////////////////////////// @@ -254,50 +383,25 @@ public Volume createVolume(final String name, final String storagePoolId, Preconditions.checkArgument(!Strings.isNullOrEmpty(storagePoolId), "Storage pool id cannot be null"); Preconditions.checkArgument(sizeInGb != null && sizeInGb > 0, "Size(GB) must be greater than 0"); - HttpResponse response = null; - try { - Volume newVolume = new Volume(); - newVolume.setName(name); - newVolume.setStoragePoolId(storagePoolId); - newVolume.setVolumeSizeInGb(sizeInGb); - if (Storage.ProvisioningType.FAT.equals(volumeType)) { - newVolume.setVolumeType(Volume.VolumeType.ThickProvisioned); - } else { - newVolume.setVolumeType(Volume.VolumeType.ThinProvisioned); - } - // The basic allocation granularity is 8GB. The volume size will be rounded up. - response = post("/types/Volume/instances", newVolume); - checkResponseOK(response); - ObjectMapper mapper = new ObjectMapper().configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); - Volume newVolumeObject = mapper.readValue(response.getEntity().getContent(), Volume.class); - return getVolume(newVolumeObject.getId()); - } catch (final IOException e) { - LOG.error("Failed to create PowerFlex volume due to:", e); - checkResponseTimeOut(e); - } finally { - if (response != null) { - EntityUtils.consumeQuietly(response.getEntity()); - } + Volume newVolume = new Volume(); + newVolume.setName(name); + newVolume.setStoragePoolId(storagePoolId); + newVolume.setVolumeSizeInGb(sizeInGb); + if (Storage.ProvisioningType.FAT.equals(volumeType)) { + newVolume.setVolumeType(Volume.VolumeType.ThickProvisioned); + } else { + newVolume.setVolumeType(Volume.VolumeType.ThinProvisioned); } - return null; + // The basic allocation granularity is 8GB. The volume size will be rounded up. + Volume newVolumeObject = post("/types/Volume/instances", newVolume, Volume.class); + return getVolume(newVolumeObject.getId()); } @Override public List listVolumes() { - HttpResponse response = null; - try { - response = get("/types/Volume/instances"); - checkResponseOK(response); - ObjectMapper mapper = new ObjectMapper().configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); - Volume[] volumes = mapper.readValue(response.getEntity().getContent(), Volume[].class); + Volume[] volumes = get("/types/Volume/instances", Volume[].class); + if (volumes != null) { return Arrays.asList(volumes); - } catch (final IOException e) { - LOG.error("Failed to list PowerFlex volumes due to:", e); - checkResponseTimeOut(e); - } finally { - if (response != null) { - EntityUtils.consumeQuietly(response.getEntity()); - } } return new ArrayList<>(); } @@ -313,52 +417,24 @@ public List listSnapshotVolumes() { } } } - return snapshotVolumes; } @Override public Volume getVolume(String volumeId) { Preconditions.checkArgument(!Strings.isNullOrEmpty(volumeId), "Volume id cannot be null"); - - HttpResponse response = null; - try { - response = get("/instances/Volume::" + volumeId); - checkResponseOK(response); - ObjectMapper mapper = new ObjectMapper().configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); - return mapper.readValue(response.getEntity().getContent(), Volume.class); - } catch (final IOException e) { - LOG.error("Failed to get volume due to:", e); - checkResponseTimeOut(e); - } finally { - if (response != null) { - EntityUtils.consumeQuietly(response.getEntity()); - } - } - return null; + return get("/instances/Volume::" + volumeId, Volume.class); } @Override public Volume getVolumeByName(String name) { Preconditions.checkArgument(!Strings.isNullOrEmpty(name), "Volume name cannot be null"); - HttpResponse response = null; - try { - Volume searchVolume = new Volume(); - searchVolume.setName(name); - response = post("/types/Volume/instances/action/queryIdByKey", searchVolume); - checkResponseOK(response); - String volumeId = EntityUtils.toString(response.getEntity()); - if (!Strings.isNullOrEmpty(volumeId)) { - return getVolume(volumeId.replace("\"", "")); - } - } catch (final IOException e) { - LOG.error("Failed to get volume due to:", e); - checkResponseTimeOut(e); - } finally { - if (response != null) { - EntityUtils.consumeQuietly(response.getEntity()); - } + Volume searchVolume = new Volume(); + searchVolume.setName(name); + String volumeId = post("/types/Volume/instances/action/queryIdByKey", searchVolume, String.class); + if (!Strings.isNullOrEmpty(volumeId)) { + return getVolume(volumeId.replace("\"", "")); } return null; } @@ -368,20 +444,11 @@ public boolean renameVolume(final String volumeId, final String newName) { Preconditions.checkArgument(!Strings.isNullOrEmpty(volumeId), "Volume id cannot be null"); Preconditions.checkArgument(!Strings.isNullOrEmpty(newName), "New name for volume cannot be null"); - HttpResponse response = null; - try { - response = post( - "/instances/Volume::" + volumeId + "/action/setVolumeName", - String.format("{\"newName\":\"%s\"}", newName)); - checkResponseOK(response); - return true; - } catch (final IOException e) { - LOG.error("Failed to rename PowerFlex volume due to: ", e); - checkResponseTimeOut(e); - } finally { - if (response != null) { - EntityUtils.consumeQuietly(response.getEntity()); - } + Boolean renameVolumeStatus = post( + "/instances/Volume::" + volumeId + "/action/setVolumeName", + String.format("{\"newName\":\"%s\"}", newName), Boolean.class); + if (renameVolumeStatus != null) { + return renameVolumeStatus; } return false; } @@ -392,21 +459,12 @@ public Volume resizeVolume(final String volumeId, final Integer sizeInGB) { Preconditions.checkArgument(sizeInGB != null && (sizeInGB > 0 && sizeInGB % 8 == 0), "Size(GB) must be greater than 0 and in granularity of 8"); - HttpResponse response = null; - try { - // Volume capacity can only be increased. sizeInGB must be a positive number in granularity of 8 GB. - response = post( - "/instances/Volume::" + volumeId + "/action/setVolumeSize", - String.format("{\"sizeInGB\":\"%s\"}", sizeInGB.toString())); - checkResponseOK(response); + // Volume capacity can only be increased. sizeInGB must be a positive number in granularity of 8 GB. + Boolean resizeVolumeStatus = post( + "/instances/Volume::" + volumeId + "/action/setVolumeSize", + String.format("{\"sizeInGB\":\"%s\"}", sizeInGB.toString()), Boolean.class); + if (resizeVolumeStatus != null && resizeVolumeStatus.booleanValue()) { return getVolume(volumeId); - } catch (final IOException e) { - LOG.error("Failed to resize PowerFlex volume due to:", e); - checkResponseTimeOut(e); - } finally { - if (response != null) { - EntityUtils.consumeQuietly(response.getEntity()); - } } return null; } @@ -426,33 +484,19 @@ public Volume cloneVolume(final String sourceVolumeId, final String destVolumeNa public SnapshotGroup takeSnapshot(final Map srcVolumeDestSnapshotMap) { Preconditions.checkArgument(srcVolumeDestSnapshotMap != null && !srcVolumeDestSnapshotMap.isEmpty(), "srcVolumeDestSnapshotMap cannot be null"); - HttpResponse response = null; - try { - final List defs = new ArrayList<>(); - for (final String volumeId : srcVolumeDestSnapshotMap.keySet()) { - final SnapshotDef snapshotDef = new SnapshotDef(); - snapshotDef.setVolumeId(volumeId); - String snapshotName = srcVolumeDestSnapshotMap.get(volumeId); - if (!Strings.isNullOrEmpty(snapshotName)) { - snapshotDef.setSnapshotName(srcVolumeDestSnapshotMap.get(volumeId)); - } - defs.add(snapshotDef); - } - final SnapshotDefs snapshotDefs = new SnapshotDefs(); - snapshotDefs.setSnapshotDefs(defs.toArray(new SnapshotDef[0])); - response = post("/instances/System/action/snapshotVolumes", snapshotDefs); - checkResponseOK(response); - ObjectMapper mapper = new ObjectMapper().configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); - return mapper.readValue(response.getEntity().getContent(), SnapshotGroup.class); - } catch (final IOException e) { - LOG.error("Failed to take snapshot due to:", e); - checkResponseTimeOut(e); - } finally { - if (response != null) { - EntityUtils.consumeQuietly(response.getEntity()); + final List defs = new ArrayList<>(); + for (final String volumeId : srcVolumeDestSnapshotMap.keySet()) { + final SnapshotDef snapshotDef = new SnapshotDef(); + snapshotDef.setVolumeId(volumeId); + String snapshotName = srcVolumeDestSnapshotMap.get(volumeId); + if (!Strings.isNullOrEmpty(snapshotName)) { + snapshotDef.setSnapshotName(srcVolumeDestSnapshotMap.get(volumeId)); } + defs.add(snapshotDef); } - return null; + final SnapshotDefs snapshotDefs = new SnapshotDefs(); + snapshotDefs.setSnapshotDefs(defs.toArray(new SnapshotDef[0])); + return post("/instances/System/action/snapshotVolumes", snapshotDefs, SnapshotGroup.class); } @Override @@ -514,22 +558,12 @@ public int deleteSnapshotGroup(final String systemId, final String snapshotGroup Preconditions.checkArgument(!Strings.isNullOrEmpty(systemId), "System id cannot be null"); Preconditions.checkArgument(!Strings.isNullOrEmpty(snapshotGroupId), "Snapshot group id cannot be null"); - HttpResponse response = null; - try { - response = post( - "/instances/System::" + systemId + "/action/removeConsistencyGroupSnapshots", - String.format("{\"snapGroupId\":\"%s\"}", snapshotGroupId)); - checkResponseOK(response); - JsonNode node = new ObjectMapper().readTree(response.getEntity().getContent()); + JsonNode node = post( + "/instances/System::" + systemId + "/action/removeConsistencyGroupSnapshots", + String.format("{\"snapGroupId\":\"%s\"}", snapshotGroupId), JsonNode.class); + if (node != null) { JsonNode noOfVolumesNode = node.get("numberOfVolumes"); return noOfVolumesNode.asInt(); - } catch (final IOException e) { - LOG.error("Failed to delete PowerFlex snapshot group due to: " + e.getMessage(), e); - checkResponseTimeOut(e); - } finally { - if (response != null) { - EntityUtils.consumeQuietly(response.getEntity()); - } } return -1; } @@ -539,31 +573,18 @@ public Volume takeSnapshot(final String volumeId, final String snapshotVolumeNam Preconditions.checkArgument(!Strings.isNullOrEmpty(volumeId), "Volume id cannot be null"); Preconditions.checkArgument(!Strings.isNullOrEmpty(snapshotVolumeName), "Snapshot name cannot be null"); - HttpResponse response = null; - try { - final SnapshotDef[] snapshotDef = new SnapshotDef[1]; - snapshotDef[0] = new SnapshotDef(); - snapshotDef[0].setVolumeId(volumeId); - snapshotDef[0].setSnapshotName(snapshotVolumeName); - final SnapshotDefs snapshotDefs = new SnapshotDefs(); - snapshotDefs.setSnapshotDefs(snapshotDef); - - response = post("/instances/System/action/snapshotVolumes", snapshotDefs); - checkResponseOK(response); - ObjectMapper mapper = new ObjectMapper().configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); - SnapshotGroup snapshotGroup = mapper.readValue(response.getEntity().getContent(), SnapshotGroup.class); - if (snapshotGroup != null) { - List volumeIds = snapshotGroup.getVolumeIds(); - if (volumeIds != null && !volumeIds.isEmpty()) { - return getVolume(volumeIds.get(0)); - } - } - } catch (final IOException e) { - LOG.error("Failed to take snapshot due to:", e); - checkResponseTimeOut(e); - } finally { - if (response != null) { - EntityUtils.consumeQuietly(response.getEntity()); + final SnapshotDef[] snapshotDef = new SnapshotDef[1]; + snapshotDef[0] = new SnapshotDef(); + snapshotDef[0].setVolumeId(volumeId); + snapshotDef[0].setSnapshotName(snapshotVolumeName); + final SnapshotDefs snapshotDefs = new SnapshotDefs(); + snapshotDefs.setSnapshotDefs(snapshotDef); + + SnapshotGroup snapshotGroup = post("/instances/System/action/snapshotVolumes", snapshotDefs, SnapshotGroup.class); + if (snapshotGroup != null) { + List volumeIds = snapshotGroup.getVolumeIds(); + if (volumeIds != null && !volumeIds.isEmpty()) { + return getVolume(volumeIds.get(0)); } } return null; @@ -574,34 +595,25 @@ public boolean revertSnapshot(final String sourceSnapshotVolumeId, final String Preconditions.checkArgument(!Strings.isNullOrEmpty(sourceSnapshotVolumeId), "Source snapshot volume id cannot be null"); Preconditions.checkArgument(!Strings.isNullOrEmpty(destVolumeId), "Destination volume id cannot be null"); - HttpResponse response = null; - try { - Volume sourceSnapshotVolume = getVolume(sourceSnapshotVolumeId); - if (sourceSnapshotVolume == null) { - throw new CloudRuntimeException("Source snapshot volume: " + sourceSnapshotVolumeId + " doesn't exists"); - } + Volume sourceSnapshotVolume = getVolume(sourceSnapshotVolumeId); + if (sourceSnapshotVolume == null) { + throw new CloudRuntimeException("Source snapshot volume: " + sourceSnapshotVolumeId + " doesn't exists"); + } - Volume destVolume = getVolume(destVolumeId); - if (sourceSnapshotVolume == null) { - throw new CloudRuntimeException("Destination volume: " + destVolumeId + " doesn't exists"); - } + Volume destVolume = getVolume(destVolumeId); + if (sourceSnapshotVolume == null) { + throw new CloudRuntimeException("Destination volume: " + destVolumeId + " doesn't exists"); + } - if (!sourceSnapshotVolume.getVtreeId().equals(destVolume.getVtreeId())) { - throw new CloudRuntimeException("Unable to revert, source snapshot volume and destination volume doesn't belong to same volume tree"); - } + if (!sourceSnapshotVolume.getVtreeId().equals(destVolume.getVtreeId())) { + throw new CloudRuntimeException("Unable to revert, source snapshot volume and destination volume doesn't belong to same volume tree"); + } - response = post( - "/instances/Volume::" + destVolumeId + "/action/overwriteVolumeContent", - String.format("{\"srcVolumeId\":\"%s\",\"allowOnExtManagedVol\":\"TRUE\"}", sourceSnapshotVolumeId)); - checkResponseOK(response); - return true; - } catch (final IOException e) { - LOG.error("Failed to map PowerFlex volume due to:", e); - checkResponseTimeOut(e); - } finally { - if (response != null) { - EntityUtils.consumeQuietly(response.getEntity()); - } + Boolean overwriteVolumeContentStatus = post( + "/instances/Volume::" + destVolumeId + "/action/overwriteVolumeContent", + String.format("{\"srcVolumeId\":\"%s\",\"allowOnExtManagedVol\":\"TRUE\"}", sourceSnapshotVolumeId), Boolean.class); + if (overwriteVolumeContentStatus != null) { + return overwriteVolumeContentStatus; } return false; } @@ -611,24 +623,15 @@ public boolean mapVolumeToSdc(final String volumeId, final String sdcId) { Preconditions.checkArgument(!Strings.isNullOrEmpty(volumeId), "Volume id cannot be null"); Preconditions.checkArgument(!Strings.isNullOrEmpty(sdcId), "Sdc Id cannot be null"); - HttpResponse response = null; - try { - if (isVolumeMappedToSdc(volumeId, sdcId)) { - return true; - } - - response = post( - "/instances/Volume::" + volumeId + "/action/addMappedSdc", - String.format("{\"sdcId\":\"%s\",\"allowMultipleMappings\":\"TRUE\"}", sdcId)); - checkResponseOK(response); + if (isVolumeMappedToSdc(volumeId, sdcId)) { return true; - } catch (final IOException e) { - LOG.error("Failed to map PowerFlex volume due to:", e); - checkResponseTimeOut(e); - } finally { - if (response != null) { - EntityUtils.consumeQuietly(response.getEntity()); - } + } + + Boolean mapVolumeToSdcStatus = post( + "/instances/Volume::" + volumeId + "/action/addMappedSdc", + String.format("{\"sdcId\":\"%s\",\"allowMultipleMappings\":\"TRUE\"}", sdcId), Boolean.class); + if (mapVolumeToSdcStatus != null) { + return mapVolumeToSdcStatus; } return false; } @@ -642,31 +645,22 @@ public boolean mapVolumeToSdcWithLimits(final String volumeId, final String sdcI Preconditions.checkArgument(bandwidthLimitInKbps != null && (bandwidthLimitInKbps == 0 || (bandwidthLimitInKbps > 0 && bandwidthLimitInKbps % 1024 == 0)), "Bandwidth limit(Kbps) must be 0 (unlimited) or in granularity of 1024"); - HttpResponse response = null; - try { - if (mapVolumeToSdc(volumeId, sdcId)) { - long iopsLimitVal = 0; - if (iopsLimit != null && iopsLimit.longValue() > 0) { - iopsLimitVal = iopsLimit.longValue(); - } - - long bandwidthLimitInKbpsVal = 0; - if (bandwidthLimitInKbps != null && bandwidthLimitInKbps.longValue() > 0) { - bandwidthLimitInKbpsVal = bandwidthLimitInKbps.longValue(); - } + if (mapVolumeToSdc(volumeId, sdcId)) { + long iopsLimitVal = 0; + if (iopsLimit != null && iopsLimit.longValue() > 0) { + iopsLimitVal = iopsLimit.longValue(); + } - response = post( - "/instances/Volume::" + volumeId + "/action/setMappedSdcLimits", - String.format("{\"sdcId\":\"%s\",\"bandwidthLimitInKbps\":\"%d\",\"iopsLimit\":\"%d\"}", sdcId, bandwidthLimitInKbpsVal, iopsLimitVal)); - checkResponseOK(response); - return true; + long bandwidthLimitInKbpsVal = 0; + if (bandwidthLimitInKbps != null && bandwidthLimitInKbps.longValue() > 0) { + bandwidthLimitInKbpsVal = bandwidthLimitInKbps.longValue(); } - } catch (final IOException e) { - LOG.error("Failed to map PowerFlex volume with limits due to:", e); - checkResponseTimeOut(e); - } finally { - if (response != null) { - EntityUtils.consumeQuietly(response.getEntity()); + + Boolean setVolumeSdcLimitsStatus = post( + "/instances/Volume::" + volumeId + "/action/setMappedSdcLimits", + String.format("{\"sdcId\":\"%s\",\"bandwidthLimitInKbps\":\"%d\",\"iopsLimit\":\"%d\"}", sdcId, bandwidthLimitInKbpsVal, iopsLimitVal), Boolean.class); + if (setVolumeSdcLimitsStatus != null) { + return setVolumeSdcLimitsStatus; } } return false; @@ -677,21 +671,12 @@ public boolean unmapVolumeFromSdc(final String volumeId, final String sdcId) { Preconditions.checkArgument(!Strings.isNullOrEmpty(volumeId), "Volume id cannot be null"); Preconditions.checkArgument(!Strings.isNullOrEmpty(sdcId), "Sdc Id cannot be null"); - HttpResponse response = null; - try { - if (isVolumeMappedToSdc(volumeId, sdcId)) { - response = post( - "/instances/Volume::" + volumeId + "/action/removeMappedSdc", - String.format("{\"sdcId\":\"%s\",\"skipApplianceValidation\":\"TRUE\"}", sdcId)); - checkResponseOK(response); - return true; - } - } catch (final IOException e) { - LOG.error("Failed to unmap PowerFlex volume due to:", e); - checkResponseTimeOut(e); - } finally { - if (response != null) { - EntityUtils.consumeQuietly(response.getEntity()); + if (isVolumeMappedToSdc(volumeId, sdcId)) { + Boolean unmapVolumeFromSdcStatus = post( + "/instances/Volume::" + volumeId + "/action/removeMappedSdc", + String.format("{\"sdcId\":\"%s\",\"skipApplianceValidation\":\"TRUE\"}", sdcId), Boolean.class); + if (unmapVolumeFromSdcStatus != null) { + return unmapVolumeFromSdcStatus; } } return false; @@ -701,30 +686,21 @@ public boolean unmapVolumeFromSdc(final String volumeId, final String sdcId) { public boolean unmapVolumeFromAllSdcs(final String volumeId) { Preconditions.checkArgument(!Strings.isNullOrEmpty(volumeId), "Volume id cannot be null"); - HttpResponse response = null; - try { - Volume volume = getVolume(volumeId); - if (volume == null) { - return false; - } - - List mappedSdcList = volume.getMappedSdcList(); - if (mappedSdcList == null || mappedSdcList.isEmpty()) { - return true; - } + Volume volume = getVolume(volumeId); + if (volume == null) { + return false; + } - response = post( - "/instances/Volume::" + volumeId + "/action/removeMappedSdc", - "{\"allSdcs\": \"\"}"); - checkResponseOK(response); + List mappedSdcList = volume.getMappedSdcList(); + if (mappedSdcList == null || mappedSdcList.isEmpty()) { return true; - } catch (final IOException e) { - LOG.error("Failed to unmap PowerFlex volume from all SDCs due to:", e); - checkResponseTimeOut(e); - } finally { - if (response != null) { - EntityUtils.consumeQuietly(response.getEntity()); - } + } + + Boolean unmapVolumeFromAllSdcsStatus = post( + "/instances/Volume::" + volumeId + "/action/removeMappedSdc", + "{\"allSdcs\": \"\"}", Boolean.class); + if (unmapVolumeFromAllSdcsStatus != null) { + return unmapVolumeFromAllSdcsStatus; } return false; } @@ -759,23 +735,14 @@ public boolean isVolumeMappedToSdc(final String volumeId, final String sdcId) { public boolean deleteVolume(final String volumeId) { Preconditions.checkArgument(!Strings.isNullOrEmpty(volumeId), "Volume id cannot be null"); - HttpResponse response = null; try { - try { - unmapVolumeFromAllSdcs(volumeId); - } catch (Exception ignored) {} - response = post( - "/instances/Volume::" + volumeId + "/action/removeVolume", - "{\"removeMode\":\"ONLY_ME\"}"); - checkResponseOK(response); - return true; - } catch (final IOException e) { - LOG.error("Failed to delete PowerFlex volume due to:", e); - checkResponseTimeOut(e); - } finally { - if (response != null) { - EntityUtils.consumeQuietly(response.getEntity()); - } + unmapVolumeFromAllSdcs(volumeId); + } catch (Exception ignored) {} + Boolean removeVolumeStatus = post( + "/instances/Volume::" + volumeId + "/action/removeVolume", + "{\"removeMode\":\"ONLY_ME\"}", Boolean.class); + if (removeVolumeStatus != null) { + return removeVolumeStatus; } return false; } @@ -797,21 +764,8 @@ public boolean migrateVolume(final String srcVolumeId, final String destPoolId, LOG.debug("Migrating the volume: " + srcVolumeId + " on the src pool: " + srcPoolId + " to the dest pool: " + destPoolId + " in the same PowerFlex cluster"); - HttpResponse response = null; - try { - response = post( - "/instances/Volume::" + srcVolumeId + "/action/migrateVTree", - String.format("{\"destSPId\":\"%s\"}", destPoolId)); - checkResponseOK(response); - } catch (final IOException e) { - LOG.error("Unable to migrate PowerFlex volume due to: ", e); - checkResponseTimeOut(e); - throw e; - } finally { - if (response != null) { - EntityUtils.consumeQuietly(response.getEntity()); - } - } + post("/instances/Volume::" + srcVolumeId + "/action/migrateVTree", + String.format("{\"destSPId\":\"%s\"}", destPoolId), Boolean.class); LOG.debug("Wait until the migration is complete for the volume: " + srcVolumeId); long migrationStartTime = System.currentTimeMillis(); @@ -899,22 +853,9 @@ private VTreeMigrationInfo.MigrationStatus getVolumeTreeMigrationStatus(final St return null; } - HttpResponse response = null; - try { - response = get("/instances/VTree::" + volumeTreeId); - checkResponseOK(response); - ObjectMapper mapper = new ObjectMapper().configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); - VTree volumeTree = mapper.readValue(response.getEntity().getContent(), VTree.class); - if (volumeTree != null && volumeTree.getVTreeMigrationInfo() != null) { - return volumeTree.getVTreeMigrationInfo().getMigrationStatus(); - } - } catch (final IOException e) { - LOG.error("Failed to migrate PowerFlex volume due to:", e); - checkResponseTimeOut(e); - } finally { - if (response != null) { - EntityUtils.consumeQuietly(response.getEntity()); - } + VTree volumeTree = get("/instances/VTree::" + volumeTreeId, VTree.class); + if (volumeTree != null && volumeTree.getVTreeMigrationInfo() != null) { + return volumeTree.getVTreeMigrationInfo().getMigrationStatus(); } return null; } @@ -922,53 +863,49 @@ private VTreeMigrationInfo.MigrationStatus getVolumeTreeMigrationStatus(final St private boolean rollbackVolumeMigration(final String srcVolumeId) { Preconditions.checkArgument(!Strings.isNullOrEmpty(srcVolumeId), "src volume id cannot be null"); - HttpResponse response = null; - try { - Volume volume = getVolume(srcVolumeId); - VTreeMigrationInfo.MigrationStatus migrationStatus = getVolumeTreeMigrationStatus(volume.getVtreeId()); - if (migrationStatus != null && migrationStatus == VTreeMigrationInfo.MigrationStatus.NotInMigration) { - LOG.debug("Volume: " + srcVolumeId + " is not migrating, no need to rollback"); - return true; - } + Volume volume = getVolume(srcVolumeId); + if (volume == null) { + LOG.warn("Unable to rollback volume migration, couldn't get details for the volume: " + srcVolumeId); + return false; + } - pauseVolumeMigration(srcVolumeId, true); // Pause forcefully - // Wait few secs for volume migration to change to Paused state - boolean paused = false; - int retryCount = 3; - while (retryCount > 0) { - try { - Thread.sleep(3000); // Try after few secs - migrationStatus = getVolumeTreeMigrationStatus(volume.getVtreeId()); // Get updated migration status - if (migrationStatus != null && migrationStatus == VTreeMigrationInfo.MigrationStatus.Paused) { - LOG.debug("Migration for the volume: " + srcVolumeId + " paused"); - paused = true; - break; - } - } catch (Exception ex) { - LOG.warn("Exception while checking for migration pause status of the volume: " + srcVolumeId + " - " + ex.getLocalizedMessage()); - // don't do anything - } finally { - retryCount--; + VTreeMigrationInfo.MigrationStatus migrationStatus = getVolumeTreeMigrationStatus(volume.getVtreeId()); + if (migrationStatus != null && migrationStatus == VTreeMigrationInfo.MigrationStatus.NotInMigration) { + LOG.debug("Volume: " + srcVolumeId + " is not migrating, no need to rollback"); + return true; + } + + pauseVolumeMigration(srcVolumeId, true); // Pause forcefully + // Wait few secs for volume migration to change to Paused state + boolean paused = false; + int retryCount = 3; + while (retryCount > 0) { + try { + Thread.sleep(3000); // Try after few secs + migrationStatus = getVolumeTreeMigrationStatus(volume.getVtreeId()); // Get updated migration status + if (migrationStatus != null && migrationStatus == VTreeMigrationInfo.MigrationStatus.Paused) { + LOG.debug("Migration for the volume: " + srcVolumeId + " paused"); + paused = true; + break; } + } catch (Exception ex) { + LOG.warn("Exception while checking for migration pause status of the volume: " + srcVolumeId + " - " + ex.getLocalizedMessage()); + // don't do anything + } finally { + retryCount--; } + } - if (paused) { - // Rollback migration to the src pool (should be quick) - response = post( - "/instances/Volume::" + srcVolumeId + "/action/migrateVTree", - String.format("{\"destSPId\":\"%s\"}", volume.getStoragePoolId())); - checkResponseOK(response); - return true; - } else { - LOG.warn("Migration for the volume: " + srcVolumeId + " didn't pause, couldn't rollback"); - } - } catch (final IOException e) { - LOG.error("Failed to rollback volume migration due to: ", e); - checkResponseTimeOut(e); - } finally { - if (response != null) { - EntityUtils.consumeQuietly(response.getEntity()); + if (paused) { + // Rollback migration to the src pool (should be quick) + Boolean migrateVTreeStatus = post( + "/instances/Volume::" + srcVolumeId + "/action/migrateVTree", + String.format("{\"destSPId\":\"%s\"}", volume.getStoragePoolId()), Boolean.class); + if (migrateVTreeStatus != null) { + return migrateVTreeStatus; } + } else { + LOG.warn("Migration for the volume: " + srcVolumeId + " didn't pause, couldn't rollback"); } return false; } @@ -979,23 +916,14 @@ private boolean pauseVolumeMigration(final String volumeId, final boolean forced return false; } - HttpResponse response = null; - try { - // When paused gracefully, all data currently being moved is allowed to complete the migration. - // When paused forcefully, migration of unfinished data is aborted and data is left at the source, if possible. - // Pausing forcefully carries a potential risk to data. - response = post( - "/instances/Volume::" + volumeId + "/action/pauseVTreeMigration", - String.format("{\"pauseType\":\"%s\"}", forced ? "Forcefully" : "Gracefully")); - checkResponseOK(response); - return true; - } catch (final IOException e) { - LOG.error("Failed to pause migration of the volume due to: ", e); - checkResponseTimeOut(e); - } finally { - if (response != null) { - EntityUtils.consumeQuietly(response.getEntity()); - } + // When paused gracefully, all data currently being moved is allowed to complete the migration. + // When paused forcefully, migration of unfinished data is aborted and data is left at the source, if possible. + // Pausing forcefully carries a potential risk to data. + Boolean pauseVTreeMigrationStatus = post( + "/instances/Volume::" + volumeId + "/action/pauseVTreeMigration", + String.format("{\"pauseType\":\"%s\"}", forced ? "Forcefully" : "Gracefully"), Boolean.class); + if (pauseVTreeMigrationStatus != null) { + return pauseVTreeMigrationStatus; } return false; } @@ -1006,20 +934,9 @@ private boolean pauseVolumeMigration(final String volumeId, final boolean forced @Override public List listStoragePools() { - HttpResponse response = null; - try { - response = get("/types/StoragePool/instances"); - checkResponseOK(response); - ObjectMapper mapper = new ObjectMapper().configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); - StoragePool[] pools = mapper.readValue(response.getEntity().getContent(), StoragePool[].class); + StoragePool[] pools = get("/types/StoragePool/instances", StoragePool[].class); + if (pools != null) { return Arrays.asList(pools); - } catch (final IOException e) { - LOG.error("Failed to list PowerFlex storage pools due to:", e); - checkResponseTimeOut(e); - } finally { - if (response != null) { - EntityUtils.consumeQuietly(response.getEntity()); - } } return new ArrayList<>(); } @@ -1027,72 +944,29 @@ public List listStoragePools() { @Override public StoragePool getStoragePool(String poolId) { Preconditions.checkArgument(!Strings.isNullOrEmpty(poolId), "Storage pool id cannot be null"); - - HttpResponse response = null; - try { - response = get("/instances/StoragePool::" + poolId); - checkResponseOK(response); - ObjectMapper mapper = new ObjectMapper().configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); - return mapper.readValue(response.getEntity().getContent(), StoragePool.class); - } catch (final IOException e) { - LOG.error("Failed to get storage pool due to:", e); - checkResponseTimeOut(e); - } finally { - if (response != null) { - EntityUtils.consumeQuietly(response.getEntity()); - } - } - return null; + return get("/instances/StoragePool::" + poolId, StoragePool.class); } @Override public StoragePoolStatistics getStoragePoolStatistics(String poolId) { Preconditions.checkArgument(!Strings.isNullOrEmpty(poolId), "Storage pool id cannot be null"); - - HttpResponse response = null; - try { - response = get("/instances/StoragePool::" + poolId + "/relationships/Statistics"); - checkResponseOK(response); - ObjectMapper mapper = new ObjectMapper().configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); - return mapper.readValue(response.getEntity().getContent(), StoragePoolStatistics.class); - } catch (final IOException e) { - LOG.error("Failed to get storage pool due to:", e); - checkResponseTimeOut(e); - } finally { - if (response != null) { - EntityUtils.consumeQuietly(response.getEntity()); - } - } - return null; + return get("/instances/StoragePool::" + poolId + "/relationships/Statistics", StoragePoolStatistics.class); } @Override public VolumeStatistics getVolumeStatistics(String volumeId) { Preconditions.checkArgument(!Strings.isNullOrEmpty(volumeId), "Volume id cannot be null"); - HttpResponse response = null; - try { - Volume volume = getVolume(volumeId); - if (volume != null) { - String volumeTreeId = volume.getVtreeId(); - if (!Strings.isNullOrEmpty(volumeTreeId)) { - response = get("/instances/VTree::" + volumeTreeId + "/relationships/Statistics"); - checkResponseOK(response); - ObjectMapper mapper = new ObjectMapper().configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); - VolumeStatistics volumeStatistics = mapper.readValue(response.getEntity().getContent(), VolumeStatistics.class); - if (volumeStatistics != null) { - volumeStatistics.setAllocatedSizeInKb(volume.getSizeInKb()); - return volumeStatistics; - } + Volume volume = getVolume(volumeId); + if (volume != null) { + String volumeTreeId = volume.getVtreeId(); + if (!Strings.isNullOrEmpty(volumeTreeId)) { + VolumeStatistics volumeStatistics = get("/instances/VTree::" + volumeTreeId + "/relationships/Statistics", VolumeStatistics.class); + if (volumeStatistics != null) { + volumeStatistics.setAllocatedSizeInKb(volume.getSizeInKb()); + return volumeStatistics; } } - } catch (final IOException e) { - LOG.error("Failed to get volume stats due to:", e); - checkResponseTimeOut(e); - } finally { - if (response != null) { - EntityUtils.consumeQuietly(response.getEntity()); - } } return null; @@ -1102,22 +976,9 @@ public VolumeStatistics getVolumeStatistics(String volumeId) { public String getSystemId(String protectionDomainId) { Preconditions.checkArgument(!Strings.isNullOrEmpty(protectionDomainId), "Protection domain id cannot be null"); - HttpResponse response = null; - try { - response = get("/instances/ProtectionDomain::" + protectionDomainId); - checkResponseOK(response); - ObjectMapper mapper = new ObjectMapper().configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); - ProtectionDomain protectionDomain = mapper.readValue(response.getEntity().getContent(), ProtectionDomain.class); - if (protectionDomain != null) { - return protectionDomain.getSystemId(); - } - } catch (final IOException e) { - LOG.error("Failed to get protection domain details due to:", e); - checkResponseTimeOut(e); - } finally { - if (response != null) { - EntityUtils.consumeQuietly(response.getEntity()); - } + ProtectionDomain protectionDomain = get("/instances/ProtectionDomain::" + protectionDomainId, ProtectionDomain.class); + if (protectionDomain != null) { + return protectionDomain.getSystemId(); } return null; } @@ -1126,20 +987,9 @@ public String getSystemId(String protectionDomainId) { public List listVolumesInStoragePool(String poolId) { Preconditions.checkArgument(!Strings.isNullOrEmpty(poolId), "Storage pool id cannot be null"); - HttpResponse response = null; - try { - response = get("/instances/StoragePool::" + poolId + "/relationships/Volume"); - checkResponseOK(response); - ObjectMapper mapper = new ObjectMapper().configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); - Volume[] volumes = mapper.readValue(response.getEntity().getContent(), Volume[].class); + Volume[] volumes = get("/instances/StoragePool::" + poolId + "/relationships/Volume", Volume[].class); + if (volumes != null) { return Arrays.asList(volumes); - } catch (final IOException e) { - LOG.error("Failed to list volumes in storage pool due to:", e); - checkResponseTimeOut(e); - } finally { - if (response != null) { - EntityUtils.consumeQuietly(response.getEntity()); - } } return new ArrayList<>(); } @@ -1150,20 +1000,9 @@ public List listVolumesInStoragePool(String poolId) { @Override public List listSdcs() { - HttpResponse response = null; - try { - response = get("/types/Sdc/instances"); - checkResponseOK(response); - ObjectMapper mapper = new ObjectMapper().configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); - Sdc[] sdcs = mapper.readValue(response.getEntity().getContent(), Sdc[].class); + Sdc[] sdcs = get("/types/Sdc/instances", Sdc[].class); + if (sdcs != null) { return Arrays.asList(sdcs); - } catch (final IOException e) { - LOG.error("Failed to list SDCs due to:", e); - checkResponseTimeOut(e); - } finally { - if (response != null) { - EntityUtils.consumeQuietly(response.getEntity()); - } } return new ArrayList<>(); } @@ -1171,43 +1010,16 @@ public List listSdcs() { @Override public Sdc getSdc(String sdcId) { Preconditions.checkArgument(!Strings.isNullOrEmpty(sdcId), "Sdc id cannot be null"); - - HttpResponse response = null; - try { - response = get("/instances/Sdc::" + sdcId); - checkResponseOK(response); - ObjectMapper mapper = new ObjectMapper().configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); - return mapper.readValue(response.getEntity().getContent(), Sdc.class); - } catch (final IOException e) { - LOG.error("Failed to get volume due to:", e); - checkResponseTimeOut(e); - } finally { - if (response != null) { - EntityUtils.consumeQuietly(response.getEntity()); - } - } - return null; + return get("/instances/Sdc::" + sdcId, Sdc.class); } @Override public Sdc getSdcByIp(String ipAddress) { Preconditions.checkArgument(!Strings.isNullOrEmpty(ipAddress), "IP address cannot be null"); - HttpResponse response = null; - try { - response = post("/types/Sdc/instances/action/queryIdByKey", String.format("{\"ip\":\"%s\"}", ipAddress)); - checkResponseOK(response); - String sdcId = EntityUtils.toString(response.getEntity()); - if (!Strings.isNullOrEmpty(sdcId)) { - return getSdc(sdcId.replace("\"", "")); - } - } catch (final IOException e) { - LOG.error("Failed to get volume due to:", e); - checkResponseTimeOut(e); - } finally { - if (response != null) { - EntityUtils.consumeQuietly(response.getEntity()); - } + String sdcId = post("/types/Sdc/instances/action/queryIdByKey", String.format("{\"ip\":\"%s\"}", ipAddress), String.class); + if (!Strings.isNullOrEmpty(sdcId)) { + return getSdc(sdcId.replace("\"", "")); } return null; } @@ -1252,4 +1064,27 @@ public boolean isSdcConnected(String ipAddress) { return false; } + + private String getConnectionManagerStats() { + StringBuilder sb = new StringBuilder(); + sb.append("\n").append("Client Connection Manager Stats => "); + if (connectionManager != null) { + sb.append("MaxTotal: ").append(connectionManager.getMaxTotal()).append(", "); + sb.append("DefaultMaxPerRoute: ").append(connectionManager.getDefaultMaxPerRoute()); + + PoolStats poolStats = connectionManager.getTotalStats(); + if (poolStats != null) { + sb.append(", "); + sb.append("Available: ").append(poolStats.getAvailable()).append(", "); + sb.append("Leased: ").append(poolStats.getLeased()).append(", "); + sb.append("Max: ").append(poolStats.getMax()).append(", "); + sb.append("Pending: ").append(poolStats.getPending()); + } + } else { + sb.append("NULL"); + } + + sb.append("\n"); + return sb.toString(); + } } diff --git a/plugins/storage/volume/scaleio/src/main/java/org/apache/cloudstack/storage/datastore/lifecycle/ScaleIOPrimaryDataStoreLifeCycle.java b/plugins/storage/volume/scaleio/src/main/java/org/apache/cloudstack/storage/datastore/lifecycle/ScaleIOPrimaryDataStoreLifeCycle.java index 5c9ddea47526..edebdac79299 100644 --- a/plugins/storage/volume/scaleio/src/main/java/org/apache/cloudstack/storage/datastore/lifecycle/ScaleIOPrimaryDataStoreLifeCycle.java +++ b/plugins/storage/volume/scaleio/src/main/java/org/apache/cloudstack/storage/datastore/lifecycle/ScaleIOPrimaryDataStoreLifeCycle.java @@ -106,7 +106,8 @@ public ScaleIOPrimaryDataStoreLifeCycle() { private org.apache.cloudstack.storage.datastore.api.StoragePool findStoragePool(String url, String username, String password, String storagePoolName) { try { final int clientTimeout = StorageManager.STORAGE_POOL_CLIENT_TIMEOUT.value(); - ScaleIOGatewayClient client = ScaleIOGatewayClient.getClient(url, username, password, false, clientTimeout); + final int clientMaxConnections = StorageManager.STORAGE_POOL_CLIENT_MAX_CONNECTIONS.value(); + ScaleIOGatewayClient client = ScaleIOGatewayClient.getClient(url, username, password, false, clientTimeout, clientMaxConnections); List storagePools = client.listStoragePools(); for (org.apache.cloudstack.storage.datastore.api.StoragePool pool : storagePools) { if (pool.getName().equals(storagePoolName)) { @@ -121,9 +122,9 @@ private org.apache.cloudstack.storage.datastore.api.StoragePool findStoragePool( } } catch (NoSuchAlgorithmException | KeyManagementException | URISyntaxException e) { LOGGER.error("Failed to add storage pool", e); - throw new CloudRuntimeException("Failed to establish connection with PowerFlex Gateway to validate storage pool"); + throw new CloudRuntimeException("Failed to establish connection with PowerFlex Gateway to find and validate storage pool: " + storagePoolName); } - throw new CloudRuntimeException("Failed to find the provided storage pool name in discovered PowerFlex storage pools"); + throw new CloudRuntimeException("Failed to find the provided storage pool name: " + storagePoolName + " in the discovered PowerFlex storage pools"); } @SuppressWarnings("unchecked") diff --git a/plugins/storage/volume/scaleio/src/test/java/org/apache/cloudstack/storage/datastore/client/ScaleIOGatewayClientImplTest.java b/plugins/storage/volume/scaleio/src/test/java/org/apache/cloudstack/storage/datastore/client/ScaleIOGatewayClientImplTest.java index 10823102cf8d..80a78c809095 100644 --- a/plugins/storage/volume/scaleio/src/test/java/org/apache/cloudstack/storage/datastore/client/ScaleIOGatewayClientImplTest.java +++ b/plugins/storage/volume/scaleio/src/test/java/org/apache/cloudstack/storage/datastore/client/ScaleIOGatewayClientImplTest.java @@ -19,30 +19,179 @@ package org.apache.cloudstack.storage.datastore.client; +import static com.github.tomakehurst.wiremock.client.WireMock.aResponse; +import static com.github.tomakehurst.wiremock.client.WireMock.containing; +import static com.github.tomakehurst.wiremock.client.WireMock.equalTo; +import static com.github.tomakehurst.wiremock.client.WireMock.get; +import static com.github.tomakehurst.wiremock.client.WireMock.getRequestedFor; +import static com.github.tomakehurst.wiremock.client.WireMock.ok; +import static com.github.tomakehurst.wiremock.client.WireMock.post; +import static com.github.tomakehurst.wiremock.client.WireMock.postRequestedFor; +import static com.github.tomakehurst.wiremock.client.WireMock.unauthorized; +import static com.github.tomakehurst.wiremock.client.WireMock.urlEqualTo; +import static com.github.tomakehurst.wiremock.core.WireMockConfiguration.wireMockConfig; + +import org.apache.cloudstack.api.ServerApiException; +import org.apache.cloudstack.storage.datastore.api.Volume; import org.junit.After; +import org.junit.Assert; import org.junit.Before; +import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.junit.MockitoJUnitRunner; +import com.cloud.storage.Storage; import com.cloud.utils.exception.CloudRuntimeException; +import com.github.tomakehurst.wiremock.client.BasicCredentials; +import com.github.tomakehurst.wiremock.junit.WireMockRule; @RunWith(MockitoJUnitRunner.class) public class ScaleIOGatewayClientImplTest { + private final int port = 443; + private final int timeout = 30; + private final int maxConnections = 50; + private final String username = "admin"; + private final String password = "P@ssword123"; + private final String sessionKey = "YWRtaW46MTYyMzM0OTc4NDk0MTo2MWQ2NGQzZWJhMTVmYTVkNDIwNjZmOWMwZDg0ZGZmOQ"; + private ScaleIOGatewayClient client = null; - ScaleIOGatewayClientImpl client; + @Rule + public WireMockRule wireMockRule = new WireMockRule(wireMockConfig() + .httpsPort(port) + .needClientAuth(false) + .basicAdminAuthenticator(username, password) + .bindAddress("localhost")); @Before public void setUp() throws Exception { + wireMockRule.stubFor(get("/api/login") + .willReturn(ok() + .withHeader("Content-Type", "application/json;charset=UTF-8") + .withBody(sessionKey))); + + client = new ScaleIOGatewayClientImpl("https://localhost/api", username, password, false, timeout, maxConnections); + + wireMockRule.stubFor(post("/api/types/Volume/instances") + .willReturn(aResponse() + .withHeader("Content-Type", "application/json;charset=UTF-8") + .withStatus(200) + .withBody("{\"id\":\"c948d0b10000000a\"}"))); + + wireMockRule.stubFor(get("/api/instances/Volume::c948d0b10000000a") + .willReturn(aResponse() + .withHeader("Content-Type", "application/json;charset=UTF-8") + .withStatus(200) + .withBody("{\"storagePoolId\":\"4daaa55e00000000\",\"dataLayout\":\"MediumGranularity\",\"vtreeId\":\"657e289500000009\"," + + "\"sizeInKb\":8388608,\"snplIdOfAutoSnapshot\":null,\"volumeType\":\"ThinProvisioned\",\"consistencyGroupId\":null," + + "\"ancestorVolumeId\":null,\"notGenuineSnapshot\":false,\"accessModeLimit\":\"ReadWrite\",\"secureSnapshotExpTime\":0," + + "\"useRmcache\":false,\"managedBy\":\"ScaleIO\",\"lockedAutoSnapshot\":false,\"lockedAutoSnapshotMarkedForRemoval\":false," + + "\"autoSnapshotGroupId\":null,\"compressionMethod\":\"Invalid\",\"pairIds\":null,\"timeStampIsAccurate\":false,\"mappedSdcInfo\":null," + + "\"retentionLevels\":[],\"snplIdOfSourceVolume\":null,\"volumeReplicationState\":\"UnmarkedForReplication\",\"replicationJournalVolume\":false," + + "\"replicationTimeStamp\":0,\"originalExpiryTime\":0,\"creationTime\":1623335880,\"name\":\"testvolume\",\"id\":\"c948d0b10000000a\"}"))); } @After public void tearDown() throws Exception { } + @Test + public void testClientAuthSuccess() { + Assert.assertNotNull(client); + wireMockRule.verify(getRequestedFor(urlEqualTo("/api/login")) + .withBasicAuth(new BasicCredentials(username, password))); + + wireMockRule.stubFor(get("/api/types/StoragePool/instances") + .willReturn(aResponse() + .withHeader("Content-Type", "application/json;charset=UTF-8") + .withStatus(200) + .withBody(""))); + + client.listStoragePools(); + + wireMockRule.verify(getRequestedFor(urlEqualTo("/api/types/StoragePool/instances")) + .withBasicAuth(new BasicCredentials(username, sessionKey))); + } + @Test(expected = CloudRuntimeException.class) - public void testClient() throws Exception { - client = (ScaleIOGatewayClientImpl) ScaleIOGatewayClient.getClient("https://10.2.3.149/api", - "admin", "P@ssword123", false, 60); + public void testClientAuthFailure() throws Exception { + wireMockRule.stubFor(get("/api/login") + .willReturn(unauthorized() + .withHeader("Content-Type", "application/json;charset=UTF-8") + .withBody(""))); + + new ScaleIOGatewayClientImpl("https://localhost/api", username, password, false, timeout, maxConnections); + } + + @Test(expected = ServerApiException.class) + public void testRequestTimeout() { + Assert.assertNotNull(client); + wireMockRule.verify(getRequestedFor(urlEqualTo("/api/login")) + .withBasicAuth(new BasicCredentials(username, password))); + + wireMockRule.stubFor(get("/api/types/StoragePool/instances") + .willReturn(aResponse() + .withHeader("Content-Type", "application/json;charset=UTF-8") + .withStatus(200) + .withFixedDelay(2 * timeout * 1000) + .withBody(""))); + + client.listStoragePools(); + } + + @Test + public void testCreateSingleVolume() { + Assert.assertNotNull(client); + wireMockRule.verify(getRequestedFor(urlEqualTo("/api/login")) + .withBasicAuth(new BasicCredentials(username, password))); + + final String volumeName = "testvolume"; + final String scaleIOStoragePoolId = "4daaa55e00000000"; + final int sizeInGb = 8; + Volume scaleIOVolume = client.createVolume(volumeName, scaleIOStoragePoolId, sizeInGb, Storage.ProvisioningType.THIN); + + wireMockRule.verify(postRequestedFor(urlEqualTo("/api/types/Volume/instances")) + .withBasicAuth(new BasicCredentials(username, sessionKey)) + .withRequestBody(containing("\"name\":\"" + volumeName + "\"")) + .withHeader("Content-Type", equalTo("application/json"))); + wireMockRule.verify(getRequestedFor(urlEqualTo("/api/instances/Volume::c948d0b10000000a")) + .withBasicAuth(new BasicCredentials(username, sessionKey))); + + Assert.assertNotNull(scaleIOVolume); + Assert.assertEquals(scaleIOVolume.getId(), "c948d0b10000000a"); + Assert.assertEquals(scaleIOVolume.getName(), volumeName); + Assert.assertEquals(scaleIOVolume.getStoragePoolId(), scaleIOStoragePoolId); + Assert.assertEquals(scaleIOVolume.getSizeInKb(), Long.valueOf(sizeInGb * 1024 * 1024)); + Assert.assertEquals(scaleIOVolume.getVolumeType(), Volume.VolumeType.ThinProvisioned); + } + + @Test + public void testCreateMultipleVolumes() { + Assert.assertNotNull(client); + wireMockRule.verify(getRequestedFor(urlEqualTo("/api/login")) + .withBasicAuth(new BasicCredentials(username, password))); + + final String volumeNamePrefix = "testvolume_"; + final String scaleIOStoragePoolId = "4daaa55e00000000"; + final int sizeInGb = 8; + final int volumesCount = 1000; + + for (int i = 1; i <= volumesCount; i++) { + String volumeName = volumeNamePrefix + i; + Volume scaleIOVolume = client.createVolume(volumeName, scaleIOStoragePoolId, sizeInGb, Storage.ProvisioningType.THIN); + + Assert.assertNotNull(scaleIOVolume); + Assert.assertEquals(scaleIOVolume.getId(), "c948d0b10000000a"); + Assert.assertEquals(scaleIOVolume.getStoragePoolId(), scaleIOStoragePoolId); + Assert.assertEquals(scaleIOVolume.getSizeInKb(), Long.valueOf(sizeInGb * 1024 * 1024)); + Assert.assertEquals(scaleIOVolume.getVolumeType(), Volume.VolumeType.ThinProvisioned); + } + + wireMockRule.verify(volumesCount, postRequestedFor(urlEqualTo("/api/types/Volume/instances")) + .withBasicAuth(new BasicCredentials(username, sessionKey)) + .withRequestBody(containing("\"name\":\"" + volumeNamePrefix)) + .withHeader("Content-Type", equalTo("application/json"))); + wireMockRule.verify(volumesCount, getRequestedFor(urlEqualTo("/api/instances/Volume::c948d0b10000000a")) + .withBasicAuth(new BasicCredentials(username, sessionKey))); } } \ No newline at end of file diff --git a/scripts/storage/secondary/createvolume.sh b/scripts/storage/secondary/createvolume.sh index 12f73ebc1096..14bbee4d4dff 100755 --- a/scripts/storage/secondary/createvolume.sh +++ b/scripts/storage/secondary/createvolume.sh @@ -139,6 +139,16 @@ create_from_file() { } +copy_from_file() { + local tmpltfs=$1 + local tmpltimg=$2 + local tmpltname=$3 + + [ -n "$verbose" ] && echo "Copying to $tmpltfs/$tmpltname...could take a while" >&2 + cp -rf $tmpltimg /$tmpltfs/$tmpltname + rm -rf $tmpltimg +} + tflag= nflag= fflag= @@ -228,7 +238,11 @@ fi imgsize=$(ls -l $tmpltimg2| awk -F" " '{print $5}') -create_from_file $tmpltfs $tmpltimg2 $tmpltname +if [ "$descr" = "configDrive" ] && [ "$Sflag" = "" ];then + copy_from_file $tmpltfs $tmpltimg2 $tmpltname +else + create_from_file $tmpltfs $tmpltimg2 $tmpltname +fi touch /$tmpltfs/volume.properties rollback_if_needed $tmpltfs $? "Failed to create volume.properties file" diff --git a/server/src/main/java/com/cloud/acl/DomainChecker.java b/server/src/main/java/com/cloud/acl/DomainChecker.java index 24b6b2a42b42..aba0d456bfa2 100644 --- a/server/src/main/java/com/cloud/acl/DomainChecker.java +++ b/server/src/main/java/com/cloud/acl/DomainChecker.java @@ -105,7 +105,7 @@ protected DomainChecker() { @Override public boolean checkAccess(Account caller, Domain domain) throws PermissionDeniedException { if (caller.getState() != Account.State.enabled) { - throw new PermissionDeniedException(caller + " is disabled."); + throw new PermissionDeniedException("Account " + caller.getAccountName() + " is disabled."); } if (domain == null) { @@ -116,10 +116,10 @@ public boolean checkAccess(Account caller, Domain domain) throws PermissionDenie if (_accountService.isNormalUser(caller.getId())) { if (caller.getDomainId() != domainId) { - throw new PermissionDeniedException(caller + " does not have permission to operate within domain id=" + domain.getUuid()); + throw new PermissionDeniedException("Account " + caller.getAccountName() + " does not have permission to operate within domain id=" + domain.getUuid()); } } else if (!_domainDao.isChildDomain(caller.getDomainId(), domainId)) { - throw new PermissionDeniedException(caller + " does not have permission to operate within domain id=" + domain.getUuid()); + throw new PermissionDeniedException("Account " + caller.getAccountName() + " does not have permission to operate within domain id=" + domain.getUuid()); } return true; @@ -155,7 +155,8 @@ public boolean checkAccess(Account caller, ControlledEntity entity, AccessType a // account can launch a VM from this template LaunchPermissionVO permission = _launchPermissionDao.findByTemplateAndAccount(template.getId(), caller.getId()); if (permission == null) { - throw new PermissionDeniedException(caller + " does not have permission to launch instances from " + template); + throw new PermissionDeniedException("Account " + caller.getAccountName() + + " does not have permission to launch instances from template " + template.getName()); } } else { // Domain admin and regular user can delete/modify only templates created by them diff --git a/server/src/main/java/com/cloud/agent/manager/allocator/impl/UserConcentratedAllocator.java b/server/src/main/java/com/cloud/agent/manager/allocator/impl/UserConcentratedAllocator.java index e71636bed628..224514e856d8 100644 --- a/server/src/main/java/com/cloud/agent/manager/allocator/impl/UserConcentratedAllocator.java +++ b/server/src/main/java/com/cloud/agent/manager/allocator/impl/UserConcentratedAllocator.java @@ -282,17 +282,6 @@ private long calcHostAllocatedCpuMemoryCapacity(long hostId, short capacityType) private boolean templateAvailableInPod(long templateId, long dcId, long podId) { return true; - /* - * List thvoList = _templateHostDao.listByTemplateStatus(templateId, dcId, podId, Status.DOWNLOADED); - * List tpvoList = _templatePoolDao.listByTemplateStatus(templateId, dcId, podId, - * Status.DOWNLOADED); - * - * if (thvoList != null && thvoList.size() > 0) { if (s_logger.isDebugEnabled()) { s_logger.debug("Found " + - * thvoList.size() + " storage hosts in pod " + podId + " with template " + templateId); } return true; } else if - * (tpvoList != null && tpvoList.size() > 0) { if (s_logger.isDebugEnabled()) { s_logger.debug("Found " + - * tpvoList.size() + " storage pools in pod " + podId + " with template " + templateId); } return true; }else { return - * false; } - */ } @Override diff --git a/server/src/main/java/com/cloud/alert/AlertManagerImpl.java b/server/src/main/java/com/cloud/alert/AlertManagerImpl.java index 99200f41c2ad..f6e4360b9816 100644 --- a/server/src/main/java/com/cloud/alert/AlertManagerImpl.java +++ b/server/src/main/java/com/cloud/alert/AlertManagerImpl.java @@ -712,6 +712,11 @@ public void sendAlert(AlertType alertType, long dataCenterId, Long podId, Long c return; } + if (recipients == null) { + s_logger.warn(String.format("No recipients set in 'alert.email.addresses', skipping sending alert with subject: %s and content: %s", subject, content)); + return; + } + SMTPMailProperties mailProps = new SMTPMailProperties(); mailProps.setSender(new MailAddress(senderAddress)); mailProps.setSubject(subject); diff --git a/server/src/main/java/com/cloud/api/ApiDBUtils.java b/server/src/main/java/com/cloud/api/ApiDBUtils.java index 91af895870df..d688c276a338 100644 --- a/server/src/main/java/com/cloud/api/ApiDBUtils.java +++ b/server/src/main/java/com/cloud/api/ApiDBUtils.java @@ -1891,18 +1891,10 @@ public static HostResponse newHostResponse(HostJoinVO vr, EnumSet d return s_hostJoinDao.newHostResponse(vr, details); } - public static HostResponse fillHostDetails(HostResponse vrData, HostJoinVO vr) { - return s_hostJoinDao.setHostResponse(vrData, vr); - } - public static HostForMigrationResponse newHostForMigrationResponse(HostJoinVO vr, EnumSet details) { return s_hostJoinDao.newHostForMigrationResponse(vr, details); } - public static HostForMigrationResponse fillHostForMigrationDetails(HostForMigrationResponse vrData, HostJoinVO vr) { - return s_hostJoinDao.setHostForMigrationResponse(vrData, vr); - } - public static List newHostView(Host vr) { return s_hostJoinDao.newHostView(vr); } diff --git a/server/src/main/java/com/cloud/api/dispatch/ParamProcessWorker.java b/server/src/main/java/com/cloud/api/dispatch/ParamProcessWorker.java index d4299861e71e..e05a982ca2f7 100644 --- a/server/src/main/java/com/cloud/api/dispatch/ParamProcessWorker.java +++ b/server/src/main/java/com/cloud/api/dispatch/ParamProcessWorker.java @@ -159,6 +159,9 @@ public void processParameters(final BaseCmd cmd, final Map params) { } continue; } + if (parameterAnnotation.required()){ + validateNonEmptyString(paramObj, parameterAnnotation.name()); + } // marshall the parameter into the correct type and set the field value try { diff --git a/server/src/main/java/com/cloud/api/query/QueryManagerImpl.java b/server/src/main/java/com/cloud/api/query/QueryManagerImpl.java index e388a7539ec8..0c8a7f794355 100644 --- a/server/src/main/java/com/cloud/api/query/QueryManagerImpl.java +++ b/server/src/main/java/com/cloud/api/query/QueryManagerImpl.java @@ -187,6 +187,7 @@ import com.cloud.network.RouterHealthCheckResult; import com.cloud.network.VpcVirtualNetworkApplianceService; import com.cloud.network.dao.RouterHealthCheckResultDao; +import com.cloud.network.dao.RouterHealthCheckResultVO; import com.cloud.network.router.VirtualNetworkApplianceManager; import com.cloud.network.security.SecurityGroupVMMapVO; import com.cloud.network.security.dao.SecurityGroupVMMapDao; @@ -232,6 +233,7 @@ import com.cloud.utils.StringUtils; import com.cloud.utils.Ternary; import com.cloud.utils.db.Filter; +import com.cloud.utils.db.GenericSearchBuilder; import com.cloud.utils.db.JoinBuilder; import com.cloud.utils.db.SearchBuilder; import com.cloud.utils.db.SearchCriteria; @@ -1262,7 +1264,7 @@ private Pair, Integer> listSecurityGroupRulesByVM(long @Override public ListResponse searchForRouters(ListRoutersCmd cmd) { Pair, Integer> result = searchForRoutersInternal(cmd, cmd.getId(), cmd.getRouterName(), cmd.getState(), cmd.getZoneId(), cmd.getPodId(), cmd.getClusterId(), - cmd.getHostId(), cmd.getKeyword(), cmd.getNetworkId(), cmd.getVpcId(), cmd.getForVpc(), cmd.getRole(), cmd.getVersion()); + cmd.getHostId(), cmd.getKeyword(), cmd.getNetworkId(), cmd.getVpcId(), cmd.getForVpc(), cmd.getRole(), cmd.getVersion(), cmd.isHealthCheckFailed()); ListResponse response = new ListResponse(); List routerResponses = ViewResponseHelper.createDomainRouterResponse(result.first().toArray(new DomainRouterJoinVO[result.first().size()])); if (VirtualNetworkApplianceManager.RouterHealthChecksEnabled.value()) { @@ -1282,7 +1284,7 @@ public ListResponse searchForRouters(ListRoutersCmd cmd) { @Override public ListResponse searchForInternalLbVms(ListInternalLBVMsCmd cmd) { Pair, Integer> result = searchForRoutersInternal(cmd, cmd.getId(), cmd.getRouterName(), cmd.getState(), cmd.getZoneId(), cmd.getPodId(), null, cmd.getHostId(), - cmd.getKeyword(), cmd.getNetworkId(), cmd.getVpcId(), cmd.getForVpc(), cmd.getRole(), null); + cmd.getKeyword(), cmd.getNetworkId(), cmd.getVpcId(), cmd.getForVpc(), cmd.getRole(), null, null); ListResponse response = new ListResponse(); List routerResponses = ViewResponseHelper.createDomainRouterResponse(result.first().toArray(new DomainRouterJoinVO[result.first().size()])); if (VirtualNetworkApplianceManager.RouterHealthChecksEnabled.value()) { @@ -1301,7 +1303,7 @@ public ListResponse searchForInternalLbVms(ListInternalLBV } private Pair, Integer> searchForRoutersInternal(BaseListProjectAndAccountResourcesCmd cmd, Long id, String name, String state, Long zoneId, Long podId, Long clusterId, - Long hostId, String keyword, Long networkId, Long vpcId, Boolean forVpc, String role, String version) { + Long hostId, String keyword, Long networkId, Long vpcId, Boolean forVpc, String role, String version, Boolean isHealthCheckFailed) { Account caller = CallContext.current().getCallingAccount(); List permittedAccounts = new ArrayList(); @@ -1345,6 +1347,27 @@ private Pair, Integer> searchForRoutersInternal(BaseLis sb.and("networkId", sb.entity().getNetworkId(), SearchCriteria.Op.EQ); } + List routersWithFailures = null; + if (isHealthCheckFailed != null) { + GenericSearchBuilder routerHealthCheckResultSearch = routerHealthCheckResultDao.createSearchBuilder(Long.class); + routerHealthCheckResultSearch.and("checkResult", routerHealthCheckResultSearch.entity().getCheckResult(), SearchCriteria.Op.EQ); + routerHealthCheckResultSearch.selectFields(routerHealthCheckResultSearch.entity().getRouterId()); + routerHealthCheckResultSearch.done(); + SearchCriteria ssc = routerHealthCheckResultSearch.create(); + ssc.setParameters("checkResult", false); + routersWithFailures = routerHealthCheckResultDao.customSearch(ssc, null); + + if (routersWithFailures != null && ! routersWithFailures.isEmpty()) { + if (isHealthCheckFailed) { + sb.and("routerId", sb.entity().getId(), SearchCriteria.Op.IN); + } else { + sb.and("routerId", sb.entity().getId(), SearchCriteria.Op.NIN); + } + } else if (isHealthCheckFailed) { + return new Pair, Integer>(Collections.emptyList(), 0); + } + } + SearchCriteria sc = sb.create(); _accountMgr.buildACLViewSearchCriteria(sc, domainId, isRecursive, permittedAccounts, listProjectResourcesCriteria); @@ -1403,6 +1426,10 @@ private Pair, Integer> searchForRoutersInternal(BaseLis sc.setParameters("version", "Cloudstack Release " + version + "%"); } + if (routersWithFailures != null && ! routersWithFailures.isEmpty()) { + sc.setParameters("routerId", routersWithFailures.toArray(new Object[routersWithFailures.size()])); + } + // search VR details by ids Pair, Integer> uniqueVrPair = _routerJoinDao.searchAndCount(sc, searchFilter); Integer count = uniqueVrPair.second(); diff --git a/server/src/main/java/com/cloud/api/query/ViewResponseHelper.java b/server/src/main/java/com/cloud/api/query/ViewResponseHelper.java index 1067ff2ed472..ec3397407f20 100644 --- a/server/src/main/java/com/cloud/api/query/ViewResponseHelper.java +++ b/server/src/main/java/com/cloud/api/query/ViewResponseHelper.java @@ -242,14 +242,7 @@ public static List createHostResponse(EnumSet details Hashtable vrDataList = new Hashtable(); // Initialise the vrdatalist with the input data for (HostJoinVO vr : hosts) { - HostResponse vrData = vrDataList.get(vr.getId()); - if (vrData == null) { - // first time encountering this vm - vrData = ApiDBUtils.newHostResponse(vr, details); - } else { - // update tags - vrData = ApiDBUtils.fillHostDetails(vrData, vr); - } + HostResponse vrData = ApiDBUtils.newHostResponse(vr, details); vrDataList.put(vr.getId(), vrData); } return new ArrayList(vrDataList.values()); @@ -259,14 +252,7 @@ public static List createHostForMigrationResponse(Enum Hashtable vrDataList = new Hashtable(); // Initialise the vrdatalist with the input data for (HostJoinVO vr : hosts) { - HostForMigrationResponse vrData = vrDataList.get(vr.getId()); - if (vrData == null) { - // first time encountering this vm - vrData = ApiDBUtils.newHostForMigrationResponse(vr, details); - } else { - // update tags - vrData = ApiDBUtils.fillHostForMigrationDetails(vrData, vr); - } + HostForMigrationResponse vrData = ApiDBUtils.newHostForMigrationResponse(vr, details); vrDataList.put(vr.getId(), vrData); } return new ArrayList(vrDataList.values()); diff --git a/server/src/main/java/com/cloud/api/query/dao/HostJoinDao.java b/server/src/main/java/com/cloud/api/query/dao/HostJoinDao.java index e7dc5d5ff046..e7ad5e53862a 100644 --- a/server/src/main/java/com/cloud/api/query/dao/HostJoinDao.java +++ b/server/src/main/java/com/cloud/api/query/dao/HostJoinDao.java @@ -31,12 +31,8 @@ public interface HostJoinDao extends GenericDao { HostResponse newHostResponse(HostJoinVO host, EnumSet details); - HostResponse setHostResponse(HostResponse response, HostJoinVO host); - HostForMigrationResponse newHostForMigrationResponse(HostJoinVO host, EnumSet details); - HostForMigrationResponse setHostForMigrationResponse(HostForMigrationResponse response, HostJoinVO host); - List newHostView(Host group); List searchByIds(Long... ids); diff --git a/server/src/main/java/com/cloud/api/query/dao/HostJoinDaoImpl.java b/server/src/main/java/com/cloud/api/query/dao/HostJoinDaoImpl.java index 32236093f03c..af392a254022 100644 --- a/server/src/main/java/com/cloud/api/query/dao/HostJoinDaoImpl.java +++ b/server/src/main/java/com/cloud/api/query/dao/HostJoinDaoImpl.java @@ -18,6 +18,7 @@ import java.text.DecimalFormat; import java.util.ArrayList; +import java.util.Arrays; import java.util.Date; import java.util.EnumSet; import java.util.Iterator; @@ -93,6 +94,18 @@ protected HostJoinDaoImpl() { this._count = "select count(distinct id) from host_view WHERE "; } + private boolean containsHostHATag(final String tags) { + boolean result = false; + String haTag = ApiDBUtils.getHaTag(); + if (StringUtils.isNotEmpty(haTag) && StringUtils.isNotEmpty(tags)) { + List tagsList = Arrays.asList(tags.split(",")); + if (tagsList.contains(haTag)) { + result = true; + } + } + return result; + } + @Override public HostResponse newHostResponse(HostJoinVO host, EnumSet details) { HostResponse hostResponse = new HostResponse(); @@ -180,13 +193,7 @@ public HostResponse newHostResponse(HostJoinVO host, EnumSet detail String hostTags = host.getTag(); hostResponse.setHostTags(hostTags); - - hostResponse.setHaHost(false); - String haTag = ApiDBUtils.getHaTag(); - if (StringUtils.isNotEmpty(haTag) && StringUtils.isNotEmpty(hostTags) && - haTag.equalsIgnoreCase(hostTags)) { - hostResponse.setHaHost(true); - } + hostResponse.setHaHost(containsHostHATag(hostTags)); hostResponse.setHypervisorVersion(host.getHypervisorVersion()); @@ -268,26 +275,6 @@ public HostResponse newHostResponse(HostJoinVO host, EnumSet detail return hostResponse; } - @Override - public HostResponse setHostResponse(HostResponse response, HostJoinVO host) { - String tag = host.getTag(); - if (StringUtils.isNotEmpty(tag)) { - if (StringUtils.isNotEmpty(response.getHostTags())) { - response.setHostTags(response.getHostTags() + "," + tag); - } else { - response.setHostTags(tag); - } - - if (Boolean.FALSE.equals(response.getHaHost())) { - String haTag = ApiDBUtils.getHaTag(); - if (StringUtils.isNotEmpty(haTag) && haTag.equalsIgnoreCase(tag)) { - response.setHaHost(true); - } - } - } - return response; - } - @Override public HostForMigrationResponse newHostForMigrationResponse(HostJoinVO host, EnumSet details) { HostForMigrationResponse hostResponse = new HostForMigrationResponse(); @@ -339,13 +326,7 @@ public HostForMigrationResponse newHostForMigrationResponse(HostJoinVO host, Enu String hostTags = host.getTag(); hostResponse.setHostTags(hostTags); - - hostResponse.setHaHost(false); - String haTag = ApiDBUtils.getHaTag(); - if (StringUtils.isNotEmpty(haTag) && StringUtils.isNotEmpty(hostTags) && - haTag.equalsIgnoreCase(hostTags)) { - hostResponse.setHaHost(true); - } + hostResponse.setHaHost(containsHostHATag(hostTags)); hostResponse.setHypervisorVersion(host.getHypervisorVersion()); @@ -410,26 +391,6 @@ public HostForMigrationResponse newHostForMigrationResponse(HostJoinVO host, Enu return hostResponse; } - @Override - public HostForMigrationResponse setHostForMigrationResponse(HostForMigrationResponse response, HostJoinVO host) { - String tag = host.getTag(); - if (tag != null) { - if (response.getHostTags() != null && response.getHostTags().length() > 0) { - response.setHostTags(response.getHostTags() + "," + tag); - } else { - response.setHostTags(tag); - } - - if (Boolean.FALSE.equals(response.getHaHost())) { - String haTag = ApiDBUtils.getHaTag(); - if (StringUtils.isNotEmpty(haTag) && haTag.equalsIgnoreCase(tag)) { - response.setHaHost(true); - } - } - } - return response; - } - @Override public List newHostView(Host host) { SearchCriteria sc = hostIdSearch.create(); diff --git a/server/src/main/java/com/cloud/api/query/dao/TemplateJoinDaoImpl.java b/server/src/main/java/com/cloud/api/query/dao/TemplateJoinDaoImpl.java index a9a971cb3417..8527ac0ece95 100644 --- a/server/src/main/java/com/cloud/api/query/dao/TemplateJoinDaoImpl.java +++ b/server/src/main/java/com/cloud/api/query/dao/TemplateJoinDaoImpl.java @@ -53,7 +53,6 @@ import com.cloud.hypervisor.Hypervisor.HypervisorType; import com.cloud.storage.Storage; import com.cloud.storage.Storage.TemplateType; -import com.cloud.storage.VMTemplateHostVO; import com.cloud.storage.VMTemplateStorageResourceAssoc.Status; import com.cloud.storage.VMTemplateVO; import com.cloud.storage.dao.VMTemplateDao; @@ -134,7 +133,7 @@ private String getTemplateStatus(TemplateJoinVO template) { String templateStatus = null; if (template.getDownloadState() != Status.DOWNLOADED) { templateStatus = "Processing"; - if (template.getDownloadState() == VMTemplateHostVO.Status.DOWNLOAD_IN_PROGRESS) { + if (template.getDownloadState() == Status.DOWNLOAD_IN_PROGRESS) { if (template.getDownloadPercent() == 100) { templateStatus = "Installing Template"; } else { @@ -147,7 +146,7 @@ private String getTemplateStatus(TemplateJoinVO template) { }else { templateStatus = template.getErrorString(); } - } else if (template.getDownloadState() == VMTemplateHostVO.Status.DOWNLOADED) { + } else if (template.getDownloadState() == Status.DOWNLOADED) { templateStatus = "Download Complete"; } else { templateStatus = "Successfully Installed"; @@ -403,9 +402,9 @@ public TemplateResponse newIsoResponse(TemplateJoinVO iso) { // add download status if (iso.getDownloadState() != Status.DOWNLOADED) { String isoStatus = "Processing"; - if (iso.getDownloadState() == VMTemplateHostVO.Status.DOWNLOADED) { + if (iso.getDownloadState() == Status.DOWNLOADED) { isoStatus = "Download Complete"; - } else if (iso.getDownloadState() == VMTemplateHostVO.Status.DOWNLOAD_IN_PROGRESS) { + } else if (iso.getDownloadState() == Status.DOWNLOAD_IN_PROGRESS) { if (iso.getDownloadPercent() == 100) { isoStatus = "Installing ISO"; } else { diff --git a/server/src/main/java/com/cloud/api/query/dao/VolumeJoinDaoImpl.java b/server/src/main/java/com/cloud/api/query/dao/VolumeJoinDaoImpl.java index 6cbc834c4088..6d46d0993181 100644 --- a/server/src/main/java/com/cloud/api/query/dao/VolumeJoinDaoImpl.java +++ b/server/src/main/java/com/cloud/api/query/dao/VolumeJoinDaoImpl.java @@ -34,7 +34,6 @@ import com.cloud.api.query.vo.VolumeJoinVO; import com.cloud.offering.ServiceOffering; import com.cloud.storage.Storage; -import com.cloud.storage.VMTemplateHostVO; import com.cloud.storage.VMTemplateStorageResourceAssoc.Status; import com.cloud.storage.Volume; import com.cloud.user.AccountManager; @@ -135,9 +134,6 @@ public VolumeResponse newVolumeResponse(ResponseView view, VolumeJoinVO volume) volResponse.setState(volume.getState().toString()); } if (volume.getState() == Volume.State.UploadOp) { - // com.cloud.storage.VolumeHostVO volumeHostRef = - // ApiDBUtils.findVolumeHostRef(volume.getId(), - // volume.getDataCenterId()); volResponse.setSize(volume.getVolumeStoreSize()); volResponse.setCreated(volume.getCreatedOnStore()); @@ -145,7 +141,7 @@ public VolumeResponse newVolumeResponse(ResponseView view, VolumeJoinVO volume) volResponse.setHypervisor(ApiDBUtils.getHypervisorTypeFromFormat(volume.getDataCenterId(), volume.getFormat()).toString()); if (volume.getDownloadState() != Status.DOWNLOADED) { String volumeStatus = "Processing"; - if (volume.getDownloadState() == VMTemplateHostVO.Status.DOWNLOAD_IN_PROGRESS) { + if (volume.getDownloadState() == Status.DOWNLOAD_IN_PROGRESS) { if (volume.getDownloadPercent() == 100) { volumeStatus = "Checking Volume"; } else { @@ -154,14 +150,14 @@ public VolumeResponse newVolumeResponse(ResponseView view, VolumeJoinVO volume) volResponse.setState("Uploading"); } else { volumeStatus = volume.getErrorString(); - if (volume.getDownloadState() == VMTemplateHostVO.Status.NOT_DOWNLOADED) { + if (volume.getDownloadState() == Status.NOT_DOWNLOADED) { volResponse.setState("UploadNotStarted"); } else { volResponse.setState("UploadError"); } } volResponse.setStatus(volumeStatus); - } else if (volume.getDownloadState() == VMTemplateHostVO.Status.DOWNLOADED) { + } else if (volume.getDownloadState() == Status.DOWNLOADED) { volResponse.setStatus("Upload Complete"); volResponse.setState("Uploaded"); } else { diff --git a/server/src/main/java/com/cloud/api/query/vo/AsyncJobJoinVO.java b/server/src/main/java/com/cloud/api/query/vo/AsyncJobJoinVO.java index be85c2a62bc1..82887d23aefa 100644 --- a/server/src/main/java/com/cloud/api/query/vo/AsyncJobJoinVO.java +++ b/server/src/main/java/com/cloud/api/query/vo/AsyncJobJoinVO.java @@ -31,7 +31,7 @@ import com.cloud.utils.db.GenericDao; @Entity -@Table(name="async_job_view") +@Table(name = "async_job_view") public class AsyncJobJoinVO extends BaseViewVO implements ControlledViewEntity { //InternalIdentity, Identity { @Id @Column(name = "id") diff --git a/server/src/main/java/com/cloud/api/query/vo/DomainJoinVO.java b/server/src/main/java/com/cloud/api/query/vo/DomainJoinVO.java index 84456e4ae87b..e17eacd68fac 100644 --- a/server/src/main/java/com/cloud/api/query/vo/DomainJoinVO.java +++ b/server/src/main/java/com/cloud/api/query/vo/DomainJoinVO.java @@ -31,7 +31,7 @@ import org.apache.cloudstack.api.InternalIdentity; @Entity -@Table(name="domain_view") +@Table(name = "domain_view") public class DomainJoinVO extends BaseViewVO implements InternalIdentity, Identity { @Id diff --git a/server/src/main/java/com/cloud/capacity/CapacityManagerImpl.java b/server/src/main/java/com/cloud/capacity/CapacityManagerImpl.java index a5c1f3b4927e..05ea9fd94ca2 100644 --- a/server/src/main/java/com/cloud/capacity/CapacityManagerImpl.java +++ b/server/src/main/java/com/cloud/capacity/CapacityManagerImpl.java @@ -926,8 +926,11 @@ public boolean postStateTransitionEvent(StateMachine2.Transition t State oldState = transition.getCurrentState(); State newState = transition.getToState(); Event event = transition.getEvent(); - s_logger.debug("VM state transitted from :" + oldState + " to " + newState + " with event: " + event + "vm's original host id: " + vm.getLastHostId() + - " new host id: " + vm.getHostId() + " host id before state transition: " + oldHostId); + Host lastHost = _hostDao.findById(vm.getLastHostId()); + Host oldHost = _hostDao.findById(oldHostId); + Host newHost = _hostDao.findById(vm.getHostId()); + s_logger.debug(String.format("%s state transited from [%s] to [%s] with event [%s]. VM's original host: %s, new host: %s, host before state transition: %s", vm, oldState, + newState, event, lastHost, newHost, oldHost)); if (oldState == State.Starting) { if (newState != State.Running) { diff --git a/server/src/main/java/com/cloud/configuration/ConfigurationManagerImpl.java b/server/src/main/java/com/cloud/configuration/ConfigurationManagerImpl.java index cb7e4b5185d6..f431945c6321 100755 --- a/server/src/main/java/com/cloud/configuration/ConfigurationManagerImpl.java +++ b/server/src/main/java/com/cloud/configuration/ConfigurationManagerImpl.java @@ -474,6 +474,9 @@ private void populateConfigValuesForValidationSet() { configValuesForValidation.add("externaldhcp.vmip.max.retry"); configValuesForValidation.add("externaldhcp.vmipFetch.threadPool.max"); configValuesForValidation.add("remote.access.vpn.psk.length"); + configValuesForValidation.add(StorageManager.STORAGE_POOL_DISK_WAIT.key()); + configValuesForValidation.add(StorageManager.STORAGE_POOL_CLIENT_TIMEOUT.key()); + configValuesForValidation.add(StorageManager.STORAGE_POOL_CLIENT_MAX_CONNECTIONS.key()); } private void weightBasedParametersForValidation() { diff --git a/server/src/main/java/com/cloud/deploy/DeploymentPlanningManagerImpl.java b/server/src/main/java/com/cloud/deploy/DeploymentPlanningManagerImpl.java index 7a939ae263e4..afcaacf01436 100644 --- a/server/src/main/java/com/cloud/deploy/DeploymentPlanningManagerImpl.java +++ b/server/src/main/java/com/cloud/deploy/DeploymentPlanningManagerImpl.java @@ -1411,7 +1411,7 @@ public int compare(Volume v1, Volume v2) { hostCanAccessPool = true; if (potentialHost.getHypervisorType() == HypervisorType.VMware) { try { - boolean isStoragePoolStoragepolicyComplaince = _storageMgr.isStoragePoolComplaintWithStoragePolicy(allVolumes, storagePool); + boolean isStoragePoolStoragepolicyComplaince = _storageMgr.isStoragePoolCompliantWithStoragePolicy(allVolumes, storagePool); if (!isStoragePoolStoragepolicyComplaince) { continue; } @@ -1450,7 +1450,7 @@ public int compare(Volume v1, Volume v2) { if (potentialHost.getHypervisorType() == HypervisorType.VMware) { try { - boolean isStoragePoolStoragepolicyComplaince = _storageMgr.isStoragePoolComplaintWithStoragePolicy(requestVolumes, potentialSPool); + boolean isStoragePoolStoragepolicyComplaince = _storageMgr.isStoragePoolCompliantWithStoragePolicy(requestVolumes, potentialSPool); if (!isStoragePoolStoragepolicyComplaince) { continue; } diff --git a/server/src/main/java/com/cloud/hypervisor/HypervisorGuruBase.java b/server/src/main/java/com/cloud/hypervisor/HypervisorGuruBase.java index 2a8b13e96ca1..5965e89773ad 100644 --- a/server/src/main/java/com/cloud/hypervisor/HypervisorGuruBase.java +++ b/server/src/main/java/com/cloud/hypervisor/HypervisorGuruBase.java @@ -179,9 +179,13 @@ protected VirtualMachineTO toVirtualMachineTO(VirtualMachineProfile vmProfile) { ServiceOffering offering = _serviceOfferingDao.findById(vmProfile.getId(), vmProfile.getServiceOfferingId()); VirtualMachine vm = vmProfile.getVirtualMachine(); HostVO host = hostDao.findById(vm.getHostId()); + boolean divideMemoryByOverprovisioning = true; + boolean divideCpuByOverprovisioning = true; - boolean divideMemoryByOverprovisioning = VmMinMemoryEqualsMemoryDividedByMemOverprovisioningFactor.valueIn(host.getClusterId()); - boolean divideCpuByOverprovisioning = VmMinCpuSpeedEqualsCpuSpeedDividedByCpuOverprovisioningFactor.valueIn(host.getClusterId()); + if (host != null) { + divideMemoryByOverprovisioning = VmMinMemoryEqualsMemoryDividedByMemOverprovisioningFactor.valueIn(host.getClusterId()); + divideCpuByOverprovisioning = VmMinCpuSpeedEqualsCpuSpeedDividedByCpuOverprovisioningFactor.valueIn(host.getClusterId()); + } Long minMemory = (long)(offering.getRamSize() / (divideMemoryByOverprovisioning ? vmProfile.getMemoryOvercommitRatio() : 1)); int minspeed = (int)(offering.getSpeed() / (divideCpuByOverprovisioning ? vmProfile.getCpuOvercommitRatio() : 1)); diff --git a/server/src/main/java/com/cloud/network/NetworkModelImpl.java b/server/src/main/java/com/cloud/network/NetworkModelImpl.java index 4322478d93e1..32643ca2a48f 100644 --- a/server/src/main/java/com/cloud/network/NetworkModelImpl.java +++ b/server/src/main/java/com/cloud/network/NetworkModelImpl.java @@ -30,6 +30,7 @@ import java.util.Map; import java.util.Set; import java.util.TreeSet; +import java.util.stream.Collectors; import javax.inject.Inject; import javax.naming.ConfigurationException; @@ -831,6 +832,15 @@ public List listNetworksUsedByVm(long vmId, boolean isSystem) { return networks; } + @Override + public List listNetworksUsedByVm(long vmId) { + return listNetworksUsedByVm(vmId, false). + stream(). + mapToLong(NetworkVO::getId). + boxed(). + collect(Collectors.toList()); + } + @Override public Nic getNicInNetwork(long vmId, long networkId) { return _nicDao.findByNtwkIdAndInstanceId(networkId, vmId); diff --git a/server/src/main/java/com/cloud/network/element/VirtualRouterElement.java b/server/src/main/java/com/cloud/network/element/VirtualRouterElement.java index 9191ddddb5b9..d101a5e4f607 100644 --- a/server/src/main/java/com/cloud/network/element/VirtualRouterElement.java +++ b/server/src/main/java/com/cloud/network/element/VirtualRouterElement.java @@ -411,12 +411,13 @@ public boolean stopVpn(final RemoteAccessVpn vpn) throws ResourceUnavailableExce if (canHandle(network, Service.Vpn)) { final List routers = _routerDao.listByNetworkAndRole(network.getId(), Role.VIRTUAL_ROUTER); if (routers == null || routers.isEmpty()) { - s_logger.debug("Virtual router elemnt doesn't need stop vpn on the backend; virtual router doesn't " + "exist in the network " + network.getId()); + s_logger.debug(String.format("There is no virtual router in network [uuid: %s, name: %s], it is not necessary to stop the VPN on backend.", + network.getUuid(), network.getName())); return true; } return _routerMgr.deleteRemoteAccessVpn(network, vpn, routers); } else { - s_logger.debug("Element " + getName() + " doesn't handle removeVpn command"); + s_logger.debug(String.format("Element %s doesn't handle removeVpn command", getName())); return false; } } diff --git a/server/src/main/java/com/cloud/network/rules/RulesManagerImpl.java b/server/src/main/java/com/cloud/network/rules/RulesManagerImpl.java index de567749043f..b743863edc71 100644 --- a/server/src/main/java/com/cloud/network/rules/RulesManagerImpl.java +++ b/server/src/main/java/com/cloud/network/rules/RulesManagerImpl.java @@ -630,20 +630,23 @@ private boolean enableStaticNat(long ipId, long vmId, long networkId, boolean is } protected void applyUserData(long vmId, Network network, Nic guestNic) throws ResourceUnavailableException { - UserVmVO vm = _vmDao.findById(vmId); - VMTemplateVO template = _templateDao.findByIdIncludingRemoved(vm.getTemplateId()); - NicProfile nicProfile = new NicProfile(guestNic, network, null, null, null, - _networkModel.isSecurityGroupSupportedInNetwork(network), - _networkModel.getNetworkTag(template.getHypervisorType(), network)); - VirtualMachineProfile vmProfile = new VirtualMachineProfileImpl(vm); UserDataServiceProvider element = _networkModel.getUserDataUpdateProvider(network); if (element == null) { s_logger.error("Can't find network element for " + Service.UserData.getName() + " provider needed for UserData update"); } else { - boolean result = element.saveUserData(network, nicProfile, vmProfile); - if (!result) { + UserVmVO vm = _vmDao.findById(vmId); + try { + VMTemplateVO template = _templateDao.findByIdIncludingRemoved(vm.getTemplateId()); + NicProfile nicProfile = new NicProfile(guestNic, network, null, null, null, + _networkModel.isSecurityGroupSupportedInNetwork(network), + _networkModel.getNetworkTag(template.getHypervisorType(), network)); + VirtualMachineProfile vmProfile = new VirtualMachineProfileImpl(vm); + if (!element.saveUserData(network, nicProfile, vmProfile)) { s_logger.error("Failed to update userdata for vm " + vm + " and nic " + guestNic); } + } catch (Exception e) { + s_logger.error("Failed to update userdata for vm " + vm + " and nic " + guestNic + " due to " + e.getMessage(), e); + } } } diff --git a/server/src/main/java/com/cloud/resource/ResourceManagerImpl.java b/server/src/main/java/com/cloud/resource/ResourceManagerImpl.java index ca3505fb6800..488be99e32da 100755 --- a/server/src/main/java/com/cloud/resource/ResourceManagerImpl.java +++ b/server/src/main/java/com/cloud/resource/ResourceManagerImpl.java @@ -909,6 +909,7 @@ public void doInTransactionWithoutResult(final TransactionStatus status) { host.setClusterId(null); _hostDao.update(host.getId(), host); + Host hostRemoved = _hostDao.findById(hostId); _hostDao.remove(hostId); if (clusterId != null) { final List hosts = listAllHostsInCluster(clusterId); @@ -922,7 +923,7 @@ public void doInTransactionWithoutResult(final TransactionStatus status) { try { resourceStateTransitTo(host, ResourceState.Event.DeleteHost, _nodeId); } catch (final NoTransitionException e) { - s_logger.debug("Cannot transmit host " + host.getId() + " to Enabled state", e); + s_logger.debug(String.format("Cannot transit %s to Enabled state", host), e); } // Delete the associated entries in host ref table @@ -947,7 +948,7 @@ public void doInTransactionWithoutResult(final TransactionStatus status) { storagePool.setClusterId(null); _storagePoolDao.update(poolId, storagePool); _storagePoolDao.remove(poolId); - s_logger.debug("Local storage id=" + poolId + " is removed as a part of host removal id=" + hostId); + s_logger.debug(String.format("Local storage [id: %s] is removed as a part of %s removal", poolId, hostRemoved.toString())); } } @@ -1278,7 +1279,7 @@ private boolean doMaintain(final long hostId) { try { resourceStateTransitTo(host, ResourceState.Event.AdminAskMaintenance, _nodeId); } catch (final NoTransitionException e) { - final String err = "Cannot transmit resource state of host " + host.getId() + " to " + ResourceState.Maintenance; + final String err = String.format("Cannot transit resource state of %s to %s", host, ResourceState.Maintenance); s_logger.debug(err, e); throw new CloudRuntimeException(err + e.getMessage()); } @@ -1530,7 +1531,7 @@ protected boolean setHostIntoPrepareForMaintenanceAfterErrorsFixed(HostVO host) protected boolean attemptMaintain(HostVO host) throws NoTransitionException { final long hostId = host.getId(); - s_logger.info("Attempting maintenance for host " + host.getName()); + s_logger.info(String.format("Attempting maintenance for %s", host)); // Step 0: First gather if VMs have pending HAWork for migration with retries left. final List allVmsOnHost = _vmDao.listByHostId(hostId); @@ -1538,7 +1539,7 @@ protected boolean attemptMaintain(HostVO host) throws NoTransitionException { boolean hasPendingMigrationRetries = false; for (VMInstanceVO vmInstanceVO : allVmsOnHost) { if (_haMgr.hasPendingMigrationsWork(vmInstanceVO.getId())) { - s_logger.info("Attempting maintenance for " + host + " found pending migration for VM " + vmInstanceVO); + s_logger.info(String.format("Attempting maintenance for %s found pending migration for %s.", host, vmInstanceVO)); hasPendingMigrationRetries = true; break; } @@ -1595,7 +1596,7 @@ public boolean checkAndMaintain(final long hostId) { hostInMaintenance = attemptMaintain(host); } } catch (final NoTransitionException e) { - s_logger.debug("Cannot transmit host " + host.getId() + " to Maintenance state", e); + s_logger.warn(String.format("Cannot transit %s from %s to Maintenance state.", host, host.getResourceState()), e); } return hostInMaintenance; } @@ -2062,12 +2063,12 @@ protected HostVO createHostVO(final StartupCommand[] cmds, final ServerResource /* Agent goes to Connecting status */ _agentMgr.agentStatusTransitTo(host, Status.Event.AgentConnected, _nodeId); } catch (final Exception e) { - s_logger.debug("Cannot transmit host " + host.getId() + " to Creating state", e); + s_logger.debug(String.format("Cannot transit %s to Creating state", host), e); _agentMgr.agentStatusTransitTo(host, Status.Event.Error, _nodeId); try { resourceStateTransitTo(host, ResourceState.Event.Error, _nodeId); } catch (final NoTransitionException e1) { - s_logger.debug("Cannot transmit host " + host.getId() + "to Error state", e); + s_logger.debug(String.format("Cannot transit %s to Error state", host), e); } } @@ -2202,7 +2203,7 @@ private Host createHostAndAgent(final ServerResource resource, final Map " + host.getUuid() + " / " + host.getId() + ". Please make sure you are still able to connect to your hosts."); + throw new CloudRuntimeException( + String.format("CloudStack failed to update the password of %s. Please make sure you are still able to connect to your hosts.", host)); } } } @@ -2797,8 +2799,7 @@ public boolean migrateAwayFailed(final long hostId, final long vmId) { ". Emitting event UnableToMigrate."); return resourceStateTransitTo(host, ResourceState.Event.UnableToMigrate, _nodeId); } catch (final NoTransitionException e) { - s_logger.debug("No next resource state for host " + host.getId() + " while current state is " + host.getResourceState() + " with event " + - ResourceState.Event.UnableToMigrate, e); + s_logger.debug(String.format("No next resource state for %s while current state is [%s] with event %s", host, host.getResourceState(), ResourceState.Event.UnableToMigrate), e); return false; } } @@ -3117,7 +3118,7 @@ public HashMap> getGPUStatistics(final Ho return null; } if (answer == null || !answer.getResult()) { - final String msg = "Unable to obtain GPU stats for host " + host.getName(); + final String msg = String.format("Unable to obtain GPU stats for %s", host); s_logger.warn(msg); return null; } else { diff --git a/server/src/main/java/com/cloud/resource/RollingMaintenanceManagerImpl.java b/server/src/main/java/com/cloud/resource/RollingMaintenanceManagerImpl.java index 0bc88276fad7..80a243156aa0 100644 --- a/server/src/main/java/com/cloud/resource/RollingMaintenanceManagerImpl.java +++ b/server/src/main/java/com/cloud/resource/RollingMaintenanceManagerImpl.java @@ -395,7 +395,7 @@ private Ternary performMaintenanceStageOnHost(Host hos * @throws AgentUnavailableException */ private void putHostIntoMaintenance(Host host) throws InterruptedException, AgentUnavailableException { - s_logger.debug("Trying to set the host " + host.getId() + " into maintenance"); + s_logger.debug(String.format("Trying to set %s into maintenance", host)); PrepareForMaintenanceCmd cmd = new PrepareForMaintenanceCmd(); cmd.setId(host.getId()); resourceManager.maintain(cmd); @@ -423,9 +423,9 @@ private void enableClusterIfDisabled(Cluster cluster, Set disabledClusters private Ternary reCheckCapacityBeforeMaintenanceOnHost(Cluster cluster, Host host, Boolean forced, List hostsSkipped) { Pair capacityCheckBeforeMaintenance = performCapacityChecksBeforeHostInMaintenance(host, cluster); if (!capacityCheckBeforeMaintenance.first()) { - String errorMsg = "Capacity check failed for host " + host.getUuid() + ": " + capacityCheckBeforeMaintenance.second(); + String errorMsg = String.format("Capacity check failed for %s: %s", host, capacityCheckBeforeMaintenance.second()); if (forced) { - s_logger.info("Skipping host " + host.getUuid() + " as: " + errorMsg); + s_logger.info(String.format("Skipping %s as: %s", host, errorMsg)); hostsSkipped.add(new HostSkipped(host, errorMsg)); return new Ternary<>(true, true, capacityCheckBeforeMaintenance.second()); } @@ -439,9 +439,9 @@ private Ternary reCheckCapacityBeforeMaintenanceOnHost */ private boolean isMaintenanceStageAvoided(Host host, Map hostsToAvoidMaintenance, List hostsSkipped) { if (hostsToAvoidMaintenance.containsKey(host.getId())) { - s_logger.debug("Host " + host.getId() + " is not being put into maintenance, skipping it"); HostSkipped hostSkipped = new HostSkipped(host, hostsToAvoidMaintenance.get(host.getId())); hostsSkipped.add(hostSkipped); + s_logger.debug(String.format("%s is in avoid maintenance list [hosts skipped: %d], skipping its maintenance.", host, hostsSkipped.size())); return true; } return false; @@ -468,7 +468,7 @@ private Ternary performPreMaintenanceStageOnHost(Host return new Ternary<>(true, false, result.second()); } if (result.third() && !hostsToAvoidMaintenance.containsKey(host.getId())) { - s_logger.debug("Host " + host.getId() + " added to the avoid maintenance set"); + logHostAddedToAvoidMaintenanceSet(host); hostsToAvoidMaintenance.put(host.getId(), "Pre-maintenance stage set to avoid maintenance"); } return new Ternary<>(false, false, result.second()); @@ -491,7 +491,7 @@ private boolean isMaintenanceScriptDefinedOnHost(Host host, List ho RollingMaintenanceAnswer answer = (RollingMaintenanceAnswer) agentManager.send(host.getId(), new RollingMaintenanceCommand(true)); return answer.isMaintenaceScriptDefined(); } catch (AgentUnavailableException | OperationTimedoutException e) { - String msg = "Could not check for maintenance script on host " + host.getId() + " due to: " + e.getMessage(); + String msg = String.format("Could not check for maintenance script on %s due to: %s", host, e.getMessage()); s_logger.error(msg, e); return false; } @@ -537,8 +537,8 @@ private Ternary sendRollingMaintenanceCommandToHost(Ho answer = agentManager.send(host.getId(), cmd); } catch (AgentUnavailableException | OperationTimedoutException e) { // Agent may be restarted on the scripts - continue polling until it is up - String msg = "Cannot send command to host: " + host.getId() + ", waiting " + pingInterval + "ms - " + e.getMessage(); - s_logger.warn(msg); + String msg = String.format("Cannot send command to %s, waiting %sms - %s", host, pingInterval, e.getMessage()); + s_logger.warn(msg, e); cmd.setStarted(true); Thread.sleep(pingInterval); timeSpent += pingInterval; @@ -571,12 +571,16 @@ private void performPreFlightChecks(List hosts, int timeout, String payloa for (Host host : hosts) { Ternary result = performStageOnHost(host, Stage.PreFlight, timeout, payload, forced); if (result.third() && !hostsToAvoidMaintenance.containsKey(host.getId())) { - s_logger.debug("Host " + host.getId() + " added to the avoid maintenance set"); + logHostAddedToAvoidMaintenanceSet(host); hostsToAvoidMaintenance.put(host.getId(), "Pre-flight stage set to avoid maintenance"); } } } + private void logHostAddedToAvoidMaintenanceSet(Host host) { + s_logger.debug(String.format("%s added to the avoid maintenance set.", host)); + } + /** * Capacity checks on hosts */ @@ -584,7 +588,7 @@ private void performCapacityChecks(Cluster cluster, List hosts, Boolean fo for (Host host : hosts) { Pair result = performCapacityChecksBeforeHostInMaintenance(host, cluster); if (!result.first() && !forced) { - throw new CloudRuntimeException("Capacity check failed for host " + host.getUuid() + ": " + result.second()); + throw new CloudRuntimeException(String.format("Capacity check failed for %s : %s", host, result.second())); } } } @@ -616,8 +620,7 @@ private Pair performCapacityChecksBeforeHostInMaintenance(Host ServiceOfferingVO serviceOffering = serviceOfferingDao.findById(runningVM.getServiceOfferingId()); for (Host hostInCluster : hostsInCluster) { if (!checkHostTags(hostTags, hostTagsDao.gethostTags(hostInCluster.getId()), serviceOffering.getHostTag())) { - s_logger.debug("Host tags mismatch between host " + host.getUuid() + " and host " + hostInCluster.getUuid() + - ". Skipping it from the capacity check"); + s_logger.debug(String.format("Host tags mismatch between %s and %s Skipping it from the capacity check", host, hostInCluster)); continue; } DeployDestination deployDestination = new DeployDestination(null, null, null, host); @@ -627,8 +630,7 @@ private Pair performCapacityChecksBeforeHostInMaintenance(Host affinityChecks = affinityChecks && affinityProcessor.check(vmProfile, deployDestination); } if (!affinityChecks) { - s_logger.debug("Affinity check failed between host " + host.getUuid() + " and host " + hostInCluster.getUuid() + - ". Skipping it from the capacity check"); + s_logger.debug(String.format("Affinity check failed between %s and %s Skipping it from the capacity check", host, hostInCluster)); continue; } boolean maxGuestLimit = capacityManager.checkIfHostReachMaxGuestLimit(host); @@ -647,15 +649,15 @@ private Pair performCapacityChecksBeforeHostInMaintenance(Host } } if (!canMigrateVm) { - String msg = "VM " + runningVM.getUuid() + " cannot be migrated away from host " + host.getUuid() + - " to any other host in the cluster"; + String msg = String.format("%s cannot be migrated away from %s to any other host in the cluster", runningVM, host); s_logger.error(msg); return new Pair<>(false, msg); } sucessfullyCheckedVmMigrations++; } if (sucessfullyCheckedVmMigrations != vmsRunning.size()) { - return new Pair<>(false, "Host " + host.getId() + " cannot enter maintenance mode as capacity check failed for hosts in cluster " + cluster.getUuid()); + String migrationCheckDetails = String.format("%s cannot enter maintenance mode as capacity check failed for hosts in cluster %s", host, cluster); + return new Pair<>(false, migrationCheckDetails); } return new Pair<>(true, "OK"); } @@ -735,4 +737,4 @@ public String getConfigComponentName() { public ConfigKey[] getConfigKeys() { return new ConfigKey[] {KvmRollingMaintenanceStageTimeout, KvmRollingMaintenancePingInterval, KvmRollingMaintenanceWaitForMaintenanceTimeout}; } -} \ No newline at end of file +} diff --git a/server/src/main/java/com/cloud/server/ManagementServerImpl.java b/server/src/main/java/com/cloud/server/ManagementServerImpl.java index 0e217a473028..5ac1aef6c1ab 100644 --- a/server/src/main/java/com/cloud/server/ManagementServerImpl.java +++ b/server/src/main/java/com/cloud/server/ManagementServerImpl.java @@ -1292,7 +1292,7 @@ public Ternary, Integer>, List, Map, Integer>, List, Map discoverers) { _discoverers = discoverers; } - protected SearchBuilder HostTemplateStatesSearch; protected GenericSearchBuilder UpHostsInPoolSearch; protected SearchBuilder StoragePoolSearch; protected SearchBuilder LocalStorageSearch; @@ -1817,7 +1816,7 @@ public void syncDatastoreClusterStoragePool(long datastoreClusterPoolId, List volumes, StoragePool pool) throws StorageUnavailableException { - if (volumes == null || volumes.isEmpty()) { + public boolean isStoragePoolCompliantWithStoragePolicy(List volumes, StoragePool pool) throws StorageUnavailableException { + if (CollectionUtils.isEmpty(volumes)) { return false; } List> answers = new ArrayList>(); @@ -3130,6 +3129,7 @@ public ConfigKey[] getConfigKeys() { MaxNumberOfManagedClusteredFileSystems, STORAGE_POOL_DISK_WAIT, STORAGE_POOL_CLIENT_TIMEOUT, + STORAGE_POOL_CLIENT_MAX_CONNECTIONS, PRIMARY_STORAGE_DOWNLOAD_WAIT, SecStorageMaxMigrateSessions, MaxDataMigrationWaitTime diff --git a/server/src/main/java/com/cloud/storage/VolumeApiServiceImpl.java b/server/src/main/java/com/cloud/storage/VolumeApiServiceImpl.java index a2b2a4978c0d..684404a84805 100644 --- a/server/src/main/java/com/cloud/storage/VolumeApiServiceImpl.java +++ b/server/src/main/java/com/cloud/storage/VolumeApiServiceImpl.java @@ -23,14 +23,19 @@ import java.util.Collections; import java.util.Date; import java.util.HashMap; +import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Optional; +import java.util.Set; import java.util.UUID; import java.util.concurrent.ExecutionException; import javax.inject.Inject; +import org.apache.cloudstack.api.command.user.vm.CloneVMCmd; +import com.cloud.api.query.dao.ServiceOfferingJoinDao; +import com.cloud.api.query.vo.ServiceOfferingJoinVO; import org.apache.cloudstack.api.command.user.volume.AttachVolumeCmd; import org.apache.cloudstack.api.command.user.volume.CreateVolumeCmd; import org.apache.cloudstack.api.command.user.volume.DetachVolumeCmd; @@ -227,6 +232,8 @@ public class VolumeApiServiceImpl extends ManagerBase implements VolumeApiServic @Inject private ServiceOfferingDetailsDao _serviceOfferingDetailsDao; @Inject + private ServiceOfferingJoinDao serviceOfferingJoinDao; + @Inject private UserVmDao _userVmDao; @Inject private UserVmDetailsDao userVmDetailsDao; @@ -302,6 +309,8 @@ public class VolumeApiServiceImpl extends ManagerBase implements VolumeApiServic private long _maxVolumeSizeInGb; private final StateMachine2 _volStateMachine; + private static final Set STATES_VOLUME_CANNOT_BE_DESTROYED = new HashSet<>(Arrays.asList(Volume.State.Destroy, Volume.State.Expunging, Volume.State.Expunged, Volume.State.Allocated)); + protected VolumeApiServiceImpl() { _volStateMachine = Volume.State.getStateMachine(); _gson = GsonHelper.getGsonLogger(); @@ -900,6 +909,12 @@ public VolumeVO createVolume(CreateVolumeCmd cmd) { } } + @Override + public Volume cloneDataVolume(CloneVMCmd cmd, long snapshotId, Volume volume) throws StorageUnavailableException { + long vmId = cmd.getEntityId(); + return createVolumeFromSnapshot((VolumeVO) volume, snapshotId, vmId); + } + protected VolumeVO createVolumeFromSnapshot(VolumeVO volume, long snapshotId, Long vmId) throws StorageUnavailableException { VolumeInfo createdVolume = null; SnapshotVO snapshot = _snapshotDao.findById(snapshotId); @@ -966,20 +981,7 @@ public VolumeVO resizeVolume(ResizeVolumeCmd cmd) throws ResourceAllocationExcep } // if we are to use the existing disk offering - ImageFormat format = null; if (newDiskOffering == null) { - Long templateId = volume.getTemplateId(); - if (templateId != null) { - VMTemplateVO template = _templateDao.findById(templateId); - format = template.getFormat(); - } - - if (volume.getVolumeType().equals(Volume.Type.ROOT) && diskOffering.getDiskSize() > 0 && format != null && format != ImageFormat.ISO) { - throw new InvalidParameterValueException( - "Failed to resize Root volume. The service offering of this Volume has been configured with a root disk size; " - + "on such case a Root Volume can only be resized when changing to another Service Offering with a Root disk size. " - + "For more details please check out the Official Resizing Volumes documentation."); - } newSize = cmd.getSize(); newHypervisorSnapshotReserve = volume.getHypervisorSnapshotReserve(); @@ -990,6 +992,13 @@ public VolumeVO resizeVolume(ResizeVolumeCmd cmd) throws ResourceAllocationExcep + "customizable or it must be a root volume (if providing a disk offering, make sure it is different from the current disk offering)."); } + if (isNotPossibleToResize(volume, diskOffering)) { + throw new InvalidParameterValueException( + "Failed to resize Root volume. The service offering of this Volume has been configured with a root disk size; " + + "on such case a Root Volume can only be resized when changing to another Service Offering with a Root disk size. " + + "For more details please check out the Official Resizing Volumes documentation."); + } + // convert from bytes to GiB newSize = newSize << 30; } else { @@ -1213,6 +1222,27 @@ public VolumeVO resizeVolume(ResizeVolumeCmd cmd) throws ResourceAllocationExcep shrinkOk); } + /** + * A volume should not be resized if it covers ALL the following scenarios:
+ * 1 - Root volume
+ * 2 - && Current Disk Offering enforces a root disk size (in this case one can resize only by changing the Service Offering) + */ + protected boolean isNotPossibleToResize(VolumeVO volume, DiskOfferingVO diskOffering) { + Long templateId = volume.getTemplateId(); + ImageFormat format = null; + if (templateId != null) { + VMTemplateVO template = _templateDao.findByIdIncludingRemoved(templateId); + format = template.getFormat(); + } + boolean isNotIso = format != null && format != ImageFormat.ISO; + boolean isRoot = Volume.Type.ROOT.equals(volume.getVolumeType()); + + ServiceOfferingJoinVO serviceOfferingView = serviceOfferingJoinDao.findById(diskOffering.getId()); + boolean isOfferingEnforcingRootDiskSize = serviceOfferingView != null && serviceOfferingView.getRootDiskSize() > 0; + + return isOfferingEnforcingRootDiskSize && isRoot && isNotIso; + } + private void checkIfVolumeIsRootAndVmIsRunning(Long newSize, VolumeVO volume, VMInstanceVO vmInstanceVO) { if (!volume.getSize().equals(newSize) && volume.getVolumeType().equals(Volume.Type.ROOT) && !State.Stopped.equals(vmInstanceVO.getState())) { throw new InvalidParameterValueException(String.format("Cannot resize ROOT volume [%s] when VM is not on Stopped State. VM %s is in state %s", volume.getName(), vmInstanceVO @@ -1432,13 +1462,14 @@ protected VolumeVO retrieveAndValidateVolume(long volumeId, Account caller) { *
    *
  • {@value Volume.State#Destroy}; *
  • {@value Volume.State#Expunging}; - *
  • {@value Volume.State#Expunged}. + *
  • {@value Volume.State#Expunged}; + *
  • {@value Volume.State#Allocated}. *
* * The volume is destroyed via {@link VolumeService#destroyVolume(long)} method. */ protected void destroyVolumeIfPossible(VolumeVO volume) { - if (volume.getState() != Volume.State.Destroy && volume.getState() != Volume.State.Expunging && volume.getState() != Volume.State.Expunged && volume.getState() != Volume.State.Allocated && volume.getState() != Volume.State.Uploaded) { + if (!STATES_VOLUME_CANNOT_BE_DESTROYED.contains(volume.getState())) { volService.destroyVolume(volume.getId()); } } @@ -1485,6 +1516,13 @@ protected void cleanVolumesCache(VolumeVO volume) { } } + private void removeVolume(long volumeId) { + final VolumeVO volume = _volsDao.findById(volumeId); + if (volume != null) { + _volsDao.remove(volumeId); + } + } + protected boolean stateTransitTo(Volume vol, Volume.Event event) throws NoTransitionException { return _volStateMachine.transitTo(vol, event, null, _volsDao); } @@ -1526,6 +1564,7 @@ public Volume destroyVolume(long volumeId, Account caller, boolean expunge, bool } } + removeVolume(volume.getId()); return volume; } @@ -1621,6 +1660,9 @@ private Volume orchestrateAttachVolumeToVM(Long vmId, Long volumeId, Long device if (destPrimaryStorage != null && (volumeToAttach.getState() == Volume.State.Allocated || volumeOnSecondary)) { try { + if (volumeOnSecondary && destPrimaryStorage.getPoolType() == Storage.StoragePoolType.PowerFlex) { + throw new InvalidParameterValueException("Cannot attach uploaded volume, this operation is unsupported on storage pool type " + destPrimaryStorage.getPoolType()); + } newVolumeOnPrimaryStorage = _volumeMgr.createVolumeOnPrimaryStorage(vm, volumeToAttach, rootDiskHyperType, destPrimaryStorage); } catch (NoTransitionException e) { s_logger.debug("Failed to create volume on primary storage", e); @@ -1663,6 +1705,11 @@ private Volume orchestrateAttachVolumeToVM(Long vmId, Long volumeId, Long device return newVol; } + @Override + public Volume attachVolumeToVm(CloneVMCmd cmd, Long volumeId, Long deviceId) { + return attachVolumeToVM(cmd.getEntityId(), volumeId, deviceId); + } + public Volume attachVolumeToVM(Long vmId, Long volumeId, Long deviceId) { Account caller = CallContext.current().getCallingAccount(); @@ -2406,7 +2453,7 @@ public Volume migrateVolume(MigrateVolumeCmd cmd) { HypervisorType hypervisorType = _volsDao.getHypervisorType(volumeId); if (hypervisorType.equals(HypervisorType.VMware)) { try { - boolean isStoragePoolStoragepolicyComplaince = storageMgr.isStoragePoolComplaintWithStoragePolicy(Arrays.asList(vol), destPool); + boolean isStoragePoolStoragepolicyComplaince = storageMgr.isStoragePoolCompliantWithStoragePolicy(Arrays.asList(vol), destPool); if (!isStoragePoolStoragepolicyComplaince) { throw new CloudRuntimeException(String.format("Storage pool %s is not storage policy compliance with the volume %s", poolUuid, vol.getUuid())); } diff --git a/server/src/main/java/com/cloud/storage/download/DownloadListener.java b/server/src/main/java/com/cloud/storage/download/DownloadListener.java index 25dffb3e8afa..9f528195bfa3 100644 --- a/server/src/main/java/com/cloud/storage/download/DownloadListener.java +++ b/server/src/main/java/com/cloud/storage/download/DownloadListener.java @@ -55,7 +55,6 @@ import com.cloud.host.Host; import com.cloud.hypervisor.Hypervisor.HypervisorType; import com.cloud.resource.ResourceManager; -import com.cloud.storage.VMTemplateHostVO; import com.cloud.storage.VMTemplateStorageResourceAssoc.Status; import com.cloud.storage.download.DownloadState.DownloadEvent; import com.cloud.storage.upload.UploadListener; @@ -157,7 +156,7 @@ public AsyncCompletionCallback getCallback() { return _callback; } - public void setCurrState(VMTemplateHostVO.Status currState) { + public void setCurrState(Status currState) { _currState = getState(currState.toString()); } diff --git a/server/src/main/java/com/cloud/template/TemplateManagerImpl.java b/server/src/main/java/com/cloud/template/TemplateManagerImpl.java index 698e23119d2a..55399b34ddd2 100755 --- a/server/src/main/java/com/cloud/template/TemplateManagerImpl.java +++ b/server/src/main/java/com/cloud/template/TemplateManagerImpl.java @@ -33,6 +33,26 @@ import javax.inject.Inject; import javax.naming.ConfigurationException; +import com.cloud.storage.DataStoreRole; +import com.cloud.storage.GuestOSVO; +import com.cloud.storage.ImageStoreUploadMonitorImpl; +import com.cloud.storage.LaunchPermissionVO; +import com.cloud.storage.Snapshot; +import com.cloud.storage.SnapshotVO; +import com.cloud.storage.Storage; +import com.cloud.storage.StorageManager; +import com.cloud.storage.StoragePool; +import com.cloud.storage.StoragePoolHostVO; +import com.cloud.storage.StoragePoolStatus; +import com.cloud.storage.TemplateProfile; +import com.cloud.storage.Upload; +import com.cloud.storage.VMTemplateStoragePoolVO; +import com.cloud.storage.VMTemplateStorageResourceAssoc; +import com.cloud.storage.VMTemplateVO; +import com.cloud.storage.VMTemplateZoneVO; +import com.cloud.storage.Volume; +import com.cloud.storage.VolumeApiService; +import com.cloud.storage.VolumeVO; import org.apache.cloudstack.acl.SecurityChecker.AccessType; import org.apache.cloudstack.api.ApiConstants; import org.apache.cloudstack.api.BaseListTemplateOrIsoPermissionsCmd; @@ -143,29 +163,9 @@ import com.cloud.hypervisor.Hypervisor.HypervisorType; import com.cloud.projects.Project; import com.cloud.projects.ProjectManager; -import com.cloud.storage.DataStoreRole; -import com.cloud.storage.GuestOSVO; -import com.cloud.storage.ImageStoreUploadMonitorImpl; -import com.cloud.storage.LaunchPermissionVO; -import com.cloud.storage.Snapshot; -import com.cloud.storage.SnapshotVO; -import com.cloud.storage.Storage; import com.cloud.storage.Storage.ImageFormat; import com.cloud.storage.Storage.TemplateType; -import com.cloud.storage.StorageManager; -import com.cloud.storage.StoragePool; -import com.cloud.storage.StoragePoolHostVO; -import com.cloud.storage.StoragePoolStatus; -import com.cloud.storage.TemplateProfile; -import com.cloud.storage.Upload; -import com.cloud.storage.VMTemplateHostVO; -import com.cloud.storage.VMTemplateStoragePoolVO; -import com.cloud.storage.VMTemplateStorageResourceAssoc; import com.cloud.storage.VMTemplateStorageResourceAssoc.Status; -import com.cloud.storage.VMTemplateVO; -import com.cloud.storage.VMTemplateZoneVO; -import com.cloud.storage.Volume; -import com.cloud.storage.VolumeVO; import com.cloud.storage.dao.GuestOSDao; import com.cloud.storage.dao.LaunchPermissionDao; import com.cloud.storage.dao.SnapshotDao; @@ -1095,44 +1095,6 @@ public boolean configure(String name, Map params) throws Configu protected TemplateManagerImpl() { } - @Override - public boolean templateIsDeleteable(VMTemplateHostVO templateHostRef) { - VMTemplateVO template = _tmpltDao.findByIdIncludingRemoved(templateHostRef.getTemplateId()); - long templateId = template.getId(); - HostVO secondaryStorageHost = _hostDao.findById(templateHostRef.getHostId()); - long zoneId = secondaryStorageHost.getDataCenterId(); - DataCenterVO zone = _dcDao.findById(zoneId); - - // Check if there are VMs running in the template host ref's zone that - // use the template - List nonExpungedVms = _vmInstanceDao.listNonExpungedByZoneAndTemplate(zoneId, templateId); - - if (!nonExpungedVms.isEmpty()) { - s_logger.debug("Template " + template.getName() + " in zone " + zone.getName() + - " is not deleteable because there are non-expunged VMs deployed from this template."); - return false; - } - List userVmUsingIso = _userVmDao.listByIsoId(templateId); - // check if there is any VM using this ISO. - if (!userVmUsingIso.isEmpty()) { - s_logger.debug("ISO " + template.getName() + " in zone " + zone.getName() + " is not deleteable because it is attached to " + userVmUsingIso.size() + " VMs"); - return false; - } - // Check if there are any snapshots for the template in the template - // host ref's zone - List volumes = _volumeDao.findByTemplateAndZone(templateId, zoneId); - for (VolumeVO volume : volumes) { - List snapshots = _snapshotDao.listByVolumeIdVersion(volume.getId(), "2.1"); - if (!snapshots.isEmpty()) { - s_logger.debug("Template " + template.getName() + " in zone " + zone.getName() + - " is not deleteable because there are 2.1 snapshots using this template."); - return false; - } - } - - return true; - } - @Override public boolean templateIsDeleteable(long templateId) { List userVmUsingIso = _userVmJoinDao.listActiveByIsoId(templateId); @@ -1784,14 +1746,258 @@ public void doInTransactionWithoutResult(TransactionStatus status) { @Override @DB + @ActionEvent(eventType = EventTypes.EVENT_TEMPLATE_CREATE, eventDescription = "creating actual private template", create = true) + public VirtualMachineTemplate createPrivateTemplate(CloneVMCmd cmd) throws CloudRuntimeException { + UserVm curVm = cmd.getTargetVM(); + long templateId = cmd.getTemporaryTemlateId(); + long snapshotId = cmd.getTemporarySnapShotId(); + final Long accountId = curVm.getAccountId(); + Account caller = CallContext.current().getCallingAccount(); + List volumes = _volumeDao.findByInstanceAndType(cmd.getId(), Volume.Type.ROOT); + VolumeVO targetVolume = volumes.get(0); + long volumeId = targetVolume.getId(); + VMTemplateVO finalTmpProduct = null; + SnapshotVO snapshot = null; + try { + TemplateInfo cloneTempalateInfp = _tmplFactory.getTemplate(templateId, DataStoreRole.Image); + long zoneId = curVm.getDataCenterId(); + AsyncCallFuture future = null; + VolumeInfo vInfo = _volFactory.getVolume(volumeId); + DataStore store = _dataStoreMgr.getImageStoreWithFreeCapacity(zoneId); + snapshot = _snapshotDao.findById(snapshotId); +// future = _tmpltSvr.createTemplateFromVolumeAsync(vInfo, cloneTempalateInfp, store); + // create template from snapshot + DataStoreRole dataStoreRole = ApiResponseHelper.getDataStoreRole(snapshot, _snapshotStoreDao, _dataStoreMgr); + SnapshotInfo snapInfo = _snapshotFactory.getSnapshot(snapshotId, dataStoreRole); + if (dataStoreRole == DataStoreRole.Image) { + if (snapInfo == null) { + snapInfo = _snapshotFactory.getSnapshot(snapshotId, DataStoreRole.Primary); + if(snapInfo == null) { + throw new CloudRuntimeException("Cannot find snapshot "+snapshotId); + } + // We need to copy the snapshot onto secondary. + SnapshotStrategy snapshotStrategy = _storageStrategyFactory.getSnapshotStrategy(snapshot, SnapshotOperation.BACKUP); + snapshotStrategy.backupSnapshot(snapInfo); + + // Attempt to grab it again. + snapInfo = _snapshotFactory.getSnapshot(snapshotId, dataStoreRole); + if(snapInfo == null) { + throw new CloudRuntimeException("Cannot find snapshot " + snapshotId + " on secondary and could not create backup"); + } + } + _accountMgr.checkAccess(caller, null, true, snapInfo); + DataStore snapStore = snapInfo.getDataStore(); + + if (snapStore != null) { + store = snapStore; // pick snapshot image store to create template + } + } + future = _tmpltSvr.createTemplateFromSnapshotAsync(snapInfo, cloneTempalateInfp, store); + // wait for the result to converge + CommandResult result = null; + try { + result = future.get(); + + if (result.isFailed()) { + finalTmpProduct = null; + s_logger.warn("Failed to create template: " + result.getResult()); + throw new CloudRuntimeException("Failed to create template: " + result.getResult()); + } + if (_dataStoreMgr.isRegionStore(store)) { + _tmpltSvr.associateTemplateToZone(templateId, null); + } else { + // Already done in the record to db step + VMTemplateZoneVO templateZone = new VMTemplateZoneVO(zoneId, templateId, new Date()); + _tmpltZoneDao.persist(templateZone); + } + s_logger.info("successfully created the template with Id: " + templateId); + finalTmpProduct = _tmpltDao.findById(templateId); + TemplateDataStoreVO srcTmpltStore = _tmplStoreDao.findByStoreTemplate(store.getId(), templateId); + UsageEventVO usageEvent = + new UsageEventVO(EventTypes.EVENT_TEMPLATE_CREATE, finalTmpProduct.getAccountId(), zoneId, finalTmpProduct.getId(), finalTmpProduct.getName(), null, + finalTmpProduct.getSourceTemplateId(), srcTmpltStore.getPhysicalSize(), finalTmpProduct.getSize()); + _usageEventDao.persist(usageEvent); + } catch (InterruptedException e) { + s_logger.debug("Failed to create template for id: " + templateId, e); + throw new CloudRuntimeException("Failed to create template" , e); + } catch (ExecutionException e) { + s_logger.debug("Failed to create template for id: " + templateId, e); + throw new CloudRuntimeException("Failed to create template ", e); + } + + } finally { + finalTmpProduct = _tmpltDao.findById(templateId); + if (finalTmpProduct == null) { + final VolumeVO volumeFinal = targetVolume; + final SnapshotVO snapshotFinal = snapshot; + Transaction.execute(new TransactionCallbackNoReturn() { + @Override + public void doInTransactionWithoutResult(TransactionStatus status) { + // template_store_ref entries should have been removed using our + // DataObject.processEvent command in case of failure, but clean + // it up here to avoid + // some leftovers which will cause removing template from + // vm_template table fail. + _tmplStoreDao.deletePrimaryRecordsForTemplate(templateId); + // Remove the template_zone_ref record + _tmpltZoneDao.deletePrimaryRecordsForTemplate(templateId); + // Remove the template record + _tmpltDao.expunge(templateId); + + // decrement resource count + if (accountId != null) { + _resourceLimitMgr.decrementResourceCount(accountId, ResourceType.template); + _resourceLimitMgr.decrementResourceCount(accountId, ResourceType.secondary_storage, new Long(volumeFinal != null ? volumeFinal.getSize() + : snapshotFinal.getSize())); + } + } + }); + + } + } + return null; + } + + @Override @ActionEvent(eventType = EventTypes.EVENT_TEMPLATE_CREATE, eventDescription = "creating template from clone", create = true) - public VMTemplateVO createPrivateTemplateRecord(CloneVMCmd cmd, Account templateOwner) throws ResourceAllocationException { + public VMTemplateVO createPrivateTemplateRecord(CloneVMCmd cmd, Account templateOwner, VolumeApiService volumeService) throws ResourceAllocationException { Account caller = CallContext.current().getCallingAccount(); - boolean isAdmin = (_accountMgr.isAdmin(caller.getId())); _accountMgr.checkAccess(caller, null, true, templateOwner); String name = cmd.getTemplateName(); - return null; + if (name.length() > 32) { + name = name.substring(5) + "-QA-Clone"; + } + + boolean featured = false; + boolean isPublic = cmd.isPublic(); + UserVm curVm = cmd.getTargetVM(); + long zoneId = curVm.getDataCenterId(); + Long volumeId = _volumeDao.findByInstanceAndType(cmd.getId(), Volume.Type.ROOT).get(0).getId(); + HypervisorType hyperType = null; + VolumeVO volume = _volumeDao.findById(volumeId); + if (volume == null) { + throw new InvalidParameterValueException("Failed to create private template record, unable to find root volume " + volumeId); + } + + // check permissions + _accountMgr.checkAccess(caller, null, true, volume); + + // If private template is created from Volume, check that the volume + // will not be active when the private template is + // created +// if (!_volumeMgr.volumeInactive(volume)) { +// String msg = "Unable to create private template for volume: " + volume.getName() + "; volume is attached to a non-stopped VM, please stop the VM first"; +// if (s_logger.isInfoEnabled()) { +// s_logger.info(msg); +// } +// throw new CloudRuntimeException(msg); +// } + + hyperType = _volumeDao.getHypervisorType(volumeId); + if (HypervisorType.LXC.equals(hyperType)) { + throw new InvalidParameterValueException("Template creation is not supported for LXC volume: " + volumeId); + } + + _resourceLimitMgr.checkResourceLimit(templateOwner, ResourceType.template); + _resourceLimitMgr.checkResourceLimit(templateOwner, ResourceType.secondary_storage, volume.getSize()); + + Long guestOSId = cmd.getTargetVM().getGuestOSId(); + GuestOSVO guestOS = _guestOSDao.findById(guestOSId); + if (guestOS == null) { + throw new InvalidParameterValueException("GuestOS with ID: " + guestOSId + " does not exist."); + } + + // get snapshot from this step + + + Long nextTemplateId = _tmpltDao.getNextInSequence(Long.class, "id"); + s_logger.info("Creating snapshot for the tempalte creation"); + SnapshotVO snapshot = (SnapshotVO) volumeService.allocSnapshot(volumeId, Snapshot.MANUAL_POLICY_ID, curVm.getDisplayName() + "-Clone-" + nextTemplateId, null); + if (snapshot == null) { + throw new CloudRuntimeException("Unable to create a snapshot during the template creation recording"); + } + Snapshot snapshotEntity = volumeService.takeSnapshot(volumeId, Snapshot.MANUAL_POLICY_ID, snapshot.getId(), caller, false, null, false, new HashMap<>()); + if (snapshotEntity == null) { + throw new CloudRuntimeException("Error when creating the snapshot entity"); + } + if (snapshotEntity.getState() != Snapshot.State.BackedUp) { + throw new CloudRuntimeException("Async backup of snapshot happens during the clone for snapshot id: " + snapshot.getId()); + } + cmd.setTemporarySnapShotId(snapshot.getId()); + String description = ""; // TODO: add this to clone parameter in the future + boolean isExtractable = false; + Long sourceTemplateId = null; + if (volume != null) { + VMTemplateVO template = ApiDBUtils.findTemplateById(volume.getTemplateId()); + isExtractable = template != null && template.isExtractable() && template.getTemplateType() != Storage.TemplateType.SYSTEM; + if (volume.getIsoId() != null && volume.getIsoId() != 0) { + sourceTemplateId = volume.getIsoId(); + } else if (volume.getTemplateId() != null) { + sourceTemplateId = volume.getTemplateId(); + } + } + + VMTemplateVO privateTemplate = null; + privateTemplate = new VMTemplateVO(nextTemplateId, name, ImageFormat.RAW, isPublic, featured, isExtractable, + TemplateType.USER, null, true, 64, templateOwner.getId(), null, description, + false, guestOS.getId(), true, hyperType, null, new HashMap<>(){{put("template to be cleared", "yes");}}, false, false, false, false); + List stores = _imgStoreDao.findRegionImageStores(); + if (!CollectionUtils.isEmpty(stores)) { + privateTemplate.setCrossZones(true); + } + + privateTemplate.setSourceTemplateId(sourceTemplateId); + VMTemplateVO template = _tmpltDao.persist(privateTemplate); + // persist this to the template zone area and remember to remove the resource count in the execute phase once in failure or clean up phase +// VMTemplateZoneVO templateZone = new VMTemplateZoneVO(zoneId, template.getId(), new Date()); +// _tmpltZoneDao.persist(templateZone); +// TemplateDataStoreVO voRecord = _tmplStoreDao.createTemplateDirectDownloadEntry(template.getId(), template.getSize()); +// voRecord.setDataStoreId(2); +// _tmplStoreDao.persist(voRecord); + // Increment the number of templates + if (template != null) { + Map details = new HashMap(); + + if (sourceTemplateId != null) { + VMTemplateVO sourceTemplate = _tmpltDao.findById(sourceTemplateId); + if (sourceTemplate != null && sourceTemplate.getDetails() != null) { + details.putAll(sourceTemplate.getDetails()); + } + } + + if (volume != null) { + Long vmId = volume.getInstanceId(); + if (vmId != null) { + UserVmVO userVm = _userVmDao.findById(vmId); + if (userVm != null) { + _userVmDao.loadDetails(userVm); + Map vmDetails = userVm.getDetails(); + vmDetails = vmDetails.entrySet() + .stream() + .filter(map -> map.getValue() != null) + .collect(Collectors.toMap(map -> map.getKey(), map -> map.getValue())); + details.putAll(vmDetails); + } + } + } + + if (!details.isEmpty()) { + privateTemplate.setDetails(details); + _tmpltDao.saveDetails(privateTemplate); + } + + _resourceLimitMgr.incrementResourceCount(templateOwner.getId(), ResourceType.template); + _resourceLimitMgr.incrementResourceCount(templateOwner.getId(), ResourceType.secondary_storage, + snapshot.getSize()); + } + + if (template != null) { + return template; + } else { + throw new CloudRuntimeException("Failed to create a template"); + } } + @Override @ActionEvent(eventType = EventTypes.EVENT_TEMPLATE_CREATE, eventDescription = "creating template", create = true) public VMTemplateVO createPrivateTemplateRecord(CreateTemplateCmd cmd, Account templateOwner) throws ResourceAllocationException { diff --git a/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java b/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java index 4fb7b83f93ad..d04c85c52ad6 100644 --- a/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java +++ b/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java @@ -50,7 +50,53 @@ import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.ParserConfigurationException; - +//import com.cloud.network.IpAddress; +//import com.cloud.network.IpAddress; +import com.cloud.network.IpAddressManager; +import com.cloud.network.Network; +import com.cloud.network.NetworkModel; +import com.cloud.network.PhysicalNetwork; +import com.cloud.network.security.SecurityGroupVO; +import com.cloud.storage.DataStoreRole; +import com.cloud.storage.DiskOfferingVO; +import com.cloud.storage.GuestOSCategoryVO; +import com.cloud.storage.GuestOSVO; +import com.cloud.storage.ScopeType; +import com.cloud.storage.Snapshot; +import com.cloud.storage.SnapshotVO; +import com.cloud.storage.Storage; +import com.cloud.storage.StorageManager; +import com.cloud.storage.StoragePool; +import com.cloud.storage.StoragePoolStatus; +import com.cloud.storage.VMTemplateStorageResourceAssoc; +import com.cloud.storage.VMTemplateVO; +import com.cloud.storage.VMTemplateZoneVO; +import com.cloud.storage.Volume; +import com.cloud.storage.VolumeApiService; +import com.cloud.storage.VolumeVO; +import com.cloud.storage.snapshot.SnapshotApiService; +import com.cloud.user.Account; +import com.cloud.user.AccountManager; +import com.cloud.user.AccountService; +import com.cloud.user.AccountVO; +import com.cloud.user.ResourceLimitService; +import com.cloud.user.SSHKeyPair; +import com.cloud.user.SSHKeyPairVO; +import com.cloud.user.User; +import com.cloud.user.UserStatisticsVO; +import com.cloud.user.UserVO; +import com.cloud.user.VmDiskStatisticsVO; +import com.cloud.utils.db.DB; +import com.cloud.utils.db.EntityManager; +import com.cloud.utils.db.GlobalLock; +import com.cloud.utils.db.SearchCriteria; +import com.cloud.utils.db.Transaction; +import com.cloud.utils.db.TransactionCallback; +import com.cloud.utils.db.TransactionCallbackNoReturn; +import com.cloud.utils.db.TransactionCallbackWithException; +import com.cloud.utils.db.TransactionCallbackWithExceptionNoReturn; +import com.cloud.utils.db.TransactionStatus; +import com.cloud.utils.db.UUIDManager; import org.apache.cloudstack.acl.ControlledEntity; import org.apache.cloudstack.acl.ControlledEntity.ACLType; import org.apache.cloudstack.acl.SecurityChecker.AccessType; @@ -83,7 +129,6 @@ import org.apache.cloudstack.api.command.user.vmgroup.CreateVMGroupCmd; import org.apache.cloudstack.api.command.user.vmgroup.DeleteVMGroupCmd; import org.apache.cloudstack.api.command.user.volume.ResizeVolumeCmd; -import com.cloud.agent.api.to.deployasis.OVFNetworkTO; import org.apache.cloudstack.backup.Backup; import org.apache.cloudstack.backup.BackupManager; import org.apache.cloudstack.backup.dao.BackupDao; @@ -147,6 +192,7 @@ import com.cloud.agent.api.to.DiskTO; import com.cloud.agent.api.to.NicTO; import com.cloud.agent.api.to.VirtualMachineTO; +import com.cloud.agent.api.to.deployasis.OVFNetworkTO; import com.cloud.agent.api.to.deployasis.OVFPropertyTO; import com.cloud.agent.manager.Commands; import com.cloud.alert.AlertManager; @@ -215,14 +261,10 @@ import com.cloud.hypervisor.Hypervisor.HypervisorType; import com.cloud.hypervisor.dao.HypervisorCapabilitiesDao; import com.cloud.hypervisor.kvm.dpdk.DpdkHelper; -import com.cloud.network.IpAddressManager; -import com.cloud.network.Network; import com.cloud.network.Network.IpAddresses; import com.cloud.network.Network.Provider; import com.cloud.network.Network.Service; -import com.cloud.network.NetworkModel; import com.cloud.network.Networks.TrafficType; -import com.cloud.network.PhysicalNetwork; import com.cloud.network.dao.FirewallRulesDao; import com.cloud.network.dao.IPAddressDao; import com.cloud.network.dao.IPAddressVO; @@ -260,26 +302,9 @@ import com.cloud.service.ServiceOfferingVO; import com.cloud.service.dao.ServiceOfferingDao; import com.cloud.service.dao.ServiceOfferingDetailsDao; -import com.cloud.storage.DataStoreRole; -import com.cloud.storage.DiskOfferingVO; -import com.cloud.storage.GuestOSCategoryVO; -import com.cloud.storage.GuestOSVO; -import com.cloud.storage.ScopeType; -import com.cloud.storage.Snapshot; -import com.cloud.storage.SnapshotVO; -import com.cloud.storage.Storage; import com.cloud.storage.Storage.ImageFormat; import com.cloud.storage.Storage.StoragePoolType; import com.cloud.storage.Storage.TemplateType; -import com.cloud.storage.StorageManager; -import com.cloud.storage.StoragePool; -import com.cloud.storage.StoragePoolStatus; -import com.cloud.storage.VMTemplateStorageResourceAssoc; -import com.cloud.storage.VMTemplateVO; -import com.cloud.storage.VMTemplateZoneVO; -import com.cloud.storage.Volume; -import com.cloud.storage.VolumeApiService; -import com.cloud.storage.VolumeVO; import com.cloud.storage.dao.DiskOfferingDao; import com.cloud.storage.dao.GuestOSCategoryDao; import com.cloud.storage.dao.GuestOSDao; @@ -292,16 +317,6 @@ import com.cloud.template.TemplateApiService; import com.cloud.template.TemplateManager; import com.cloud.template.VirtualMachineTemplate; -import com.cloud.user.Account; -import com.cloud.user.AccountManager; -import com.cloud.user.AccountService; -import com.cloud.user.ResourceLimitService; -import com.cloud.user.SSHKeyPair; -import com.cloud.user.SSHKeyPairVO; -import com.cloud.user.User; -import com.cloud.user.UserStatisticsVO; -import com.cloud.user.UserVO; -import com.cloud.user.VmDiskStatisticsVO; import com.cloud.user.dao.AccountDao; import com.cloud.user.dao.SSHKeyPairDao; import com.cloud.user.dao.UserDao; @@ -316,16 +331,6 @@ import com.cloud.utils.concurrency.NamedThreadFactory; import com.cloud.utils.crypt.DBEncryptionUtil; import com.cloud.utils.crypt.RSAHelper; -import com.cloud.utils.db.DB; -import com.cloud.utils.db.EntityManager; -import com.cloud.utils.db.GlobalLock; -import com.cloud.utils.db.SearchCriteria; -import com.cloud.utils.db.Transaction; -import com.cloud.utils.db.TransactionCallbackNoReturn; -import com.cloud.utils.db.TransactionCallbackWithException; -import com.cloud.utils.db.TransactionCallbackWithExceptionNoReturn; -import com.cloud.utils.db.TransactionStatus; -import com.cloud.utils.db.UUIDManager; import com.cloud.utils.exception.CloudRuntimeException; import com.cloud.utils.exception.ExecutionException; import com.cloud.utils.fsm.NoTransitionException; @@ -584,6 +589,13 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir private static final ConfigKey VmDestroyForcestop = new ConfigKey("Advanced", Boolean.class, "vm.destroy.forcestop", "false", "On destroy, force-stop takes this value ", true); + public static final List VM_STORAGE_MIGRATION_SUPPORTING_HYPERVISORS = new ArrayList<>(Arrays.asList( + HypervisorType.KVM, + HypervisorType.VMware, + HypervisorType.XenServer, + HypervisorType.Simulator + )); + @Override public UserVmVO getVirtualMachine(long vmId) { return _vmDao.findById(vmId); @@ -864,22 +876,28 @@ public UserVm resetVMSSHKey(ResetVMSSHKeyCmd cmd) throws ResourceUnavailableExce } _accountMgr.checkAccess(caller, null, true, userVm); - String password = null; + String sshPublicKey = s.getPublicKey(); - if (template != null && template.isEnablePassword()) { - password = _mgr.generateRandomPassword(); - } - boolean result = resetVMSSHKeyInternal(vmId, sshPublicKey, password); + boolean result = resetVMSSHKeyInternal(vmId, sshPublicKey); if (!result) { throw new CloudRuntimeException("Failed to reset SSH Key for the virtual machine "); } - userVm.setPassword(password); + + removeEncryptedPasswordFromUserVmVoDetails(userVm); + return userVm; } - private boolean resetVMSSHKeyInternal(Long vmId, String sshPublicKey, String password) throws ResourceUnavailableException, InsufficientCapacityException { + protected void removeEncryptedPasswordFromUserVmVoDetails(UserVmVO userVmVo) { + Map details = userVmVo.getDetails(); + details.remove(VmDetailConstants.ENCRYPTED_PASSWORD); + userVmVo.setDetails(details); + _vmDao.saveDetails(userVmVo); + } + + private boolean resetVMSSHKeyInternal(Long vmId, String sshPublicKey) throws ResourceUnavailableException, InsufficientCapacityException { Long userId = CallContext.current().getCallingUserId(); VMInstanceVO vmInstance = _vmDao.findById(vmId); @@ -896,10 +914,6 @@ private boolean resetVMSSHKeyInternal(Long vmId, String sshPublicKey, String pas VirtualMachineProfile vmProfile = new VirtualMachineProfileImpl(vmInstance); - if (template.isEnablePassword()) { - vmProfile.setParameter(VirtualMachineProfile.Param.VmPassword, password); - } - UserDataServiceProvider element = _networkMgr.getSSHKeyResetProvider(defaultNetwork); if (element == null) { throw new CloudRuntimeException("Can't find network element for " + Service.UserData.getName() + " provider needed for SSH Key reset"); @@ -914,11 +928,6 @@ private boolean resetVMSSHKeyInternal(Long vmId, String sshPublicKey, String pas final UserVmVO userVm = _vmDao.findById(vmId); _vmDao.loadDetails(userVm); userVm.setDetail(VmDetailConstants.SSH_PUBLIC_KEY, sshPublicKey); - if (template.isEnablePassword()) { - userVm.setPassword(password); - //update the encrypted password in vm_details table too - encryptAndStorePassword(userVm, password); - } _vmDao.saveDetails(userVm); if (vmInstance.getState() == State.Stopped) { @@ -1338,12 +1347,8 @@ public UserVm addNicToVirtualMachine(AddNicToVMCmd cmd) throws InvalidParameterV throw new InvalidParameterValueException("unable to find a network with id " + networkId); } - if (caller.getType() != Account.ACCOUNT_TYPE_ADMIN) { - if (!(network.getGuestType() == Network.GuestType.Shared && network.getAclType() == ACLType.Domain) - && !(network.getAclType() == ACLType.Account && network.getAccountId() == vmInstance.getAccountId())) { - throw new InvalidParameterValueException("only shared network or isolated network with the same account_id can be added to vmId: " + vmId); - } - } + Account vmOwner = _accountMgr.getAccount(vmInstance.getAccountId()); + _networkModel.checkNetworkPermissions(vmOwner, network); List allNics = _nicDao.listByVmId(vmInstance.getId()); for (NicVO nic : allNics) { @@ -1756,7 +1761,7 @@ public UserVm updateNicIpForVirtualMachine(UpdateVmNicIpCmd cmd) { throw new InvalidParameterValueException("Allocating ip to guest nic " + nicVO.getUuid() + " failed, please choose another ip"); } - final IPAddressVO newIp = _ipAddressDao.findByIpAndDcId(dc.getId(), ipaddr); + final IPAddressVO newIp = _ipAddressDao.findByIpAndSourceNetworkId(network.getId(), ipaddr); final Vlan vlan = _vlanDao.findById(newIp.getVlanId()); nicVO.setIPv4Gateway(vlan.getVlanGateway()); nicVO.setIPv4Netmask(vlan.getVlanNetmask()); @@ -3016,7 +3021,7 @@ public UserVm destroyVm(DestroyVMCmd cmd) throws ResourceUnavailableException, C throw new InvalidParameterValueException("unable to find a virtual machine with id " + vmId); } - if (vm.getState() == State.Destroyed || vm.getState() == State.Expunging) { + if ((vm.getState() == State.Destroyed && !expunge) || vm.getState() == State.Expunging) { s_logger.debug("Vm id=" + vmId + " is already destroyed"); return vm; } @@ -4502,24 +4507,218 @@ protected String validateUserData(String userData, HTTPMethod httpmethod) { } @Override - public void checkCloneCondition(CloneVMCmd cmd) throws ResourceUnavailableException, CloudRuntimeException, ConcurrentOperationException { + public void checkCloneCondition(CloneVMCmd cmd) throws InvalidParameterValueException, ResourceUnavailableException, CloudRuntimeException, ResourceAllocationException { + + if (cmd.getAccountName() != null && cmd.getDomainId() == null) { + throw new InvalidParameterValueException("You must input the domainId together with the account name"); + } + + final DomainVO domain = cmd.getDomainId() == null ? null : _domainDao.findById(cmd.getDomainId()); + final Account account = cmd.getAccountName() == null ? null : _accountService.getActiveAccountByName(cmd.getAccountName(), cmd.getDomainId()); + if (domain != null && account != null) { + if (account.getType() == Account.ACCOUNT_TYPE_PROJECT) { + throw new InvalidParameterValueException("Invalid user type: project to clone the VM"); + } + if (account.getState() != Account.State.enabled) { + throw new InvalidParameterValueException("User is not enabled to clone this VM"); + } + } UserVm curVm = cmd.getTargetVM(); if (curVm == null) { throw new CloudRuntimeException("the VM doesn't exist or not registered in management server!"); } UserVmVO vmStatus = _vmDao.findById(cmd.getId()); - if (vmStatus.state != State.Shutdown) { - throw new CloudRuntimeException("You should clone an instance that's shutdown!"); - } - List volumeInformation = _volsDao.findByInstanceAndType(cmd.getId(), Volume.Type.ROOT); - if (CollectionUtils.isEmpty(volumeInformation)) { +// if (vmStatus.state != State.Shutdown && vmStatus.state != State.Stopped) { +// throw new CloudRuntimeException("You should clone an instance that's shutdown!"); +// } + if (vmStatus.getHypervisorType() != HypervisorType.KVM && vmStatus.getHypervisorType() != HypervisorType.Simulator) { + throw new CloudRuntimeException("The clone operation is only supported on KVM and Simulator!"); + } + String kvmEnabled = _configDao.getValue("kvm.snapshot.enabled"); + if (kvmEnabled == null || !kvmEnabled.equalsIgnoreCase("true")) { + throw new CloudRuntimeException("Clone VM is not supported, as snapshots are disabled"); + } + Long accountId = curVm.getAccountId(); + Account vmOwner = _accountDao.findById(accountId); + if (vmOwner == null) { + throw new CloudRuntimeException("This VM doesn't have an owner account, please assign one to it"); + } + List volumes = _volsDao.findByInstanceAndType(cmd.getId(), Volume.Type.ROOT); + if (CollectionUtils.isEmpty(volumes)) { throw new CloudRuntimeException("The VM to copy does not have a Volume attached!"); } + // verify that the VM doesn't expire + Map details = curVm.getDetails(); + verifyDetails(details); +// Account activeOwner = _accountDao.findById(cmd.getEntityOwnerId()); + long zoneId = curVm.getDataCenterId(); + DataCenter zone = _entityMgr.findById(DataCenter.class, zoneId); + if (zone == null) { + throw new InvalidParameterValueException("Unable to find a zone in the current VM by zone id=" + zoneId); + } + // service offering check + long serviceOfferingId = curVm.getServiceOfferingId(); + ServiceOffering serviceOffering = _entityMgr.findById(ServiceOffering.class, serviceOfferingId); + if (serviceOffering == null) { + throw new InvalidParameterValueException("Service offering Id for this VM: " + serviceOfferingId + " doesn't exist now"); + } + if (!serviceOffering.isDynamic() && details != null) { + for(String detail: details.keySet()) { + if(detail.equalsIgnoreCase(VmDetailConstants.CPU_NUMBER) || detail.equalsIgnoreCase(VmDetailConstants.CPU_SPEED) || detail.equalsIgnoreCase(VmDetailConstants.MEMORY)) { + throw new InvalidParameterValueException("cpuNumber or cpuSpeed or memory should not be specified for static service offering"); + } + } + } + // disk offering check + VolumeVO rootDisk = volumes.get(0); + Long diskOfferingID = rootDisk.getDiskOfferingId(); + DiskOfferingVO diskOffering =null; + if (diskOfferingID != null) { + diskOffering = _diskOfferingDao.findById(diskOfferingID); + if (diskOffering == null) { + throw new CloudRuntimeException("Unable to find disk offering " + diskOfferingID); + } + } + if (!zone.isLocalStorageEnabled()) { + if (serviceOffering.isUseLocalStorage()) { + throw new CloudRuntimeException("Zone is not configured to use local storage now but this service offering " + serviceOffering.getName() + " uses it"); + } + if (diskOffering != null && diskOffering.isUseLocalStorage()) { + throw new CloudRuntimeException("Zone is not configured to use local storage but disk offering " + diskOffering.getName() + " uses it"); + } + } + // resource limit checks & account check + AccountVO activeOwner = _accountDao.findById(cmd.getEntityOwnerId()); + List totalVolumes = _volsDao.findByInstance(cmd.getId()); + _resourceLimitMgr.checkResourceLimit(activeOwner, ResourceType.volume, totalVolumes.size()); + Long totalSize = 0L; + for (VolumeVO volumeToCheck : totalVolumes) { + totalSize += volumeToCheck.getSize(); + } + _resourceLimitMgr.checkResourceLimit(activeOwner, ResourceType.primary_storage, totalSize); + } + + private VolumeVO saveDataDiskVolumeFromSnapShot(final Account owner, final Boolean displayVolume, final Long zoneId, final Long diskOfferingId, + final Storage.ProvisioningType provisioningType, final Long size, final Long minIops, final Long maxIops, final VolumeVO parentVolume, final String volumeName, final String uuid, final Map details) { + return Transaction.execute((TransactionCallback) status -> { + VolumeVO volume = new VolumeVO(volumeName, -1, -1, -1, -1, new Long(-1), null, null, provisioningType, 0, Volume.Type.DATADISK); + volume.setPoolId(null); + volume.setUuid(uuid); + volume.setDataCenterId(zoneId); + volume.setPodId(null); + volume.setAccountId(owner.getId()); + volume.setDomainId(owner.getDomainId()); + volume.setDiskOfferingId(diskOfferingId); + volume.setSize(size); + volume.setMinIops(minIops); + volume.setMaxIops(maxIops); + volume.setInstanceId(null); + volume.setUpdated(new Date()); + volume.setDisplayVolume(displayVolume); + if (parentVolume != null) { + volume.setTemplateId(parentVolume.getTemplateId()); + volume.setFormat(parentVolume.getFormat()); + } else { + volume.setTemplateId(null); + } + + volume = _volsDao.persist(volume); + CallContext.current().setEventDetails("Volume Id: " + volume.getUuid()); + + // Increment resource count during allocation; if actual creation fails, + // decrement it + _resourceLimitMgr.incrementResourceCount(volume.getAccountId(), ResourceType.volume, displayVolume); + _resourceLimitMgr.incrementResourceCount(volume.getAccountId(), ResourceType.primary_storage, displayVolume, new Long(volume.getSize())); + return volume; + }); } + @Override @ActionEvent(eventType = EventTypes.EVENT_VM_CLONE, eventDescription = "clone vm", async = true) - public Optional cloneVirtualMachine(CloneVMCmd cmd) throws ResourceUnavailableException, ConcurrentOperationException, CloudRuntimeException { - return Optional.ofNullable(null); + public Optional cloneVirtualMachine(CloneVMCmd cmd, VolumeApiService volumeService, SnapshotApiService snapshotService) throws ResourceUnavailableException, ConcurrentOperationException, CloudRuntimeException, InsufficientCapacityException, ResourceAllocationException { + long vmId = cmd.getEntityId(); + UserVmVO curVm = _vmDao.findById(vmId); + // create and attach data disk + long targetClonedVmId = cmd.getId(); + Account caller = CallContext.current().getCallingAccount(); + List dataDisks = _volsDao.findByInstanceAndType(targetClonedVmId, Volume.Type.DATADISK); + List createdSnapshots = new ArrayList<>(); + List createdVolumes = new ArrayList<>(); + long zoneId = cmd.getTargetVM().getDataCenterId(); + s_logger.info("Trying to attach data disk before starting the VM..."); + if (dataDisks.size() > 0) { + VolumeVO newDatadisk = null; + try { + for (VolumeVO dataDisk : dataDisks) { + long diskId = dataDisk.getId(); + SnapshotVO dataSnapShot = (SnapshotVO) volumeService.allocSnapshot(diskId, Snapshot.MANUAL_POLICY_ID, "DataDisk-Clone" + dataDisk.getName(), null); + if (dataSnapShot == null) { + throw new CloudRuntimeException("Unable to allocate snapshot of data disk: " + dataDisk.getId() + " name: " + dataDisk.getName()); + } + createdSnapshots.add(dataSnapShot); + SnapshotVO snapshotEntity = (SnapshotVO) volumeService.takeSnapshot(diskId, Snapshot.MANUAL_POLICY_ID, dataSnapShot.getId(), caller, false, null, false, new HashMap<>()); + if (snapshotEntity == null) { + throw new CloudRuntimeException("Error when creating the snapshot entity"); + } + if (snapshotEntity.getState() != Snapshot.State.BackedUp) { + throw new CloudRuntimeException("Async backup of snapshot happens during the clone for snapshot id: " + dataSnapShot.getId()); + } + long diskOfferingId = snapshotEntity.getDiskOfferingId(); + DiskOfferingVO diskOffering = _diskOfferingDao.findById(diskOfferingId); + Long minIops = snapshotEntity.getMinIops(); + Long maxIops = snapshotEntity.getMaxIops(); + Long size = snapshotEntity.getSize(); + Storage.ProvisioningType provisioningType = diskOffering.getProvisioningType(); + DataCenterVO dataCenter = _dcDao.findById(zoneId); + String volumeName = snapshotEntity.getName() + "-DataDisk-Volume"; + VolumeVO parentVolume = _volsDao.findByIdIncludingRemoved(snapshotEntity.getVolumeId()); + newDatadisk = saveDataDiskVolumeFromSnapShot(caller, true, zoneId, + diskOfferingId, provisioningType, size, minIops, maxIops, parentVolume, volumeName, _uuidMgr.generateUuid(Volume.class, null), new HashMap<>()); + VolumeVO volumeEntity = (VolumeVO) volumeService.cloneDataVolume(cmd, snapshotEntity.getId(), newDatadisk); + createdVolumes.add(volumeEntity); + } + } catch (CloudRuntimeException e){ + s_logger.warn("data disk process failed during clone, clearing the temporary resources..."); + for (VolumeVO dataDiskToClear : createdVolumes) { + volumeService.destroyVolume(dataDiskToClear.getId(), caller, true, false); + } + // clear the created disks + if (newDatadisk != null) { + volumeService.destroyVolume(newDatadisk.getId(), caller, true, false); + } + throw new CloudRuntimeException(e.getMessage()); + } finally { + // clear the temporary data snapshots + for (Snapshot snapshotLeftOver : createdSnapshots) { + snapshotService.deleteSnapshot(snapshotLeftOver.getId()); + } + } + } + + for (VolumeVO createdVol : createdVolumes) { + try { + volumeService.attachVolumeToVm(cmd, createdVol.getId(), createdVol.getDeviceId()); + } catch (CloudRuntimeException e) { + s_logger.warn("data disk: " + createdVol.getId() + " attachment to VM " + vmId + " failed due to" + e.getMessage()); + s_logger.info("Clearing the data disk: " + createdVol.getId()); + volumeService.destroyVolume(createdVol.getId(), caller, true, true); + } + } + + // start the VM if successfull + Long podId = curVm.getPodIdToDeployIn(); + Long clusterId = null; + Long hostId = curVm.getHostId(); + Map additonalParams = new HashMap<>(); + Map diskOfferingMap = new HashMap<>(); + if (MapUtils.isNotEmpty(curVm.getDetails()) && curVm.getDetails().containsKey(ApiConstants.BootType.UEFI.toString())) { + Map map = curVm.getDetails(); + additonalParams.put(VirtualMachineProfile.Param.UefiFlag, "Yes"); + additonalParams.put(VirtualMachineProfile.Param.BootType, ApiConstants.BootType.UEFI.toString()); + additonalParams.put(VirtualMachineProfile.Param.BootMode, map.get(ApiConstants.BootType.UEFI.toString())); + } + + return Optional.of(startVirtualMachine(vmId, podId, clusterId, hostId, diskOfferingMap, additonalParams, null)); } @Override @@ -5281,7 +5480,7 @@ public void doInTransactionWithoutResult(TransactionStatus status) { } }); } catch (Exception e) { - s_logger.warn("Unable to update vm disk statistics for vm: " + userVm.getId() + " from host: " + hostId, e); + s_logger.warn(String.format("Unable to update VM disk statistics for %s from %s", userVm.getInstanceName(), host), e); } } } @@ -5507,6 +5706,79 @@ public UserVm createVirtualMachine(DeployVMCmd cmd) throws InsufficientCapacityE return vm; } + @Override + public UserVm recordVirtualMachineToDB(CloneVMCmd cmd) throws ConcurrentOperationException, ResourceAllocationException, InsufficientCapacityException, ResourceUnavailableException { + //network configurations and check, then create the template + UserVm curVm = cmd.getTargetVM(); + // check if host is available + Long hostId = curVm.getHostId(); + getDestinationHost(hostId, true); + Long zoneId = curVm.getDataCenterId(); + DataCenter dataCenter = _entityMgr.findById(DataCenter.class, zoneId); + Map vmProperties = curVm.getDetails() != null ? curVm.getDetails() : new HashMap<>(); + String keyboard = vmProperties.get(VmDetailConstants.KEYBOARD); + HypervisorType hypervisorType = curVm.getHypervisorType(); + Account curAccount = _accountDao.findById(curVm.getAccountId()); + long callingUserId = CallContext.current().getCallingUserId(); + Account callerAccount = CallContext.current().getCallingAccount(); +// IpAddress ipAddress = _ipAddrMgr.assignPublicIpAddress(zoneId, curVm.getPodIdToDeployIn(), callerAccount, VlanType.DirectAttached, ) +// IpAddress ipAddress = _ipAddrMgr.allocateIp(curAccount, false, callerAccount, callingUserId, dataCenter, true, null); + String ipv6Address = null; + String macAddress = null; + IpAddresses addr = new IpAddresses(null, ipv6Address, macAddress); +// IpAddresses addr = new IpAddresses("172.20.0.98", ipv6Address, macAddress); + long serviceOfferingId = curVm.getServiceOfferingId(); + ServiceOffering serviceOffering = _serviceOfferingDao.findById(curVm.getId(), serviceOfferingId); + List securityGroupList = _securityGroupMgr.getSecurityGroupsForVm(curVm.getId()); + List securityGroupIdList = securityGroupList.stream().map(SecurityGroupVO::getId).collect(Collectors.toList()); + String uuidName = _uuidMgr.generateUuid(UserVm.class, null); + String hostName = generateHostName(uuidName); + String displayName = hostName + "-Clone"; + Long diskOfferingId = curVm.getDiskOfferingId(); + Long size = null; // mutual exclusive with disk offering id + HTTPMethod httpMethod = cmd.getHttpMethod(); + String userData = curVm.getUserData(); + String sshKeyPair = null; + Map ipToNetoworkMap = null; // Since we've specified Ip + boolean isDisplayVM = curVm.isDisplayVm(); + boolean dynamicScalingEnabled = curVm.isDynamicallyScalable(); + Long templateId = cmd.getTemporaryTemlateId(); + VirtualMachineTemplate template = _entityMgr.findById(VirtualMachineTemplate.class, templateId); + if (template == null) { + throw new CloudRuntimeException("the temporary template is not created, server error, contact your sys admin"); + } + List networkIds = _networkModel.listNetworksUsedByVm(curVm.getId()); + String group = null; + InstanceGroupVO groupVo = getGroupForVm(cmd.getId()); + if (groupVo != null) { + group = groupVo.getName(); + } + UserVm vmResult = null; + List affinityGroupIdList = _affinityGroupDao.findByAccountAndNames(curAccount.getId(), curAccount.getAccountName()) + .stream(). + mapToLong(AffinityGroupVO::getId). + boxed(). + collect(Collectors.toList()); + if (dataCenter.getNetworkType() == NetworkType.Basic) { + vmResult = createBasicSecurityGroupVirtualMachine(dataCenter, serviceOffering, template, securityGroupIdList, curAccount, hostName, displayName, diskOfferingId, + size, group, hypervisorType, cmd.getHttpMethod(), userData, sshKeyPair, ipToNetoworkMap, addr, isDisplayVM, keyboard, affinityGroupIdList, + curVm.getDetails() == null ? new HashMap<>() : curVm.getDetails(), cmd.getCustomId(), new HashMap<>(), + null, new HashMap<>(), dynamicScalingEnabled); + } else { + if (dataCenter.isSecurityGroupEnabled()) { + vmResult = createAdvancedSecurityGroupVirtualMachine(dataCenter, serviceOffering, template, networkIds, securityGroupIdList, curAccount, hostName, + displayName, diskOfferingId, size, group, hypervisorType, cmd.getHttpMethod(), userData, sshKeyPair, ipToNetoworkMap, addr, isDisplayVM, keyboard, + affinityGroupIdList, curVm.getDetails() == null ? new HashMap<>() : curVm.getDetails(), cmd.getCustomId(), new HashMap<>(), + null, new HashMap<>(), dynamicScalingEnabled); + } else { + vmResult = createAdvancedVirtualMachine(dataCenter, serviceOffering, template, networkIds, curAccount, hostName, displayName, diskOfferingId, size, group, + hypervisorType, cmd.getHttpMethod(), userData, sshKeyPair, ipToNetoworkMap, addr, isDisplayVM, keyboard, affinityGroupIdList, curVm.getDetails() == null ? new HashMap<>() : curVm.getDetails(), + cmd.getCustomId(), new HashMap<>(), null, new HashMap<>(), dynamicScalingEnabled); + } + } + return vmResult; + } + /** * Persist extra configuration data in the user_vm_details table as key/value pair * @param decodedUrl String consisting of the extra config data to appended onto the vmx file for VMware instances @@ -6292,56 +6564,18 @@ private boolean isVmVolumesOnZoneWideStore(VMInstanceVO vm) { return true; } - @Override - @ActionEvent(eventType = EventTypes.EVENT_VM_MIGRATE, eventDescription = "migrating VM", async = true) - public VirtualMachine migrateVirtualMachineWithVolume(Long vmId, Host destinationHost, Map volumeToPool) throws ResourceUnavailableException, - ConcurrentOperationException, ManagementServerException, VirtualMachineMigrationException { - // Access check - only root administrator can migrate VM. - Account caller = CallContext.current().getCallingAccount(); - if (!_accountMgr.isRootAdmin(caller.getId())) { - if (s_logger.isDebugEnabled()) { - s_logger.debug("Caller is not a root admin, permission denied to migrate the VM"); - } - throw new PermissionDeniedException("No permission to migrate VM, Only Root Admin can migrate a VM!"); - } - - VMInstanceVO vm = _vmInstanceDao.findById(vmId); - if (vm == null) { - throw new InvalidParameterValueException("Unable to find the vm by id " + vmId); - } - - // OfflineVmwareMigration: this would be it ;) if multiple paths exist: unify - if (vm.getState() != State.Running) { - // OfflineVmwareMigration: and not vmware - if (s_logger.isDebugEnabled()) { - s_logger.debug("VM is not Running, unable to migrate the vm " + vm); - } - CloudRuntimeException ex = new CloudRuntimeException("VM is not Running, unable to migrate the vm with" + " specified id"); - 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"); - } - - // OfflineVmwareMigration: this condition is to complicated. (already a method somewhere) - 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)) { - throw new InvalidParameterValueException("Unsupported hypervisor type for vm migration, we support" + " XenServer/VMware/KVM only"); - } - + private Pair getHostsForMigrateVmWithStorage(VMInstanceVO vm, Host destinationHost) throws VirtualMachineMigrationException { long srcHostId = vm.getHostId(); Host srcHost = _resourceMgr.getHost(srcHostId); if (srcHost == null) { - throw new InvalidParameterValueException("Cannot migrate VM, host with id: " + srcHostId + " for VM not found"); + throw new InvalidParameterValueException("Cannot migrate VM, host with ID: " + srcHostId + " for VM not found"); } // Check if source and destination hosts are valid and migrating to same host if (destinationHost.getId() == srcHostId) { - throw new InvalidParameterValueException("Cannot migrate VM, VM is already present on this host, please" + " specify valid destination host to migrate the VM"); + throw new InvalidParameterValueException(String.format("Cannot migrate VM as it is already present on host %s (ID: %s), please specify valid destination host to migrate the VM", + destinationHost.getName(), destinationHost.getUuid())); } String srcHostVersion = srcHost.getHypervisorVersion(); @@ -6371,39 +6605,45 @@ public VirtualMachine migrateVirtualMachineWithVolume(Long vmId, Host destinatio } } - if (!Boolean.TRUE.equals(_hypervisorCapabilitiesDao.isStorageMotionSupported(srcHost.getHypervisorType(), srcHostVersion))) { - throw new CloudRuntimeException("Migration with storage isn't supported for source host ID: " + srcHost.getUuid() + " on hypervisor " + srcHost.getHypervisorType() + " of version " + srcHost.getHypervisorVersion()); + if (!_hypervisorCapabilitiesDao.isStorageMotionSupported(srcHost.getHypervisorType(), srcHostVersion)) { + throw new CloudRuntimeException(String.format("Migration with storage isn't supported for source host %s (ID: %s) on hypervisor %s with version %s", srcHost.getName(), srcHost.getUuid(), srcHost.getHypervisorType(), srcHost.getHypervisorVersion())); } if (srcHostVersion == null || !srcHostVersion.equals(destHostVersion)) { - if (!Boolean.TRUE.equals(_hypervisorCapabilitiesDao.isStorageMotionSupported(destinationHost.getHypervisorType(), destHostVersion))) { - throw new CloudRuntimeException("Migration with storage isn't supported for target host ID: " + srcHost.getUuid() + " on hypervisor " + srcHost.getHypervisorType() + " of version " + srcHost.getHypervisorVersion()); + if (!_hypervisorCapabilitiesDao.isStorageMotionSupported(destinationHost.getHypervisorType(), destHostVersion)) { + throw new CloudRuntimeException(String.format("Migration with storage isn't supported for target host %s (ID: %s) on hypervisor %s with version %s", destinationHost.getName(), destinationHost.getUuid(), destinationHost.getHypervisorType(), destinationHost.getHypervisorVersion())); } } // Check if destination host is up. if (destinationHost.getState() != com.cloud.host.Status.Up || destinationHost.getResourceState() != ResourceState.Enabled) { - throw new CloudRuntimeException("Cannot migrate VM, destination host is not in correct state, has " + "status: " + destinationHost.getState() + ", state: " - + destinationHost.getResourceState()); + throw new CloudRuntimeException(String.format("Cannot migrate VM, destination host %s (ID: %s) is not in correct state, has status: %s, state: %s", + destinationHost.getName(), destinationHost.getUuid(), destinationHost.getState(), destinationHost.getResourceState())); } - // Check that Vm does not have VM Snapshots - if (_vmSnapshotDao.findByVm(vmId).size() > 0) { - throw new InvalidParameterValueException("VM with VM Snapshots cannot be migrated with storage, please remove all VM snapshots"); + // Check max guest vm limit for the destinationHost. + if (_capacityMgr.checkIfHostReachMaxGuestLimit(destinationHost)) { + throw new VirtualMachineMigrationException(String.format("Cannot migrate VM as destination host %s (ID: %s) already has max running vms (count includes system VMs)", + destinationHost.getName(), destinationHost.getUuid())); } + return new Pair<>(srcHost, destinationHost); + } + + private List getVmVolumesForMigrateVmWithStorage(VMInstanceVO vm) { List vmVolumes = _volsDao.findUsableVolumesForInstance(vm.getId()); - Map volToPoolObjectMap = new HashMap(); - if (!isVMUsingLocalStorage(vm) && MapUtils.isEmpty(volumeToPool) - && (destinationHost.getClusterId().equals(srcHost.getClusterId()) || isVmVolumesOnZoneWideStore(vm))){ - // If volumes do not have to be migrated - // call migrateVirtualMachine for non-user VMs else throw exception - if (!VirtualMachine.Type.User.equals(vm.getType())) { - return migrateVirtualMachine(vmId, destinationHost); + for (VolumeVO volume : vmVolumes) { + if (volume.getState() != Volume.State.Ready) { + throw new CloudRuntimeException(String.format("Volume %s (ID: %s) of the VM is not in Ready state. Cannot migrate the VM %s (ID: %s) with its volumes", volume.getName(), volume.getUuid(), vm.getInstanceName(), vm.getUuid())); } - throw new InvalidParameterValueException("Migration of the vm " + vm + "from host " + srcHost + " to destination host " + destinationHost - + " doesn't involve migrating the volumes."); } + return vmVolumes; + } + + private Map getVolumePoolMappingForMigrateVmWithStorage(VMInstanceVO vm, Map volumeToPool) { + Map volToPoolObjectMap = new HashMap(); + + List vmVolumes = getVmVolumesForMigrateVmWithStorage(vm); if (MapUtils.isNotEmpty(volumeToPool)) { // Check if all the volumes and pools passed as parameters are valid. @@ -6420,15 +6660,15 @@ public VirtualMachine migrateVirtualMachineWithVolume(Long vmId, Host destinatio } else { // Verify the volume given belongs to the vm. if (!vmVolumes.contains(volume)) { - throw new InvalidParameterValueException("There volume " + volume + " doesn't belong to " + "the virtual machine " + vm + " that has to be migrated"); + throw new InvalidParameterValueException(String.format("Volume " + volume + " doesn't belong to the VM %s (ID: %s) that has to be migrated", vm.getInstanceName(), vm.getUuid())); } - volToPoolObjectMap.put(Long.valueOf(volume.getId()), Long.valueOf(pool.getId())); + volToPoolObjectMap.put(volume.getId(), pool.getId()); } HypervisorType hypervisorType = _volsDao.getHypervisorType(volume.getId()); if (hypervisorType.equals(HypervisorType.VMware)) { try { - boolean isStoragePoolStoragepolicyComplaince = storageManager.isStoragePoolComplaintWithStoragePolicy(Arrays.asList(volume), pool); - if (!isStoragePoolStoragepolicyComplaince) { + boolean isStoragePoolStoragepolicyCompliance = storageManager.isStoragePoolCompliantWithStoragePolicy(Arrays.asList(volume), pool); + if (!isStoragePoolStoragepolicyCompliance) { throw new CloudRuntimeException(String.format("Storage pool %s is not storage policy compliance with the volume %s", pool.getUuid(), volume.getUuid())); } } catch (StorageUnavailableException e) { @@ -6437,24 +6677,69 @@ public VirtualMachine migrateVirtualMachineWithVolume(Long vmId, Host destinatio } } } + return volToPoolObjectMap; + } - // Check if all the volumes are in the correct state. - for (VolumeVO volume : vmVolumes) { - if (volume.getState() != Volume.State.Ready) { - throw new CloudRuntimeException("Volume " + volume + " of the VM is not in Ready state. Cannot " + "migrate the vm with its volumes."); + @Override + @ActionEvent(eventType = EventTypes.EVENT_VM_MIGRATE, eventDescription = "migrating VM", async = true) + public VirtualMachine migrateVirtualMachineWithVolume(Long vmId, Host destinationHost, Map volumeToPool) throws ResourceUnavailableException, + ConcurrentOperationException, ManagementServerException, VirtualMachineMigrationException { + // Access check - only root administrator can migrate VM. + Account caller = CallContext.current().getCallingAccount(); + if (!_accountMgr.isRootAdmin(caller.getId())) { + if (s_logger.isDebugEnabled()) { + s_logger.debug("Caller is not a root admin, permission denied to migrate the VM"); } + throw new PermissionDeniedException("No permission to migrate VM, Only Root Admin can migrate a VM!"); } - // Check max guest vm limit for the destinationHost. - HostVO destinationHostVO = _hostDao.findById(destinationHost.getId()); - if (_capacityMgr.checkIfHostReachMaxGuestLimit(destinationHostVO)) { - throw new VirtualMachineMigrationException("Host name: " + destinationHost.getName() + ", hostId: " + destinationHost.getId() - + " already has max running vms (count includes system VMs). Cannot" + " migrate to this host"); + VMInstanceVO vm = _vmInstanceDao.findById(vmId); + if (vm == null) { + throw new InvalidParameterValueException("Unable to find the VM by ID " + vmId); } - checkHostsDedication(vm, srcHostId, destinationHost.getId()); + // OfflineVmwareMigration: this would be it ;) if multiple paths exist: unify + if (vm.getState() != State.Running) { + // OfflineVmwareMigration: and not vmware + if (s_logger.isDebugEnabled()) { + s_logger.debug("VM is not Running, unable to migrate the vm " + vm); + } + CloudRuntimeException ex = new CloudRuntimeException(String.format("Unable to migrate the VM %s (ID: %s) as it is not in Running state", vm.getInstanceName(), vm.getUuid())); + 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_STORAGE_MIGRATION_SUPPORTING_HYPERVISORS.contains(vm.getHypervisorType())) { + throw new InvalidParameterValueException(String.format("Unsupported hypervisor: %s for VM migration, we support XenServer/VMware/KVM only", vm.getHypervisorType())); + } + + if (_vmSnapshotDao.findByVm(vmId).size() > 0) { + throw new InvalidParameterValueException("VM with VM Snapshots cannot be migrated with storage, please remove all VM snapshots"); + } + + Pair sourceDestinationHosts = getHostsForMigrateVmWithStorage(vm, destinationHost); + Host srcHost = sourceDestinationHosts.first(); + + if (!isVMUsingLocalStorage(vm) && MapUtils.isEmpty(volumeToPool) + && (destinationHost.getClusterId().equals(srcHost.getClusterId()) || isVmVolumesOnZoneWideStore(vm))){ + // If volumes do not have to be migrated + // call migrateVirtualMachine for non-user VMs else throw exception + if (!VirtualMachine.Type.User.equals(vm.getType())) { + return migrateVirtualMachine(vmId, destinationHost); + } + throw new InvalidParameterValueException(String.format("Migration of the VM: %s (ID: %s) from host %s (ID: %s) to destination host %s (ID: %s) doesn't involve migrating the volumes", + vm.getInstanceName(), vm.getUuid(), srcHost.getName(), srcHost.getUuid(), destinationHost.getName(), destinationHost.getUuid())); + } + + Map volToPoolObjectMap = getVolumePoolMappingForMigrateVmWithStorage(vm, volumeToPool); + + checkHostsDedication(vm, srcHost.getId(), destinationHost.getId()); - _itMgr.migrateWithStorage(vm.getUuid(), srcHostId, destinationHost.getId(), volToPoolObjectMap); + _itMgr.migrateWithStorage(vm.getUuid(), srcHost.getId(), destinationHost.getId(), volToPoolObjectMap); return findMigratedVm(vm.getId(), vm.getType()); } diff --git a/server/src/main/java/org/apache/cloudstack/agent/lb/IndirectAgentLBServiceImpl.java b/server/src/main/java/org/apache/cloudstack/agent/lb/IndirectAgentLBServiceImpl.java index a25575cd175a..003664cc5e7c 100644 --- a/server/src/main/java/org/apache/cloudstack/agent/lb/IndirectAgentLBServiceImpl.java +++ b/server/src/main/java/org/apache/cloudstack/agent/lb/IndirectAgentLBServiceImpl.java @@ -221,7 +221,7 @@ public void propagateMSListToAgents() { final SetupMSListCommand cmd = new SetupMSListCommand(msList, lbAlgorithm, lbCheckInterval); final Answer answer = agentManager.easySend(host.getId(), cmd); if (answer == null || !answer.getResult()) { - LOG.warn("Failed to setup management servers list to the agent of host id=" + host.getId()); + LOG.warn(String.format("Failed to setup management servers list to the agent of %s", host)); } } } diff --git a/server/src/main/java/org/apache/cloudstack/outofbandmanagement/OutOfBandManagementServiceImpl.java b/server/src/main/java/org/apache/cloudstack/outofbandmanagement/OutOfBandManagementServiceImpl.java index 89f6ae718ee6..a956cf6727b5 100644 --- a/server/src/main/java/org/apache/cloudstack/outofbandmanagement/OutOfBandManagementServiceImpl.java +++ b/server/src/main/java/org/apache/cloudstack/outofbandmanagement/OutOfBandManagementServiceImpl.java @@ -189,7 +189,7 @@ private void sendAuthError(final Host host, final String message) { if (sentCount != null && sentCount <= 0) { boolean concurrentUpdateResult = hostAlertCache.asMap().replace(host.getId(), sentCount, sentCount+1L); if (concurrentUpdateResult) { - final String subject = String.format("Out-of-band management auth-error detected for host:%d in cluster:%d, zone:%d", host.getId(), host.getClusterId(), host.getDataCenterId()); + final String subject = String.format("Out-of-band management auth-error detected for %s in cluster [id: %d] and zone [id: %d].", host, host.getClusterId(), host.getDataCenterId()); LOG.error(subject + ": " + message); alertMgr.sendAlert(AlertManager.AlertType.ALERT_TYPE_OOBM_AUTH_ERROR, host.getDataCenterId(), host.getPodId(), subject, message); } @@ -203,11 +203,12 @@ private boolean transitionPowerState(OutOfBandManagement.PowerState.Event event, return false; } OutOfBandManagement.PowerState currentPowerState = outOfBandManagementHost.getPowerState(); + Host host = hostDao.findById(outOfBandManagementHost.getHostId()); try { OutOfBandManagement.PowerState newPowerState = OutOfBandManagement.PowerState.getStateMachine().getNextState(currentPowerState, event); boolean result = OutOfBandManagement.PowerState.getStateMachine().transitTo(outOfBandManagementHost, event, null, outOfBandManagementDao); if (result) { - final String message = String.format("Transitioned out-of-band management power state from:%s to:%s due to event:%s for the host id:%d", currentPowerState, newPowerState, event, outOfBandManagementHost.getHostId()); + final String message = String.format("Transitioned out-of-band management power state from %s to %s due to event: %s for %s", currentPowerState, newPowerState, event, host); LOG.debug(message); if (newPowerState == OutOfBandManagement.PowerState.Unknown) { ActionEventUtils.onActionEvent(CallContext.current().getCallingUserId(), CallContext.current().getCallingAccountId(), Domain.ROOT_DOMAIN, @@ -216,7 +217,7 @@ private boolean transitionPowerState(OutOfBandManagement.PowerState.Event event, } return result; } catch (NoTransitionException ignored) { - LOG.trace(String.format("Unable to transition out-of-band management power state for host id=%s for the event=%s and current power state=%s", outOfBandManagementHost.getHostId(), event, currentPowerState)); + LOG.trace(String.format("Unable to transition out-of-band management power state for %s for the event: %s and current power state: %s", host, event, currentPowerState)); } return false; } @@ -372,13 +373,14 @@ public OutOfBandManagementResponse configure(final Host host, final ImmutableMap } boolean updatedConfig = outOfBandManagementDao.update(outOfBandManagementConfig.getId(), (OutOfBandManagementVO) outOfBandManagementConfig); - CallContext.current().setEventDetails("host id:" + host.getId() + " configuration:" + outOfBandManagementConfig.getAddress() + ":" + outOfBandManagementConfig.getPort()); + String eventDetails = String.format("Configuring %s out-of-band with address [%s] and port [%s]", host, outOfBandManagementConfig.getAddress(), outOfBandManagementConfig.getPort()); + CallContext.current().setEventDetails(eventDetails); if (!updatedConfig) { - throw new CloudRuntimeException("Failed to update out-of-band management config for the host in the database."); + throw new CloudRuntimeException(String.format("Failed to update out-of-band management config for %s in the database.", host)); } - String result = "Out-of-band management successfully configured for the host"; + String result = String.format("Out-of-band management successfully configured for %s.", host); LOG.debug(result); final OutOfBandManagementResponse response = new OutOfBandManagementResponse(outOfBandManagementDao.findByHost(host.getId())); @@ -404,7 +406,7 @@ public OutOfBandManagementResponse executePowerOperation(final Host host, final final OutOfBandManagementDriverResponse driverResponse = driver.execute(cmd); if (driverResponse == null) { - throw new CloudRuntimeException(String.format("Out-of-band Management action (%s) on host (%s) failed due to no response from the driver", powerOperation, host.getUuid())); + throw new CloudRuntimeException(String.format("Out-of-band Management action [%s] on %s failed due to no response from the driver", powerOperation, host)); } if (powerOperation.equals(OutOfBandManagement.PowerOperation.STATUS)) { @@ -412,9 +414,9 @@ public OutOfBandManagementResponse executePowerOperation(final Host host, final } if (!driverResponse.isSuccess()) { - String errorMessage = String.format("Out-of-band Management action (%s) on host (%s) failed with error: %s", powerOperation, host.getUuid(), driverResponse.getError()); + String errorMessage = String.format("Out-of-band Management action [%s] on %s failed with error: %s", powerOperation, host, driverResponse.getError()); if (driverResponse.hasAuthFailure()) { - errorMessage = String.format("Out-of-band Management action (%s) on host (%s) failed due to authentication error: %s. Please check configured credentials.", powerOperation, host.getUuid(), driverResponse.getError()); + errorMessage = String.format("Out-of-band Management action [%s] on %s failed due to authentication error: %s. Please check configured credentials.", powerOperation, host, driverResponse.getError()); sendAuthError(host, errorMessage); } if (!powerOperation.equals(OutOfBandManagement.PowerOperation.STATUS)) { @@ -436,13 +438,13 @@ public OutOfBandManagementResponse executePowerOperation(final Host host, final public OutOfBandManagementResponse changePassword(final Host host, final String newPassword) { checkOutOfBandManagementEnabledByZoneClusterHost(host); if (Strings.isNullOrEmpty(newPassword)) { - throw new CloudRuntimeException(String.format("Cannot change out-of-band management password as provided new-password is null or empty for the host %s.", host.getUuid())); + throw new CloudRuntimeException(String.format("Cannot change out-of-band management password as provided new-password is null or empty for %s.", host)); } final OutOfBandManagement outOfBandManagementConfig = outOfBandManagementDao.findByHost(host.getId()); final ImmutableMap options = getOptions(outOfBandManagementConfig); if (!(options.containsKey(OutOfBandManagement.Option.PASSWORD) && !Strings.isNullOrEmpty(options.get(OutOfBandManagement.Option.PASSWORD)))) { - throw new CloudRuntimeException(String.format("Cannot change out-of-band management password as we've no previously configured password for the host %s.", host.getUuid())); + throw new CloudRuntimeException(String.format("Cannot change out-of-band management password as we've no previously configured password for %s.", host)); } final OutOfBandManagementDriver driver = getDriver(outOfBandManagementConfig); final OutOfBandManagementDriverChangePasswordCommand changePasswordCmd = new OutOfBandManagementDriverChangePasswordCommand(options, ActionTimeout.valueIn(host.getClusterId()), newPassword); @@ -455,7 +457,7 @@ public Boolean doInTransaction(TransactionStatus status) { boolean result = outOfBandManagementDao.update(updatedOutOfBandManagementConfig.getId(), (OutOfBandManagementVO) updatedOutOfBandManagementConfig); if (!result) { - throw new CloudRuntimeException(String.format("Failed to change out-of-band management password for host (%s) in the database.", host.getUuid())); + throw new CloudRuntimeException(String.format("Failed to change out-of-band management password for %s in the database.", host)); } final OutOfBandManagementDriverResponse driverResponse; @@ -463,11 +465,11 @@ public Boolean doInTransaction(TransactionStatus status) { driverResponse = driver.execute(changePasswordCmd); } catch (Exception e) { LOG.error("Out-of-band management change password failed due to driver error: " + e.getMessage()); - throw new CloudRuntimeException(String.format("Failed to change out-of-band management password for host (%s) due to driver error: %s", host.getUuid(), e.getMessage())); + throw new CloudRuntimeException(String.format("Failed to change out-of-band management password for %s due to driver error: %s", host, e.getMessage())); } if (!driverResponse.isSuccess()) { - throw new CloudRuntimeException(String.format("Failed to change out-of-band management password for host (%s) with error: %s", host.getUuid(), driverResponse.getError())); + throw new CloudRuntimeException(String.format("Failed to change out-of-band management password for %s with error: %s", host, driverResponse.getError())); } return result && driverResponse.isSuccess(); @@ -566,7 +568,7 @@ protected void runInContext() { } else if (outOfBandManagementHost.getPowerState() != OutOfBandManagement.PowerState.Disabled) { if (transitionPowerStateToDisabled(Collections.singletonList(host))) { if (LOG.isDebugEnabled()) { - LOG.debug("Out-of-band management was disabled in zone/cluster/host, disabled power state for host id:" + host.getId()); + LOG.debug(String.format("Out-of-band management was disabled in zone/cluster/host, disabled power state for %s", host)); } } } diff --git a/server/src/test/async-job-component.xml b/server/src/test/async-job-component.xml index 6bc99c260422..fbe1015cbeed 100644 --- a/server/src/test/async-job-component.xml +++ b/server/src/test/async-job-component.xml @@ -1,24 +1,24 @@ - - @@ -77,8 +77,6 @@ - - diff --git a/server/src/test/java/com/cloud/storage/VolumeApiServiceImplTest.java b/server/src/test/java/com/cloud/storage/VolumeApiServiceImplTest.java index 8ec24afe9385..f317ea8acf3b 100644 --- a/server/src/test/java/com/cloud/storage/VolumeApiServiceImplTest.java +++ b/server/src/test/java/com/cloud/storage/VolumeApiServiceImplTest.java @@ -35,6 +35,9 @@ import java.util.UUID; import java.util.concurrent.ExecutionException; +import com.cloud.api.query.dao.ServiceOfferingJoinDao; +import com.cloud.api.query.vo.ServiceOfferingJoinVO; +import com.cloud.storage.dao.VMTemplateDao; import org.apache.cloudstack.acl.ControlledEntity; import org.apache.cloudstack.acl.SecurityChecker.AccessType; import org.apache.cloudstack.api.command.user.volume.CreateVolumeCmd; @@ -78,7 +81,6 @@ import com.cloud.exception.ResourceAllocationException; import com.cloud.host.dao.HostDao; import com.cloud.hypervisor.Hypervisor.HypervisorType; -import com.cloud.hypervisor.dao.HypervisorCapabilitiesDao; import com.cloud.org.Grouping; import com.cloud.serializer.GsonHelper; import com.cloud.server.TaggedResourceService; @@ -153,7 +155,9 @@ public class VolumeApiServiceImplTest { @Mock private StoragePoolTagsDao storagePoolTagsDao; @Mock - private HypervisorCapabilitiesDao hypervisorCapabilitiesDao; + private VMTemplateDao templateDao; + @Mock + private ServiceOfferingJoinDao serviceOfferingJoinDao; private DetachVolumeCmd detachCmd = new DetachVolumeCmd(); private Class _detachCmdClass = detachCmd.getClass(); @@ -1079,4 +1083,52 @@ public void doesTargetStorageSupportDiskOfferingTestDiskOfferingTagsEqualsStorag Assert.assertTrue(result); } + + @Test + public void isNotPossibleToResizeTestAllFormats() { + Storage.ImageFormat[] imageFormat = Storage.ImageFormat.values(); + for (int i = 0; i < imageFormat.length - 1; i++) { + if (imageFormat[i] != Storage.ImageFormat.ISO) { + prepareAndRunTestOfIsNotPossibleToResize(Type.ROOT, 10l, imageFormat[i], true); + } else { + prepareAndRunTestOfIsNotPossibleToResize(Type.ROOT, 10l, imageFormat[i], false); + } + } + } + + @Test + public void isNotPossibleToResizeTestAllTypes() { + Type[] types = Type.values(); + for (int i = 0; i < types.length - 1; i++) { + if (types[i] != Type.ROOT) { + prepareAndRunTestOfIsNotPossibleToResize(types[i], 10l, Storage.ImageFormat.QCOW2, false); + } else { + prepareAndRunTestOfIsNotPossibleToResize(types[i], 10l, Storage.ImageFormat.QCOW2, true); + } + } + } + + @Test + public void isNotPossibleToResizeTestNoRootDiskSize() { + prepareAndRunTestOfIsNotPossibleToResize(Type.ROOT, 0l, Storage.ImageFormat.QCOW2, false); + } + + private void prepareAndRunTestOfIsNotPossibleToResize(Type volumeType, Long rootDisk, Storage.ImageFormat imageFormat, boolean expectedIsNotPossibleToResize) { + VolumeVO volume = Mockito.mock(VolumeVO.class); + when(volume.getVolumeType()).thenReturn(volumeType); + + when(volume.getTemplateId()).thenReturn(1l); + DiskOfferingVO diskOffering = Mockito.mock(DiskOfferingVO.class); + + ServiceOfferingJoinVO serviceOfferingJoinVO = Mockito.mock(ServiceOfferingJoinVO.class); + when(serviceOfferingJoinVO.getRootDiskSize()).thenReturn(rootDisk); + when(serviceOfferingJoinDao.findById(Mockito.anyLong())).thenReturn(serviceOfferingJoinVO); + + VMTemplateVO template = Mockito.mock(VMTemplateVO.class); + when(template.getFormat()).thenReturn(imageFormat); + when(templateDao.findByIdIncludingRemoved(Mockito.anyLong())).thenReturn(template); + + boolean result = volumeApiServiceImpl.isNotPossibleToResize(volume, diskOffering); + Assert.assertEquals(expectedIsNotPossibleToResize, result); + } } diff --git a/server/src/test/java/com/cloud/vm/UserVmManagerImplTest.java b/server/src/test/java/com/cloud/vm/UserVmManagerImplTest.java index da59f07a3a86..ae647f349df7 100644 --- a/server/src/test/java/com/cloud/vm/UserVmManagerImplTest.java +++ b/server/src/test/java/com/cloud/vm/UserVmManagerImplTest.java @@ -558,4 +558,17 @@ private DiskOfferingVO prepareDiskOffering(long rootSize, long diskOfferingId, l Mockito.when(newRootDiskOffering.getName()).thenReturn("OfferingName"); return newRootDiskOffering; } + + @Test + public void validateRemoveEncryptedPasswordFromUserVmVoDetails(){ + Map detailsMock = Mockito.mock(HashMap.class); + + Mockito.doReturn(detailsMock).when(userVmVoMock).getDetails(); + Mockito.doNothing().when(userVmDao).saveDetails(userVmVoMock); + userVmManagerImpl.removeEncryptedPasswordFromUserVmVoDetails(userVmVoMock); + + Mockito.verify(detailsMock, Mockito.times(1)).remove(VmDetailConstants.ENCRYPTED_PASSWORD); + Mockito.verify(userVmVoMock, Mockito.times(1)).setDetails(detailsMock); + Mockito.verify(userVmDao, Mockito.times(1)).saveDetails(userVmVoMock); + } } diff --git a/server/src/test/java/com/cloud/vm/UserVmManagerTest.java b/server/src/test/java/com/cloud/vm/UserVmManagerTest.java index 9d58f4f00b5a..1103fb179611 100644 --- a/server/src/test/java/com/cloud/vm/UserVmManagerTest.java +++ b/server/src/test/java/com/cloud/vm/UserVmManagerTest.java @@ -604,6 +604,7 @@ public void testUpdateVmNicIpSuccess2() throws Exception { NicVO nic = new NicVO("nic", 1L, 2L, VirtualMachine.Type.User); when(_nicDao.findById(anyLong())).thenReturn(nic); + nic.setIPv4Address("10.10.10.9"); when(_vmDao.findById(anyLong())).thenReturn(_vmMock); when(_networkDao.findById(anyLong())).thenReturn(_networkMock); doReturn(9L).when(_networkMock).getNetworkOfferingId(); @@ -630,9 +631,9 @@ public void testUpdateVmNicIpSuccess2() throws Exception { when(vlan.getVlanNetmask()).thenReturn("255.255.255.0"); when(_ipAddrMgr.allocatePublicIpForGuestNic(Mockito.eq(_networkMock), nullable(Long.class), Mockito.eq(_accountMock), anyString())).thenReturn("10.10.10.10"); - lenient().when(_ipAddressDao.findByIpAndSourceNetworkId(anyLong(), anyString())).thenReturn(null); + when(_ipAddressDao.findByIpAndSourceNetworkId(anyLong(), eq("10.10.10.10"))).thenReturn(newIp); + when(_ipAddressDao.findByIpAndSourceNetworkId(anyLong(), eq("10.10.10.9"))).thenReturn(null); when(_nicDao.persist(any(NicVO.class))).thenReturn(nic); - when(_ipAddressDao.findByIpAndDcId(anyLong(), anyString())).thenReturn(newIp); when(_vlanDao.findById(anyLong())).thenReturn(vlan); Account caller = new AccountVO("testaccount", 1, "networkdomain", (short)0, UUID.randomUUID().toString()); diff --git a/server/src/test/java/com/cloud/vpc/VpcTestConfiguration.java b/server/src/test/java/com/cloud/vpc/VpcTestConfiguration.java index dcc44d6dc83f..2dfbb3799b8d 100644 --- a/server/src/test/java/com/cloud/vpc/VpcTestConfiguration.java +++ b/server/src/test/java/com/cloud/vpc/VpcTestConfiguration.java @@ -86,7 +86,6 @@ import com.cloud.storage.dao.SnapshotDaoImpl; import com.cloud.storage.dao.VMTemplateDaoImpl; import com.cloud.storage.dao.VMTemplateDetailsDaoImpl; -import com.cloud.storage.dao.VMTemplateHostDaoImpl; import com.cloud.storage.dao.VMTemplateZoneDaoImpl; import com.cloud.storage.dao.VolumeDaoImpl; import com.cloud.tags.dao.ResourceTagsDaoImpl; @@ -116,7 +115,7 @@ UserStatisticsDaoImpl.class, PhysicalNetworkTrafficTypeDaoImpl.class, FirewallRulesCidrsDaoImpl.class, ResourceLimitManagerImpl.class, ResourceLimitDaoImpl.class, ResourceCountDaoImpl.class, DomainDaoImpl.class, UserVmDaoImpl.class, UserVmDetailsDaoImpl.class, NicDaoImpl.class, SnapshotDaoImpl.class, VMInstanceDaoImpl.class, VolumeDaoImpl.class, UserIpv6AddressDaoImpl.class, NicSecondaryIpDaoImpl.class, - VpcServiceMapDaoImpl.class, ServiceOfferingDaoImpl.class, VMTemplateHostDaoImpl.class, MockVpcDaoImpl.class, VMTemplateDaoImpl.class, + VpcServiceMapDaoImpl.class, ServiceOfferingDaoImpl.class, MockVpcDaoImpl.class, VMTemplateDaoImpl.class, VMTemplateZoneDaoImpl.class, VMTemplateDetailsDaoImpl.class, DataCenterDaoImpl.class, DataCenterIpAddressDaoImpl.class, DataCenterLinkLocalIpAddressDaoImpl.class, DataCenterVnetDaoImpl.class, PodVlanDaoImpl.class, DataCenterDetailsDaoImpl.class, MockNetworkManagerImpl.class, MockVpcVirtualNetworkApplianceManager.class, EntityManagerImpl.class, LoadBalancerDaoImpl.class, diff --git a/services/secondary-storage/controller/src/main/java/org/apache/cloudstack/secondarystorage/SecondaryStorageManagerImpl.java b/services/secondary-storage/controller/src/main/java/org/apache/cloudstack/secondarystorage/SecondaryStorageManagerImpl.java index 20db0fb0fa44..f7c22c209852 100644 --- a/services/secondary-storage/controller/src/main/java/org/apache/cloudstack/secondarystorage/SecondaryStorageManagerImpl.java +++ b/services/secondary-storage/controller/src/main/java/org/apache/cloudstack/secondarystorage/SecondaryStorageManagerImpl.java @@ -261,7 +261,7 @@ public class SecondaryStorageManagerImpl extends ManagerBase implements Secondar private final GlobalLock _allocLock = GlobalLock.getInternLock(getAllocLockName()); static final ConfigKey NTPServerConfig = new ConfigKey(String.class, "ntp.server.list", "Advanced", null, - "Comma separated list of NTP servers to configure in Secondary storage VM", false, ConfigKey.Scope.Global, null); + "Comma separated list of NTP servers to configure in Secondary storage VM", true, ConfigKey.Scope.Global, null); static final ConfigKey MaxNumberOfSsvmsForMigration = new ConfigKey("Advanced", Integer.class, "max.ssvm.count", "5", "Number of additional SSVMs to handle migration of data objects concurrently", true, ConfigKey.Scope.Global); diff --git a/services/secondary-storage/server/src/main/java/org/apache/cloudstack/storage/template/DownloadManager.java b/services/secondary-storage/server/src/main/java/org/apache/cloudstack/storage/template/DownloadManager.java index 78190af05989..48093f2cf1fe 100644 --- a/services/secondary-storage/server/src/main/java/org/apache/cloudstack/storage/template/DownloadManager.java +++ b/services/secondary-storage/server/src/main/java/org/apache/cloudstack/storage/template/DownloadManager.java @@ -27,9 +27,9 @@ import com.cloud.utils.net.Proxy; import com.cloud.agent.api.to.S3TO; import com.cloud.storage.Storage.ImageFormat; -import com.cloud.storage.VMTemplateHostVO; import com.cloud.storage.template.TemplateDownloader; import com.cloud.storage.template.TemplateProp; +import com.cloud.storage.VMTemplateStorageResourceAssoc.Status; import com.cloud.utils.component.Manager; public interface DownloadManager extends Manager { @@ -67,7 +67,7 @@ public String downloadS3Template(S3TO s3, long id, String url, String name, Imag * @param jobId job Id * @return status of the download job */ - public VMTemplateHostVO.Status getDownloadStatus2(String jobId); + public Status getDownloadStatus2(String jobId); /** * Get the download percent of a download job diff --git a/services/secondary-storage/server/src/main/java/org/apache/cloudstack/storage/template/DownloadManagerImpl.java b/services/secondary-storage/server/src/main/java/org/apache/cloudstack/storage/template/DownloadManagerImpl.java index 7ce252a8ed7c..a3595a24d87e 100644 --- a/services/secondary-storage/server/src/main/java/org/apache/cloudstack/storage/template/DownloadManagerImpl.java +++ b/services/secondary-storage/server/src/main/java/org/apache/cloudstack/storage/template/DownloadManagerImpl.java @@ -72,7 +72,6 @@ import com.cloud.exception.InternalErrorException; import com.cloud.storage.Storage.ImageFormat; import com.cloud.storage.StorageLayer; -import com.cloud.storage.VMTemplateHostVO; import com.cloud.storage.VMTemplateStorageResourceAssoc; import com.cloud.storage.template.Processor.FormatInfo; import com.cloud.storage.template.TemplateDownloader.DownloadCompleteCallback; @@ -701,31 +700,31 @@ public int getDownloadPct(String jobId) { return 0; } - public static VMTemplateHostVO.Status convertStatus(Status tds) { + public static VMTemplateStorageResourceAssoc.Status convertStatus(Status tds) { switch (tds) { case ABORTED: - return VMTemplateHostVO.Status.NOT_DOWNLOADED; + return VMTemplateStorageResourceAssoc.Status.NOT_DOWNLOADED; case DOWNLOAD_FINISHED: - return VMTemplateHostVO.Status.DOWNLOAD_IN_PROGRESS; + return VMTemplateStorageResourceAssoc.Status.DOWNLOAD_IN_PROGRESS; case IN_PROGRESS: - return VMTemplateHostVO.Status.DOWNLOAD_IN_PROGRESS; + return VMTemplateStorageResourceAssoc.Status.DOWNLOAD_IN_PROGRESS; case NOT_STARTED: - return VMTemplateHostVO.Status.NOT_DOWNLOADED; + return VMTemplateStorageResourceAssoc.Status.NOT_DOWNLOADED; case RECOVERABLE_ERROR: - return VMTemplateHostVO.Status.NOT_DOWNLOADED; + return VMTemplateStorageResourceAssoc.Status.NOT_DOWNLOADED; case UNKNOWN: - return VMTemplateHostVO.Status.UNKNOWN; + return VMTemplateStorageResourceAssoc.Status.UNKNOWN; case UNRECOVERABLE_ERROR: - return VMTemplateHostVO.Status.DOWNLOAD_ERROR; + return VMTemplateStorageResourceAssoc.Status.DOWNLOAD_ERROR; case POST_DOWNLOAD_FINISHED: - return VMTemplateHostVO.Status.DOWNLOADED; + return VMTemplateStorageResourceAssoc.Status.DOWNLOADED; default: - return VMTemplateHostVO.Status.UNKNOWN; + return VMTemplateStorageResourceAssoc.Status.UNKNOWN; } } @Override - public com.cloud.storage.VMTemplateHostVO.Status getDownloadStatus2(String jobId) { + public com.cloud.storage.VMTemplateStorageResourceAssoc.Status getDownloadStatus2(String jobId) { return convertStatus(getDownloadStatus(jobId)); } diff --git a/setup/bindir/cloud-set-guest-sshkey-configdrive.in b/setup/bindir/cloud-set-guest-sshkey-configdrive.in index 31dc6df92db3..7294871f3293 100644 --- a/setup/bindir/cloud-set-guest-sshkey-configdrive.in +++ b/setup/bindir/cloud-set-guest-sshkey-configdrive.in @@ -31,7 +31,7 @@ mountdir=$(mktemp -d) # If lable name is other than config, please change the below line as required DefaultDisk=/dev/disk/by-label/config-2 -SSHKey_File=$mountdir/cloudstack/metadata/public_keys.txt +SSHKey_File=$mountdir/cloudstack/metadata/public-keys.txt keys_received=0 function prepare_mount @@ -44,7 +44,7 @@ function prepare_mount if [ -e $DefaultDisk ]; then Disk=$DefaultDisk else - BLOCK_DEVICE=$(blkid -t LABEL='config' /dev/hd? /dev/sd? /dev/xvd? /dev/vd? -o device) + BLOCK_DEVICE=$(blkid -t LABEL='config-2' /dev/hd? /dev/sd? /dev/xvd? /dev/vd? -o device) if [ -n $BLOCK_DEVICE ]; then Disk=$BLOCK_DEVICE else diff --git a/systemvm/debian/opt/cloud/bin/configure.py b/systemvm/debian/opt/cloud/bin/configure.py index 8fdf134b506c..cafd739d7cab 100755 --- a/systemvm/debian/opt/cloud/bin/configure.py +++ b/systemvm/debian/opt/cloud/bin/configure.py @@ -111,7 +111,7 @@ def __init__(self, obj, fw): self.rule['allowed'] = True self.rule['action'] = "ACCEPT" - if self.rule['type'] == 'all' and obj['source_cidr_list']: + if self.rule['type'] == 'all' and not obj['source_cidr_list']: self.rule['cidr'] = [] else: self.rule['cidr'] = obj['source_cidr_list'] diff --git a/systemvm/debian/opt/cloud/bin/setup/common.sh b/systemvm/debian/opt/cloud/bin/setup/common.sh index e24642fc6035..987f07d7659d 100755 --- a/systemvm/debian/opt/cloud/bin/setup/common.sh +++ b/systemvm/debian/opt/cloud/bin/setup/common.sh @@ -567,14 +567,12 @@ setup_ntp() { if [ -f $NTP_CONF_FILE ] then IFS=',' read -a server_list <<< "$NTP_SERVER_LIST" + sed -i "/^server /d" $NTP_CONF_FILE for (( iterator=${#server_list[@]}-1 ; iterator>=0 ; iterator-- )) do server=$(echo ${server_list[iterator]} | tr -d '\r') PATTERN="server $server" - if grep -q "^$PATTERN$" $NTP_CONF_FILE ; then - sed -i "/^$PATTERN$/d" $NTP_CONF_FILE - fi - sed -i "0,/^server/s//$PATTERN\nserver/" $NTP_CONF_FILE + sed -i "0,/^#server/s//$PATTERN\n#server/" $NTP_CONF_FILE done systemctl enable ntp else diff --git a/systemvm/debian/opt/cloud/bin/setup/router.sh b/systemvm/debian/opt/cloud/bin/setup/router.sh index 7c9549354e11..e8f6edf0ceb5 100755 --- a/systemvm/debian/opt/cloud/bin/setup/router.sh +++ b/systemvm/debian/opt/cloud/bin/setup/router.sh @@ -100,6 +100,13 @@ setup_router() { mv -n /etc/cron.daily/logrotate /etc/cron.hourly 2>&1 fi + # Setup hourly lograte in systemd timer + sed -i 's/OnCalendar=daily/OnCalendar=hourly/g' /usr/lib/systemd/system/logrotate.timer + sed -i 's/AccuracySec=12h/AccuracySec=5m/g' /usr/lib/systemd/system/logrotate.timer + + # reload daemon + /usr/bin/systemctl daemon-reload + # Load modules to support NAT traversal in VR modprobe nf_nat_pptp } diff --git a/systemvm/debian/opt/cloud/bin/setup/vpcrouter.sh b/systemvm/debian/opt/cloud/bin/setup/vpcrouter.sh index 68877821fb32..f97fb161f47f 100755 --- a/systemvm/debian/opt/cloud/bin/setup/vpcrouter.sh +++ b/systemvm/debian/opt/cloud/bin/setup/vpcrouter.sh @@ -113,6 +113,13 @@ EOF mv -n /etc/cron.daily/logrotate /etc/cron.hourly 2>&1 fi + # Setup hourly lograte in systemd timer + sed -i 's/OnCalendar=daily/OnCalendar=hourly/g' /usr/lib/systemd/system/logrotate.timer + sed -i 's/AccuracySec=12h/AccuracySec=5m/g' /usr/lib/systemd/system/logrotate.timer + + # reload daemon + /usr/bin/systemctl daemon-reload + # Load modules to support NAT traversal in VR modprobe nf_nat_pptp } diff --git a/test/integration/component/test_acl_isolatednetwork.py b/test/integration/component/test_acl_isolatednetwork.py index a1deb93b2623..2347b27a2ea9 100644 --- a/test/integration/component/test_acl_isolatednetwork.py +++ b/test/integration/component/test_acl_isolatednetwork.py @@ -926,7 +926,7 @@ def test_20_1_deployvm_user_incrossnetwork(self): self.cleanup.append(vm) self.fail("User is allowed to deploy VM in a network that is not self-owned ") except Exception as e: - self.debug("When user tries to deploy vm in a network that does not belong to him %s" % e) + self.debug("When user tries to deploy vm in a network that does not belong to the user %s" % e) if not CloudstackAclException.verifyMsginException(e, CloudstackAclException.UNABLE_TO_USE_NETWORK): self.fail("Error message validation failed when User is allowed to deploy VM in a network that is not self-owned ") diff --git a/test/integration/component/test_configdrive.py b/test/integration/component/test_configdrive.py index 316fbe98c980..fed69081199d 100644 --- a/test/integration/component/test_configdrive.py +++ b/test/integration/component/test_configdrive.py @@ -106,12 +106,12 @@ def __init__(self): self.services = { "test_templates": { "kvm": { - "name": "Centos-5.5-configdrive", - "displaytext": "ConfigDrive enabled CentOS", + "name": "Centos-5.5-sshkey-and-configdrive", + "displaytext": "SSHkey and ConfigDrive enabled CentOS", "format": "qcow2", "hypervisor": "kvm", "ostype": "CentOS 5.5 (64-bit)", - "url": "http://people.apache.org/~fmaximus/centos55-extended.qcow2.bz2", + "url": "http://people.apache.org/~weizhou/centos55-sshkey-configdrive.qcow2.bz2", "requireshvm": "False", "ispublic": "True", "isextractable": "True" @@ -655,8 +655,7 @@ def given_template_password_enabled_is(self, new_state): orig_state = self.template.passwordenabled self.debug("Updating guest VM template to password enabled " "from %s to %s" % (orig_state, new_state)) - if orig_state != new_state: - self.update_template(passwordenabled=new_state) + self.update_template(passwordenabled=new_state) self.assertEqual(self.template.passwordenabled, new_state, "Guest VM template is not password enabled") return orig_state @@ -852,7 +851,7 @@ def then_config_drive_is_as_expected(self, vm, self.debug("SSHing into the VM %s" % vm.name) - ssh = self.ssh_into_VM(vm, public_ip, reconnect=reconnect) + ssh = self.ssh_into_VM(vm, public_ip, reconnect=reconnect, keypair=vm.key_pair) d = {x.name: x for x in ssh.logger.handlers} ssh.logger.handlers = list(d.values()) @@ -976,6 +975,7 @@ def plug_nic(self, vm, network): vm.add_nic(self.api_client, network.id) self.debug("Added NIC in VM with ID - %s and network with ID - %s" % (vm.id, network.id)) + vm.password_test = ConfigDriveUtils.PasswordTest(expect_pw=False) def unplug_nic(self, vm, network): nic = self._find_nic(vm, network) @@ -1532,12 +1532,14 @@ def ssh_into_VM(self, vm, public_ip, reconnect=True, self.debug("SSH into VM with ID - %s on public IP address - %s" % (vm.id, public_ip.ipaddress.ipaddress)) tries = 1 if negative_test else 3 + private_key_file_location = keypair.private_key_file if keypair else None @retry(tries=tries) def retry_ssh(): ssh_client = vm.get_ssh_client( ipaddress=public_ip.ipaddress.ipaddress, reconnect=reconnect, + keyPairFileLocation=private_key_file_location, retries=3 if negative_test else 30 ) self.debug("Successful to SSH into VM with ID - %s on " @@ -1704,6 +1706,7 @@ def migrate_VM(self, vm): "%s to Host: %s" % (vm.id, host.id)) try: vm.migrate(self.api_client, hostid=host.id) + vm.password_test = ConfigDriveUtils.PasswordTest(expect_pw=False) except Exception as e: self.fail("Failed to migrate instance, %s" % e) self.debug("Migrated VM with ID: " @@ -1919,7 +1922,8 @@ def test_configdrive_isolated_network(self): # ===================================================================== self.debug("+++ Scenario: " "update userdata and reset password after migrate") - self.migrate_VM(vm1) + host = self.migrate_VM(vm1) + vm1.hostname = host.name self.then_config_drive_is_as_expected(vm1, public_ip_1, metadata=True) self.debug("Updating userdata after migrating VM - %s" % vm1.name) self.update_and_validate_userdata(vm1, "hello after migrate", @@ -1957,7 +1961,7 @@ def test_configdrive_isolated_network(self): # ===================================================================== self.debug("+++ Scenario: " "Update Userdata on a VM that is not password enabled") - self.update_template(passwordenabled=False) + self.given_template_password_enabled_is(False) vm1 = self.when_I_deploy_a_vm_with_keypair_in(network1) public_ip_1 = \ @@ -2114,7 +2118,8 @@ def test_configdrive_vpc_network(self): # ===================================================================== self.debug("+++ Scenario: " "update userdata and reset password after migrate") - self.migrate_VM(vm) + host = self.migrate_VM(vm) + vm.hostname = host.name self.then_config_drive_is_as_expected(vm, public_ip_1, metadata=True) self.update_and_validate_userdata(vm, "hello migrate", public_ip_1) @@ -2152,7 +2157,7 @@ def test_configdrive_vpc_network(self): self.debug("+++ Scenario: " "Update Userdata on a VM that is not password enabled") - self.update_template(passwordenabled=False) + self.given_template_password_enabled_is(False) vm = self.when_I_deploy_a_vm(network1, keypair=self.keypair.name) @@ -2287,7 +2292,7 @@ def test_configdrive_shared_network(self): self.delete(vm1, expunge=True) self.given_config_drive_provider_is("Enabled") - self.update_template(passwordenabled=False) + self.given_template_password_enabled_is(False) vm1 = self.create_VM( [shared_network.network], @@ -2364,6 +2369,7 @@ def test_configdrive_isolated_network_hypervisor_hostname_exposed(self): self.debug("+++Deploy VM in the created Isolated network " "with user data provider as configdrive") + self.given_template_password_enabled_is(True) vm1 = self.when_I_deploy_a_vm(network1) public_ip_1 = self.when_I_create_a_static_nat_ip_to(vm1, network1) @@ -2477,6 +2483,7 @@ def test_configdrive_vpc_network_verify_metadata(self): # ===================================================================== self.debug("+++ Scenario: " "Deploy VM in the Tier 1 with user data") + self.given_template_password_enabled_is(True) vm = self.when_I_deploy_a_vm(network1) public_ip_1 = self.when_I_create_a_static_nat_ip_to(vm, network1) diff --git a/test/integration/smoke/test_direct_download.py b/test/integration/smoke/test_direct_download.py index 324fb5972cb2..b894f08934b2 100644 --- a/test/integration/smoke/test_direct_download.py +++ b/test/integration/smoke/test_direct_download.py @@ -184,20 +184,28 @@ def setUpClass(cls): cls.services["service_offerings"]["tiny"] ) cls._cleanup.append(cls.service_offering) - cls.network_offering = NetworkOffering.create( - cls.apiclient, - cls.services["l2-network_offering"], - ) - cls.network_offering.update(cls.apiclient, state='Enabled') - cls.services["network"]["networkoffering"] = cls.network_offering.id - cls.l2_network = Network.create( - cls.apiclient, - cls.services["l2-network"], - zoneid=cls.zone.id, - networkofferingid=cls.network_offering.id - ) - cls._cleanup.append(cls.l2_network) - cls._cleanup.append(cls.network_offering) + + if cls.zone.networktype == 'Basic' : + networks = Network.list(cls.apiclient) + if len(networks) == 0 : + self.skipTest("Skipping test since no network found in basic zone") + else : + cls.network = networks[0] + else : + cls.network_offering = NetworkOffering.create( + cls.apiclient, + cls.services["l2-network_offering"], + ) + cls._cleanup.append(cls.network_offering) + cls.network_offering.update(cls.apiclient, state='Enabled') + cls.services["network"]["networkoffering"] = cls.network_offering.id + cls.network = Network.create( + cls.apiclient, + cls.services["l2-network"], + zoneid=cls.zone.id, + networkofferingid=cls.network_offering.id + ) + cls._cleanup.append(cls.network) storage_pools = StoragePool.list( cls.apiclient, @@ -221,11 +229,7 @@ def setUpClass(cls): @classmethod def tearDownClass(cls): - try: - cleanup_resources(cls.apiclient, cls._cleanup) - except Exception as e: - raise Exception("Warning: Exception during cleanup : %s" % e) - return + super(TestDirectDownloadTemplates, cls).tearDownClass() def setUp(self): self.apiclient = self.testClient.getApiClient() @@ -234,11 +238,7 @@ def setUp(self): return def tearDown(self): - try: - cleanup_resources(self.apiclient, self.cleanup) - except Exception as e: - raise Exception("Warning: Exception during cleanup : %s" % e) - return + super(TestDirectDownloadTemplates, self).tearDown() def getCurrentStoragePoolTags(self, poolId): local_pool = StoragePool.list( @@ -269,6 +269,22 @@ def createServiceOffering(self, name, type, tags): tags=tags ) + def deployVM(self, offering) : + if self.zone.networktype == 'Basic' : + vm = VirtualMachine.create( + self.apiclient, + self.services["virtual_machine"], + serviceofferingid=offering.id + ) + else : + vm = VirtualMachine.create( + self.apiclient, + self.services["virtual_machine"], + serviceofferingid=offering.id, + networkids=self.network.id + ) + self.cleanup.append(vm) + return vm @skipTestIf("nfsKvmNotAvailable") @attr(tags=["advanced", "basic", "eip", "advancedns", "sg"], required_hardware="false") @@ -282,12 +298,7 @@ def test_01_deploy_vm_from_direct_download_template_nfs_storage(self): self.updateStoragePoolTags(self.nfsPoolId, test_tag) nfs_storage_offering = self.createServiceOffering("TestNFSStorageDirectDownload", "shared", test_tag) - vm = VirtualMachine.create( - self.apiclient, - self.services["virtual_machine"], - serviceofferingid=nfs_storage_offering.id, - networkids=self.l2_network.id - ) + vm = self.deployVM(nfs_storage_offering) self.assertEqual( vm.state, "Running", @@ -296,7 +307,6 @@ def test_01_deploy_vm_from_direct_download_template_nfs_storage(self): # Revert storage tags for the storage pool used in this test self.updateStoragePoolTags(self.nfsPoolId, tags) - self.cleanup.append(vm) self.cleanup.append(nfs_storage_offering) return @@ -313,12 +323,7 @@ def test_02_deploy_vm_from_direct_download_template_local_storage(self): local_storage_offering = self.createServiceOffering("TestLocalStorageDirectDownload", "local", test_tag) # Deploy VM - vm = VirtualMachine.create( - self.apiclient, - self.services["virtual_machine"], - serviceofferingid=local_storage_offering.id, - networkids=self.l2_network.id, - ) + vm = self.deployVM(local_storage_offering) self.assertEqual( vm.state, "Running", @@ -327,7 +332,6 @@ def test_02_deploy_vm_from_direct_download_template_local_storage(self): # Revert storage tags for the storage pool used in this test self.updateStoragePoolTags(self.localPoolId, tags) - self.cleanup.append(vm) self.cleanup.append(local_storage_offering) return diff --git a/test/integration/smoke/test_domain_network_offerings.py b/test/integration/smoke/test_domain_network_offerings.py index 0bab9a12c1d6..d2d6120697f4 100644 --- a/test/integration/smoke/test_domain_network_offerings.py +++ b/test/integration/smoke/test_domain_network_offerings.py @@ -274,7 +274,6 @@ def test_02_edit_network_offering(self): @attr( tags=[ "advanced", - "basic", "eip", "sg", "advancedns", diff --git a/test/integration/smoke/test_domain_vpc_offerings.py b/test/integration/smoke/test_domain_vpc_offerings.py index 928c24accb73..f3d31b2bf7e9 100644 --- a/test/integration/smoke/test_domain_vpc_offerings.py +++ b/test/integration/smoke/test_domain_vpc_offerings.py @@ -319,7 +319,6 @@ def test_02_edit_vpc_offering(self): @attr( tags=[ "advanced", - "basic", "eip", "sg", "advancedns", diff --git a/test/integration/smoke/test_persistent_network.py b/test/integration/smoke/test_persistent_network.py index cf14b04b5635..65f37bfa0e15 100644 --- a/test/integration/smoke/test_persistent_network.py +++ b/test/integration/smoke/test_persistent_network.py @@ -52,6 +52,22 @@ def setUpClass(cls): cls.testClient = super(TestL2PersistentNetworks, cls).getClsTestClient() cls.api_client = cls.testClient.getApiClient() cls.hypervisor = cls.testClient.getHypervisorInfo() + + isKVM = cls.hypervisor.lower() in ["kvm"] + isOVSEnabled = False + hostConfig = cls.config.__dict__["zones"][0].__dict__["pods"][0].__dict__["clusters"][0].__dict__["hosts"][0].__dict__ + if isKVM : + # Test only if all the hosts use OVS + grepCmd = 'grep "network.bridge.type=openvswitch" /etc/cloudstack/agent/agent.properties' + hosts = list_hosts(cls.api_client, type='Routing', hypervisor='kvm') + for host in hosts : + if len(SshClient(host.ipaddress, port=22, user=hostConfig["username"], + passwd=hostConfig["password"]).execute(grepCmd)) != 0 : + isOVSEnabled = True + break + if isKVM and isOVSEnabled : + cls.skipTest(cls, "KVM with OVS doesn't support persistent networks, skipping") + # Fill services from the external config file cls.services = cls.testClient.getParsedTestDataConfig() cls.hostConfig = cls.config.__dict__["zones"][0].__dict__["pods"][0].__dict__["clusters"][0].__dict__["hosts"][ @@ -152,7 +168,7 @@ def list_all_hosts_in_zone(self, zone_id): return hosts ''' - Verifies creation of bridge on KVM host + Verifies creation of bridge on KVM host ''' def verify_bridge_creation(self, host, vlan_id): username = self.hostConfig["username"] @@ -186,7 +202,7 @@ def get_port_group_name(self, switch_type, vlan_id, network_rate): return None ''' - Verifies creation of port group on the Distributed vSwitch or a host in a cluster connected to + Verifies creation of port group on the Distributed vSwitch or a host in a cluster connected to a Standard vSwitch ''' def verify_port_group_creation(self, vlan_id): @@ -264,7 +280,7 @@ def verify_network_setup_on_host_per_cluster(self, hypervisor, vlan_id): "Failed to find port group on hosts of cluster: " + cluster.name) ''' - This test verifies that on creation of an Isolated network with network offering with isPersistent flag + This test verifies that on creation of an Isolated network with network offering with isPersistent flag set to true the corresponding network resources are created without having to deploy a VM - VR created ''' @attr(tags=["advanced", "isolated", "persistent", "network"], required_hardware="false") @@ -303,7 +319,7 @@ def test_01_isolated_persistent_network(self): self.verify_network_setup_on_host_per_cluster(host.hypervisor.lower(), networkVlan) ''' - This test verifies that on creation of an L2 network with network offering with isPersistent flag + This test verifies that on creation of an L2 network with network offering with isPersistent flag set to true the corresponding network resources are created without having to deploy a VM - VR created ''' @attr(tags=["advanced", "l2", "persistent", "network"], required_hardware="false") diff --git a/test/integration/smoke/test_primary_storage.py b/test/integration/smoke/test_primary_storage.py index 7c0a9487af67..4e630b70a78d 100644 --- a/test/integration/smoke/test_primary_storage.py +++ b/test/integration/smoke/test_primary_storage.py @@ -256,6 +256,9 @@ def test_01_add_primary_storage_disabled_host(self): """Test add primary storage pool with disabled host """ + if self.zone.localstorageenabled : + self.skipTest("Skipping since localstorageenabled") + # Disable a host clusters = list_clusters( self.apiclient, diff --git a/test/integration/smoke/test_vm_life_cycle.py b/test/integration/smoke/test_vm_life_cycle.py index d6a78907ad5d..61b3a22a6c8e 100644 --- a/test/integration/smoke/test_vm_life_cycle.py +++ b/test/integration/smoke/test_vm_life_cycle.py @@ -613,6 +613,9 @@ def test_08_migrate_vm(self): # 2. DeployVM on suitable host (with another host in the cluster) # 3. Migrate the VM and assert migration successful + if self.zone.localstorageenabled : + self.skipTest("Migration is not supported on zones with local storage") + suitable_hosts = None hosts = Host.list( diff --git a/test/integration/smoke/test_volumes.py b/test/integration/smoke/test_volumes.py index 107403e2df3d..e1d419ff150b 100644 --- a/test/integration/smoke/test_volumes.py +++ b/test/integration/smoke/test_volumes.py @@ -16,41 +16,42 @@ # under the License. """ BVT tests for Volumes """ -#Import Local Modules -from marvin.cloudstackTestCase import cloudstackTestCase +import os +import tempfile +import time import unittest -#from marvin.cloudstackException import * +import urllib.error +import urllib.parse +import urllib.request + from marvin.cloudstackAPI import (deleteVolume, extractVolume, resizeVolume) -#from marvin.sshClient import SshClient -from marvin.lib.utils import (cleanup_resources, - format_volume_to_ext3, - wait_until) + +from marvin.cloudstackTestCase import cloudstackTestCase +from marvin.codes import SUCCESS, FAILED, XEN_SERVER from marvin.lib.base import (ServiceOffering, VirtualMachine, Account, Volume, Host, DiskOffering, - StoragePool,) + StoragePool) from marvin.lib.common import (get_domain, - get_suitable_test_template, - get_zone, - find_storage_pool_type, - get_pod, - list_disk_offering) + get_suitable_test_template, + get_zone, + find_storage_pool_type, + get_pod, + list_disk_offering) from marvin.lib.utils import checkVolumeSize -from marvin.codes import SUCCESS, FAILED, XEN_SERVER +from marvin.lib.utils import (format_volume_to_ext3, + wait_until) + from nose.plugins.attrib import attr -#Import System modules -import os -import urllib.request, urllib.parse, urllib.error -import time -import tempfile _multiprocess_shared_ = True + class TestCreateVolume(cloudstackTestCase): @classmethod @@ -65,25 +66,28 @@ def setUpClass(cls): cls.hypervisor = testClient.getHypervisorInfo() cls.services['mode'] = cls.zone.networktype cls.invalidStoragePoolType = False - #for LXC if the storage pool of type 'rbd' ex: ceph is not available, skip the test + # for LXC if the storage pool of type 'rbd' ex: ceph is not available, skip the test if cls.hypervisor.lower() == 'lxc': if not find_storage_pool_type(cls.apiclient, storagetype='rbd'): # RBD storage type is required for data volumes for LXC cls.invalidStoragePoolType = True return cls.disk_offering = DiskOffering.create( - cls.apiclient, - cls.services["disk_offering"] - ) + cls.apiclient, + cls.services["disk_offering"] + ) + cls._cleanup.append(cls.disk_offering) cls.sparse_disk_offering = DiskOffering.create( - cls.apiclient, - cls.services["sparse_disk_offering"] - ) + cls.apiclient, + cls.services["sparse_disk_offering"] + ) + cls._cleanup.append(cls.sparse_disk_offering) cls.custom_disk_offering = DiskOffering.create( - cls.apiclient, - cls.services["disk_offering"], - custom=True - ) + cls.apiclient, + cls.services["disk_offering"], + custom=True + ) + cls._cleanup.append(cls.custom_disk_offering) template = get_suitable_test_template( cls.apiclient, @@ -101,28 +105,24 @@ def setUpClass(cls): cls.services["diskname"] = cls.services["volume"]["diskname"] # Create VMs, NAT Rules etc cls.account = Account.create( - cls.apiclient, - cls.services["account"], - domainid=cls.domain.id - ) + cls.apiclient, + cls.services["account"], + domainid=cls.domain.id + ) + cls._cleanup.append(cls.account) cls.service_offering = ServiceOffering.create( - cls.apiclient, - cls.services["service_offerings"]["tiny"] - ) + cls.apiclient, + cls.services["service_offerings"]["tiny"] + ) cls.virtual_machine = VirtualMachine.create( - cls.apiclient, - cls.services, - accountid=cls.account.name, - domainid=cls.account.domainid, - serviceofferingid=cls.service_offering.id, - mode=cls.services["mode"] - ) - cls._cleanup = [ - cls.service_offering, - cls.disk_offering, - cls.custom_disk_offering, - cls.account - ] + cls.apiclient, + cls.services, + accountid=cls.account.name, + domainid=cls.account.domainid, + serviceofferingid=cls.service_offering.id, + mode=cls.services["mode"] + ) + cls._cleanup.append(cls.virtual_machine) def setUp(self): @@ -134,81 +134,81 @@ def setUp(self): self.skipTest("Skipping test because of valid storage\ pool not available") - @attr(tags = ["advanced", "advancedns", "smoke", "basic"], required_hardware="true") + @attr(tags=["advanced", "advancedns", "smoke", "basic"], required_hardware="true") def test_01_create_volume(self): """Test Volume creation for all Disk Offerings (incl. custom) - """ # Validate the following # 1. Create volumes from the different sizes # 2. Verify the size of volume with actual size allocated + """ self.volumes = [] for k, v in list(self.services["volume_offerings"].items()): volume = Volume.create( - self.apiClient, - v, - zoneid=self.zone.id, - account=self.account.name, - domainid=self.account.domainid, - diskofferingid=self.disk_offering.id - ) - self.debug("Created a volume with ID: %s" % volume.id) + self.apiClient, + v, + zoneid=self.zone.id, + account=self.account.name, + domainid=self.account.domainid, + diskofferingid=self.disk_offering.id + ) self.volumes.append(volume) + self.debug("Created a volume with ID: %s" % volume.id) if self.virtual_machine.hypervisor == "KVM": sparse_volume = Volume.create( - self.apiClient, - self.services, - zoneid=self.zone.id, - account=self.account.name, - domainid=self.account.domainid, - diskofferingid=self.sparse_disk_offering.id - ) - self.debug("Created a sparse volume: %s" % sparse_volume.id) + self.apiClient, + self.services, + zoneid=self.zone.id, + account=self.account.name, + domainid=self.account.domainid, + diskofferingid=self.sparse_disk_offering.id + ) self.volumes.append(sparse_volume) + self.debug("Created a sparse volume: %s" % sparse_volume.id) volume = Volume.create_custom_disk( - self.apiClient, - self.services, - account=self.account.name, - domainid=self.account.domainid, - ) - self.debug("Created a volume with custom offering: %s" % volume.id) + self.apiClient, + self.services, + account=self.account.name, + domainid=self.account.domainid, + ) self.volumes.append(volume) + self.debug("Created a volume with custom offering: %s" % volume.id) - #Attach a volume with different disk offerings - #and check the memory allocated to each of them + # Attach a volume with different disk offerings + # and check the memory allocated to each of them for volume in self.volumes: list_volume_response = Volume.list( - self.apiClient, - id=volume.id) + self.apiClient, + id=volume.id) self.assertEqual( - isinstance(list_volume_response, list), - True, - "Check list response returns a valid list" - ) + isinstance(list_volume_response, list), + True, + "Check list response returns a valid list" + ) self.assertNotEqual( - list_volume_response, - None, - "Check if volume exists in ListVolumes" - ) + list_volume_response, + None, + "Check if volume exists in ListVolumes" + ) self.debug( "Attaching volume (ID: %s) to VM (ID: %s)" % ( - volume.id, - self.virtual_machine.id - )) + volume.id, + self.virtual_machine.id + )) self.virtual_machine.attach_volume( - self.apiClient, - volume - ) + self.apiClient, + volume + ) try: ssh = self.virtual_machine.get_ssh_client() self.debug("Rebooting VM %s" % self.virtual_machine.id) ssh.execute("reboot") except Exception as e: self.fail("SSH access failed for VM %s - %s" % - (self.virtual_machine.ipaddress, e)) + (self.virtual_machine.ipaddress, e)) # Poll listVM to ensure VM is started properly timeout = self.services["timeout"] @@ -217,9 +217,9 @@ def test_01_create_volume(self): # Ensure that VM is in running state list_vm_response = VirtualMachine.list( - self.apiClient, - id=self.virtual_machine.id - ) + self.apiClient, + id=self.virtual_machine.id + ) if isinstance(list_vm_response, list): vm = list_vm_response[0] @@ -234,41 +234,35 @@ def test_01_create_volume(self): vol_sz = str(list_volume_response[0].size) ssh = self.virtual_machine.get_ssh_client( - reconnect=True - ) + reconnect=True + ) # Get the updated volume information list_volume_response = Volume.list( - self.apiClient, - id=volume.id) + self.apiClient, + id=volume.id) if list_volume_response[0].hypervisor.lower() == XEN_SERVER.lower(): volume_name = "/dev/xvd" + chr(ord('a') + int(list_volume_response[0].deviceid)) self.debug(" Using XenServer volume_name: %s" % (volume_name)) - ret = checkVolumeSize(ssh_handle=ssh,volume_name=volume_name,size_to_verify=vol_sz) + ret = checkVolumeSize(ssh_handle=ssh, volume_name=volume_name, size_to_verify=vol_sz) elif list_volume_response[0].hypervisor.lower() == "kvm": volume_name = "/dev/vd" + chr(ord('a') + int(list_volume_response[0].deviceid)) self.debug(" Using KVM volume_name: %s" % (volume_name)) - ret = checkVolumeSize(ssh_handle=ssh,volume_name=volume_name,size_to_verify=vol_sz) + ret = checkVolumeSize(ssh_handle=ssh, volume_name=volume_name, size_to_verify=vol_sz) elif list_volume_response[0].hypervisor.lower() == "hyperv": - ret = checkVolumeSize(ssh_handle=ssh,volume_name="/dev/sdb",size_to_verify=vol_sz) + ret = checkVolumeSize(ssh_handle=ssh, volume_name="/dev/sdb", size_to_verify=vol_sz) else: - ret = checkVolumeSize(ssh_handle=ssh,size_to_verify=vol_sz) - self.debug(" Volume Size Expected %s Actual :%s" %(vol_sz,ret[1])) + ret = checkVolumeSize(ssh_handle=ssh, size_to_verify=vol_sz) + self.debug(" Volume Size Expected %s Actual :%s" % (vol_sz, ret[1])) self.virtual_machine.detach_volume(self.apiClient, volume) - self.assertEqual(ret[0],SUCCESS,"Check if promised disk size actually available") + self.assertEqual(ret[0], SUCCESS, "Check if promised disk size actually available") time.sleep(self.services["sleep"]) def tearDown(self): - #Clean up, terminate the created volumes - cleanup_resources(self.apiClient, self.cleanup) - return + super(TestCreateVolume, self).tearDown() @classmethod def tearDownClass(cls): - try: - cls.apiclient = super(TestCreateVolume, cls).getClsTestClient().getApiClient() - cleanup_resources(cls.apiclient, cls._cleanup) - except Exception as e: - raise Exception("Warning: Exception during cleanup : %s" % e) + super(TestCreateVolume, cls).tearDownClass() class TestVolumes(cloudstackTestCase): @@ -285,25 +279,28 @@ def setUpClass(cls): cls.services['mode'] = cls.zone.networktype cls.hypervisor = testClient.getHypervisorInfo() cls.invalidStoragePoolType = False - #for LXC if the storage pool of type 'rbd' ex: ceph is not available, skip the test + # for LXC if the storage pool of type 'rbd' ex: ceph is not available, skip the test if cls.hypervisor.lower() == 'lxc': if not find_storage_pool_type(cls.apiclient, storagetype='rbd'): # RBD storage type is required for data volumes for LXC cls.invalidStoragePoolType = True return cls.disk_offering = DiskOffering.create( - cls.apiclient, - cls.services["disk_offering"] - ) + cls.apiclient, + cls.services["disk_offering"] + ) + cls._cleanup.append(cls.disk_offering) cls.resized_disk_offering = DiskOffering.create( - cls.apiclient, - cls.services["resized_disk_offering"] - ) + cls.apiclient, + cls.services["resized_disk_offering"] + ) + cls._cleanup.append(cls.resized_disk_offering) cls.custom_resized_disk_offering = DiskOffering.create( - cls.apiclient, - cls.services["resized_disk_offering"], - custom=True - ) + cls.apiclient, + cls.services["resized_disk_offering"], + custom=True + ) + cls._cleanup.append(cls.custom_resized_disk_offering) cls.template = get_suitable_test_template( cls.apiclient, @@ -324,53 +321,40 @@ def setUpClass(cls): # Create VMs, VMs etc cls.account = Account.create( - cls.apiclient, - cls.services["account"], - domainid=cls.domain.id - ) + cls.apiclient, + cls.services["account"], + domainid=cls.domain.id + ) + cls._cleanup.append(cls.account) cls.service_offering = ServiceOffering.create( - cls.apiclient, - cls.services["service_offerings"]["tiny"] - ) + cls.apiclient, + cls.services["service_offerings"]["tiny"] + ) + cls._cleanup.append(cls.service_offering) cls.virtual_machine = VirtualMachine.create( - cls.apiclient, - cls.services, - accountid=cls.account.name, - domainid=cls.account.domainid, - serviceofferingid=cls.service_offering.id, - mode=cls.services["mode"] - ) + cls.apiclient, + cls.services, + accountid=cls.account.name, + domainid=cls.account.domainid, + serviceofferingid=cls.service_offering.id, + mode=cls.services["mode"] + ) + cls._cleanup.append(cls.virtual_machine) pools = StoragePool.list(cls.apiclient) - # cls.assertEqual( - # validateList(pools)[0], - # PASS, - # "storage pool list validation failed") - - if cls.hypervisor.lower() == 'lxc' and cls.storage_pools.type.lower() != 'rbd': raise unittest.SkipTest("Snapshots not supported on Hyper-V or LXC") cls.volume = Volume.create( - cls.apiclient, - cls.services, - account=cls.account.name, - domainid=cls.account.domainid - ) - cls._cleanup = [ - cls.resized_disk_offering, - cls.custom_resized_disk_offering, - cls.service_offering, - cls.disk_offering, - cls.volume, - cls.account - ] + cls.apiclient, + cls.services, + account=cls.account.name, + domainid=cls.account.domainid + ) + cls._cleanup.append(cls.volume) @classmethod def tearDownClass(cls): - try: - cleanup_resources(cls.apiclient, cls._cleanup) - except Exception as e: - raise Exception("Warning: Exception during cleanup : %s" % e) + super(TestVolumes, cls).tearDownClass() def setUp(self): self.apiClient = self.testClient.getApiClient() @@ -383,25 +367,29 @@ def setUp(self): available") def tearDown(self): - #Clean up, terminate the created volumes - if self.attached: - self.virtual_machine.detach_volume(self.apiClient, self.volume) - if self.virtual_machine.hypervisor == "KVM": self.virtual_machine.stop(self.apiClient) + if self.attached: + self.virtual_machine.detach_volume(self.apiClient, self.volume) self.virtual_machine.start(self.apiClient) + try: + self.virtual_machine.get_ssh_client(reconnect=True) + except Exception as err: + self.fail("SSH failed for Virtual machine: %s due to %s" % + (self.virtual_machine.ipaddress, err)) + elif self.attached: + self.virtual_machine.detach_volume(self.apiClient, self.volume) - cleanup_resources(self.apiClient, self.cleanup) - return + super(TestVolumes, self).tearDown() - @attr(tags = ["advanced", "advancedns", "smoke", "basic"], required_hardware="true") + @attr(tags=["advanced", "advancedns", "smoke", "basic"], required_hardware="true") def test_02_attach_volume(self): """Attach a created Volume to a Running VM - """ # Validate the following # 1. shows list of volumes # 2. "Attach Disk" pop-up box will display with list of instances # 3. disk should be attached to instance successfully + """ self.debug( "Attaching volume (ID: %s) to VM (ID: %s)" % ( @@ -431,7 +419,7 @@ def test_02_attach_volume(self): "Check if volume state (attached) is reflected" ) try: - #Format the attached volume to a known fs + # Format the attached volume to a known fs format_volume_to_ext3(self.virtual_machine.get_ssh_client()) except Exception as e: @@ -440,14 +428,14 @@ def test_02_attach_volume(self): (self.virtual_machine.ipaddress, e)) return - @attr(tags = ["advanced", "advancedns", "smoke", "basic"], required_hardware="false") + @attr(tags=["advanced", "advancedns", "smoke", "basic"], required_hardware="false") def test_03_download_attached_volume(self): """Download a Volume attached to a VM - """ # Validate the following # 1. download volume will fail with proper error message # "Failed - Invalid state of the volume with ID: # It should be either detached or the VM should be in stopped state + """ self.debug("Extract attached Volume ID: %s" % self.volume.id) @@ -462,84 +450,84 @@ def test_03_download_attached_volume(self): with self.assertRaises(Exception): self.apiClient.extractVolume(cmd) - @attr(tags = ["advanced", "advancedns", "smoke", "basic"], required_hardware="false") + @attr(tags=["advanced", "advancedns", "smoke", "basic"], required_hardware="false") def test_04_delete_attached_volume(self): """Delete a Volume attached to a VM - """ # Validate the following # 1. delete volume will fail with proper error message # "Failed - Invalid state of the volume with ID: # It should be either detached or the VM should be in stopped state + """ self.debug("Trying to delete attached Volume ID: %s" % - self.volume.id) + self.volume.id) self.virtual_machine.attach_volume(self.apiClient, self.volume) self.attached = True cmd = deleteVolume.deleteVolumeCmd() cmd.id = self.volume.id - #Proper exception should be raised; deleting attach VM is not allowed - #with self.assertRaises(Exception): + # Proper exception should be raised; deleting attach VM is not allowed + # with self.assertRaises(Exception): with self.assertRaises(Exception): self.apiClient.deleteVolume(cmd) + self._cleanup.remove(self.volume) # when succeeded - @attr(tags = ["advanced", "advancedns", "smoke", "basic"], required_hardware="false") + @attr(tags=["advanced", "advancedns", "smoke", "basic"], required_hardware="false") def test_05_detach_volume(self): """Detach a Volume attached to a VM - """ # Validate the following # Data disk should be detached from instance and detached data disk # details should be updated properly + """ self.debug( - "Detaching volume (ID: %s) from VM (ID: %s)" % ( - self.volume.id, - self.virtual_machine.id - )) + "Detaching volume (ID: %s) from VM (ID: %s)" % ( + self.volume.id, + self.virtual_machine.id)) self.virtual_machine.attach_volume(self.apiClient, self.volume) self.virtual_machine.detach_volume(self.apiClient, self.volume) self.attached = False - #Sleep to ensure the current state will reflected in other calls + # Sleep to ensure the current state will reflected in other calls time.sleep(self.services["sleep"]) list_volume_response = Volume.list( - self.apiClient, - id=self.volume.id - ) + self.apiClient, + id=self.volume.id + ) self.assertEqual( - isinstance(list_volume_response, list), - True, - "Check list response returns a valid list" - ) + isinstance(list_volume_response, list), + True, + "Check list response returns a valid list" + ) self.assertNotEqual( - list_volume_response, - None, - "Check if volume exists in ListVolumes" - ) + list_volume_response, + None, + "Check if volume exists in ListVolumes" + ) volume = list_volume_response[0] self.assertEqual( - volume.virtualmachineid, - None, - "Check if volume state (detached) is reflected" - ) + volume.virtualmachineid, + None, + "Check if volume state (detached) is reflected" + ) return - @attr(tags = ["advanced", "advancedns", "smoke", "basic"], required_hardware="true") + @attr(tags=["advanced", "advancedns", "smoke", "basic"], required_hardware="true") def test_06_download_detached_volume(self): """Download a Volume unattached to an VM + Validate the following + 1. able to download the volume when its not attached to instance """ - # Validate the following - # 1. able to download the volume when its not attached to instance self.debug("Extract detached Volume ID: %s" % self.volume.id) self.virtual_machine.attach_volume(self.apiClient, self.volume) - #Sleep to ensure the current state will reflected in other calls + # Sleep to ensure the current state will reflected in other calls time.sleep(self.services["sleep"]) self.virtual_machine.detach_volume(self.apiClient, self.volume) self.attached = False - #Sleep to ensure the current state will reflected in other calls + # Sleep to ensure the current state will reflected in other calls time.sleep(self.services["sleep"]) cmd = extractVolume.extractVolumeCmd() @@ -548,90 +536,90 @@ def test_06_download_detached_volume(self): cmd.zoneid = self.services["zoneid"] extract_vol = self.apiClient.extractVolume(cmd) - #Attempt to download the volume and save contents locally + # Attempt to download the volume and save contents locally try: formatted_url = urllib.parse.unquote_plus(extract_vol.url) self.debug("Attempting to download volume at url %s" % formatted_url) response = urllib.request.urlopen(formatted_url) self.debug("response from volume url %s" % response.getcode()) fd, path = tempfile.mkstemp() - self.debug("Saving volume %s to path %s" %(self.volume.id, path)) + self.debug("Saving volume %s to path %s" % (self.volume.id, path)) os.close(fd) with open(path, 'wb') as fd: fd.write(response.read()) self.debug("Saved volume successfully") - except Exception: + except Exception as e: self.fail( - "Extract Volume Failed with invalid URL %s (vol id: %s)" \ - % (extract_vol.url, self.volume.id) + "Extract Volume Failed (URL: %s , vol id: %s) due to %s" + % (extract_vol.url, self.volume.id, e) ) - @attr(tags = ["advanced", "advancedns", "smoke", "basic"], required_hardware="true") + @attr(tags=["advanced", "advancedns", "smoke", "basic"], required_hardware="true") def test_07_resize_fail(self): """Test resize (negative) non-existent volume""" # Verify the size is the new size is what we wanted it to be. self.debug("Fail Resize Volume ID: %s" % self.volume.id) # first, an invalid id - cmd = resizeVolume.resizeVolumeCmd() - cmd.id = "invalid id" + cmd = resizeVolume.resizeVolumeCmd() + cmd.id = "invalid id" cmd.diskofferingid = self.services['customresizeddiskofferingid'] - success = False + success = False try: self.apiClient.resizeVolume(cmd) except Exception as ex: - #print str(ex) + # print str(ex) if "invalid" in str(ex): success = True self.assertEqual( - success, - True, - "ResizeVolume - verify invalid id is handled appropriately") + success, + True, + "ResizeVolume - verify invalid id is handled appropriately") # Next, we'll try an invalid disk offering id - cmd.id = self.volume.id + cmd.id = self.volume.id cmd.diskofferingid = "invalid id" - success = False + success = False try: self.apiClient.resizeVolume(cmd) except Exception as ex: if "invalid" in str(ex): success = True self.assertEqual( - success, - True, - "ResizeVolume - verify disk offering is handled appropriately") + success, + True, + "ResizeVolume - verify disk offering is handled appropriately") # try to resize a root disk with a disk offering, root can only be resized by size= # get root vol from created vm list_volume_response = Volume.list( - self.apiClient, - virtualmachineid=self.virtual_machine.id, - type='ROOT', - listall=True - ) + self.apiClient, + virtualmachineid=self.virtual_machine.id, + type='ROOT', + listall=True + ) rootvolume = list_volume_response[0] - cmd.id = rootvolume.id + cmd.id = rootvolume.id cmd.diskofferingid = self.services['diskofferingid'] with self.assertRaises(Exception): self.apiClient.resizeVolume(cmd) # Ok, now let's try and resize a volume that is not custom. - cmd.id = self.volume.id + cmd.id = self.volume.id cmd.diskofferingid = self.services['diskofferingid'] - cmd.size = 4 + cmd.size = 4 self.debug( - "Attaching volume (ID: %s) to VM (ID: %s)" % ( - self.volume.id, - self.virtual_machine.id) - ) - #attach the volume + "Attaching volume (ID: %s) to VM (ID: %s)" % ( + self.volume.id, + self.virtual_machine.id) + ) + # attach the volume self.virtual_machine.attach_volume(self.apiClient, self.volume) self.attached = True - #stop the vm if it is on xenserver + # stop the vm if it is on xenserver hosts = Host.list(self.apiClient, id=self.virtual_machine.hostid) self.assertTrue(isinstance(hosts, list)) self.assertTrue(len(hosts) > 0) @@ -652,16 +640,15 @@ def test_07_resize_fail(self): time.sleep(30) return - - @attr(tags = ["advanced", "advancedns", "smoke", "basic"], required_hardware="true") + @attr(tags=["advanced", "advancedns", "smoke", "basic"], required_hardware="true") def test_08_resize_volume(self): """Test resize a volume""" # Verify the size is the new size is what we wanted it to be. self.debug( - "Attaching volume (ID: %s) to VM (ID: %s)" % ( - self.volume.id, - self.virtual_machine.id - )) + "Attaching volume (ID: %s) to VM (ID: %s)" % ( + self.volume.id, + self.virtual_machine.id + )) self.virtual_machine.attach_volume(self.apiClient, self.volume) self.attached = True @@ -680,13 +667,13 @@ def test_08_resize_volume(self): self.services["disk_offering"]["disksize"] = 20 disk_offering_20_GB = DiskOffering.create( - self.apiclient, - self.services["disk_offering"] - ) + self.apiclient, + self.services["disk_offering"] + ) self.cleanup.append(disk_offering_20_GB) - cmd = resizeVolume.resizeVolumeCmd() - cmd.id = self.volume.id + cmd = resizeVolume.resizeVolumeCmd() + cmd.id = self.volume.id cmd.diskofferingid = disk_offering_20_GB.id self.apiClient.resizeVolume(cmd) @@ -695,12 +682,12 @@ def test_08_resize_volume(self): success = False while count < 3: list_volume_response = Volume.list( - self.apiClient, - id=self.volume.id, - type='DATADISK' - ) + self.apiClient, + id=self.volume.id, + type='DATADISK' + ) for vol in list_volume_response: - if vol.id == self.volume.id and int(vol.size) == (int(disk_offering_20_GB.disksize) * (1024** 3)) and vol.state == 'Ready': + if vol.id == self.volume.id and int(vol.size) == (int(disk_offering_20_GB.disksize) * (1024 ** 3)) and vol.state == 'Ready': success = True if success: break @@ -709,18 +696,18 @@ def test_08_resize_volume(self): count += 1 self.assertEqual( - success, - True, - "Check if the data volume resized appropriately" - ) + success, + True, + "Check if the data volume resized appropriately" + ) can_shrink = False list_volume_response = Volume.list( - self.apiClient, - id=self.volume.id, - type='DATADISK' - ) + self.apiClient, + id=self.volume.id, + type='DATADISK' + ) storage_pool_id = [x.storageid for x in list_volume_response if x.id == self.volume.id][0] storage = StoragePool.list(self.apiclient, id=storage_pool_id)[0] # At present only CLVM supports shrinking volumes @@ -730,15 +717,15 @@ def test_08_resize_volume(self): if can_shrink: self.services["disk_offering"]["disksize"] = 10 disk_offering_10_GB = DiskOffering.create( - self.apiclient, - self.services["disk_offering"] - ) + self.apiclient, + self.services["disk_offering"] + ) self.cleanup.append(disk_offering_10_GB) - cmd = resizeVolume.resizeVolumeCmd() - cmd.id = self.volume.id + cmd = resizeVolume.resizeVolumeCmd() + cmd.id = self.volume.id cmd.diskofferingid = disk_offering_10_GB.id - cmd.shrinkok = "true" + cmd.shrinkok = "true" self.apiClient.resizeVolume(cmd) @@ -746,9 +733,9 @@ def test_08_resize_volume(self): success = False while count < 3: list_volume_response = Volume.list( - self.apiClient, - id=self.volume.id - ) + self.apiClient, + id=self.volume.id + ) for vol in list_volume_response: if vol.id == self.volume.id and int(vol.size) == (int(disk_offering_10_GB.disksize) * (1024 ** 3)) and vol.state == 'Ready': success = True @@ -759,37 +746,38 @@ def test_08_resize_volume(self): count += 1 self.assertEqual( - success, - True, - "Check if the root volume resized appropriately" - ) + success, + True, + "Check if the root volume resized appropriately" + ) - #start the vm if it is on xenserver + # start the vm if it is on xenserver if hosts[0].hypervisor == "XenServer": self.virtual_machine.start(self.apiClient) time.sleep(30) return - @attr(tags = ["advanced", "advancedns", "smoke","basic"], required_hardware="false") + @attr(tags=["advanced", "advancedns", "smoke", "basic"], required_hardware="false") def test_09_delete_detached_volume(self): """Delete a Volume unattached to an VM - """ # Validate the following # 1. volume should be deleted successfully and listVolume should not # contain the deleted volume details. # 2. "Delete Volume" menu item not shown under "Actions" menu. # (UI should not allow to delete the volume when it is attached # to instance by hiding the menu Item) + """ self.debug("Delete Volume ID: %s" % self.volume.id) self.volume_1 = Volume.create( - self.apiclient, - self.services, - account=self.account.name, - domainid=self.account.domainid + self.apiclient, + self.services, + account=self.account.name, + domainid=self.account.domainid ) + self.cleanup.append(self.volume_1) self.virtual_machine.attach_volume(self.apiClient, self.volume_1) self.virtual_machine.detach_volume(self.apiClient, self.volume_1) @@ -797,28 +785,30 @@ def test_09_delete_detached_volume(self): cmd = deleteVolume.deleteVolumeCmd() cmd.id = self.volume_1.id self.apiClient.deleteVolume(cmd) + self.cleanup.remove(self.volume_1) list_volume_response = Volume.list( - self.apiClient, - id=self.volume_1.id, - type='DATADISK' - ) + self.apiClient, + id=self.volume_1.id, + type='DATADISK' + ) self.assertEqual( - list_volume_response, - None, - "Check if volume exists in ListVolumes" - ) + list_volume_response, + None, + "Check if volume exists in ListVolumes" + ) return - @attr(tags = ["advanced", "advancedns", "smoke", "basic"], required_hardware="true") + @attr(tags=["advanced", "advancedns", "smoke", "basic"], required_hardware="true") def test_10_list_volumes(self): - + """ # Validate the following # # 1. List Root Volume and waits until it has the newly introduced attributes # # 2. Verifies return attributes has values different from none, when instance is running # + """ list_vm = VirtualMachine.list(self.apiclient, id=self.virtual_machine.id)[0] @@ -867,15 +857,15 @@ def test_10_list_volumes(self): self.assertTrue(hasattr(root_volume, "podname")) self.assertEqual(root_volume.podname, list_pods.name) - @attr(tags = ["advanced", "advancedns", "smoke", "basic"], required_hardware="true") + @attr(tags=["advanced", "advancedns", "smoke", "basic"], required_hardware="true") def test_11_attach_volume_with_unstarted_vm(self): """Attach a created Volume to a unstarted VM + Validate the following + 1. Attach to a vm in startvm=false state works and vm can be started afterwards. + 2. shows list of volumes + 3. "Attach Disk" pop-up box will display with list of instances + 4. disk should be attached to instance successfully """ - # Validate the following - # 1. Attach to a vm in startvm=false state works and vm can be started afterwards. - # 2. shows list of volumes - # 3. "Attach Disk" pop-up box will display with list of instances - # 4. disk should be attached to instance successfully test_vm = VirtualMachine.create( self.apiclient, @@ -887,6 +877,7 @@ def test_11_attach_volume_with_unstarted_vm(self): mode=self.services["mode"], startvm=False ) + self.cleanup.append(test_vm) self.debug( "Attaching volume (ID: %s) to VM (ID: %s)" % ( @@ -916,11 +907,10 @@ def test_11_attach_volume_with_unstarted_vm(self): None, "Check if volume state (attached) is reflected" ) - #Sleep to ensure the current state will reflected in other calls + # Sleep to ensure the current state will reflected in other calls time.sleep(self.services["sleep"]) test_vm.detach_volume(self.apiClient, self.volume) - self.cleanup.append(test_vm) return @@ -943,34 +933,31 @@ def checkVolumeResponse(): self.fail("Failed to return root volume response") return response - @attr(tags=["advanced", "advancedns", "smoke", "basic"], required_hardware="true") def test_11_migrate_volume_and_change_offering(self): - - # Validates the following - # - # 1. Creates a new Volume with a small disk offering - # - # 2. Migrates the Volume to another primary storage and changes the offering - # - # 3. Verifies the Volume has new offering when migrated to the new storage. + """ + Validates the following + 1. Creates a new Volume with a small disk offering + 2. Migrates the Volume to another primary storage and changes the offering + 3. Verifies the Volume has new offering when migrated to the new storage. + """ small_offering = list_disk_offering( self.apiclient, - name = "Small" + name="Small" )[0] large_offering = list_disk_offering( self.apiclient, - name = "Large" + name="Large" )[0] volume = Volume.create( self.apiClient, self.services, - zoneid = self.zone.id, - account = self.account.name, - domainid = self.account.domainid, - diskofferingid = small_offering.id + zoneid=self.zone.id, + account=self.account.name, + domainid=self.account.domainid, + diskofferingid=small_offering.id ) self.debug("Created a small volume: %s" % volume.id) @@ -982,7 +969,7 @@ def test_11_migrate_volume_and_change_offering(self): pools = StoragePool.listForMigration( self.apiclient, id=volume.id - ) + ) pool = None @@ -1001,17 +988,16 @@ def test_11_migrate_volume_and_change_offering(self): Volume.migrate( self.apiclient, - volumeid = volume.id, - storageid = pool.id, - newdiskofferingid = large_offering.id, - livemigrate = livemigrate + volumeid=volume.id, + storageid=pool.id, + newdiskofferingid=large_offering.id, + livemigrate=livemigrate ) if self.virtual_machine.hypervisor == "KVM": - self.virtual_machine.start(self.apiclient - ) + self.virtual_machine.start(self.apiclient) migrated_vol = Volume.list( self.apiclient, - id = volume.id + id=volume.id )[0] self.assertEqual( migrated_vol.diskofferingname, diff --git a/test/metadata/func/templates_sync.xml b/test/metadata/func/templates_sync.xml index 034ddb9cc219..a03e4bf93b53 100644 --- a/test/metadata/func/templates_sync.xml +++ b/test/metadata/func/templates_sync.xml @@ -20,7 +20,7 @@ under the License. - - + deployVirtualMachine Deploy a VM @@ -69,7 +69,7 @@ under the License. diskofferingid globaldiskofferingid - + templateid globaltemplateid @@ -102,7 +102,7 @@ under the License. - + select id from volumes true @@ -120,7 +120,7 @@ under the License. - + stopVirtualMachine Stop the Virtual Machine @@ -131,8 +131,8 @@ under the License. - - + + createTemplate Create template @@ -169,45 +169,6 @@ under the License. - - - select download_state from template_host_ref - true - Getting volume path for the vm DATADISK volume - - - template_id - privatetemplateid - - - - - download_state - DOWNLOADED - - - - - - - select install_path from template_host_ref - true - Getting install_path from the template - - - template_id - privatetemplateid - - - - - install_path - template_path - - - - - listtemplate.sh @@ -226,8 +187,8 @@ under the License. template_path - - + + removetemplate.sh @@ -247,8 +208,8 @@ under the License. - - + + ms.sh @@ -264,7 +225,7 @@ under the License. - + ms.sh @@ -280,8 +241,8 @@ under the License. - - + + sleep.sh @@ -292,29 +253,9 @@ under the License. 240 - - - - select download_state from template_host_ref - true - Checking download state of the template in the DB after the template was deleted on secondary storage and management server process was restarted - - - template_id - privatetemplateid - - - - - download_state - DOWNLOAD_ERROR - - - - - - + + createTemplate Create template @@ -351,45 +292,7 @@ under the License. - - - select download_state from template_host_ref - true - Getting volume path for the vm DATADISK volume - - - template_id - privatetemplateid - - - - - download_state - DOWNLOADED - - - - - - - select install_path from template_host_ref - true - Getting install_path from the template - - - template_id - privatetemplateid - - - - - install_path - template_path - - - - - + listtemplate.sh @@ -408,8 +311,8 @@ under the License. template_path - - + + corrupttemplate.sh @@ -433,8 +336,8 @@ under the License. - - + + ms.sh @@ -450,7 +353,7 @@ under the License. - + ms.sh @@ -466,8 +369,8 @@ under the License. - - + + sleep.sh @@ -478,26 +381,8 @@ under the License. 240 - - - - select download_state from template_host_ref - true - Checking download state of the template in the DB after the template was deleted on secondary storage and management server process was restarted - - - template_id - privatetemplateid - - - - - download_state - DOWNLOAD_ERROR - - - - + + listtemplate.sh @@ -517,9 +402,9 @@ under the License. template_path - - - + + + createTemplate @@ -557,45 +442,7 @@ under the License. - - - select download_state from template_host_ref - true - Getting volume path for the vm DATADISK volume - - - template_id - privatetemplateid - - - - - download_state - DOWNLOADED - - - - - - - select install_path from template_host_ref - true - Getting install_path from the template - - - template_id - privatetemplateid - - - - - install_path - template_path - - - - - + listtemplate.sh @@ -614,8 +461,8 @@ under the License. template_path - - + + createfaketemplate.sh @@ -643,8 +490,8 @@ under the License. - - + + ms.sh @@ -660,7 +507,7 @@ under the License. - + ms.sh @@ -676,8 +523,8 @@ under the License. - - + + sleep.sh @@ -688,8 +535,8 @@ under the License. 240 - - + + listtemplate.sh @@ -709,10 +556,10 @@ under the License. /template/tmpl/1/300556/template.properties - + - - + + createTemplate Create template @@ -749,45 +596,7 @@ under the License. - - - select download_state from template_host_ref - true - Getting volume path for the vm DATADISK volume - - - template_id - privatetemplateid - - - - - download_state - DOWNLOADED - - - - - - - select install_path from template_host_ref - true - Getting install_path from the template - - - template_id - privatetemplateid - - - - - install_path - template_path - - - - - + listtemplate.sh @@ -806,8 +615,8 @@ under the License. template_path - - + + removetemplate.sh @@ -827,8 +636,8 @@ under the License. - - + + ms.sh @@ -844,7 +653,7 @@ under the License. - + ms.sh @@ -860,8 +669,8 @@ under the License. - - + + ms.sh @@ -877,7 +686,7 @@ under the License. - + ms.sh @@ -893,7 +702,7 @@ under the License. - + sleep.sh @@ -904,29 +713,9 @@ under the License. 240 - - - - select download_state from template_host_ref - true - Checking download state of the template in the DB after the template was deleted on secondary storage and management server process was restarted - - - template_id - privatetemplateid - - - - - download_state - DOWNLOAD_ERROR - - - - - - + + createTemplate Create template @@ -963,45 +752,7 @@ under the License. - - - select download_state from template_host_ref - true - Getting volume path for the vm DATADISK volume - - - template_id - privatetemplateid - - - - - download_state - DOWNLOADED - - - - - - - select install_path from template_host_ref - true - Getting install_path from the template - - - template_id - privatetemplateid - - - - - install_path - template_path - - - - - + listtemplate.sh @@ -1020,8 +771,8 @@ under the License. template_path - - + + ms.sh @@ -1037,7 +788,7 @@ under the License. - + ms.sh @@ -1053,8 +804,8 @@ under the License. - - + + sleep.sh @@ -1065,27 +816,8 @@ under the License. 240 - - - - select download_state from template_host_ref - true - Checking download state of the template in the DB after the template was deleted on secondary storage and management server process was restarted - - - template_id - privatetemplateid - - - - - download_state - DOWNLOADED - - - - + deployVirtualMachine Deploy vm from private template after management server was rebooted @@ -1101,7 +833,7 @@ under the License. diskofferingid globaldiskofferingid - + templateid privatetemplateid @@ -1125,7 +857,7 @@ under the License. networkids globalnetworkid - + @@ -1134,8 +866,8 @@ under the License. - - + + registerTemplate @@ -1180,8 +912,8 @@ under the License. privatetemplateid - - + + sleep.sh @@ -1192,47 +924,8 @@ under the License. 300 - - - - - select download_state from template_host_ref - true - Getting volume path for the vm DATADISK volume - - - template_id - privatetemplateid - - - - - download_state - DOWNLOADED - - - - - - select install_path from template_host_ref - true - Getting install_path from the template - - - template_id - privatetemplateid - - - - - install_path - template_path - - - - - + listtemplate.sh @@ -1251,8 +944,8 @@ under the License. template_path - - + + removetemplate.sh @@ -1272,8 +965,8 @@ under the License. - - + + ms.sh @@ -1289,7 +982,7 @@ under the License. - + ms.sh @@ -1305,8 +998,8 @@ under the License. - - + + ms.sh @@ -1322,7 +1015,7 @@ under the License. - + ms.sh @@ -1338,7 +1031,7 @@ under the License. - + sleep.sh @@ -1349,26 +1042,7 @@ under the License. 15 - - - - select download_state from template_host_ref - true - Checking download state of the template in the DB after the template was deleted on secondary storage and management server process was restarted - - - template_id - privatetemplateid - - - - - download_state - DOWNLOAD_IN_PROGRESS - - - diff --git a/tools/appliance/systemvmtemplate/http/preseed.cfg b/tools/appliance/systemvmtemplate/http/preseed.cfg index ce51f746c300..42718933ecba 100644 --- a/tools/appliance/systemvmtemplate/http/preseed.cfg +++ b/tools/appliance/systemvmtemplate/http/preseed.cfg @@ -45,6 +45,10 @@ d-i apt-setup/services-select multiselect security, updates d-i apt-setup/security_host string security.debian.org d-i apt-setup/local0/source boolean false d-i apt-setup/multiarch string i386 +d-i apt-setup/backports boolean true +d-i apt-setup/contrib boolean true +d-i apt-setup/multiverse boolean true +d-i apt-setup/universe boolean true ### Clock and time zone setup d-i clock-setup/utc boolean true @@ -56,13 +60,13 @@ d-i partman-auto/disk string /dev/vda d-i partman-auto/method string regular d-i partman-auto/expert_recipe string \ boot-root :: \ - 100 60 100 ext2 \ + 400 60 400 ext2 \ $primary{ } $bootable{ } \ method{ format } format{ } \ use_filesystem{ } filesystem{ ext2 } \ mountpoint{ /boot } \ . \ - 2240 40 2500 ext4 \ + 2240 40 4000 ext4 \ method{ format } format{ } \ use_filesystem{ } filesystem{ ext4 } \ mountpoint{ / } \ diff --git a/tools/appliance/systemvmtemplate/scripts/apt_upgrade.sh b/tools/appliance/systemvmtemplate/scripts/apt_upgrade.sh index ea75c2d8bf2c..5699323f8941 100644 --- a/tools/appliance/systemvmtemplate/scripts/apt_upgrade.sh +++ b/tools/appliance/systemvmtemplate/scripts/apt_upgrade.sh @@ -53,11 +53,16 @@ function apt_upgrade() { rm -fv /root/*.iso apt-get -q -y update + apt-get -q -y upgrade apt-get -q -y dist-upgrade + apt-get -q -y upgrade -t buster-backports + apt-get -q -y dist-upgrade -t buster-backports + apt-get -y autoremove --purge apt-get autoclean apt-get clean + reboot } return 2>/dev/null || apt_upgrade diff --git a/tools/appliance/systemvmtemplate/scripts/configure_grub.sh b/tools/appliance/systemvmtemplate/scripts/configure_grub.sh index 4d250c0417b1..231aa764449f 100644 --- a/tools/appliance/systemvmtemplate/scripts/configure_grub.sh +++ b/tools/appliance/systemvmtemplate/scripts/configure_grub.sh @@ -20,6 +20,9 @@ set -e set -x function configure_grub() { + # Remove the old/unused kernel + dpkg --list | grep linux-image | awk '{ print $2 }' | sort -V | sed -n '/'`uname -r`'/q;p' | xargs sudo apt-get remove -y --purge || true + apt-get -y autoremove --purge echo "blacklist floppy" > /etc/modprobe.d/blacklist-floppy.conf rmmod floppy || true update-initramfs -u diff --git a/tools/appliance/systemvmtemplate/scripts/install_systemvm_packages.sh b/tools/appliance/systemvmtemplate/scripts/install_systemvm_packages.sh index 82d08ce05845..d19fd06a8a7c 100644 --- a/tools/appliance/systemvmtemplate/scripts/install_systemvm_packages.sh +++ b/tools/appliance/systemvmtemplate/scripts/install_systemvm_packages.sh @@ -22,7 +22,7 @@ set -x function install_vhd_util() { [[ -f /bin/vhd-util ]] && return - wget --no-check-certificate https://github.com/shapeblue/cloudstack-nonoss/raw/master/vhd-util -O /bin/vhd-util + wget --no-check-certificate https://github.com/shapeblue/cloudstack-nonoss/raw/main/vhd-util -O /bin/vhd-util chmod a+x /bin/vhd-util } @@ -42,7 +42,7 @@ function install_packages() { debconf_packages - local apt_get="apt-get --no-install-recommends -q -y" + local apt_get="apt-get --no-install-recommends -q -y -t buster-backports" ${apt_get} install grub-legacy \ rsyslog logrotate cron net-tools ifupdown tmux vim-tiny htop netbase iptables nftables \ @@ -76,8 +76,6 @@ function install_packages() { apt-get clean apt-get autoclean - ${apt_get} install links - #32 bit architecture support for vhd-util: not required for 32 bit template if [ "${arch}" != "i386" ]; then dpkg --add-architecture i386 diff --git a/tools/appliance/systemvmtemplate/template.json b/tools/appliance/systemvmtemplate/template.json index 5ec5f35a3b19..1e33241cd893 100644 --- a/tools/appliance/systemvmtemplate/template.json +++ b/tools/appliance/systemvmtemplate/template.json @@ -6,7 +6,14 @@ "type": "shell", "execute_command": "echo 'cloud' | sudo -u root -S bash {{.Path}}", "scripts": [ - "scripts/apt_upgrade.sh", + "scripts/apt_upgrade.sh" + ], + "expect_disconnect": true + }, + { + "type": "shell", + "execute_command": "echo 'cloud' | sudo -u root -S bash {{.Path}}", + "scripts": [ "scripts/configure_grub.sh", "scripts/configure_locale.sh", "scripts/configure_networking.sh", @@ -33,7 +40,7 @@ [ "-smp", "1" ] ], "format": "qcow2", - "disk_size": 2500, + "disk_size": 3000, "disk_interface": "virtio", "net_device": "virtio-net", "iso_url": "https://cdimage.debian.org/debian-cd/10.9.0/amd64/iso-cd/debian-10.9.0-amd64-netinst.iso", diff --git a/tools/marvin/marvin/deployDataCenter.py b/tools/marvin/marvin/deployDataCenter.py index c3e8511141f4..868768982f7d 100644 --- a/tools/marvin/marvin/deployDataCenter.py +++ b/tools/marvin/marvin/deployDataCenter.py @@ -71,9 +71,9 @@ def __persistDcConfig(self): ts = strftime("%b_%d_%Y_%H_%M_%S", localtime()) dc_file_path = "dc_entries_" + str(ts) + ".obj" - file_to_write = open(dc_file_path, 'w') + file_to_write = open(dc_file_path, 'wb') if file_to_write: - pickle.dump(self.__cleanUp, file_to_write) + pickle.dump(self.__cleanUp, file_to_write, protocol=0) print("\n=== Data Center Settings are dumped to %s===" % dc_file_path) self.__tcRunLogger.debug("\n=== Data Center Settings are dumped to %s===" % dc_file_path) except Exception as e: diff --git a/tools/travis/xunit-reader.py b/tools/travis/xunit-reader.py index 66d78feceff6..26d0ced699d0 100755 --- a/tools/travis/xunit-reader.py +++ b/tools/travis/xunit-reader.py @@ -78,7 +78,7 @@ def parse_reports(file_path_list): exit_code = 0 for file_path in file_path_list: - data = lxml.etree.iterparse(file_path, tag='testcase') + data = lxml.etree.iterparse(file_path, tag='testcase', huge_tree=True) for event, elem in data: name = '' status = 'Success' diff --git a/ui/public/locales/de_DE.json b/ui/public/locales/de_DE.json index f30e9abbf4c2..b1e29fc64b11 100644 --- a/ui/public/locales/de_DE.json +++ b/ui/public/locales/de_DE.json @@ -111,7 +111,7 @@ "label.action.delete.physical.network": "Physikalisches Netzwerk löschen", "label.action.delete.pod": "Pod löschen", "label.action.delete.pod.processing": "Pod wird gelöscht....", -"label.action.delete.primary.storage": "Hauptspeicher löschen", +"label.action.delete.primary.storage": "Primärspeicher löschen", "label.action.delete.primary.storage.processing": "Primary Storage wird gelöscht....", "label.action.delete.secondary.storage": "Sekundärspeicher löschen", "label.action.delete.secondary.storage.processing": "Secondary Storage wird gelöscht....", @@ -168,7 +168,7 @@ "label.action.edit.network.offering": "Netzwerkangebot bearbeiten", "label.action.edit.network.processing": "Netzwerk wird bearbeitet....", "label.action.edit.pod": "Bearbeiten des Pods", -"label.action.edit.primary.storage": "Hauptspeicher bearbeiten", +"label.action.edit.primary.storage": "Primärspeicher bearbeiten", "label.action.edit.resource.limits": "Resourcenlimit bearbeiten", "label.action.edit.service.offering": "Dienstangebot bearbeiten", "label.action.edit.template": "Vorlage bearbeiten", @@ -335,7 +335,7 @@ "label.add.pod": "Pod hinzufügen", "label.add.port.forwarding.rule": "Portweiterleitungsregel hinzufügen", "label.add.portable.ip.range": "Portablen IP-Bereich hinzufügen", -"label.add.primary.storage": "Hauptspeicher hinzufügen", +"label.add.primary.storage": "Primärspeicher hinzufügen", "label.add.private.gateway": "Privaten Gateway hinzufügen", "label.add.region": "Region hinzufügen", "label.add.resources": "Ressourcen hinzufügen", @@ -467,7 +467,7 @@ "label.baremetalcpu": "CPU (in MHz)", "label.baremetalcpucores": "Anzahl an CPU-Kernen", "label.baremetalmac": "Host-MAC", -"label.baremetalmemory": "Speicher (in MB)", +"label.baremetalmemory": "Arbeitsspeicher", "label.based.on": "Basierend auf", "label.basic": "Basis", "label.basic.mode": "Grundmodus", @@ -1271,8 +1271,8 @@ "label.may.continue": "Sie können jetzt fortfahren", "label.mb.memory": "MB Speicher", "label.memallocated": "Speicher Belegung", -"label.memory": "Speicher (in MB)", -"label.memory.maximum.mb": "Max. Speicher (in MB)", +"label.memory": "Arbeitsspeicher", +"label.memory.maximum.mb": "Max. Arbeitsspeicher", "label.memory.total": "Speicher insgesamt", "label.memory.used": "Genutzter Speicher", "label.memoryallocated": "zugeordneter Speicher", @@ -1331,7 +1331,7 @@ "label.migrate.to.storage": "Zu Speicher migrieren", "label.migrate.volume": "Volumen migrieren", "label.migrate.volume.newdiskoffering.desc": "This option allows administrators to replace the old disk offering, using one that better suits the new placement of the volume.", -"label.migrate.volume.to.primary.storage": "Migriere ein Speichervolumen zu einem anderen Hauptspeicher", +"label.migrate.volume.to.primary.storage": "Migriere ein Speichervolumen zu einem anderen Primärspeicher", "label.migrating": "Migriere", "label.min.balance": "Min Abrechnung", "label.min.past.hour": "min seit Std. vergangen", @@ -1341,7 +1341,7 @@ "label.mininstance": "Min Instanzen", "label.miniops": "Min IOPS", "label.minmaxiops": "Min. IOPS / Max IOPS", -"label.minmemory": "Min. Speicher (in MB)", +"label.minmemory": "Min. Arbeitsspeicher", "label.minute.past.hour": "Minute(n) seit der Stunde vergangen", "label.minutes.past.hour": "Minute(n) seit der Stunde vergangen", "label.monday": "Montag", @@ -1561,12 +1561,12 @@ "label.previous": "Vorherige", "label.primary": "Primär", "label.primary.network": "Hauptnetzwerk", -"label.primary.storage": "Hauptspeicher", -"label.primary.storage.allocated": "Zugewiesener Hauptspeicher", -"label.primary.storage.count": "Hauptspeicher-Pools", -"label.primary.storage.used": "Genutzter Hauptspeicher", -"label.primarystoragelimit": "Hauptspeicher-Limits (GiB)", -"label.primarystoragetotal": "Hauptspeicher", +"label.primary.storage": "Primärspeicher", +"label.primary.storage.allocated": "Zugewiesener Primärspeicher", +"label.primary.storage.count": "Primärspeicher-Pools", +"label.primary.storage.used": "Genutzter Primärspeicher", +"label.primarystoragelimit": "Primärspeicher-Limits (GiB)", +"label.primarystoragetotal": "Primärspeicher", "label.private.gateway": "Privater Gateway", "label.private.interface": "Privates Interface", "label.private.ip.range": "Privater IP-Bereich", @@ -1978,7 +1978,7 @@ "label.storage": "Speicher", "label.storage.tags": "Datenspeicher-Markierung", "label.storage.traffic": "Datenspeicherverkehr", -"label.storageid": "Hauptspeicher", +"label.storageid": "Primärspeicher", "label.storagemotionenabled": "Speicherbewegung aktiviert", "label.storagepolicy": "Speicherkonzept", "label.storagepool": "Speicher-Pool", @@ -2316,7 +2316,7 @@ "message.action.delete.nexusvswitch": "Bitte bestätigen Sie, dass Sie diesen nexus 1000v löschen möchten.", "message.action.delete.physical.network": "Bitte bestätigen Sie, dass Sie dieses physikalische Netzwerk löschen möchten", "message.action.delete.pod": "Bitte bestätigen Sie, dass Sie dieses pod löschen möchten.", -"message.action.delete.primary.storage": "Bitte bestätigen Sie, dass Sie diese Hauptspeicher löschen möchten.", +"message.action.delete.primary.storage": "Bitte bestätigen Sie, dass Sie diese Primärspeicher löschen möchten.", "message.action.delete.secondary.storage": "Bitte bestätigen Sie, dass Sie diesen Sekundärspeicher löschen möchten.", "message.action.delete.security.group": "Bitte bestätigen Sie, dass Sie diese Sicherheitsgruppe löschen möchten.", "message.action.delete.service.offering": "Bitte bestätigen Sie, dass Sie dieses Dienstangebot löschen möchten.", @@ -2350,7 +2350,7 @@ "message.action.host.enable.maintenance.mode": "Die Aktivierung des Wartungsmodus verursacht eine Livemigration aller laufenden Instanzen auf diesem Host zu einem anderen verfügbaren Host.", "message.action.instance.reset.password": "Bitte bestätigen Sie, dass Sie das ROOT Passwort für diese virtuelle Maschine ändern möchten.", "message.action.manage.cluster": "Bitte bestätigen Sie, dass das Cluster bearbeitet werden soll.", -"message.action.primarystorage.enable.maintenance.mode": "Warnung: den Hauptspeicher in den Wartungsmodus zu stellen, wird alle VMs stoppen, welche noch Volumen auf demjenigen haben. Möchten Sie fortfahren?", +"message.action.primarystorage.enable.maintenance.mode": "Warnung: den Primärspeicher in den Wartungsmodus zu stellen, wird alle VMs stoppen, welche noch Volumen auf demjenigen haben. Möchten Sie fortfahren?", "message.action.reboot.instance": "Bitte bestätigen Sie, dass Sie diese Instanz neu starten möchten.", "message.action.reboot.router": "Alle angebotenen Dienste dieses Routers werden unterbrochen. Bitte bestätigen Sie, dass Sie den Router neu starten möchten.", "message.action.reboot.systemvm": "Bitte bestätigen Sie, dass Sie diese System-VM neu starten möchten.", @@ -2406,7 +2406,7 @@ "message.add.pod.during.zone.creation": "Jede Zone muss mindestens einen Pod enthalten, welchen wir nun konfigurieren und hinzufügen. Ein Pod enthält Hosts und primären Storage, welche in einem späteren Schritt hinzugefügt werden. Zuerst konfigurieren Sie den Bereich der reservierten IP-Adressen für CloudStacks internen Verwaltungsdatenverkehr. Der reservierte IP-Bereich muss für jede Zone in der Cloud eindeutig sein.", "message.add.port.forward.failed": "Hinzufügen einer neuen Port-Weiterleitungsregel ist fehlgeschlagen", "message.add.port.forward.processing": "Hinzufügen einer neuen Port-Weiterleitungsregel...", -"message.add.primary": "Bitte spezifizieren Sie die folgenden Parameter, um einen neuen Hauptspeicher hinzuzufügen", +"message.add.primary": "Bitte spezifizieren Sie die folgenden Parameter, um einen neuen Primärspeicher hinzuzufügen", "message.add.primary.storage": "Bitte fügen Sie einen neuen primären Speicher für Zone , und Pod hinzu.", "message.add.private.gateway.failed": "Hinzufügen eines privaten Gateways ist fehlgeschlagen", "message.add.private.gateway.processing": "Hinzufügen eines privaten Gateways...", @@ -2562,7 +2562,7 @@ "message.creating.guest.network": "Gastnetzwerk wird erstellt", "message.creating.physical.networks": "Physikalische Netzwerke werden erstellt", "message.creating.pod": "Erstelle einen Pod", -"message.creating.primary.storage": "Hauptspeicher wird erstellt", +"message.creating.primary.storage": "Primärspeicher wird erstellt", "message.creating.secondary.storage": "Sekundärspeicher wird erstellt", "message.creating.systemvm": "Erstellung von System VMs (das kann eine Weile dauern)", "message.creating.zone": "Zone wird erstellt", @@ -2596,14 +2596,14 @@ "message.desc.add.new.lb.sticky.rule": "Neue Lastverteiler Sticky Regel hinzufügen", "message.desc.advanced.zone": "Für anspruchvollere Netzwerk-Topologien. Dieses Netzwerkmodell bietet die höchste Flexibilität beim Definieren der Gast-Netzwerke und beim Anbieten von maßgeschneiderten Nerzwerk-Angeboten wie Firewall-, VPN- oder Lastverteilungsunterstützung.", "message.desc.basic.zone": "Biete ein einzelnes Netzwerk an, in dem alle VM-Instanzen direkt mit IP vom Netzwerk verbunden sind. Gästeisolation kann durch Layer-3 wie Sicherheitsgruppen angeboten werden (IP-Adressen Source Filtering)", -"message.desc.cluster": "Jeder Pod muss einen oder mehrere Clusters enthalten, und wir werden jetzt den ersten Cluster hinzufügen. Ein Cluster bietet die Möglichkeit Hosts zu gruppieren. Die Hosts in einem Cluster haben alle identische Hardware, betreiben den selben Hypervisor, sind im selben Subnetz und greiffen auf den selben geteilten Speicher zu. Jeder Cluster besteht aus einem oder mehreren Hosts und einem oder mehreren Hauptspeicher-Server.", +"message.desc.cluster": "Jeder Pod muss einen oder mehrere Clusters enthalten, und wir werden jetzt den ersten Cluster hinzufügen. Ein Cluster bietet die Möglichkeit Hosts zu gruppieren. Die Hosts in einem Cluster haben alle identische Hardware, betreiben den selben Hypervisor, sind im selben Subnetz und greiffen auf den selben geteilten Speicher zu. Jeder Cluster besteht aus einem oder mehreren Hosts und einem oder mehreren Primärspeicher-Server.", "message.desc.create.ssh.key.pair": "Bitte die folgenden Daten eintragen um einen SSH-Schlüsselpaar zu registrieren oder erstellen.

(1) Wenn öffentlicher Schlüssel ausgewählt, registriert CloudStack einen öffentlichen Schlüssel. Dieser kann über den privaten Schlüssel verwendet werden.

(2) Wenn öffentlicher Schlüssel nicht ausgewählt ist, erstellt CloudStack einen neuen SSH-Schlüssel. In diesem Fall bitte den privaten Schlüssel kopieren und speichern. CloudStack wird ihn nicht speichern.
", "message.desc.created.ssh.key.pair": "Erstellte ein SSH-Schlüsselpaar.", "message.desc.host": "Jeder Cluster muss mindestens ein Host (Computer) beinhalten damit Gast-VMs darauf laufen können und wir werden nun den ersten Host erstellen. Damit ein Host in CloudStack funktioniert, muss eine Hypervisor-Software darauf installiert, eine IP-Adressse zugewiesen sowie sichergestellt sein, dass sich der Host mit dem CloudStack Verwaltungs-Server verbinden kann .

Geben Sie bitte den DNS-Namen oder IP-Adresse, den Benutzernamen (für gewöhnlich root) und das Passwort sowie jegliche Labels ein, mit denen Sie den Host kategorisieren möchten.", -"message.desc.primary.storage": "Jeder Cluster muss einen oder mehrere Hauptspeicher-Server enthalten, und wir werden nun den ersten erfassen. Hauptspeicher enthält die Festplatten-Volumen aller VMs, welche auf den Hosts in dem Cluster befinden. Benutzen Sie irgend ein standardkonformes Protokoll, welches vom darunterliegenden Hypervisor unterstützt wird.", +"message.desc.primary.storage": "Jeder Cluster muss einen oder mehrere Primärspeicher-Server enthalten, und wir werden nun den ersten erfassen. Primärspeicher enthält die Festplatten-Volumen aller VMs, welche auf den Hosts in dem Cluster befinden. Benutzen Sie irgend ein standardkonformes Protokoll, welches vom darunterliegenden Hypervisor unterstützt wird.", "message.desc.reset.ssh.key.pair": "Bitte definieren Sie ein SSH-Schlüsselpaar welches Sie zu dieser VM hinzufügen möchten. Bitte beachten Sie, dass das Root-Passwort dabei geändert wird falls es aktiviert ist.", "message.desc.secondary.storage": "Jede Zone muss mindestens ein NFS oder Sekundärspeicher-Server haben und wir werden nun den ersten hinzufügen. Sekundärspeicher speichert VM-Vorlagen, ISO-Abbilder und VM-Festplatten-Schnappschüsse. Dieser Server muss für alle Host in der Zone erreichbar sein.

Geben Sie die IP und den exportierten Pfad an.", -"message.desc.zone": "Eine Zone ist die größte organisatorische Einheit in CloudStack und entspricht typischerweise eines einzelnen Rechenzentrum. Zonen bieten physikalische Isolation und Redundanz. Eine Zone beinhaltet einen oder mehrere Pods (jeder von Ihnen beinhaltet Hosts und Hauptspeicher-Server) und ein Sekundärspeicher-Server, welcher von allen Pods in der Zone geteilt wird.", +"message.desc.zone": "Eine Zone ist die größte organisatorische Einheit in CloudStack und entspricht typischerweise eines einzelnen Rechenzentrum. Zonen bieten physikalische Isolation und Redundanz. Eine Zone beinhaltet einen oder mehrere Pods (jeder von Ihnen beinhaltet Hosts und Primärspeicher-Server) und ein Sekundärspeicher-Server, welcher von allen Pods in der Zone geteilt wird.", "message.detach.disk": "Sind Sie sicher, dass Sie diese Festplatte loslösen möchten?", "message.detach.iso.confirm": "Bitte bestätigen Sie, dass Sie die ISO von der virtuellen Instanz trennen möchten.", "message.diagnostics.exitcode": "exitcode: var", @@ -2785,7 +2785,7 @@ "message.installwizard.copy.whatisapod": "Ein Pod steht häufig für ein einzelnes Rack. Host im selben Pod sind im selben Subnetz.

Ein Pod ist die zweitgrößte Einheit innerhalb einer CloudStack™ Installation. Pods sind geschlossen innerhalb der Zonen. Jede Zone kann eine oder mehrere Pods enthalten; in der Basisinstallation werden Sie nur ein Pod in Ihrer Zone haben.", "message.installwizard.copy.whatisazone": "Eine Zone ist die größte organisatorische Einheit innerhalb einer CloudStack™ Installation. Eine Zone steht typischerweise für ein einzelnes Rechenzentrum, obwohl es natürlich erlaubt ist, mehrere Zonen in einem Rechenzentrum zu haben. Der Vorteil einer Unterteilung der Infrastruktur in Zonen besteht im Anbieten einer physikalischen Isolierung und Redundanz. Zum Beispiel kann jede Zone ihre eigene Stromversorgung und ihr eigener Netzwerk-Uplink haben und geographisch weit auseinanderliegen (obschon dies nicht zwingend ist).", "message.installwizard.copy.whatiscloudstack": "CloudStack™ ist eine Software-Plattform welche Rechenressourcen zusammenfasst, um öffentliche, private oder hybride \"Infrastructure as a Service\" (IaaS) Clouds zu bauen. CloudStack™ verwaltet das Netzwerk-, Speicher- und Computingknoten was eine Cloud-Infrastruktur ausmacht. Benutzen Sie CloudStack™ um Computing-Umgebungen zu erstellen, verwalten und zu konfigurieren.

Neben dem Erweitern von individuellen virtuellen Maschinenabbilder auf auf Standardhardware bietet CloudStack™ einen schlüsselfertigen Cloud Infrastruktur-Software-Stack für die Bereitstellung von virtueller Rechenzentren as a Service – Liefert alle wesentlichen Komponenten für das Bauen, Bereitstellen und Verwalten von multi-tier- und mandantenfähigen Cloud-Anwendungen. Open-Source sowie Premium-Versionen sind verfügbar, mit nahezu identischen Features.", -"message.installwizard.copy.whatisprimarystorage": "Eine CloudStack™ Cloud-Infrastruktur verwendet zwei Arten von Speicher: Hauptspeicher und Sekundärspeicher. Beide können iSCSI- oder NFS-Server, oder auch lokale Festplatten sein.

Hauptspeicher ist mit einem Cluster verbunden und speichert Festplattenvolumen aller diejenigen Gast-VMs, welche auf Hosts in diesem Cluster laufen. Der Hauptspeicher-Server ist typischerweise nahe am Host gelegen.", +"message.installwizard.copy.whatisprimarystorage": "Eine CloudStack™ Cloud-Infrastruktur verwendet zwei Arten von Speicher: Primärspeicher und Sekundärspeicher. Beide können iSCSI- oder NFS-Server, oder auch lokale Festplatten sein.

Primärspeicher ist mit einem Cluster verbunden und speichert Festplattenvolumen aller diejenigen Gast-VMs, welche auf Hosts in diesem Cluster laufen. Der Primärspeicher-Server ist typischerweise nahe am Host gelegen.", "message.installwizard.copy.whatissecondarystorage": "Sekundärspeicher wird mit einer Zone verbunden und speichert alles folgende:
  • Vorlagen - Betriebssystemabbilder welche für das Booten der VMs verwendet werden und zusätzliche Konfigurationsinformationen wie installierte Applikationen beinhalten kann
  • ISO-Abbilder - Betriebssystemabbilder welche bootbar oder nicht bootbar sein können
  • Festplattenvolumen-Schnappschüsse - gesicherte Kopien von VM-Daten, welche für die Datenwiederherstellung oder für neue Vorlagen verwenden werden können
", "message.installwizard.now.building": "Ihre Cloud wird erstellt...", "message.installwizard.tooltip.addcluster.name": "Der Name des Clusters. Der Name kann frei gewählt werden und wird von Cloudstack nicht genutzt.", @@ -2870,7 +2870,7 @@ "message.number.clusters": "

# of Cluster

", "message.number.hosts": "

# of Hosts

", "message.number.pods": "

Anzahl derPods

", -"message.number.storage": "

# von Hauptspeichervolumina

", +"message.number.storage": "

# von Primärspeicherdatenträgern

", "message.number.zones": "

# of Zonen

", "message.outofbandmanagement.action.maintenance": "Warnung Host ist im Wartungsmodus", "message.ovf.properties.available": "Die folgenden OVF-Eigenschaften stehen für die Bearbeitung zur Verfügung. Bitte passen Sie die Werte dementsprechend an", @@ -3150,7 +3150,7 @@ "message.zone.step.1.desc": "Bitte wählen Sie ein Netzwerk-Modell für Ihre Zone.", "message.zone.step.2.desc": "Bitte geben Sie die folgende Information ein, um eine neue Zone hinzuzufügen", "message.zone.step.3.desc": "Bitte geben Sie die folgende Information ein, um einen neuen pod hinzuzufügen", -"message.zonewizard.enable.local.storage": "WARNUNG: Wenn Sie den lokalen Speicher für diese Zone aktivieren möchten, müssen Sie, abhängig davon wo Sie Ihre System-VMs starten möchten, wie folgt vorgehen:

1. Wenn die System-VMs im geteilten Hauptspeicher gestartet werden sollen, muss der geteilte Hauptspeicher nach dem Erstellen zur Zone hinzugefügt werden. Zudem muss die Zone im deaktivierten Zustand gestartet werden.

2. Wenn die System-VMs im lokalen Hauptspeicher gestartet werden sollen, muss, \"system.vm.use.local.storage\" auf \"true\" gesetzt werden bevor Sie die Zone aktivieren.


Möchten Sie weiterfahren?", +"message.zonewizard.enable.local.storage": "WARNUNG: Wenn Sie den lokalen Speicher für diese Zone aktivieren möchten, müssen Sie, abhängig davon wo Sie Ihre System-VMs starten möchten, wie folgt vorgehen:

1. Wenn die System-VMs im geteilten Primärspeicher gestartet werden sollen, muss der geteilte Primärspeicher nach dem Erstellen zur Zone hinzugefügt werden. Zudem muss die Zone im deaktivierten Zustand gestartet werden.

2. Wenn die System-VMs im lokalen Primärspeicher gestartet werden sollen, muss, \"system.vm.use.local.storage\" auf \"true\" gesetzt werden bevor Sie die Zone aktivieren.


Möchten Sie weiterfahren?", "messgae.validate.min": "Bitte geben sie einen Wert größer oder gleich {0} ein.", "network.rate": "Netzwerk-Rate", "router.health.checks": "Gesundheitsüberprüfung", diff --git a/ui/public/locales/el_GR.json b/ui/public/locales/el_GR.json new file mode 100644 index 000000000000..07edb492e18c --- /dev/null +++ b/ui/public/locales/el_GR.json @@ -0,0 +1,3332 @@ +{ +"alert.service.domainrouter" : "Δρομολογητής τομέα", +"changed.item.properties" : "Τροποποιημένες ιδιότητες στοιχείου", +"confirm.enable.s3" : "Συμπληρώστε τις ακόλουθες πληροφορίες για να ενεργοποιήσετε την υποστήριξη για δευτερεύοντα χώρο αποθήκευσης με υποστήριξη S3", +"confirm.enable.swift" : "Παρακαλούμε συμπληρώστε τις ακόλουθες πληροφορίες για να ενεργοποιήσετε την υποστήριξη για swift", +"error.could.not.change.your.password.because.non.native.user" : "Το σφάλμα δεν ήταν δυνατό να αλλάξει τον κωδικό πρόσβασής σας, επειδή ο χρήστης δεν είναι εγγενής χρήστης cloudstack.", +"error.could.not.enable.zone" : "Δεν ήταν δυνατή η ενεργοποίηση της ζώνης", +"error.dedicate.cluster.failed" : "Απέτυχε η αποκλειστική διάθεση της συστοιχία (cluster)", +"error.dedicate.host.failed" : "Απέτυχε η αποκλειστική διάθεση του κεντρικού υπολογιστή", +"error.dedicate.pod.failed" : "Απέτυχε η αποκλειστική διάθεση pod", +"error.dedicate.zone.failed" : "Απέτυχε η αποκλειστική διάθεση ζώνης", +"error.execute.api.failed" : "Απέτυχε η εκτέλεση του API", +"error.fetching.async.job.result" : "Παρουσιάστηκε σφάλμα κατά τη λήψη αποτελέσματος ασύγχρονης εργασίας", +"error.form.message" : "Υπάρχουν λάθη στη φόρμα. Παρακαλώ διορθώστε τα.", +"error.installwizard.message" : "Κάτι πήγε στραβά. Μπορείτε να επιστρέψετε και να διορθώσετε τυχόν σφάλματα", +"error.invalid.username.password" : "Το όνομα χρήστη ή ο κωδικός πρόσβασης δεν είναι έγκυρα.

Αυτό μπορεί επίσης να είναι ένας περιορισμός στη διεύθυνση IP από την οποία συνδέεστε.", +"error.login" : "Το όνομα χρήστη/ο κωδικός πρόσβασής σας δεν ταιριάζει με τα αρχεία μας.", +"error.menu.select" : "Δεν είναι δυνατή η εκτέλεση ενέργειας λόγω επιλογής στοιχείων.", +"error.mgmt.server.inaccessible" : "Δεν είναι δυνατή η πρόσβαση στο διακομιστή διαχείρισης. Προσπαθήστε ξανά αργότερα.", +"error.password.not.match" : "Τα πεδία κωδικού πρόσβασης δεν ταιριάζουν", +"error.please.specify.physical.network.tags" : "Οι προσφορές υπηρεσίας δικτύου δεν είναι διαθέσιμες μέχρι να καθορίσετε ετικέτες για αυτό το φυσικό δίκτυο.", +"error.release.dedicate.cluster" : "Απέτυχε η αποδεύσμευση της αποκλειστικής ομοταξίας (cluster)", +"error.release.dedicate.host" : "Απέτυχε η αποδεύσμευση του αποκλειστικού κεντρικού υπολογιστή", +"error.release.dedicate.pod" : "Απέτυχε η αποδεύσμευση της υποομάδας (pod)", +"error.release.dedicate.zone" : "Απέτυχε η αποδέσμευση της αποκλειστικής ζώνης", +"error.session.expired" : "Η περίοδος λειτουργίας σας έχει λήξει.", +"error.unable.to.reach.management.server" : "Δεν είναι δυνατή η πρόσβαση στο διακομιστή διαχείρισης", +"error.unable.to.proceed" : "Δεν είναι δυνατή η συνέχιση. Επικοινωνήστε με το διαχειριστή σας", +"error.unresolved.internet.name" : "Δεν είναι δυνατή η επίλυση του ονόματος Internet.", +"firewall.close" : "Τείχος προστασίας", +"force.delete.domain.warning" : "Προειδοποίηση: Επιλέγοντας την ενέργεια αυτή όλα τα δεδομένα (accounts,resources,child domains) κάτω απο το παρόν θα διαγραφούν", +"force.remove" : "Επιβολή κατάργησης", +"force.remove.host.warning" : "Προειδοποίηση: Επιλέγοντας την ενέργεια αυτή το Cloudstack θα τερματήσει την εκτέλεση όλων των εικονικών μηχανών πριν την κατάργηση του διακομιστή απο την συστοιχία.", +"force.stop" : "Επιβολή διακοπής ", +"force.stop.instance.warning" : "Προειδοποίηση: Η επιλογή του τερμαστισμού δια της βίας της εικονικής μηχανής πρέπει να είναι η τελευταία επιλογή. Μπορεί να οδηγήσει σε απώλεια δεδομένων ή/και σε απρόβλεπτη συμπεριφορά της εικονικής μηχανής ", +"hint.no.host.tags" : "Δεν βρέθηκαν ετικέτες κεντρικού υπολογιστή", +"hint.no.storage.tags" : "Δεν βρέθηκαν ετικέτες αποθήκευσης", +"hint.type.part.host.tag" : "Πληκτρολόγηση σε μέρος ετικέτας κεντρικού υπολογιστή", +"hint.type.part.storage.tag" : "Πληκτρολόγηση σε μέρος ετικέτας χώρου αποθήκευσης", +"icmp.code.desc" : "Καθορίστε -1 εάν θέλετε να επιτρέψετε όλους τους κωδικούς ICMP", +"icmp.type.desc" : "Καθορίστε -1 εάν θέλετε να επιτρέψετε όλους τους τύπους ICMP.", +"image.directory" : "Κατάλογος εικόνων", +"inline" : "Ενσωματωμένη", +"label.about" : "Για", +"label.about.app" : "Πληροφορίες για το CloudStack", +"label.accept" : "Αποδεχθεί", +"label.accept.project.invitation" : "Αποδοχή πρόσκλησης έργου", +"label.access" : "Πρόσβαση", +"label.accesskey" : "Κλειδί πρόσβασης", +"label.account" : "Λογαριασμό", +"label.account.and.security.group" : "Λογαριασμός - Ομάδα ασφαλείας", +"label.account.details" : "Λεπτομέρειες λογαριασμού", +"label.account.id" : "Αναγνωριστικό λογαριασμού", +"label.account.name" : "Όνομα λογαριασμού", +"label.account.specific" : "Συγκεκριμένα χαρακτηριστικά του λογαριασμού", +"label.accounts" : "Λογαριασμούς", +"label.accounttype" : "Τύπος λογαριασμού", +"label.acl.export" : "Εξαγωγή ACL", +"label.acl.id" : "Αναγνωριστικό ACL", +"label.acl.list.rules" : "Κανόνες λίστας ACL", +"label.acl.reason.description" : "Εισαγάγετε την αιτία πίσω από έναν κανόνα ACL.", +"label.acl.replaced" : "Αντικατάσταση ACL", +"label.aclid" : "ACL", +"label.aclname" : "Όνομα ACL", +"label.acltotal" : "Σύνολο ACL δικτύου", +"label.acquire.new.ip" : "Απόκτηση νέας IP", +"label.acquire.new.secondary.ip" : "Απόκτηση νέας δευτερεύουσας ΔΙΕΎΘΥΝΣΗΣ IP", +"label.acquiring.ip" : "Απόκτηση IP", +"label.action" : "Δράση", +"label.action.attach.disk" : "Επισύναψη δίσκου", +"label.action.attach.disk.processing" : "Επισύναψη δίσκου....", +"label.action.attach.iso" : "Επισύναψη ISO", +"label.action.attach.iso.processing" : "Συνδέοντας iso ....", +"label.action.cancel.maintenance.mode" : "Ακύρωση λειτουργίας συντήρησης", +"label.action.cancel.maintenance.mode.processing" : "Ακύρωση λειτουργίας συντήρησης....", +"label.action.change.password" : "Αλλαγή κωδικού πρόσβασης", +"label.action.change.service" : "Αλλαγή υπηρεσίας", +"label.action.change.service.processing" : "Αλλαγή υπηρεσίας....", +"label.action.configure.samlauthorization" : "Ρύθμιση παραμέτρων εξουσιοδότησης SAML SSO", +"label.action.configure.stickiness" : "Stickiness", +"label.action.copy.iso" : "Αντιγραφή ISO", +"label.action.copy.iso.processing" : "Αντιγραφή ISO ....", +"label.action.copy.template" : "Αντιγραφή προτύπου", +"label.action.copy.template.processing" : "Αντιγραφή προτύπου....", +"label.action.create.template.from.vm" : "Δημιουργία προτύπου από vm", +"label.action.create.template.from.volume" : "Δημιουργία προτύπου από τόμο", +"label.action.create.template.processing" : "Δημιουργία προτύπου....", +"label.action.create.snapshot.from.vmsnapshot" : "Δημιουργία στιγμιότυπου από στιγμιότυπο εικονικής μηχανής", +"label.action.create.vm" : "Δημιουργία εικονικής μηχανής", +"label.action.create.vm.processing" : "Δημιουργία VM....", +"label.action.create.volume" : "Δημιουργία τόμου", +"label.action.create.volume.processing" : "Δημιουργία τόμου....", +"label.action.delete.account" : "Διαγραφή λογαριασμού", +"label.action.delete.account.processing" : "Διαγραφή λογαριασμού....", +"label.action.delete.backup.offering" : "Διαγραφή προσφοράς δημιουργίας αντιγράφων ασφαλείας", +"label.action.delete.cluster" : "Διαγραφή ομοταξίας", +"label.action.delete.cluster.processing" : "Διαγραφή ομοταξίας....", +"label.action.delete.disk.offering" : "Διαγραφή προσφοράς υπηρεσίας δίσκου", +"label.action.delete.disk.offering.processing" : "Διαγραφή προσφοράς υπηρεσίας δίσκου....", +"label.action.delete.domain" : "Διαγραφή τομέα", +"label.action.delete.domain.processing" : "Διαγραφή τομέα....", +"label.action.delete.firewall" : "Διαγραφή κανόνα τείχους προστασίας", +"label.action.delete.firewall.processing" : "Διαγραφή τείχους προστασίας....", +"label.action.delete.ingress.rule" : "Διαγραφή κανόνα εισόδου", +"label.action.delete.ingress.rule.processing" : "Διαγραφή κανόνα εισόδου....", +"label.action.delete.ip.range" : "Διαγραφή περιοχής IP", +"label.action.delete.ip.range.processing" : "Διαγραφή περιοχής IP....", +"label.action.delete.iso" : "Διαγραφή ISO", +"label.action.delete.iso.processing" : "Διαγραφή ISO....", +"label.action.delete.load.balancer" : "Διαγραφή κανόνα εξισορρόπησης φόρτου", +"label.action.delete.load.balancer.processing" : "Διαγραφή εξισορρόπησης φόρτου....", +"label.action.delete.network" : "Διαγραφή δικτύου", +"label.action.delete.network.processing" : "Διαγραφή δικτύου....", +"label.action.delete.nexusvswitch" : "Διαγραφή Nexus 1000v", +"label.action.delete.nic" : "Κατάργηση nic", +"label.action.delete.physical.network" : "Διαγραφή φυσικού δικτύου", +"label.action.delete.pod" : "Διαγραφή υποομάδας", +"label.action.delete.pod.processing" : "Η υποομάδα διαγραφεται ....", +"label.action.delete.primary.storage" : "Διαγραφή πρωτεύοντος χώρου αποθήκευσης", +"label.action.delete.primary.storage.processing" : "Διαγραφή πρωτεύοντος χώρου αποθήκευσης....", +"label.action.delete.secondary.storage" : "Διαγραφή δευτερεύοντος χώρου αποθήκευσης", +"label.action.delete.secondary.storage.processing" : "Διαγραφή δευτερεύοντος χώρου αποθήκευσης....", +"label.action.delete.security.group" : "Διαγραφή ομάδας ασφαλείας", +"label.action.delete.security.group.processing" : "Διαγραφή ομάδας ασφαλείας....", +"label.action.delete.service.offering" : "Διαγραφή προσφοράς υπηρεσίας υπηρεσίας", +"label.action.delete.service.offering.processing" : "Διαγραφή προσφοράς υπηρεσίας υπηρεσίας....", +"label.action.delete.snapshot" : "Διαγραφή στιγμιότυπου", +"label.action.delete.snapshot.processing" : "Διαγραφή στιγμιότυπου....", +"label.action.delete.system.service.offering" : "Διαγραφή προσφοράς υπηρεσίας, υπηρεσίας συστήματος", +"label.action.delete.template" : "Διαγραφή προτύπου", +"label.action.delete.template.processing" : "Διαγραφή προτύπου....", +"label.action.delete.user" : "Διαγραφή χρήστη", +"label.action.delete.user.processing" : "Διαγραφή χρήστη....", +"label.action.delete.volume" : "Διαγραφή τόμου", +"label.action.delete.volume.processing" : "Διαγραφή τόμου....", +"label.action.delete.zone" : "Διαγραφή ζώνης", +"label.action.delete.zone.processing" : "Διαγραφή ζώνης....", +"label.action.destroy.instance" : "Καταστροφή εικονική μηχανής", +"label.action.destroy.instance.processing" : "Καταστροφή εικονική μηχανής ....", +"label.action.destroy.systemvm" : "Καταστρέψτε το σύστημα VM", +"label.action.destroy.systemvm.processing" : "Καταστρέφοντας VM συστήματος ....", +"label.action.destroy.volume" : "Καταστροφή τόμου", +"label.action.detach.disk" : "Αποσύνδεση δίσκου", +"label.action.detach.disk.processing" : "Αποσύνδεση δίσκου....", +"label.action.detach.iso" : "Αποσύνδεση ISO", +"label.action.detach.iso.processing" : "Αποσύνδεση iso....", +"label.action.disable.account" : "Απενεργοποίηση λογαριασμού", +"label.action.disable.account.processing" : "Απενεργοποίηση λογαριασμού....", +"label.action.disable.cluster" : "Απενεργοποίηση ομοταξίας", +"label.action.disable.cluster.processing" : "Απενεργοποίηση ομοταξίας....", +"label.action.disable.nexusvswitch" : "Απενεργοποίηση του Nexus 1000v", +"label.action.disable.physical.network" : "Απενεργοποίηση φυσικού δικτύου", +"label.action.disable.pod" : "Απενεργοποίηση υποομάδας", +"label.action.disable.pod.processing" : "Η υποομάδα απενεργοποίείται (Pod) ....", +"label.action.disable.static.nat" : "Απενεργοποίηση στατικού NAT", +"label.action.disable.static.nat.processing" : "Απενεργοποίηση του στατικού NAT....", +"label.action.disable.user" : "Απενεργοποίηση χρήστη", +"label.action.disable.user.processing" : "Απενεργοποίηση χρήστη....", +"label.action.disable.zone" : "Απενεργοποίηση ζώνης", +"label.action.disable.zone.processing" : "Απενεργοποίηση ζώνης....", +"label.action.download.iso" : "Κατεβάστε το ISO", +"label.action.download.template" : "Λήψη προτύπου", +"label.action.download.volume" : "Λήψη τόμου", +"label.action.download.volume.processing" : "Λήψη τόμου....", +"label.action.edit.account" : "Επεξεργασία λογαριασμού", +"label.action.edit.disk.offering" : "Επεξεργασία προσφοράς υπηρεσίας δίσκου", +"label.action.edit.domain" : "Επεξεργασία τομέα", +"label.action.edit.global.setting" : "Επεξεργασία καθολικής ρύθμισης", +"label.action.edit.host" : "Επεξεργασία κεντρικού υπολογιστή", +"label.action.edit.instance" : "Επεξεργασία εικονική μηχανής", +"label.action.edit.iso" : "Επεξεργασία ISO", +"label.action.edit.network" : "Επεξεργασία δικτύου", +"label.action.edit.network.offering" : "Επεξεργασία προσφοράς υπηρεσίας δικτύου", +"label.action.edit.network.processing" : "Επεξεργασία δικτύου....", +"label.action.edit.pod" : "Επεξεργασία pod", +"label.action.edit.primary.storage" : "Επεξεργασία πρωτεύοντος χώρου αποθήκευσης", +"label.action.edit.resource.limits" : "Επεξεργασία ορίων πόρων", +"label.action.edit.service.offering" : "Επεξεργασία προσφοράς υπηρεσίας υπηρεσιών", +"label.action.edit.template" : "Επεξεργασία προτύπου", +"label.action.edit.user" : "Επεξεργασία χρήστη", +"label.action.edit.zone" : "Επεξεργασία ζώνης", +"label.action.enable.account" : "Ενεργοποίηση λογαριασμού", +"label.action.enable.account.processing" : "Ενεργοποίηση λογαριασμού....", +"label.action.enable.cluster" : "Ενεργοποίηση ομοταξίας", +"label.action.enable.cluster.processing" : "Ενεργοποίηση ομοταξίας....", +"label.action.enable.maintenance.mode" : "Ενεργοποίηση λειτουργίας συντήρησης", +"label.action.enable.maintenance.mode.processing" : "Ενεργοποίηση λειτουργίας συντήρησης....", +"label.action.enable.nexusvswitch" : "Ενεργοποίηση nexus 1000v", +"label.action.enable.physical.network" : "Ενεργοποίηση φυσικού δικτύου", +"label.action.enable.pod" : "Ενεργοποίηση pod", +"label.action.enable.pod.processing" : "Ενεργοποίηση Pod ....", +"label.action.enable.static.nat" : "Ενεργοποίηση στατικού NAT", +"label.action.enable.static.nat.processing" : "Ενεργοποίηση στατικού NAT....", +"label.action.enable.user" : "Ενεργοποίηση χρήστη", +"label.action.enable.user.processing" : "Ενεργοποίηση χρήστη....", +"label.action.enable.zone" : "Ενεργοποίηση ζώνης", +"label.action.enable.zone.processing" : "Ενεργοποίηση ζώνης....", +"label.action.expunge.instance" : "διαγραφή εικονική μηχανής", +"label.action.expunge.instance.processing" : "Παράδειγμα διαγραφής....", +"label.action.force.reconnect" : "Επιβολή επανασύνδεσης", +"label.action.force.reconnect.processing" : "Επανασύνδεση....", +"label.action.generate.keys" : "Δημιουργία κλειδιών", +"label.action.generate.keys.processing" : "Δημιουργία κλειδιών....", +"label.action.get.diagnostics" : "Λήψη διαγνωστικών δεδομένων", +"label.action.image.store.read.only" : "Μετατροπή χώρου αποθήκευσης ειδώλων σε κατάσταση μόνο ανάγωνσης read-only", +"label.action.image.store.read.write" : "Μετατροπή χώρου αποθήκευσης ειδώλων σε κατάσταση μόνο ανάγωνσης read-write", +"label.action.iso.permission" : "Ενημέρωση δικαιωμάτων ISO", +"label.action.iso.share" : "Ενημέρωση κοινής χρήσης ISO", +"label.action.list.nexusvswitch" : "Λίστα Nexus 1000v", +"label.action.lock.account" : "Κλείδωμα λογαριασμού", +"label.action.lock.account.processing" : "Κλείδωμα λογαριασμού....", +"label.action.manage.cluster" : "Διαχείριση ομοταξίας", +"label.action.manage.cluster.processing" : "Διαχείριση ομοταξίας....", +"label.action.migrate.instance" : "Μετεγκατάσταση εικονική μηχανής", +"label.action.migrate.instance.processing" : "Μετεγκατάσταση εικονική μηχανής....", +"label.action.migrate.router" : "Μετεγκατάσταση δρομολογητή", +"label.action.migrate.router.processing" : "Μετεγκατάσταση δρομολογητή....", +"label.action.migrate.router.to.ps" : "Μετεγκατάσταση δρομολογητή σε άλλο πρωτεύον αποθηκευτικό χώρο", +"label.action.migrate.systemvm" : "Μετεγκατάσταση εικονικής μηχανής συστήματος", +"label.action.migrate.systemvm.processing" : "Μετεγκατάσταση VM συστήματος....", +"label.action.migrate.systemvm.to.ps" : "Μετεγκατάσταση συστημικής εικονικής μηχανής σε άλλο πρωτεύον αποθηκευτικό χώρο", +"label.action.project.add.account" : "Προσθήκη λογαριασμού στο Project", +"label.action.project.add.user" : "Προσθήκη χρήστη στο Project", +"label.action.reboot.instance" : "Επανεκκίνηση εικονική μηχανής", +"label.action.reboot.instance.processing" : "Επανεκκίνηση εικονική μηχανής....", +"label.action.reboot.router" : "Επανεκκίνηση δρομολογητή", +"label.action.reboot.router.processing" : "Επανεκκίνηση δρομολογητή ....", +"label.action.reboot.systemvm" : "Επανεκκίνηση της εικονικής μηχανής συστήματος", +"label.action.reboot.systemvm.processing" : "Επανεκκίνηση του συστήματος VM ....", +"label.action.recover.volume" : "Ανάκτηση τόμου", +"label.action.recurring.snapshot" : "Επαναλαμβανόμενα στιγμιότυπα", +"label.action.register.iso" : "Καταχώρηση ISO", +"label.action.register.ncc" : "Καταχώρηση NCC", +"label.action.register.template" : "Καταχώρηση προτύπου από τη διεύθυνση URL", +"label.action.release.ip" : "Έκδοση IP", +"label.action.release.ip.processing" : "Αποδεσμεύεται η IP ....", +"label.action.remove.host" : "Κατάργηση κεντρικού υπολογιστή", +"label.action.remove.host.processing" : "Κατάργηση κεντρικού υπολογιστή....", +"label.action.remove.vm" : "Αποδέσμευση VM", +"label.action.reset.password" : "Επαναφορά κωδικού πρόσβασης", +"label.action.reset.password.processing" : "Επαναφορά κωδικού πρόσβασης....", +"label.action.resize.volume" : "Αλλαγή μεγέθους τόμου", +"label.action.resize.volume.processing" : "Αλλαγή μεγέθους τόμου....", +"label.action.resource.limits" : "Όρια πόρων", +"label.action.restore.instance" : "Επαναφορά εικονική μηχανής", +"label.action.restore.instance.processing" : "Επαναφορά εικονική μηχανής....", +"label.action.revert.snapshot" : "Επαναφορά στο στιγμιότυπο", +"label.action.revert.snapshot.processing" : "Επαναφορά στο στιγμιότυπο...", +"label.action.router.health.checks" : "Λήψη αποτελεσμάτων υγειονομικών ελέγχων", +"label.action.run.diagnostics" : "Εκτέλεση διαγνωστικών", +"label.action.secure.host" : "Παροχή κλειδιών ασφαλείας κεντρικού υπολογιστή", +"label.action.start.instance" : "Έναρξη εικονική μηχανής", +"label.action.start.instance.processing" : "Έναρξη εικονική μηχανής....", +"label.action.start.router" : "Εκκίνηση δρομολογητή", +"label.action.start.router.processing" : "Εκκίνηση δρομολογητή....", +"label.action.start.systemvm" : "Έναρξη εικονικής μηχανής συστήματος", +"label.action.start.systemvm.processing" : "Εκκίνηση του συστήματος VM ....", +"label.action.stop.instance" : "Διακοπή εικονική μηχανής", +"label.action.stop.instance.processing" : "Διακοπή εικονική μηχανής....", +"label.action.stop.router" : "Διακοπή δρομολογητή", +"label.action.stop.router.processing" : "Διακοπή δρομολογητή....", +"label.action.stop.systemvm" : "Διακοπή της εικονικής μηχανής συστήματος", +"label.action.stop.systemvm.processing" : "Διακοπή του συστήματος VM ....", +"label.action.take.snapshot" : "Λήψη στιγμιότυπου", +"label.action.take.snapshot.processing" : "Λήψη στιγμιότυπου....", +"label.action.template.permission" : "Ενημέρωση δικαιωμάτων προτύπου", +"label.action.template.share" : "Ενημέρωση κοινής χρήσης προτύπων", +"label.action.unmanage.cluster" : "Μη διαχείριση ομοταξίας", +"label.action.unmanage.cluster.processing" : "Μη διαχείριση ομοταξίας ....", +"label.action.unmanage.virtualmachine" : "Μη διαχείριση VM", +"label.action.update.offering.access" : "Ενημέρωση που προσφέρει πρόσβαση", +"label.action.update.os.preference" : "Ενημέρωση προτίμησης λειτουργικού συστήματος", +"label.action.update.os.preference.processing" : "Ενημέρωση προτίμησης λειτουργικού συστήματος....", +"label.action.update.resource.count" : "Ενημέρωση πλήθους πόρων", +"label.action.update.resource.count.processing" : "Ενημέρωση πλήθους πόρων....", +"label.action.vmsnapshot.create" : "Λήψη στιγμιότυπου VM", +"label.action.vmsnapshot.delete" : "Διαγραφή στιγμιότυπου VM", +"label.action.vmsnapshot.revert" : "Επαναφορά στο στιγμιότυπο VM", +"label.action.vmstoragesnapshot.create" : "Λήψη στιγμιότυπου τόμου VM", +"label.actions" : "Ενέργειες", +"label.activate.project" : "Ενεργοποίηση έργου", +"label.activeviewersessions" : "Ενεργές περίοδοι λειτουργίας", +"label.add" : "Προσθέσετε", +"label.add.account" : "Προσθήκη λογαριασμού", +"label.add.accounts" : "Προσθήκη λογαριασμών", +"label.add.accounts.to" : "Προσθήκη λογαριασμών σε", +"label.add.acl" : "Προσθήκη ACL", +"label.add.acl.list" : "Προσθήκη λίστας ACL", +"label.add.affinity.group" : "Προσθήκη νέας ομάδας συνάφειας", +"label.add.baremetal.dhcp.device" : "Προσθήκη συσκευής DHCP baremetal", +"label.add.baremetal.rack.configuration" : "Προσθήκη ρύθμισης παραμέτρων rack baremetal", +"label.add.bigswitchbcf.device" : "Προσθήκη ελεγκτή BCF BigSwitch", +"label.add.brocadevcs.device" : "Προσθήκη εναλλάκτη Brocade Vcs", +"label.add.by" : "Προσθήκη κατά", +"label.add.by.cidr" : "Προσθήκη κατά CIDR", +"label.add.by.group" : "Προσθήκη κατά ομάδα", +"label.add.certificate" : "Προσθήκη πιστοποιητικού", +"label.add.ciscoasa1000v" : "Προσθήκη πόρου CiscoASA1000v", +"label.add.cluster" : "Προσθήκη ομοταξίας", +"label.add.compute.offering" : "Προσθήκη προσφοράς υπηρεσίας υπολογισμού", +"label.add.direct.iprange" : "Προσθήκη περιοχής άμεσης ip", +"label.add.disk.offering" : "Προσθήκη προσφοράς υπηρεσίας δίσκου", +"label.add.domain" : "Προσθήκη τομέα", +"label.add.egress.rule" : "Προσθήκη κανόνα εξόδου", +"label.add.f5.device" : "Προσθήκη συσκευής F5", +"label.add.firewall" : "Προσθήκη κανόνα τείχους προστασίας", +"label.add.globo.dns" : "Προσθήκη GloboDNS", +"label.add.gslb" : "Προσθήκη GSLB", +"label.add.guest.network" : "Προσθήκη δικτύου επισκεπτών", +"label.add.host" : "Προσθήκη κεντρικού υπολογιστή", +"label.add.ingress.rule" : "Προσθήκη κανόνα εισόδου", +"label.add.intermediate.certificate" : "Προσθήκη ενδιάμεσου πιστοποιητικού", +"label.add.internal.lb" : "Προσθήκη εσωτερικού LB", +"label.add.ip.range" : "Προσθήκη περιοχής IP", +"label.add.isolated.guest.network" : "Προσθήκη απομονωμένου δικτύου επισκεπτών", +"label.add.isolated.guest.network.with.sourcenat" : "Προσθήκη απομονωμένου δικτύου επισκεπτών με SourceNat", +"label.add.isolated.network" : "Προσθήκη απομονωμένου δικτύου", +"label.add.kubernetes.cluster" : "Προσθήκη ομοταξίας Kubernetes", +"label.add.l2.guest.network" : "Προσθήκη δικτύου επισκεπτών L2", +"label.add.ldap.account" : "Προσθήκη λογαριασμού LDAP", +"label.add.ldap.list.users" : "Λίστα χρηστών LDAP", +"label.add.list.name" : "Όνομα λίστας ACL", +"label.add.load.balancer" : "Προσθήκη εξισορρόπησης φόρτου", +"label.add.management.ip.range" : "Προσθήκη περιοχής IP διαχείρισης", +"label.add.more" : "Προσθήκη περισσότερων", +"label.add.netscaler.device" : "Προσθήκη συσκευής Netsccaler", +"label.add.network" : "Προσθήκη δικτύου", +"label.add.network.acl" : "Προσθήκη ACL δικτύου", +"label.add.network.acl.list" : "Προσθήκη λίστας ACL δικτύου", +"label.add.network.device" : "Προσθήκη συσκευής δικτύου", +"label.add.network.offering" : "Προσθήκη προσφοράς υπηρεσίας δικτύου", +"label.add.new.f5" : "Προσθήκη νέου F5", +"label.add.new.gateway" : "Προσθήκη νέας πύλης", +"label.add.new.iso" : "Προσθήκη νέου ISO", +"label.add.new.netscaler" : "Προσθήκη νέου netsccaler", +"label.add.new.pa" : "Προσθήκη νέου Palo Alto", +"label.add.new.srx" : "Προσθήκη νέου SRX", +"label.add.new.tier" : "Προσθήκη νέας βαθμίδας", +"label.add.nfs.secondary.staging.store" : "Προσθήκη δευτερεύοντος χώρου αποθήκευσης ανασυγκρότησης NFS", +"label.add.niciranvp.device" : "Προσθήκη ελεγκτή Nvp", +"label.add.note" : "Προσθήκη σημείωσης", +"label.add.opendaylight.device" : "Προσθήκη ελεγκτή opendaylight", +"label.add.pa.device" : "Προσθήκη συσκευής Palo Alto", +"label.add.physical.network" : "Προσθήκη φυσικού δικτύου", +"label.add.pod" : "Προσθήκη pod", +"label.add.port.forwarding.rule" : "Προσθήκη κανόνα προώθησης θυρών", +"label.add.portable.ip.range" : "Προσθήκη φορητής περιοχής IP", +"label.add.primary.storage" : "Προσθήκη πρωτεύοντος χώρου αποθήκευσης", +"label.add.private.gateway" : "Προσθήκη ιδιωτικής πύλης", +"label.add.project.role" : "Προσθήκη ρόλου έργου", +"label.add.region" : "Προσθήκη περιοχής", +"label.add.resources" : "Προσθήκη πόρων", +"label.add.role" : "Προσθήκη ρόλου", +"label.add.route" : "Προσθήκη διαδρομής", +"label.add.rule" : "Προσθήκη κανόνα", +"label.add.rule.desc" : "Δημιουργία νέου κανόνα ACL", +"label.add.secondary.ip" : "Προσθήκη δευτερεύουσας διεύθυνσης IP", +"label.add.secondary.storage" : "Προσθήκη δευτερεύοντος χώρου αποθήκευσης", +"label.add.security.group" : "Προσθήκη ομάδας ασφαλείας", +"label.add.service.offering" : "Προσθήκη προσφοράς υπηρεσίας υπηρεσιών", +"label.add.setting" : "Προσθήκη ρύθμισης", +"label.add.srx.device" : "Προσθήκη συσκευής SRX", +"label.add.static.nat.rule" : "Προσθήκη στατικού κανόνα NAT", +"label.add.static.route" : "Προσθήκη στατικής διαδρομής", +"label.add.system.service.offering" : "Προσθήκη προσφοράς υπηρεσίας υπηρεσιών συστήματος", +"label.add.template" : "Προσθήκη προτύπου", +"label.add.to.group" : "Προσθήκη στην ομάδα", +"label.add.traffic" : "Προσθήκη κίνησης", +"label.add.traffic.type" : "Προσθήκη τύπου κίνησης", +"label.add.ucs.manager" : "Προσθήκη διαχειριστή UCS", +"label.add.user" : "Προσθήκη χρήστη", +"label.add.vlan" : "Προσθήκη VLAN", +"label.add.vm" : "Προσθήκη εικονικής μηχανής", +"label.add.vm.to.tier" : "Προσθήκη εικονικής μηχανής στη βαθμίδα", +"label.add.vms" : "Προσθήκη VM", +"label.add.vms.to.lb" : "Προσθήκη vm(s) σε κανόνα εξισορρόπησης φόρτου", +"label.add.vmware.datacenter" : "Προσθήκη κέντρου δεδομένων VMware", +"label.add.vnmc.device" : "Προσθήκη συσκευής VNMC", +"label.add.vnmc.provider" : "Προσθήκη υπηρεσίας παροχής VNMC", +"label.add.volume" : "Προσθήκη τόμου", +"label.add.vpc" : "Προσθήκη VPC", +"label.add.vpc.offering" : "Προσθήκη προσφοράς υπηρεσίας VPC", +"label.add.vpn.customer.gateway" : "Προσθήκη πύλης πελατών VPN", +"label.add.vpn.gateway" : "Προσθήκη πύλης VPN", +"label.add.vpn.user" : "Προσθήκη χρήστη VPN", +"label.add.vxlan" : "Προσθήκη VXLAN", +"label.add.zone" : "Προσθήκη ζώνης", +"label.addanothernetwork" : "Προσθήκη άλλου δικτύου", +"label.added.brocade.vcs.switch" : "Προστέθηκε νέος εναλλάκτης Μπροκάρ Vcs", +"label.added.network.offering" : "Προστέθηκε προσφορά δικτύου", +"label.added.new.bigswitch.bcf.controller" : "Προστέθηκε νέος ελεγκτής BigSwitch BCF", +"label.added.nicira.nvp.controller" : "Προστέθηκε νέος ελεγκτής NVP Nicira", +"label.addes.new.f5" : "Προστέθηκε νέο F5", +"label.adding" : "Προσθήκη", +"label.adding.cluster" : "Προσθήκη ομοταξίας", +"label.adding.failed" : "Η προσθήκη απέτυχε", +"label.adding.pod" : "Προσθήκη pod", +"label.adding.processing" : "Προσθήκη....", +"label.adding.succeeded" : "Η προσθήκη ολοκληρώθηκε με επιτυχία", +"label.adding.user" : "Προσθήκη χρήστη", +"label.adding.zone" : "Προσθήκη ζώνης", +"label.additional.networks" : "Πρόσθετα δίκτυα", +"label.addnewnetworks" : "Προσθήκη νέων δικτύων", +"label.address" : "Διεύθυνση", +"label.admin" : "Διαχειριστής τομέα", +"label.admin.accounts" : "Λογαριασμοί διαχειριστή", +"label.advanced" : "Προηγμένη", +"label.advanced.mode" : "Λειτουργία για προχωρημένους", +"label.advanced.search" : "Σύνθετη αναζήτηση", +"label.affinity" : "Συγγένεια", +"label.affinity.groups" : "Ομάδες συγγένειας", +"label.affinitygroup" : "Ομάδα συνάφειας", +"label.agent.password" : "Κωδικός πρόσβασης agent", +"label.agent.username" : "Όνομα χρήστη agent", +"label.agentport" : "Θύρα agent", +"label.agentstate" : "Κατάσταση agent", +"label.agree" : "Συμφωνούν", +"label.alert" : "Ειδοποίηση", +"label.alert.archived" : "Αρχειοθετηθεί ειδοποίηση", +"label.alert.deleted" : "Η ειδοποίηση διαγράφηκε", +"label.alert.details" : "Λεπτομέρειες ειδοποίησης", +"label.alerts" : "Ειδοποιήσεις", +"label.algorithm" : "Αλγόριθμο", +"label.all" : "Όλα", +"label.all.zone" : "Όλες οι ζώνες", +"label.allocated" : "Εκχωρηθεί", +"label.allocatediops" : "Εκχωρήθηκε IOPS", +"label.allocationstate" : "Κράτος κατανομής", +"label.allow" : "Επιτρέψει", +"label.allowuserdrivenbackups" : "Να επιτρέπονται αντίγραφα ασφαλείας που οδηγούνται από το χρήστη", +"label.annotated.by" : "Σχολιαστής", +"label.annotation" : "Σχολιασμός", +"label.anti.affinity" : "εκτος συνάφειας", +"label.anti.affinity.group" : "Ομάδα εκτος συνάφειας", +"label.anti.affinity.groups" : "Ομάδες εκτος συνάφειας", +"label.api.version" : "Έκδοση API", +"label.apikey" : "Κλειδί API", +"label.app.cookie" : "AppCookie", +"label.app.name" : "CloudStack", +"label.apply" : "Εφαρμόσετε", +"label.archive" : "Αρχείο", +"label.archive.alerts" : "Αρχειοθέτηση ειδοποιήσεων", +"label.archive.events" : "Αρχειοθέτηση συμβάντων", +"label.as.default" : "ως προεπιλογή", +"label.assign" : "Αντιστοιχίσετε", +"label.assign.instance.another" : "Αντιστοίχιση εικονική μηχανής σε άλλο λογαριασμό", +"label.assign.to.load.balancer" : "Αντιστοίχιση εικονική μηχανής στην εξισορρόπηση φόρτου", +"label.assign.vms" : "Αντιστοίχιση VM", +"label.assigning.vms" : "Αντιστοίχιση VM", +"label.associatednetwork" : "Συσχετισμένο δίκτυο", +"label.associatednetworkid" : "Συσχετισμένο αναγνωριστικό δικτύου", +"label.associatednetworkname" : "Όνομα δικτύου", +"label.asyncbackup" : "Ασύγχρονη δημιουργία αντιγράφων ασφαλείας", +"label.author.email" : "Συντάκτης ηλεκτρονικού ταχυδρομείου", +"label.author.name" : "Όνομα συντάκτη", +"label.autoscale" : "Αυτόματη κλίμακα", +"label.autoscale.configuration.wizard" : "Οδηγός ρύθμισης παραμέτρων αυτόματης κλίμακας", +"label.availability" : "Διαθεσιμότητα", +"label.availabilityzone" : "Ζώνη Διαθεσιμότητας", +"label.available" : "Διαθέσιμα", +"label.available.public.ips" : "Διαθέσιμες δημόσιες διευθύνσεις IP", +"label.back" : "Bck", +"label.backup" : "Αντίγραφα ασφαλείας", +"label.backup.attach.restore" : "Επαναφορά και επισύναψη τόμου αντιγράφου ασφαλείας", +"label.backup.offering.assign" : "Αντιστοίχιση εικονικής μηχανής σε προσφορά δημιουργίας αντιγράφων ασφαλείας", +"label.backup.offering.remove" : "Κατάργηση εικονικής μηχανής από την προσφορά δημιουργίας αντιγράφων ασφαλείας", +"label.backup.offerings" : "προσφορές υπηρεσίας δημιουργίας αντιγράφων ασφαλείας", +"label.backup.restore" : "Επαναφορά αντιγράφου ασφαλείας VM", +"label.backupofferingid" : "Προσφορά δημιουργίας αντιγράφων ασφαλείας", +"label.backupofferingname" : "Προσφορά δημιουργίας αντιγράφων ασφαλείας", +"label.balance" : "Ισορροπία", +"label.bandwidth" : "Εύρος ζώνης", +"label.baremetal.dhcp.devices" : "Συσκευές DHCP baremetal", +"label.baremetal.dhcp.provider" : "Υπηρεσία παροχής DHCP baremetal", +"label.baremetal.pxe.device" : "Προσθήκη συσκευής Baremetal PXE", +"label.baremetal.pxe.devices" : "Συσκευές Baremetal PXE", +"label.baremetal.pxe.provider" : "Υπηρεσία παροχής Baremetal PXE", +"label.baremetal.rack.configuration" : "Ρύθμιση παραμέτρων rack baremetal", +"label.baremetalcpu" : "CPU (σε MHz)", +"label.baremetalcpucores" : "# των πυρήνων cpu", +"label.baremetalmac" : "Κεντρικός υπολογιστής MAC", +"label.baremetalmemory" : "Μνήμη (σε MB)", +"label.based.on" : "Με βάση", +"label.based.on.role.id.or.type" : "Δημιουργεί έναν ρόλο με βάση το role id ή το type", +"label.basic" : "Βασικές", +"label.basic.mode" : "Βασική λειτουργία", +"label.basicsetup" : "Βασική ρύθμιση", +"label.bcfdeviceid" : "Αναγνωριστικό", +"label.bigswitch.bcf.details" : "Λεπτομέρειες για το BigSwitch BCF", +"label.bigswitch.controller.address" : "Διεύθυνση ελεγκτή BigSwitch BCF", +"label.bladeid" : "Αναγνωριστικό Blade", +"label.blades" : "Blades", +"label.bootable" : "Bootable", +"label.bootintosetup" : "Εκκίνηση στην εγκατάσταση υλικού", +"label.bootmode" : "Λειτουργία εκκίνησης", +"label.boottype" : "Τύπος εκκίνησης", +"label.broadcastdomainrange" : "Περιοχή τομέα μετάδοσης", +"label.broadcastdomaintype" : "Τύπος τομέα μετάδοσης", +"label.broadcasturi" : "URI μετάδοσης", +"label.brocade.vcs.address" : "Διεύθυνση εναλλαγής Vcs", +"label.brocade.vcs.details" : "Brocade Vcs εναλλάκτη λεπτομέρειες", +"label.bucket" : "Κουβά", +"label.by.account" : "Ανά λογαριασμό", +"label.by.alert.type" : "Κατά τύπο ειδοποίησης", +"label.by.availability" : "Κατά διαθεσιμότητα", +"label.by.domain" : "Κατά τομέα", +"label.by.end.date" : "Κατά ημερομηνία λήξης", +"label.by.event.type" : "Κατά τύπο συμβάντος", +"label.by.level" : "Κατά επίπεδο", +"label.by.pod" : "Με Pod", +"label.by.role" : "Κατά ρόλο", +"label.by.start.date" : "Κατά ημερομηνία έναρξης", +"label.by.state" : "Ανά κράτος", +"label.by.traffic.type" : "Κατά τύπο κίνησης", +"label.by.type" : "Κατά τύπο", +"label.by.type.id" : "Κατά αναγνωριστικό τύπου", +"label.by.zone" : "Ανά ζώνη", +"label.bypassvlanoverlapcheck" : "Παράκαμψη επικάλυψης ταυτότητας/περιοχής VLAN", +"label.cachemode" : "Τύπος cache εγγραφής", +"label.cancel" : "Ακυρώσετε", +"label.capacity" : "Ικανότητα", +"label.capacity.iops" : "IOPS χωρητικότητας", +"label.capacitybytes" : "Byte χωρητικότητας", +"label.capacityiops" : "Σύνολο IOPS", +"label.category" : "Κατηγορία", +"label.certchain" : "Αλυσίδα", +"label.certificate" : "Πιστοποιητικό", +"label.certificate.details" : "Λεπτομέρειες πιστοποιητικού", +"label.certificate.upload" : "Το πιστοποιητικό που φορτώθηκε", +"label.certificate.upload.failed" : "Η αποστολή πιστοποιητικού απέτυχε", +"label.certificate.upload.failed.description" : "Απέτυχε η ενημέρωση του πιστοποιητικού SSL. Απέτυχε η επιτυχία του ελέγχου επικύρωσης πιστοποιητικού", +"label.certificateid" : "Αναγνωριστικό πιστοποιητικού", +"label.change.affinity" : "Αλλαγή συνάφειας", +"label.change.ip.addess" : "Αλλαγή διεύθυνσης IP", +"label.change.ipaddress" : "Αλλαγή διεύθυνσης IP για nic", +"label.change.service.offering" : "Αλλαγή προσφοράς υπηρεσίας υπηρεσιών", +"label.change.value" : "Αλλαγή τιμής", +"label.character" : "Χαρακτήρα", +"label.chassis" : "Πλαίσιο", +"label.checksum" : "Άθροισμα ελέγχου", +"label.choose.saml.indentity" : "Επιλογή υπηρεσίας παροχής ταυτότητας SAML", +"label.cidr" : "Cidr", +"label.cidr.account" : "CIDR ή ομάδα λογαριασμού/ασφάλειας", +"label.cidr.destination.network" : "Δίκτυο προορισμού CIDR", +"label.cidr.of.destination.network" : "CIDR του δικτύου προορισμού", +"label.cidrlist" : "Κατάλογος CIDR", +"label.cisco.nexus1000v.ip.address" : "Διεύθυνση IP Nexus 1000v", +"label.cisco.nexus1000v.password" : "Nexus 1000v Κωδικός πρόσβασης", +"label.cisco.nexus1000v.username" : "Όνομα χρήστη Nexus 1000v", +"label.ciscovnmc.resource.details" : "Λεπτομέρειες πόρων CiscoVNMC", +"label.cks.cluster.size" : "Μέγεθος ομοταξίας (κόμβοι εργασίας)", +"label.cleanup" : "Καθαρισμός", +"label.clear" : "Σαφές", +"label.clear.list" : "Απαλοιφή λίστας", +"label.close" : "Κλείσιμο", +"label.cloud.console" : "Κονσόλα διαχείρισης cloud", +"label.cloud.managed" : "Διαχείριση Cloud.com", +"label.cloudian.storage" : "Χωρος Αποθήκευσης cloudian", +"label.cluster" : "ομοταξίας", +"label.cluster.name" : "Όνομα ομοταξίας", +"label.cluster.size" : "Μέγεθος ομοταξίας", +"label.clusterid" : "ομοταξίας", +"label.clustername" : "Όνομα ομοταξίας", +"label.clusternamelabel" : "Όνομα ομοταξίας", +"label.clusters" : "Συμπλέγματα", +"label.clustertype" : "Τύπος ομοταξίας", +"label.clvm" : "CLVM", +"label.code" : "Κωδικός", +"label.comma.separated.list.description" : "Εισαγωγή λίστας εντολών διαχωρισμένων με κόμματα", +"label.comments" : "Σχόλια", +"label.community" : "Κοινότητα", +"label.complete" : "Ολοκληρωθεί", +"label.compute" : "Υπολογίσετε", +"label.compute.and.storage" : "Υπολογισμός και αποθήκευση", +"label.compute.offering.access" : "Υπολογισμός πρόσβασης προσφοράς υπηρεσίας", +"label.compute.offerings" : "Υπολογισμός προσφορών", +"label.configuration" : "Ρύθμισης παραμέτρων", +"label.configure" : "Ρυθμίσετε", +"label.configure.ldap" : "Ρύθμιση παραμέτρων LDAP", +"label.configure.network.acls" : "Ρύθμιση παραμέτρων ACL δικτύου", +"label.configure.ovs" : "Ρύθμιση παραμέτρων ovs", +"label.configure.sticky.policy" : "Ρύθμιση παραμέτρων πολιτικής sticky", +"label.configure.vpc" : "Ρύθμιση παραμέτρων VPC", +"label.confirmacceptinvitation" : "Επιβεβαιώστε ότι επιθυμείτε να συμμετάσχετε σε αυτό το έργο", +"label.confirmation" : "Επιβεβαίωση", +"label.confirmdeclineinvitation" : "Είστε βέβαιοι ότι θέλετε να απορρίψετε αυτήν την πρόσκληση έργου;", +"label.confirmpassword" : "Επιβεβαίωση κωδικού πρόσβασης", +"label.confirmpassword.description" : "Πληκτρολογήστε ξανά τον ίδιο κωδικό πρόσβασης", +"label.congratulations" : "Συγχαρητήρια!!", +"label.connectiontimeout" : "Χρονικό όριο σύνδεσης", +"label.conservemode" : "Λειτουργία εξοικονόμησης", +"label.console.proxy" : "Διακομιστής μεσολάβησης κονσόλας", +"label.console.proxy.vm" : "VM διακομιστή μεσολάβησης κονσόλας", +"label.continue" : "Συνεχίσει", +"label.continue.install" : "Συνεχίστε με την εγκατάσταση", +"label.copied.clipboard" : "Αντιγράφηκε στο Πρόχειρο", +"label.copy" : "Αντίγραφο", +"label.copy.clipboard" : "Αντιγραφή στο Πρόχειρο", +"label.copy.text" : "Αντιγραφή κειμένου", +"label.copyid" : "Αναγνωριστικό αντιγραφής", +"label.copying.iso" : "Αντιγραφή ISO", +"label.corrections.saved" : "Αποθηκευμένες διορθώσεις", +"label.counterid" : "Μετρητή", +"label.cpu" : "Cpu", +"label.cpu.allocated" : "Εκχωρήθηκε cpu", +"label.cpu.sockets" : "Υποδοχές CPU", +"label.cpuallocated" : "Cpu που έχει εκχωρηθεί για VM", +"label.cpuallocatedghz" : "Εκχωρήθηκε cpu", +"label.cpulimit" : "Όρια CPU", +"label.cpumaxdeviation" : "Απόκλιση", +"label.cpunumber" : "Πυρήνες CPU", +"label.cpusockets" : "Ο αριθμός των υποδοχών CPU", +"label.cpuspeed" : "CPU (σε MHz)", +"label.cputotal" : "Σύνολο CPU", +"label.cputotalghz" : "Σύνολο CPU", +"label.cpuused" : "Cpu που χρησιμοποιείται", +"label.cpuusedghz" : "Cpu που χρησιμοποιήθηκε", +"label.create.account" : "Δημιουργία λογαριασμού", +"label.create.backup" : "Έναρξη δημιουργίας αντιγράφων ασφαλείας", +"label.create.network" : "Δημιουργία νέου δικτύου", +"label.create.network.gateway.description" : "Η πύλη της βαθμίδας στην περιοχή super CIDR και δεν επικαλύπτει το CIDR οποιουδήποτε άλλου επιπέδου σε αυτό το VPC.", +"label.create.network.netmask.description" : "Μάσκα δικτύου της βαθμίδας. Για παράδειγμα, με το VPC CIDR 10.0.0.0/16 και το cidr επιπέδου δικτύου 10.1.1.0/24, η πύλη είναι 10.1.1.1 και η μάσκα δικτύου είναι 255.255.255.0", +"label.create.nfs.secondary.staging.storage" : "Δημιουργία δευτερεύοντος χώρου αποθήκευσης ανασυγκρότησης NFS", +"label.create.nfs.secondary.staging.store" : "Δημιουργία δευτερεύοντος χώρου αποθήκευσης ανασυγκρότησης NFS", +"label.create.project" : "Δημιουργία έργου", +"label.create.project.role" : "Δημιουργία ρόλου έργου", +"label.create.site.vpn.connection" : "Δημιουργία σύνδεσης VPN από τοποθεσία σε τοποθεσία", +"label.create.site.vpn.gateway" : "Δημιουργία πύλης VPN από τοποθεσία σε τοποθεσία", +"label.create.snapshot.for.volume" : "Στιγμιότυπο που δημιουργήθηκε για τόμο", +"label.create.ssh.key.pair" : "Δημιουργία ζεύγους κλειδιών SSH", +"label.create.template" : "Δημιουργία προτύπου", +"label.create.user" : "Δημιουργία χρήστη", +"label.create.vpc.tier" : "Δημιουργία επιπέδου VPC", +"label.create.vpn.connection" : "Δημιουργία σύνδεσης VPN", +"label.created" : "Δημιουργήθηκε", +"label.created.by.system" : "Δημιουργήθηκε από το σύστημα", +"label.createnfscache" : "Δημιουργία δευτερεύοντος χώρου αποθήκευσης ανασυγκρότησης NFS", +"label.creating.iprange" : "Δημιουργία περιοχών IP", +"label.credit" : "Πιστωτική", +"label.crosszones" : "Διασταυρωτικές Ζώνες", +"label.currency" : "Νόμισμα", +"label.current" : "Τρέχον", +"label.currentpassword" : "Τρέχων κωδικός πρόσβασης", +"label.custom" : "Προσαρμοσμένη", +"label.custom.disk.offering" : "Προσφορά προσαρμοσμένου δίσκου", +"label.customconstrained" : "Προσαρμοσμένο περιορισμένο", +"label.customdisksize" : "Προσαρμοσμένο μέγεθος δίσκου", +"label.customunconstrained" : "Προσαρμοσμένη χωρίς περιορισμούς", +"label.daily" : "Καθημερινά", +"label.dashboard" : "Ταμπλό", +"label.dashboard.endpoint" : "Τελικό σημείο πίνακα εργαλείων", +"label.data.disk" : "Δίσκος δεδομένων", +"label.data.disk.offering" : "Προσφορά δίσκου δεδομένων", +"label.date" : "Ημερομηνία", +"label.day" : "Ημέρα", +"label.day.of.month" : "Ημέρα του Μήνα", +"label.day.of.week" : "Ημέρα της Εβδομάδας", +"label.dc.name" : "Όνομα ελεγκτή τομέα", +"label.decline.invitation" : "Απόρριψη πρόσκλησης", +"label.dedicate" : "Αφιερώσω", +"label.dedicate.cluster" : "αποκλειστικής χρήσης σύμπλεγμα", +"label.dedicate.host" : "αποκλειστικής χρήσης κεντρικός υπολογιστής", +"label.dedicate.pod" : "αποκλειστικής χρήσης υποομάδας", +"label.dedicate.vlan.vni.range" : "αποκλειστικής χρήσης περιοχή VLAN/VNI", +"label.dedicate.zone" : "Ζώνη αποκλειστικής χρήσης", +"label.dedicated" : "αποκλειστικής χρήσης", +"label.dedicated.vlan.vni.ranges" : "Αποκλειστικής χρήσης σειρές VLAN/VNI", +"label.default" : "Προεπιλογή", +"label.default.use" : "Προεπιλεγμένη χρήση", +"label.default.view" : "Προεπιλεγμένη προβολή", +"label.defaultnetwork" : "Προεπιλεγμένο δίκτυο", +"label.delete" : "Διαγραφή", +"label.delete.acl.list" : "Διαγραφή λίστας ACL", +"label.delete.affinity.group" : "Διαγραφή ομάδας συνάφειας", +"label.delete.alerts" : "Διαγραφή ειδοποιήσεων", +"label.delete.backup" : "Διαγραφή αντιγράφου ασφαλείας", +"label.delete.baremetal.rack.configuration" : "Διαγραφή ρύθμισης παραμέτρων του συνόλου baremetal", +"label.delete.bigswitchbcf" : "Κατάργηση ελεγκτή BCF BigSwitch", +"label.delete.brocadevcs" : "Κατάργηση εναλλάκτης βίντεο μπροκάρ", +"label.delete.certificate" : "Διαγραφή πιστοποιητικού", +"label.delete.ciscoasa1000v" : "Διαγραφή CiscoASA1000v", +"label.delete.ciscovnmc.resource" : "Διαγραφή πόρου CiscoVNMC", +"label.delete.confirm" : "Διαγραφή?", +"label.delete.dedicated.vlan.range" : "Διαγραμμένη αποκλειστική περιοχή VLAN/VNI", +"label.delete.domain" : "Διαγραφή τομέα", +"label.delete.events" : "Διαγραφή συμβάντων", +"label.delete.f5" : "Διαγραφή F5", +"label.delete.gateway" : "Διαγραφή πύλης", +"label.delete.instance.group" : "Διαγραφή ομάδας εικονική μηχανής", +"label.delete.internal.lb" : "Διαγραφή εσωτερικού LB", +"label.delete.netscaler" : "Διαγραφή κλίμακας δικτύου", +"label.delete.niciranvp" : "Κατάργηση ελεγκτή Nvp", +"label.delete.opendaylight.device" : "Διαγραφή ελεγκτή opendaylight", +"label.delete.pa" : "Διαγραφή Πάλο Άλτο", +"label.delete.portable.ip.range" : "Διαγραφή φορητής περιοχής IP", +"label.delete.project" : "Διαγραφή έργου", +"label.delete.project.role" : "Διαγραφή ρόλου έργου", +"label.delete.role" : "Διαγραφή ρόλου", +"label.delete.rule" : "Διαγραφή κανόνα", +"label.delete.secondary.staging.store" : "Διαγραφή δευτερεύοντος χώρου αποθήκευσης ανασυγκρότησης", +"label.delete.setting" : "Διαγραφή ρύθμισης", +"label.delete.snapshot.policy" : "Διαγραφή πολιτικής στιγμιότυπου", +"label.delete.srx" : "Διαγραφή SRX", +"label.delete.sslcertificate" : "Διαγραφή πιστοποιητικού SSL", +"label.delete.ucs.manager" : "Διαγραφή διαχειριστή UCS", +"label.delete.volumes" : "Τόμοι δεδομένων που θα διαγραφούν", +"label.delete.vpn.connection" : "Διαγραφή σύνδεσης VPN", +"label.delete.vpn.customer.gateway" : "Διαγραφή πύλης πελάτη VPN", +"label.delete.vpn.gateway" : "Διαγραφή πύλης VPN", +"label.delete.vpn.user" : "Διαγραφή χρήστη VPN", +"label.deleteconfirm" : "Επιβεβαιώστε ότι θέλετε να διαγράψετε αυτό το", +"label.deleteprofile" : "Διαγραφή προφίλ", +"label.deleting" : "Διαγραφή", +"label.deleting.failed" : "Η διαγραφή απέτυχε", +"label.deleting.iso" : "Διαγραφή ISO", +"label.deleting.processing" : "Διαγραφή....", +"label.deleting.template" : "Διαγραφή προτύπου", +"label.demote.project.owner" : "Υποβιβασμός λογαριασμού σε κανονικό ρόλο", +"label.demote.project.owner.user" : "Υποβιβασμός χρήστη σε κανονικό ρόλο", +"label.deny" : "Άρνηση", +"label.deployasis" : "Ανάγωση ρυθμίσων VM απο OVA", +"label.deploymentplanner" : "Σχεδιασμός ανάπτυξης", +"label.description" : "Περιγραφή", +"label.destcidr" : "Προορισμός CIDR", +"label.destination" : "Προορισμού", +"label.destinationphysicalnetworkid" : "Αναγνωριστικό φυσικού δικτύου προορισμού", +"label.destinationzoneid" : "Ζώνη προορισμού", +"label.destroy" : "Καταστροφή", +"label.destroy.kubernetes.cluster" : "Καταστροφή του ομοταξίας Kubernetes", +"label.destroy.router" : "Καταστροφή του δρομολογητή", +"label.destroyvmgraceperiod" : "Καταστροφή περιόδου χάριτος VM", +"label.detaching.disk" : "Αποσύνδεση δίσκου", +"label.details" : "Λεπτομέρειες", +"label.deviceid" : "Αναγνωριστικό συσκευής", +"label.devices" : "Συσκευές", +"label.dhcp" : "Dhcp", +"label.dhcp.server.type" : "Τύπος διακομιστή DHCP", +"label.direct.attached.public.ip" : "Άμεση συνημμένη δημόσια IP", +"label.direct.ips" : "Υπηρεσίες ip κοινόχρηστου δικτύου", +"label.directdownload" : "Άμεση λήψη", +"label.disable.autoscale" : "Απενεργοποίηση αυτόματης κλίμακας", +"label.disable.host" : "Απενεργοποίηση κεντρικού υπολογιστή", +"label.disable.storage" : "Απενεργοποίηση χώρου συγκέντρωσης χώρου αποθήκευσης", +"label.disable.network.offering" : "Απενεργοποίηση προσφοράς υπηρεσίας δικτύου", +"label.disable.provider" : "Απενεργοποίηση υπηρεσίας παροχής", +"label.disable.vnmc.provider" : "Απενεργοποίηση υπηρεσίας παροχής VNMC", +"label.disable.vpc.offering" : "Απενεργοποίηση προσφοράς υπηρεσίας VPC", +"label.disable.vpn" : "Απενεργοποίηση VPN απομακρυσμένης πρόσβασης", +"label.disabled" : "Απενεργοποιημένη", +"label.disabling.vpn.access" : "Απενεργοποίηση πρόσβασης VPN", +"label.disassociate.profile.blade" : "Κατάργηση συσχέτισης προφίλ από το Blade", +"label.disbale.vnmc.device" : "Απενεργοποίηση συσκευής VNMC", +"label.disconnected" : "Τελευταία αποσύνδεση", +"label.disk" : "Δίσκο", +"label.disk.newoffering" : "Νέα προσφορά δίσκου", +"label.disk.newoffering.description" : "Νέα προσφορά δίσκου που θα χρησιμοποιηθεί από αυτόν τον τόμο μετά τη μετεγκατάσταση.", +"label.disk.offering.access" : "Δίσκος που προσφέρει πρόσβαση", +"label.disk.offering.details" : "Δίσκος που προσφέρει λεπτομέρειες", +"label.disk.offerings" : "προσφορές υπηρεσίας δίσκων", +"label.disk.size" : "Μέγεθος δίσκου", +"label.disk.volume" : "Τόμος δίσκου", +"label.diskbytesreadrate" : "Ρυθμός ανάγνωσης δίσκου (BPS)", +"label.diskbyteswriterate" : "Ρυθμός εγγραφής δίσκου (BPS)", +"label.diskiopsmax" : "Μέγιστο IOPS", +"label.diskiopsmin" : "Min IOPS", +"label.diskiopsreadrate" : "Ρυθμός ανάγνωσης δίσκου (IOPS)", +"label.diskiopstotal" : "IOPS δίσκου", +"label.diskiopswriterate" : "Ρυθμός εγγραφής δίσκου (IOPS)", +"label.diskioread" : "Ανάγνωση δίσκου (IO)", +"label.diskiowrite" : "Εγγραφή δίσκου (IO)", +"label.diskkbsread" : "Ανάγνωση δίσκου (byte)", +"label.diskkbswrite" : "Εγγραφή δίσκου (byte)", +"label.diskoffering" : "Προσφορά δίσκου", +"label.diskofferingdisplaytext" : "Προσφορά δίσκου", +"label.diskofferingid" : "Προσφορά δίσκου", +"label.disksize" : "Μέγεθος δίσκου (σε GB)", +"label.disksizeallocated" : "o δίσκος εκχωρήθηκε", +"label.disksizeallocatedgb" : "Εκχωρηθεί", +"label.disksizetotal" : "Σύνολο δίσκου", +"label.disksizetotalgb" : "Σύνολο", +"label.disksizeunallocatedgb" : "Μη εκχωρημένο", +"label.disksizeused" : "Μέγεθος δίσκου που χρησιμοποιείται", +"label.disksizeusedgb" : "Χρησιμοποιείται", +"label.display.text" : "Εμφάνιση κειμένου", +"label.displayname" : "Εμφανιζόμενο όνομα", +"label.displaytext" : "Περιγραφή", +"label.distributedvpcrouter" : "Κατανεμημένος δρομολογητής VPC", +"label.dns" : "Dns", +"label.dns.domain.for.guest.networks" : "Τομέας DNS για δίκτυα επισκεπτών", +"label.dns1" : "DNS 1", +"label.dns2" : "DNS 2", +"label.domain" : "Τομέα", +"label.domain.details" : "Λεπτομέρειες τομέα", +"label.domain.id" : "Αναγνωριστικό τομέα", +"label.domain.name" : "Όνομα τομέα", +"label.domain.router" : "Δρομολογητής τομέα", +"label.domain.suffix" : "Επίθημα τομέα DNS (π.χ. xyz.com)", +"label.domainid" : "Τομέα", +"label.domainname" : "Τομέα", +"label.domainpath" : "Τομέα", +"label.domains" : "Τομείς", +"label.done" : "Γίνει", +"label.double.quotes.are.not.allowed" : "Δεν επιτρέπονται διπλά εισαγωγικά", +"label.download" : "Κατέβασμα", +"label.download.kubeconfig.cluster" : "Κατεβάστε το kubeconfig για το σύμπλεγμα

Το kubectl εργαλείο γραμμής εντολών χρησιμοποιεί αρχεία kubeconfig για να βρει τις πληροφορίες που χρειάζεται για να επιλέξει ένα σύμπλεγμα και να επικοινωνήσει με το διακομιστή API ενός ομοταξίας.", +"label.download.kubectl" : "Κατεβάστε kubectl το εργαλείο για την έκδοση ομοταξίας Kubernetes", +"label.download.kubernetes.cluster.config" : "Κατεβάστε kubernetes σύμπλεγμα config", +"label.download.progress" : "Λήψη προόδου", +"label.dpd" : "Εντοπισμός αδρανών ομοτίμων", +"label.drag.new.position" : "Μεταφορά σε νέα θέση", +"label.driver" : "Πρόγραμμα οδήγησης", +"label.duration.in.sec" : "Διάρκεια (σε δευτερόλεπτα)", +"label.dynamicscalingenabled" : "Δυναμική αναπροσαρμογή Ενεργοποίημένη", +"label.dynamicscalingenabled.tooltip" : "To VM μπορεί να αναπροσαρμόζεται δυναμικά μόνο αν τα πρότυπο,προσφερόμενη υπηρεσία και γενικές ρυθμίσεις έχουν την επιλογή δυναμικής αναπροσαρμογής ενεργοποιήμενη.", +"label.edit" : "Επεξεργασία", +"label.edit.acl.list" : "Επεξεργασία λίστας ACL", +"label.edit.acl.rule" : "Επεξεργασία κανόνα ACL", +"label.edit.affinity.group" : "Επεξεργασία ομάδας συνάφειας", +"label.edit.lb.rule" : "Επεξεργασία κανόνα LB", +"label.edit.network.details" : "Επεξεργασία λεπτομερειών δικτύου", +"label.edit.project.details" : "Επεξεργασία λεπτομερειών έργου", +"label.edit.project.role" : "Επεξεργασία ρόλου έργου", +"label.edit.region" : "Επεξεργασία περιοχής", +"label.edit.role" : "Επεξεργασία ρόλου", +"label.edit.rule" : "Επεξεργασία κανόνα", +"label.edit.secondary.ips" : "Επεξεργασία δευτερευουσών ips", +"label.edit.tags" : "Επεξεργασία ετικετών", +"label.edit.traffic.type" : "Επεξεργασία τύπου κίνησης", +"label.edit.user" : "Επεξεργασία χρήστη", +"label.edit.vpc" : "Επεξεργασία VPC", +"label.egress" : "Έξοδος", +"label.egress.default.policy" : "Έξοδος προεπιλεγμένη πολιτική", +"label.egress.rule" : "Κανόνας εξόδου", +"label.egress.rules" : "Κανόνες εξόδου", +"label.egressdefaultpolicy" : "Προεπιλεγμένη πολιτική εξόδου", +"label.elastic" : "Elastic", +"label.email" : "Email", +"label.enable.autoscale" : "Ενεργοποίηση αυτόματης κλίμακας", +"label.enable.host" : "Ενεργοποίηση κεντρικού υπολογιστή", +"label.enable.network.offering" : "Ενεργοποίηση προσφοράς υπηρεσίας δικτύου", +"label.enable.provider" : "Ενεργοποίηση υπηρεσίας παροχής", +"label.enable.s3" : "Ενεργοποίηση δευτερεύοντος χώρου αποθήκευσης με υποστήριξη S3", +"label.enable.swift" : "Ενεργοποίηση γρήγορης ταχύτητας", +"label.enable.storage" : "Ενεργοποίηση χώρου συγκέντρωσης χώρου αποθήκευσης", +"label.enable.vnmc.device" : "Ενεργοποίηση συσκευής VNMC", +"label.enable.vnmc.provider" : "Ενεργοποίηση υπηρεσίας παροχής VNMC", +"label.enable.vpc.offering" : "Ενεργοποίηση προσφοράς υπηρεσίας VPC", +"label.enable.vpn" : "Ενεργοποίηση VPN απομακρυσμένης πρόσβασης", +"label.enabling.vpn" : "Ενεργοποίηση VPN", +"label.enabling.vpn.access" : "Ενεργοποίηση πρόσβασης VPN", +"label.end" : "Τέλος", +"label.end.ip" : "Τερματισμός IP", +"label.end.reserved.system.ip" : "Τερματισμός δεσμευμένου συστήματος IP", +"label.end.vlan" : "Τέλος VLAN", +"label.end.vxlan" : "Τέλος VXLAN", +"label.enddate" : "Κατά ημερομηνία (τέλος)", +"label.endip" : "Τερματισμός IP", +"label.endipv4" : "Τερματισμός IP IPv4", +"label.endipv6" : "Τερματισμός IP IPv6", +"label.endpoint" : "Τελικό σημείο", +"label.endpoint.or.operation" : "Τελικό σημείο ή λειτουργία", +"label.endport" : "Θύρα τέλους", +"label.enter.token" : "Εισαγωγή διακριτικού", +"label.error" : "Σφάλμα", +"label.error.caught" : "Εντοπίστηκε σφάλμα", +"label.error.code" : "Κωδικός σφάλματος", +"label.error.file.read" : "Δεν είναι δυνατή η ανάγνωση του αρχείου", +"label.error.file.upload" : "Η αποστολή του αρχείου απέτυχε", +"label.error.rules.file.import" : "Επιλέξτε ένα έγκυρο αρχείο κανόνων CSV", +"label.error.setting" : "Ρύθμιση σφάλματος", +"label.error.something.went.wrong.please.correct.the.following" : "Κάτι πήγε στραβά. Διορθώστε τα ακόλουθα", +"label.error.upper" : "Σφάλμα", +"label.error.volume.upload" : "Επιλέξτε ένα αρχείο", +"label.espencryption" : "Κρυπτογράφηση ESP", +"label.esphash" : " Hash ESP", +"label.esplifetime" : "Διάρκεια ζωής ESP (δεύτερη)", +"label.esppolicy" : "Πολιτική ESP", +"label.event" : "Συμβάν", +"label.event.archived" : "Αρχειοθετημένα συμβάντα", +"label.event.deleted" : "Τα συμβάντα διαγράφηκαν", +"label.event.timeline" : "χρονοδιάγραμμα συμβάντος", +"label.events" : "Εκδηλώσεις", +"label.every" : "Κάθε", +"label.example" : "Παράδειγμα", +"label.example.plugin" : "Παράδειγμα plugin", +"label.existingnetworks" : "Υφιστάμενα δίκτυα", +"label.expunge" : "Διαγραφή", +"label.expunged" : "Απόκρυψη", +"label.expunging" : "Διαγραφή", +"label.external.link" : "Εξωτερική σύνδεση", +"label.externalid" : "Εξωτερικό αναγνωριστικό", +"label.externalloadbalanceripaddress" : "Διεύθυνση IP της εξωτερικής εξισορρόπησης φόρτου", +"label.extra" : "Επιπλέον ορίσματα", +"label.f5" : "F5", +"label.f5.details" : "F5 λεπτομέρειες", +"label.f5.ip.loadbalancer" : "F5 μεγάλος ισορροπητής φορτίων Ip", +"label.failed" : "Απέτυχε", +"label.featured" : "Επιλεγμένα", +"label.fetch.latest" : "Λήψη της τελευταίας", +"label.files" : "Εναλλακτικά αρχεία για ανάκτηση", +"label.filter" : "Φίλτρο", +"label.filterby" : "Φιλτράρισμα κατά", +"label.fingerprint" : "Δακτυλικών αποτυπωμάτων", +"label.firewall" : "Τείχος προστασίας", +"label.firstname" : "Όνομα", +"label.firstname.lower" : "Όνομα", +"label.fix.errors" : "Επιδιόρθωση σφαλμάτων", +"label.fixed" : "Σταθερή προσφορά", +"label.for" : "Για", +"label.forbidden" : "Απαγορεύεται", +"label.forced" : "Επιβολή", +"label.forceencap" : "Επιβολή ενθυλάκωσης UDP των πακέτων ESP", +"label.forgedtransmits" : "Πλαστά μεταδίδει", +"label.format" : "Μορφή", +"label.french.azerty.keyboard" : "Γαλλικό πληκτρολόγιο AZERTY", +"label.friday" : "Παρασκευή", +"label.from" : "Από", +"label.from.lb" : "από LB", +"label.full" : "Πλήρη", +"label.full.path" : "Πλήρης διαδρομή", +"label.fwdeviceid" : "Αναγνωριστικό", +"label.fwdevicename" : "Πληκτρολογήστε", +"label.fwdevicestate" : "Κατάσταση", +"label.gateway" : "Πύλη", +"label.general.alerts" : "Γενικές ειδοποιήσεις", +"label.generating.url" : "Δημιουργία διεύθυνσης URL", +"label.get.diagnostics.desc" : "Εάν θέλετε να παρακάμψετε τα τυπικά αρχεία που επιστρέφονται, εισαγάγετέ τα εδώ. Διαφορετικά αφήστε κενό και πατήστε OK", +"label.global.settings" : "Καθολικές ρυθμίσεις", +"label.globo.dns" : "GloboDNS", +"label.globo.dns.configuration" : "Ρύθμιση παραμέτρων GloboDNS", +"label.glustervolume" : "Όγκο", +"label.go.back" : "Πήγαινε πίσω", +"label.go.step.2" : "Μετάβαση στο Βήμα 2", +"label.go.step.3" : "Μετάβαση στο Βήμα 3", +"label.go.step.4" : "Μετάβαση στο Βήμα 4", +"label.go.step.5" : "Μετάβαση στο Βήμα 5", +"label.gpu" : "Gpu", +"label.group" : "Ομάδα", +"label.group.by.account" : "Ομαδοποίηση κατά λογαριασμό", +"label.group.by.cluster" : "Ομαδοποίηση κατά σύμπλεγμα", +"label.group.by.pod" : "Ομαδοποίηση κατά υποομάδα", +"label.group.by.zone" : "Ομαδοποίηση κατά ζώνη", +"label.group.optional" : "Ομάδα (Προαιρετικό)", +"label.gslb" : "GSLB", +"label.gslb.assigned.lb" : "Αντιστοιχισμένη εξισορρόπηση φόρτου", +"label.gslb.assigned.lb.more" : "Αντιστοίχιση μεγαλύτερης εξισορρόπησης φόρτου", +"label.gslb.delete" : "Διαγραφή GSLB", +"label.gslb.details" : "Λεπτομέρειες GSLB", +"label.gslb.lb.details" : "Λεπτομέρειες εξισορρόπησης φόρτου", +"label.gslb.lb.remove" : "Κατάργηση εξισορρόπησης φόρτου από αυτό το GSLB", +"label.gslb.service" : "Υπηρεσία GSLB", +"label.gslb.service.private.ip" : "Υπηρεσία GSLB Ιδιωτική IP", +"label.gslb.service.public.ip" : "Υπηρεσία GSLB Δημόσια IP", +"label.gslbdomainname" : "Όνομα τομέα GSLB", +"label.gslbprovider" : "Υπηρεσία GSLB", +"label.gslbproviderprivateip" : "Υπηρεσία GSLB Ιδιωτική IP", +"label.gslbproviderpublicip" : "Υπηρεσία GSLB Δημόσια IP", +"label.gslbservicetype" : "Τύπος υπηρεσίας", +"label.guest" : "Επισκέπτη", +"label.guest.cidr" : "Επισκέπτης CIDR", +"label.guest.end.ip" : "Ip λήξης επισκέπτη", +"label.guest.gateway" : "Πύλη επισκέπτη", +"label.guest.ip" : "Διεύθυνση IP επισκέπτη", +"label.guest.ip.range" : "Εύρος IP επισκέπτη", +"label.guest.netmask" : "Netmask επισκέπτη", +"label.guest.network.details" : "Λεπτομέρειες δικτύου επισκεπτών", +"label.guest.networks" : "Δίκτυα επισκεπτών", +"label.guest.start.ip" : "Εκκίνηση ip επισκέπτη", +"label.guest.traffic" : "Κίνηση επισκεπτών", +"label.guestcidraddress" : "Επισκέπτης CIDR", +"label.guestendip" : "Ip λήξης επισκέπτη", +"label.guestgateway" : "Πύλη επισκέπτη", +"label.guestipaddress" : "Διεύθυνση IP επισκέπτη", +"label.guestiptype" : "Τύπος επισκέπτη", +"label.guestnetmask" : "Netmask επισκέπτη", +"label.guestnetwork" : "Δίκτυο επισκεπτών", +"label.guestnetworkid" : "Αναγνωριστικό δικτύου", +"label.guestnetworkname" : "Όνομα δικτύου", +"label.guestosid" : "Τύπος λειτουργικού συστήματος", +"label.gueststartip" : "Εκκίνηση ip επισκέπτη", +"label.guestvlanrange" : "Εύρος(-ες) VLAN", +"label.guestvmcidr" : "Cidr", +"label.ha" : "HA", +"label.ha.configure" : "Ρύθμιση παραμέτρων HA", +"label.ha.disable" : "Απενεργοποίηση HA", +"label.ha.enable" : "Ενεργοποίηση HA", +"label.haenable" : "Ενεργοποίηση HA", +"label.hahost" : "Ενεργοποίηση HA", +"label.haprovider" : "Υπηρεσία παροχής HA", +"label.hardware" : "Υλικού", +"label.hastate" : "Κράτος HA", +"label.header.backup.schedule" : "Μπορείτε να ρυθμίσετε επαναλαμβανόμενα χρονοδιαγράμματα δημιουργίας αντιγράφων ασφαλείας επιλέγοντας από τις παρακάτω διαθέσιμες επιλογές και εφαρμόζοντας τις προτιμήσεις πολιτικής σας", +"label.header.volume.snapshot" : "Μπορείτε να ρυθμίσετε επαναλαμβανόμενα χρονοδιαγράμματα στιγμιότυπων επιλέγοντας από τις παρακάτω διαθέσιμες επιλογές και εφαρμόζοντας τις προτιμήσεις πολιτικής σας", +"label.header.volume.take.snapshot" : "Επιβεβαιώστε ότι θέλετε να τραβήξετε ένα στιγμιότυπο αυτού του τόμου.", +"label.health.check" : "Έλεγχος υγείας", +"label.health.check.advanced.options" : "Επιλογές για προχωρημένους:", +"label.health.check.configurations.options" : "Επιλογές ρυθμίσεων:", +"label.health.check.interval.in.sec" : "Διάστημα ελέγχου εύρυθμης λειτουργίας (σε δευτερόλεπτο)", +"label.health.check.message.desc" : "Η εξισορρόπηση φόρτου θα εκτελεί αυτόματα ελέγχους εύρυθμης λειτουργίας στις παρουσίες cloudtack και θα δρομολογεί την κίνηση μόνο σε παρουσίες που περνούν τον έλεγχο εύρυθμης λειτουργίας", +"label.health.check.wizard" : "Οδηγός ελέγχου εύρυθμης λειτουργίας", +"label.healthy.threshold" : "Υγιές κατώφλι", +"label.help" : "Βοήθεια", +"label.hide.ingress.rule" : "Απόκρυψη κανόνα εισόδου", +"label.hideipaddressusage" : "Απόκρυψη χρήσης διεύθυνσης IP", +"label.hints" : "Υποδείξεις", +"label.home" : "Αρχική", +"label.host" : "Διεύθυνση IP", +"label.host.alerts" : "Κεντρικοί υπολογιστές σε κατάσταση προειδοποίησης", +"label.host.name" : "Όνομα κεντρικού υπολογιστή", +"label.host.tag" : "Ετικέτα κεντρικού υπολογιστή", +"label.host.ueficapability" : "Υποστηρίζεται UEFI", +"label.hostid" : "Κεντρικού υπολογιστή", +"label.hostname" : "Κεντρικού υπολογιστή", +"label.hostnamelabel" : "Όνομα κεντρικού υπολογιστή", +"label.hosts" : "Hosts", +"label.hosttags" : "Ετικέτες κεντρικού υπολογιστή", +"label.hourly" : "Ωριαία", +"label.hypervisor" : "Hypervisor", +"label.hypervisor.capabilities" : "Δυνατότητες Hypervisor", +"label.hypervisor.type" : "Τύπος Hypervisor", +"label.hypervisors" : "Υπερεπόπτες", +"label.hypervisorsnapshotreserve" : "Αποθεματικό στιγμιότυπου Hypervisor", +"label.hypervisortype" : "Hypervisor", +"label.hypervisorversion" : "Έκδοση Hypervisor", +"label.hypervnetworklabel" : "Ετικέτα κίνησης HyperV", +"label.i.accept.all.license.agreements" : "Αποδέχομαι όλες τις άδειες χρήσης", +"label.icmp" : "Icmp", +"label.icmpcode" : "Κωδικός ICMP", +"label.icmpcode.end.port" : "Κωδικός ICMP / Τελική θύρα", +"label.icmptype" : "Τύπος ICMP", +"label.icmptype.start.port" : "Τύπος ICMP / Θύρα έναρξης", +"label.id" : "Αναγνωριστικό", +"label.identity.and.access" : "Ταυτότητα και πρόσβαση", +"label.ike.version" : "IKE Έδκοση", +"label.ikedh" : "IKE DH", +"label.ikeencryption" : "Κρυπτογράφηση IKE", +"label.ikehash" : "Κατακερματισμός IKE", +"label.ikelifetime" : "Διάρκεια ζωής IKE (δεύτερη)", +"label.ikepolicy" : "Πολιτική IKE", +"label.ikeversion" : "IKE Version", +"label.images" : "Εικόνες", +"label.import.backup.offering" : "Εισαγωγή προσφοράς υπηρεσίας δημιουργίας αντιγράφων ασφαλείας", +"label.import.offering" : "Προσφορά εισαγωγής", +"label.import.role" : "Ρόλος εισαγωγής", +"label.in.progress" : "σε εξέλιξη", +"label.in.progress.for" : "σε εξέλιξη για", +"label.info" : "Πληροφορίες", +"label.info.upper" : "Πληροφορίες", +"label.infrastructure" : "Υποδομή", +"label.ingress" : "Διείσδυση", +"label.ingress.rule" : "Κανόνας εισόδου", +"label.initiated.by" : "Ξεκίνησε από", +"label.insideportprofile" : "Εσωτερικό προφίλ θύρας", +"label.installwizard.addclusterintro.subtitle" : "Τι είναι ένα σύμπλεγμα;", +"label.installwizard.addclusterintro.title" : "Ας προσθέσουμε ένα σύμπλεγμα", +"label.installwizard.addhostintro.subtitle" : "Τι είναι ο κεντρικός υπολογιστής;", +"label.installwizard.addhostintro.title" : "Ας προσθέσουμε έναν κεντρικό υπολογιστή", +"label.installwizard.addpodintro.subtitle" : "Τι είναι η υποομάδα (pod);", +"label.installwizard.addpodintro.title" : "Ας προσθέσουμε μία υποομάδα", +"label.installwizard.addprimarystorageintro.subtitle" : "Τι είναι ο κύριος χώρος αποθήκευσης;", +"label.installwizard.addprimarystorageintro.title" : "Ας προσθέσουμε κύριο χώρο αποθήκευσης", +"label.installwizard.addsecondarystorageintro.subtitle" : "Τι είναι η δευτερεύουσα αποθήκευση;", +"label.installwizard.addsecondarystorageintro.title" : "Ας προσθέσουμε δευτερεύοντα χώρο αποθήκευσης", +"label.installwizard.addzoneintro.subtitle" : "Τι είναι η ζώνη;", +"label.installwizard.addzoneintro.title" : "Ας προσθέσουμε μια ζώνη", +"label.installwizard.click.launch" : "Κάντε κλικ στο κουμπί εκκίνησης.", +"label.installwizard.subtitle" : "Αυτός ο οδηγός θα σας βοηθήσει στη ρύθμιση της εγκατάστασης ™ CloudStack", +"label.installwizard.title" : "Γεια σας και καλώς ήρθατε στο CloudStack™", +"label.instance" : "Παράδειγμα", +"label.instance.groups" : "Ομάδες εικονική μηχανής", +"label.instance.name" : "Όνομα εικονική μηχανής", +"label.instance.scaled.up" : "εικονική μηχανή που κλιμακώνεται στην προσφορά που ζητήθηκε", +"label.instancename" : "Εσωτερικό όνομα", +"label.instanceport" : "Θύρα εικονική μηχανής", +"label.instances" : "Περιπτώσεις", +"label.instanciate.template.associate.profile.blade" : "Αρχικοποίηση προτύπου και συσχέτιση προφίλ με blade", +"label.intermediate.certificate" : "Ενδιάμεσο πιστοποιητικό", +"label.internal.dns.1" : "Εσωτερικό DNS 1", +"label.internal.dns.2" : "Εσωτερικό DNS 2", +"label.internal.lb" : "Εσωτερικό LB", +"label.internal.lb.details" : "Εσωτερικές λεπτομέρειες LB", +"label.internaldns1" : "Εσωτερικό DNS 1", +"label.internaldns2" : "Εσωτερικό DNS 2", +"label.internallb.description" : "Σύντομη περιγραφή της εσωτερικής LB", +"label.internallb.name.description" : "Μοναδικό όνομα για εσωτερική LB", +"label.internallb.sourceip.description" : "Σύντομη περιγραφή της εσωτερικής LB", +"label.internallbvm" : "ΕσωτερικήlbVm", +"label.interval" : "Διάστημα σταθμοσκόπησης (σε δευτερόλεπτο)", +"label.intervaltype" : "Τύπος διαστήματος", +"label.introduction.to.cloudstack" : "Εισαγωγή στο CloudStack™", +"label.invalid.integer" : "Ο ακέραιος δεν είναι έγκυρος", +"label.invalid.number" : "Μη έγκυρος αριθμός", +"label.invitations" : "Προσκλήσεις", +"label.invite" : "Προσκαλέσετε", +"label.invite.to" : "Πρόσκληση σε", +"label.invited.accounts" : "Προσκεκλημένοι λογαριασμοί", +"label.ip" : "Διεύθυνση IP", +"label.ip.allocations" : "Εκχωρήσεις IP", +"label.ip.or.fqdn" : "IP ή FQDN", +"label.ip.range" : "Περιοχή IP", +"label.ip.ranges" : "Περιοχές IP", +"label.ip4dns1" : "IPv4 DNS1", +"label.ip4dns2" : "Dns4 του IPv4", +"label.ip4gateway" : "Πύλη IPv4", +"label.ip4netmask" : "Μάσκα δικτύου IPv4", +"label.ip6address" : "Διεύθυνση IP IPv6", +"label.ip6cidr" : "IPv6 CIDR", +"label.ip6dns1" : "IPv6 DNS1", +"label.ip6dns2" : "Dns6 του IPv6", +"label.ip6gateway" : "Πύλη IPv6", +"label.ipaddress" : "Διεύθυνση IP", +"label.ipaddress1" : "Διεύθυνση IP", +"label.ipaddress2" : "Διεύθυνση IP", +"label.iplimit" : "Δημόσια όρια IP", +"label.ips" : "Ips", +"label.ipsec.splitconnections" : "Διαχωρισμός συνδέσεων", +"label.ipsecpsk" : "Ήδη κοινόχρηστο κλειδί IPsec", +"label.iptotal" : "Σύνολο διευθύνσεων IP", +"label.ipv4.cidr" : "IPv4 CIDR", +"label.ipv4.dns1" : "IPv4 DNS1", +"label.ipv4.dns2" : "Dns4 του IPv4", +"label.ipv6.dns1" : "IPv6 DNS1", +"label.ipv6.dns2" : "Dns6 του IPv6", +"label.iqn" : "Στόχος IQN", +"label.is.in.progress" : "βρίσκεται σε εξέλιξη", +"label.is.redundant.router" : "Εφεδρική", +"label.is.shared" : "Είναι κοινόχρηστο", +"label.isadvanced" : "Εμφάνιση ρυθμίσεων για προχωρημένους", +"label.iscsi" : "Iscsi", +"label.iscustomized" : "Προσαρμοσμένο μέγεθος δίσκου", +"label.iscustomizeddiskiops" : "Προσαρμοσμένη iops", +"label.iscustomizediops" : "Προσαρμοσμένη iops", +"label.isdedicated" : "αποκλειστικής χρήσης", +"label.isdefault" : "Είναι προεπιλογή", +"label.isdynamicallyscalable" : "Δυναμικά επεκτάσιμη", +"label.isextractable" : "Εκχυλιζόμενο", +"label.isfeatured" : "Επιλεγμένα", +"label.isforced" : "Επιβολή διαγραφής", +"label.ismanaged" : "Διαχείριση", +"label.iso" : "Iso", +"label.iso.boot" : "Εκκίνηση ISO", +"label.iso.id" : "Αναγνωριστικό ISO", +"label.iso.name" : "Όνομα ISO", +"label.isoid" : "Iso", +"label.isolated" : "Απομονωμένες", +"label.isolated.networks" : "Απομονωμένα δίκτυα", +"label.isolatedpvlanid" : "Δευτερεύον αναγνωριστικό VLAN", +"label.isolatedpvlantype" : "Δευτερεύων τύπος VLAN", +"label.isolation.method" : "Μέθοδος απομόνωσης", +"label.isolation.mode" : "Λειτουργία απομόνωσης", +"label.isolationmethod" : "Μέθοδος απομόνωσης", +"label.isolationmethods" : "Μέθοδος απομόνωσης", +"label.isolationuri" : "URI απομόνωσης", +"label.isoname" : "Συνημμένο ISO", +"label.isos" : "ISOs", +"label.isostate" : "Κατάσταση ISO", +"label.ispasswordenabled" : "Ενεργοποιημένος κωδικός πρόσβασης", +"label.ispersistent" : "Επίμονο ", +"label.isportable" : "Διασταυρωτικές Ζώνες", +"label.ispublic" : "Δημόσια", +"label.isready" : "Έτοιμο", +"label.isredundantrouter" : "Εφεδρικός δρομολογητής", +"label.isrouting" : "Δρομολόγηση", +"label.isself" : "Self", +"label.isshared" : "Κοινόχρηστο", +"label.issourcenat" : "Πηγαίο NAT", +"label.isstaticnat" : "Στατικό NAT", +"label.issystem" : "Είναι σύστημα", +"label.isvolatile" : "Άστατο", +"label.item.listing" : "Λίστα στοιχείων", +"label.items" : "Στοιχεία", +"label.japanese.keyboard" : "Ιαπωνικό πληκτρολόγιο", +"label.keep" : "Διατήρηση", +"label.keep.colon" : "Διατήρηση", +"label.key" : "Κλειδί", +"label.keyboard" : "Γλώσσα πληκτρολογίου", +"label.keyboardtype" : "Τύπος πληκτρολογίου", +"label.keypair" : "Ζεύγος πλήκτρων SSH", +"label.kubeconfig.cluster" : "Ρύθμιση παραμέτρων ομοταξίας Kubernetes", +"label.kubernetes" : "Κουμπερνέτες", +"label.kubernetes.cluster" : "Σύμπλεγμα Kubernetes", +"label.kubernetes.cluster.create" : "Δημιουργία ομοταξίας Kubernetes", +"label.kubernetes.cluster.delete" : "Διαγραφή ομοταξίας Kubernetes", +"label.kubernetes.cluster.details" : "Λεπτομέρειες ομοταξίας Kubernetes", +"label.kubernetes.cluster.scale" : "κλιμάκωση ομοταξίας kubernetes ", +"label.kubernetes.cluster.start" : "Εκκίνηση ομοταξίας kubernetes", +"label.kubernetes.cluster.stop" : "Σύμπλεγμα \"Στάση κουμπερνέτες\"", +"label.kubernetes.cluster.upgrade" : "Αναβάθμιση ομοταξίας Kubernetes", +"label.kubernetes.dashboard" : "Περιβάλλον εργασίας χρήστη πίνακα εργαλείων kubernetes", +"label.kubernetes.isos" : "Kubernetes ISOs", +"label.kubernetes.service" : "Υπηρεσία Kubernetes", +"label.kubernetes.version.add" : "Προσθήκη έκδοσης Kubernetes", +"label.kubernetes.version.delete" : "Διαγραφή έκδοσης Kubernetes", +"label.kubernetes.version.details" : "Λεπτομέρειες έκδοσης kubernetes", +"label.kubernetes.version.update" : "Διαχείριση έκδοσης Kubernetes", +"label.kubernetesversionid" : "Έκδοση Kubernetes", +"label.kubernetesversionname" : "Έκδοση Kubernetes", +"label.kvmnetworklabel" : "Ετικέτα κίνησης KVM", +"label.l2" : "L2", +"label.l2gatewayserviceuuid" : "Uuid υπηρεσίας πύλης L2", +"label.l3gatewayserviceuuid" : "Uuid υπηρεσίας πύλης L3", +"label.label" : "Ετικέτα", +"label.lang.arabic" : "Αραβικά", +"label.lang.brportugese" : "Πορτογαλικά Βραζιλίας", +"label.lang.catalan" : "Καταλανικά", +"label.lang.chinese" : "Κινέζικα (Απλοποιημένα)", +"label.lang.dutch" : "Ολλανδικά (Κάτω Χώρες)", +"label.lang.english" : "Αγγλικά", +"label.lang.french" : "Γαλλικά", +"label.lang.german" : "Γερμανικά", +"label.lang.hungarian" : "Ουγγρικά", +"label.lang.italian" : "Ιταλικά", +"label.lang.japanese" : "Ιαπωνικά", +"label.lang.korean" : "Κορεατικά", +"label.lang.norwegian" : "Νορβηγικά", +"label.lang.polish" : "Πολωνικά", +"label.lang.russian" : "Ρωσικά", +"label.lang.spanish" : "Ισπανικά", +"label.last.updated" : "Τελευταία ενημέρωση", +"label.lastannotated" : "Τελευταία ημερομηνία σχολίου", +"label.lastname" : "Επώνυμο", +"label.lastname.lower" : "Επώνυμο", +"label.latest.events" : "Τελευταίες εκδηλώσεις", +"label.launch" : "Έναρξη", +"label.launch.vm" : "Εκκίνηση εικονικής μηχανής", +"label.launch.zone" : "Ζώνη εκκίνησης", +"label.lb.algorithm.leastconn" : "Ελάχιστες συνδέσεις", +"label.lb.algorithm.roundrobin" : "Round-robin", +"label.lb.algorithm.source" : "Πηγή", +"label.lb.cookie" : "LbCookie", +"label.lb.protocol.http" : "HTTP", +"label.lb.protocol.ssl" : "Ssl", +"label.lb.protocol.tcp.proxy" : "Διακομιστής μεσολάβησης TCP", +"label.lbdevicededicated" : "αποκλειστικής χρήσης", +"label.lbdeviceid" : "Αναγνωριστικό", +"label.lbdevicename" : "Πληκτρολογήστε", +"label.lbdevicestate" : "Κατάσταση", +"label.lbtype" : "Τύπος εξισορρόπησης φόρτου", +"label.ldap.configuration" : "Ρύθμιση παραμέτρων LDAP", +"label.ldap.group.name" : "Ομάδα LDAP", +"label.ldap.port" : "Θύρα LDAP", +"label.level" : "Επίπεδο", +"label.license.agreements" : "Άδειες χρήσης", +"label.limit" : "Όριο", +"label.limitcpuuse" : "όριο CPU", +"label.limits" : "Ρύθμιση παραμέτρων ορίων", +"label.link.domain.to.ldap" : "Σύνδεση τομέα με LDAP", +"label.linklocalip" : "Σύνδεση τοπικής διεύθυνσης IP", +"label.linux" : "Linux", +"label.list.ciscoasa1000v" : "ASA 1000v", +"label.list.ciscovnmc" : "Cisco VNMC", +"label.list.nodes" : "Κόμβοι λίστας", +"label.list.pods" : "Κατάλογος υποομάδων", +"label.list.services" : "Υπηρεσίες λίστας", +"label.load.balancer" : "Εξισορρόπηση φόρτου", +"label.load.balancing.policies" : "Πολιτικές εξισορρόπησης φόρτου", +"label.loadbalancerinstance" : "Αντιστοιχισμένα VM", +"label.loadbalancerrule" : "Κανόνας εξισορρόπησης φόρτου", +"label.loadbalancing" : "Εξισορρόπηση φόρτου", +"label.loading" : "Φόρτωση", +"label.local" : "Τοπικό", +"label.local.storage" : "Τοπικός χώρος αποθήκευσης", +"label.local.storage.enabled" : "Ενεργοποίηση τοπικού χώρου αποθήκευσης για VM χρήστη", +"label.local.storage.enabled.system.vms" : "Ενεργοποίηση τοπικού χώρου αποθήκευσης για VM συστήματος", +"label.localstorageenabled" : "Ενεργοποίηση τοπικού χώρου αποθήκευσης για VM χρήστη", +"label.localstorageenabledforsystemvm" : "Ενεργοποίηση τοπικού χώρου αποθήκευσης για VM συστήματος", +"label.login" : "Σύνδεση", +"label.login.portal" : "Σύνδεση πύλης", +"label.login.single.signon" : "Καθολική σύνδεση", +"label.logout" : "Αποσύνδεση", +"label.lun" : "Lun", +"label.lun.number" : "Lun #", +"label.lxcnetworklabel" : "Ετικέτα κίνησης LXC", +"label.macaddress" : "Διεύθυνση MAC", +"label.macaddress.example" : "Η διεύθυνση MAC. Παράδειγμα: 01:23:45:67:89:ab", +"label.macaddresschanges" : "Αλλαγές διεύθυνσης MAC", +"label.macos" : "Macos", +"label.make.project.owner" : "Πραγματοποίηση κατόχου έργου λογαριασμού", +"label.make.user.project.owner" : "Ορισμός κατόχου έργου χρήστη", +"label.makeredundant" : "Κάνε εφεδρικό", +"label.manage" : "Διαχείριση", +"label.manage.resources" : "Διαχείριση πόρων", +"label.manage.vpn.user" : "Διαχείριση χρηστών VPN", +"label.managedstate" : "Διαχειριζόμενη κατάσταση", +"label.management" : "Διαχείριση", +"label.management.ips" : "Διευθύνσεις IP διαχείρισης", +"label.management.server" : "Διακομιστής διαχείρισης", +"label.management.servers" : "Διακομιστές διαχείρισης", +"label.managementservers" : "Αριθμός διακομιστών διαχείρισης", +"label.controlnodes" : "Kόμβοι ελέγχου", +"label.max.primary.storage" : "Μέγιστος αρχικός (GiB)", +"label.max.secondary.storage" : "Μέγιστος αριθμός δευτερευουσών (GiB)", +"label.maxcpu" : "Μέγιστοι πυρήνες CPU", +"label.maxcpunumber" : "Μέγιστοι πυρήνες CPU", +"label.maxdatavolumeslimit" : "Μέγιστο όριο τόμων δεδομένων", +"label.maxerrorretry" : "Μέγιστη επανάληψη σφάλματος", +"label.maxguestslimit" : "Μέγιστο όριο επισκεπτών", +"label.maxhostspercluster" : "Μέγιστοι κεντρικοί υπολογιστές ανά σύμπλεγμα", +"label.maximum" : "Μέγιστη", +"label.maxinstance" : "Μέγιστες παρουσίες", +"label.maxiops" : "Μέγιστο IOPS", +"label.maxmemory" : "Μέγιστη μνήμη (MiB)", +"label.maxnetwork" : "Μέγιστα δίκτυα", +"label.maxprimarystorage" : "Μέγιστη κύρια αποθήκευση (GiB)", +"label.maxproject" : "Μέγ. Έργα", +"label.maxpublicip" : "Μέγιστος αριθμός δημόσιων IP", +"label.maxsecondarystorage" : "Μέγιστη δευτερεύουσα αποθήκευση (GiB)", +"label.maxsnapshot" : "Μέγιστα στιγμιότυπα", +"label.maxtemplate" : "Μέγ. πρότυπα", +"label.maxuservm" : "Μέγιστες vm χρήστη", +"label.maxvolume" : "Μέγιστος αριθμός Volumes", +"label.maxvpc" : "Μέγ. VPCs", +"label.may.continue" : "Μπορείτε τώρα να συνεχίσετε.", +"label.mb.memory" : "Μνήμη MB", +"label.memallocated" : "Κατανομή Μνήμης", +"label.memory" : "Μνήμη", +"label.memory.maximum.mb" : "Μέγιστη μνήμη (σε MB)", +"label.memory.mb" : "Μνήμη (σε MB)", +"label.memory.total" : "Σύνολο μνήμης", +"label.memory.used" : "Μνήμη που χρησιμοποιείται", +"label.memoryallocated" : "Εκχωρημένη μνήμη", +"label.memoryallocatedgb" : "Εκχωρημένη μνήμη", +"label.memorylimit" : "Όρια μνήμης (MiB)", +"label.memorymaxdeviation" : "Απόκλιση", +"label.memorytotal" : "Εκχωρημένη μνήμη", +"label.memorytotalgb" : "Σύνολο μνήμης", +"label.memoryused" : "Χρησιμοποιημένη μνήμη", +"label.memoryusedgb" : "Μνήμη που χρησιμοποιείται", +"label.memused" : "Χρήση μνήμης", +"label.menu.all.accounts" : "Όλοι οι λογαριασμοί", +"label.menu.all.instances" : "Όλες οι παρουσίες", +"label.menu.backup" : "Αντίγραφο ασφαλείας", +"label.menu.backup.offerings" : "προσφορές υπηρεσίας δημιουργίας αντιγράφων ασφαλείας", +"label.menu.community.isos" : "Κοινότητα ISOs", +"label.menu.community.templates" : "Πρότυπα κοινότητας", +"label.menu.destroyed.instances" : "Κατεστραμμένες παρουσίες", +"label.menu.featured.isos" : "Προτεινόμενα ISOs", +"label.menu.featured.templates" : "Προτεινόμενα πρότυπα", +"label.menu.ipaddresses" : "Διευθύνσεις IP", +"label.menu.my.accounts" : "Οι λογαριασμοί μου", +"label.menu.my.instances" : "Οι παρουσίες μου", +"label.menu.my.isos" : "IsOs μου", +"label.menu.my.templates" : "Τα πρότυπά μου", +"label.menu.physical.resources" : "Φυσικοί πόροι", +"label.menu.regions" : "Περιοχές", +"label.menu.running.instances" : "Εκτέλεση παρουσιών", +"label.menu.security.groups" : "Ομάδες ασφαλείας", +"label.menu.service.offerings" : "προσφορές υπηρεσίας υπηρεσιών", +"label.menu.sshkeypair" : "SSH KeyPair", +"label.menu.stopped.instances" : "Παρουσίες που διακόπηκαν", +"label.menu.storage" : "Αποθήκευσης", +"label.menu.system" : "Σύστημα", +"label.menu.virtual.appliances" : "Εικονικές συσκευές", +"label.menu.virtual.resources" : "Εικονικοί πόροι", +"label.metrics" : "Μετρήσεις", +"label.metrics.cpu.allocated" : "Εκχώρηση CPU", +"label.metrics.cpu.usage" : "Cpu", +"label.metrics.disk.iops.total" : "Iops", +"label.metrics.disk.read" : "Διαβάστε", +"label.metrics.disk.usage" : "Χρήση δίσκου", +"label.metrics.disk.write" : "Γράψετε", +"label.metrics.memory.usage" : "Χρήση Mem", +"label.metrics.network.read" : "Διαβάστε", +"label.metrics.network.usage" : "Χρήση δικτύου", +"label.metrics.network.write" : "Γράψετε", +"label.metrics.num.cpu.cores" : "Πυρήνες", +"label.migrate.data.from.image.store" : "Μετεγκατάσταση δεδομένων από το χώρο αποθήκευσης εικόνων", +"label.migrate.instance.to" : "Μετεγκατάσταση εικονική μηχανής σε", +"label.migrate.instance.to.host" : "Μετεγκατάσταση εικονική μηχανής σε άλλο κεντρικό υπολογιστή", +"label.migrate.instance.to.ps" : "Μετεγκατάσταση εικονική μηχανής σε άλλο κύριο χώρο αποθήκευσης", +"label.migrate.lb.vm" : "Μετεγκατάσταση εικονικής μηχανής LB", +"label.migrate.lb.vm.to.ps" : "Μετεγκατάσταση LB VM σε άλλο κύριο χώρο αποθήκευσης", +"label.migrate.router.to" : "Μετεγκατάσταση δρομολογητή σε", +"label.migrate.systemvm.to" : "Μετεγκατάσταση εικονικής μηχανής συστήματος σε", +"label.migrate.to.host" : "Μετεγκατάσταση στον κεντρικό υπολογιστή", +"label.migrate.to.storage" : "Μετεγκατάσταση στο χώρο αποθήκευσης", +"label.migrate.volume" : "Μετεγκατάσταση τόμου", +"label.migrate.volume.newdiskoffering.desc" : "Αυτή η επιλογή επιτρέπει στους διαχειριστές να αντικαταστήσουν την παλιά προσφορά υπηρεσίας δίσκου, χρησιμοποιώντας μία που ταιριάζει καλύτερα στη νέα τοποθέτηση του τόμου.", +"label.migrate.volume.to.primary.storage" : "Μετεγκατάσταση τόμου σε άλλο κύριο χώρο αποθήκευσης", +"label.migrating" : "Μετεγκατάσταση", +"label.migrating.data" : "Μετεγκατάσταση δεδομένων", +"label.min.balance" : "Υπόλοιπο Min", +"label.min.past.hour" : "min μετά την ώρα", +"label.min_balance" : "Υπόλοιπο Min", +"label.mincpunumber" : "Ελάχιστοι πυρήνες CPU", +"label.minimum" : "Ελάχιστο", +"label.mininstance" : "Ελάχιστες παρουσίες", +"label.miniops" : "Min IOPS", +"label.minmaxiops" : "Min IOPS / Max IOPS", +"label.minmemory" : "Ελάχιστη μνήμη (σε MB)", +"label.minute.past.hour" : "λεπτά μετά την ώρα", +"label.minutes.past.hour" : "λεπτά μετά την ώρα", +"label.monday" : "Δευτέρα", +"label.monitor" : "Παρακολούθηση", +"label.monthly" : "Μηνιαία", +"label.more.access.dashboard.ui" : "Περισσότερες πληροφορίες σχετικά με την πρόσβαση στο περιβάλλον εργασίας χρήστη του πίνακα εργαλείων", +"label.more.templates" : "Περισσότερα πρότυπα", +"label.move.down.row" : "Μετακίνηση κατά μία γραμμή προς τα κάτω", +"label.move.to.bottom" : "Μετακίνηση προς τα κάτω", +"label.move.to.top" : "Μετακίνηση στην κορυφή", +"label.move.up.row" : "Μετακίνηση κατά μία γραμμή προς τα επάνω", +"label.my.account" : "Ο λογαριασμός μου", +"label.my.network" : "Το δίκτυό μου", +"label.my.templates" : "Τα πρότυπά μου", +"label.na" : "Μη Διαθέσιμο", +"label.name" : "Όνομα", +"label.name.optional" : "Όνομα (Προαιρετικό)", +"label.nat" : "Ενεργοποίηση NAT bigswitch BCF", +"label.nat.port.range" : "Περιοχή θυρών NAT", +"label.ncc" : "Ncc", +"label.ncc.delete" : "Διαγραφή NCC", +"label.ncc.details" : "Λεπτομέρειες NCC", +"label.netmask" : "Netmask", +"label.netscaler" : "Διαβαθμίσεις δικτύου", +"label.netscaler.details" : "Λεπτομέρειες netsccaler", +"label.netscaler.mpx" : "Εξισορρόπηση φόρτου NETSccaler MPX", +"label.netscaler.sdx" : "Εξισορρόπηση φόρτου SDX κλίμακας δικτύου", +"label.netscaler.vpx" : "Εξισορρόπηση φόρτου VPX του NetScaler", +"label.network" : "Δικτύου", +"label.network.acl" : "ACL δικτύου", +"label.network.acl.lists" : "Λίστες ACL δικτύου", +"label.network.acls" : "Acl δικτύου", +"label.network.addvm" : "Προσθήκη δικτύου σε εικονική μηχανή", +"label.network.desc" : "Δίκτυο Desc", +"label.network.details" : "Λεπτομέρειες δικτύου", +"label.network.device" : "Συσκευή δικτύου", +"label.network.device.type" : "Τύπος συσκευής δικτύου", +"label.network.domain" : "Τομέας δικτύου", +"label.network.label.display.for.blank.value" : "Χρήση προεπιλεγμένης πύλης", +"label.network.name" : "Όνομα δικτύου", +"label.network.offering" : "Προσφορά δικτύου", +"label.network.offering.access" : "Δίκτυο που προσφέρει πρόσβαση", +"label.network.offering.details" : "Λεπτομέρειες προσφοράς υπηρεσίας δικτύου", +"label.network.offering.display.text" : "Κείμενο εμφάνισης προσφοράς υπηρεσίας δικτύου", +"label.network.offering.name" : "Όνομα προσφοράς υπηρεσίας δικτύου", +"label.network.offerings" : "προσφορές υπηρεσίας δικτύου", +"label.network.service.providers" : "Υπηρεσίες παροχής δικτύου", +"label.networkcidr" : "Δίκτυο CIDR", +"label.networkdevicetype" : "Πληκτρολογήστε", +"label.networkdomain" : "Τομέας δικτύου", +"label.networkdomaintext" : "Τομέας δικτύου", +"label.networkid" : "Δικτύου", +"label.networking.and.security" : "Δικτύωση και ασφάλεια", +"label.networkkbsread" : "Ανάγνωση δικτύου", +"label.networkkbswrite" : "Εγγραφή δικτύου", +"label.networklimit" : "Όρια δικτύου", +"label.networkname" : "Όνομα δικτύου", +"label.networkofferingdisplaytext" : "Προσφορά δικτύου", +"label.networkofferingid" : "Προσφορά δικτύου", +"label.networkofferingidtext" : "Αναγνωριστικό προσφοράς υπηρεσίας δικτύου", +"label.networkofferingname" : "Προσφορά δικτύου", +"label.networkrate" : "Ρυθμός δικτύου (Mb/s)", +"label.networkread" : "Ανάγνωση δικτύου", +"label.networks" : "Δίκτυα", +"label.networkspeed" : "Ταχύτητα δικτύου", +"label.networktype" : "Τύπος δικτύου", +"label.networkwrite" : "Εγγραφή δικτύου", +"label.new" : "Νέο", +"label.new.instance.group" : "Νέα ομάδα εικονική μηχανής", +"label.new.password" : "Νέος κωδικός πρόσβασης", +"label.new.project" : "Νέο έργο", +"label.new.secondaryip.description" : "Εισαγωγή νέας δευτερεύουσας διεύθυνσης IP", +"label.new.tag" : "Νέα ετικέτα", +"label.new.vm" : "Νέα εικονική μηχανή", +"label.newdiskoffering" : "Νέα Προσφορά", +"label.newinstance" : "Νέα εικονική μηχανή", +"label.newname" : "Νέο όνομα", +"label.newsize" : "Νέο μέγεθος (GB)", +"label.next" : "Επόμενη", +"label.nexusvswitch" : "Nexus 1000v", +"label.nfs" : "Nfs", +"label.nfs.storage" : "Χώρος αποθήκευσης NFS", +"label.nfscachenfsserver" : "Διακομιστής NFS", +"label.nfscachepath" : "Διαδρομή", +"label.nfscachezoneid" : "Ζώνη", +"label.nfsserver" : "Διακομιστής NFS", +"label.nicadaptertype" : "Τύπος προσαρμογέα NIC", +"label.nicira.controller.address" : "Διεύθυνση ελεγκτή", +"label.nicira.nvp.details" : "Λεπτομέρειες για το NVP nicira", +"label.nics" : "Nics", +"label.no" : "Όχι", +"label.no.actions" : "Δεν υπάρχουν διαθέσιμες ενέργειες", +"label.no.alerts" : "Χωρίς πρόσφατες ειδοποιήσεις", +"label.no.data" : "Δεν υπάρχουν δεδομένα για εμφάνιση", +"label.no.errors" : "Δεν υπάρχουν πρόσφατα σφάλματα", +"label.no.grouping" : "(χωρίς ομαδοποίηση)", +"label.no.isos" : "Δεν υπάρχουν διαθέσιμα ISOs", +"label.no.items" : "Δεν υπάρχουν διαθέσιμα στοιχεία", +"label.no.matching.offering" : "Δεν βρέθηκε προσφορά που να ταιριάζει", +"label.no.security.groups" : "Δεν υπάρχουν διαθέσιμες ομάδες ασφαλείας", +"label.noderootdisksize" : "Μέγεθος ριζικού δίσκου κόμβου (σε GB)", +"label.nodiskcache" : "Δεν υπάρχει cache δίσκου", +"label.none" : "Κανένας", +"label.noselect" : "Όχι, ευχαριστώ", +"label.not.found" : "Δεν βρέθηκε", +"label.not.suitable" : "Δεν είναι κατάλληλο", +"label.notifications" : "Ειδοποιήσεις", +"label.num.cpu.cores" : "# των πυρήνων cpu", +"label.number" : "#Rule", +"label.number.of.clusters" : "Αριθμός συμπλεγμάτων", +"label.number.of.hosts" : "Αριθμός κεντρικών υπολογιστών", +"label.number.of.pods" : "Αριθμός υποομάδων", +"label.number.of.system.vms" : "Αριθμός VM συστήματος", +"label.number.of.virtual.routers" : "Αριθμός εικονικών δρομολογητών", +"label.number.of.zones" : "Αριθμός ζωνών", +"label.numberofrouterrequiresupgrade" : "Σύνολο εικονικών δρομολογητών που απαιτούν αναβάθμιση", +"label.numretries" : "Αριθμός επαναλήψεων", +"label.nvpdeviceid" : "Αναγνωριστικό", +"label.ocfs2" : "OCFS2", +"label.of" : "του", +"label.of.month" : "του μήνα", +"label.offerha" : "Προσφορά HA", +"label.offeringtype" : "Υπολογισμός τύπου προσφοράς υπηρεσίας", +"label.ok" : "Ok", +"label.open.documentation" : "Άνοιγμα τεκμηρίωσης", +"label.open.url" : "Άνοιγμα διεύθυνσης URL στο πρόγραμμα περιήγησης", +"label.opendaylight" : "Άνοιγμα σημειωσιού ημέρας", +"label.opendaylight.controller" : "Ελεγκτής ανοιχτού φωτισμού ημέρας", +"label.opendaylight.controllerdetail" : "Λεπτομέρειες ελεγκτή OpenDaylight", +"label.opendaylight.controllers" : "Ελεγκτές φωτισμού OpenDay", +"label.operation" : "Λειτουργία", +"label.optional" : "Προαιρετική", +"label.order" : "Παραγγελία", +"label.oscategoryid" : "Προτίμηση λειτουργικού συστήματος", +"label.ostypeid" : "Τύπος λειτουργικού συστήματος", +"label.ostypename" : "Τύπος λειτουργικού συστήματος", +"label.other" : "Άλλα", +"label.outofbandmanagement" : "Διαχείριση εκτός ζώνης", +"label.outofbandmanagement.action.issue" : "Έκδοση ενέργειας ενέργειας διαχείρισης εκτός ζώνης", +"label.outofbandmanagement.changepassword" : "Αλλαγή κωδικού πρόσβασης διαχείρισης εκτός ζώνης", +"label.outofbandmanagement.configure" : "Ρύθμιση παραμέτρων διαχείρισης εκτός ζώνης", +"label.outofbandmanagement.disable" : "Απενεργοποίηση διαχείρισης εκτός ζώνης", +"label.outofbandmanagement.enable" : "Ενεργοποίηση διαχείρισης εκτός ζώνης", +"label.overprovisionfactor" : "Υπερυποθωσών συντελεστής", +"label.override.guest.traffic" : "Παράκαμψη της κίνησης επισκεπτών", +"label.override.public.traffic" : "Παράκαμψη δημόσιας κίνησης", +"label.override.rootdisk.size" : "Παράκαμψη μεγέθους ριζικού δίσκου", +"label.overrideguesttraffic" : "Παράκαμψη της κίνησης επισκεπτών", +"label.overridepublictraffic" : "Παράκαμψη δημόσιας κίνησης", +"label.ovf.properties" : "ιδιότητες vApp", +"label.ovm3cluster" : "Εγγενής ομαδοποίηση", +"label.ovm3networklabel" : "Ετικέτα κίνησης OVM3", +"label.ovm3pool" : "Εγγενής ομαδοποίηση", +"label.ovm3vip" : "Πρωτεύουσα Vip IP", +"label.ovmnetworklabel" : "Ετικέτα κίνησης OVM", +"label.ovs" : "OVS", +"label.owned.public.ips" : "Δημόσιες διευθύνσεις IP που ανήκουν", +"label.owner.account" : "Λογαριασμός κατόχου", +"label.owner.domain" : "Τομέας κατόχου", +"label.owners" : "Ιδιοκτήτες", +"label.pa" : "Palo Alto", +"label.page" : "Σελίδα", +"label.palo.alto.details" : "Palo Alto λεπτομέρειες", +"label.palo.alto.firewall" : "Τείχος προστασίας Palo Alto", +"label.palp" : "Προφίλ αρχείου καταγραφής Palo Alto", +"label.params" : "Παραμέτρους", +"label.parent.domain" : "Γονικός τομέας", +"label.parentdomainname" : "Γονικός τομέας", +"label.parentname" : "Γονικό", +"label.passive" : "Παθητική", +"label.password" : "Κωδικό πρόσβασης", +"label.password.reset.confirm" : "Έγινε επαναφορά του κωδικού πρόσβασης σε ", +"label.passwordenabled" : "Ενεργοποιημένος κωδικός πρόσβασης", +"label.path" : "Διαδρομή", +"label.patp" : "Palo Alto Προφίλ Απειλής", +"label.pavr" : "Εικονικός δρομολογητής", +"label.payload" : "Ωφέλιμο φορτίο", +"label.pcidevice" : "Gpu", +"label.per.account" : "Ανά λογαριασμό", +"label.per.zone" : "Ανά ζώνη", +"label.perfectforwardsecrecy" : "Ιδανική προώθηση μυστικότητας", +"label.perform.fresh.checks" : "Εκτέλεση νέων ελέγχων", +"label.performfreshchecks" : "Εκτέλεση νέων ελέγχων", +"label.permission" : "Άδεια", +"label.permissions" : "Δικαιώματα", +"label.physical.network" : "Φυσικό δίκτυο", +"label.physical.network.id" : "Αναγνωριστικό φυσικού δικτύου", +"label.physical.network.name" : "Όνομα φυσικού δικτύου", +"label.physicalnetworkid" : "Φυσικό δίκτυο", +"label.physicalsize" : "Φυσικό μέγεθος", +"label.ping.cifs.password" : "Κωδικός πρόσβασης PING CIFS", +"label.ping.cifs.username" : "Όνομα χρήστη PING CIFS", +"label.ping.dir" : "Κατάλογος PING", +"label.ping.path" : "Διαδρομή ping", +"label.ping.storage.ip" : "IP αποθήκευσης PING", +"label.pkcs.private.certificate" : "Ιδιωτικό πιστοποιητικό PKCS#8", +"label.plannermode" : "Λειτουργία σχεδιασμού", +"label.please.complete.the.following.fields" : "Συμπληρώστε τα ακόλουθα πεδία", +"label.please.specify.netscaler.info" : "Καθορίστε πληροφορίες netsccaler", +"label.please.wait" : "Παρακαλώ περίμενε", +"label.plugin.details" : "Λεπτομέρειες προσθήκης", +"label.plugins" : "Plugins", +"label.pod" : "Υποομάδα", +"label.pod.dedicated" : "Υποομάδα αποκλειστικής χρήσης", +"label.pod.name" : "Όνομα υποομάδας", +"label.podid" : "Υποομάδα", +"label.podname" : "Όνομα υπομονάδας", +"label.pods" : "Υποομάδα", +"label.port" : "Θύρα", +"label.port.forwarding.policies" : "Πολιτικές προώθησης θυρών", +"label.port.range" : "Εύρος θυρών", +"label.portable.ip" : "Φορητή IP", +"label.portable.ip.range.details" : "λεπτομέρειες εύρους Φορητής IP", +"label.portable.ip.ranges" : "Φορητές περιοχές IP", +"label.portableipaddress" : "Φορητές IP", +"label.portforwarding" : "Προώθηση Θυρών", +"label.powerflex.gateway" : "Πύλη", +"label.powerflex.gateway.username" : "Όνομα χρήστη πύλης", +"label.powerflex.gateway.password" : "Κωδικός χρήστη πύλης", +"label.powerflex.storage.pool" : "Χώρος αποθήκευσης", +"label.powerstate" : "Κατάσταση ενέργειας", +"label.preferred" : "Προτιμώμενη", +"label.presetup" : "Προρύθμιση", +"label.prev" : "Προηγούμενο", +"label.previous" : "Προηγούμενη", +"label.primary" : "Πρωτοβάθμια", +"label.primary.network" : "Πρωτεύον δίκτυο", +"label.primary.storage" : "Κύριος χώρος αποθήκευσης", +"label.primary.storage.allocated" : "Εκχωρήθηκε κύριος χώρος αποθήκευσης", +"label.primary.storage.count" : "Κύριοι χώροι συγκέντρωσης αποθήκευσης", +"label.primary.storage.used" : "Χρησιμοποιείται κύριος χώρος αποθήκευσης", +"label.primarystoragelimit" : "Όρια κύριας αποθήκευσης (GiB)", +"label.primarystoragetotal" : "Κύριος χώρος αποθήκευσης", +"label.private.gateway" : "Ιδιωτική πύλη", +"label.private.interface" : "Ιδιωτική διασύνδεση", +"label.private.ip.range" : "Ιδιωτική περιοχή IP", +"label.private.ips" : "Ιδιωτικές διευθύνσεις IP", +"label.private.registry" : "Ιδιωτικό μητρώο", +"label.private.zone" : "Ιδιωτική Ζώνη", +"label.privateinterface" : "Ιδιωτική διασύνδεση", +"label.privateip" : "Ιδιωτική διεύθυνση IP", +"label.privatekey" : "Ιδιωτικό κλειδί", +"label.privatekey.password" : "Κωδικός πρόσβασης ιδιωτικού κλειδιού", +"label.privatenetwork" : "Ιδιωτικό δίκτυο", +"label.privateport" : "Ιδιωτική θύρα", +"label.profiledn" : "Συσχετισμένο προφίλ", +"label.profilename" : "Προφίλ", +"label.project" : "Έργο", +"label.project.dashboard" : "Πίνακας εργαλείων έργου", +"label.project.ids" : "Τα id έργου", +"label.project.invitation" : "Προσκλήσεις έργου", +"label.project.invite" : "Πρόσκληση σε έργο", +"label.project.name" : "Όνομα έργου", +"label.project.owner" : "Κάτοχοι έργου", +"label.project.role" : "Ρόλος έργου", +"label.project.role.permissions" : "Δικαιώματα ρόλου έργου", +"label.project.roles" : "Ρόλοι έργου", +"label.project.view" : "Προβολή έργου", +"label.projectaccountname" : "Όνομα λογαριασμού έργου", +"label.projectid" : "Αναγνωριστικό έργου", +"label.projectlimit" : "Όρια έργου", +"label.projectname" : "Έργο", +"label.projects" : "Έργα", +"label.promiscuousmode" : "Μεικτή λειτουργία", +"label.property" : "Ιδιότητα", +"label.protocol" : "Πρωτόκολλο", +"label.protocol.number" : "Αριθμός πρωτοκόλλου", +"label.protocolnumber" : "#Πρωτόκολλο", +"label.provider" : "Πάροχος", +"label.providername" : "Πάροχος", +"label.providers" : "Παρόχους", +"label.provisioning" : "Διάταξη", +"label.provisioningtype" : "Τύπος διάταξης", +"label.provisioningtype.fat" : "Διάταξη Fat", +"label.provisioningtype.sparse" : "Διάταξη sparse", +"label.provisioningtype.thin" : "thin Διάταξη", +"label.public.interface" : "Δημόσια διασύνδεση", +"label.public.ip" : "Δημόσια διεύθυνση IP", +"label.public.ip.addresses" : "Δημόσιες διευθύνσεις IP", +"label.public.ips" : "Δημόσιες διευθύνσεις IP", +"label.public.lb" : "Δημόσια LB", +"label.public.load.balancer.provider" : "Υπηρεσία παροχής δημόσιου εξισορρόπησης φόρτου", +"label.public.network" : "Δημόσιο δίκτυο", +"label.public.traffic" : "Δημόσια κίνηση", +"label.public.zone" : "Δημόσια Ζώνη", +"label.publicinterface" : "Δημόσια διασύνδεση", +"label.publicip" : "Διεύθυνση IP", +"label.publickey" : "Δημόσιο κλειδί", +"label.publicnetwork" : "Δημόσιο δίκτυο", +"label.publicport" : "Δημόσιa θύρα", +"label.purpose" : "Σκοπός", +"label.pxe.server.type" : "Τύπος διακομιστή Pxe", +"label.qostype" : "Τύπος QoS", +"label.quickview" : "Γρήγορη προβολή", +"label.quiescevm" : "Εικονική μηχανή Quiesce", +"label.quiettime" : "Ώρα ηρεμίας (σε δευτερόλεπτο)", +"label.quota" : "Ποσόστωση", +"label.quota.add.credits" : "Προσθήκη μονάδων", +"label.quota.configuration" : "Ρύθμιση παραμέτρων ορίου δίσκου", +"label.quota.configure" : "Ρύθμιση παραμέτρων ορίου", +"label.quota.credits" : "Πιστώσεις", +"label.quota.dates" : "Ενημέρωση ημερομηνιών", +"label.quota.description" : "Περιγραφή ορίου μεγέθους", +"label.quota.email.edit" : "Επεξεργασία προτύπου ηλεκτρονικού ταχυδρομείου", +"label.quota.enddate" : "Ημερομηνία λήξης", +"label.quota.endquota" : "Όριο τέλους", +"label.quota.enforce" : "Επιβολή ορίου μεγέθους", +"label.quota.fullsummary" : "Όλοι οι λογαριασμοί", +"label.quota.remove" : "Κατάργηση ορίου μεγέθους", +"label.quota.startdate" : "Ημερομηνία έναρξης", +"label.quota.startquota" : "Έναρξη ορίου", +"label.quota.statement" : "Δήλωση", +"label.quota.statement.balance" : "Υπόλοιπο ποσόστωσης", +"label.quota.statement.bydates" : "Δήλωση", +"label.quota.statement.quota" : "Χρήση ορίου δίσκου", +"label.quota.statement.tariff" : "Tariff ποσόστωσης", +"label.quota.tariff" : "Tariff", +"label.quota.tariff.edit" : "Επεξεργασία τιμολογίου", +"label.quota.tariff.effectivedate" : "Ημερομηνία έναρξης ισχύος", +"label.quota.total" : "Σύνολο", +"label.quota.totalusage" : "Συνολική χρήση", +"label.quota.type.name" : "Τύπος χρήσης", +"label.quota.type.unit" : "Μονάδα χρήσης", +"label.quota.usage" : "Κατανάλωση ποσοστώσεων", +"label.quota.value" : "Τιμή ορίου δίσκου", +"label.quota_enforce" : "Επιβολή ορίου μεγέθους", +"label.rados.monitor" : "Οθόνη RADOS", +"label.rados.pool" : "Πισίνα RADOS", +"label.rados.secret" : "RADOS Μυστικό", +"label.rados.user" : "Χρήστης RADOS", +"label.ram" : "Ram", +"label.rbd" : "Rbd", +"label.rbdid" : "Χρήστης Cephx", +"label.rbdmonitor" : "Οθόνη Ceph", +"label.rbdpool" : "Πισίνα Ceph", +"label.rbdsecret" : "Cephx μυστικό", +"label.read" : "Διαβάστε", +"label.read.io" : "Ανάγνωση (IO)", +"label.readonly" : "Μόνο για ανάγνωση", +"label.reason" : "Λόγο", +"label.reboot" : "Επανεκκίνηση", +"label.receivedbytes" : "Byte που λήφθηκαν", +"label.recent.errors" : "Πρόσφατα σφάλματα", +"label.recover.vm" : "Ανάκτηση εικονικής μηχανής", +"label.redundantrouter" : "Εφεδρικός δρομολογητής", +"label.redundantrouterstate" : "Περιττή κατάσταση", +"label.redundantstate" : "Περιττή κατάσταση", +"label.redundantvpcrouter" : "Πλεονάζον VPC", +"label.reenterpassword" : "Επανάληψη εισαγωγής κωδικού πρόσβασης", +"label.refresh" : "Ανανέωση", +"label.refresh.blades" : "Ανανέωση Blades", +"label.region" : "Περιοχή", +"label.region.details" : "Λεπτομέρειες περιοχής", +"label.register.template" : "Πρότυπο καταχώρησης", +"label.reinstall.vm" : "Επανεγκατάσταση εικονικής μηχανής", +"label.reject" : "Απορρίψει", +"label.related" : "Σχετικές", +"label.relationaloperator" : "Φορέα", +"label.release" : "Αποδέσμευση", +"label.release.account" : "Αποδέσμευση από λογαριασμό", +"label.release.dedicated.cluster" : "Έκδοση αποκλειστικού ομοταξίας", +"label.release.dedicated.host" : "Αποδέσμευση αποκλειστικού κεντρικού υπολογιστή", +"label.release.dedicated.pod" : "Αποδέσμευση αποκλειστικής υποομάδας (pod)", +"label.release.dedicated.vlan.range" : "Έκδοση αποκλειστικής σειράς VLAN", +"label.release.dedicated.zone" : "Έκδοση αποκλειστικής ζώνης", +"label.releasing.ip" : "Αποδέσμευση IP", +"label.remind.later" : "Θύμισέ μου αργότερα", +"label.remove" : "Κατάργηση", +"label.remove.acl" : "Κατάργηση ACL", +"label.remove.egress.rule" : "Κατάργηση κανόνα εξόδου", +"label.remove.from.load.balancer" : "Κατάργηση εικονική μηχανής από την εξισορρόπηση φόρτου", +"label.remove.ingress.rule" : "Κατάργηση κανόνα εισόδου", +"label.remove.ip.range" : "Κατάργηση περιοχής IP", +"label.remove.ldap" : "Κατάργηση LDAP", +"label.remove.management.ip.range" : "Κατάργηση περιοχής IP διαχείρισης", +"label.remove.network.offering" : "Κατάργηση προσφοράς υπηρεσίας δικτύου", +"label.remove.pf" : "Κατάργηση κανόνα προώθησης θυρών", +"label.remove.project.account" : "Κατάργηση λογαριασμού από το έργο", +"label.remove.project.role" : "Κατάργηση ρόλου έργου", +"label.remove.project.user" : "Κατάργηση χρήστη από το έργο", +"label.remove.region" : "Κατάργηση περιοχής", +"label.remove.rule" : "Κατάργηση κανόνα", +"label.remove.ssh.key.pair" : "Κατάργηση ζεύγους πλήκτρων SSH", +"label.remove.static.nat.rule" : "Κατάργηση στατικού κανόνα NAT", +"label.remove.static.route" : "Κατάργηση στατικής διαδρομής", +"label.remove.this.physical.network" : "Κατάργηση αυτού του φυσικού δικτύου", +"label.remove.tier" : "Κατάργηση βαθμίδας", +"label.remove.vm.from.lb" : "Κατάργηση εικονικής μηχανής από τον κανόνα εξισορρόπησης φόρτου", +"label.remove.vm.load.balancer" : "Κατάργηση εικονικής μηχανής από την εξισορρόπηση φόρτου", +"label.remove.vmware.datacenter" : "Κατάργηση κέντρου δεδομένων VMware", +"label.remove.vpc" : "Κατάργηση VPC", +"label.remove.vpc.offering" : "Κατάργηση προσφοράς υπηρεσίας VPC", +"label.removing" : "Αφαίρεση", +"label.removing.user" : "Κατάργηση χρήστη", +"label.replace.acl" : "Αντικατάσταση ACL", +"label.replace.acl.list" : "Αντικατάσταση λίστας ACL", +"label.report.bug" : "Θέμα αναφοράς", +"label.required" : "Απαιτείται", +"label.requireshvm" : "HVM", +"label.requiresupgrade" : "Απαιτεί αναβάθμιση", +"label.reserved.system.gateway" : "Δεσμευμένη πύλη συστήματος", +"label.reserved.system.ip" : "Δεσμευμένο IP συστήματος", +"label.reserved.system.netmask" : "Δεσμευμένη μάσκα δικτύου συστήματος", +"label.reservediprange" : "Δεσμευμένη περιοχή IP", +"label.reservedsystemendip" : "Τερματισμός δεσμευμένου συστήματος IP", +"label.reservedsystemgateway" : "Δεσμευμένη πύλη συστήματος", +"label.reservedsystemnetmask" : "Δεσμευμένη μάσκα δικτύου συστήματος", +"label.reservedsystemstartip" : "Έναρξη δεσμευμένης IP συστήματος", +"label.reset" : "Επαναφορά", +"label.reset.ssh.key.pair" : "Επαναφορά ζεύγους κλειδιών SSH", +"label.reset.ssh.key.pair.on.vm" : "Επαναφορά ζεύγους κλειδιών SSH σε εικονική μηχανή", +"label.reset.vpn.connection" : "Επαναφορά σύνδεσης VPN", +"label.resetvm" : "Επαναφορά εικονικής μηχανής", +"label.resource" : "Πόρων", +"label.resource.limit.exceeded" : "Υπέρβαση ορίου πόρων", +"label.resource.limits" : "Όρια πόρων", +"label.resource.name" : "Όνομα πόρου", +"label.resourceid" : "Αναγνωριστικό πόρου", +"label.resourcename" : "Όνομα πόρου", +"label.resources" : "Πόρους", +"label.resourcestate" : "Κατάσταση πόρου", +"label.response.timeout.in.sec" : "Χρονικό όριο απόκρισης (σε δευτερόλεπτα)", +"label.restart.network" : "Επανεκκίνηση δικτύου", +"label.restart.vpc" : "Επανεκκίνηση VPC", +"label.restartrequired" : "Απαιτείται επανεκκίνηση", +"label.restore" : "Επαναφορά", +"label.restore.volume.attach" : "Επαναφορά τόμου και επισύναψη", +"label.retry.interval" : "Διάστημα επανάληψης", +"label.review" : "Αναθεώρηση", +"label.revoke.project.invite" : "Ανάκληση πρόσκλησης", +"label.revokeinvitationconfirm" : "Επιβεβαιώστε ότι θέλετε να ανακαλέσετε αυτήν την πρόσκληση;", +"label.role" : "Ρόλο", +"label.rolename" : "Ρόλο", +"label.roles" : "Ρόλους", +"label.roletype" : "Τύπος ρόλου", +"label.rootdisksize" : "Μέγεθος ριζικού δίσκου (GB)", +"label.root.certificate" : "Πιστοποιητικό ρίζας", +"label.root.disk.offering" : "Προσφορά ριζικού δίσκου", +"label.root.disk.size" : "Μέγεθος ριζικού δίσκου (GB)", +"label.rootdiskcontrollertype" : "Ελεγκτής ριζικού δίσκου", +"label.rootdiskcontrollertypekvm" : "Ελεγκτής ριζικού δίσκου", +"label.routerip" : "IPv4 διεύθυνση του δρομολογητή στο κοινόχρηστο δίκτυο ", +"label.routeripv6" : "IPv6 διεύθυνση του δρομολογητή στο κοινόχρηστο δίκτυο", +"label.router.health.check.last.updated" : "Τελευταία ενημέρωση", +"label.router.health.check.name" : "Έλεγχος ονόματος", +"label.router.health.check.success" : "Επιτυχία", +"label.router.health.checks" : "Υγειονομικοί έλεγχοι", +"label.router.vm.scaled.up" : "Κλίμακα vm δρομολογητή", +"label.routercount" : "Σύνολο εικονικών δρομολογητών", +"label.routerrequiresupgrade" : "Απαιτείται αναβάθμιση", +"label.routertype" : "Πληκτρολογήστε", +"label.routing.host" : "Κεντρικός υπολογιστής δρομολόγησης", +"label.rule" : "Κανόνα", +"label.rule.number" : "Αριθμός κανόνα", +"label.rules" : "Κανόνες", +"label.rules.file" : "Αρχείο κανόνων", +"label.rules.file.to.import" : "Αρχείο κανόνων σε μορφή CSV για εισαγωγή", +"label.rules.file.import.description" : "Κάντε κλικ ή σύρετε τις ρυθμίσεις κανόνα CSV για εισαγωγή", +"label.run.proxy.locally" : "Τοπική εκτέλεση διακομιστή μεσολάβησης", +"label.running" : "Εκτέλεση VM", +"label.s3.access.key" : "Κλειδί πρόσβασης", +"label.s3.bucket" : "Κουβά", +"label.s3.connection.timeout" : "Χρονικό όριο σύνδεσης", +"label.s3.endpoint" : "Τελικό σημείο", +"label.s3.max.error.retry" : "Μέγιστη επανάληψη σφάλματος", +"label.s3.nfs.path" : "Διαδρομή S3 NFS", +"label.s3.nfs.server" : "Διακομιστής S3 NFS", +"label.s3.secret.key" : "Μυστικό κλειδί", +"label.s3.socket.timeout" : "Χρονικό όριο υποδοχής", +"label.s3.use.https" : "Χρήση HTTPS", +"label.saml.disable" : "Απενεργοποίηση SAML", +"label.saml.enable" : "Ενεργοποίηση SAML", +"label.samlenable" : "Εξουσιοδότηση SAML SSO", +"label.samlentity" : "Υπηρεσία παροχής ταυτότητας", +"label.saturday" : "Σάββατο", +"label.save" : "Αποθήκευση", +"label.save.and.continue" : "Αποθήκευση και συνέχιση", +"label.save.changes" : "Αποθήκευση αλλαγών", +"label.save.new.rule" : "Αποθήκευση νέου κανόνα", +"label.saving.processing" : "Εξοικονόμηση....", +"label.scale.vm" : "Κλίμακα VM", +"label.scale.up.policy" : "ΚΛΙΜΆΚΩΣΗ POLICY", +"label.scaledown.policy" : "αρνητική κλιμάκωση policy ", +"label.scaleup.policy" : "θετική κλιμάκωση policy", +"label.schedule" : "Πρόγραμμα", +"label.scheduled.backups" : "Προγραμματισμένα αντίγραφα ασφαλείας", +"label.scheduled.snapshots" : "Προγραμματισμένα στιγμιότυπα", +"label.scope" : "Πεδίο εφαρμογής", +"label.search" : "Αναζήτηση", +"label.secondary.isolated.vlan.type.isolated" : "Απομονωμένες", +"label.secondary.isolated.vlan.type.promiscuous" : "Ανομοιογενές", +"label.secondary.staging.store" : "Δευτερεύων χώρος αποθήκευσης ανασυγκρότησης", +"label.secondary.staging.store.details" : "Λεπτομέρειες δευτερεύοντος χώρου αποθήκευσης ανασυγκρότησης", +"label.secondary.storage" : "Δευτερεύουσα αποθήκευση", +"label.secondary.storage.count" : "Δευτερεύοντες χώροι αποθήκευσης", +"label.secondary.storage.details" : "Λεπτομέρειες δευτερεύουσας αποθήκευσης", +"label.secondary.storage.vm" : "Δευτερεύων χώρος αποθήκευσης vm", +"label.secondary.used" : "Δευτερεύων χώρος αποθήκευσης που χρησιμοποιείται", +"label.secondaryips" : "Δευτερεύουσες διευθύνσεις IP", +"label.secondarystoragelimit" : "Όρια δευτερεύουσας αποθήκευσης (GiB)", +"label.secretkey" : "Μυστικό κλειδί", +"label.secured" : "Ασφαλές", +"label.security.group.name" : "Όνομα ομάδας ασφαλείας", +"label.security.groups" : "Ομάδες ασφαλείας", +"label.security.groups.enabled" : "Ενεργοποιημένες ομάδες ασφαλείας", +"label.securitygroup" : "Ομάδα ασφαλείας", +"label.securitygroupenabled" : "Ενεργοποιημένες ομάδες ασφαλείας", +"label.securitygroups" : "Ομάδες ασφαλείας", +"label.securitygroupsenabled" : "Ενεργοποιημένες ομάδες ασφαλείας", +"label.select" : "Επιλέξτε", +"label.select-view" : "Επιλογή προβολής", +"label.select.a.zone" : "Επιλογή ζώνης", +"label.select.deployment.infrastructure" : "Επιλογή υποδομής ανάπτυξης", +"label.select.host" : "Επιλογή κεντρικού υπολογιστή", +"label.select.instance" : "Επιλογή εικονική μηχανής", +"label.select.instance.to.attach.volume.to" : "Επιλογή εικονική μηχανής για επισύναψη τόμου σε", +"label.select.iso.or.template" : "Επιλογή ISO ή προτύπου", +"label.select.offering" : "Επιλογή προσφοράς υπηρεσίας", +"label.select.project" : "Επιλογή έργου", +"label.select.projects" : "Επιλογή έργων", +"label.select.region" : "Επιλογή περιοχής", +"label.select.tier" : "Επιλογή βαθμίδας", +"label.select.vm.for.static.nat" : "Επιλογή εικονικής μηχανής για στατικό NAT", +"label.select.zones" : "Επιλογή ζωνών", +"label.self" : "Εξόρυξη", +"label.selfexecutable" : "Self", +"label.semanticversion" : "Σημασιολογική έκδοση", +"label.sent" : "Ημερομηνία", +"label.sentbytes" : "Byte που στάλθηκαν", +"label.server" : "Διακομιστής", +"label.server.certificate" : "Πιστοποιητικό διακομιστή", +"label.service.connectivity.distributedroutercapabilitycheckbox" : "Κατανεμημένος δρομολογητής", +"label.service.connectivity.regionlevelvpccapabilitycheckbox" : "Επίπεδο περιοχής VPC", +"label.service.lb.elasticlbcheckbox" : "Ελαστική LB", +"label.service.lb.inlinemodedropdown" : "Λειτουργία", +"label.service.lb.lbisolationdropdown" : "Απομόνωση LB", +"label.service.lb.netscaler.servicepackages" : "Πακέτα υπηρεσιών netsccaler", +"label.service.lb.netscaler.servicepackages.description" : "Περιγραφή πακέτου εξυπηρέτησης", +"label.service.offering" : "Προσφορά Υπηρεσιών", +"label.service.offering.details" : "Υπηρεσίες που προσφέρουν λεπτομέρειες", +"label.service.sourcenat.redundantroutercapabilitycheckbox" : "Δυνατότητα εφεδρικού δρομολογητή", +"label.service.state" : "Κατάσταση υπηρεσίας", +"label.service.staticnat.associatepublicip" : "Συσχέτιση δημόσιας διεύθυνσης IP", +"label.service.staticnat.elasticipcheckbox" : "Ελαστική IP", +"label.servicecapabilities" : "Δυνατότητες υπηρεσίας", +"label.servicelist" : "Υπηρεσίες", +"label.serviceofferingid" : "Προσφορά υπολογισμού", +"label.serviceofferingname" : "Προσφορά υπολογισμού", +"label.session.expired" : "Η περίοδος λειτουργίας έληξε", +"label.set.default.nic" : "Ορισμός προεπιλεγμένου NIC", +"label.set.reservation" : "Ορισμός κράτησης", +"label.set.reservation.desc" : "Προαιρετικό: Υποδείξτε τον λογαριασμό που θα συσχετιστεί με αυτό το εύρος IP.

Συστημικά VMs: Ενεργοποίηση της αντιστοίχησης δημοσίου εύρους IP για SSVM και CPVM, πεδίο λογαριασμού απενεργοποιημένο. Οι κανόνες αντιστοίχησης καθορίζονται στο system.vm.public.ip.reservation.mode.strictness'", +"label.set.up.zone.type" : "Ρύθμιση τύπου ζώνης", +"label.setting" : "Ρύθμιση", +"label.settings" : "Ρυθμίσεις", +"label.setup" : "Εγκατάστασης", +"label.setup.network" : "Ρύθμιση δικτύου", +"label.setup.zone" : "Ρύθμιση ζώνης", +"label.shared" : "Κοινόχρηστο", +"label.sharedexecutable" : "Κοινόχρηστο", +"label.sharedmountpoint" : "Κοινόχρηστο μέσο", +"label.sharewith" : "Κοινή χρήση με", +"label.show.ingress.rule" : "Εμφάνιση κανόνα εισόδου", +"label.showing" : "Προβολή", +"label.shrinkok" : "Συρρίκνωση OK", +"label.shutdown.provider" : "Υπηρεσία παροχής τερματισμού", +"label.simplified.chinese.keyboard" : "Απλοποιημένο πληκτρολόγιο στα κινέζικα", +"label.s2scustomergatewayid" : "Αναγνωριστικό πύλης πελάτη τοποθεσίας σε τοποθεσία", +"label.s2svpngatewayid" : "Αναγνωριστικό πύλης VPN τοποθεσίας σε τοποθεσία", +"label.site.to.site.vpn" : "VPN από τοποθεσία σε τοποθεσία", +"label.site.to.site.vpn.connections" : "Συνδέσεις VPN από τοποθεσία σε τοποθεσία", +"label.size" : "Μέγεθος", +"label.sizegb" : "Μέγεθος", +"label.skip.guide" : "Έχω χρησιμοποιήσει CloudStack πριν, παραλείψτε αυτόν τον οδηγό", +"label.smb.domain" : "Τομέας SMB", +"label.smb.password" : "Κωδικός πρόσβασης SMB", +"label.smb.username" : "Όνομα χρήστη SMB", +"label.smbdomain" : "Τομέας SMB", +"label.smbpassword" : "Κωδικός πρόσβασης SMB", +"label.smbusername" : "Όνομα χρήστη SMB", +"label.snapshot" : "Στιγμιότυπο", +"label.snapshot.name" : "Όνομα στιγμιότυπου", +"label.snapshot.schedule" : "Ρύθμιση επαναλαμβανόμενου στιγμιότυπου", +"label.snapshotlimit" : "Όρια στιγμιοτύπων", +"label.snapshotmemory" : "Μνήμη στιγμιότυπου", +"label.snapshots" : "Στιγμιότυπα", +"label.snmpcommunity" : "Κοινότητα SNMP", +"label.snmpport" : "Θύρα SNMP", +"label.sockettimeout" : "Χρονικό όριο υποδοχής", +"label.source.based" : "Βάσει πηγής", +"label.source.nat.supported" : "Υποστηρίζεται από το SourceNAT", +"label.sourcecidr" : "Πηγή CIDR", +"label.sourceipaddress" : "Πηγαία Διεύθυνση IP ", +"label.sourcenat" : "Πηγαίο NAT", +"label.sourcenatsupported" : "Η προέλευση NAT υποστηρίζεται", +"label.sourcenattype" : "Υποστηριζόμενος τύπος πηγαίου NAT ", +"label.sourceport" : "Θύρα πηγαία", +"label.specify.vxlan" : "Καθορισμός VXLAN", +"label.specifyipranges" : "Καθορισμός περιοχών IP", +"label.specifyvlan" : "Καθορισμός VLAN", +"label.splitconnections" : "Διαχωρισμός συνδέσεων", +"label.sr.name" : "Ετικέτα ονόματος SR", +"label.srx" : "SRX", +"label.srx.details" : "Λεπτομέρειες SRX", +"label.srx.firewall" : "Τείχος προστασίας Juniper SRX", +"label.ssh.key.pair.details" : "Λεπτομέρειες ζεύγους κλειδιών SSH", +"label.ssh.key.pairs" : "Ζεύγη πλήκτρων SSH", +"label.ssh.port" : "Θύρα SSH", +"label.sshkeypair" : "Νέο ζεύγος κλειδιών SSH", +"label.sshkeypairs" : "SSH ζεύγη κλειδιών", +"label.sslcertificates" : "Πιστοποιητικά SSL", +"label.standard.us.keyboard" : "Τυπικό πληκτρολόγιο (Η.Π.Α.)", +"label.start" : "Ξεκινήσετε", +"label.start.ip" : "Έναρξη IP", +"label.start.lb.vm" : "Έναρξη εικονικής μηχανής LB", +"label.start.reserved.system.ip" : "Έναρξη δεσμευμένης IP συστήματος", +"label.start.rolling.maintenance" : "Έναρξη συντήρησης κύλισης", +"label.start.rolling.maintenance.payload" : "Ωφέλιμο φορτίο", +"label.start.vlan" : "Εκκίνηση VLAN", +"label.start.vxlan" : "Εκκίνηση VXLAN", +"label.startdate" : "Κατά ημερομηνία (έναρξη)", +"label.startip" : "Έναρξη IP", +"label.startipv4" : "Εκκίνηση IP του IPv4", +"label.startipv6" : "Εκκίνηση IP του IPv6", +"label.startport" : "θύρα έναρξης", +"label.startquota" : "Τιμή ορίου δίσκου", +"label.state" : "Κατάσταση", +"label.static.nat.enabled" : "Ενεργοποίηση στατικού NAT", +"label.static.nat.to" : "Στατικό NAT για να", +"label.static.nat.vm.details" : "Στατικές λεπτομέρειες vm NAT", +"label.static.routes" : "Στατικές διαδρομές", +"label.statistics" : "Στατιστικές", +"label.status" : "Κατάσταση", +"label.step.1" : "Βήμα 1", +"label.step.1.title" : "Βήμα 1: Επιλογή προτύπου", +"label.step.2" : "Βήμα 2", +"label.step.2.title" : "Βήμα 2: Επιλογή προσφοράς", +"label.step.3" : "Βήμα 3", +"label.step.3.title" : "Βήμα 3: Επιλογή προσφοράς δίσκου", +"label.step.4" : "Βήμα 4", +"label.step.4.title" : "Βήμα 4: Δίκτυο", +"label.step.5" : "Βήμα 5", +"label.step.5.title" : "Βήμα 5: Επιβεβαίωση", +"label.stickiness.method" : "Μέθοδος Stickiness", +"label.sticky.cookie-name" : "Όνομα cookie", +"label.sticky.expire" : "Λήγει", +"label.sticky.holdtime" : "Χρόνος αναμονής", +"label.sticky.indirect" : "Έμμεση", +"label.sticky.length" : "Μήκος", +"label.sticky.mode" : "Λειτουργία", +"label.sticky.name" : "Sticky όνομα", +"label.sticky.nocache" : "Δεν υπάρχει cache", +"label.sticky.postonly" : "Δημοσίευση μόνο", +"label.sticky.prefix" : "Πρόθεμα", +"label.sticky.request-learn" : "Αίτηση εκμάθησης", +"label.sticky.tablesize" : "Μέγεθος πίνακα", +"label.stop" : "Σταμάτα", +"label.stop.lb.vm" : "Διακοπή εικονικής μηχανής LB", +"label.stopped" : "Σταματημένοι VM", +"label.storage" : "Αποθήκευσης", +"label.storage.tags" : "Ετικέτες αποθήκευσης", +"label.storage.traffic" : "Κίνηση αποθήκευσης", +"label.storageid" : "Κύριος χώρος αποθήκευσης", +"label.storage.migration.required" : "Η μετεγκατάσταση αποθηκευτικού χώρου είναι απαραίτητη", +"label.storagemotionenabled" : "Ενεργοποίηση κίνησης αποθήκευσης", +"label.storagepolicy" : "Πολιτική αποθήκευσης", +"label.storagepool" : "Χώρος αποθήκευσης", +"label.storagetags" : "Ετικέτες αποθήκευσης", +"label.storagetype" : "Τύπος αποθήκευσης", +"label.strict" : "Αυστηρή", +"label.subdomainaccess" : "Πρόσβαση δευτερεύοντος τομέα", +"label.submit" : "Υποβάλει", +"label.submitted.by" : "[Κατατέθηκε απο: ]", +"label.succeeded" : "Πέτυχε", +"label.success" : "Επιτυχία", +"label.success.set" : "Ο ορισμός ολοκληρώθηκε με επιτυχία", +"label.success.updated" : "Η ενημέρωση ολοκληρώθηκε με επιτυχία", +"label.suitability" : "Καταλληλότητα", +"label.suitable" : "Κατάλληλο", +"label.summary" : "Περίληψη", +"label.sunday" : "Κυριακή", +"label.supportedservices" : "Υποστηριζόμενες υπηρεσίες", +"label.supportsha" : "Υποστηρίζει HA", +"label.supportspublicaccess" : "Υποστηρίζει δημόσια πρόσβαση", +"label.supportsregionlevelvpc" : "Υποστηρίζει VPC επιπέδου περιοχής", +"label.supportsstrechedl2subnet" : "Υποστηρίζει υποδίκτυο Streched L2", +"label.suspend.project" : "Αναστολή έργου", +"label.switch.type" : "Τύπος εναλλάκτη", +"label.system.capacity" : "Χωρητικότητα συστήματος", +"label.system.offering" : "Προσφορά συστήματος", +"label.system.offering.for.router" : "Προσφορά συστήματος για δρομολογητή", +"label.system.offerings" : "προσφορές υπηρεσίας συστημάτων", +"label.system.service.offering" : "Προσφορά υπηρεσιών συστήματος", +"label.system.service.offering.details" : "Λεπτομέρειες προσφοράς υπηρεσίας υπηρεσιών συστήματος", +"label.system.vm" : "Εικονική μηχανή συστήματος", +"label.system.vm.details" : "Λεπτομέρειες vm συστήματος", +"label.system.vm.scaled.up" : "Κλιμάκωση εικονικής μηχανής συστήματος", +"label.system.vms" : "VM συστήματος", +"label.system.wide.capacity" : "Χωρητικότητα σε όλο το σύστημα", +"label.systemvmtype" : "Τύπος εικονικής μηχανής συστήματος", +"label.tag.key" : "Πλήκτρο ετικέτας", +"label.tag.value" : "Τιμή ετικέτας", +"label.tagged" : "Με ετικέτα", +"label.tags" : "Ετικέτες", +"label.target.iqn" : "Στόχος IQN", +"label.tariffactions" : "Ενέργειες", +"label.tariffvalue" : "Δασμολογική Αξία", +"label.task.completed" : "Η εργασία ολοκληρώθηκε", +"label.tcp" : "TCP", +"label.tcp.proxy" : "Διακομιστής μεσολάβησης TCP", +"label.template" : "Επιλογή προτύπου", +"label.templatebody" : "Σώμα", +"label.templatedn" : "Επιλογή προτύπου", +"label.templatefileupload" : "Τοπικό αρχείο", +"label.templateid" : "Επιλογή προτύπου", +"label.templateiso" : "Πρότυπο/ISO", +"label.templatelimit" : "Όρια προτύπων", +"label.templatename" : "Πρότυπο", +"label.templatenames" : "Πρότυπο", +"label.templates" : "Πρότυπα", +"label.templatesubject" : "Θέμα", +"label.templatetotal" : "Πρότυπο", +"label.templatetype" : "Τύπος προτύπου", +"label.tftp.dir" : "Κατάλογος TFTP", +"label.tftpdir" : "Ριζικός κατάλογος Tftp", +"label.theme.default" : "Προεπιλεγμένο θέμα", +"label.theme.grey" : "Προσαρμοσμένο - Γκρι", +"label.theme.lightblue" : "Προσαρμοσμένο - Ανοιχτό Μπλε", +"label.threshold" : "Όριο", +"label.thursday" : "Πέμπτη", +"label.tier.details" : "Λεπτομέρειες βαθμίδας", +"label.tiername" : "Βαθμίδα", +"label.time" : "Ώρα", +"label.time.colon" : "Ωρα:", +"label.timeout" : "Χρονικό όριο", +"label.timeout.in.second " : " Χρονικό όριο (δευτερόλεπτα)", +"label.timezone" : "Ζώνη ώρας", +"label.timezone.colon" : "Ζώνη ώρας:", +"label.to" : "Να", +"label.token" : "Διακριτικό", +"label.token.for.dashboard.login" : "Το διακριτικό για σύνδεση πίνακα εργαλείων μπορεί να ανακτηθεί χρησιμοποιώντας την ακόλουθη εντολή", +"label.total" : "Σύνολο", +"label.total.hosts" : "Σύνολο κεντρικών υπολογιστών", +"label.total.memory" : "Συνολική μνήμη", +"label.total.network" : "Σύνολο δικτύων", +"label.total.storage" : "Συνολικός χώρος αποθήκευσης", +"label.total.vms" : "Σύνολο VM", +"label.total.volume" : "Σύνολο τόμων", +"label.totalcpu" : "Σύνολο CPU", +"label.traffic.label" : "Ετικέτα κίνησης", +"label.traffic.types" : "Τύποι κίνησης", +"label.traffictype" : "Τύπος κίνησης", +"label.transportzoneuuid" : "Ζώνη μεταφοράς Uuid", +"label.try.again" : "Δοκίμασε ξανά", +"label.tuesday" : "Τρίτη", +"label.type" : "Πληκτρολογήστε", +"label.type.id" : "Αναγνωριστικό τύπου", +"label.ucs" : "UCS", +"label.udp" : "UDP", +"label.uk.keyboard" : "Πληκτρολόγιο Ηνωμένου Βασιλείου", +"label.unauthorized" : "Μη εξουσιοδοτημένη", +"label.unavailable" : "Διαθέσιμη", +"label.unhealthy.threshold" : "Μη υγιές όριο", +"label.unique.name.tier" : "Ένα μοναδικό όνομα της βαθμίδας", +"label.unit" : "Μονάδα χρήσης", +"label.unknown" : "Άγνωστο", +"label.unlimited" : "Απεριόριστη", +"label.untagged" : "Χωρίς tag", +"label.update.instance.group" : "Ενημέρωση ομάδας εικονική μηχανής", +"label.update.physical.network" : "Ενημέρωση φυσικού δικτύου", +"label.update.project.resources" : "Ενημέρωση πόρων έργου", +"label.update.project.role" : "Ενημέρωση ρόλου έργου", +"label.update.ssl" : " Πιστοποιητικό SSL", +"label.update.ssl.cert" : " Πιστοποιητικό SSL", +"label.update.to" : "ενημερώθηκε σε", +"label.update.traffic.label" : "Ενημέρωση ετικετών κίνησης", +"label.update.vmware.datacenter" : "Ενημέρωση κέντρου δεδομένων VMware", +"label.updating" : "Ενημέρωση", +"label.upgrade.router.newer.template" : "Αναβάθμιση δρομολογητή για χρήση νεότερου προτύπου", +"label.upload" : "Φόρτωση", +"label.upload.from.local" : "Αποστολή από τοπικό", +"label.upload.iso.from.local" : "Αποστολή του ISO από την τοπική", +"label.upload.template.from.local" : "Αποστολή προτύπου από τοπικό", +"label.upload.volume" : "Αποστολή τόμου", +"label.upload.volume.from.local" : "Αποστολή τόμου από τοπικό", +"label.upload.volume.from.url" : "Αποστολή τόμου από τη διεύθυνση URL", +"label.url" : "Διεύθυνση url", +"label.usage.sanity.result" : "Αποτέλεσμα λογικής χρήσης", +"label.usage.server" : "Διακομιστής χρήσης", +"label.usageinterface" : "Διασύνδεση χρήσης", +"label.usagename" : "Τύπος χρήσης", +"label.usageunit" : "Μονάδα", +"label.use.local.timezone" : "Χρήση τοπικής ζώνης ώρας", +"label.use.kubectl.access.cluster" : "kubectl και kubeconfig αρχείο για πρόσβαση στο σύμπλεγμα", +"label.use.vm.ip" : "Χρήση VM IP:", +"label.use.vm.ips" : "Χρήση VM IPs", +"label.used" : "Χρησιμοποιείται", +"label.usehttps" : "Χρήση HTTPS", +"label.usenewdiskoffering" : "Αντικατάσταση προσφοράς υπηρεσίας δίσκου;", +"label.user" : "Χρήστη", +"label.user.as.admin" : "Ορισμός χρήστη ως διαχειριστή έργου", +"label.user.conflict" : "Σύγκρουση", +"label.user.details" : "Στοιχεία χρήστη", +"label.user.source" : "Πηγή", +"label.user.vm" : "VM χρήστη", +"label.userdata" : "Userdata", +"label.userdatal2" : "Δεδομένα χρήστη", +"label.username" : "Όνομα χρήστη", +"label.users" : "Χρήστες", +"label.usersource" : "Τύπος χρήστη", +"label.usevpc" : "VPC", +"label.using.cli" : "Χρήση CLI", +"label.utilization" : "Χρήση", +"label.uuid" : "Αναγνωριστικό", +"label.value" : "Τιμή", +"label.vcdcname" : "όνομα vCenter DC", +"label.vcenter" : "VMware Datacenter vCenter", +"label.vcenter.cluster" : "σύμπλεγμα vCenter", +"label.vcenter.datacenter" : "vCenter Datacenter", +"label.vcenter.datastore" : "vCenter Datastore", +"label.vcenter.host" : "Κεντρικός υπολογιστής vCenter", +"label.vcenter.password" : "Κωδικός πρόσβασης vCenter", +"label.vcenter.username" : "όνομα χρήστη vCenter", +"label.vcenterdatacenter" : "vCenter Datacenter", +"label.vcenterdatastore" : "vCenter Datastore", +"label.esx.host" : "Κεντρικός υπολογιστής ESX/ESXi", +"label.vcenterpassword" : "Κωδικός πρόσβασης vCenter", +"label.vcenterusername" : "όνομα χρήστη vCenter", +"label.vcipaddress" : "Διεύθυνση IP vCenter", +"label.vcsdeviceid" : "Αναγνωριστικό", +"label.version" : "Έκδοση", +"label.versions" : "Εκδόσεις", +"label.vgpu" : "VGPU", +"label.vgpu.max.resolution" : "Μέγιστη ανάλυση", +"label.vgpu.max.vgpu.per.gpu" : "vGPU ανά GPU", +"label.vgpu.remaining.capacity" : "Εναπομένουσα χωρητικότητα", +"label.vgpu.video.ram" : "Μνήμη RAM βίντεο", +"label.vgputype" : "τύπος vGPU", +"label.view" : "Δείτε", +"label.view.all" : "Προβολή όλων", +"label.view.console" : "Προβολή κονσόλας", +"label.view.more" : "Δείτε περισσότερα", +"label.view.secondary.ips" : "Προβολή δευτερευουσών IP", +"label.viewing" : "Προβολή", +"label.virtual.appliance" : "Εικονική συσκευή", +"label.virtual.appliance.details" : "Λεπτομέρειες εικονικής εφαρμογής", +"label.virtual.appliances" : "Εικονικές συσκευές", +"label.virtual.machine" : "Εικονική μηχανή", +"label.virtual.machines" : "Εικονικές μηχανές", +"label.virtual.network" : "Εικονικό δίκτυο", +"label.virtual.networking" : "Εικονική δικτύωση", +"label.virtual.routers" : "Εικονικοί δρομολογητές", +"label.virtual.routers.group.account" : "Εικονικοί δρομολογητές ομάδα κατά λογαριασμό", +"label.virtual.routers.group.cluster" : "Ομάδα εικονικών δρομολογητών κατά σύμπλεγμα", +"label.virtual.routers.group.pod" : "Εικονικοί δρομολογητές ανά υποομάδα (pod)", +"label.virtual.routers.group.zone" : "Εικονικοί δρομολογητές ομαδοποιούνται κατά ζώνη", +"label.virtualmachinedisplayname" : "Όνομα VM", +"label.virtualmachineid" : "Αναγνωριστικό εικονικής μηχανής", +"label.virtualmachinename" : "Όνομα VM", +"label.virtualsize" : "Εικονικό μέγεθος", +"label.vlan" : "VLAN/VNI", +"label.vlan.range" : "Περιοχή VLAN/VNI", +"label.vlan.range.details" : "Λεπτομέρειες εύρους VLAN", +"label.vlan.vni.ranges" : "Εύρος(ες) VLAN/VNI", +"label.vlanid" : "Αναγνωριστικό VLAN/VNI", +"label.vlanname" : "Vlan", +"label.vlanrange" : "Περιοχή VLAN/VNI", +"label.vm" : "Vm", +"label.vm.add" : "Προσθήκη εικονική μηχανής", +"label.vm.destroy" : "Καταστροφή", +"label.vm.password" : "Ο κωδικός πρόσβασης της εικονικής μηχανής είναι", +"label.vm.reboot" : "Επανεκκίνηση", +"label.vm.snapshots" : "Στιγμιότυπα VM", +"label.vm.start" : "Ξεκινήσετε", +"label.vm.stop" : "Σταμάτα", +"label.vmdisplayname" : "Εμφανιζόμενο όνομα VM", +"label.vmfs" : "VMFS", +"label.vmfs.datastore" : "Κατάστημα δεδομένων VMFS", +"label.vmipaddress" : "Διεύθυνση IP VM", +"label.vmlimit" : "Όρια εικονική μηχανής", +"label.vmname" : "Όνομα εικονικής μηχανής", +"label.vms" : "VMs", +"label.vms.in.tier" : "VM στη βαθμίδα", +"label.vmstate" : "Κατάσταση VM", +"label.vmtotal" : "Σύνολο VM", +"label.vmware.storage.policy" : "Πολιτική αποθήκευσης VMWare", +"label.vmwaredcid" : "Αναγνωριστικό Datacenter VMware", +"label.vmwaredcname" : "Όνομα Datacenter VMware", +"label.vmwaredcvcenter" : "VMware Datacenter vCenter", +"label.vmwarenetworklabel" : "Ετικέτα κίνησης VMware", +"label.vnmc" : "VNMC", +"label.vnmc.devices" : "Συσκευές VNMC", +"label.volgroup" : "Ομάδα τόμων", +"label.volume" : "Όγκο", +"label.volumeid" : "Όγκο", +"label.volume.details" : "Λεπτομέρειες τόμου", +"label.volume.empty" : "Δεν υπάρχουν τόμοι δεδομένων που να είναι συνδεδεμένοι σε αυτήν την εικονική μηχανή", +"label.volume.ids" : "Αναγνωριστικό τόμου", +"label.volume.migrated" : "Μετεγκατάσταση τόμου", +"label.volume.volumefileupload.description" : "Κάντε κλικ ή σύρετε το αρχείο σε αυτήν την περιοχή για αποστολή", +"label.volumechecksum" : "Άθροισμα ελέγχου MD5", +"label.volumechecksum.description" : "Χρήση του κατακερματισμού που δημιουργήσατε κατά την έναρξη της διαδικασίας αποστολής τόμου", +"label.volumefileupload" : "Τοπικό αρχείο", +"label.volumegroup" : "Ομάδα τόμων", +"label.volumeids" : "Τόμοι προς διαγραφή", +"label.volumelimit" : "Όρια τόμου", +"label.volumename" : "Όνομα τόμου", +"label.volumes" : "Τόμους", +"label.volumetotal" : "Όγκο", +"label.vpc" : "VPC", +"label.vpc.id" : "Αναγνωριστικό VPC", +"label.vpc.offering.access" : "VPC που προσφέρει την πρόσβαση", +"label.vpc.offering.details" : "VPC που προσφέρει τις λεπτομέρειες", +"label.vpc.offerings" : "προσφορές υπηρεσίας VPC", +"label.vpc.router.details" : "Λεπτομέρειες δρομολογητή VPC", +"label.vpc.virtual.router" : "Εικονικός δρομολογητής VPC", +"label.vpcid" : "VPC", +"label.vpclimit" : "Όρια VPC", +"label.vpcname" : "VPC", +"label.vpcoffering" : "Προσφορά υπηρεσίας VPC", +"label.vpcofferingid" : "Προσφορά υπηρεσίας VPC", +"label.vpctotal" : "Σύνολο VPC", +"label.vpn" : "VPN", +"label.vpn.connection" : "Σύνδεση VPN", +"label.vpn.gateway" : "Πύλη VPN", +"label.vpn.users" : "Χρήστες VPN", +"label.vpncustomergateway" : "Διεύθυνση IP της απομακρυσμένης πύλης", +"label.vpncustomergateway.cidrlist" : "Λίστα CIDR επισκέπτη διαχωρισμένων με κόμματα των απομακρυσμένων υποδικτύων.", +"label.vpncustomergateway.esplifetime" : "Η διάρκεια ζωής της φάσης-2 της συσχέτισης ασφαλείας σε δευτερόλεπτα", +"label.vpncustomergateway.ikelifetime" : "φάση-1 διάρκεια ζωής της συσχέτισης ασφαλείας σε δευτερόλεπτα", +"label.vpncustomergateway.secretkey" : "Εισαγωγή μιας μυστικής τιμής κλειδιού", +"label.vpncustomergatewayid" : "Πύλη πελάτη VPN", +"label.vpncustomergatewayname" : "Μοναδικό όνομα για πύλη πελάτη VPN", +"label.vsmctrlvlanid" : "Αναγνωριστικό VLAN ελέγχου", +"label.vsmdeviceid" : "Όνομα", +"label.vsmdevicestate" : "Κατάσταση", +"label.vsmipaddress" : "Διεύθυνση IP Nexus 1000v", +"label.vsmpassword" : "Nexus 1000v Κωδικός πρόσβασης", +"label.vsmpktvlanid" : "Αναγνωριστικό VLAN πακέτου", +"label.vsmstoragevlanid" : "Αναγνωριστικό VLAN αποθήκευσης", +"label.vsmusername" : "Όνομα χρήστη Nexus 1000v", +"label.vsmusername.req" : "Όνομα χρήστη Nexus 1000v", +"label.vsphere.managed" : "διαχείριση vSphere", +"label.vspherestoragepolicy" : "Πολιτική αποθήκευσης vSphere", +"label.vswitch.name" : "όνομα vSwitch", +"label.vswitch.type" : "τύπος vSwitch", +"label.vswitchguestname" : "Όνομα vSwitch κίνησης επισκεπτών", +"label.vswitchguesttype" : "Τύπος vSwitch κίνησης επισκεπτών", +"label.vswitchpublicname" : "Όνομα vSwitch κίνησης κοινού", +"label.vswitchpublictype" : "Τύπος vSwitch δημόσιας κίνησης", +"label.vxlan" : "VXLAN", +"label.vxlan.id" : "Αναγνωριστικό VXLAN", +"label.vxlan.range" : "Σειρά VXLAN", +"label.waiting" : "Αναμονή", +"label.warn" : "Προειδοποιεί", +"label.warn.upper" : "Προειδοποιεί", +"label.warning" : "Προειδοποίηση", +"label.wednesday" : "Τετάρτη", +"label.weekly" : "Εβδομαδιαία", +"label.welcome" : "Καλώς ήρθες", +"label.welcome.cloud.console" : "Καλώς ορίσατε στην Κονσόλα διαχείρισης", +"label.what.is.cloudstack" : "Τι είναι το CloudStack™;", +"label.windows" : "Windows", +"label.with.snapshotid" : "με αναγνωριστικό στιγμιότυπου", +"label.write" : "Γράψετε", +"label.writeback" : "Προσωρινή αποθήκευση δίσκου επιστροφής εγγραφής", +"label.writecachetype" : "Τύπος cache εγγραφής", +"label.writeio" : "Εγγραφή (IO)", +"label.writethrough" : "Εγγραφή μέσω", +"label.xennetworklabel" : "Ετικέτα κίνησης XenServer", +"label.xenservertoolsversion61plus" : "Η αρχική έκδοση XS είναι 6.1+", +"label.yes" : "Ναι", +"label.yourinstance" : "Η περίστασή σας", +"label.zone" : "Ζώνη", +"label.zone.dedicated" : "Αποκλειστική ζώνη", +"label.zone.details" : "Λεπτομέρειες ζώνης", +"label.zone.id" : "Αναγνωριστικό ζώνης", +"label.zone.step.1.title" : "Βήμα 1: Επιλογή δικτύου", +"label.zone.step.2.title" : "Βήμα 2: Πρόσθήκη ζώνης", +"label.zone.step.3.title" : "Βήμα 3: Προσθήκη υποομάδας", +"label.zone.step.4.title" : "Βήμα 4: Προσθήκη εύρους IP", +"label.zone.type" : "Τύπος ζώνης", +"label.zone.wide" : "Σε ολόκληρη τη ζώνη", +"label.zoneid" : "Ζώνη", +"label.zonename" : "Ζώνη", +"label.zonenamelabel" : "Όνομα ζώνης", +"label.zones" : "Ζώνες", +"label.zonewizard.traffictype.guest" : "Επισκέπτες (guest): Κίνηση μεταξύ των εικονικών μηχανών των τελικών χρηστών", +"label.zonewizard.traffictype.management" : "Διαχείριση (Management): Κίνηση μεταξύ των πόρων του Cloudstack καθώς και την επικοινωνία με τον διακομιστή διαχείρισης (management), διακομιστών (hosts), συστημικών VMs", +"label.zonewizard.traffictype.public" : "Δημόσιο (public): Κίνηση μεταξύ του διαδυκτίου και των εικονικών μηχανών", +"label.zonewizard.traffictype.storage" : "Χώρος αποθήκευσης (storage): Κίνηση μεταξύ των πρωτεύοντων και δευτερεύοντων διακομιστών χώρου αποθήκευσης όπως VM templates και snapshosts", +"message.acquire.ip.failed" : "Απέτυχε η απόκτηση ip", +"message.acquire.ip.nic" : "Επιβεβαιώστε ότι θέλετε να αποκτήσετε μια νέα δευτερεύουσα IP για την κάρτα δικτύου.
Σημείωση: Θα πρέπει να ορίσετε μέσα στο VM χειροκίνητα την δευτερεύουσα IP", +"message.acquire.new.ip" : "Επιβεβαιώστε ότι θέλετε να αποκτήσετε μια νέα IP για αυτό το δίκτυο.", +"message.acquire.new.ip.vpc" : "Επιβεβαιώστε ότι θέλετε να αποκτήσετε μια νέα IP για αυτό το VPC.", +"message.acquire.public.ip" : "Επιλέξτε μια ζώνη από την οποία θέλετε να αποκτήσετε τη νέα σας IP.", +"message.action.acquire.ip" : "Επιβεβαιώστε ότι θέλετε να αποκτήσετε νέα IP", +"message.action.cancel.maintenance" : "Ο κεντρικός υπολογιστής σας ακυρώθηκε με επιτυχία για συντήρηση. Αυτή η διαδικασία μπορεί να διαρκέσει έως και μερικά λεπτά.", +"message.action.cancel.maintenance.mode" : "Επιβεβαιώστε ότι θέλετε να ακυρώσετε αυτήν τη συντήρηση.", +"message.action.change.service.warning.for.instance" : "Η εικονική μηχανή σας πρέπει να διακοπεί πριν επιχειρήσετε να αλλάξετε την τρέχουσα προσφορά υπηρεσιών.", +"message.action.change.service.warning.for.router" : "Ο δρομολογητής σας πρέπει να διακοπεί πριν επιχειρήσετε να αλλάξετε την τρέχουσα προσφορά υπηρεσιών.", +"message.action.create.snapshot.from.vmsnapshot" : "Επιβεβαιώστε ότι θέλετε να δημιουργήσετε στιγμιότυπο από το Στιγμιότυπο του VM", +"message.action.delete.backup.offering" : "Επιβεβαιώστε ότι θέλετε να διαγράψετε αυτήν την προσφορά υπηρεσίας αντιγράφων ασφαλείας;", +"message.action.delete.cluster" : "Επιβεβαιώστε ότι θέλετε να διαγράψετε αυτό το σύμπλεγμα.", +"message.action.delete.disk.offering" : "Επιβεβαιώστε ότι θέλετε να διαγράψετε αυτήν την προσφορά υπηρεσίας δίσκου.", +"message.action.delete.domain" : "Επιβεβαιώστε ότι θέλετε να διαγράψετε αυτόν τον τομέα.", +"message.action.delete.external.firewall" : "Επιβεβαιώστε ότι θέλετε να αφαιρέσετε το εξωτερικό τοίχος προστασίας. Προειδοποίηση: Αν σκοπεύεται να το προσθέσετε ξανά πρέπει να μηδενίσετε τα δεδομένα χρήσης στην συσκευή", +"message.action.delete.external.load.balancer" : "Επιβεβαιώστε ότι θέλετε να αφαιρέσετε τον εξωτερικό LB. Προειδοποίηση: Αν σκοπεύεται να τον προσθέσετε ξανά πρέπει να μηδενίσετε τα δεδομένα χρήσης στην συσκευή", +"message.action.delete.ingress.rule" : "Επιβεβαιώστε ότι θέλετε να διαγράψετε αυτόν τον κανόνα εισόδου.", +"message.action.delete.iso" : "Επιβεβαιώστε ότι θέλετε να διαγράψετε αυτό το ISO.", +"message.action.delete.iso.for.all.zones" : "Το ISO χρησιμοποιείται από όλες τις ζώνες. Επιβεβαιώστε ότι θέλετε να το διαγράψετε από όλες τις ζώνες.", +"message.action.delete.network" : "Επιβεβαιώστε ότι θέλετε να διαγράψετε αυτό το δίκτυο.", +"message.action.delete.nexusvswitch" : "Επιβεβαιώστε ότι θέλετε να διαγράψετε αυτό το nexus 1000v", +"message.action.delete.physical.network" : "Επιβεβαιώστε ότι θέλετε να διαγράψετε αυτό το φυσικό δίκτυο", +"message.action.delete.pod" : "Επιβεβαιώστε ότι θέλετε να διαγράψετε αυτήν την υποομάδα.", +"message.action.delete.primary.storage" : "Επιβεβαιώστε ότι θέλετε να διαγράψετε αυτόν τον πρωτεύοντα χώρο αποθήκευσης.", +"message.action.delete.secondary.storage" : "Επιβεβαιώστε ότι θέλετε να διαγράψετε αυτόν τον δευτερεύοντα χώρο αποθήκευσης.", +"message.action.delete.security.group" : "Επιβεβαιώστε ότι θέλετε να διαγράψετε αυτήν την ομάδα ασφαλείας.", +"message.action.delete.service.offering" : "Επιβεβαιώστε ότι θέλετε να διαγράψετε αυτήν την προσφορά υπηρεσίας.", +"message.action.delete.snapshot" : "Επιβεβαιώστε ότι θέλετε να διαγράψετε αυτό το στιγμιότυπο.", +"message.action.delete.system.service.offering" : "Επιβεβαιώστε ότι θέλετε να διαγράψετε αυτήν την προσφορά υπηρεσίας συστήματος.", +"message.action.delete.template" : "Επιβεβαιώστε ότι θέλετε να διαγράψετε αυτό το πρότυπο.", +"message.action.delete.template.for.all.zones" : "Το πρότυπο χρησιμοποιείται από όλες τις ζώνες. Επιβεβαιώστε ότι θέλετε να το διαγράψετε από όλες τις ζώνες.", +"message.action.delete.volume" : "Επιβεβαιώστε ότι θέλετε να διαγράψετε αυτόν τον τόμο.", +"message.action.delete.vpn.user" : "Επιβεβαιώστε ότι θέλετε να διαγράψετε το χρήστη VPN.", +"message.action.delete.zone" : "Επιβεβαιώστε ότι θέλετε να διαγράψετε αυτήν τη ζώνη.", +"message.action.destroy.instance" : "Επιβεβαιώστε ότι θέλετε να καταστρέψετε την εικονική μηχανή.", +"message.action.destroy.instance.with.backups" : "Επιβεβαιώστε ότι θέλετε να καταστρέψετε την εικονική μηχανή. Πιθανόν να υπάρχουν αντίγραφα ασφαλείας που θα σβηστούν επίσης", +"message.action.destroy.systemvm" : "Επιβεβαιώστε ότι θέλετε να καταστρέψετε την εικονική μηχανή συστήματος.", +"message.action.destroy.volume" : "Επιβεβαιώστε ότι θέλετε να καταστρέψετε τον τόμο.", +"message.action.disable.cluster" : "Επιβεβαιώστε ότι θέλετε να απενεργοποιήσετε αυτό το σύμπλεγμα.", +"message.action.disable.nexusvswitch" : "Επιβεβαιώστε ότι θέλετε να απενεργοποιήσετε αυτό το nexus 1000v", +"message.action.disable.physical.network" : "Επιβεβαιώστε ότι θέλετε να απενεργοποιήσετε αυτό το φυσικό δίκτυο.", +"message.action.disable.pod" : "Επιβεβαιώστε ότι θέλετε να απενεργοποιήσετε αυτήν την υποομάδα (pod).", +"message.action.disable.static.nat" : "Επιβεβαιώστε ότι θέλετε να απενεργοποιήσετε το στατικό NAT.", +"message.action.disable.zone" : "Επιβεβαιώστε ότι θέλετε να απενεργοποιήσετε αυτήν τη ζώνη.", +"message.action.download.iso" : "Επιβεβαιώστε ότι θέλετε να κατεβάσετε αυτό το ISO.", +"message.action.download.template" : "Επιβεβαιώστε ότι θέλετε να κάνετε λήψη αυτού του προτύπου.", +"message.action.downloading.template" : "Λήψη προτύπου.", +"message.action.enable.cluster" : "Επιβεβαιώστε ότι θέλετε να ενεργοποιήσετε αυτό το σύμπλεγμα.", +"message.action.enable.maintenance" : "Ο κεντρικός υπολογιστής σας έχει προετοιμαστεί με επιτυχία για συντήρηση. Αυτή η διαδικασία μπορεί να διαρκέσει έως και αρκετά λεπτά ή περισσότερο, ανάλογα με τον αριθμό των VM που βρίσκονται αυτήν τη στιγμή σε αυτόν τον κεντρικό υπολογιστή.", +"message.action.enable.nexusvswitch" : "Επιβεβαιώστε ότι θέλετε να ενεργοποιήσετε αυτό το nexus 1000v", +"message.action.enable.physical.network" : "Επιβεβαιώστε ότι θέλετε να ενεργοποιήσετε αυτό το φυσικό δίκτυο.", +"message.action.enable.pod" : "Επιβεβαιώστε ότι θέλετε να ενεργοποιήσετε αυτό το pod.", +"message.action.enable.zone" : "Επιβεβαιώστε ότι θέλετε να ενεργοποιήσετε αυτήν τη ζώνη.", +"message.action.expunge.instance" : "Επιβεβαιώστε ότι θέλετε να εξουδετεί αυτήν την εικονική μηχανή.", +"message.action.expunge.instance.with.backups" : "Επιβεβαιώστε ότι θέλετε να σβήσετε οριστικά την εικονική μηχανή. Πιθανόν να υπάρχουν αντίγραφα ασφαλείας που θα σβηστούν επίσης", +"message.action.force.reconnect" : "Ο κεντρικός υπολογιστής σας αναγκάστηκε να επανασυνδεθεί με επιτυχία. Αυτή η διαδικασία μπορεί να διαρκέσει έως και μερικά λεπτά.", +"message.action.host.enable.maintenance.mode" : "Η ενεργοποίηση της λειτουργίας συντήρησης θα προκαλέσει μια ζωντανή μετεγκατάσταση όλων των εμφανίσεων που εκτελούνται σε αυτόν τον κεντρικό υπολογιστή σε οποιονδήποτε διαθέσιμο κεντρικό υπολογιστή.", +"message.action.instance.reset.password" : "Επιβεβαιώστε ότι θέλετε να αλλάξετε τον κωδικό πρόσβασης ROOT για αυτήν την εικονική μηχανή.", +"message.action.manage.cluster" : "Επιβεβαιώστε ότι θέλετε να διαχειριστείτε το σύμπλεγμα.", +"message.action.primarystorage.enable.maintenance.mode" : "Προειδοποίηση: Αν θέσετε το πρωτεύον χώρο αποθήκευσης σε συντήρηση όλες οι εικονικές μηχανές που χρησιμοποιούν τόμους απο αυτό θα σταματήσουν. Θέλετε να συνεχίσετε;", +"message.action.reboot.instance" : "Επιβεβαιώστε ότι θέλετε να επανεκκινήσετε αυτήν την εικονική μηχανή.", +"message.action.reboot.router" : "Όλες οι υπηρεσίες που παρέχονται από αυτόν τον εικονικό δρομολογητή θα διακοπούν. Επιβεβαιώστε ότι θέλετε να επανεκκινήσετε αυτόν το δρομολογητή.", +"message.action.reboot.systemvm" : "Επιβεβαιώστε ότι θέλετε να επανεκκινήσετε αυτό το σύστημα VM.", +"message.action.recover.volume" : "Επιβεβαιώστε ότι θέλετε να ανακτήσετε αυτόν τον τόμο.", +"message.action.release.ip" : "Επιβεβαιώστε ότι θέλετε να αποδεσμεύσετε αυτήν την IP.", +"message.action.remove.host" : "Επιβεβαιώστε ότι θέλετε να καταργήσετε αυτόν τον κεντρικό υπολογιστή.", +"message.action.reset.password.off" : "Αυτήν τη στιγμή η εικονική μηχανή σας δεν υποστηρίζει αυτήν τη δυνατότητα.", +"message.action.reset.password.warning" : "Η εικονική μηχανή σας πρέπει να διακοπεί πριν επιχειρήσετε να αλλάξετε τον τρέχοντα κωδικό πρόσβασής της.", +"message.action.restore.instance" : "Επιβεβαιώστε ότι θέλετε να επαναφέρετε αυτήν την εικονική μηχανή.", +"message.action.revert.snapshot" : "Επιβεβαιώστε ότι θέλετε να επαναφέρετε τον τόμο κατοχής σε αυτό το στιγμιότυπο.", +"message.action.router.health.checks" : "Το αποτέλεσμα των ελέγχων εύρυθμης λειτουργίας θα ληφθεί από το δρομολογητή.", +"message.action.router.health.checks.disabled.warning" : "Ενεργοποιήστε τους ελέγχους εύρυθμης λειτουργίας του δρομολογητή.", +"message.action.secondary.storage.read.only" : "Επιβεβαιώστε ότι θέλετε να θέσετε το δευτερεύον χώρο αποθήκευσης σε επιλογή read-only", +"message.action.secondary.storage.read.write" : "Επιβεβαιώστε ότι θέλετε να θέσετε το δευτερεύον χώρο αποθήκευσης σε επιλογή read-write", +"message.action.secure.host" : "Αυτό θα επανεκκινήσει τον κεντρικό agent και την διεργασία libvirtd μετά την εφαρμογή νέων πιστοποιητικών X509, επιβεβαιώνετε;", +"message.action.settings.warning.vm.running" : "Διακόψτε την εικονική μηχανή για πρόσβαση στις ρυθμίσεις", +"message.action.settings.warning.vm.started" : "Η εικονική μηχανή έχει ξεκινήσει. Πρέπει να διακοπεί για να αποκτήσετε πρόσβαση στις ρυθμίσεις", +"message.action.start.instance" : "Επιβεβαιώστε ότι θέλετε να ξεκινήσετε αυτήν την εικονική μηχανή.", +"message.action.start.router" : "Επιβεβαιώστε ότι θέλετε να ξεκινήσετε αυτόν το δρομολογητή.", +"message.action.start.systemvm" : "Επιβεβαιώστε ότι θέλετε να ξεκινήσετε αυτό το σύστημα VM.", +"message.action.stop.instance" : "Επιβεβαιώστε ότι θέλετε να διακόψετε αυτήν την εικονική μηχανή.", +"message.action.stop.router" : "Όλες οι υπηρεσίες που παρέχονται από αυτόν τον εικονικό δρομολογητή θα διακοπούν. Επιβεβαιώστε ότι θέλετε να διακόψετε αυτόν το δρομολογητή.", +"message.action.stop.systemvm" : "Επιβεβαιώστε ότι θέλετε να διακόψετε αυτό το σύστημα VM.", +"message.action.unmanage.cluster" : "Επιβεβαιώστε ότι θέλετε να καταργήσετε τη διαχείριση του ομοταξίας.", +"message.action.unmanage.virtualmachine" : "Επιβεβαιώστε ότι θέλετε να απενεργοποιήσετε τη διαχείριση της εικονικής μηχανής.", +"message.action.vmsnapshot.create" : "Επιβεβαιώστε ότι θέλετε να τραβήξετε ένα στιγμιότυπο αυτής της εικονική μηχανής.
Παρατηρήστε ότι η εικονική μηχανή θα διακοπεί κατά τη διάρκεια της λήψης στιγμιοτύπου και θα συνεχιστεί μετά την ολοκλήρωση της διαδικασίας, εάν εκτελείται στο KVM.", +"message.action.vmsnapshot.delete" : "Επιβεβαιώστε ότι θέλετε να διαγράψετε αυτό το στιγμιότυπο VM.
Παρατηρήστε ότι η εικονική μηχανή θα διακοπεί πριν από τη διαγραφή του στιγμιότυπου και θα συνεχιστεί μετά τη διαγραφή, εάν εκτελείται στο KVM.", +"message.action.vmsnapshot.revert" : "Επαναφορά στιγμιότυπου VM", +"message.action.vmstoragesnapshot.create" : "Επιλέξτε έναν τόμο που θέλετε να τραβήξετε ένα στιγμιότυπο.", +"message.activate.project" : "Είστε βέβαιοι ότι θέλετε να ενεργοποιήσετε αυτό το έργο;", +"message.add.cluster" : "Προσθέστε ένα διαχειριζόμενο σύμπλεγμα hypervisor για τη ζώνη , pod ", +"message.add.cluster.zone" : "Προσθήκη διαχειριζόμενου ομοταξίας hypervisor για ζώνη ", +"message.add.disk.offering" : "Καθορίστε τις ακόλουθες παραμέτρους για να προσθέσετε μια νέα προσφορά δίσκου", +"message.add.domain" : "Καθορίστε τον δευτερεύοντα τομέα που θέλετε να δημιουργήσετε κάτω από αυτόν τον τομέα", +"message.add.egress.rule.failed" : "Η προσθήκη νέου κανόνα εξόδου απέτυχε", +"message.add.egress.rule.processing" : "Προσθήκη νέου κανόνα εξόδου...", +"message.add.failed" : "Η προσθήκη απέτυχε", +"message.add.firewall" : "Προσθήκη τείχους προστασίας στη ζώνη", +"message.add.firewall.rule.failed" : "Η προσθήκη νέου κανόνα τείχους προστασίας απέτυχε", +"message.add.firewall.rule.processing" : "Προσθήκη νέου κανόνα τείχους προστασίας...", +"message.add.guest.network" : "Επιβεβαιώστε ότι θέλετε να προσθέσετε ένα δίκτυο επισκεπτών", +"message.add.host" : "Καθορίστε τις ακόλουθες παραμέτρους για να προσθέσετε έναν νέο κεντρικό υπολογιστή", +"message.add.ip.range" : "Προσθήκη περιοχής IP σε δημόσιο δίκτυο στη ζώνη", +"message.add.ip.range.direct.network" : "Προσθήκη περιοχής IP για την άμεση σύνδεση δικτύου στη ζώνη ", +"message.add.ip.range.to.pod" : "

Προσθέστε ένα εύρος διεθύνσεων IPs στην υποομάδα:

", +"message.add.iprange.processing" : "Προσθήκη περιοχής IP...", +"message.add.load.balancer" : "Προσθήκη εξισορρόπησης φόρτου στη ζώνη", +"message.add.load.balancer.under.ip" : "Ο κανόνας ισομοιρασμού φόρτου προστέθηκε στην IP:", +"message.add.network" : "Προσθέστε ένα νέο δίκτυο για την ζώνη: ", +"message.add.network.acl.failed" : "Η προσθήκη λίστας ACL δικτύου απέτυχε", +"message.add.network.acl.processing" : "Προσθήκη λίστας ACL δικτύου...", +"message.add.network.failed" : "Η προσθήκη δικτύου απέτυχε", +"message.add.network.processing" : "Προσθήκη δικτύου...", +"message.add.new.gateway.to.vpc" : "Καθορίστε τις πληροφορίες για να προσθέσετε μια νέα πύλη σε αυτό το VPC.", +"message.add.pod" : "Προσθέστε ένα νέο pod για τη ζώνη ", +"message.add.pod.during.zone.creation" : "Κάθε ζώνη πρέπει να περιέχει ένα ή περισσότερα pods, και θα προσθέσουμε το πρώτο pod τώρα. Ένα pod περιέχει κεντρικούς υπολογιστές και κύριους διακομιστές αποθήκευσης, τα οποία θα προσθέσετε σε ένα μεταγενέστερο βήμα. Πρώτα, ρυθμίστε τις παραμέτρους μιας περιοχής δεσμευμένων διευθύνσεων IP για την εσωτερική Κίνηση διαχείρισης του CloudStack. Η δεσμευμένη περιοχή IP πρέπει να είναι μοναδική για κάθε ζώνη στο cloud.", +"message.add.port.forward.failed" : "Η προσθήκη νέου κανόνα προώθησης θυρών απέτυχε", +"message.add.port.forward.processing" : "Προσθήκη νέου κανόνα προώθησης θυρών...", +"message.add.primary" : "Καθορίστε τις ακόλουθες παραμέτρους για να προσθέσετε ένα νέο πρωτεύον χώρο αποθήκευσης", +"message.add.primary.storage" : "Προσθέστε ένα νέο κύριο χώρο αποθήκευσης για τη ζώνη , pod ", +"message.add.private.gateway.failed" : "Η προσθήκη ιδιωτικής πύλης απέτυχε", +"message.add.private.gateway.processing" : "Προσθήκη ιδιωτικής πύλης...", +"message.add.region" : "Καθορίστε τις απαιτούμενες πληροφορίες για την προσθήκη μιας νέας περιοχής.", +"message.add.resource.description" : "Προσθήκη πόρων υποδομής", +"message.add.resource.hint" : "Προσθέστε πόρους υποδομής - pods, συμπλέγματα, πρωτεύοντες/δευτερεύουσες αποθήκες.", +"message.add.rule.failed" : "Απέτυχε η προσθήκη νέου κανόνα", +"message.add.rule.processing" : "Προσθήκη νέου κανόνα ομάδας ασφαλείας...", +"message.add.secondary.ipaddress.processing" : "Προσθήκη δευτερεύουσας διεύθυνσης IP...", +"message.add.secondary.storage" : "Προσθήκη νέου χώρου αποθήκευσης για τη ζώνη ", +"message.add.service.offering" : "Συμπληρώστε τα παρακάτω δεδομένα για να προσθέσετε μια νέα προσφορά υπηρεσίας υπολογισμού.", +"message.add.static.route.failed" : "Απέτυχε η προσθήκη στατικής διαδρομής", +"message.add.static.route.processing" : "Προσθήκη στατικής διαδρομής...", +"message.add.system.service.offering" : "Συμπληρώστε τα παρακάτω δεδομένα για να προσθέσετε μια νέα προσφορά υπηρεσιών συστήματος.", +"message.add.tag.failed" : "Απέτυχε η προσθήκη νέας ετικέτας", +"message.add.tag.for.networkacl" : "Προσθήκη ετικέτας για networkacl", +"message.add.tag.processing" : "Προσθήκη νέας ετικέτας...", +"message.add.template" : "Πληκτρολογήστε τα ακόλουθα δεδομένα για να δημιουργήσετε το νέο σας πρότυπο", +"message.add.user.to.project" : "Αυτή η φόρμα χρησιμοποιείται για να ενεργοποιήσετε την προσθήκη συγκεκριμένων χρηστών ενός λογαριασμού σε ένα έργο.
Επιπλέον, ένα ProjectRole μπορεί να προστεθεί στο πρόσθετο χρήστη/λογαριασμό για να επιτρέψει/απαγορεύσει την πρόσβαση API σε επίπεδο έργου.
Μπορούμε επίσης να καθορίσουμε το ρόλο με τον οποίο ο χρήστης θα πρέπει να προστεθεί σε ένα έργο - Admin/Regular, εάν δεν καθοριστεί, είναι προεπιλογή σε «Regular»", +"message.add.volume" : "Συμπληρώστε τα παρακάτω δεδομένα για να προσθέσετε έναν νέο τόμο.", +"message.add.vpn.connection.failed" : "Η προσθήκη σύνδεσης VPN απέτυχε", +"message.add.vpn.connection.processing" : "Προσθήκη σύνδεσης VPN...", +"message.add.vpn.customer.gateway" : "Προσθήκη πύλης πελατών VPN", +"message.add.vpn.customer.gateway.failed" : "Απέτυχε η προσθήκη πύλης πελάτη VPN", +"message.add.vpn.customer.gateway.processing" : "Η δημιουργία της πύλης πελατών VPN βρίσκεται σε εξέλιξη", +"message.add.vpn.gateway" : "Επιβεβαιώστε ότι θέλετε να προσθέσετε μια πύλη VPN", +"message.add.vpn.gateway.failed" : "Η προσθήκη πύλης VPN απέτυχε", +"message.add.vpn.gateway.processing" : "Προσθήκη πύλης VPN...", +"message.added.vpc.offering" : "Προστέθηκε προσφορά υπηρεσίας VPC", +"message.adding.host" : "Προσθήκη κεντρικού υπολογιστή", +"message.adding.netscaler.device" : "Προσθήκη συσκευής netsccaler", +"message.adding.netscaler.provider" : "Προσθήκη υπηρεσίας παροχής Netsccaler", +"message.additional.networks.desc" : "Επιλέξτε πρόσθετα δίκτυα με τα οποία θα συνδεθεί η εικονική εικονική μηχανή σας.", +"message.admin.guide.read" : "Για VM που βασίζονται σε VM, διαβάστε την ενότητα δυναμικής κλιμάκωσης στον οδηγό διαχείρισης πριν από την κλιμάκωση. Θέλετε να συνεχίσετε;,", +"message.advanced.mode.desc" : "Επιλέξτε αυτό το μοντέλο δικτύου εάν θέλετε να ενεργοποιήσετε την υποστήριξη VLAN. Αυτό το μοντέλο δικτύου παρέχει τη μεγαλύτερη ευελιξία στην παροχή στους διαχειριστές προσαρμοσμένων προσφορών δικτύου, όπως η παροχή υποστήριξης τείχους προστασίας, VPN ή εξισορρόπησης φόρτου, καθώς και η ενεργοποίηση της άμεσης vs εικονικής δικτύωσης.", +"message.advanced.security.group" : "Επιλέξτε αυτό εάν θέλετε να χρησιμοποιήσετε ομάδες ασφαλείας για να παρέχετε απομόνωση vm επισκέπτη.", +"message.advanced.virtual" : "Επιλέξτε αυτό εάν θέλετε να χρησιμοποιήσετε vlan σε ολόκληρη τη ζώνη για να παρέχετε απομόνωση VM επισκέπτη.", +"message.after.enable.s3" : "Η παραμετροποίηση του δευτερεύοντος χώρου αποθήκευσης S3-backend έχει ολοκληρωθεί. Σημείωση: Μετά την απομάκρυνση απο την παρούσα σελίδα δεν είναι δυνατή η εκ νέου παραμετροποίηση", +"message.after.enable.swift" : "Η παραμετροποίηση του δευτερεύοντος χώρου αποθήκευσης Swift έχει ολοκληρωθεί. Σημείωση: Μετά την απομάκρυνση απο την παρούσα σελίδα δεν είναι δυνατή η εκ νέου παραμετροποίηση", +"message.alert.state.detected" : "Εντοπίστηκε κατάσταση ειδοποίησης", +"message.allow.vpn.access" : "Πληκτρολογήστε ένα όνομα χρήστη και κωδικό πρόσβασης του χρήστη που θέλετε να επιτρέψετε την πρόσβαση VPN.", +"message.apply.snapshot.policy" : "Έχετε ενημερώσει με επιτυχία την τρέχουσα πολιτική στιγμιοτύπων.", +"message.apply.success" : "Η εφαρμογή ολοκληρώθηκε με επιτυχία", +"message.assign.instance.another" : "Καθορίστε τον τύπο λογαριασμού, τον τομέα, το όνομα λογαριασμού και το δίκτυο (προαιρετικό) του νέου λογαριασμού.
Εάν το προεπιλεγμένο nic της εικονικής μηχανής βρίσκεται σε κοινόχρηστο δίκτυο, το CloudStack θα ελέγξει αν το δίκτυο μπορεί να χρησιμοποιηθεί από το νέο λογαριασμό, εάν δεν καθορίσετε ένα δίκτυο.
Εάν το προεπιλεγμένο nic της εικονικής μηχανής βρίσκεται σε απομονωμένο δίκτυο και ο νέος λογαριασμός έχει περισσότερα απομονωμένα δίκτυα, θα πρέπει να καθορίσετε ένα.", +"message.assign.vm.failed" : "Απέτυχε η αντιστοίχιση vm", +"message.assign.vm.processing" : "Αντιστοίχιση εικονικής μηχανής...", +"message.attach.iso.confirm" : "Επιβεβαιώστε ότι θέλετε να επισυνάψετε το ISO σε αυτήν την εικονική εικονική μηχανή.", +"message.attach.volume" : "Συμπληρώστε τα παρακάτω δεδομένα για να επισυνάψετε έναν νέο τόμο. Εάν συνδέετε έναν τόμο δίσκου σε μια εικονική μηχανή που βασίζεται στα Windows, θα χρειαστεί να επανεκκινήσετε την εικονική μηχανή για να δείτε τον συνημμένο δίσκο.", +"message.attach.volume.failed" : "Απέτυχε η επισύναψη τόμου", +"message.attach.volume.progress" : "Επισύναψη τόμου", +"message.authorization.failed" : "Η περίοδος λειτουργίας έληξε, η επαλήθευση εξουσιοδότησης απέτυχε", +"message.backup.attach.restore" : "Επιβεβαιώστε ότι θέλετε να επαναφέρετε και να επισυνάψετε τον τόμο από το αντίγραφο ασφαλείας;", +"message.backup.create" : "Είστε βέβαιοι ότι θέλετε να δημιουργήσετε ένα αντίγραφο ασφαλείας VM;", +"message.backup.offering.remove" : "Είστε βέβαιοι ότι θέλετε να καταργήσετε την εικονική μηχανή από την προσφορά δημιουργίας αντιγράφων ασφαλείας και να διαγράψετε την αλυσίδα αντιγράφων ασφαλείας;", +"message.backup.restore" : "Επιβεβαιώστε ότι θέλετε να επαναφέρετε το αντίγραφο ασφαλείας vm;", +"message.basic.mode.desc" : "Επιλέξτε αυτό το μοντέλο δικτύου, αν δεν* * θέλετε να ενεργοποιήσετε οποιαδήποτε υποστήριξη VLAN. Σε όλες τις εικονικές παρουσίες που δημιουργούνται στο πλαίσιο αυτού του μοντέλου δικτύου θα εκχωρηθεί μια διεύθυνση IP απευθείας από το δίκτυο και οι ομάδες ασφαλείας χρησιμοποιούνται για την παροχή ασφάλειας και διαχωρισμού.", +"message.certificate.upload.processing" : "Αποστολή πιστοποιητικού σε εξέλιξη", +"message.change.offering.confirm" : "Επιβεβαιώστε ότι θέλετε να αλλάξετε την προσφορά υπηρεσιών αυτής της εικονικής εικονική μηχανής.", +"message.change.password" : "Αλλάξτε τον κωδικό πρόσβασής σας", +"message.cluster.dedicated" : "Αποκλειστικό σύμπλεγμα", +"message.cluster.dedication.released" : "Η αποκλειστική διάθεση στο σύμπλεγμα αποδεσμέυτηκε", +"message.config.sticky.policy.failed" : "Απέτυχε η ρύθμιση παραμέτρων της πολιτικής αυτοκόλλητης", +"message.config.sticky.policy.processing" : "Ενημέρωση sticky πολιτικής...", +"message.configure.all.traffic.types" : "Έχετε πολλά φυσικά δίκτυα. Ρυθμίστε τις παραμέτρους των ετικετών για κάθε τύπο κίνησης κάνοντας κλικ στο κουμπί Επεξεργασία.", +"message.configure.firewall.rules.allow.traffic" : "Ρύθμιση παραμέτρων των κανόνων ώστε να επιτρέπεται η Κίνηση", +"message.configure.firewall.rules.block.traffic" : "Ρύθμιση παραμέτρων των κανόνων για τον αποκλεισμό της κίνησης", +"message.configure.ldap" : "Επιβεβαιώστε ότι θέλετε να ρυθμίσετε τις παραμέτρους του LDAP.", +"message.configuring.guest.traffic" : "Ρύθμιση παραμέτρων επισκεψιμότητας επισκεπτών", +"message.configuring.physical.networks" : "Ρύθμιση παραμέτρων φυσικών δικτύων", +"message.configuring.public.traffic" : "Ρύθμιση παραμέτρων δημόσιας κίνησης", +"message.configuring.storage.traffic" : "Ρύθμιση παραμέτρων κίνησης αποθήκευσης", +"message.confirm.action.force.reconnect" : "Επιβεβαιώστε ότι θέλετε να επισυνάσετε την επανασύνδεση αυτού του κεντρικού υπολογιστή.", +"message.confirm.add.vnmc.provider" : "Επιβεβαιώστε ότι θέλετε να προσθέσετε την υπηρεσία παροχής VNMC.", +"message.confirm.archive.alert" : "Επιβεβαιώστε ότι θέλετε να αρχειοθετήσετε αυτήν την ειδοποίηση.", +"message.confirm.archive.event" : "Επιβεβαιώστε ότι θέλετε να αρχειοθετήσετε αυτό το συμβάν.", +"message.confirm.archive.selected.alerts" : "Επιβεβαιώστε ότι θέλετε να αρχειοθετήσετε τις επιλεγμένες ειδοποιήσεις", +"message.confirm.archive.selected.events" : "Επιβεβαιώστε ότι θέλετε να αρχειοθετήσετε τα επιλεγμένα συμβάντα", +"message.confirm.attach.disk" : "Είστε βέβαιοι ότι θέλετε να επισυνάψετε το δίσκο;", +"message.confirm.configure.ovs" : "Είστε βέβαιοι ότι θέλετε να ρυθμίσετε τις παραμέτρους του Ovs;", +"message.confirm.create.volume" : "Είστε βέβαιοι ότι θέλετε να δημιουργήσετε τόμο;", +"message.confirm.current.guest.cidr.unchanged" : "Θέλετε να διατηρήσετε αμετάβλητο το τρέχον δίκτυο επισκεπτών CIDR;", +"message.confirm.dedicate.cluster.domain.account" : "Θέλετε πραγματικά να αφιερώσετε αυτό το σύμπλεγμα σε έναν τομέα / λογαριασμό; ", +"message.confirm.dedicate.host.domain.account" : "Θέλετε πραγματικά να αφιερώσετε αυτόν τον κεντρικό υπολογιστή σε έναν τομέα/απολογισμό; ", +"message.confirm.dedicate.pod.domain.account" : "Θέλετε πραγματικά να αφιερώσετε αυτήν την υποομάδα (pod) σε ένα domain / λογαριασμό; ", +"message.confirm.dedicate.zone" : "Θέλετε πραγματικά να αφιερώσετε αυτή τη ζώνη σε έναν τομέα / λογαριασμό;", +"message.confirm.delete.acl.list" : "Είστε βέβαιοι ότι θέλετε να διαγράψετε αυτήν τη λίστα ACL;", +"message.confirm.delete.alert" : "Είστε βέβαιοι ότι θέλετε να διαγράψετε αυτήν την ειδοποίηση;", +"message.confirm.delete.baremetal.rack.configuration" : "Επιβεβαιώστε ότι θέλετε να διαγράψετε τη ρύθμιση παραμέτρων του Baremetal Rack.", +"message.confirm.delete.bigswitchbcf" : "Επιβεβαιώστε ότι θέλετε να διαγράψετε αυτόν τον ελεγκτή BigSwitch BCF", +"message.confirm.delete.brocadevcs" : "Επιβεβαιώστε ότι θέλετε να διαγράψετε το εναλλάκτη Brocade Vcs", +"message.confirm.delete.ciscoasa1000v" : "Παρακαλώ επιβεβαιώστε ότι θέλετε να διαγράψετε CiscoASA1000v", +"message.confirm.delete.ciscovnmc.resource" : "Επιβεβαιώστε ότι θέλετε να διαγράψετε τον πόρο CiscoVNMC", +"message.confirm.delete.f5" : "Επιβεβαιώστε ότι θέλετε να διαγράψετε το F5", +"message.confirm.delete.internal.lb" : "Επιβεβαιώστε ότι θέλετε να διαγράψετε το εσωτερικό LB", +"message.confirm.delete.kubernetes.version" : "Επιβεβαιώστε ότι θέλετε να διαγράψετε αυτήν την έκδοση Kubernetes.", +"message.confirm.delete.netscaler" : "Επιβεβαιώστε ότι θέλετε να διαγράψετε το NetSccaler", +"message.confirm.delete.niciranvp" : "Επιβεβαιώστε ότι θέλετε να διαγράψετε τον ελεγκτή Nicira Nvp", +"message.confirm.delete.pa" : "Επιβεβαιώστε ότι θέλετε να διαγράψετε το Palo Alto", +"message.confirm.delete.provider" : "Επιβεβαιώστε ότι θέλετε να διαγράψετε αυτήν την υπηρεσία παροχής;", +"message.confirm.delete.secondary.staging.store" : "Επιβεβαιώστε ότι θέλετε να διαγράψετε το δευτερεύον χώρο αποθήκευσης ανασυγκρότησης.", +"message.confirm.delete.srx" : "Επιβεβαιώστε ότι θέλετε να διαγράψετε το SRX", +"message.confirm.delete.ucs.manager" : "Επιβεβαιώστε ότι θέλετε να διαγράψετε το UCS Manager", +"message.confirm.destroy.kubernetes.cluster" : "Επιβεβαιώστε ότι θέλετε να καταστρέψετε αυτό το σύμπλεγμα Kubernetes.", +"message.confirm.destroy.router" : "Όλες οι υπηρεσίες που παρέχονται από αυτόν τον εικονικό δρομολογητή θα διακοπούν. Επιβεβαιώστε ότι θέλετε να διακόψετε αυτόν το δρομολογητή. Επιβεβαιώστε ότι θέλετε να καταστρέψετε αυτόν το δρομολογητή", +"message.confirm.disable.host" : "Επιβεβαιώστε ότι θέλετε να απενεργοποιήσετε τον κεντρικό υπολογιστή", +"message.confirm.disable.storage" : "Επιβεβαιώστε ότι θέλετε να απενεργοποιήσετε το χώρο συγκέντρωσης χώρου αποθήκευσης", +"message.confirm.disable.network.offering" : "Είστε βέβαιοι ότι θέλετε να απενεργοποιήσετε αυτήν την προσφορά δικτύου;", +"message.confirm.disable.provider" : "Επιβεβαιώστε ότι θέλετε να απενεργοποιήσετε αυτήν την υπηρεσία παροχής", +"message.confirm.disable.vnmc.provider" : "Επιβεβαιώστε ότι θέλετε να απενεργοποιήσετε την υπηρεσία παροχής VNMC.", +"message.confirm.disable.vpc.offering" : "Είστε βέβαιοι ότι θέλετε να απενεργοποιήσετε αυτήν την προσφορά VPC;", +"message.confirm.enable.host" : "Επιβεβαιώστε ότι θέλετε να ενεργοποιήσετε τον κεντρικό υπολογιστή", +"message.confirm.enable.storage" : "Επιβεβαιώστε ότι θέλετε να ενεργοποιήσετε το χώρο συγκέντρωσης χώρου αποθήκευσης", +"message.confirm.enable.network.offering" : "Είστε βέβαιοι ότι θέλετε να ενεργοποιήσετε αυτήν την προσφορά δικτύου;", +"message.confirm.enable.provider" : "Επιβεβαιώστε ότι θέλετε να ενεργοποιήσετε αυτήν την υπηρεσία παροχής", +"message.confirm.enable.vnmc.provider" : "Επιβεβαιώστε ότι θέλετε να ενεργοποιήσετε την υπηρεσία παροχής VNMC.", +"message.confirm.enable.vpc.offering" : "Είστε βέβαιοι ότι θέλετε να ενεργοποιήσετε αυτήν την προσφορά VPC;", +"message.confirm.force.update" : "Θέλετε να επιβάλετε την ενημέρωση;", +"message.confirm.join.project" : "Επιβεβαιώστε ότι επιθυμείτε να συμμετάσχετε σε αυτό το έργο.", +"message.confirm.migrate.volume" : "Θέλετε να μετεγκαταστήσετε αυτόν τον τόμο;", +"message.confirm.refresh.blades" : "Επιβεβαιώστε ότι θέλετε να ανανεώσετε τα Blades.", +"message.confirm.release.dedicate.vlan.range" : "Επιβεβαιώστε ότι θέλετε να αποδεσμεύσετε την αποκλειστική σειρά VLAN", +"message.confirm.release.dedicated.cluster" : "Θέλετε να αποδεσμεύσετε αυτό το αποκλειστικό σύμπλεγμα;", +"message.confirm.release.dedicated.host" : "Θέλετε να αποδεσμεύσετε αυτόν τον αποκλειστικό κεντρικό υπολογιστή;", +"message.confirm.release.dedicated.pod" : "Θέλετε να αποδεσμεύσετε αυτήν την ειδική υποομάδα (pod);", +"message.confirm.release.dedicated.zone" : "Θέλετε να αποδεσμεύσετε αυτήν την αποκλειστική ζώνη; ", +"message.confirm.remove.event" : "Είστε βέβαιοι ότι θέλετε να καταργήσετε αυτό το συμβάν;", +"message.confirm.remove.ip.range" : "Επιβεβαιώστε ότι θέλετε να καταργήσετε αυτήν την περιοχή IP.", +"message.confirm.remove.load.balancer" : "Επιβεβαιώστε ότι θέλετε να καταργήσετε την εικονική μηχανή από την εξισορρόπηση φόρτου", +"message.confirm.remove.network.offering" : "Είστε βέβαιοι ότι θέλετε να καταργήσετε αυτήν την προσφορά δικτύου;", +"message.confirm.remove.selected.alerts" : "Επιβεβαιώστε ότι θέλετε να καταργήσετε τις επιλεγμένες ειδοποιήσεις", +"message.confirm.remove.selected.events" : "Επιβεβαιώστε ότι θέλετε να καταργήσετε τα επιλεγμένα συμβάντα", +"message.confirm.remove.vmware.datacenter" : "Επιβεβαιώστε ότι θέλετε να καταργήσετε το κέντρο δεδομένων VMware", +"message.confirm.remove.vpc.offering" : "Είστε βέβαιοι ότι θέλετε να καταργήσετε αυτήν την προσφορά VPC;", +"message.confirm.replace.acl.new.one" : "Θέλετε να αντικαταστήσετε το ACL με ένα νέο;", +"message.confirm.scale.up.router.vm" : "Θέλετε πραγματικά να κλιμακώσετε το Router VM;", +"message.confirm.scale.up.system.vm" : "Θέλετε πραγματικά να κλιμακώσετε το σύστημα VM;", +"message.confirm.shutdown.provider" : "Επιβεβαιώστε ότι θέλετε να τερματίσετε τη λειτουργία αυτής της υπηρεσίας παροχής", +"message.confirm.start.kubernetes.cluster" : "Επιβεβαιώστε ότι θέλετε να ξεκινήσετε αυτό το σύμπλεγμα Kubernetes.", +"message.confirm.start.lb.vm" : "Επιβεβαιώστε ότι θέλετε να ξεκινήσετε το LB VM", +"message.confirm.stop.kubernetes.cluster" : "Επιβεβαιώστε ότι θέλετε να διακόψετε αυτό το σύμπλεγμα Kubernetes.", +"message.confirm.stop.lb.vm" : "Επιβεβαιώστε ότι θέλετε να διακόψετε το LB VM", +"message.confirm.upgrade.router.newer.template" : "Επιβεβαιώστε ότι θέλετε να αναβαθμίσετε το δρομολογητή για να χρησιμοποιήσετε νεότερο πρότυπο", +"message.confirm.upgrade.routers.account.newtemplate" : "Επιβεβαιώστε ότι θέλετε να αναβαθμίσετε όλους τους δρομολογητές σε αυτόν το λογαριασμό για να χρησιμοποιήσετε νεότερο πρότυπο", +"message.confirm.upgrade.routers.cluster.newtemplate" : "Επιβεβαιώστε ότι θέλετε να αναβαθμίσετε όλους τους δρομολογητές σε αυτό το σύμπλεγμα για να χρησιμοποιήσετε νεότερο πρότυπο", +"message.confirm.upgrade.routers.newtemplate" : "Επιβεβαιώστε ότι θέλετε να αναβαθμίσετε όλους τους δρομολογητές σε αυτήν τη ζώνη για να χρησιμοποιήσετε νεότερα πρότυπα", +"message.confirm.upgrade.routers.pod.newtemplate" : "Επιβεβαιώστε ότι θέλετε να αναβαθμίσετε όλους τους δρομολογητές σε αυτήν την υποομάδα (pod) για να χρησιμοποιήσετε νεότερα πρότυπα", +"message.copy.iso.confirm" : "Επιβεβαιώστε ότι επιθυμείτε να αντιγράψετε το ISO σας", +"message.copy.template" : "Αντιγραφή προτύπου XXX από ζώνη σε", +"message.copy.template.confirm" : "Είστε βέβαιοι ότι θέλετε να αντιγράψετε το πρότυπο;", +"message.create.compute.offering" : "Υπολογισμός προσφοράς υπηρεσίας που δημιουργήθηκε", +"message.create.internallb" : "Δημιουργία εσωτερικού LB", +"message.create.internallb.failed" : "Απέτυχε η δημιουργία εσωτερικής lb", +"message.create.internallb.processing" : "Δημιουργία εσωτερικού LB σε εξέλιξη", +"message.create.service.offering" : "Δημιουργία προσφοράς υπηρεσίας υπηρεσιών", +"message.create.snapshot.from.vmsnapshot.failed" : "Απέτυχε η δημιουργία στιγμιότυπου από το στιγμιότυπο VM", +"message.create.snapshot.from.vmsnapshot.progress" : "Δημιουργία στιγμιότυπου σε εξέλιξη", +"message.create.template" : "Είστε βέβαιοι ότι θέλετε να δημιουργήσετε πρότυπο;", +"message.create.template.vm" : "Δημιουργία εικονικής μηχανής από πρότυπο ", +"message.create.template.volume" : "Παρακαλώ εισάγεται της ακόλουθες πληροφορίες πριν την δημιουργία του προτύπου τόμου δίσκων: . Η δημιουργία του προτύπου, ανάλογα με το μέγεθος του, ενδέχεται να διαρκέσει απο κάποια λεπτά ώρες.", +"message.create.volume.failed" : "Απέτυχε η δημιουργία τόμου", +"message.create.volume.processing" : "Δημιουργία τόμου σε εξέλιξη", +"message.create.vpc.offering" : "VPC προσφορά που δημιουργήθηκε", +"message.create.vpn.customer.gateway.failed" : "Η δημιουργία πύλης πελάτη VPN απέτυχε", +"message.creating.cluster" : "Δημιουργία ομοταξίας", +"message.creating.guest.network" : "Δημιουργία δικτύου επισκεπτών", +"message.creating.physical.networks" : "Δημιουργία φυσικών δικτύων", +"message.creating.pod" : "Δημιουργία υποομάδας (pod)", +"message.creating.primary.storage" : "Δημιουργία πρωτεύοντος χώρου αποθήκευσης", +"message.creating.secondary.storage" : "Δημιουργία δευτερεύοντος χώρου αποθήκευσης", +"message.creating.systemvm" : "Δημιουργία VM συστήματος (αυτό μπορεί να διαρκέσει λίγο)", +"message.creating.zone" : "Δημιουργία ζώνης", +"message.datacenter.description" : "Όνομα του κέντρου δεδομένων στο vCenter", +"message.datastore.description" : "Όνομα του χώρου αποθήκευσης δεδομένων στο vCenter", +"message.data.migration" : "Μετεγκατάσταση δεδομένων", +"message.data.migration.progress" : "Μετεγκατάσταση δεδομένων μεταξύ των καταστημάτων αποθήκευσης εικόνων", +"message.dedicate.zone" : "αποκλειστική διάθεση ζώνης", +"message.dedicated.zone.released" : "Αποδεσμεύτηκε η αποκλειστική διάθεση ζώνης", +"message.dedicating.cluster" : "αποκλειστικοποίηση ομοταξίας...", +"message.dedicating.host" : "αποκλειστικοποίηση υποδοχής...", +"message.dedicating.pod" : "αποκλειστικοποίηση υποομάδας (pod)...", +"message.dedicating.zone" : "αποκλειστικοποίηση Ζώνης...", +"message.delete.account" : "Επιβεβαιώστε ότι θέλετε να διαγράψετε αυτόν το λογαριασμό.", +"message.delete.acl.processing" : "Κατάργηση κανόνα ACL...", +"message.delete.acl.rule" : "Κατάργηση κανόνα ACL", +"message.delete.acl.rule.failed" : "Απέτυχε η κατάργηση του κανόνα ACL", +"message.delete.affinity.group" : "Επιβεβαιώστε ότι θέλετε να καταργήσετε αυτήν την ομάδα συνάφειας.", +"message.delete.backup" : "Είστε βέβαιοι ότι θέλετε να διαγράψετε το αντίγραφο ασφαλείας;", +"message.delete.failed" : "Η διαγραφή απέτυχε", +"message.delete.gateway" : "Επιβεβαιώστε ότι θέλετε να διαγράψετε την πύλη", +"message.delete.port.forward.processing" : "Διαγραφή κανόνα προώθησης θυρών...", +"message.delete.project" : "Είστε βέβαιοι ότι θέλετε να διαγράψετε αυτό το έργο;", +"message.delete.rule.processing" : "Διαγραφή κανόνα...", +"message.delete.sslcertificate" : "Επιβεβαιώστε ότι θέλετε να διαγράψετε αυτό το πιστοποιητικό.", +"message.delete.static.route.failed" : "Απέτυχε η διαγραφή της στατικής διαδρομής", +"message.delete.static.route.processing" : "Διαγραφή στατικής διαδρομής...", +"message.delete.tag.failed" : "Απέτυχε η διαγραφή της ετικέτας", +"message.delete.tag.for.networkacl" : "Κατάργηση ετικέτας για networkacl", +"message.delete.tag.processing" : "Διαγραφή ετικέτας...", +"message.delete.user" : "Επιβεβαιώστε ότι θέλετε να διαγράψετε αυτόν το χρήστη.", +"message.delete.vpn.connection" : "Επιβεβαιώστε ότι θέλετε να διαγράψετε τη σύνδεση VPN", +"message.delete.vpn.customer.gateway" : "Επιβεβαιώστε ότι θέλετε να διαγράψετε αυτήν την πύλη πελάτη VPN", +"message.delete.vpn.gateway" : "Επιβεβαιώστε ότι θέλετε να διαγράψετε αυτήν την πύλη VPN", +"message.deleting.vm" : "Διαγραφή εικονικής μηχανής", +"message.deployasis" : "Το επιλεγμένο πρότυπο μπορεί να χρησιμοποιηθεί χωρίς αλλαγές (as-is). To VM θα εισάγει ένα OVA με vApps απευθείας απο το Virtual Center. Οι κύριοι δίσκοι μπορούν να αλλάξουν μέγεθος μόνο αν είναι σε κατάσταση σταματημένη για αυτά πρότυπα", +"message.desc.add.new.lb.sticky.rule" : "Προσθήκη νέου αυτοκόλλητου κανόνα LB", +"message.desc.advanced.zone" : "Για πιο εξελιγμένες τοπολογίες δικτύου. Αυτό το μοντέλο δικτύου παρέχει τη μεγαλύτερη ευελιξία στον ορισμό των δικτύων επισκεπτών και στην παροχή προσαρμοσμένων προσφορών δικτύου, όπως υποστήριξη τείχους προστασίας, VPN ή εξισορρόπησης φόρτου.", +"message.desc.basic.zone" : "Παρέχετε ένα μόνο δίκτυο όπου σε κάθε εικονική μηχανή VM εκχωρείται μια διεύθυνση IP απευθείας από το δίκτυο. Η απομόνωση των επισκεπτών μπορεί να παρέχεται μέσω των μέσων επιπέδου 3, όπως ομάδες ασφαλείας (φιλτράρισμα πηγαία διευθύνσεων IP).", +"message.desc.cluster" : "Κάθε υποομάδα (pod) πρέπει να περιέχει ένα ή περισσότερα συμπλέγματα, και θα προσθέσουμε το πρώτο σύμπλεγμα τώρα. Ένα σύμπλεγμα παρέχει έναν τρόπο ομαδοποίησης κεντρικών υπολογιστών. Οι κεντρικοί υπολογιστές σε ένα σύμπλεγμα έχουν όλοι πανομοιότυπο υλικό, εκτελούν τον ίδιο Hypervisor, βρίσκονται στο ίδιο υποδίκτυο και έχουν πρόσβαση στον ίδιο κοινόχρηστο χώρο αποθήκευσης. Κάθε σύμπλεγμα αποτελείται από έναν ή περισσότερους κεντρικούς υπολογιστές και έναν ή περισσότερους κύριους διακομιστές αποθήκευσης.", +"message.desc.create.ssh.key.pair" : "Παρακαλούμε συμπληρώστε τα παρακάτω δεδομένα για να δημιουργήσετε ή να καταχωρήσετε ένα ζεύγος κλειδιών ssh.

(1) Εάν έχει οριστεί δημόσιο κλειδί, το CloudStack θα καταχωρήσει το δημόσιο κλειδί. Μπορείτε να το χρησιμοποιήσετε μέσω του ιδιωτικού σας κλειδιού.

(2) Εάν το δημόσιο κλειδί δεν έχει οριστεί, cloudstack θα δημιουργήσει ένα νέο ζεύγος κλειδιών SSH. Σε αυτήν την περίπτωση, αντιγράψτε και αποθηκεύστε το ιδιωτικό κλειδί. Το CloudStack δεν θα το διατήρησει.
", +"message.desc.created.ssh.key.pair" : "Δημιούργησε ένα ζεύγος κλειδιών SSH.", +"message.desc.host" : "Κάθε σύμπλεγμα πρέπει να περιέχει τουλάχιστον έναν κεντρικό υπολογιστή (υπολογιστή) για να εκτελούνται οι VM επισκεπτών και θα προσθέσουμε τον πρώτο κεντρικό υπολογιστή τώρα. Για να λειτουργήσει ένας κεντρικός υπολογιστής στο CloudStack, πρέπει να εγκαταστήσετε λογισμικό hypervisor στον κεντρικό υπολογιστή, να αντιστοιχίσετε μια διεύθυνση IP στον κεντρικό υπολογιστή και να βεβαιωθείτε ότι ο κεντρικός υπολογιστής είναι συνδεδεμένος στο διακομιστή διαχείρισης CloudStack.

Δώστε τη διεύθυνση DNS ή IP του κεντρικού υπολογιστή, το όνομα χρήστη (συνήθως root) και τον κωδικό πρόσβασης, καθώς και τυχόν ετικέτες που χρησιμοποιείτε για να κατηγοριοποιήσετε κεντρικούς υπολογιστές.", +"message.desc.primary.storage" : "Κάθε σύμπλεγμα πρέπει να περιέχει έναν ή περισσότερους πρωτεύοντες διακομιστές αποθήκευσης και θα προσθέσουμε τον πρώτο τώρα. Ο κύριος χώρος αποθήκευσης περιέχει τους τόμους δίσκων για όλους τους VM που εκτελούνται σε κεντρικούς υπολογιστές του ομοταξίας. Χρησιμοποιήστε οποιοδήποτε πρωτόκολλο συμβατό με πρότυπα που υποστηρίζεται από τον υποκείμενο Hypervisor.", +"message.desc.reset.ssh.key.pair" : "Καθορίστε ένα ζεύγος κλειδιών ssh που θέλετε να προσθέσετε σε αυτήν την εικονική μηχανή. Σημειώστε ότι ο ριζικός κωδικός πρόσβασης θα αλλάξει από αυτήν τη λειτουργία, εάν είναι ενεργοποιημένος ο κωδικός πρόσβασης.", +"message.desc.secondary.storage" : "Κάθε ζώνη πρέπει να έχει τουλάχιστον ένα NFS ή δευτερεύοντα διακομιστή αποθήκευσης, και θα προσθέσουμε το πρώτο τώρα. Ο δευτερεύων χώρος αποθήκευσης αποθηκεύει πρότυπα VM, εικόνες ISO και στιγμιότυπα τόμου δίσκου VM. Αυτός ο διακομιστής πρέπει να είναι διαθέσιμος σε όλους τους κεντρικούς υπολογιστές της ζώνης.

Δώστε τη διεύθυνση IP και την εξαγόμενη διαδρομή.", +"message.desc.zone" : "Μια ζώνη είναι η μεγαλύτερη οργανική μονάδα στο CloudStack και συνήθως αντιστοιχεί σε ένα μόνο κέντρο δεδομένων. Οι ζώνες παρέχουν φυσική απομόνωση και πλεονασμό. Μια ζώνη αποτελείται από ένα ή περισσότερα pods (καθένα από τα οποία περιέχει κεντρικούς υπολογιστές και πρωτεύοντες διακομιστές αποθήκευσης) και έναν δευτερεύοντα διακομιστή αποθήκευσης, ο οποίος είναι κοινόχρηστος από όλα τα pods της ζώνης.", +"message.detach.disk" : "Είστε βέβαιοι ότι θέλετε να αποσυνδέσετε αυτόν το δίσκο;", +"message.detach.iso.confirm" : "Επιβεβαιώστε ότι θέλετε να αποσυνδέσετε το ISO από αυτήν την εικονική εικονική μηχανή.", +"message.diagnostics.exitcode" : "exitcode: var", +"message.diagnostics.stderr" : "exitcode: var", +"message.diagnostics.stdout" : "exitcode: var", +"message.disable.account" : "Επιβεβαιώστε ότι θέλετε να απενεργοποιήσετε αυτόν το λογαριασμό. Απενεργοποιώντας το λογαριασμό, όλοι οι χρήστες αυτού του λογαριασμού δεν θα έχουν πλέον πρόσβαση στους πόρους τους στο cloud. Όλες οι εικονικές μηχανές που εκτελούνται θα τερματιστούν αμέσως.", +"message.disable.snapshot.policy" : "Έχετε απενεργοποιήσει με επιτυχία την τρέχουσα πολιτική στιγμιοτύπων.", +"message.disable.user" : "Επιβεβαιώστε ότι θέλετε να απενεργοποιήσετε αυτόν το χρήστη.", +"message.disable.vpn" : "Είστε βέβαιοι ότι θέλετε να απενεργοποιήσετε το VPN;", +"message.disable.vpn.access" : "Επιβεβαιώστε ότι θέλετε να απενεργοποιήσετε το VPN απομακρυσμένης πρόσβασης.", +"message.disable.vpn.failed" : "Απέτυχε η απενεργοποίηση του VPN", +"message.disable.vpn.processing" : "Απενεργοποίηση VPN...", +"message.disabling.network.offering" : "Απενεργοποίηση προσφοράς VPN...", +"message.disabling.vpc.offering" : "Απενεργοποίηση προσφοράς υπηρεσίας VPC", +"message.disallowed.characters" : "Disallowed character <,>", +"message.discovering.feature" : "Ανακαλύπτοντας χαρακτηριστικά, περιμένετε...", +"message.disk.offering.created" : "Disk offering created:", +"message.download.diagnostics" : "Επιλέξτε τον κάτωθι σύνδεσμο για να κατεβάσετε τα διαγνωστικά:

00000", +"message.download.iso" : "Επιλέξτε τον κάτωθι σύνδεσμο για να κατεβάσετε το ISO::

00000", +"message.download.template" : "Επιλέξτε τον κάτωθι σύνδεσμο για να κατεβάσετε το πρότυπο:

00000", +"message.download.volume" : "Επιλέξτε τον κάτωθι σύνδεσμο για να κατεβάσετε τον τόμο:

00000", +"message.download.volume.confirm" : "Επιβεβαιώστε ότι θέλετε να κάνετε λήψη αυτού του τόμου.", +"message.edit.account" : "Επεξεργασία (\"-1\" δηλώνει ότι δεν υπάρχει όριο στο ποσό των πόρων που δημιουργούνται)", +"message.edit.acl.failed" : "Απέτυχε η επεξεργασία του κανόνα ACL", +"message.edit.acl.processing" : "Επεξεργασία κανόνα ACL...", +"message.edit.confirm" : "Επιβεβαιώστε τις αλλαγές σας πριν κάνετε κλικ στο κουμπί \"Αποθήκευση\".", +"message.edit.limits" : "Καθορίστε όρια στους ακόλουθους πόρους. Ένα \"-1\" δηλώνει ότι δεν υπάρχει όριο στο ποσό των πόρων που δημιουργούνται.", +"message.edit.rule.failed" : "Απέτυχε η επεξεργασία του κανόνα", +"message.edit.rule.processing" : "Ενημέρωση κανόνα...", +"message.edit.traffic.type" : "Καθορίστε την ετικέτα κίνησης που θέλετε να σχετίζεται με αυτόν τον τύπο κίνησης.", +"message.enable.account" : "Επιβεβαιώστε ότι θέλετε να ενεργοποιήσετε αυτόν το λογαριασμό.", +"message.enable.netsacler.provider.failed" : "απέτυχε η ενεργοποίηση της υπηρεσίας παροχής Netsccaler", +"message.enable.securitygroup.provider.failed" : "Απέτυχε η ενεργοποίηση της υπηρεσίας παροχής ομάδας ασφαλείας", +"message.enable.user" : "Επιβεβαιώστε ότι θέλετε να ενεργοποιήσετε αυτόν το χρήστη.", +"message.enable.vpn" : "Επιβεβαιώστε ότι θέλετε να είναι ενεργοποιημένο το VPN απομακρυσμένης πρόσβασης για αυτήν τη διεύθυνση IP.", +"message.enable.vpn.access" : "Το VPN είναι απενεργοποιημένο αυτήν τη στιγμή για αυτήν τη διεύθυνση IP. Θέλετε να ενεργοποιήσετε την πρόσβαση VPN;", +"message.enable.vpn.failed" : "Απέτυχε η ενεργοποίηση του VPN", +"message.enable.vpn.processing" : "Ενεργοποίηση VPN...", +"message.enabled.vpn" : "Το VPN απομακρυσμένης πρόσβασης είναι επί του παρόντος ενεργοποιημένο και είναι προσβάσιμο μέσω της", +"message.enabled.vpn.ip.sec" : "Το προ-κοινόχρηστο κλειδί IPSec είναι", +"message.enabled.vpn.note" : "Σημείωση: Οι χρήστες VPN μπορούν να παραμετροποιηθούν απο το μενού networks", +"message.enabling.network.offering" : "Ενεργοποίηση προσφοράς υπηρεσίας δικτύου", +"message.enabling.security.group.provider" : "Ενεργοποίηση της υπηρεσίας παροχής ομάδας ασφαλείας", +"message.enabling.vpc.offering" : "Ενεργοποίηση προσφοράς υπηρεσίας VPC", +"message.enabling.zone" : "Ενεργοποίηση ζώνης", +"message.enabling.zone.dots" : "Ενεργοποίηση ζώνης...", +"message.enter.seperated.list.multiple.cidrs" : "Εισαγάγετε μια λίστα CIDR διαχωρισμένων με κόμματα, εάν υπάρχουν περισσότερα από ένα", +"message.enter.token" : "Πληκτρολογήστε το διακριτικό που σας δόθηκε στο μήνυμα ηλεκτρονικού ταχυδρομείου πρόσκλησης.", +"message.error.access.key" : "Πληκτρολογήστε το κλειδί πρόσβασης", +"message.error.add.guest.network" : "Τα πεδία IPv4 ή τα πεδία IPv6 πρέπει να συμπληρωθούν κατά την προσθήκη ενός δικτύου επισκεπτών", +"message.error.add.secondary.ipaddress" : "Παρουσιάστηκε σφάλμα κατά την προσθήκη της δευτερεύουσας διεύθυνσης IP", +"message.error.agent.password" : "Πληκτρολογήστε τον κωδικό πρόσβασης του agent", +"message.error.agent.username" : "Πληκτρολογήστε το όνομα χρήστη του agent", +"message.error.binaries.iso.url" : "Πληκτρολογήστε δυαδικά αρχεία ISO URL", +"message.error.bucket" : "Παρακαλώ εισάγετε κάδο", +"message.error.cloudian.console" : "Η καθολική σύνδεση απέτυχε για την κονσόλα διαχείρισης cloudian. Ζητήστε από το διαχειριστή σας να διορθώσει προβλήματα ενοποίησης.", +"message.error.cluster.description" : "Πληκτρολογήστε την περιγραφή του ομοταξίας Kubernetes", +"message.error.cluster.name" : "Πληκτρολογήστε το όνομα του ομοταξίας", +"message.error.confirm.password" : "Επιβεβαιώστε τον νέο κωδικό πρόσβασης", +"message.error.current.password" : "Πληκτρολογήστε τον τρέχοντα κωδικό πρόσβασης", +"message.error.custom.disk.size" : "Πληκτρολογήστε προσαρμοσμένο μέγεθος δίσκου", +"message.error.date" : "Επιλέξτε μια ημερομηνία", +"message.error.description" : "Πληκτρολογήστε την περιγραφή", +"message.error.discovering.feature" : "Εντοπίστηκε εξαίρεση κατά τον εντοπισμό δυνατοτήτων", +"message.error.display.text" : "Πληκτρολογήστε εμφανιζόμενο κείμενο", +"message.error.domain" : "Εισάγετε τον τομέα σας, αφήστε κενό για τον τομέα ROOT", +"message.error.enable.saml" : "Δεν είναι δυνατή η εύρεση των id χρηστών για την ενεργοποίηση του Saml σύνδεση μιας φοράς, παρακαλούμε να το ενεργοποιήσετε με μη αυτόματο τρόπο.", +"message.error.endip" : "Πληκτρολογήστε End IP", +"message.error.gateway" : "Πληκτρολογήστε Πύλη", +"message.error.host.name" : "Πληκτρολογήστε το όνομα του κεντρικού υπολογιστή", +"message.error.host.password" : "Πληκτρολογήστε τον κωδικό πρόσβασης κεντρικού υπολογιστή", +"message.error.host.tags" : "Πληκτρολογήστε ετικέτες κεντρικού υπολογιστή", +"message.error.host.username" : "Πληκτρολογήστε το όνομα χρήστη του κεντρικού υπολογιστή", +"message.error.hypervisor.type" : "Επιλέξτε τύπο Hypervisor", +"message.error.input.value" : "Πληκτρολογήστε την τιμή", +"message.error.internal.dns1" : "Πληκτρολογήστε εσωτερικό DNS 1", +"message.error.internal.dns2" : "Πληκτρολογήστε Εσωτερικό DNS 2", +"message.error.internallb.instance.port" : "Καθορίστε μια θύρα εικονική μηχανής", +"message.error.internallb.name" : "Καθορίστε ένα όνομα για το εσωτερικό LB", +"message.error.internallb.source.port" : "Καθορίστε μια πηγαία θύρα", +"message.error.invalid.range" : "Εισαγάγετε τιμές από το 0 έως το 1", +"message.error.ip.range" : "Πληκτρολογήστε έγκυρο εύρος", +"message.error.ipv4.address" : "Πληκτρολογήστε μια έγκυρη διεύθυνση IPv4", +"message.error.ipv4.dns1" : "Πληκτρολογήστε IpV4 DNS 1", +"message.error.ipv4.dns2" : "Πληκτρολογήστε IpV4 DNS 2", +"message.error.ipv6.address" : "Πληκτρολογήστε μια έγκυρη διεύθυνση IP v6.", +"message.error.ipv6.cidr" : "Πληκτρολογήστε IpV6 CIDR", +"message.error.ipv6.dns1" : "Πληκτρολογήστε IpV6 DNS 1", +"message.error.ipv6.dns2" : "Πληκτρολογήστε IpV6 DNS 2", +"message.error.ipv6.gateway" : "Πληκτρολογήστε πύλη IpV6", +"message.error.ipv6.gateway.format" : "Πληκτρολογήστε μια έγκυρη πύλη IPv6.", +"message.error.kubecluster.name" : "Πληκτρολογήστε το όνομα ομοταξίας Kubernetes", +"message.error.kuberversion" : "Πληκτρολογήστε kubernetes σημασιολογική έκδοση", +"message.error.limit.value" : "Η τιμή δεν πρέπει να είναι μικρότερη από", +"message.error.loading.setting" : "Παρουσιάστηκε σφάλμα κατά τη φόρτωση αυτών των ρυθμίσεων.", +"message.error.lun" : "Πληκτρολογήστε LUN #", +"message.error.macaddress" : "Πληκτρολογήστε μια έγκυρη διεύθυνση MAC.", +"message.error.name" : "Πληκτρολογήστε το όνομα", +"message.error.netmask" : "Πληκτρολογήστε Netmask", +"message.error.network.domain" : "Πληκτρολογήστε τομέα δικτύου", +"message.error.network.offering" : "Επιλέξτε προσφορά δικτύου", +"message.error.new.password" : "Πληκτρολογήστε νέο κωδικό πρόσβασης", +"message.error.nexus1000v.ipaddess" : "Πληκτρολογήστε Nexus 1000v ΔΙΕΎΘΥΝΣΗ IP", +"message.error.nexus1000v.password" : "Παρακαλώ εισάγετε Nexus 1000v κωδικός πρόσβασης", +"message.error.nexus1000v.username" : "Παρακαλώ εισάγετε Nexus 1000v όνομα χρήστη", +"message.error.number" : "Πληκτρολογήστε έναν έγκυρο αριθμό", +"message.error.password" : "Πληκτρολογήστε τον κωδικό πρόσβασής σας", +"message.error.path" : "Πληκτρολογήστε διαδρομή", +"message.error.provide.setting" : "Πρέπει να παρέχει ένα έγκυρο κλειδί και τιμή για τη ρύθμιση", +"message.error.rados.monitor" : "Πληκτρολογήστε RADOS Monitor", +"message.error.rados.pool" : "Παρακαλώ εισάγετε rados πισίνα", +"message.error.rados.secret" : "Παρακαλώ εισάγετε RADOS Μυστικό", +"message.error.rados.user" : "Πληκτρολογήστε rados χρήστη", +"message.error.remove.nic" : "Παρουσιάστηκε σφάλμα", +"message.error.remove.secondary.ipaddress" : "Παρουσιάστηκε σφάλμα κατά την κατάργηση της δευτερεύουσας διεύθυνσης IP", +"message.error.required.input" : "Εισαγάγετε είσοδο", +"message.error.retrieve.kubeconfig" : "Δεν είναι δυνατή η ανάκτηση του ομοταξίας Kubernetes", +"message.error.s3nfs.path" : "Πληκτρολογήστε S3 NFS Path", +"message.error.s3nfs.server" : "Πληκτρολογήστε S3 NFS Server", +"message.error.save.setting" : "Παρουσιάστηκε σφάλμα κατά την αποθήκευση αυτής της ρύθμισης.", +"message.error.sbdomain" : "Πληκτρολογήστε τομέα SMB", +"message.error.sbdomain.password" : "Πληκτρολογήστε τον κωδικό πρόσβασης τομέα SMB", +"message.error.sbdomain.username" : "Πληκτρολογήστε όνομα χρήστη τομέα SMB", +"message.error.secret.key" : "Πληκτρολογήστε μυστικό κλειδί", +"message.error.select" : "Επιλέξτε την επιλογή", +"message.error.select.domain.to.dedicate" : "Επιλέξτε τομέα για να αφιερώσετε", +"message.error.select.zone.type" : "Επιλέξτε τον τύπο ζώνης παρακάτω.", +"message.error.server" : "Πληκτρολογήστε το διακομιστή", +"message.error.serviceoffering.for.cluster" : "Επιλέξτε την προσφορά υπηρεσιών για το σύμπλεγμα Kubernetes", +"message.error.size" : "Πληκτρολογήστε μέγεθος σε GB", +"message.error.size.for.cluster" : "Πληκτρολογήστε μέγεθος για το σύμπλεγμα Kubernetes", +"message.error.smb.password" : "Πληκτρολογήστε τον κωδικό πρόσβασης SMB", +"message.error.smb.username" : "Πληκτρολογήστε όνομα χρήστη SMB", +"message.error.specify.sticky.name" : "Καθορίστε ένα sticky όνομα", +"message.error.sr.namelabel" : "Πληκτρολογήστε όνομα-ετικέτα sr", +"message.error.startip" : "Πληκτρολογήστε IP Έναρξης ", +"message.error.storage.tags" : "Εισαγάγετε ετικέτες αποθήκευσης", +"message.error.target.iqn" : "Παρακαλώ εισάγετε IQN στόχου", +"message.error.time" : "Επιλέξτε ώρα", +"message.error.traffic.label" : "Πληκτρολογήστε ετικέτα κίνησης", +"message.error.try.save.setting" : "Παρουσιάστηκε σφάλμα κατά την αποθήκευση αυτής της ρύθμισης. Προσπαθήστε ξανά αργότερα.", +"message.error.upload.iso.description" : "Μόνο ένα ISO μπορεί να φορτωθεί κάθε φορά", +"message.error.upload.template" : "Η αποστολή του προτύπου απέτυχε", +"message.error.upload.template.description" : "Μόνο ένα πρότυπο μπορεί να αποσταλεί κάθε φορά", +"message.error.url" : "Πληκτρολογήστε διεύθυνση URL", +"message.error.username" : "Εισάγετε το όνομα χρήστη σας", +"message.error.vcenter.datacenter" : "Πληκτρολογήστε vCenter Datacenter", +"message.error.vcenter.datastore" : "Πληκτρολογήστε vCenter Datastore", +"message.error.vcenter.host" : "Πληκτρολογήστε vCenter Host", +"message.error.vcenter.password" : "Πληκτρολογήστε τον κωδικό πρόσβασης vCenter", +"message.error.vcenter.username" : "Πληκτρολογήστε όνομα χρήστη vCenter", +"message.error.version.for.cluster" : "Επιλέξτε την έκδοση Kubernetes για το σύμπλεγμα Kubernetes", +"message.error.vlan.range" : "Πληκτρολογήστε μια έγκυρη περιοχή VLAN/VNI", +"message.error.volume.name" : "Πληκτρολογήστε το όνομα τόμου", +"message.error.volumne" : "Πληκτρολογήστε Τόμος", +"message.error.volumne.group" : "Εισαγάγετε την ομάδα τόμων", +"message.error.zone" : "Επιλέξτε μια ζώνη", +"message.error.zone.combined" : "Όλες οι ζώνες δεν μπορούν να συνδυαστούν με οποιαδήποτε άλλη ζώνη", +"message.error.zone.for.cluster" : "Επιλέξτε ζώνη για σύμπλεγμα Kubernetes", +"message.error.zone.name" : "Πληκτρολογήστε το όνομα της ζώνης", +"message.error.zone.type" : "Επιλέξτε τύπο ζώνης", +"message.fail.to.delete" : "Απέτυχε η διαγραφή.", +"message.failed.to.add" : "Απέτυχε η προσθήκη", +"message.failed.to.assign.vms" : "Απέτυχε η αντιστοίχιση VM", +"message.failed.to.remove" : "Απέτυχε η κατάργηση", +"message.generate.keys" : "Επιβεβαιώστε ότι θέλετε να δημιουργήσετε νέα κλειδιά για αυτόν το χρήστη.", +"message.gslb.delete.confirm" : "Επιβεβαιώστε ότι θέλετε να διαγράψετε αυτό το GSLB", +"message.gslb.lb.remove.confirm" : "Επιβεβαιώστε ότι θέλετε να καταργήσετε την εξισορρόπηση φόρτου από το GSLB", +"message.guest.traffic.in.advanced.zone" : "Η κίνηση δικτύου επισκεπτών είναι η επικοινωνία μεταξύ εικονικών μηχανών τελικού χρήστη. Καθορίστε μια περιοχή των id VLAN για τη μεταφορά της κίνησης των επισκεπτών για κάθε φυσικό δίκτυο.", +"message.guest.traffic.in.basic.zone" : "Η κίνηση δικτύου επισκεπτών είναι η επικοινωνία μεταξύ εικονικών μηχανών τελικού χρήστη. Καθορίστε μια περιοχή διευθύνσεων IP που μπορεί να αντιστοιχίσει το CloudStack σε VM επισκέπτη. Βεβαιωθείτε ότι αυτή η περιοχή δεν επικαλύπτει την δεσμευμένη περιοχή IP του συστήματος.", +"message.guestnetwork.state.allocated" : "Υποδεικνύει ότι η ρύθμιση παραμέτρων δικτύου έχει εκχωρηθεί, αλλά δεν έχει ρυθμιστεί", +"message.guestnetwork.state.destroy" : "Υποδεικνύει ότι το δίκτυο έχει καταστραφεί", +"message.guestnetwork.state.implemented" : "Υποδεικνύει ότι η ρύθμιση παραμέτρων δικτύου χρησιμοποιείται", +"message.guestnetwork.state.implementing" : "Υποδεικνύει ότι η ρύθμιση παραμέτρων δικτύου υλοποιείται", +"message.guestnetwork.state.setup" : "Υποδεικνύει ότι η ρύθμιση παραμέτρων δικτύου έχει ρυθμιστεί", +"message.guestnetwork.state.shutdown" : "Υποδεικνύει ότι η ρύθμιση παραμέτρων δικτύου καταστρέφεται", +"message.host.dedicated" : "Ο κεντρικος υπολογιστής είναι αποκλειστικής διάθεσης", +"message.host.dedication.released" : "Η αποκλειστική διάθεση του κεντρικου υπολογιστή Αποδεσμεύτηκε", +"message.info.cloudian.console" : "Η κονσόλα διαχείρισης Cloudian πρέπει να ανοίξει σε άλλο παράθυρο", +"message.installwizard.click.retry" : "Κάντε κλικ στο κουμπί για να προσπαθήσετε ξανά να ξεκινήσετε.", +"message.installwizard.copy.whatisacluster" : "Ένα σύμπλεγμα παρέχει έναν τρόπο ομαδοποίησης κεντρικών υπολογιστών. Οι κεντρικοί υπολογιστές σε ένα σύμπλεγμα έχουν όλοι πανομοιότυπο υλικό, εκτελούν τον ίδιο Hypervisor, βρίσκονται στο ίδιο υποδίκτυο και έχουν πρόσβαση στον ίδιο κοινόχρηστο χώρο αποθήκευσης. Οι παρουσίες εικονικής μηχανής (VM) μπορούν να μετεγκατασταθούν ζωντανά από έναν κεντρικό υπολογιστή σε έναν άλλο μέσα στο ίδιο σύμπλεγμα, χωρίς να διακοπεί η υπηρεσία στο χρήστη. Ένα σύμπλεγμα είναι η τρίτη μεγαλύτερη οργανωτική μονάδα μέσα σε ένα CloudStack™. Ανάπτυξης. Οι συστάδες περιέχονται μέσα σε pods, και τα pods περιέχονται μέσα στις ζώνες.

CloudStack™; Επιτρέπει πολλά συμπλέγματα σε μια ανάπτυξη σύννεφο, αλλά για μια βασική εγκατάσταση, χρειαζόμαστε μόνο ένα σύμπλεγμα.", +"message.installwizard.copy.whatisahost" : "Ένας κεντρικός υπολογιστής είναι ένας μεμονωμένος υπολογιστής. Οι κεντρικοί υπολογιστές παρέχουν τους πόρους υπολογιστών που εκτελούν τις εικονικές μηχανές επισκεπτών. Κάθε κεντρικός υπολογιστής έχει το λογισμικό hypervisor εγκατεστημένο για να διαχειριστεί τα vms φιλοξενουμένων (εκτός από τους bare metal κεντρικούς υπολογιστές, οι οποίοι είναι μια πρόσθετη περίπτωση που συζητείται στον προηγμένο οδηγό εγκαταστάσεων). Για παράδειγμα, ένας διακομιστής με δυνατότητα Linux KVM, ένας διακομιστής Citrix XenServer και ένας διακομιστής ESXi είναι κεντρικοί υπολογιστές. Σε μια βασική εγκατάσταση, χρησιμοποιούμε έναν μόνο κεντρικό υπολογιστή που εκτελεί XenServer ή KVM.

Ο κεντρικός υπολογιστής είναι η μικρότερη οργανική μονάδα μέσα σε ένα CloudStack™. Ανάπτυξης. Οι κεντρικοί υπολογιστές περιέχονται σε συστοιχίες, οι συστοιχίες περιέχονται μέσα σε pods και τα pods περιέχονται σε ζώνες.", +"message.installwizard.copy.whatisapod" : "Ένα pod αντιπροσωπεύει συχνά ένα ενιαίο rack. Οι κεντρικοί υπολογιστές στο ίδιο pod είναι στο ίδιο υποδίκτυο.

Ένα pod είναι η δεύτερη μεγαλύτερη οργανωτική μονάδα μέσα σε μια εγκατάσταση CloudStack™. Τα pods περιέχονται σε ζώνες. Κάθε ζώνη μπορεί να περιέχει ένα ή περισσότερα pods? στη βασική εγκατάσταση, θα έχετε μόνο ένα pod στη ζώνη σας.", +"message.installwizard.copy.whatisazone" : "Μια ζώνη είναι η μεγαλύτερη οργανωτική μονάδα μέσα σε μια εγκατάσταση CloudStack™. Μια ζώνη συνήθως αντιστοιχεί σε ένα μόνο κέντρο δεδομένων, αν και επιτρέπεται να υπάρχουν πολλές ζώνες σε ένα κέντρο δεδομένων. Το όφελος της οργάνωσης των υποδομών σε ζώνες είναι η παροχή φυσικής απομόνωσης και πλεονασμού. Για παράδειγμα, κάθε ζώνη μπορεί να έχει τη δική της σύνδεση παροχής ενέργειας και δικτύου και οι ζώνες μπορούν να διαχωριστούν ευρέως γεωγραφικά (αν και αυτό δεν απαιτείται).", +"message.installwizard.copy.whatiscloudstack" : "Το CloudStack™ είναι μια πλατφόρμα λογισμικού που συγκεντρώνει υπολογιστικούς πόρους για τη δημιουργία δημόσιων, ιδιωτικών και υβριδικών υποδομων ως υπηρεσίας (IaaS) cloud. Το CloudStack™ διαχειρίζεται τους κόμβους δικτύου, αποθήκευσης και υπολογισμού που αποτελούν μια υποδομή cloud. Χρησιμοποιήστε το CloudStack™ για να αναπτύξετε, να διαχειριστείτε και να ρυθμίσετε τις παραμέτρους περιβαλλόντων Cloud.\n\nΤο CloudStack™ παρέχει μια στοίβα λογισμικού υποδομής cloud για την παροχή εικονικών κέντρων δεδομένων ως υπηρεσία - παρέχοντας όλα τα βασικά στοιχεία για τη δημιουργία, την ανάπτυξη και τη διαχείριση εφαρμογών cloud πολλαπλών επιπέδων και πολλών tenants. Και οι εκδόσεις ανοιχτού κώδικα και Premium είναι διαθέσιμες, με την έκδοση ανοιχτού κώδικα να προσφέρει σχεδόν πανομοιότυπα χαρακτηριστικά.", +"message.installwizard.copy.whatisprimarystorage" : "Μία CloudStack™; υποδομή χρησιμοποιεί δύο τύπους αποθηκευτικού χώρου. Πρωτεύον και Δευτερεύον. Και τα δύο μπορούν να είναι iSCSI ή NFS ή τοπικοί δίσκοι.ο

πρωτεύον αποθηκευτικός χώρος ορίζεται στις συστοιχίες (cluster) και αποθηκεύει τους τόμους δίσκων των εικονικών μηχανών (VM). Γι αυτό το σκοπό βρίσκεται κοντά στους διακομιστές", +"message.installwizard.copy.whatissecondarystorage" : "Ο δευτερεύον χώρος αποθήκευσης λειτουργεί με τις ζωνες και αποθηκεύει τα παρακάτω:

  • Πρότυπα - OS είδωλα που χρησμιποιούνται για την εκκίνηση των VMs και μπορούν να περιλαμβάνουν περεταίρω πληροφορίες όπως οι εγκατεστήμενες εφαρμογές
  • ISO είδωλα - OS images που μπορεί να είναι εκκινήσημα ή όχι
  • Στιγμιότυπα απο τόμους - αποθηκευμένα αντίγραφα που μπορούν να χρησιμοποιηθούν για ανάκτηση δεδομένων ή για την δημιουργία νέων προτύπων
", +"message.installwizard.now.building" : "Τώρα υλοποιείται το cloud σας ...", +"message.installwizard.tooltip.addcluster.name" : "Ένα όνομα για το σύμπλεγμα. Αυτό μπορεί να είναι κείμενο της επιλογής σας και δεν χρησιμοποιείται από το CloudStack.", +"message.installwizard.tooltip.addhost.hostname" : "Το όνομα DNS ή η διεύθυνση IP του κεντρικού υπολογιστή.", +"message.installwizard.tooltip.addhost.password" : "Αυτός είναι ο κωδικός πρόσβασης για το χρήστη που ονομάζεται παραπάνω (από την εγκατάσταση του XenServer).", +"message.installwizard.tooltip.addhost.username" : "Συνήθως root.", +"message.installwizard.tooltip.addpod.name" : "Ένα όνομα για το pod", +"message.installwizard.tooltip.addpod.reservedsystemendip" : "Αυτή είναι η περιοχή IP στο ιδιωτικό δίκτυο που χρησιμοποιεί το CloudStack για τη διαχείριση των VM δευτερεύουσας αποθήκευσης και των vm διακομιστή μεσολάβησης κονσόλας. Αυτές οι διευθύνσεις IP λαμβάνονται από το ίδιο υποδίκτυο με τους διακομιστές υπολογιστών.", +"message.installwizard.tooltip.addpod.reservedsystemgateway" : "Η πύλη για τους κεντρικους υπολογιστές σε αυτό το pod.", +"message.installwizard.tooltip.addpod.reservedsystemnetmask" : "Η μάσκα δικτύου που χρησιμοποιείται στο υποδίκτυο που θα χρησιμοποιήσουν οι επισκέπτες.", +"message.installwizard.tooltip.addpod.reservedsystemstartip" : "Αυτή είναι η περιοχή IP στο ιδιωτικό δίκτυο που χρησιμοποιεί το CloudStack για τη διαχείριση των VM δευτερεύουσας αποθήκευσης και των vm διακομιστή μεσολάβησης κονσόλας. Αυτές οι διευθύνσεις IP λαμβάνονται από το ίδιο υποδίκτυο με τους διακομιστές υπολογιστών.", +"message.installwizard.tooltip.addprimarystorage.name" : "Το όνομα της συσκευής αποθήκευσης.", +"message.installwizard.tooltip.addprimarystorage.path" : "(για NFS) Στο NFS αυτή είναι η διαδρομή που εξάγεται από το διακομιστή. Διαδρομή (για κοινόχρηστο σημείο). Με το KVM αυτή είναι η διαδρομή σε κάθε κεντρικό υπολογιστή που είναι το σημείο όπου έχει μονταριστεί αυτός ο κύριος χώρος αποθήκευσης. Για παράδειγμα, \"/mnt/primary\".", +"message.installwizard.tooltip.addprimarystorage.server" : "(για NFS, iSCSI ή προρύθμιση) Η διεύθυνση IP ή το όνομα DNS της συσκευής αποθήκευσης.", +"message.installwizard.tooltip.addsecondarystorage.nfsserver" : "Η διεύθυνση IP του διακομιστή NFS που φιλοξενεί τον δευτερεύοντα χώρο αποθήκευσης", +"message.installwizard.tooltip.addsecondarystorage.path" : "Η διαδρομή εξαγωγής, που βρίσκεται στο διακομιστή που καθορίσατε παραπάνω", +"message.installwizard.tooltip.addzone.dns1" : "Αυτοί είναι διακομιστές DNS για χρήση από vm επισκέπτη στη ζώνη. Αυτοί οι διακομιστές DNS θα προσεγγιστούν μέσω του δημόσιου δικτύου που θα προσθέσετε αργότερα. Οι δημόσιες διευθύνσεις IP για τη ζώνη πρέπει να έχουν μια διαδρομή προς το διακομιστή DNS που ονομάζεται εδώ.", +"message.installwizard.tooltip.addzone.dns2" : "Αυτοί είναι διακομιστές DNS για χρήση από vm επισκέπτη στη ζώνη. Αυτοί οι διακομιστές DNS θα προσεγγιστούν μέσω του δημόσιου δικτύου που θα προσθέσετε αργότερα. Οι δημόσιες διευθύνσεις IP για τη ζώνη πρέπει να έχουν μια διαδρομή προς το διακομιστή DNS που ονομάζεται εδώ.", +"message.installwizard.tooltip.addzone.internaldns1" : "Αυτοί είναι διακομιστές DNS για χρήση από vm συστήματος στη ζώνη. Αυτοί οι διακομιστές DNS θα προσεγγιστούν μέσω της ιδιωτικής διασύνδεσης δικτύου των VM συστήματος. Η ιδιωτική διεύθυνση IP που παρέχετε για τα pods πρέπει να έχει μια διαδρομή προς το διακομιστή DNS που ονομάζεται εδώ.", +"message.installwizard.tooltip.addzone.internaldns2" : "Αυτοί είναι διακομιστές DNS για χρήση από vm συστήματος στη ζώνη. Αυτοί οι διακομιστές DNS θα προσεγγιστούν μέσω της ιδιωτικής διασύνδεσης δικτύου των VM συστήματος. Η ιδιωτική διεύθυνση IP που παρέχετε για τα pods πρέπει να έχει μια διαδρομή προς το διακομιστή DNS που ονομάζεται εδώ.", +"message.installwizard.tooltip.addzone.name" : "Ένα όνομα για τη ζώνη", +"message.installwizard.tooltip.configureguesttraffic.description" : "Μια περιγραφή για το δίκτυό σας", +"message.installwizard.tooltip.configureguesttraffic.guestendip" : "Το εύρος των διευθύνσεων IP που θα είναι διαθέσιμες για εκχώρηση σε επισκέπτες σε αυτήν τη ζώνη. Εάν χρησιμοποιείται ένα NIC, αυτά τα IP θα πρέπει να είναι στο ίδιο CIDR με το pod CIDR.", +"message.installwizard.tooltip.configureguesttraffic.guestgateway" : "Η πύλη που πρέπει να χρησιμοποιούν οι επισκέπτες", +"message.installwizard.tooltip.configureguesttraffic.guestnetmask" : "Η μάσκα δικτύου που χρησιμοποιείται στο υποδίκτυο που πρέπει να χρησιμοποιούν οι επισκέπτες", +"message.installwizard.tooltip.configureguesttraffic.gueststartip" : "Το εύρος των διευθύνσεων IP που θα είναι διαθέσιμες για εκχώρηση σε επισκέπτες σε αυτήν τη ζώνη. Εάν χρησιμοποιείται ένα NIC, αυτά τα IP θα πρέπει να είναι στο ίδιο CIDR με το pod CIDR.", +"message.installwizard.tooltip.configureguesttraffic.name" : "Ένα όνομα για το δίκτυό σας", +"message.instance.scaled.up.confirm" : "Θέλετε πραγματικά να κλιμακώσετε την εικονική μηχανή σας;", +"message.instancewizard.notemplates" : "Δεν έχετε διαθέσιμα πρότυπα. Προσθέστε ένα συμβατό πρότυπο και ξεκινήστε ξανά τον οδηγό εικονική μηχανής.", +"message.interloadbalance.not.return.elementid" : "Σφάλμα, η εντολή listInternalLoadBalancerElements API δεν επέστρεψε δεδομένα Internal LB element Id", +"message.ip.address.changed" : "Οι διευθύνσεις IP σας μπορεί να έχουν αλλάξει. Θέλετε να ανανεώσετε την καταχώρηση; Σημειώστε ότι σε αυτήν την περίπτωση το παράθυρο λεπτομερειών θα κλείσει.", +"message.iso.desc" : "Εικόνα δίσκου που περιέχει δεδομένα ή μέσα με δυνατότητα εκκίνησης για λειτουργικό σύστημα", +"message.join.project" : "Τώρα έχετε συμμετάσχει σε ένα έργο. Μεταβείτε στην προβολή Project για να δείτε το έργο.", +"message.kubeconfig.cluster.not.available" : "To σύμπλεγμα Kubernetes kubeconfig δεν είναι διαθέσιμo προς το παρόν", +"message.kubernetes.cluster.delete" : "Επιβεβαιώστε ότι θέλετε να καταστρέψετε το σύμπλεγμα", +"message.kubernetes.cluster.scale" : "Επιλέξτε τη ρύθμιση παραμέτρων ομοταξίας που θέλετε", +"message.kubernetes.cluster.start" : "Επιβεβαιώστε ότι θέλετε να ξεκινήσετε το σύμπλεγμα", +"message.kubernetes.cluster.stop" : "Επιβεβαιώστε ότι θέλετε να διακόψετε το σύμπλεγμα", +"message.kubernetes.cluster.upgrade" : "Επιλέξτε νέα έκδοση Kubernetes", +"message.kubernetes.version.delete" : "Επιβεβαιώστε ότι θέλετε να διαγράψετε αυτήν την έκδοση Kubernetes", +"message.launch.vm.on.private.network" : "Θέλετε να ξεκινήσετε την εικονική μηχανή σας στο δικό σας ιδιωτικό αποκλειστικό δίκτυο;", +"message.launch.zone" : "Η ζώνη είναι έτοιμη για εκκίνηση. προχωρήστε στο επόμενο βήμα.", +"message.launch.zone.description" : "Η ζώνη είναι έτοιμη για εκκίνηση. προχωρήστε στο επόμενο βήμα.", +"message.launch.zone.hint" : "Ρύθμιση παραμέτρων στοιχείων δικτύου και κίνησης, συμπεριλαμβανομένων των διευθύνσεων IP.", +"message.ldap.group.import" : "Όλοι οι χρήστες από το συγκεκριμένο όνομα ομάδας θα εισαχθούν", +"message.license.agreements.not.accepted" : "Οι άδειες χρήσης δεν γίνονται δεκτές", +"message.link.domain.to.ldap" : "Ενεργοποίηση αυτόματου συγχρονισμού για αυτόν τον τομέα στο LDAP", +"message.listnsp.not.return.providerid" : "Σφάλμα: η εντολή listNetworkServiceProviders API δεν επέστρεψε δεδομένα VirtualRouter provider ID", +"message.listview.subselect.multi" : "(Ctrl/Cmd-κλικ)", +"message.load.host.failed" : "Απέτυχε η φόρτωση κεντρικών υπολογιστών", +"message.lock.account" : "Επιβεβαιώστε ότι θέλετε να κλειδώσετε αυτόν το λογαριασμό. Με το κλείδωμα του λογαριασμού, όλοι οι χρήστες για αυτόν το λογαριασμό δεν θα μπορούν πλέον να διαχειρίζονται τους πόρους cloud. Η πρόσβαση στους υπάρχοντες πόρους εξακολουθεί να είναι ανοιχτή.", +"message.login.failed" : "Η σύνδεση απέτυχε", +"message.migrate.instance.confirm" : "Επιβεβαιώστε τον κεντρικό υπολογιστή στον οποίο θέλετε να μετεγκαταστήσετε την εικονική εικονική μηχανή.", +"message.migrate.instance.select.host" : "Επιλέξτε έναν κεντρικό υπολογιστή για μετεγκατάσταση", +"message.migrate.instance.to.host" : "Επιβεβαιώστε ότι θέλετε να μετεγκαταστήσετε την εικονική μηχανή σε άλλο κεντρικό υπολογιστή.", +"message.migrate.instance.to.ps" : "Επιβεβαιώστε ότι θέλετε να μετεγκαταστήσετε την εικονική μηχανή σε άλλο πρωτεύοντα χώρο αποθήκευσης.", +"message.migrate.router.confirm" : "Επιβεβαιώστε ότι θέλετε να μετεγκαστήσετε τον δρομολογητή σε:", +"message.migrate.systemvm.confirm" : "Επιβεβαιώστε ότι θέλετε να μετεγκαστήσετε το συστημικό μηχάνημα σε:", +"message.migrate.lb.vm.to.ps" : "Επιβεβαιώστε ότι θέλετε να μετεγκαστήσετε το LB VM σε άλλον πρωτεύοντα χώρο", +"message.migrate.router.to.ps" : "Επιβεβαιώστε ότι θέλετε να μετεγκαστήσετε το δρομολογητή VM σε άλλον πρωτεύοντα χώρο", +"message.migrate.system.vm.to.ps" : "Επιβεβαιώστε ότι θέλετε να μετεγκαστήσετε το συστημικό VM σε άλλον πρωτεύοντα χώρο", +"message.migrate.volume" : "Επιβεβαιώστε ότι θέλετε να μετεγκαταστήσετε όγκο σε άλλο πρωτεύοντα χώρο αποθήκευσης.", +"message.migrate.volume.failed" : "Η μετεγκατάσταση τόμου απέτυχε", +"message.migrate.volume.processing" : "Μετεγκατάσταση τόμου...", +"message.migrating.failed" : "Η μετεγκατάσταση απέτυχε", +"message.migrating.processing" : "Η μετανάστευση σε εξέλιξη για", +"message.migrating.vm.to.host.failed" : "Απέτυχε η μετεγκατάσταση της εικονικής μηχανής στον κεντρικό υπολογιστή", +"message.migrating.vm.to.storage.failed" : "Αποτυχία μετεγκατάστσης VM στον πρωτεύοντα χώρο", +"message.move.acl.order" : "Μετακίνηση σειράς κανόνων ACL", +"message.move.acl.order.failed" : "Απέτυχε η μετακίνηση του κανόνα ACL", +"message.move.acl.order.processing" : "Μετακίνηση κανόνα ACL...", +"message.ncc.delete.confirm" : "Επιβεβαιώστε ότι θέλετε να διαγράψετε αυτό το NCC", +"message.network.acl.default.allow" : "Προσοχή: Με την παρούσα πολιτική όλη η κίνηση διαμέσου του τοίχους ασφαλείας θα επιτραπεί για αυτό το VPC tier. Πρέπει να ασφαλίσεται το δίκτυο σας.", +"message.network.acl.default.deny" : "Προσοχή: Με την παρούσα πολιτική όλη η κίνηση διαμέσου του τοίχους ασφαλείας θα απαγορευτεί για αυτό το VPC tier. Για να επιτρέψετε την επικοινωνία θα πρέπει να αλλάξετε πολιτική.", +"message.network.addvm.desc" : "Καθορίστε το δίκτυο στο οποίο θέλετε να προσθέσετε αυτήν την εικονική μηχανή. Θα προστεθεί μια νέα nic για αυτό το δίκτυο.", +"message.network.addvmnic" : "Επιβεβαιώστε ότι θέλετε να προσθέσετε ένα νέο NIC VM για αυτό το δίκτυο.", +"message.network.description" : "Δίκτυο εγκατάστασης και κίνηση", +"message.network.error" : "Σφάλμα δικτύου", +"message.network.error.description" : "Δεν είναι δυνατή η πρόσβαση στο διακομιστή διαχείρισης ή μια επέκταση προγράμματος περιήγησης ενδέχεται να αποκλείει την αίτηση δικτύου.", +"message.network.hint" : "Ρύθμιση παραμέτρων στοιχείων δικτύου και της δημόσιας/guest/διαχείρισης της κίνησης, συμπεριλαμβανομένων των διευθύνσεων IP.", +"message.network.remote.access.vpn.configuration" : "Δημιουργήθηκε ρύθμιση παραμέτρων VPN απομακρυσμένης πρόσβασης, αλλά απέτυχε να εφαρμοστεί. Ελέγξτε τη σύνδεση του στοιχείου δικτύου και, στη συνέχεια, προσπαθήστε ξανά.", +"message.network.removenic" : "Επιβεβαιώστε ότι θέλετε να καταργήσετε αυτό το NIC, το οποίο θα καταργήσει επίσης το συσχετισμένο δίκτυο από την εικονική μηχανή.", +"message.network.secondaryip" : "Επιβεβαιώστε ότι θέλετε να αντιστοιχήσετε δευτερεύουσα IP σε αυτήν την κάρτα δικτύου.\n Σημείωση: Θα πρέπει να ρυθμίσετε μέσα στην εικονική μηχανή την διαθέσιμη IP χειροκίνητα.", +"message.network.updateip" : "Επιβεβαιώστε ότι θέλετε να αλλάξετε τη διεύθυνση IP για αυτό το NIC σε VM.", +"message.new.user" : "Καθορίστε τα ακόλουθα για να προσθέσετε ένα νέο χρήστη στο λογαριασμό", +"message.no.affinity.groups" : "Δεν έχετε καμία ομάδα συνάφειας. Συνεχίστε στο επόμενο βήμα.", +"message.no.datadisk" : "Το πρότυπο πολλαπλών δίσκων δεν έχει δίσκο δεδομένων, συνεχίστε στο επόμενο βήμα.", +"message.no.description" : "Δεν έχει εισαχθεί περιγραφή.", +"message.no.host.available" : "Δεν υπάρχουν διαθέσιμοι κεντρικοί υπολογιστές για μετεγκατάσταση", +"message.no.label.on.left" : "Δεν υπάρχει ετικέτα στα αριστερά", +"message.no.label.on.right" : "Δεν υπάρχει ετικέτα στα δεξιά", +"message.no.more.hosts.available" : "Δεν υπάρχουν άλλοι διαθέσιμοι κεντρικοί υπολογιστές για μετεγκατάσταση", +"message.no.network.support" : "Ο επιλεγμένος Hypervisorς σας, vSphere, δεν έχει πρόσθετες δυνατότητες δικτύου. Συνεχίστε με το βήμα 5.", +"message.no.network.support.configuration.not.true" : "Δεν έχετε καμία ζώνη που να έχει ενεργοποιημένη την ομάδα ασφαλείας. Έτσι, δεν υπάρχουν πρόσθετες δυνατότητες δικτύου. Συνεχίστε με το βήμα 5.", +"message.no.primary.stores" : "Δεν υπάρχουν διαθέσιμοι χώροι αποθήκευσης πρωτεύοντος χώρου αποθήκευσης για μετεγκατάσταση", +"message.no.projects" : "Δεν έχετε κανένα εργο.
Δημιουργήστε ένα νέο από την ενότητα έργων.", +"message.no.projects.adminonly" : "Δεν έχετε κανένα εργο.
Ζητήστε από το διαχειριστή σας να δημιουργήσει ένα νέο έργο.", +"message.number.clusters" : "

# του Συμπλέγματα

", +"message.number.hosts" : "

# του Κεντρικοί υπολογιστές

", +"message.number.pods" : "

# του pod

", +"message.number.storage" : "

# του Τόμοι πρωτεύοντος χώρου αποθήκευσης

", +"message.number.zones" : "

# του Ζώνες

", +"message.outofbandmanagement.action.maintenance" : "Ο κεντρικός υπολογιστής ειδοποιήσεων βρίσκεται σε λειτουργία συντήρησης", +"message.ovf.configurations" : "Διαθέσιμες διαμορφώσεις OVF για την επιλεγμένη συσκευή. Επιλέξτε την επιθυμητή τιμή. Οι μη συμβατές προσφορές υπηρεσίας υπολογισμού θα αποσυντεθεί.", +"message.ovf.properties.available" : "Υπάρχουν διαθέσιμες ιδιότητες OVF για την προσαρμογή της επιλεγμένης συσκευής. Επεξεργαστείτε τις τιμές ανάλογα.", +"message.password.has.been.reset.to" : "Έγινε επαναφορά του κωδικού πρόσβασης σε", +"message.password.of.the.vm.has.been.reset.to" : "Ο κωδικός πρόσβασης της εικονικής μηχανής επαναπροσδιορίστηκε σε", +"message.path.description" : "NFS: η εξαχθ΄είσα διαδρομή απο τον διακομιστή. VMFS: /datacenter name/datastore name. SharedMountPoint: Διαδρομή που βρίσκεται ο πρωτεύον αποθηκευτικός χώρος, παράδειγμα /mnt/primary", +"message.pending.projects.1" : "Έχετε εκκρεμή πρόσκληση για έργο", +"message.pending.projects.2" : "Για να προβάλετε, μεταβείτε στην ενότητα έργα και, στη συνέχεια, επιλέξτε προσκλήσεις από το πτυσσόμενο μενού.", +"message.please.add.at.lease.one.traffic.range" : "Προσθέστε τουλάχιστον ένα εύρος κίνησης.", +"message.please.confirm.remove.ssh.key.pair" : "Επιβεβαιώστε ότι θέλετε να καταργήσετε αυτό το ζεύγος κλειδιών SSH", +"message.please.enter.value" : "Πληκτρολογήστε τιμές", +"message.please.proceed" : "Προχωρήστε στο επόμενο βήμα.", +"message.please.select.a.configuration.for.your.zone" : "Επιλέξτε μια ρύθμιση παραμέτρων για τη ζώνη σας.", +"message.please.select.a.different.public.and.management.network.before.removing" : "Επιλέξτε ένα διαφορετικό δημόσιο δίκτυο και δίκτυο διαχείρισης πριν από την κατάργηση", +"message.please.select.networks" : "Επιλέξτε δίκτυα για την εικονική μηχανή σας.", +"message.please.select.ssh.key.pair.use.with.this.vm" : "Επιλέξτε ένα ζεύγος SSH για να χρησμοποιηθεί στην εικονική μηχανή", +"message.please.wait.while.zone.is.being.created" : "Περιμένετε όσο δημιουργείται η ζώνη σας. αυτό μπορεί να πάρει λίγο χρόνο ...", +"message.pod.dedicated" : "Pod αποκλειστικής χρήσης", +"message.pod.dedication.released" : "Η αποκλειστική δεσμευση το Pod Αποδεσμεύτηκε", +"message.portable.ip.delete.confirm" : "Επιβεβαιώστε ότι θέλετε να διαγράψετε το φορητό εύρος IP", +"message.processing.complete" : "Η επεξεργασία ολοκληρώθηκε!", +"message.protocol.description" : "Για XenServer, επιλέξτε NFS, iSCSI, or PreSetup. Για KVM, επιλέξτε NFS, SharedMountPoint, RDB, CLVM or Gluster. Για vSphere, επιλέξτε NFS, PreSetup (VMFS or iSCSI or FiberChannel or vSAN or vVols) or DatastoreCluster. Για Hyper-V, επιλέξτε SMB/CIFS. Για LXC, επιλέξτε NFS or SharedMountPoint. Για OVM, επιλέξτε NFS or ocfs2.", +"message.project.invite.sent" : "Πρόσκληση που στάλθηκε στο χρήστη. θα προστεθούν στο έργο μόλις αποδεχθούν την πρόσκληση", +"message.public.traffic.in.advanced.zone" : "Η δημόσια κίνηση δημιουργείται όταν τα VM στο cloud αποκτούν πρόσβαση στο Internet. Για το σκοπό αυτό, πρέπει να διατίθενται οι IPs που είναι διαθέσιμες στο κοινό. Οι τελικοί χρήστες μπορούν να χρησιμοποιήσουν το περιβάλλον εργασίας χρήστη CloudStack για να αποκτήσουν αυτές τις υπηρεσίες IP για την υλοποίηση του NAT μεταξύ του δικτύου επισκεπτών τους και του δημόσιου δικτύου τους.

Παρέχετε τουλάχιστον μία σειρά διευθύνσεων IP για την κίνηση στο διαδίκτυο.", +"message.public.traffic.in.basic.zone" : "Η δημόσια κίνηση δημιουργείται όταν τα VM στο cloud αποκτούν πρόσβαση στο Internet ή παρέχουν υπηρεσίες σε υπολογιστές-πελάτες μέσω του Internet. Για το σκοπό αυτό, πρέπει να διατίθενται δημόσια προσβάσιμες IPs. Όταν δημιουργείται μια εικονική μηχανή, μια διεύθυνση IP από αυτό το σύνολο δημόσιων IP θα εκχωρηθεί στην εικονική μηχανή εκτός από τη διεύθυνση IP του επισκέπτη. Στατική 1-1 NAT θα ρυθμιστεί αυτόματα μεταξύ της δημόσιας IP και του επισκέπτη IP. Οι τελικοί χρήστες μπορούν επίσης να χρησιμοποιήσουν το περιβάλλον εργασίας χρήστη CloudStack για να αποκτήσουν πρόσθετες διευθύνσεις IP για την υλοποίηση στατικού NAT μεταξύ των περιστάσεων τους και της δημόσιας διεύθυνσης IP.", +"message.publicip.state.allocated" : "η διεύθυνση IP χρησιμοποιείται .", +"message.publicip.state.allocating" : "Η διεύθυνση IP μεταδίδεται σε άλλα στοιχεία δικτύου και δεν είναι ακόμα έτοιμη για χρήση.", +"message.publicip.state.free" : "Η διεύθυνση IP είναι έτοιμη να εκχωρηθεί.", +"message.publicip.state.releasing" : "Η διεύθυνση IP αποδεσμεύεται για άλλα στοιχεία δικτύου και δεν είναι έτοιμη για εκχώρηση.", +"message.question.are.you.sure.you.want.to.add" : "Είστε βέβαιοι ότι θέλετε να προσθέσετε", +"message.read.accept.license.agreements" : "Παρακαλούμε διαβάστε και αποδεχτείτε τους όρους για τις άδειες χρήσης.", +"message.read.admin.guide.scaling.up" : "Διαβάστε την ενότητα δυναμικής κλιμάκωσης στον οδηγό διαχείρισης πριν από την κλιμάκωση.", +"message.recover.vm" : "Επιβεβαιώστε ότι θέλετε να ανακτήσετε αυτό το VM.", +"message.redirecting.region" : "Ανακατεύθυνση στην περιοχή...", +"message.register.failed" : "Η δήλωση απέτυχε", +"message.register.succeeded" : "Η εγγραφή ολοκληρώθηκε με επιτυχία", +"message.reinstall.vm" : "Σημείωση: Προχωρήστε με επιφύλαξη. Η εργασία αυτή θα προκαλέσει επανεγκατάσταση της εικονικής μηχανής απο το πρότυπο. Όλα τα δεδομένα στον κύριο δίσκο θα χαθούν. Αν υπάρχουν δευτερεύοντες δίσκοι θα παραμείνουν άθικτοι", +"message.release.ip.failed" : "Απέτυχε η αποδέσμευση της IP", +"message.releasing.dedicated.cluster" : "Αποδέσμευση αποκλειστικού ομοταξίας...", +"message.releasing.dedicated.host" : "Αποδέσμευση αποκλειστικού κεντρικού υπολογιστή...", +"message.releasing.dedicated.pod" : "Αποδέσμευση αποκλειστικού pod ...", +"message.releasing.dedicated.zone" : "Αποδέσμευση αποκλειστικής ζώνης...", +"message.remove.egress.rule.failed" : "Η κατάργηση του κανόνα εξόδου απέτυχε", +"message.remove.egress.rule.processing" : "Διαγραφή κανόνα εξόδου...", +"message.remove.failed" : "Η κατάργηση απέτυχε", +"message.remove.firewall.rule.failed" : "Η κατάργηση του κανόνα τείχους προστασίας απέτυχε", +"message.remove.firewall.rule.processing" : "Διαγραφή κανόνα τείχους προστασίας...", +"message.remove.instance.failed" : "Απέτυχε η κατάργηση της εικονική μηχανής", +"message.remove.instance.processing" : "Αφαίρεση...", +"message.remove.iprange.processing" : "Κατάργηση περιοχής IP...", +"message.remove.ldap" : "Είστε βέβαιοι ότι θέλετε να διαγράψετε τη ρύθμιση παραμέτρων LDAP;", +"message.remove.nic.processing" : "Κατάργηση nic...", +"message.remove.port.forward.failed" : "Η κατάργηση του κανόνα προώθησης θυρών απέτυχε", +"message.remove.region" : "Είστε βέβαιοι ότι θέλετε να καταργήσετε αυτήν την περιοχή από αυτόν το διακομιστή διαχείρισης;", +"message.remove.rule.failed" : "Απέτυχε η διαγραφή του κανόνα", +"message.remove.secondary.ipaddress.processing" : "Κατάργηση δευτερεύουσας διεύθυνσης IP...", +"message.remove.securitygroup.rule.processing" : "Διαγραφή κανόνα ομάδας ασφαλείας...", +"message.remove.sticky.policy.failed" : "Απέτυχε η κατάργηση της sticky πολιτικής", +"message.remove.sticky.policy.processing" : "Κατάργηση sticky πολιτικής...", +"message.remove.vpc" : "Επιβεβαιώστε ότι θέλετε να καταργήσετε το VPC", +"message.remove.vpn.access" : "Επιβεβαιώστε ότι θέλετε να καταργήσετε την πρόσβαση VPN από τον ακόλουθο χρήστη.", +"message.removed.ssh.key.pair" : "Καταργήθηκε ένα ζεύγος κλειδιών SSH", +"message.request.failed" : "Η αίτηση απέτυχε", +"message.required.add.least.ip" : "Προσθέστε τουλάχιστον 1 εύρος IP", +"message.required.traffic.type" : "Σφάλμα στη ρύθμιση παραμέτρων! Όλοι οι απαιτούμενοι τύποι κίνησης θα πρέπει να προστίθενται και με πολλαπλά φυσικά δίκτυα κάθε δίκτυο θα πρέπει να έχει ετικέτα.", +"message.reset.password.warning.notpasswordenabled" : "Το πρότυπο αυτής της εικονική μηχανής δημιουργήθηκε χωρίς να ενεργοποιηθεί ο κωδικός πρόσβασης", +"message.reset.password.warning.notstopped" : "Η εικονική μηχανή σας πρέπει να διακοπεί πριν επιχειρήσετε να αλλάξετε τον τρέχοντα κωδικό πρόσβασής της", +"message.reset.vpn.connection" : "Επιβεβαιώστε ότι θέλετε να επαναφέρετε τη σύνδεση VPN", +"message.resize.volume.failed" : "Απέτυχε η αλλαγή μεγέθους του τόμου", +"message.resource.not.found" : "Ο πόρος δεν βρέθηκε", +"message.restart.mgmt.server" : "Επανεκκινήστε τους διακομιστές διαχείρισης για να τεθούν σε ισχύ οι νέες ρυθμίσεις σας.", +"message.restart.mgmt.usage.server" : "Επανεκκινήστε τους διακομιστές διαχείρισης και τους διακομιστές χρήσης για να τεθούν σε ισχύ οι νέες ρυθμίσεις σας.", +"message.restart.network" : "Όλες οι υπηρεσίες που παρέχονται από αυτό το δίκτυο θα διακοπεί. Επιβεβαιώστε ότι θέλετε να επανεκκινήσετε αυτό το δίκτυο.", +"message.restart.vpc" : "Επιβεβαιώστε ότι θέλετε να επανεκκινήσετε το VPC", +"message.restart.vpc.remark" : "Επιβεβαιώστε ότι θέλετε να επανεκκινήσετε το VPC

Παρατήρηση: Αν κάνετε ένα απλο VPC πλεονάζον τα δεδομένα του θα καθαριστούν. Τα δίκτυα δεν θα είναι διαθέσιμα για κάποια λεπτά.

", +"message.restorevm" : "Θέλετε να επαναφέρετε την εικονική μηχανή;", +"message.role.ordering.fail" : "Η αναδιάταξη των δικαιωμάτων κανόνων ματαιώθηκε καθώς η λίστα έχει αλλάξει κατά την πραγματοποίηση αλλαγών. Προσπαθήστε ξανά.", +"message.role.update.fail" : "Απέτυχε η ενημέρωση του δικαιώματος κανόνα", +"message.scale.processing" : "Κλίμακα σε εξέλιξη", +"message.security.group.usage" : "(Χρησιμοποιήστε το πλήκτρο Ctrl-κλικ για να επιλέξετε όλες τις ισχύουσες ομάδες ασφαλείας)", +"message.select.a.zone" : "Μια ζώνη αντιστοιχεί συνήθως σε ένα μόνο κέντρο δεδομένων. Πολλές ζώνες συμβάλλουν στο να γίνει το cloud πιο αξιόπιστο, παρέχοντας φυσική απομόνωση και πλεονασμό.", +"message.select.affinity.groups" : "Επιλέξτε τις ομάδες συνάφειας που θέλετε αυτό το VM να ανήκει", +"message.select.destination.image.stores" : "Επιλέξτε Χώρους αποθήκευσης εικόνων στους οποίους πρόκειται να μετεγκατασταθούν δεδομένα", +"message.select.instance" : "Επιλέξτε μια εικονική μηχανή.", +"message.select.iso" : "Επιλέξτε ένα ISO για τη νέα εικονική εικονική μηχανή σας.", +"message.select.item" : "Επιλέξτε ένα στοιχείο.", +"message.select.migration.policy" : "Επιλέξτε μια πολιτική μετεγκατάστασης", +"message.select.security.groups" : "Επιλέξτε ομάδες ασφαλείας για τη νέα εικονική μηχανή", +"message.select.template" : "Επιλέξτε ένα πρότυπο για τη νέα εικονική εικονική μηχανή σας.", +"message.select.tier" : "Επιλέξτε ένα επίπεδο", +"message.select.zone.description" : "Επιλογή τύπου ζώνης βασικής/προηγμένης", +"message.select.zone.hint" : "Αυτοί είναι οι τύποι ζώνης που μπορείται να χρησμοποιήσετε. Βασική ζώνη: Υποστηρίζει ένα δίκτυο όπου όλες οι εικονικές μηχανές λαμβάνουν IPs απο το δίκτυο. Η απομόνηση των μηχανημάτων παρέχεται μέσω μηχανισμών layer-3 όπως είναι τα security groups (IP address source filtering). Ζώνη για προχωρημένους: H Ζώνη αυτή χρησιμοποιείται για πολύπλοκες τοπολογίες. Διαθέσιμες υπηρεσίες που παρέχονται είναι τείχος προστασίας, VPN, load balancing", +"message.server.description" : "NFS, iSCSI, or PreSetup: Διεύθυνση IP ή όνομα DNS της συσκευής αποθήκευσης. VMware PreSetup: Διεύθυνση IP ή όνομα DNS του vCenter διακομιστή.", +"message.set.default.nic" : "Επιβεβαιώστε ότι θέλετε να κάνετε αυτό το NIC προεπιλογή για αυτήν την εικονική μηχανή.", +"message.set.default.nic.manual" : "Ενημερώστε τώρα με μη αυτόματο τρόπο το προεπιλεγμένο NIC στην εικονική μηχανή.", +"message.setting.updated" : "Θέση αναβάθμισης:", +"message.setup.physical.network.during.zone.creation" : "Όταν προσθέτετε μια ζώνη, πρέπει να ρυθμίσετε ένα ή περισσότερα φυσικά δίκτυα. Κάθε δίκτυο αντιστοιχεί σε ένα NIC στον Hypervisor. Κάθε φυσικό δίκτυο μπορεί να μεταφέρει έναν ή περισσότερους τύπους κίνησης, με ορισμένους περιορισμούς στον τρόπο με τον οποίο μπορούν να συνδυαστούν. Προσθέστε ή καταργήστε έναν ή περισσότερους τύπους κίνησης σε κάθε φυσικό δίκτυο.", +"message.setup.physical.network.during.zone.creation.basic" : "Όταν προσθέτετε μια βασική ζώνη, μπορείτε να ρυθμίσετε ένα φυσικό δίκτυο, το οποίο αντιστοιχεί σε ένα NIC στον Hypervisor. Το δίκτυο μεταφέρει διάφορους τύπους κίνησης.

Μπορείτε επίσης να προσθέσετε άλλους τύπους κίνησης στο φυσικό δίκτυο.", +"message.setup.successful" : "Cloud setup επιτυχής!", +"message.specifiy.tag.key" : "Καθορίστε ένα κλειδί ετικέτας", +"message.specifiy.tag.key.value" : "Καθορίστε ένα κλειδί ετικέτας και μια τιμή", +"message.specifiy.tag.value" : "Καθορίστε μια τιμή ετικέτας", +"message.specify.url" : "Καθορίστε τη διεύθυνση URL", +"message.step.1.desc" : "Επιλέξτε ένα πρότυπο για τη νέα εικονική εικονική μηχανή σας. Μπορείτε επίσης να επιλέξετε ένα κενό πρότυπο από το οποίο μπορεί να εγκατασταθεί μια εικόνα ISO.", +"message.step.2.continue" : "Επιλέξτε μια προσφορά υπηρεσιών για να συνεχίσετε", +"message.step.3.continue" : "Επιλέξτε μια προσφορά δίσκου για να συνεχίσετε", +"message.step.4.continue" : "Επιλέξτε τουλάχιστον ένα δίκτυο για να συνεχίσετε", +"message.step.4.desc" : "Επιλέξτε το πρωτεύον δίκτυο με το οποίο θα συνδεθεί η εικονική εικονική μηχανή σας.", +"message.step.license.agreements.continue" : "Παρακαλούμε αποδεχτείτε όλες τις συμφωνίες άδειας χρήσης για να συνεχίσετε", +"message.storage.traffic" : "Η κίνηση μεταξύ των εσωτερικών πόρων του CloudStack, συμπεριλαμβανομένων τυχόν στοιχείων που επικοινωνούν με το διακομιστή διαχείρισης, όπως οι κεντρικοί υπολογιστές και οι VM του συστήματος CloudStack. Ρυθμίστε εδώ τις παραμέτρους της κίνησης αποθήκευσης.", +"message.success.acquire.ip" : "Επιτυχής απόκτηση IP", +"message.success.add.egress.rule" : "Προστέθηκε με επιτυχία νέος κανόνας εξόδου", +"message.success.add.firewall.rule" : "Προστέθηκε με επιτυχία νέος κανόνας τείχους προστασίας", +"message.success.add.guest.network" : "Δημιουργήθηκε με επιτυχία το δίκτυο επισκεπτών", +"message.success.add.iprange" : "Προστέθηκε με επιτυχία εύρος IP", +"message.success.add.kuberversion" : "Προστέθηκε με επιτυχία η έκδοση kubernetes", +"message.success.add.network" : "Προστέθηκε με επιτυχία το δίκτυο", +"message.success.add.network.acl" : "Προστέθηκε με επιτυχία η λίστα ACL δικτύου", +"message.success.add.port.forward" : "Προστέθηκε με επιτυχία ο νέος κανόνας προώθησης θυρών", +"message.success.add.private.gateway" : "Προστέθηκε με επιτυχία ιδιωτική πύλη", +"message.success.add.rule" : "Προστέθηκε με επιτυχία νέος κανόνας", +"message.success.add.secondary.ipaddress" : "Προστέθηκε με επιτυχία δευτερεύουσα διεύθυνση IP", +"message.success.add.static.route" : "Προστέθηκε με επιτυχία στατική διαδρομή", +"message.success.add.tag" : "Προστέθηκε με επιτυχία νέα ετικέτα", +"message.success.add.vpc.network" : "Προστέθηκε με επιτυχία δίκτυο VPC", +"message.success.add.vpn.customer.gateway" : "Προστέθηκε με επιτυχία πύλη πελάτη VPN", +"message.success.add.vpn.gateway" : "Προστέθηκε με επιτυχία πύλη VPN", +"message.success.asign.vm" : "Η εικονική μηχανή που εκχωρήθηκαν με επιτυχία ολοκληρώθηκε με επιτυχία", +"message.success.assigned.vms" : "Η αντιστοίχιση VM ολοκληρώθηκε με επιτυχία", +"message.success.certificate.upload" : "Η αποστολή του πιστοποιητικού ολοκληρώθηκε με επιτυχία", +"message.success.change.affinity.group" : "Η αλλαγή ομάδων συνάφειας ολοκληρώθηκε με επιτυχία", +"message.success.change.offering" : "Η προσφορά άλλαξε με επιτυχία", +"message.success.change.password" : "Ο κωδικός πρόσβασης που άλλαξε με επιτυχία για το χρήστη", +"message.success.config.backup.schedule" : "Ρύθμιση παραμέτρων χρονοδιαγράμματος δημιουργίας αντιγράφων ασφαλείας VM", +"message.success.config.sticky.policy" : "Η ρύθμιση παραμέτρων της πολιτικής κολλώδους ολοκληρώθηκε με επιτυχία", +"message.success.copy.clipboard" : "Η αντιγραφή ολοκληρώθηκε με επιτυχία στο Πρόχειρο", +"message.success.create.account" : "Λογαριασμός που δημιουργήθηκε με επιτυχία", +"message.success.create.internallb" : "Η εσωτερική lb ολοκληρώθηκε με επιτυχία", +"message.success.create.isolated.network" : "Δημιουργήθηκε με επιτυχία απομονωμένο δίκτυο", +"message.success.create.keypair" : "Δημιουργήθηκε με επιτυχία ζεύγος κλειδιών SSH", +"message.success.create.kubernetes.cluter" : "Δημιουργήθηκε με επιτυχία το σύμπλεγμα Kubernetes", +"message.success.create.l2.network" : "Δημιουργήθηκε με επιτυχία το δίκτυο L2", +"message.success.create.snapshot.from.vmsnapshot" : "Επιτυχής δημιουργία στιγμιότυπου από στιγμιότυπο VM", +"message.success.create.user" : "Ο χρήστης δημιουργήθηκε με επιτυχία", +"message.success.create.volume" : "Ο τόμος δημιουργήθηκε με επιτυχία", +"message.success.delete" : "Διαγραφή επιτυχίας", +"message.success.delete.acl.rule" : "Η κατάργηση του κανόνα ACL ολοκληρώθηκε με επιτυχία", +"message.success.delete.backup.schedule" : "Η διαγραφή του ολοκληρώθηκε με επιτυχία Ρύθμιση παραμέτρων χρονοδιαγράμματος δημιουργίας αντιγράφων ασφαλείας VM", +"message.success.delete.snapshot.policy" : "Η πολιτική στιγμιότυπων διαγράφηκε με επιτυχία", +"message.success.delete.static.route" : "Η διαγραφή της στατικής διαδρομής ολοκληρώθηκε με επιτυχία", +"message.success.delete.tag" : "Η ετικέτα διαγράφηκε με επιτυχία", +"message.success.delete.vm" : "Η εικονική μηχανή διαγράφηκε με επιτυχία", +"message.success.disable.saml.auth" : "Η εξουσιοδότηση SAML απενεργοποιήθηκε με επιτυχία", +"message.success.disable.vpn" : "Επιτυχής απενεργοποίηση vpn", +"message.success.edit.acl" : "Η επεξεργασία του κανόνα ACL ολοκληρώθηκε με επιτυχία", +"message.success.edit.rule" : "Επιτυχής επεξεργασία κανόνα", +"message.success.enable.saml.auth" : "Η εξουσιοδότηση SAML ενεργοποιήθηκε με επιτυχία", +"message.success.migrate.volume" : "Επιτυχής μετεγκατάσταση τόμου", +"message.success.migrating" : "Η μετεγκατάσταση ολοκληρώθηκε με επιτυχία για", +"message.success.move.acl.order" : "Η μετακίνηση του κανόνα ACL ολοκληρώθηκε με επιτυχία", +"message.success.recurring.snapshot" : "Επιτυχής επανάληψη στιγμιότυπα", +"message.success.register.iso" : "Επιτυχής καταχώρηση του ISO", +"message.success.register.keypair" : "Επιτυχής καταχώρηση ζεύγους κλειδιών SSH", +"message.success.register.template" : "Ολοκληρώθηκε με επιτυχία η καταχώρηση του προτύπου", +"message.success.release.ip" : "Η διεύθυνση IP αποδεσμέυτηκε με επιτυχία", +"message.success.remove.egress.rule" : "Η κατάργηση του κανόνα εξόδου ολοκληρώθηκε με επιτυχία", +"message.success.remove.firewall.rule" : "Ο κανόνας τείχους προστασίας καταργήθηκε με επιτυχία", +"message.success.remove.instance.rule" : "Η κατάργηση της εικονική μηχανής από τον κανόνα ολοκληρώθηκε με επιτυχία", +"message.success.remove.ip" : "Ολοκληρώθηκε με επιτυχία η ip", +"message.success.remove.iprange" : "Η περιοχή IP καταργήθηκε με επιτυχία", +"message.success.remove.nic" : "Η κατάργηση ολοκληρώθηκε με επιτυχία", +"message.success.remove.port.forward" : "Η κατάργηση του κανόνα προώθησης θυρών ολοκληρώθηκε με επιτυχία", +"message.success.remove.rule" : "Ο κανόνας διαγράφηκε με επιτυχία", +"message.success.remove.secondary.ipaddress" : "Η κατάργηση της δευτερεύουσας διεύθυνσης IP ολοκληρώθηκε με επιτυχία", +"message.success.remove.sticky.policy" : "Η κατάργηση της πολιτικής sticky ολοκληρώθηκε με επιτυχία", +"message.success.resize.volume" : "Επιτυχής αλλαγή μεγέθους τόμου", +"message.success.scale.kubernetes" : "Σύμπλεγμα Kubernetes με επιτυχία", +"message.success.update.ipaddress" : "Η ενημέρωση της διεύθυνσης IP ολοκληρώθηκε με επιτυχία", +"message.success.update.kubeversion" : "Η επικαιροποίηση υποστηριζόμενης έκδοσης του Kubernetes ολοκληρώθηκε με επιτυχία", +"message.success.update.user" : "Ο χρήστης ενημερώθηκε με επιτυχία", +"message.success.upgrade.kubernetes" : "Το σύμπλεγμα Kubernetes αναβαθμίστηκε με επιτυχία", +"message.success.upload" : "Η αποστολή ολοκληρώθηκε με επιτυχία", +"message.success.upload.description" : "Αυτό το αρχείο ISO έχει αποσταλεί. Ελέγξτε την κατάστασή του στο μενού \"Πρότυπα\"", +"message.success.upload.iso.description" : "Αυτό το αρχείο ISO έχει αποσταλεί. Ελέγξτε την κατάστασή του στο μενού Εικόνες > ISOs", +"message.success.upload.template.description" : "Αυτό το αρχείο προτύπου έχει αποσταλεί. Ελέγξτε την κατάστασή του στο μενού \"Πρότυπα\"", +"message.success.upload.volume.description" : "Αυτός ο τόμος έχει αποσταλεί. Ελέγξτε την κατάστασή του στο μενού \"Τόμοι\"", +"message.suspend.project" : "Είστε βέβαιοι ότι θέλετε να αναστείλετε αυτό το έργο;", +"message.sussess.discovering.feature" : "Ανακάλυψε όλα τα διαθέσιμα χαρακτηριστικά!", +"message.switch.to" : "Μετάβαση σε", +"message.systems.vms.ready" : "Σύστημα VM έτοιμο.", +"message.template.copy.select.zone" : "Επιλέξτε μια ζώνη για αντιγραφή προτύπου.", +"message.template.copying" : "Το πρότυπο αντιγράφεται.", +"message.template.desc" : "Εικόνα λειτουργικού συστήματος που μπορεί να χρησιμοποιηθεί για την εκκίνηση VM", +"message.template.iso" : "Επιλέξτε ένα πρότυπο ή iso για να συνεχίσετε", +"message.tier.required" : "Απαιτείται βαθμίδα", +"message.tooltip.dns.1" : "Όνομα διακομιστή DNS για χρήση από VM στη ζώνη. Οι δημόσιες διευθύνσεις IP για τη ζώνη πρέπει να έχουν μια διαδρομή προς αυτόν το διακομιστή.", +"message.tooltip.dns.2" : "Ένα δεύτερο όνομα διακομιστή DNS για χρήση από VM στη ζώνη. Οι δημόσιες διευθύνσεις IP για τη ζώνη πρέπει να έχουν μια διαδρομή προς αυτόν το διακομιστή.", +"message.tooltip.internal.dns.1" : "Όνομα διακομιστή DNS για χρήση από VM εσωτερικού συστήματος CloudStack στη ζώνη. Η ιδιωτική διεύθυνση IP για τα pods πρέπει να έχει μια διαδρομή προς αυτόν το διακομιστή.", +"message.tooltip.internal.dns.2" : "Όνομα διακομιστή DNS για χρήση από VM εσωτερικού συστήματος CloudStack στη ζώνη. Η ιδιωτική διεύθυνση IP για τα pods πρέπει να έχει μια διαδρομή προς αυτόν το διακομιστή.", +"message.tooltip.network.domain" : "Ένα επίθεμα DNS που θα δημιουργήσει ένα προσαρμοσμένο όνομα τομέα για το δίκτυο στο οποίο γίνεται πρόσβαση από VM επισκέπτη.", +"message.tooltip.pod.name" : "Ένα όνομα γι' αυτό το pod.", +"message.tooltip.reserved.system.gateway" : "Η πύλη για τους κεντρικούς υπολογιστές στο pod.", +"message.tooltip.reserved.system.netmask" : "Το πρόθεμα δικτύου που ορίζει το δευτερεύον δίκτυο pod χρησιμοποιεί σημειογραφία CIDR.", +"message.tooltip.zone.name" : "Ένα όνομα για τη ζώνη.", +"message.traffic.type.to.basic.zone" : "τύπος κίνησης στη βασική ζώνη", +"message.update.ipaddress.processing" : "Ενημέρωση διεύθυνσης IP...", +"message.update.os.preference" : "Επιλέξτε μια προτίμηση λειτουργικού συστήματος για αυτόν τον κεντρικό υπολογιστή. Όλες οι εικονικές περιστάσεις με παρόμοιες προτιμήσεις θα εκχωρηθούν πρώτα σε αυτόν τον κεντρικό υπολογιστή πριν επιλέξουν έναν άλλο.", +"message.update.resource.count" : "Επιβεβαιώστε ότι θέλετε να ενημερώσετε τις μετρήσεις πόρων για αυτόν το λογαριασμό.", +"message.update.resource.count.domain" : "Επιβεβαιώστε ότι θέλετε να ενημερώσετε τις μετρήσεις πόρων για αυτόν τον τομέα.", +"message.update.ssl" : "Παρακαλώ προσκομείστε ένα νέο πιστοποιητικό SSL X.509 μαζί με την αλυσίδα επαλήθευσης του για να αναβαθμιστούν τα συστημικά μηχανήματα Console Proxy και Secondary Storage", +"message.update.ssl.failed" : "Απέτυχε η ενημέρωση του πιστοποιητικού SSL.", +"message.update.ssl.succeeded" : "Η ενημέρωση των πιστοποιητικών SSL ολοκληρώθηκε με επιτυχία", +"message.upload.failed" : "Η αποστολή απέτυχε", +"message.upload.file.limit" : "Μόνο ένα αρχείο μπορεί να αποσταλεί κάθε φορά", +"message.upload.file.processing" : "Μην κλείσετε αυτήν τη φόρμα, η αποστολή αρχείου βρίσκεται σε εξέλιξη...", +"message.upload.iso.failed" : "Η αποστολή ISO απέτυχε", +"message.upload.iso.failed.description" : "Απέτυχε η αποστολή του ISO", +"message.upload.template.failed.description" : "Απέτυχε η αποστολή του προτύπου", +"message.upload.volume.failed" : "Η αποστολή τόμου απέτυχε", +"message.user.not.permitted.api" : "Ο χρήστης δεν επιτρέπεται να χρησιμοποιήσει το API", +"message.validate.accept" : "Εισαγάγετε μια τιμή με έγκυρη επέκταση.", +"message.validate.creditcard" : "Πληκτρολογήστε έναν έγκυρο αριθμό πιστωτικής κάρτας.", +"message.validate.date" : "Πληκτρολογήστε μια έγκυρη ημερομηνία.", +"message.validate.date.iso" : "Πληκτρολογήστε μια έγκυρη ημερομηνία (ISO).", +"message.validate.digits" : "Πληκτρολογήστε μόνο ψηφία.", +"message.validate.email.address" : "Πληκτρολογήστε μια έγκυρη διεύθυνση ηλεκτρονικού ταχυδρομείου.", +"message.validate.equalto" : "Πληκτρολογήστε ξανά την ίδια τιμή.", +"message.validate.fieldrequired" : "Αυτό το πεδίο είναι απαραίτητο.", +"message.validate.fixfield" : "Παρακαλώ διορθώστε αυτό το πεδίο.", +"message.validate.instance.name" : "Το όνομα εικονική μηχανής δεν μπορεί να υπερβαίνει τους 63 χαρακτήρες. Επιτρέπονται μόνο ascii γράμματα a~z, A~Z, ψηφία 0~9, παύλα. Πρέπει να ξεκινά με ένα γράμμα και να τελειώνει με ένα γράμμα ή ένα ψηφίο.", +"message.validate.invalid.characters" : "Βρέθηκαν μη έγκυροι χαρακτήρες. παρακαλώ διορθώστε.", +"message.validate.max" : "Πληκτρολογήστε μια τιμή μικρότερη ή ίση με {0}.", +"message.validate.maxlength" : "Πληκτρολογήστε όχι περισσότερους από {0} χαρακτήρες.", +"message.validate.minlength" : "Πληκτρολογήστε τουλάχιστον {0} χαρακτήρες.", +"message.validate.number" : "Πληκτρολογήστε έναν έγκυρο αριθμό.", +"message.validate.range" : "Εισαγάγετε μια τιμή μεταξύ {0} και {1}.", +"message.validate.range.length" : "Πληκτρολογήστε μια τιμή μεταξύ {0} και {1} χαρακτήρων.", +"message.validate.url" : "Πληκτρολογήστε μια έγκυρη διεύθυνση URL.", +"message.virtual.network.desc" : "Ένα αποκλειστικό δίκτυο εικονικής διαμόρφωσης για το λογαριασμό σας. Ο τομέας μετάδοσης περιέχεται σε ένα VLAN και όλη η πρόσβαση στο δημόσιο δίκτυο δρομολογείται από έναν εικονικό δρομολογητή.", +"message.virtual.router.not.return.elementid" : "Σφάλμα, η εντολή listVirtualRouterElement API δεν επέστρεψε δεδομένα Virtual Router Element Id", +"message.vm.create.template.confirm" : "Δημιουργία προτύπου θα επανεκκινήσει την εικονική μηχανή αυτόματα.", +"message.vm.review.launch" : "Ελέγξτε τις ακόλουθες πληροφορίες και επιβεβαιώστε ότι η εικονική εικονική μηχανή σας είναι σωστή πριν από την εκκίνηση.", +"message.vm.state.destroyed" : "Το VM έχει επισημανθεί για καταστροφή", +"message.vm.state.error" : "Η εικονική μηχανή είναι σε σφάλμα", +"message.vm.state.expunging" : "Το VM πρόκειται να διαγραφεί", +"message.vm.state.migrating" : "Γίνεται μετεγκατάσταση της εικονικής μηχανής", +"message.vm.state.running" : "Η εικονική μηχανή εκτελείται", +"message.vm.state.shutdown" : "Η κατάσταση VM τερματίζεται από μέσα", +"message.vm.state.starting" : "Γίνεται εκκίνηση της εικονικής μηχανής", +"message.vm.state.stopped" : "Η εικονική μηχανή διακόπηκε", +"message.vm.state.stopping" : "Η εικονική μηχανή διακόπτεται", +"message.vm.state.unknown" : "Η κατάσταση VM είναι άγνωστη.", +"message.vmsnapshot.state.allocated" : "Το στιγμιότυπο VM έχει εκχωρηθεί, αλλά δεν έχει δημιουργηθεί ακόμα", +"message.vmsnapshot.state.creating" : "Δημιουργείται το στιγμιότυπο εικονικής μηχανής", +"message.vmsnapshot.state.error" : "Το στιγμιότυπο VM βρίσκεται σε κατάσταση σφάλματος και δεν είναι δυνατή η ανάκτησή του", +"message.vmsnapshot.state.expunging" : "Το στιγμιότυπο VM είναι να διαγραφεί", +"message.vmsnapshot.state.ready" : "Το στιγμιότυπο VM είναι έτοιμο για χρήση", +"message.vmsnapshot.state.removed" : "Το στιγμιότυπο VM καταστρέφεται και δεν είναι δυνατή η ανάκτησή του", +"message.vmsnapshot.state.reverting" : "Το στιγμιότυπο VM χρησιμοποιείται για την επαναφορά", +"message.vnmc.available.list" : "Το VNMC δεν είναι διαθέσιμο από τη λίστα υπηρεσιών παροχής.", +"message.vnmc.not.available.list" : "Το VNMC δεν είναι διαθέσιμο από τη λίστα υπηρεσιών παροχής.", +"message.volume.create.template.confirm" : "Επιβεβαιώστε ότι θέλετε να δημιουργήσετε ένα πρότυπο για αυτόν τον τόμο δίσκου. Η δημιουργία του προτύπου μπορεί να κυμαίνεται από αρκετά λεπτά έως περισσότερο, ανάλογα με το μέγεθος του τόμου.", +"message.volume.root.shrink.disk.size" : "Η λειτουργία συρρίκνωσης σε τόμο ROOT δεν υποστηρίζεται", +"message.volume.state.allocated" : "Ο τόμος έχει εκχωρηθεί αλλά δεν έχει δημιουργηθεί ακόμα", +"message.volume.state.attaching" : "Ο τόμος συνδέεται σε έναν τόμο από την κατάσταση \"Έτοιμο\".", +"message.volume.state.copying" : "Ο τόμος αντιγράφεται από το χώρο αποθήκευσης εικόνων στο πρωτεύον, σε περίπτωση που είναι ένας τόμος που έχει αποσταλεί", +"message.volume.state.creating" : "Ο τόμος δημιουργείται", +"message.volume.state.destroy" : "Ο τόμος καταστρέφεται και δεν είναι δυνατή η ανάκτηση του", +"message.volume.state.destroying" : "Ο τόμος καταστρέφει και δεν μπορεί να ανακτηθεί", +"message.volume.state.expunged" : "Ο όγκος έχει διαγραφεί", +"message.volume.state.expunging" : "Ο όγκος είναι να διαγραφεί", +"message.volume.state.migrating" : "Ο τόμος μετεγκαθίσταται σε άλλο χώρο αποθήκευσης", +"message.volume.state.notuploaded" : "Η καταχώρηση τόμου μόλις δημιουργήθηκε σε DB, δεν έχει αποσταλεί ακόμα", +"message.volume.state.ready" : "Ο τόμος είναι έτοιμος για χρήση", +"message.volume.state.resizing" : "Γίνεται αλλαγή μεγέθους του τόμου", +"message.volume.state.revertsnapshotting" : "Υπάρχει ένα στιγμιότυπο που δημιουργήθηκε σε αυτόν τον τόμο, ο τόμος επανέρχεται από το στιγμιότυπο", +"message.volume.state.snapshotting" : "Υπάρχει ένα στιγμιότυπο που δημιουργήθηκε σε αυτόν τον τόμο, δεν έχει δημιουργηθεί αντίγραφο ασφαλείας σε δευτερεύοντα χώρο αποθήκευσης ακόμα", +"message.volume.state.uploadabandoned" : "Η αποστολή τόμου έχει εγκαταλειφθεί, καθώς η αποστολή δεν ξεκίνησε ποτέ εντός συγκεκριμένου χρόνου", +"message.volume.state.uploaded" : "Ο τόμος αποστέλλεται", +"message.volume.state.uploaderror" : "Η αποστολή τόμου αντιμετώπισε κάποιο σφάλμα", +"message.volume.state.uploadinprogress" : "Η αποστολή τόμου βρίσκεται σε εξέλιξη", +"message.volume.state.uploadop" : "Η λειτουργία αποστολής τόμου βρίσκεται σε εξέλιξη ή, εν ολίγοις, ο τόμος βρίσκεται σε δευτερεύουσα αποθήκευση", +"message.waiting.for.builtin.templates.to.load" : "Αναμονή για τη φόρτωση αρχικών προτύπων...", +"message.xstools61plus.update.failed" : "Αποτυχία ενημέρωσης εργαλείων XS στην έκδοση 6.1+. Σφάλμα:", +"message.you.must.have.at.least.one.physical.network" : "Πρέπει να έχετε τουλάχιστον ένα φυσικό δίκτυο", +"message.your.cloudstack.is.ready" : "Το CloudStack σας είναι έτοιμο!", +"message.zone.creation.complete" : "Η δημιουργία ζώνης ολοκληρώθηκε", +"message.zone.creation.complete.would.you.like.to.enable.this.zone" : "Η δημιουργία ζώνης ολοκληρώθηκε. Θέλετε να ενεργοποιήσετε αυτήν τη ζώνη;", +"message.zone.detail.description" : "Συμπλήρωση λεπτομερειών ζώνης", +"message.zone.detail.hint" : "Μια ζώνη είναι η μεγαλύτερη οργανική μονάδα στο CloudStack και συνήθως αντιστοιχεί σε ένα μόνο κέντρο δεδομένων. Οι ζώνες παρέχουν φυσική απομόνωση και πλεονασμό. Μια ζώνη αποτελείται από ένα ή περισσότερα pods (καθένα από τα οποία περιέχει κεντρικούς υπολογιστές και πρωτεύοντες διακομιστές αποθήκευσης) και έναν δευτερεύοντα διακομιστή αποθήκευσης, ο οποίος είναι κοινόχρηστος από όλα τα pods της ζώνης.", +"message.zone.no.network.selection" : "Η ζώνη που επιλέξατε δεν έχει επιλογές για την επιλογή δικτύου.", +"message.zone.step.1.desc" : "Επιλέξτε ένα μοντέλο δικτύου για τη ζώνη σας.", +"message.zone.step.2.desc" : "Πληκτρολογήστε τις ακόλουθες πληροφορίες για να προσθέσετε μια νέα ζώνη", +"message.zone.step.3.desc" : "Παρακαλώ εισάγετε τις ακόλουθες πληροφορίες για να προσθέσετε ένα νέο pod", +"message.zonewizard.enable.local.storage" : "Προειδοποίηση: Αν ενεργοποιηθεί ο τοπικός χώρος αποθήκευσης για την ζώνη πρέπει να ορίσετε απο που θα εκκινούνται οι συστημικές εικονικές μηχανές:

1. Αν θέλετε να εκκινούνται απο τον κοινό πρωτεύον χώρο αποθήκευσης ο χώρος αυτός πρέπει να προστεθεί στην ζώνη μετά την δημιουργία της καθώς και η ζώνη να βρίσκεται σε κατάσταση απενεργοποίησης.

2. Αν θέλετε να εκκινούνται απο τον τοπικό πρωτεύον χώρο αποθήκευσης, η τιμή της μεταβλητής system.vm.use.local.storage πρέπει να τεθεί στο αληθές (true) πριν ενεργοποιηθεί η ζώνη.


Θέλετε να συνεχίσετε;", +"messgae.validate.min" : "Πληκτρολογήστε μια τιμή μεγαλύτερη ή ίση με {0}.", +"migrate.from" : "Μετεγκατάσταση από", +"migrate.to" : "Μετεγκατάσταση σε", +"migrationPolicy" : "Μεταναστευτική Πολιτική", +"network.rate" : "Ρυθμός μετάδοσης δεδομένων δικτύου", +"router.health.checks" : "Έλεγχος ομαλής λειτουργείας", +"side.by.side" : "Δίπλα-δίπλα", +"state.accepted" : "Αποδεκτό", +"state.active" : "Ενεργό", +"state.allocating" : "Κατανομή", +"state.backedup" : "Αντίγραφα ασφαλείας", +"state.backingup" : "Δημιουργία αντιγράφων ασφαλείας", +"state.completed" : "Ολοκληρωθηκε", +"state.creating" : "Δημιουργείται", +"state.declined" : "Μειώμένο", +"state.destroyed" : "Κατεστραμένο", +"state.detached" : "Αποκολλημένο", +"state.disabled" : "Απενεργοποιημένο", +"state.enabled" : "Ενεργοποιημένο", +"state.error" : "Σφάλμα", +"state.expired" : "Έληξε", +"state.expunging" : "Διαγράφεται", +"state.migrating" : "Μετεγκαθίσταται", +"state.pending" : "Εκκρεμεί", +"state.running" : "Εκτέλείται", +"state.starting" : "Ξεκινάει", +"state.stopped" : "Σταμάτησε", +"state.stopping" : "Διακόπτεται", +"state.suspended" : "Ανεσταλμένο", +"title.upload.volume" : "Αναφόρτωση τόμου", +"user.login" : "Σύνδεση χρήστη", +"user.logout" : "Αποσύνδεση χρήστη" +} diff --git a/ui/public/locales/en.json b/ui/public/locales/en.json index 33e8f32aa497..3ff927b578ab 100644 --- a/ui/public/locales/en.json +++ b/ui/public/locales/en.json @@ -1223,6 +1223,7 @@ "label.latest.events": "Latest events", "label.launch": "Launch", "label.launch.vm": "Launch Virtual Machine", +"label.launch.vm.and.stay": "Launch VM & Stay On This Page", "label.launch.zone": "Launch Zone", "label.lb.algorithm.leastconn": "Least connections", "label.lb.algorithm.roundrobin": "Round-robin", @@ -2076,6 +2077,7 @@ "label.supportsstrechedl2subnet": "Supports Streched L2 Subnet", "label.suspend.project": "Suspend Project", "label.switch.type": "Switch Type", +"label.sync.storage": "Sync Storage Pool", "label.system.capacity": "System Capacity", "label.system.offering": "System Offering", "label.system.offering.for.router": "System Offering for Router", @@ -2640,6 +2642,7 @@ "message.confirm.start.lb.vm": "Please confirm you want to start LB VM", "message.confirm.stop.kubernetes.cluster": "Please confirm that you want to stop this Kubernetes cluster.", "message.confirm.stop.lb.vm": "Please confirm you want to stop LB VM", +"message.confirm.sync.storage": "Please confirm you want to sync the storage pool", "message.confirm.upgrade.router.newer.template": "Please confirm that you want to upgrade router 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.upgrade.routers.cluster.newtemplate": "Please confirm that you want to upgrade all routers in this cluster to use newer template", @@ -2702,7 +2705,7 @@ "message.delete.vpn.customer.gateway": "Please confirm that you want to delete this VPN Customer Gateway", "message.delete.vpn.gateway": "Please confirm that you want to delete this VPN Gateway", "message.deleting.vm": "Deleting VM", -"message.deployasis": "Selected template is Deploy As-Is i.e., the VM is deployed by importing an OVA with vApps directly into vCenter. Root disk(s) resize is allowed only on stopped VMs for such templates.", +"message.deployasis": "Selected template is Deploy As-Is i.e., the VM is deployed by importing an OVA with vApps directly into vCenter. Root disk(s) resize is allowed only on stopped VMs for such templates.", "message.desc.add.new.lb.sticky.rule": "Add new LB sticky rule", "message.desc.advanced.zone": "For more sophisticated network topologies. This network model provides the most flexibility in defining guest networks and providing custom network offerings such as firewall, VPN, or load balancer support.", "message.desc.basic.zone": "Provide a single network where each VM instance is assigned an IP directly from the network. Guest isolation can be provided through layer-3 means such as security groups (IP address source filtering).", @@ -2777,7 +2780,7 @@ "message.error.custom.disk.size": "Please enter custom disk size", "message.error.date": "Please select a date", "message.error.description": "Please enter description", -"message.error.discovering.feature": "Exception caught while discoverying features", +"message.error.discovering.feature": "Exception caught while discovering features", "message.error.display.text": "Please enter display text", "message.error.domain": "Enter your domain, leave empty for ROOT domain", "message.error.enable.saml": "Unable to find users IDs to enable SAML Single Sign On, kindly enable it manually.", @@ -2860,6 +2863,7 @@ "message.error.upload.template.description": "Only one template can be uploaded at a time", "message.error.url": "Please enter URL", "message.error.username": "Enter your username", +"message.error.valid.iops.range": "Please enter a valid IOPS range", "message.error.vcenter.datacenter": "Please enter vCenter Datacenter", "message.error.vcenter.datastore": "Please enter vCenter Datastore", "message.error.vcenter.host": "Please enter vCenter Host", @@ -3321,6 +3325,8 @@ "state.expunging": "Expunging", "state.migrating": "Migrating", "state.pending": "Pending", +"state.readonly": "Read-Only", +"state.readwrite": "Read-Write", "state.running": "Running", "state.starting": "Starting", "state.stopped": "Stopped", diff --git a/ui/src/components/header/TranslationMenu.vue b/ui/src/components/header/TranslationMenu.vue index 3240e4fc3c3a..cf43e96702b7 100644 --- a/ui/src/components/header/TranslationMenu.vue +++ b/ui/src/components/header/TranslationMenu.vue @@ -41,6 +41,7 @@ Polish Português brasileiro Русский + Ελληνικά diff --git a/ui/src/components/view/DetailSettings.vue b/ui/src/components/view/DetailSettings.vue index 1af56bf321a2..302fd63af780 100644 --- a/ui/src/components/view/DetailSettings.vue +++ b/ui/src/components/view/DetailSettings.vue @@ -110,7 +110,7 @@ + + diff --git a/ui/src/config/section/compute.js b/ui/src/config/section/compute.js index f16f89e5dc58..d6ecbf53b96a 100644 --- a/ui/src/config/section/compute.js +++ b/ui/src/config/section/compute.js @@ -145,6 +145,17 @@ export default { virtualmachineid: { value: (record) => { return record.id } } + }, + successMethod: (obj, result) => { + const vm = result.jobresult.virtualmachine || {} + if (result.jobstatus === 1 && vm.password) { + const name = vm.displayname || vm.name || vm.id + obj.$notification.success({ + message: `${obj.$t('label.reinstall.vm')}: ` + name, + description: `${obj.$t('label.password.reset.confirm')}: ` + vm.password, + duration: 0 + }) + } } }, { @@ -339,6 +350,17 @@ export default { domainid: { value: (record) => { return record.domainid } } + }, + successMethod: (obj, result) => { + const vm = result.jobresult.virtualmachine || {} + if (result.jobstatus === 1 && vm.password) { + const name = vm.displayname || vm.name || vm.id + obj.$notification.success({ + message: `${obj.$t('label.reset.ssh.key.pair.on.vm')}: ` + name, + description: `${obj.$t('label.password.reset.confirm')}: ` + vm.password, + duration: 0 + }) + } } }, { @@ -408,7 +430,7 @@ export default { fields.push('zonename') return fields }, - details: ['name', 'description', 'zonename', 'kubernetesversionname', 'size', 'masternodes', 'cpunumber', 'memory', 'keypair', 'associatednetworkname', 'account', 'domain', 'zonename'], + details: ['name', 'description', 'zonename', 'kubernetesversionname', 'size', 'controlnodes', 'cpunumber', 'memory', 'keypair', 'associatednetworkname', 'account', 'domain', 'zonename'], tabs: [{ name: 'k8s', component: () => import('@/views/compute/KubernetesServiceTab.vue') diff --git a/ui/src/config/section/infra/primaryStorages.js b/ui/src/config/section/infra/primaryStorages.js index 9f78ab95768d..eda571766681 100644 --- a/ui/src/config/section/infra/primaryStorages.js +++ b/ui/src/config/section/infra/primaryStorages.js @@ -81,6 +81,14 @@ export default { defaultArgs: { enabled: true }, show: (record) => { return record.state === 'Disabled' } }, + { + api: 'syncStoragePool', + icon: 'sync', + label: 'label.sync.storage', + message: 'message.confirm.sync.storage', + dataView: true, + show: (record) => { return record.state === 'Up' && record.type === 'DatastoreCluster' } + }, { api: 'enableStorageMaintenance', icon: 'plus-square', diff --git a/ui/src/config/section/infra/secondaryStorages.js b/ui/src/config/section/infra/secondaryStorages.js index 17600aaa17bc..d22564d7221b 100644 --- a/ui/src/config/section/infra/secondaryStorages.js +++ b/ui/src/config/section/infra/secondaryStorages.js @@ -25,7 +25,10 @@ export default { columns: () => { var fields = ['name', 'url', 'protocol', 'scope', 'zonename'] if (store.getters.apis.listImageStores.params.filter(x => x.name === 'readonly').length > 0) { - fields.push('readonly') + fields.push({ + field: 'readonly', + customTitle: 'access' + }) } return fields }, diff --git a/ui/src/config/section/offering.js b/ui/src/config/section/offering.js index f495841e49b3..13be7c4ee07e 100644 --- a/ui/src/config/section/offering.js +++ b/ui/src/config/section/offering.js @@ -31,7 +31,7 @@ export default { params: { isrecursive: 'true' }, columns: ['name', 'displaytext', 'cpunumber', 'cpuspeed', 'memory', 'domain', 'zone', 'order'], details: () => { - var fields = ['name', 'id', 'displaytext', 'offerha', 'provisioningtype', 'storagetype', 'iscustomized', 'limitcpuuse', 'cpunumber', 'cpuspeed', 'memory', 'hosttags', 'tags', 'domain', 'zone', 'created', 'dynamicscalingenabled'] + var fields = ['name', 'id', 'displaytext', 'offerha', 'provisioningtype', 'storagetype', 'iscustomized', 'iscustomizediops', 'limitcpuuse', 'cpunumber', 'cpuspeed', 'memory', 'hosttags', 'tags', 'domain', 'zone', 'created', 'dynamicscalingenabled'] if (store.getters.apis.createServiceOffering && store.getters.apis.createServiceOffering.params.filter(x => x.name === 'storagepolicy').length > 0) { fields.splice(6, 0, 'vspherestoragepolicy') @@ -124,7 +124,7 @@ export default { params: { isrecursive: 'true' }, columns: ['name', 'displaytext', 'disksize', 'domain', 'zone', 'order'], details: () => { - var fields = ['name', 'id', 'displaytext', 'disksize', 'provisioningtype', 'storagetype', 'iscustomized', 'tags', 'domain', 'zone', 'created'] + var fields = ['name', 'id', 'displaytext', 'disksize', 'provisioningtype', 'storagetype', 'iscustomized', 'iscustomizediops', 'tags', 'domain', 'zone', 'created'] if (store.getters.apis.createDiskOffering && store.getters.apis.createDiskOffering.params.filter(x => x.name === 'storagepolicy').length > 0) { fields.splice(6, 0, 'vspherestoragepolicy') diff --git a/ui/src/core/lazy_lib/components_use.js b/ui/src/core/lazy_lib/components_use.js index 72a57b88ec7f..50e2d96d0d88 100644 --- a/ui/src/core/lazy_lib/components_use.js +++ b/ui/src/core/lazy_lib/components_use.js @@ -89,6 +89,7 @@ Vue.use(Icon) Vue.use(Badge) Vue.use(Popover) Vue.use(Dropdown) +Vue.use(Descriptions) Vue.use(List) Vue.use(Avatar) Vue.use(Breadcrumb) diff --git a/ui/src/main.js b/ui/src/main.js index 064314b98de8..9fbae3e0acdb 100644 --- a/ui/src/main.js +++ b/ui/src/main.js @@ -26,7 +26,7 @@ import './core/lazy_use' import './core/ext' import './permission' // permission control import './utils/filter' // global filter -import { pollJobPlugin, notifierPlugin, toLocaleDatePlugin, configUtilPlugin } from './utils/plugins' +import { pollJobPlugin, notifierPlugin, toLocaleDatePlugin, configUtilPlugin, apiMetaUtilPlugin } from './utils/plugins' import { VueAxios } from './utils/request' Vue.config.productionTip = false @@ -51,3 +51,4 @@ fetch('config.json').then(response => response.json()).then(config => { }) Vue.use(configUtilPlugin) +Vue.use(apiMetaUtilPlugin) diff --git a/ui/src/utils/plugins.js b/ui/src/utils/plugins.js index 3276eea63e78..87e4e74ff389 100644 --- a/ui/src/utils/plugins.js +++ b/ui/src/utils/plugins.js @@ -185,3 +185,20 @@ export const configUtilPlugin = { } } } + +export const apiMetaUtilPlugin = { + install (Vue) { + Vue.prototype.$getApiParams = function () { + var apiParams = {} + for (var argument of arguments) { + var apiConfig = this.$store.getters.apis[argument] || {} + if (apiConfig && apiConfig.params) { + apiConfig.params.forEach(param => { + apiParams[param.name] = param + }) + } + } + return apiParams + } + } +} diff --git a/ui/src/views/AutogenView.vue b/ui/src/views/AutogenView.vue index c51487c3b7a5..697194102567 100644 --- a/ui/src/views/AutogenView.vue +++ b/ui/src/views/AutogenView.vue @@ -159,12 +159,7 @@ :v-bind="field.name" v-if="!(currentAction.mapping && field.name in currentAction.mapping && currentAction.mapping[field.name].value)" > - - {{ $t('label.' + field.name) }} - - - - + this.fetchData(), loadingMessage: `${this.$t(action.label)} - ${resourceName}`, diff --git a/ui/src/views/compute/CreateKubernetesCluster.vue b/ui/src/views/compute/CreateKubernetesCluster.vue index 9659b3da8767..e32aa8d8c1e1 100644 --- a/ui/src/views/compute/CreateKubernetesCluster.vue +++ b/ui/src/views/compute/CreateKubernetesCluster.vue @@ -23,12 +23,7 @@ @submit="handleSubmit" layout="vertical"> - - {{ $t('label.name') }} - - - - + - {{ $t('label.description') }} - - - - + - - {{ $t('label.zoneid') }} - - - - + - {{ $t('label.kubernetesversionid') }} - - - - + - {{ $t('label.serviceofferingid') }} - - - - + - {{ $t('label.noderootdisksize') }} - - - - + - - {{ $t('label.networkid') }} - - - - + - - {{ $t('label.controlnodes') }} - - - - + - - {{ $t('label.externalloadbalanceripaddress') }} - - - - + - - {{ $t('label.cks.cluster.size') }} - - - - + - - {{ $t('label.keypair') }} - - - - +
- - {{ $t('label.username') }} - - - - + - - {{ $t('label.password') }} - - - - + - - {{ $t('label.url') }} - - - - + - - {{ $t('label.email') }} - - - - + - - {{ $t('label.volumeid') }} - - - - + - - {{ $t('label.name') }} - - - - + - - {{ $t('label.quiescevm') }} - - - - + - - {{ $t('label.asyncbackup') }} - - - - +
@@ -85,9 +65,13 @@